[gnome-music/wip/jfelder/playlists-core-rewrite-prep-work: 3/21] playlists: Manage playlists deletion list internally



commit 85a587947921031a37bf4805100f209e8710cc53
Author: Jean Felder <jfelder src gnome org>
Date:   Thu May 16 16:07:33 2019 +0200

    playlists: Manage playlists deletion list internally
    
    There are two types of playlists:
     - smart playlists: directly retrieved by tracker, they need to be
     created if they don't already exist
     - user playlists which are created by the user. They can be retrieved
     from Grilo (all_user_playlists function)
    
    User playlists can be deleted from the PlaylistsView and
    PlaylistDialog needs the list of the playlists which are about to be
    deleted in order to prevent the user from adding songs to a playlist
    which is about to be deleted. This results in some strange logic being
    exposed in the main Window class.
    
    This whole logic can be simplified by directly managing playlists
    deletion in the Playlists class.
    This will also make things easier once the Playlists model is handled
    by Playlists.

 gnomemusic/playlists.py                  | 46 +++++++++++++++++++++++++---
 gnomemusic/views/playlistsview.py        | 51 ++++++++++++++------------------
 gnomemusic/widgets/notificationspopup.py |  4 +--
 gnomemusic/widgets/playlistdialog.py     |  8 ++---
 gnomemusic/window.py                     |  3 +-
 5 files changed, 71 insertions(+), 41 deletions(-)
---
diff --git a/gnomemusic/playlists.py b/gnomemusic/playlists.py
index 60fa7611..86327f3d 100644
--- a/gnomemusic/playlists.py
+++ b/gnomemusic/playlists.py
@@ -113,7 +113,7 @@ class Playlists(GObject.GObject):
             GObject.SignalFlags.RUN_FIRST, None, (Grl.Media,)
         ),
         'playlist-deleted': (
-            GObject.SignalFlags.RUN_FIRST, None, (Grl.Media,)
+            GObject.SignalFlags.RUN_FIRST, None, (str,)
         ),
         'playlist-updated': (
             GObject.SignalFlags.RUN_FIRST, None, (int,)
@@ -145,6 +145,7 @@ class Playlists(GObject.GObject):
         super().__init__()
 
         self._smart_playlists = SmartPlaylists()
+        self._pls_todelete = {}
 
         grilo.connect('ready', self._on_grilo_ready)
 
@@ -369,13 +370,18 @@ class Playlists(GObject.GObject):
             None, update_callback, None)
 
     @log
-    def delete_playlist(self, item):
+    def delete_playlist(self, item_id):
+        """Deletes a user playlist
+
+        :param str item_id: Playlist id to delete
+        """
         def update_callback(conn, res, data):
             conn.update_finish(res)
-            self.emit('playlist-deleted', item)
+            self.emit('playlist-deleted', item_id)
 
+        self._pls_todelete.pop(item_id)
         self._tracker.update_async(
-            Query.delete_playlist(item.get_id()), GLib.PRIORITY_LOW,
+            Query.delete_playlist(item_id), GLib.PRIORITY_LOW,
             None, update_callback, None)
 
     @log
@@ -460,3 +466,35 @@ class Playlists(GObject.GObject):
         """
         # FIXME: just a proxy
         self.emit('activate-playlist', playlist_id)
+
+    @log
+    def stage_playlist_for_deletion(self, playlist, index):
+        """Adds a playlist to the list of playlists to delete
+
+        :param Grl.Media playlist: playlist to delete
+        :param int index: Playlist position in PlaylistView
+        """
+        playlist_id = playlist.get_id()
+        self._pls_todelete[playlist_id] = {
+            'playlist': playlist,
+            'index': index
+        }
+
+    @log
+    def undo_pending_deletion(self, playlist):
+        """Undo pending playlist deletion
+
+        :param Grl.Media playlist: playlist to restore
+        :returns: playlist previous index
+        :rtype: int
+        """
+        playlist_id = playlist.get_id()
+        index = self._pls_todelete[playlist_id]["index"]
+        self._pls_todelete.pop(playlist_id)
+
+        return index
+
+    @log
+    def get_playlists_to_delete(self):
+        """Gets playlists ids ready for deletion"""
+        return self._pls_todelete.keys()
diff --git a/gnomemusic/views/playlistsview.py b/gnomemusic/views/playlistsview.py
index 1649841e..2e0f30bc 100644
--- a/gnomemusic/views/playlistsview.py
+++ b/gnomemusic/views/playlistsview.py
@@ -117,7 +117,6 @@ class PlaylistsView(BaseView):
         self._iter_to_clean_model = None
         self._current_playlist = None
         self._plays_songs_on_activation = False
-        self.pls_todelete = {}
         self._songs_todelete = {}
         self._songs_count = 0
 
@@ -450,8 +449,7 @@ class PlaylistsView(BaseView):
         model, _iter = self._view.get_selection().get_selected()
         song = model[_iter][5]
 
-        playlist_dialog = PlaylistDialog(
-            self._window, self.pls_todelete)
+        playlist_dialog = PlaylistDialog(self._window)
         if playlist_dialog.run() == Gtk.ResponseType.ACCEPT:
             playlists.add_to_playlist(playlist_dialog.get_selected(), [song])
         playlist_dialog.destroy()
@@ -609,7 +607,7 @@ class PlaylistsView(BaseView):
         return playlist.get_id() == self._current_playlist.get_id()
 
     @log
-    def _get_removal_notification_message(self, type_, media_id):
+    def _get_removal_notification_message(self, type_, data):
         """ Returns a label for the playlist notification popup
 
         Handles two cases:
@@ -619,12 +617,13 @@ class PlaylistsView(BaseView):
         msg = ""
 
         if type_ == PlaylistNotification.Type.PLAYLIST:
-            pl_todelete = self.pls_todelete[media_id]
-            playlist_title = utils.get_media_title(pl_todelete['playlist'])
+            pl_todelete = data
+            playlist_title = utils.get_media_title(pl_todelete)
             msg = _("Playlist {} removed".format(playlist_title))
 
         else:
-            song_todelete = self._songs_todelete[media_id]
+            song_id = data
+            song_todelete = self._songs_todelete[song_id]
             playlist_title = utils.get_media_title(song_todelete['playlist'])
             song_title = utils.get_media_title(song_todelete['song'])
             msg = _("{} removed from {}".format(
@@ -633,10 +632,10 @@ class PlaylistsView(BaseView):
         return msg
 
     @log
-    def _create_notification(self, type_, media_id):
-        msg = self._get_removal_notification_message(type_, media_id)
+    def _create_notification(self, type_, data):
+        msg = self._get_removal_notification_message(type_, data)
         playlist_notification = PlaylistNotification(
-            self._window.notifications_popup, type_, msg, media_id)
+            self._window.notifications_popup, type_, msg, data)
         playlist_notification.connect(
             'undo-deletion', self._undo_pending_deletion)
         playlist_notification.connect(
@@ -648,10 +647,7 @@ class PlaylistsView(BaseView):
         selection = self._sidebar.get_selected_row()
         index = selection.get_index()
         playlist_id = self._current_playlist.get_id()
-        self.pls_todelete[playlist_id] = {
-            'playlist': selection.playlist,
-            'index': index
-        }
+        playlists.stage_playlist_for_deletion(selection.playlist, index)
         row_next = (self._sidebar.get_row_at_index(index + 1)
                     or self._sidebar.get_row_at_index(index - 1))
         self._sidebar.remove(selection)
@@ -666,23 +662,22 @@ class PlaylistsView(BaseView):
             row_next.emit('activate')
 
         self._create_notification(
-            PlaylistNotification.Type.PLAYLIST, playlist_id)
+            PlaylistNotification.Type.PLAYLIST, selection.playlist)
 
     @log
     def _undo_pending_deletion(self, playlist_notification):
         """Revert the last playlist removal"""
         notification_type = playlist_notification.type_
-        media_id = playlist_notification.media_id
 
         if notification_type == PlaylistNotification.Type.PLAYLIST:
-            pl_todelete = self.pls_todelete[media_id]
-            self._add_playlist_to_sidebar(
-                pl_todelete['playlist'], pl_todelete['index'])
-            self.pls_todelete.pop(media_id)
+            pl_todelete = playlist_notification.data
+            index = playlists.undo_pending_deletion(pl_todelete)
+            self._add_playlist_to_sidebar(pl_todelete, index)
 
         else:
-            song_todelete = self._songs_todelete[media_id]
-            self._songs_todelete.pop(media_id)
+            song_id = playlist_notification.data
+            song_todelete = self._songs_todelete[song_id]
+            self._songs_todelete.pop(song_id)
             if not self._is_current_playlist(song_todelete['playlist']):
                 return
 
@@ -700,18 +695,16 @@ class PlaylistsView(BaseView):
     @log
     def _finish_pending_deletion(self, playlist_notification):
         notification_type = playlist_notification.type_
-        media_id = playlist_notification.media_id
 
         if notification_type == PlaylistNotification.Type.PLAYLIST:
-            pl_todelete = self.pls_todelete[media_id]
-            playlists.delete_playlist(pl_todelete['playlist'])
-            self.pls_todelete.pop(media_id)
-
+            pl_todelete = playlist_notification.data
+            playlists.delete_playlist(pl_todelete.get_id())
         else:
-            song_todelete = self._songs_todelete[media_id]
+            song_id = playlist_notification.data
+            song_todelete = self._songs_todelete[song_id]
             playlists.remove_from_playlist(
                 song_todelete['playlist'], [song_todelete['song']])
-            self._songs_todelete.pop(media_id)
+            self._songs_todelete.pop(song_id)
 
     @GObject.Property(type=bool, default=False)
     def rename_active(self):
diff --git a/gnomemusic/widgets/notificationspopup.py b/gnomemusic/widgets/notificationspopup.py
index a3667be2..08b2750a 100644
--- a/gnomemusic/widgets/notificationspopup.py
+++ b/gnomemusic/widgets/notificationspopup.py
@@ -220,11 +220,11 @@ class PlaylistNotification(Gtk.Grid):
         return '<PlaylistNotification>'
 
     @log
-    def __init__(self, notifications_popup, type_, message, media_id):
+    def __init__(self, notifications_popup, type_, message, data):
         super().__init__(column_spacing=18)
         self._notifications_popup = notifications_popup
         self.type_ = type_
-        self.media_id = media_id
+        self.data = data
 
         self._label = Gtk.Label(
             label=message, halign=Gtk.Align.START, hexpand=True)
diff --git a/gnomemusic/widgets/playlistdialog.py b/gnomemusic/widgets/playlistdialog.py
index fc9ab023..0635635e 100644
--- a/gnomemusic/widgets/playlistdialog.py
+++ b/gnomemusic/widgets/playlistdialog.py
@@ -52,7 +52,7 @@ class PlaylistDialog(Gtk.Dialog):
         return '<PlaylistDialog>'
 
     @log
-    def __init__(self, parent, playlists_todelete):
+    def __init__(self, parent):
         super().__init__()
 
         self._add_playlist_button = None
@@ -60,14 +60,14 @@ class PlaylistDialog(Gtk.Dialog):
 
         self.props.transient_for = parent
         self.set_titlebar(self._title_bar)
-        self._populate()
-
-        self._playlists_todelete_ids = playlists_todelete.keys()
 
         self._user_playlists_available = False
         self._playlist = Playlists.get_default()
+        self._playlists_todelete_ids = self._playlist.get_playlists_to_delete()
         self._playlist.connect('playlist-created', self._on_playlist_created)
 
+        self._populate()
+
     @log
     def get_selected(self):
         """Get the selected playlist"""
diff --git a/gnomemusic/window.py b/gnomemusic/window.py
index 7b7141dc..6e747cbd 100644
--- a/gnomemusic/window.py
+++ b/gnomemusic/window.py
@@ -490,8 +490,7 @@ class Window(Gtk.ApplicationWindow):
             if len(selected_songs) < 1:
                 return
 
-            playlist_dialog = PlaylistDialog(
-                self, self.views[View.PLAYLIST].pls_todelete)
+            playlist_dialog = PlaylistDialog(self)
             if playlist_dialog.run() == Gtk.ResponseType.ACCEPT:
                 playlists.add_to_playlist(
                     playlist_dialog.get_selected(), selected_songs)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]