Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gui: add fav page #744

Merged
merged 1 commit into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions feeluown/gui/base_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from abc import abstractmethod
from typing import runtime_checkable, Protocol

from feeluown.models import ModelType
from feeluown.gui.widgets.tabbar import Tab, TabBar


Expand Down Expand Up @@ -67,6 +68,15 @@ def render_tab_bar(self):
def render_by_tab_index(self, tab_index):
raise NotImplementedError

def default_tabs(self):
return [
('歌曲', ModelType.song, self.show_songs),
('专辑', ModelType.album, self.show_albums),
('歌手', ModelType.artist, self.show_artists),
('歌单', ModelType.playlist, self.show_playlists),
('视频', ModelType.video, self.show_videos)
]


@runtime_checkable
class VFillableBg(Protocol):
Expand Down
2 changes: 2 additions & 0 deletions feeluown/gui/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ def initialize(self):
from feeluown.gui.pages.recommendation import render as render_rec
from feeluown.gui.pages.recommendation_daily_songs import \
render as render_rec_daily_songs
from feeluown.gui.pages.my_fav import render as render_my_fav

model_prefix = f'{MODEL_PAGE_PREFIX}<provider>'

Expand All @@ -214,6 +215,7 @@ async def dummy_render(req, *args, **kwargs):
('/search', render_search),
('/rec', render_rec),
('/rec/daily_songs', render_rec_daily_songs),
('/my_fav', render_my_fav),
]
for url, renderer in urlpatterns:
self.route(url)(renderer)
31 changes: 31 additions & 0 deletions feeluown/gui/drawers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import math
from typing import Optional

from PyQt5.QtCore import Qt, QRect, QPoint, QPointF
Expand Down Expand Up @@ -255,3 +256,33 @@ def paint(self, painter: QPainter):
painter.drawLine(self.p3, self.p4)
painter.drawLine(self.p4, self.p5)
painter.drawLine(self.p4, self.p6)


class StarIconDrawer:
def __init__(self, length, padding):

radius_outer = (length - 2*padding)//2
length_half = length // 2
radius_inner = radius_outer // 2
center = QPointF(length_half, length_half)
angle = math.pi / 2

self._star_polygon = QPolygonF()
for _ in range(5):
outer_point = center + QPointF(
radius_outer * math.cos(angle),
-radius_outer * math.sin(angle)
)
self._star_polygon.append(outer_point)
inner_point = center + QPointF(
radius_inner * math.cos(angle + math.pi/5),
-radius_inner * math.sin(angle + math.pi/5)
)
self._star_polygon.append(inner_point)
angle += 2 * math.pi / 5

def paint(self, painter: QPainter):
pen = painter.pen()
pen.setWidthF(1.5)
painter.setPen(pen)
painter.drawPolygon(self._star_polygon)
8 changes: 1 addition & 7 deletions feeluown/gui/pages/coll_mixed.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,7 @@ def __init__(self, app, tab_index, coll: Collection):
self._app = app
self._coll = coll
self.tab_index = tab_index
self.tabs = [
('歌曲', ModelType.song, self.show_songs),
('专辑', ModelType.album, self.show_albums),
('歌手', ModelType.artist, self.show_artists),
('歌单', ModelType.playlist, self.show_playlists),
('视频', ModelType.video, self.show_videos)
]
self.tabs = self.default_tabs()

async def render(self):
coll = self._coll
Expand Down
83 changes: 83 additions & 0 deletions feeluown/gui/pages/my_fav.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from feeluown.app.gui_app import GuiApp
from feeluown.models import ModelType
from feeluown.utils.aio import run_fn
from feeluown.gui.page_containers.table import Renderer
from feeluown.gui.base_renderer import TabBarRendererMixin
from feeluown.library import (
SupportsCurrentUserFavSongsReader,
SupportsCurrentUserFavAlbumsReader,
SupportsCurrentUserFavArtistsReader,
SupportsCurrentUserFavPlaylistsReader,
SupportsCurrentUserFavVideosReader,
)
from feeluown.utils.reader import create_reader
from .template import render_error_message


async def render(req, **kwargs):
app: GuiApp = req.ctx['app']
ui = app.ui
tab_index = int(req.query.get('tab_index', 0))
pvd_ui = app.current_pvd_ui_mgr.get()
if pvd_ui is None:
return await render_error_message(app, '当前资源提供方未知,无法浏览该页面')

ui.right_panel.set_body(ui.right_panel.scrollarea)
table_container = ui.right_panel.table_container
renderer = MyFavRenderer(app, tab_index, pvd_ui.provider)
await table_container.set_renderer(renderer)


class MyFavRenderer(Renderer, TabBarRendererMixin):
def __init__(self, app, tab_index, provider):
self._app = app
self._provider = provider
self.tab_index = tab_index
self.tabs = self.default_tabs()

async def render(self):
self.meta_widget.show()
self.meta_widget.title = '我的收藏'
self.render_tab_bar()
await self.render_models()

async def render_models(self):
# pylint: disable=too-many-branches
_, mtype, show_handler = self.tabs[self.tab_index]
err = ''
reader = create_reader([])
if mtype is ModelType.song:
if isinstance(self._provider, SupportsCurrentUserFavSongsReader):
reader = await run_fn(self._provider.current_user_fav_create_songs_rd)
else:
err = '收藏的歌曲'
elif mtype is ModelType.album:
if isinstance(self._provider, SupportsCurrentUserFavAlbumsReader):
reader = await run_fn(self._provider.current_user_fav_create_albums_rd)
else:
err = '收藏的专辑'
elif mtype is ModelType.artist:
if isinstance(self._provider, SupportsCurrentUserFavArtistsReader):
reader = await run_fn(self._provider.current_user_fav_create_artists_rd)
else:
err = '收藏的歌手'
elif mtype is ModelType.playlist:
if isinstance(self._provider, SupportsCurrentUserFavPlaylistsReader):
reader = await run_fn(self._provider.current_user_fav_create_playlists_rd) # noqa
else:
err = '收藏的歌单'
else:
if isinstance(self._provider, SupportsCurrentUserFavVideosReader):
reader = await run_fn(self._provider.current_user_fav_create_videos_rd)
else:
err = '收藏的视频'
if err:
return await render_error_message(
self._app,
f'当前资源提供方({self._provider.name})不支持获取 {err}'
)
else:
show_handler(reader)

def render_by_tab_index(self, tab_index):
self._app.browser.goto(page='/my_fav', query={'tab_index': tab_index})
15 changes: 13 additions & 2 deletions feeluown/gui/uimain/sidebar.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
HomeButton,
PlusButton,
TriagleButton,
StarButton,
)

from feeluown.gui.widgets.playlists import PlaylistsView
Expand Down Expand Up @@ -107,6 +108,7 @@ def __init__(self, app: 'GuiApp', parent=None):

self.home_btn = HomeButton(height=30, parent=self)
self.discovery_btn = DiscoveryButton(height=30, padding=0.2, parent=self)
self.fav_btn = StarButton('我的收藏', height=30, parent=self)
self.collections_header = QLabel('本地收藏集', self)
self.collections_header.setToolTip('我们可以在本地建立『收藏集』来收藏自己喜欢的音乐资源\n\n'
'每个收藏集都以一个独立 .fuo 文件的存在,'
Expand Down Expand Up @@ -141,6 +143,7 @@ def __init__(self, app: 'GuiApp', parent=None):
self._top_layout.setContentsMargins(15, 16, 16, 0)
self._top_layout.addWidget(self.home_btn)
self._top_layout.addWidget(self.discovery_btn)
self._top_layout.addWidget(self.fav_btn)
self._sub_layout.setContentsMargins(16, 8, 16, 0)
self._sub_layout.addWidget(self.collections_con)
self._sub_layout.addWidget(self.my_music_con)
Expand All @@ -156,6 +159,7 @@ def __init__(self, app: 'GuiApp', parent=None):
self.playlists_con.hide()
self.my_music_con.hide()
self.discovery_btn.setDisabled(True)
self.fav_btn.setDisabled(True)
self.discovery_btn.setToolTip('当前资源提供方未知')

self.home_btn.clicked.connect(self.show_library)
Expand All @@ -173,6 +177,8 @@ def __init__(self, app: 'GuiApp', parent=None):
self.on_current_pvd_ui_changed)
self.discovery_btn.clicked.connect(
lambda: self._app.browser.goto(page='/rec'))
self.fav_btn.clicked.connect(
lambda: self._app.browser.goto(page='/my_fav'))

def popup_collection_adding_dialog(self):
dialog = QDialog(self)
Expand Down Expand Up @@ -282,5 +288,10 @@ def do():
box.open()

def on_current_pvd_ui_changed(self, pvd_ui, _):
self.discovery_btn.setEnabled(True)
self.discovery_btn.setToolTip(f'点击进入 {pvd_ui.provider.name} 推荐页')
if pvd_ui:
self.discovery_btn.setEnabled(True)
self.fav_btn.setEnabled(True)
self.discovery_btn.setToolTip(f'点击进入 {pvd_ui.provider.name} 推荐页')
else:
self.discovery_btn.setEnabled(False)
self.fav_btn.setEnabled(False)
1 change: 1 addition & 0 deletions feeluown/gui/widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
HomeButton, LeftArrowButton, RightArrowButton, SearchButton, SettingsButton,
PlusButton, TriagleButton, DiscoveryButton,
SelfPaintAbstractIconTextButton, CalendarButton, RankButton,
StarButton,
)
12 changes: 11 additions & 1 deletion feeluown/gui/widgets/selfpaint_btn.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from feeluown.gui.drawers import (
HomeIconDrawer, PlusIconDrawer, TriangleIconDrawer, CalendarIconDrawer,
RankIconDrawer,
RankIconDrawer, StarIconDrawer,
)
from feeluown.gui.helpers import darker_or_lighter

Expand Down Expand Up @@ -296,6 +296,15 @@ def draw_icon(self, painter):
self.rank_icon.paint(painter)


class StarButton(SelfPaintAbstractIconTextButton):
def __init__(self, text='收藏', *args, **kwargs):
super().__init__(text, *args, **kwargs)
self.star_icon = StarIconDrawer(self.height(), self._padding)

def draw_icon(self, painter):
self.star_icon.paint(painter)


if __name__ == '__main__':
from feeluown.gui.debug import simple_layout

Expand All @@ -315,3 +324,4 @@ def draw_icon(self, painter):
layout.addWidget(TriagleButton(length=length, direction='up'))
layout.addWidget(CalendarButton(height=length))
layout.addWidget(RankButton(height=length))
layout.addWidget(StarButton(height=length))
74 changes: 40 additions & 34 deletions feeluown/library/provider_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,6 @@
from .flags import Flags as PF


__all__ = (
'SupportsAlbumGet',
'SupportsAlbumSongsReader',

'SupportsArtistAlbumsReader',
'SupportsArtistGet',
'SupportsArtistSongsReader',

'SupportsCurrentUser',

'SupportsPlaylistAddSong',
'SupportsPlaylistGet',
'SupportsPlaylistCreateByName',
'SupportsPlaylistDelete',
'SupportsPlaylistRemoveSong',
'SupportsPlaylistSongsReader',

'SupportsSongGet',
'SupportsSongHotComments',
'SupportsSongLyric',
'SupportsSongMV',
'SupportsSongMultiQuality',
'SupportsSongSimilar',
'SupportsSongWebUrl',

'SupportsVideoGet',
'SupportsVideoMultiQuality',

'SupportsRecListDailySongs',
'SupportsRecListDailyAlbums',
'SupportsRecListDailyPlaylists',
)


ID = str
_FlagProtocolMapping: Dict[Tuple[ModelType, PF], type] = {}

Expand Down Expand Up @@ -349,6 +315,46 @@ def get_current_user(self) -> UserModel:
"""


#
# Protocols for current user favorites/collections
#
@runtime_checkable
class SupportsCurrentUserFavSongsReader(Protocol):
@abstractmethod
def current_user_fav_create_songs_rd(self):
"""
: raises NoUserLoggedIn:
"""


@runtime_checkable
class SupportsCurrentUserFavAlbumsReader(Protocol):
@abstractmethod
def current_user_fav_create_albums_rd(self):
pass


@runtime_checkable
class SupportsCurrentUserFavArtistsReader(Protocol):
@abstractmethod
def current_user_fav_create_artists_rd(self):
pass


@runtime_checkable
class SupportsCurrentUserFavPlaylistsReader(Protocol):
@abstractmethod
def current_user_fav_create_playlists_rd(self):
pass


@runtime_checkable
class SupportsCurrentUserFavVideosReader(Protocol):
@abstractmethod
def current_user_fav_create_videos_rd(self):
pass


#
# Protocols for recommendation.
#
Expand Down
Loading