diff --git a/src/downgrade.blp b/src/downgrade.blp new file mode 100644 index 0000000..7636b5c --- /dev/null +++ b/src/downgrade.blp @@ -0,0 +1,83 @@ +using Gtk 4.0; +using Adw 1; + +template DowngradeWindow : Adw.Window { + default-width: 500; + default-height: 750; + modal: true; + + Adw.ToolbarView main_toolbar_view { + [top] + HeaderBar header_bar { + show-title-buttons: false; + + [start] + Button cancel_button { + label: _("Cancel"); + } + [end] + Button apply_button { + sensitive: false; + label: _("Apply"); + styles["suggested-action"] + } + } + content: + Adw.ToastOverlay toast_overlay { + Stack main_stack { + Overlay main_overlay { + [overlay] + ProgressBar progress_bar { + pulse-step: 0.7; + can-target: false; + styles["osd"] + } + + ScrolledWindow scrolled_window { + vexpand: true; + Adw.Clamp{ + Box outerbox { + orientation: vertical; + + ListBox { + margin-top: 12; + margin-start: 12; + margin-end: 12; + hexpand: true; + valign: start; + selection-mode: none; + styles["boxed-list"] + + Adw.SwitchRow mask_row { + title: _("Mask this Flatpak"); + subtitle: _("Ensure that the flatpak will never update to a newer version"); + active: true; + } + } + + Label { + label: _("Select a Version"); + margin-top: 12; + margin-start: 12; + halign: start; + styles["title-3"] + } + + ListBox versions_listbox { + margin-top: 12; + margin-bottom: 12; + margin-start: 12; + margin-end: 12; + hexpand: true; + valign: start; + selection-mode: none; + styles["boxed-list"] + } + } + } + } + } + } + }; + } +} \ No newline at end of file diff --git a/src/downgrade_window.py b/src/downgrade_window.py new file mode 100644 index 0000000..c162275 --- /dev/null +++ b/src/downgrade_window.py @@ -0,0 +1,110 @@ +from gi.repository import Gtk, Adw, GLib, Gdk, Gio +from .common import myUtils +import subprocess +import os +import pathlib + +@Gtk.Template(resource_path="/io/github/flattool/Warehouse/downgrade.ui") +class DowngradeWindow(Adw.Window): + __gtype_name__ = "DowngradeWindow" + + new_env = dict( os.environ ) + new_env['LC_ALL'] = 'C' + + cancel_button = Gtk.Template.Child() + apply_button = Gtk.Template.Child() + versions_listbox = Gtk.Template.Child() + progress_bar = Gtk.Template.Child() + mask_row = Gtk.Template.Child() + + def pulser(self): + if self.should_pulse: + self.progress_bar.pulse() + GLib.timeout_add(500, self.pulser) + + def key_handler(self, _a, event, _c, _d): + if event == Gdk.KEY_Escape: + self.close() + + def selectionHandler(self, button, index): + self.apply_button.set_sensitive(True) + if button.get_active(): + self.commit_to_use = self.versions[index][0] + + def getCommits(self): + output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "remote-info", "--log", self.remote, self.app_ref, f"--{self.install_type}"], capture_output=True, text=True, env=self.new_env).stdout + lines = output.strip().split("\n") + columns = lines[0].split("\t") + data = [columns] + for line in lines[1:]: + row = line.split("\t") + data.append(row[0].strip()) + + commits = [] + changes = [] + dates = [] + for i in range(len(data)): + line = data[i] + + if "Commit:" in line: + commits.append(line.replace("Commit: ", "")) + + if "Subject:" in line: + changes.append(line.replace("Subject: ", "")) + + if "Date:" in line: + dates.append(line.replace("Date: ", "")) + + for i in range(len(commits)): + self.versions.append([commits[i], changes[i], dates[i]]) + + def commitsResponse(self): + self.progress_bar.set_visible(False) + self.should_pulse = False + for i in range(len(self.versions)): + version = self.versions[i] + row = Adw.ActionRow(title=version[2], subtitle=version[1]) + select = Gtk.CheckButton() + select.connect("toggled", self.selectionHandler, i) + + if i > 0: + select.set_group(self.versions[i-1][3]) + + version.append(select) + row.set_activatable_widget(select) + row.add_prefix(select) + self.versions_listbox.append(row) + + def generateList(self): + task = Gio.Task.new(None, None, lambda *_: self.commitsResponse()) + task.run_in_thread(lambda *_: self.getCommits()) + + def __init__(self, parent_window, flatpak_row_item, **kwargs): + super().__init__(**kwargs) + + # Create Variables + self.my_utils = myUtils(self) + self.app_name = flatpak_row_item[0] + self.app_id = flatpak_row_item[2] + self.remote = flatpak_row_item[6] + self.install_type = flatpak_row_item[7] + self.app_ref = flatpak_row_item[8] + self.versions = [] + self.should_pulse = True + self.commit_to_use = "" + event_controller = Gtk.EventControllerKey() + + # Connections + event_controller.connect("key-pressed", self.key_handler) + self.cancel_button.connect("clicked", lambda *_: self.close()) + + # Apply + self.pulser() + self.add_controller(event_controller) + self.set_title(_("Downgrade {}").format(self.app_name)) + self.set_transient_for(parent_window) + # print(self.mask_row.get_active()) + + self.generateList() + + self.present() \ No newline at end of file diff --git a/src/filter.blp b/src/filter.blp index 9cef034..f2ebfb6 100644 --- a/src/filter.blp +++ b/src/filter.blp @@ -24,9 +24,7 @@ template FilterWindow : Adw.Window { } content: Adw.ToastOverlay toast_overlay { - Stack main_stack { - //Box main_box { - //orientation: vertical; + Stack main_stack { Overlay main_overlay { ScrolledWindow scrolled_window { vexpand: true; @@ -82,7 +80,6 @@ template FilterWindow : Adw.Window { } } } - //} Adw.StatusPage no_data { icon-name: "check-plain-symbolic"; title: _("No Leftover Data"); @@ -90,12 +87,5 @@ template FilterWindow : Adw.Window { } } }; - // [bottom] - // ActionBar action_bar { - // [start] - // ToggleButton select_all_button { - // label: _("Select All"); - // } - // } } } \ No newline at end of file diff --git a/src/meson.build b/src/meson.build index ade318a..92b7e8a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -9,7 +9,8 @@ blueprints = custom_target('blueprints', 'orphans.blp', 'filter.blp', 'popular_remotes.blp', - 'remotes.blp' + 'remotes.blp', + 'downgrade.blp', ), output: '.', command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'], @@ -53,7 +54,9 @@ warehouse_sources = [ 'filter.blp', 'popular_remotes_window.py', 'style.css', - 'remotes.blp' + 'remotes.blp', + 'downgrade_window.py', + 'downgrade.blp' ] install_data(warehouse_sources, install_dir: moduledir) diff --git a/src/warehouse.gresource.xml b/src/warehouse.gresource.xml index 81742b3..e352131 100644 --- a/src/warehouse.gresource.xml +++ b/src/warehouse.gresource.xml @@ -6,6 +6,7 @@ filter.ui popular_remotes.ui remotes.ui + downgrade.ui style.css gtk/help-overlay.ui diff --git a/src/window.py b/src/window.py index 279074f..8b6722f 100644 --- a/src/window.py +++ b/src/window.py @@ -26,6 +26,7 @@ from .properties_window import show_properties_window from .filter_window import FilterWindow from .common import myUtils from .remotes_window import RemotesWindow +from .downgrade_window import DowngradeWindow @Gtk.Template(resource_path="/io/github/flattool/Warehouse/window.ui") class WarehouseWindow(Adw.ApplicationWindow): @@ -354,6 +355,10 @@ class WarehouseWindow(Adw.ApplicationWindow): uninstall_item = Gio.MenuItem.new(_("Uninstall {}").format(app_name), f"win.uninstall{index}") row_menu_model.append_item(uninstall_item) + self.create_action(("downgrade" + str(index)), lambda *_, row=self.host_flatpaks[index]: DowngradeWindow(self, row)) + downgrade_item = Gio.MenuItem.new(_("Downgrade {}").format(app_name), f"win.downgrade{index}") + row_menu_model.append_item(downgrade_item) + # row_menu_model.remove(1) row_menu.set_menu_model(row_menu_model)