~comcloudway/melon

9d70ecd65e78b9d5062406f967a5537c588120f2 — Jakob Meier 6 months ago d38fdc6
implement multi-value preferencerow
3 files changed, 175 insertions(+), 46 deletions(-)

M melon/playlist/pick.py
M melon/widgets/preferencerow.py
M melon/widgets/simpledialog.py
M melon/playlist/pick.py => melon/playlist/pick.py +1 -1
@@ 2,7 2,7 @@ import sys
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk, Adw, Gio, GLib
from gi.repository import Gtk, Adw, Gio, GLib, Gdk

from melon.widgets.feeditem import AdaptiveFeedItem
from melon.widgets.iconbutton import IconButton

M melon/widgets/preferencerow.py => melon/widgets/preferencerow.py +171 -44
@@ 6,6 6,8 @@ from gi.repository import Gtk, Adw, GLib, Gdk
from melon.servers import Resource,Video,Playlist,Channel,Preference,PreferenceType
from melon.servers.utils import pixbuf_from_url
from melon.widgets.iconbutton import IconButton
from melon.widgets.simpledialog import SimpleDialog
from copy import deepcopy as copy

class PreferenceRow():
    def __init__(self, pref: Preference, *args, **kwargs):


@@ 62,49 64,8 @@ class PreferenceRow():
                lambda a: self.pass_to_callback(self.widget.get_value())
            )
        elif pref.type is PreferenceType.MULTI:
            self.widget = Adw.PreferencesRow()
            self.inner = Adw.PreferencesGroup()
            padding = 12
            self.inner.set_margin_top(padding)
            self.inner.set_margin_bottom(padding)
            self.inner.set_margin_start(padding)
            self.inner.set_margin_end(padding)
            self.widget.set_child(self.inner)
            self.inner.set_title(pref.name)
            self.inner.set_description(pref.description)
            self.children = []
            # TODO: implement functionality
            self.adder = IconButton("Add", "list-add-symbolic")
            self.inner.set_header_suffix(self.adder)
            counter = 0
            length = len(self.pref.value)
            for item in self.pref.value:
                row = Adw.ActionRow()
                row.set_title(item)
                actions = Gtk.Box()
                # move up button
                if counter > 0:
                    # TODO: implement functionality
                    move_up = IconButton("","go-up-symbolic")
                    move_up.set_tooltip_text("Move up")
                    move_up.add_css_class("circular")
                    actions.append(move_up)
                if counter < length-1:
                    # TODO: implement functionality
                    move_down = IconButton("", "go-down-symbolic")
                    move_down.set_tooltip_text("Move down")
                    move_down.add_css_class("circular")
                    actions.append(move_down)
                counter += 1
                # TODO: implement functionality
                remove = IconButton("", "list-remove-symbolic")
                remove.set_tooltip_text("Remove from list")
                remove.add_css_class("circular")
                actions.append(remove)
                row.add_suffix(actions)
                # store rows in seperate list to make removing them possible
                self.children.append(row)
                self.inner.add(row)
            self.widget = MultiRow(pref)
            self.widget.connect(lambda v: self.pass_to_callback(v))
        else:
            # shouldn't be reachable
            self.widget = Adw.ActionRow()


@@ 117,7 78,7 @@ class PreferenceRow():
            # that the callback would be called multiple times,
            # because the "notify" signal might be called more than once
            return
        self.current_value = value
        self.current_value = copy(value)
        if not self.callback is None:
            self.callback(value)
    def get_widget(self):


@@ 127,3 88,169 @@ class PreferenceRow():
    def on_active(self):
        if not self.callback is None:
            self.callback(self.get_active())

class MultiRow(Adw.PreferencesRow):
    callback = None
    values = []
    def __init__(self, pref, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.pref = pref
        self.values = copy(pref.value)
        self.update()
    def connect(self, cb):
        self.callback = cb
    def update(self):
        self.inner = Adw.PreferencesGroup()
        padding = 12
        self.inner.set_margin_top(padding)
        self.inner.set_margin_bottom(padding)
        self.inner.set_margin_start(padding)
        self.inner.set_margin_end(padding)
        self.set_child(self.inner)
        self.inner.set_title(self.pref.name)
        self.inner.set_description(self.pref.description)
        self.adder = IconButton("Add", "list-add-symbolic")
        self.adder.connect("clicked", lambda x: self.open_add())
        self.inner.set_header_suffix(self.adder)
        counter = 0
        length = len(self.values)
        # create items list
        for item in self.values:
            row = Adw.ActionRow()
            row.set_title(item)
            actions = Gtk.Box()
            # move up button
            # not shown for first element
            if counter > 0:
                move_up = IconButton("","go-up-symbolic")
                move_up.set_tooltip_text("Move up")
                move_up.add_css_class("circular")
                move_up.connect(
                    "clicked",
                    pass_me(self.move_up, item, counter)
                )
                actions.append(move_up)
            # move down button
            # not shown for last element
            if counter < length-1:
                move_down = IconButton("", "go-down-symbolic")
                move_down.set_tooltip_text("Move down")
                move_down.add_css_class("circular")
                move_down.connect(
                    "clicked",
                    pass_me(self.move_down, item, counter)
                )
                actions.append(move_down)
            # remove button
            remove = IconButton("", "list-remove-symbolic")
            remove.set_tooltip_text("Remove from list")
            remove.add_css_class("circular")
            remove.connect("clicked", pass_me(self.confirm_delete, item, counter))
            actions.append(remove)
            row.add_suffix(actions)
            self.inner.add(row)
            counter += 1
    def notify(self):
        if not self.callback is None:
            self.callback(copy(self.values))
        self.update()
    def open_add(self):
        diag = SimpleDialog()
        diag.set_title("Add Item")
        # preview prferences group
        box = Adw.PreferencesGroup();
        box.set_title("Create a new list entry")
        box.set_description("Enter the new value here")
        # text input
        inp = Adw.EntryRow()
        inp.set_title("Value")
        box.add(inp)
        diag.set_widget(box)
        # place button bar in toolbar
        bottom_bar = Gtk.Box()
        btn_cancel = IconButton("Cancel", "process-stop-symbolic", tooltip="Do not create a new item")
        btn_confirm = IconButton("Create", "list-add-symbolic", tooltip="Add entry to list")
        btn_confirm.connect(
            "clicked",
            lambda _: many(
                self.values.append(inp.get_text()),
                self.notify(),
                diag.hide())
        )
        btn_cancel.connect(
            "clicked",
            lambda x: 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)
        diag.toolbar_view.add_bottom_bar(bottom_bar)

        diag.show()
    def confirm_delete(self, _, item:str, counter:int):
        diag = SimpleDialog()
        diag.set_title("Delete")
        # preview prferences group
        preview = Adw.PreferencesGroup();
        preview.set_title("Do you really want to delete this item?")
        preview.set_description("You won't be able to restore it afterwards")
        row = Adw.ActionRow()
        row.set_title(item)
        preview.add(row)
        diag.set_widget(preview)
        # place button bar in toolbar
        bottom_bar = Gtk.Box()
        btn_cancel = IconButton("Cancel", "process-stop-symbolic", tooltip="Do not remove item")
        btn_confirm = IconButton("Delete", "list-add-symbolic", tooltip="Remove item from list")
        btn_confirm.connect(
            "clicked",
            lambda _: many(
                self.values.pop(counter),
                self.notify(),
                diag.hide())
        )
        btn_cancel.connect(
            "clicked",
            lambda x: 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)
        diag.toolbar_view.add_bottom_bar(bottom_bar)
        diag.show()
        pass
    def move_up(self, _, item:str, counter:int):
        val = self.values.pop(counter)
        self.values.insert(counter-1, val)
        self.notify()
    def move_down(self, _, item:str, counter:int):
        val = self.values.pop(counter)
        self.values.insert(counter+1, val)
        self.notify()

def pass_me(func, *args):
    return lambda *a: func(*a, *args)
def many(*funcs):
    return [funcs]

M melon/widgets/simpledialog.py => melon/widgets/simpledialog.py +3 -1
@@ 14,8 14,10 @@ class SimpleDialog(Adw.Window):
        self.set_content(self.toolbar_view)
    def set_title(self, text):
        self.title.set_title(text)
    def set_widget(self, child):
    def set_widget(self, child,padding=12):
        self.toolbar_view.set_content(child)
        child.set_margin_end(padding)
        child.set_margin_start(padding)
    def show(self):
        self.set_visible(True)
    def hide(self):