diff --git a/src/install_page/install_page.blp b/src/install_page/install_page.blp index 2165e85..a877a06 100644 --- a/src/install_page/install_page.blp +++ b/src/install_page/install_page.blp @@ -125,6 +125,9 @@ template $InstallPage : Adw.BreakpointBin { Button clear_button { label: _("Remove All"); } + } + Adw.PreferencesPage added_pref_page { + } [bottom] Box { diff --git a/src/install_page/install_page.py b/src/install_page/install_page.py index cb18d3c..305d323 100644 --- a/src/install_page/install_page.py +++ b/src/install_page/install_page.py @@ -3,8 +3,42 @@ from .host_info import HostInfo from .error_toast import ErrorToast from .app_row import AppRow from .snapshots_list_page import SnapshotsListPage +from .result_row import ResultRow import os, subprocess +class AddedPackage: + def __init__(self, name, app_id, branch, version, remote, installation): + self.name = name + self.app_id = app_id + self.branch = branch + self.version = version + self.remote = remote + self.installation = installation + +class AddedGroup(Adw.PreferencesGroup): + __gtype_name__ = "AddedGroup" + + package_rows = [] + + def add_row(self, row): + self.package_rows.append(row) + self.add(row) + self.set_visible(True) + + def rem_row(self, row): + if row in self.package_rows: + self.package_rows.remove(row) + self.remove(row) + + def __init__(self, remote, installation, **kwargs): + super().__init__(**kwargs) + + self.remote = remote + self.installation = installation + + self.set_title(f"{remote.title}") + self.set_description(_("Installation: {}").format(installation)) + @Gtk.Template(resource_path="/io/github/flattool/Warehouse/install_page/install_page.ui") class InstallPage(Adw.BreakpointBin): __gtype_name__ = "InstallPage" @@ -17,6 +51,7 @@ class InstallPage(Adw.BreakpointBin): search_entry = gtc() search_apply_button = gtc() results_list = gtc() + added_pref_page = gtc() # Referred to in the main window # It is used to determine if a new page should be made or not @@ -27,7 +62,11 @@ class InstallPage(Adw.BreakpointBin): current_remote = None def start_loading(self): - pass + for row in self.remote_rows: + self.remotes_group.remove(row) + self.remote_rows.clear() + self.added_packages.clear() + self.added_package_groups.clear() def end_loading(self): for installation in HostInfo.installations: @@ -38,6 +77,7 @@ class InstallPage(Adw.BreakpointBin): row.add_suffix(Gtk.Image(icon_name="right-large-symbolic")) row.connect("activated", self.remote_selected, installation, remote) self.remotes_group.add(row) + self.remote_rows.append(row) def remote_selected(self, row, installation, remote): self.current_installation = installation @@ -63,7 +103,7 @@ class InstallPage(Adw.BreakpointBin): try: output = subprocess.run(['flatpak-spawn', '--host', 'flatpak', 'search', '--columns=all', installation, text], text=True, check=True, capture_output=True).stdout.split("\n") - for line in output: + for i, line in enumerate(output): info = line.split("\t") if len(info) != 6: continue @@ -73,11 +113,26 @@ class InstallPage(Adw.BreakpointBin): app_id = GLib.markup_escape_text(info[2]) version = GLib.markup_escape_text(info[3]) branch = GLib.markup_escape_text(info[4]) - remotes = GLib.markup_escape_text(info[5]) - row = Adw.ActionRow(title=name, subtitle=app_id) + remotes = info[5] - self.results_list.append(row) - + if not self.current_remote.name in remotes.split(','): + continue + + is_added = False + try: + for package in self.added_packages: + if package.name == name and package.app_id == app_id and package.version == version and package.branch == branch: + is_added = True + break + + except KeyError: + print("passing key error") + + if not is_added: + row = ResultRow(name, app_id, branch, version) + row.connect("activated", self.add_package, i, name, app_id, branch, version) + self.results_list.append(row) + except Exception as e: print(e) except subprocess.CalledProcessError as cpe: @@ -85,9 +140,60 @@ class InstallPage(Adw.BreakpointBin): thread() + def list_focus_grabber(self, row): + i = 0 + prev_visible_row = None + while rover := self.results_list.get_row_at_index(i): + i += 1 + if rover is row: + break + + if rover.get_visible(): + prev_visible_row = rover + + while rover := self.results_list.get_row_at_index(i): + i += 1 + if rover.get_visible(): + rover.grab_focus() + return + + if prev_visible_row: + prev_visible_row.grab_focus() + + def add_package(self, row, index, name, app_id, branch, version): + key = f"{self.current_remote}<>{self.current_installation}" + package = AddedPackage(name, app_id, branch, version, self.current_remote, self.current_installation) + added_row = ResultRow(name, app_id, branch, version, row) + self.added_packages.append(package) + group = None + try: + group = self.added_package_groups[key] + group.add_row(added_row) + except KeyError: + group = AddedGroup(self.current_remote, self.current_installation) + self.added_package_groups[key] = group + self.added_pref_page.add(group) + group.add_row(added_row) + except Exception as e: + print(e) + return + added_row.connect("activated", self.remove_package, group) + row.set_visible(False) + self.list_focus_grabber(row) + + def remove_package(self, row, group): + row.original_row.set_visible(True) + group.rem_row(row) + if len(group.package_rows) == 0: + group.set_visible(False) + def __init__(self, main_window, **kwargs): super().__init__(**kwargs) self.instance = self + self.main_window = main_window + self.remote_rows = [] + self.added_packages = [] # remote<>installation + self.added_package_groups = {} # remote<>installation self.back_button.connect("clicked", lambda *_: self.sb_page_view.pop()) # self.search_entry.connect("search-changed", self.on_search) self.search_entry.connect("activate", self.on_search) diff --git a/src/install_page/result_row.blp b/src/install_page/result_row.blp new file mode 100644 index 0000000..4312df1 --- /dev/null +++ b/src/install_page/result_row.blp @@ -0,0 +1,39 @@ +using Gtk 4.0; +using Adw 1; + +template $ResultRow : Adw.ActionRow { + activatable: true; + title: "No title set"; + subtitle: "No subtitle set"; + + Box { + orientation: vertical; + valign: center; + spacing: 4; + margin-end: 4; + Label version_label { + styles ["subtitle"] + label: ""; + justify: right; + halign: end; + hexpand: true; + wrap: true; + } + Label branch_label { + styles ["subtitle"] + label: ""; + justify: right; + halign: end; + hexpand: true; + wrap: true; + } + } + [suffix] + Image add_image { + icon-name: "plus-large-symbolic"; + } + [suffix] + Image sub_image { + icon-name: "minus-large-symbolic"; + } +} \ No newline at end of file diff --git a/src/install_page/result_row.py b/src/install_page/result_row.py new file mode 100644 index 0000000..75d615a --- /dev/null +++ b/src/install_page/result_row.py @@ -0,0 +1,36 @@ +from gi.repository import Adw, Gtk, GLib, Gio +from .host_info import HostInfo +from .error_toast import ErrorToast +import os, subprocess + +@Gtk.Template(resource_path="/io/github/flattool/Warehouse/install_page/result_row.ui") +class ResultRow(Adw.ActionRow): + __gtype_name__ = "ResultRow" + gtc = Gtk.Template.Child + + version_label = gtc() + branch_label = gtc() + add_image = gtc() + sub_image = gtc() + + def idle_stuff(self): + self.set_title(GLib.markup_escape_text(self.name)) + self.set_subtitle(self.app_id) + self.version_label.set_label(GLib.markup_escape_text(self.version)) + self.branch_label.set_label(GLib.markup_escape_text(self.branch)) + self.version_label.set_visible(len(self.version_label.get_label()) != 0) + self.branch_label.set_visible(len(self.branch_label.get_label()) != 0) + self.sub_image.set_visible(bool(self.original_row)) + self.add_image.set_visible(not bool(self.original_row)) + self.set_tooltip_text(_("Remove Package from Queue") if bool(self.original_row) else _("Add Package to Queue")) + + def __init__(self, name, app_id, branch, version, original_row=None, **kwargs): + super().__init__(**kwargs) + + self.name = name + self.app_id = app_id + self.branch = branch + self.version = version + self.original_row = original_row + + GLib.idle_add(self.idle_stuff) \ No newline at end of file diff --git a/src/meson.build b/src/meson.build index a5cfac8..7247cb5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -21,6 +21,7 @@ blueprints = custom_target('blueprints', 'snapshot_page/snapshots_list_page.blp', 'snapshot_page/snapshot_box.blp', 'install_page/install_page.blp', + 'install_page/result_row.blp', ), output: '.', command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'], @@ -80,6 +81,7 @@ warehouse_sources = [ 'snapshot_page/snapshots_list_page.py', 'snapshot_page/snapshot_box.py', 'install_page/install_page.py', + 'install_page/result_row.py', '../data/style.css', ] diff --git a/src/snapshot_page/snapshot_box.blp b/src/snapshot_page/snapshot_box.blp index 962d736..36cd0cb 100644 --- a/src/snapshot_page/snapshot_box.blp +++ b/src/snapshot_page/snapshot_box.blp @@ -66,6 +66,4 @@ template $SnapshotBox : Gtk.Box { styles ["flat"] } } -} - -Adw.AlertDialog name_dialog {} \ No newline at end of file +} \ No newline at end of file diff --git a/src/warehouse.gresource.xml b/src/warehouse.gresource.xml index 9ad410f..bd2d391 100644 --- a/src/warehouse.gresource.xml +++ b/src/warehouse.gresource.xml @@ -19,6 +19,7 @@ snapshot_page/snapshots_list_page.ui snapshot_page/snapshot_box.ui install_page/install_page.ui + install_page/result_row.ui