@@ 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()
@@ 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"))
@@ 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):