diff --git a/src/common.py b/src/common.py index 35c83ea..ded119a 100644 --- a/src/common.py +++ b/src/common.py @@ -146,6 +146,17 @@ class myUtils: return(1) return(0) + def downgradeFlatpak(self, ref, commit, install_type="system"): + command = ['flatpak-spawn', '--host', 'pkexec', 'flatpak', 'update', ref, f"--commit={commit}", f"--{install_type}", '-y'] + try: + response = subprocess.run(command, capture_output=True, text=True, env=self.new_env).stderr + except subprocess.CalledProcessError as e: + if "note that" in response.lower(): + return(0) + print(f"Error setting mask for {app_id}:\n", e) + return(1) + return(0) + def uninstallFlatpak(self, ref_arr, type_arr, should_trash): self.uninstall_success = True diff --git a/src/downgrade.blp b/src/downgrade.blp index 7636b5c..6e6bd36 100644 --- a/src/downgrade.blp +++ b/src/downgrade.blp @@ -3,7 +3,7 @@ using Adw 1; template DowngradeWindow : Adw.Window { default-width: 500; - default-height: 750; + default-height: 450; modal: true; Adw.ToolbarView main_toolbar_view { @@ -18,7 +18,7 @@ template DowngradeWindow : Adw.Window { [end] Button apply_button { sensitive: false; - label: _("Apply"); + label: _("Downgrade"); styles["suggested-action"] } } @@ -33,48 +33,20 @@ template DowngradeWindow : Adw.Window { 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"] - } + Adw.PreferencesPage outerbox { + + Adw.PreferencesGroup { + Adw.SwitchRow mask_row { + title: _("Mask this Flatpak"); + subtitle: _("Ensure that the flatpak will never be updated to a newer version"); + active: true; } } + + Adw.PreferencesGroup versions_group { + title: _("Select a Release"); + description: _("This will uninstall the current release and install the chosen one instead. Note that downgrading can cause issues."); + } } } } diff --git a/src/downgrade_window.py b/src/downgrade_window.py index b678f53..769f661 100644 --- a/src/downgrade_window.py +++ b/src/downgrade_window.py @@ -13,9 +13,11 @@ class DowngradeWindow(Adw.Window): cancel_button = Gtk.Template.Child() apply_button = Gtk.Template.Child() - versions_listbox = Gtk.Template.Child() + versions_group = Gtk.Template.Child() progress_bar = Gtk.Template.Child() + toast_overlay = Gtk.Template.Child() mask_row = Gtk.Template.Child() + main_toolbar_view = Gtk.Template.Child() def pulser(self): if self.should_pulse: @@ -58,12 +60,20 @@ class DowngradeWindow(Adw.Window): for i in range(len(commits)): self.versions.append([commits[i], changes[i], dates[i]]) - def commitsResponse(self): + def commitsCallback(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=GLib.markup_escape_text(version[1])) + date_time = version[2].split(' ') + date = date_time[0].split('-') + offset = date_time[2][:3] + ":" + date_time[2][3:] + time = date_time[1].split(':') + display_time = GLib.DateTime.new(GLib.TimeZone.new(offset), int(date[0]), int(date[1]), int(date[2]), int(time[0]), int(time[1]), int(time[2])) + display_time = display_time.format("%x %X") + change = version[1].split('(') + change[1] = change[1][:-1] + row = Adw.ActionRow(title=GLib.markup_escape_text(change[0]), subtitle=str(display_time + " - " + change[1])) select = Gtk.CheckButton() select.connect("toggled", self.selectionHandler, i) @@ -73,30 +83,60 @@ class DowngradeWindow(Adw.Window): version.append(select) row.set_activatable_widget(select) row.add_prefix(select) - self.versions_listbox.append(row) + self.versions_group.add(row) def generateList(self): - task = Gio.Task.new(None, None, lambda *_: self.commitsResponse()) + task = Gio.Task.new(None, None, lambda *_: self.commitsCallback()) task.run_in_thread(lambda *_: self.getCommits()) - def onApply(self): + def downgradeCallack(self): + self.progress_bar.set_visible(False) + self.should_pulse = False + self.disconnect(self.no_close) + self.main_toolbar_view.set_sensitive(True) + self.progress_bar.set_visible = False + + if self.response != 0: + self.toast_overlay.add_toast(Adw.Toast.new(_("Could not downgrade {}").format(self.app_name))) + return + if self.mask_row.get_active(): - self.my_utils.maskFlatpak(self.app_id, self.install_type) + if self.my_utils.maskFlatpak(self.app_id, self.install_type) == 0: + self.flatpak_row[7].set_visible(True) + else: + self.parent_window.toast_overlay.add_toast(Adw.Toast.new(_("Could not mask {}").format(self.app_name))) + self.close() - def __init__(self, parent_window, flatpak_row_item, **kwargs): + def downgradeThread(self): + self.response = self.my_utils.downgradeFlatpak(self.app_ref, self.commit_to_use, self.install_type) + + def onApply(self): + self.no_close = self.connect("close-request", lambda event: True) + self.main_toolbar_view.set_sensitive(False) + self.should_pulse = True + self.progress_bar.set_visible(True) + self.pulser() + + task = Gio.Task.new(None, None, lambda *_: self.downgradeCallack()) + task.run_in_thread(lambda *_: self.downgradeThread()) + + def __init__(self, parent_window, flatpak_row, **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.app_name = flatpak_row[6][0] + self.app_id = flatpak_row[6][2] + self.remote = flatpak_row[6][6] + self.install_type = flatpak_row[6][7] + self.app_ref = flatpak_row[6][8] self.versions = [] self.should_pulse = True self.commit_to_use = "" + self.parent_window = parent_window + self.flatpak_row = flatpak_row + self.response = 0 event_controller = Gtk.EventControllerKey() # Connections @@ -109,7 +149,6 @@ class DowngradeWindow(Adw.Window): 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() diff --git a/src/window.py b/src/window.py index 11f0fd8..7d2a621 100644 --- a/src/window.py +++ b/src/window.py @@ -290,6 +290,7 @@ class WarehouseWindow(Adw.ApplicationWindow): for index in range(len(self.host_flatpaks)): app_name = self.host_flatpaks[index][0] app_id = self.host_flatpaks[index][2] + install_type = self.host_flatpaks[index][7] app_ref = self.host_flatpaks[index][8] flatpak_row = Adw.ActionRow(title=GLib.markup_escape_text(app_name)) flatpak_row.add_prefix(self.my_utils.findAppIcon(app_id)) @@ -304,11 +305,11 @@ class WarehouseWindow(Adw.ApplicationWindow): eol_runtime_label.add_css_class("error") flatpak_row.add_suffix(eol_runtime_label) - mask_label = Gtk.Label(label=_("Masked"), valign=Gtk.Align.CENTER, tooltip_text=_("This Flatpak is masked and will not be updated")) + mask_label = Gtk.Label(label=_("Masked"), valign=Gtk.Align.CENTER, tooltip_text=_("This Flatpak is masked and will not be updated"), visible=False) + flatpak_row.add_suffix(mask_label) # ^ This is up here as we need to add this to flatpak_rows regardless of if its visible or not if app_id in self.system_mask_list or app_id in self.user_mask_list: mask_label.set_visible(True) - flatpak_row.add_suffix(mask_label) properties_button = Gtk.Button(icon_name="info-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("View Properties")) properties_button.add_css_class("flat") @@ -330,6 +331,9 @@ class WarehouseWindow(Adw.ApplicationWindow): row_menu_model = Gio.Menu() copy_menu_model = Gio.Menu() + self.flatpak_rows.append([True, False, flatpak_row, properties_button, row_menu, select_flatpak_tickbox, self.host_flatpaks[index], mask_label, row_menu_model]) + # {Row visibility, Row selected, the row itself, properties, menu button, select, the flatpak row from `flatpak list`, mask label, the dropdown menu model} + # self.create_action(("properties" + str(index)), lambda *_, index=index: show_properties_window(None, index, self)) # properties_item = Gio.MenuItem.new(_("Show Properties"), f"win.properties{index}") # row_menu_model.append_item(properties_item) @@ -348,11 +352,15 @@ class WarehouseWindow(Adw.ApplicationWindow): row_menu_model.append_submenu(_("Copy"), copy_menu_model) + self.create_action(("run" + str(index)), lambda *_, ref=app_ref, name=app_name: self.runAppThread(ref, _("Opened {}").format(name))) + run_item = Gio.MenuItem.new(_("Open {}").format(app_name), f"win.run{index}") if "runtime" not in self.host_flatpaks[index][12]: - self.create_action(("run" + str(index)), lambda *_a, ref=app_ref, name=app_name: self.runAppThread(ref, _("Opened {}").format(name))) - run_item = Gio.MenuItem.new(_("Open {}").format(app_name), f"win.run{index}") row_menu_model.append_item(run_item) + self.create_action(("mask" + str(index)), lambda *_, id=app_id, type=install_type, index=index: self.maskFlatpak(id, type, index)) + mask_item = Gio.MenuItem.new(_("Toggle Mask"), f"win.mask{index}") + row_menu_model.append_item(mask_item) + # if os.path.exists(self.user_data_path + app_id): # self.create_action(("open-data" + str(index)), lambda *_, path=(self.user_data_path + app_id): Gio.AppInfo.launch_default_for_uri(f"file://{path}", None)) # open_data_item = Gio.MenuItem.new(_("Open Data Folder"), f"win.open-data{index}") @@ -362,7 +370,7 @@ 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)) + self.create_action(("downgrade" + str(index)), lambda *_, row=self.flatpak_rows[index]: DowngradeWindow(self, row)) downgrade_item = Gio.MenuItem.new(_("Downgrade {}").format(app_name), f"win.downgrade{index}") row_menu_model.append_item(downgrade_item) @@ -375,13 +383,29 @@ class WarehouseWindow(Adw.ApplicationWindow): flatpak_row.set_activatable_widget(select_flatpak_tickbox) self.flatpaks_list_box.append(flatpak_row) - # {Row visibility, Row selected, the row itself, properties, menu button, select, the flatpak row from `flatpak list`} - self.flatpak_rows.append([True, False, flatpak_row, properties_button, row_menu, select_flatpak_tickbox, self.host_flatpaks[index], mask_label]) self.windowSetEmpty(not self.flatpaks_list_box.get_row_at_index(0)) self.applyFilter(self.filter_list) self.batchActionsEnable(False) + def maskFlatpak(self, id, type, index): + is_masked = self.flatpak_rows[index][7].get_visible() # Check the visibility of the mask label to see if the flatpak is masked + response = [] + + def callback(): + if response[0] == 1: + name = self.host_flatpaks[index][0] + self.toast_overlay.add_toast(Adw.Toast.new(_("Could not toggle {}'s mask").format(name))) + return + self.flatpak_rows[index][7].set_visible(not is_masked) + + def thread(): + response.append(self.my_utils.maskFlatpak(id, type, is_masked)) + + task = Gio.Task.new(None, None, lambda *_: callback()) + task.run_in_thread(lambda *_: thread()) + + def copyItem(self, to_copy, to_toast=None): self.clipboard.set(to_copy) if to_toast: