From 3c018e30bd89007e265271360e2fa25106d88ab5 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Sun, 21 Jan 2024 12:12:08 +0100 Subject: [PATCH] add search bar --- .../clan_vm_manager/models/use_views.py | 4 + .../clan_vm_manager/models/use_vms.py | 16 ++- .../clan-vm-manager/clan_vm_manager/style.css | 8 ++ .../clan_vm_manager/views/list.py | 18 ++- .../clan_vm_manager/views/trust_join.py | 135 ------------------ .../clan_vm_manager/windows/main_window.py | 2 + 6 files changed, 44 insertions(+), 139 deletions(-) delete mode 100644 pkgs/clan-vm-manager/clan_vm_manager/views/trust_join.py diff --git a/pkgs/clan-vm-manager/clan_vm_manager/models/use_views.py b/pkgs/clan-vm-manager/clan_vm_manager/models/use_views.py index 6407da27b..0c87d1d66 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/models/use_views.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/models/use_views.py @@ -22,6 +22,7 @@ class Views: _instance: "None | Views" = None view: Adw.ViewStack + main_window: Adw.ApplicationWindow = None # Make sure the VMS class is used as a singleton def __init__(self) -> None: @@ -35,3 +36,6 @@ class Views: cls.view = Adw.ViewStack() return cls._instance + + def set_main_window(self, window: Adw.ApplicationWindow) -> None: + self.main_window = window diff --git a/pkgs/clan-vm-manager/clan_vm_manager/models/use_vms.py b/pkgs/clan-vm-manager/clan_vm_manager/models/use_vms.py index 33647cd68..47bae5364 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/models/use_vms.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/models/use_vms.py @@ -123,10 +123,20 @@ class VMS: cls._instance = cls.__new__(cls) cls.list_store = Gio.ListStore.new(VM) - for vm in get_initial_vms(): + for vm in get_saved_vms(): cls.list_store.append(vm) return cls._instance + def filter_by_name(self, text: str) -> None: + if text: + filtered_list = self.list_store + filtered_list.remove_all() + for vm in get_saved_vms(): + if text.lower() in vm.data.flake.clan_name.lower(): + filtered_list.append(vm) + else: + self.refresh() + def handle_vm_stopped(self, func: Callable[[VM, VM], None]) -> None: for vm in self.list_store: vm.connect("vm_stopped", func) @@ -144,11 +154,11 @@ class VMS: def refresh(self) -> None: self.list_store.remove_all() - for vm in get_initial_vms(): + for vm in get_saved_vms(): self.list_store.append(vm) -def get_initial_vms() -> list[VM]: +def get_saved_vms() -> list[VM]: vm_list = [] try: diff --git a/pkgs/clan-vm-manager/clan_vm_manager/style.css b/pkgs/clan-vm-manager/clan_vm_manager/style.css index 7413c62a0..0539043b1 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/style.css +++ b/pkgs/clan-vm-manager/clan_vm_manager/style.css @@ -25,6 +25,14 @@ avatar { box-shadow: none; } +.search-entry { + margin-bottom: 12px; +} + +searchbar { + margin-bottom: 25px; +} + /* TODO: Disable shadow for empty lists */ /* list:empty { box-shadow: none; diff --git a/pkgs/clan-vm-manager/clan_vm_manager/views/list.py b/pkgs/clan-vm-manager/clan_vm_manager/views/list.py index 285477924..bb033a610 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/views/list.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/views/list.py @@ -5,6 +5,7 @@ import gi from clan_cli.history.add import HistoryEntry from clan_vm_manager.models.use_join import Join, JoinValue +from clan_vm_manager.models.use_views import Views gi.require_version("Adw", "1") from gi.repository import Adw, Gdk, Gio, GObject, Gtk @@ -57,16 +58,31 @@ class ClanList(Gtk.Box): ) self.vm_boxed_list.add_css_class("vm-list") + search_bar = Gtk.SearchBar() + # This widget will typically be the top-level window + search_bar.set_key_capture_widget(Views.use().main_window) + entry = Gtk.SearchEntry() + entry.set_placeholder_text("Search cLan") + entry.connect("search-changed", self.on_search_changed) + entry.add_css_class("search-entry") + search_bar.set_child(entry) + + self.append(search_bar) self.append(self.join_boxed_list) self.append(self.vm_boxed_list) + def on_search_changed(self, entry: Gtk.SearchEntry) -> None: + VMS.use().filter_by_name(entry.get_text()) + # Disable the shadow if the list is empty + if not VMS.use().list_store.get_n_items(): + self.vm_boxed_list.add_css_class("no-shadow") + def render_vm_row(self, boxed_list: Gtk.ListBox, item: VM) -> Gtk.Widget: if boxed_list.has_css_class("no-shadow"): boxed_list.remove_css_class("no-shadow") flake = item.data.flake row = Adw.ActionRow() - print("Creating", item.data.flake.flake_attr) # Title row.set_title(flake.clan_name) diff --git a/pkgs/clan-vm-manager/clan_vm_manager/views/trust_join.py b/pkgs/clan-vm-manager/clan_vm_manager/views/trust_join.py deleted file mode 100644 index d0b69d277..000000000 --- a/pkgs/clan-vm-manager/clan_vm_manager/views/trust_join.py +++ /dev/null @@ -1,135 +0,0 @@ -from functools import partial - -import gi -from clan_cli.errors import ClanError -from clan_cli.history.add import add_history - -from clan_vm_manager.errors.show_error import show_error_dialog -from clan_vm_manager.models.use_join import JoinValue - -gi.require_version("Gtk", "4.0") -gi.require_version("Adw", "1") - - -from gi.repository import Adw, Gio, GObject, Gtk - - -class TrustValues(GObject.Object): - data: JoinValue - - def __init__(self, data: JoinValue) -> None: - super().__init__() - print("TrustValues", data) - self.data = data - - -class Trust(Gtk.Box): - def __init__( - self, - ) -> None: - super().__init__(orientation=Gtk.Orientation.VERTICAL) - - # self.on_trust = on_trust - # self.url: ClanURI | None = Join.use(). - - def render(item: TrustValues) -> Gtk.Widget: - row = Adw.ActionRow() - row.set_title(str(item.data.url)) - row.add_css_class("trust") - - avatar = Adw.Avatar() - avatar.set_text(str(item.data.url)) - avatar.set_show_initials(True) - avatar.set_size(50) - row.add_prefix(avatar) - - cancel_button = Gtk.Button(label="Cancel") - cancel_button.add_css_class("error") - - trust_button = Gtk.Button(label="Join") - trust_button.add_css_class("success") - trust_button.connect("clicked", partial(self.on_trust_clicked, item.data)) - - box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) - box.set_valign(Gtk.Align.CENTER) - box.append(cancel_button) - box.append(trust_button) - - # switch.connect("notify::active", partial(self.on_row_toggle, item.data)) - row.add_suffix(box) - - return row - - boxed_list = Gtk.ListBox() - boxed_list.set_selection_mode(Gtk.SelectionMode.NONE) - boxed_list.add_css_class("boxed-list") - - list_store = Gio.ListStore.new(TrustValues) - # list_store.append(TrustValues(data=initial_values)) - - # icon = Gtk.Image.new_from_pixbuf( - # GdkPixbuf.Pixbuf.new_from_file_at_scale( - # filename=str(assets.loc / "placeholder.jpeg"), - # width=256, - # height=256, - # preserve_aspect_ratio=True, - # ) - # ) - - boxed_list.bind_model(list_store, create_widget_func=render) - - self.append(boxed_list) - - # layout = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - # # layout.set_border_width(20) - # layout.set_spacing(20) - - # if self.url is not None: - # self.entry = Gtk.Label(label=str(self.url)) - # layout.append(icon) - # layout.append(Gtk.Label(label="Clan URL")) - # else: - # layout.append(Gtk.Label(label="Enter Clan URL")) - # self.entry = Gtk.Entry() - # # Autocomplete - # # TODO: provide intelligent suggestions - # completion_list = Gtk.ListStore(str) - # completion_list.append(["clan://"]) - # completion = Gtk.EntryCompletion() - # completion.set_model(completion_list) - # completion.set_text_column(0) - # completion.set_popup_completion(False) - # completion.set_inline_completion(True) - - # self.entry.set_completion(completion) - # self.entry.set_placeholder_text("clan://") - - # layout.append(self.entry) - - # if self.url is None: - # trust_button = Gtk.Button(label="Load cLAN-URL") - # else: - # trust_button = Gtk.Button(label="Trust cLAN-URL") - - # trust_button.connect("clicked", self.on_trust_clicked) - # layout.append(trust_button) - - def on_trust_clicked(self, item: JoinValue, widget: Gtk.Widget) -> None: - try: - uri = item.url - # or ClanURI(self.entry.get_text()) - print(f"trusted: {uri}") - if uri: - add_history(uri) - # history = list_history() - - # found = filter( - # lambda item: item.flake.flake_url == uri.get_internal(), history - # ) - # if found: - # [item] = found - # self.on_trust(uri.get_internal(), item.flake) - - except ClanError as e: - pass - show_error_dialog(e) diff --git a/pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py b/pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py index 4cfd07b8d..d75f65c2b 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py @@ -23,6 +23,8 @@ class MainWindow(Adw.ApplicationWindow): # Initialize all views stack_view = Views.use().view + Views.use().set_main_window(self) + stack_view.add_named(ClanList(), "list") stack_view.set_visible_child_name(config.initial_view)