From a3d902414456383664c76261dc79e0ed939826fd Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Sun, 3 Mar 2024 15:33:43 +0100 Subject: [PATCH] add edit button for local playlists The edit screen allows the user to change the playlist name and description. Additionally it allows the user the delete the playlist. A confirmation dialog is shown before actually deleting the playlist. Once confirmed, the playlist screen is closed and then the playlist is deleted. This is done, so that the playlist-change doesn't reach the playlist viewer --- melon/playlist/__init__.py | 136 +++++++++++++++++++++++++++++++++- melon/playlist/create.py | 2 +- melon/widgets/simpledialog.py | 3 + 3 files changed, 137 insertions(+), 4 deletions(-) diff --git a/melon/playlist/__init__.py b/melon/playlist/__init__.py index 721bcf2..9abfce2 100644 --- a/melon/playlist/__init__.py +++ b/melon/playlist/__init__.py @@ -10,7 +10,8 @@ from melon.servers.utils import get_servers_list, get_server_instance from melon.servers import Preference, PreferenceType from melon.widgets.iconbutton import IconButton from melon.widgets.feeditem import AdaptiveFeedItem -from melon.models import get_app_settings, get_local_playlist +from melon.widgets.simpledialog import SimpleDialog +from melon.models import get_app_settings, get_local_playlist, PlaylistWrapper, ensure_playlist, ensure_delete_local_playlist from melon.models import is_server_enabled, ensure_server_disabled, ensure_server_enabled class LocalPlaylistScreen(Adw.NavigationPage): @@ -18,7 +19,11 @@ class LocalPlaylistScreen(Adw.NavigationPage): super().__init__(*args, **kwargs) app_conf = get_app_settings() - playlist = get_local_playlist(playlist_id) + self.playlist = get_local_playlist(playlist_id) + self.update() + + def update(self): + playlist = self.playlist self.set_title(playlist.title) @@ -30,6 +35,10 @@ class LocalPlaylistScreen(Adw.NavigationPage): self.wrapper = Adw.Clamp() self.scrollview = Gtk.ScrolledWindow() + # the edit button should be displayed on both screens + edit_button = IconButton(_("Edit"), "document-edit-symbolic") + edit_button.connect("clicked", lambda _: self.open_edit()) + if len(playlist.content) == 0: status = Adw.StatusPage() status.set_title(_("*crickets chirping*")) @@ -38,7 +47,11 @@ class LocalPlaylistScreen(Adw.NavigationPage): icon_button = IconButton(_("Start watching"), "video-display-symbolic") icon_button.set_action_name("win.home") box = Gtk.CenterBox() - box.set_center_widget(icon_button) + col = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + col.append(icon_button) + icon_button.set_margin_bottom(6) + col.append(edit_button) + box.set_center_widget(col) status.set_child(box) self.box = status else: @@ -47,6 +60,7 @@ class LocalPlaylistScreen(Adw.NavigationPage): group = Adw.PreferencesGroup() group.set_title(unidecode(playlist.title)) group.set_description(unidecode(playlist.description)) + group.set_header_suffix(edit_button) app_conf = get_app_settings() self.box.add(group) # add playlist content to group as well @@ -57,3 +71,119 @@ class LocalPlaylistScreen(Adw.NavigationPage): self.wrapper.set_child(self.scrollview) self.toolbar_view.set_content(self.wrapper) self.set_child(self.toolbar_view) + + def open_edit(self): + self.edit_diag = SimpleDialog() + self.edit_diag.set_title(_("Edit Playlist")) + + page = Adw.PreferencesPage() + + # preference group for input + input_group = Adw.PreferencesGroup() + input_group.set_title(_("Playlist details")) + input_group.set_description(_("Change playlist information")) + self.input_title = Adw.EntryRow() + self.input_title.set_title(_("Playlist name")) + self.input_title.set_text(self.playlist.title) + self.input_desc = Adw.EntryRow() + self.input_desc.set_title(_("Playlist description")) + self.input_desc.set_text(self.playlist.description) + input_group.add(self.input_title) + input_group.add(self.input_desc) + save_btn = Adw.ActionRow() + save_btn.set_title(_("Save details")) + save_btn.set_subtitle(_("Change playlist title and description. (Closes the dialog)")) + save_btn.add_suffix(Gtk.Image.new_from_icon_name("go-next-symbolic")) + save_btn.set_activatable(True) + save_btn.connect("activated", lambda _: self.save_details()) + input_group.add(save_btn) + page.add(input_group) + + # preference group for dangerous stuff + dgroup = Adw.PreferencesGroup() + delete_btn = Adw.ActionRow() + delete_btn.set_title(_("Delete Playlist")) + delete_btn.set_subtitle(_("Delete this playlist and it's content. This can NOT be undone.")) + delete_btn.add_suffix(Gtk.Image.new_from_icon_name("go-next-symbolic")) + delete_btn.set_activatable(True) + delete_btn.connect("activated", lambda _: self.confirm_delete()) + dgroup.add(delete_btn) + page.add(dgroup) + + # bottom bar with close button + # to manually close the dialog + # without applying changes + bottom_bar = Gtk.Box() + btn_cancel = IconButton(_("Close"), "process-stop-symbolic", tooltip=_("Close without chaning anything")) + btn_cancel.connect( + "clicked", + lambda x: self.edit_diag.hide()) + padding = 12 + btn_cancel.set_vexpand(True) + btn_cancel.set_hexpand(True) + btn_cancel.set_margin_start(padding) + btn_cancel.set_margin_end(padding) + btn_cancel.set_margin_top(padding) + btn_cancel.set_margin_bottom(padding) + bottom_bar.append(btn_cancel) + self.edit_diag.toolbar_view.add_bottom_bar(bottom_bar) + + self.edit_diag.set_widget(page) + self.edit_diag.show() + + def save_details(self): + self.playlist.title = self.input_title.get_text() + self.playlist.description = self.input_desc.get_text() + wrap = PlaylistWrapper.from_local(self.playlist) + ensure_playlist(wrap) + self.update() + self.edit_diag.hide() + + def confirm_delete(self): + # close edit dialog + self.edit_diag.hide() + # show delete confirmation dialog + self.dlt_diag = SimpleDialog() + self.dlt_diag.set_title(_("Delete Playlist")) + + info = Adw.PreferencesGroup() + info.set_title(_("Do you really wan't to delete this playlist?")) + info.set_description(_("This cannot be undone")) + self.dlt_diag.set_widget(info) + + bottom_bar = Gtk.Box() + btn_cancel = IconButton(_("Cancel"), "process-stop-symbolic", tooltip=_("Do not delete the playlist")) + btn_confirm = IconButton(_("Delete"), "list-add-symbolic", tooltip=_("Delete this playlist")) + btn_confirm.connect( + "clicked", + lambda _: self.delete() + ) + btn_cancel.connect( + "clicked", + lambda _: self.dlt_diag.hide()) + + padding = 12 + btn_confirm.set_vexpand(True) + btn_confirm.set_hexpand(True) + btn_confirm.set_margin_end(padding) + btn_confirm.set_margin_start(padding/2) + btn_confirm.set_margin_top(padding) + btn_confirm.set_margin_bottom(padding) + btn_cancel.set_vexpand(True) + btn_cancel.set_hexpand(True) + btn_cancel.set_margin_start(padding) + btn_cancel.set_margin_end(padding/2) + btn_cancel.set_margin_top(padding) + btn_cancel.set_margin_bottom(padding) + bottom_bar.append(btn_cancel) + bottom_bar.append(btn_confirm) + self.dlt_diag.toolbar_view.add_bottom_bar(bottom_bar) + + self.dlt_diag.show() + + def delete(self): + # go home and delete afterwards + # so that the reload/callback doesn't trigger + self.activate_action("win.home", None) + ensure_delete_local_playlist(self.playlist.id) + self.dlt_diag.hide() diff --git a/melon/playlist/create.py b/melon/playlist/create.py index d3ebd1a..bfbafe4 100644 --- a/melon/playlist/create.py +++ b/melon/playlist/create.py @@ -35,7 +35,7 @@ class PlaylistCreatorDialog(SimpleDialog): input_group.set_description(_("Enter more playlist information")) self.input_title = Adw.EntryRow() - self.input_title.set_title(_("Playlist Name")) + self.input_title.set_title(_("Playlist name")) self.input_title.set_text(_("Unnamed Playlist")) self.input_desc = Adw.EntryRow() self.input_desc.set_title(_("Playlist description")) diff --git a/melon/widgets/simpledialog.py b/melon/widgets/simpledialog.py index f7b32e3..cf8e7f6 100644 --- a/melon/widgets/simpledialog.py +++ b/melon/widgets/simpledialog.py @@ -12,6 +12,9 @@ class SimpleDialog(Adw.Window): self.header_bar.set_title_widget(self.title) self.toolbar_view.add_top_bar(self.header_bar) self.set_content(self.toolbar_view) + # this is a dialog and thus the main window should not be usable + # when the dialog is opened + self.set_modal(True) def set_title(self, text): self.title.set_title(text) def set_widget(self, child,padding=12): -- 2.38.5