5
5
from PyQt5 .QtWidgets import QFrame , QLabel , QVBoxLayout , QSizePolicy , QScrollArea , \
6
6
QHBoxLayout , QFormLayout , QDialog , QLineEdit , QDialogButtonBox , QMessageBox
7
7
8
+ from feeluown .excs import ProviderIOError , NoUserLoggedIn
9
+ from feeluown .library import (
10
+ SupportsPlaylistDelete ,
11
+ SupportsPlaylistCreateByName ,
12
+ SupportsCurrentUser ,
13
+ )
8
14
from feeluown .collection import CollectionAlreadyExists , CollectionType
15
+ from feeluown .utils import aio
9
16
from feeluown .gui .widgets import (
10
- DiscoveryButton , HomeButton , PlusButton , TriagleButton ,
17
+ DiscoveryButton ,
18
+ HomeButton ,
19
+ PlusButton ,
20
+ TriagleButton ,
11
21
)
12
22
from feeluown .gui .widgets .playlists import PlaylistsView
13
23
from feeluown .gui .components import CollectionListView
@@ -64,6 +74,7 @@ def toggle_view(self):
64
74
65
75
66
76
class LeftPanel (QScrollArea ):
77
+
67
78
def __init__ (self , app : 'GuiApp' , parent = None ):
68
79
super ().__init__ (parent )
69
80
self ._app = app
@@ -96,26 +107,23 @@ def __init__(self, app: 'GuiApp', parent=None):
96
107
self .home_btn = HomeButton (height = 30 , parent = self )
97
108
self .discovery_btn = DiscoveryButton (height = 30 , padding = 0.2 , parent = self )
98
109
self .collections_header = QLabel ('本地收藏集' , self )
99
- self .collections_header .setToolTip (
100
- '我们可以在本地建立『收藏集』来收藏自己喜欢的音乐资源\n \n '
101
- '每个收藏集都以一个独立 .fuo 文件的存在,'
102
- '将鼠标悬浮在收藏集上,可以查看文件所在路径。\n '
103
- '新建 fuo 文件,则可以新建收藏集,文件名即是收藏集的名字。\n \n '
104
- '手动编辑 fuo 文件即可编辑收藏集中的音乐资源,也可以在界面上拖拽来增删歌曲。'
105
- )
110
+ self .collections_header .setToolTip ('我们可以在本地建立『收藏集』来收藏自己喜欢的音乐资源\n \n '
111
+ '每个收藏集都以一个独立 .fuo 文件的存在,'
112
+ '将鼠标悬浮在收藏集上,可以查看文件所在路径。\n '
113
+ '新建 fuo 文件,则可以新建收藏集,文件名即是收藏集的名字。\n \n '
114
+ '手动编辑 fuo 文件即可编辑收藏集中的音乐资源,也可以在界面上拖拽来增删歌曲。' )
106
115
self .playlists_header = QLabel ('歌单列表' , self )
107
116
self .my_music_header = QLabel ('我的音乐' , self )
108
117
109
118
self .playlists_view = PlaylistsView (self )
110
119
self .my_music_view = MyMusicView (self )
111
120
self .collections_view = CollectionListView (self ._app )
112
121
113
- self .collections_con = ListViewContainer (
114
- self .collections_header , self .collections_view )
115
- self .playlists_con = ListViewContainer (
116
- self .playlists_header , self .playlists_view )
117
- self .my_music_con = ListViewContainer (
118
- self .my_music_header , self .my_music_view )
122
+ self .collections_con = ListViewContainer (self .collections_header ,
123
+ self .collections_view )
124
+ self .playlists_con = ListViewContainer (self .playlists_header ,
125
+ self .playlists_view )
126
+ self .my_music_con = ListViewContainer (self .my_music_header , self .my_music_view )
119
127
120
128
self .playlists_view .setModel (self ._app .pl_uimgr .model )
121
129
self .my_music_view .setModel (self ._app .mymusic_uimgr .model )
@@ -153,9 +161,11 @@ def __init__(self, app: 'GuiApp', parent=None):
153
161
lambda pl : self ._app .browser .goto (model = pl ))
154
162
self .collections_view .show_collection .connect (
155
163
lambda coll : self ._app .browser .goto (page = f'/colls/{ coll .identifier } ' ))
156
- self .collections_view .remove_collection .connect (self .remove_coll )
164
+ self .collections_view .remove_collection .connect (self ._remove_coll )
165
+ self .playlists_view .remove_playlist .connect (self ._remove_playlist )
157
166
self .collections_con .create_btn .clicked .connect (
158
167
self .popup_collection_adding_dialog )
168
+ self .playlists_con .create_btn .clicked .connect (self ._create_playlist )
159
169
160
170
def popup_collection_adding_dialog (self ):
161
171
dialog = QDialog (self )
@@ -184,6 +194,50 @@ def create_collection_and_reload():
184
194
dialog .accepted .connect (create_collection_and_reload )
185
195
dialog .open ()
186
196
197
+ def _create_playlist (self ):
198
+ provider_ui = self ._app .current_pvd_ui_mgr .get ()
199
+ if provider_ui is None :
200
+ self ._app .show_msg ('当前的资源提供方未注册其 UI' )
201
+ return
202
+ provider = provider_ui .provider
203
+ if not isinstance (provider , SupportsPlaylistCreateByName ) \
204
+ or not isinstance (provider , SupportsCurrentUser ) \
205
+ or not provider .has_current_user ():
206
+ self ._app .show_msg ('当前的资源提供方不支持创建歌单' )
207
+ return
208
+
209
+ dialog = QDialog (self )
210
+ # Set WA_DeleteOnClose so that the dialog can be deleted (from self.children).
211
+ dialog .setAttribute (Qt .WA_DeleteOnClose )
212
+ layout = QFormLayout (dialog )
213
+ title_edit = QLineEdit (dialog )
214
+ layout .addRow ('歌单名' , title_edit )
215
+ button_box = QDialogButtonBox (QDialogButtonBox .Cancel | QDialogButtonBox .Yes )
216
+ layout .addRow ('' , button_box )
217
+ button_box .accepted .connect (dialog .accept )
218
+ button_box .rejected .connect (dialog .reject )
219
+
220
+ def create_playlist_and_reload ():
221
+ title = title_edit .text ()
222
+
223
+ async def do ():
224
+ try :
225
+ playlist = await aio .run_fn (provider .playlist_create_by_name , title )
226
+ except (ProviderIOError , NoUserLoggedIn ) as e :
227
+ QMessageBox .warning (self ._app , '错误' , f"创建歌单 '{ title } ' 失败: { e } " )
228
+ else :
229
+ # Add playlist to pl_uimgr is a workaround, which may cause bug.
230
+ # For example, the order of the newly created playlist should be
231
+ # in the top for some providers.
232
+ # TODO: re-fetch user's playlists and fill the UI.
233
+ self ._app .pl_uimgr .add (playlist , is_fav = False )
234
+ self ._app .show_msg (f"创建歌单 '{ title } ' 成功" )
235
+
236
+ aio .run_afn (do )
237
+
238
+ dialog .accepted .connect (create_playlist_and_reload )
239
+ dialog .open ()
240
+
187
241
def show_library (self ):
188
242
coll_library = self ._app .coll_mgr .get_coll_library ()
189
243
self ._app .browser .goto (page = f'/colls/{ coll_library .identifier } ' )
@@ -192,7 +246,25 @@ def show_pool(self):
192
246
coll = self ._app .coll_mgr .get (CollectionType .sys_pool )
193
247
self ._app .browser .goto (page = f'/colls/{ coll .identifier } ' )
194
248
195
- def remove_coll (self , coll ):
249
+ def _remove_playlist (self , playlist ):
250
+
251
+ async def do ():
252
+ provider = self ._app .library .get_or_raise (playlist .source )
253
+ if isinstance (provider , SupportsPlaylistDelete ):
254
+ ok = await aio .run_fn (provider .playlist_delete , playlist .identifier )
255
+ self ._app .show_msg (f"删除歌单 { playlist .name } { '成功' if ok else '失败' } " )
256
+ if ok is True :
257
+ self ._app .pl_uimgr .model .remove (playlist )
258
+ else :
259
+ self ._app .show_msg (f'资源提供方({ provider .identifier } )不支持删除歌单' )
260
+
261
+ box = QMessageBox (QMessageBox .Warning , '提示' , f"确认删除歌单 '{ playlist .name } ' 吗?" ,
262
+ QMessageBox .Yes | QMessageBox .No , self )
263
+ box .accepted .connect (lambda : aio .run_afn (do ))
264
+ box .open ()
265
+
266
+ def _remove_coll (self , coll ):
267
+
196
268
def do ():
197
269
self ._app .coll_mgr .remove (coll )
198
270
self ._app .coll_mgr .refresh ()
0 commit comments