diff --git a/src/app_row_widget.py b/src/app_row_widget.py index c92e87b..f8513f1 100644 --- a/src/app_row_widget.py +++ b/src/app_row_widget.py @@ -10,8 +10,8 @@ from .snapshots_window import SnapshotsWindow from .filter_window import FilterWindow from .common import myUtils -class AppRow(Adw.ActionRow): +class AppRow(Adw.ActionRow): def set_selectable(self, is_selectable): self.tickbox.set_active(False) self.tickbox.set_visible(is_selectable) @@ -61,13 +61,38 @@ class AppRow(Adw.ActionRow): if len(current_flatpak[13]) == 0: self.is_runtime = True - info_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, valign=Gtk.Align.CENTER, halign=Gtk.Align.CENTER, hexpand=True, vexpand=True, spacing=6) + info_box = Gtk.Box( + orientation=Gtk.Orientation.VERTICAL, + valign=Gtk.Align.CENTER, + halign=Gtk.Align.CENTER, + hexpand=True, + vexpand=True, + spacing=6, + ) # justify=Gtk.Justification.RIGHT - self.mask_label = Gtk.Label(label=_("Updates Disabled"), visible=False, hexpand=True, wrap=True, valign=Gtk.Align.CENTER, tooltip_text=_("{} is masked and will not be updated").format(self.app_name)) + self.mask_label = Gtk.Label( + label=_("Updates Disabled"), + visible=False, + hexpand=True, + wrap=True, + valign=Gtk.Align.CENTER, + tooltip_text=_("{} is masked and will not be updated").format( + self.app_name + ), + ) self.mask_label.add_css_class("warning") - self.eol_app_label = Gtk.Label(label=_("App EOL"), visible=False, hexpand=True, wrap=True, valign=Gtk.Align.CENTER, tooltip_text=_("{} has reached its End of Life and will not receive any security updates").format(self.app_name)) + self.eol_app_label = Gtk.Label( + label=_("App EOL"), + visible=False, + hexpand=True, + wrap=True, + valign=Gtk.Align.CENTER, + tooltip_text=_( + "{} has reached its End of Life and will not receive any security updates" + ).format(self.app_name), + ) self.eol_app_label.add_css_class("error") info_box.append(self.eol_app_label) if "eol" in parent_window.host_flatpaks[index][12]: @@ -75,7 +100,16 @@ class AppRow(Adw.ActionRow): # justify=Gtk.Justification.RIGHT self.eol_app_label.set_visible(True) - self.eol_runtime_label = Gtk.Label(label=_("Runtime EOL"), visible=False, hexpand=True, wrap=True, valign=Gtk.Align.CENTER, tooltip_text=_("{}'s runtime has reached its End of Life and will not receive any security updates").format(self.app_name)) + self.eol_runtime_label = Gtk.Label( + label=_("Runtime EOL"), + visible=False, + hexpand=True, + wrap=True, + valign=Gtk.Align.CENTER, + tooltip_text=_( + "{}'s runtime has reached its End of Life and will not receive any security updates" + ).format(self.app_name), + ) self.eol_runtime_label.add_css_class("error") info_box.append(self.eol_runtime_label) if current_flatpak[13] in parent_window.eol_list: @@ -85,92 +119,188 @@ class AppRow(Adw.ActionRow): info_pop = Gtk.Popover() info_pop.set_child(info_box) - self.info_button = Gtk.MenuButton(visible=False, valign=Gtk.Align.CENTER, popover=info_pop, icon_name="software-update-urgent-symbolic") + self.info_button = Gtk.MenuButton( + visible=False, + valign=Gtk.Align.CENTER, + popover=info_pop, + icon_name="software-update-urgent-symbolic", + ) self.info_button.add_css_class("flat") info_box.append(self.mask_label) self.add_suffix(self.info_button) - properties_button = Gtk.Button(icon_name="info-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("View Properties")) + properties_button = Gtk.Button( + icon_name="info-symbolic", + valign=Gtk.Align.CENTER, + tooltip_text=_("View Properties"), + ) properties_button.add_css_class("flat") - properties_button.connect("clicked", lambda *_: PropertiesWindow(index, host_flatpaks, parent_window)) + properties_button.connect( + "clicked", lambda *_: PropertiesWindow(index, host_flatpaks, parent_window) + ) self.add_suffix(properties_button) - - self.tickbox = Gtk.CheckButton(visible=False) # visible=self.in_batch_mode + + self.tickbox = Gtk.CheckButton(visible=False) # visible=self.in_batch_mode self.tickbox.add_css_class("selection-mode") self.tickbox.connect("toggled", parent_window.rowSelectHandler) self.add_suffix(self.tickbox) self.set_activatable_widget(self.tickbox) self.set_activatable(False) - self.row_menu = Gtk.MenuButton(icon_name="view-more-symbolic", valign=Gtk.Align.CENTER) # visible=not self.in_batch_mode + self.row_menu = Gtk.MenuButton( + icon_name="view-more-symbolic", valign=Gtk.Align.CENTER + ) # visible=not self.in_batch_mode self.row_menu.add_css_class("flat") row_menu_model = Gio.Menu() copy_menu_model = Gio.Menu() advanced_menu_model = Gio.Menu() self.add_suffix(self.row_menu) - parent_window.create_action(("copy-name" + str(index)), lambda *_, name=self.app_name, toast=_("Copied name"): parent_window.copyItem(name, toast)) - copy_menu_model.append_item(Gio.MenuItem.new(_("Copy Name"), f"win.copy-name{index}")) + parent_window.create_action( + ("copy-name" + str(index)), + lambda *_, name=self.app_name, toast=_( + "Copied name" + ): parent_window.copyItem(name, toast), + ) + copy_menu_model.append_item( + Gio.MenuItem.new(_("Copy Name"), f"win.copy-name{index}") + ) - parent_window.create_action(("copy-id" + str(index)), lambda *_, id=self.app_id, toast=_("Copied ID"): parent_window.copyItem(id, toast)) - copy_menu_model.append_item(Gio.MenuItem.new(_("Copy ID"), f"win.copy-id{index}")) + parent_window.create_action( + ("copy-id" + str(index)), + lambda *_, id=self.app_id, toast=_("Copied ID"): parent_window.copyItem( + id, toast + ), + ) + copy_menu_model.append_item( + Gio.MenuItem.new(_("Copy ID"), f"win.copy-id{index}") + ) - parent_window.create_action(("copy-ref" + str(index)), lambda *_, ref=self.app_ref, toast=_("Copied ref"): parent_window.copyItem(ref, toast)) - copy_menu_model.append_item(Gio.MenuItem.new(_("Copy Ref"), f"win.copy-ref{index}")) + parent_window.create_action( + ("copy-ref" + str(index)), + lambda *_, ref=self.app_ref, toast=_("Copied ref"): parent_window.copyItem( + ref, toast + ), + ) + copy_menu_model.append_item( + Gio.MenuItem.new(_("Copy Ref"), f"win.copy-ref{index}") + ) - parent_window.create_action(("copy-command" + str(index)), lambda *_, ref=self.app_ref, toast=_("Copied launch command"): parent_window.copyItem(f"flatpak run {ref}", toast)) - copy_menu_model.append_item(Gio.MenuItem.new(_("Copy Launch Command"), f"win.copy-command{index}")) + parent_window.create_action( + ("copy-command" + str(index)), + lambda *_, ref=self.app_ref, toast=_( + "Copied launch command" + ): parent_window.copyItem(f"flatpak run {ref}", toast), + ) + copy_menu_model.append_item( + Gio.MenuItem.new(_("Copy Launch Command"), f"win.copy-command{index}") + ) row_menu_model.append_submenu(_("Copy"), copy_menu_model) if "runtime" not in parent_window.host_flatpaks[index][12]: - parent_window.create_action(("run" + str(index)), lambda *_a, ref=self.app_ref, name=self.app_name: parent_window.runAppThread(ref, _("Opened {}").format(name))) + parent_window.create_action( + ("run" + str(index)), + lambda *_a, ref=self.app_ref, name=self.app_name: parent_window.runAppThread( + ref, _("Opened {}").format(name) + ), + ) run_item = Gio.MenuItem.new(_("Open"), f"win.run{index}") row_menu_model.append_item(run_item) - parent_window.create_action(("uninstall" + str(index)), lambda *_: parent_window.uninstallButtonHandler(self, self.app_name, self.app_ref, self.app_id)) + parent_window.create_action( + ("uninstall" + str(index)), + lambda *_: parent_window.uninstallButtonHandler( + self, self.app_name, self.app_ref, self.app_id + ), + ) uninstall_item = Gio.MenuItem.new(_("Uninstall"), f"win.uninstall{index}") row_menu_model.append_item(uninstall_item) data_menu_model = Gio.Menu() - parent_window.create_action(("open-data" + str(index)), lambda *_, path=(parent_window.user_data_path + self.app_id): parent_window.openDataFolder(path)) - open_data_item = Gio.MenuItem.new(_("Open User Data Folder"), f"win.open-data{index}") - open_data_item.set_attribute_value("hidden-when", GLib.Variant.new_string("action-disabled")) + parent_window.create_action( + ("open-data" + str(index)), + lambda *_, path=( + parent_window.user_data_path + self.app_id + ): parent_window.openDataFolder(path), + ) + open_data_item = Gio.MenuItem.new( + _("Open User Data Folder"), f"win.open-data{index}" + ) + open_data_item.set_attribute_value( + "hidden-when", GLib.Variant.new_string("action-disabled") + ) data_menu_model.append_item(open_data_item) - parent_window.create_action(("trash" + str(index)), lambda *_, name=self.app_name, id=self.app_id, index=index: parent_window.trashData(name, id, index)) + parent_window.create_action( + ("trash" + str(index)), + lambda *_, name=self.app_name, id=self.app_id, index=index: parent_window.trashData( + name, id, index + ), + ) trash_item = Gio.MenuItem.new(_("Trash User Data"), f"win.trash{index}") - trash_item.set_attribute_value("hidden-when", GLib.Variant.new_string("action-disabled")) + trash_item.set_attribute_value( + "hidden-when", GLib.Variant.new_string("action-disabled") + ) data_menu_model.append_item(trash_item) row_menu_model.append_section(None, data_menu_model) - + if not os.path.exists(parent_window.user_data_path + self.app_id): parent_window.lookup_action(f"open-data{self.index}").set_enabled(False) parent_window.lookup_action(f"trash{self.index}").set_enabled(False) - parent_window.create_action(("mask" + str(index)), lambda *_, id=self.app_id, type=self.install_type, index=index: parent_window.maskFlatpak(self)) + parent_window.create_action( + ("mask" + str(index)), + lambda *_, id=self.app_id, type=self.install_type, index=index: parent_window.maskFlatpak( + self + ), + ) mask_item = Gio.MenuItem.new(_("Disable Updates"), f"win.mask{index}") - mask_item.set_attribute_value("hidden-when", GLib.Variant.new_string("action-disabled")) + mask_item.set_attribute_value( + "hidden-when", GLib.Variant.new_string("action-disabled") + ) advanced_menu_model.append_item(mask_item) - parent_window.create_action(("unmask" + str(index)), lambda *_, id=self.app_id, type=self.install_type, index=index: parent_window.maskFlatpak(self)) + parent_window.create_action( + ("unmask" + str(index)), + lambda *_, id=self.app_id, type=self.install_type, index=index: parent_window.maskFlatpak( + self + ), + ) unmask_item = Gio.MenuItem.new(_("Enable Updates"), f"win.unmask{index}") - unmask_item.set_attribute_value("hidden-when", GLib.Variant.new_string("action-disabled")) + unmask_item.set_attribute_value( + "hidden-when", GLib.Variant.new_string("action-disabled") + ) advanced_menu_model.append_item(unmask_item) if "runtime" not in parent_window.host_flatpaks[index][12]: - parent_window.create_action(("snapshot" + str(index)), lambda *_, row=current_flatpak: SnapshotsWindow(parent_window, row).present()) - snapshot_item = Gio.MenuItem.new(_("Manage Snapshots"), f"win.snapshot{index}") + parent_window.create_action( + ("snapshot" + str(index)), + lambda *_, row=current_flatpak: SnapshotsWindow( + parent_window, row + ).present(), + ) + snapshot_item = Gio.MenuItem.new( + _("Manage Snapshots"), f"win.snapshot{index}" + ) advanced_menu_model.append_item(snapshot_item) - parent_window.create_action(("downgrade" + str(index)), lambda *_, row=current_flatpak, index=index: DowngradeWindow(parent_window, row, index)) + parent_window.create_action( + ("downgrade" + str(index)), + lambda *_, row=current_flatpak, index=index: DowngradeWindow( + parent_window, row, index + ), + ) downgrade_item = Gio.MenuItem.new(_("Downgrade"), f"win.downgrade{index}") advanced_menu_model.append_item(downgrade_item) - if self.app_id in parent_window.system_mask_list or self.app_id in parent_window.user_mask_list: + if ( + self.app_id in parent_window.system_mask_list + or self.app_id in parent_window.user_mask_list + ): self.mask_label.set_visible(True) parent_window.lookup_action(f"mask{index}").set_enabled(False) else: diff --git a/src/common.py b/src/common.py index 8b6ce57..ab38a94 100644 --- a/src/common.py +++ b/src/common.py @@ -1,9 +1,10 @@ -from gi.repository import GLib, Gtk, Adw, Gio #, Gdk +from gi.repository import GLib, Gtk, Adw, Gio # , Gdk import os import subprocess import pathlib import time + class myUtils: def __init__(self, window, **kwargs): self.parent_window = window @@ -11,15 +12,20 @@ class myUtils: self.user_data_path = self.host_home + "/.var/app/" self.install_success = True self.uninstall_success = True - self.new_env = dict( os.environ ) - self.new_env['LC_ALL'] = 'C' - + self.new_env = dict(os.environ) + self.new_env["LC_ALL"] = "C" + def trashFolder(self, path): if not os.path.exists(path): print("error in common.trashFolder: path does not exists. path =", path) return 1 try: - subprocess.run(["gio", "trash", path], capture_output=False, check=True, env=self.new_env) + subprocess.run( + ["gio", "trash", path], + capture_output=False, + check=True, + env=self.new_env, + ) return 0 except subprocess.CalledProcessError as e: print("error in common.trashFolder: CalledProcessError:", e) @@ -68,10 +74,18 @@ class myUtils: def findAppIcon(self, app_id): icon_theme = Gtk.IconTheme.new() icon_theme.add_search_path("/var/lib/flatpak/exports/share/icons/") - icon_theme.add_search_path(self.host_home + "/.local/share/flatpak/exports/share/icons") - + icon_theme.add_search_path( + self.host_home + "/.local/share/flatpak/exports/share/icons" + ) + try: - icon_path = (icon_theme.lookup_icon(app_id, None, 512, 1, self.parent_window.get_direction(), 0).get_file().get_path()) + icon_path = ( + icon_theme.lookup_icon( + app_id, None, 512, 1, self.parent_window.get_direction(), 0 + ) + .get_file() + .get_path() + ) except GLib.GError: icon_path = None if icon_path: @@ -85,7 +99,12 @@ class myUtils: def getHostUpdates(self): list = [] - output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "update"], capture_output=True, text=True, env=self.new_env).stdout + output = subprocess.run( + ["flatpak-spawn", "--host", "flatpak", "update"], + capture_output=True, + text=True, + env=self.new_env, + ).stdout lines = output.strip().split("\n") columns = lines[0].split("\t") data = [columns] @@ -94,20 +113,37 @@ class myUtils: data.append(row) for i in range(len(data)): - if data[i][0].find('.') == 2: + if data[i][0].find(".") == 2: list.append(data[i][2]) - - return(list) + + return list def getHostPins(self): - output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "pin"], capture_output=True, text=True, env=self.new_env).stdout + output = subprocess.run( + ["flatpak-spawn", "--host", "flatpak", "pin"], + capture_output=True, + text=True, + env=self.new_env, + ).stdout data = output.strip().split("\n") for i in range(len(data)): data[i] = data[i].strip() return data def getHostRemotes(self): - output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "remotes", "--columns=all", "--show-disabled"], capture_output=True, text=True, env=self.new_env).stdout + output = subprocess.run( + [ + "flatpak-spawn", + "--host", + "flatpak", + "remotes", + "--columns=all", + "--show-disabled", + ], + capture_output=True, + text=True, + env=self.new_env, + ).stdout lines = output.strip().split("\n") columns = lines[0].split("\t") data = [columns] @@ -117,7 +153,12 @@ class myUtils: return data def getHostFlatpaks(self): - output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "list", "--columns=all"], capture_output=True, text=True, env=self.new_env).stdout + output = subprocess.run( + ["flatpak-spawn", "--host", "flatpak", "list", "--columns=all"], + capture_output=True, + text=True, + env=self.new_env, + ).stdout lines = output.strip().split("\n") columns = lines[0].split("\t") data = [columns] @@ -125,7 +166,12 @@ class myUtils: row = line.split("\t") data.append(row) - output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "list", "--columns=runtime"], capture_output=True, text=True, env=self.new_env).stdout + output = subprocess.run( + ["flatpak-spawn", "--host", "flatpak", "list", "--columns=runtime"], + capture_output=True, + text=True, + env=self.new_env, + ).stdout lines = output.split("\n") for i in range(len(data)): data[i].append(lines[i]) @@ -142,39 +188,65 @@ class myUtils: dependent_runtimes.append(current[13]) except: print("Could not get dependent runtime") - return(dependent_runtimes) + return dependent_runtimes def getHostMasks(self, user_or_system): - output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "mask", f"--{user_or_system}"], capture_output=True, text=True, env=self.new_env).stdout + output = subprocess.run( + ["flatpak-spawn", "--host", "flatpak", "mask", f"--{user_or_system}"], + capture_output=True, + text=True, + env=self.new_env, + ).stdout lines = output.strip().split("\n") for i in range(len(lines)): lines[i] = lines[i].strip() - return(lines) + return lines def maskFlatpak(self, app_id, user_or_system, remove=False): - command = ["flatpak-spawn", "--host", "flatpak", "mask", f"--{user_or_system}", app_id] + command = [ + "flatpak-spawn", + "--host", + "flatpak", + "mask", + f"--{user_or_system}", + app_id, + ] if remove: command.append("--remove") response = "" try: - response = subprocess.run(command, capture_output=True, text=True, env=self.new_env) + response = subprocess.run( + command, capture_output=True, text=True, env=self.new_env + ) except subprocess.CalledProcessError as e: print(f"Error setting mask for {app_id}:\n", e) - return(1) + return 1 if len(response.stderr) > 0: - return(1) - return(0) + 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'] + 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 + 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) + return 0 print(f"Error setting mask for {app_id}:\n", e) - return(1) - return(0) + return 1 + return 0 def uninstallFlatpak(self, ref_arr, type_arr, should_trash, progress_bar=None): self.uninstall_success = True @@ -193,23 +265,40 @@ class myUtils: # apps array guide: [app_ref, app_id, user_or_system_install] for i in range(len(apps)): - command = ['flatpak-spawn', '--host', 'flatpak', 'remove', '-y', f"--{apps[i][2]}", apps[i][0]] + command = [ + "flatpak-spawn", + "--host", + "flatpak", + "remove", + "-y", + f"--{apps[i][2]}", + apps[i][0], + ] try: - subprocess.run(command, capture_output=False, check=True, env=self.new_env) + subprocess.run( + command, capture_output=False, check=True, env=self.new_env + ) if progress_bar: GLib.idle_add(progress_bar.set_visible, True) GLib.idle_add(progress_bar.set_fraction, (i + 1.0) / len(ref_arr)) except subprocess.CalledProcessError: fails.append(apps[i]) - if len(fails) > 0: # Run this only if there is 1 or more non uninstalled apps - pk_command = ['flatpak-spawn', '--host', 'pkexec', 'flatpak', 'remove', '-y', '--system'] + if len(fails) > 0: # Run this only if there is 1 or more non uninstalled apps + pk_command = [ + "flatpak-spawn", + "--host", + "pkexec", + "flatpak", + "remove", + "-y", + "--system", + ] print("second uninstall process") for i in range(len(fails)): - if fails[i][2] == "user": self.uninstall_success = False - continue # Skip if app is a user install app + continue # Skip if app is a user install app pk_command.append(fails[i][0]) try: @@ -217,7 +306,9 @@ class myUtils: if progress_bar: GLib.idle_add(progress_bar.set_visible, True) GLib.idle_add(progress_bar.set_fraction, 0.9) - subprocess.run(pk_command, capture_output=False, check=True, env=self.new_env) + subprocess.run( + pk_command, capture_output=False, check=True, env=self.new_env + ) except subprocess.CalledProcessError: self.uninstall_success = False @@ -242,29 +333,42 @@ class myUtils: fails = [] for i in range(len(app_arr)): - command = ['flatpak-spawn', '--host', 'flatpak', 'install'] + command = ["flatpak-spawn", "--host", "flatpak", "install"] if remote != None: command.append(remote) command.append(f"--{user_or_system}") - command.append('-y') + command.append("-y") command.append(app_arr[i]) try: - subprocess.run(command, capture_output=False, check=True, env=self.new_env) + subprocess.run( + command, capture_output=False, check=True, env=self.new_env + ) if progress_bar: GLib.idle_add(progress_bar.set_visible, True) GLib.idle_add(progress_bar.set_fraction, (i + 1.0) / len(app_arr)) except subprocess.CalledProcessError: fails.append(app_arr[i]) - + if (len(fails) > 0) and (user_or_system == "system"): - pk_command = ['flatpak-spawn', '--host', 'pkexec', 'flatpak', 'install', remote, f"--{user_or_system}", '-y'] + pk_command = [ + "flatpak-spawn", + "--host", + "pkexec", + "flatpak", + "install", + remote, + f"--{user_or_system}", + "-y", + ] for i in range(len(fails)): pk_command.append(fails[i]) try: if progress_bar: GLib.idle_add(progress_bar.set_visible, True) GLib.idle_add(progress_bar.set_fraction, 0.9) - subprocess.run(pk_command, capture_output=False, check=True, env=self.new_env) + subprocess.run( + pk_command, capture_output=False, check=True, env=self.new_env + ) except subprocess.CalledProcessError: self.install_success = False @@ -279,7 +383,12 @@ class myUtils: self.run_app_error = False self.run_app_error_message = "" try: - subprocess.run(['flatpak-spawn', '--host', 'flatpak', 'run', ref], check=True, env=self.new_env, start_new_session=True) + subprocess.run( + ["flatpak-spawn", "--host", "flatpak", "run", ref], + check=True, + env=self.new_env, + start_new_session=True, + ) except subprocess.CalledProcessError as e: self.run_app_error_message = str(e) self.run_app_error = True @@ -292,9 +401,20 @@ class myUtils: if "system" in type_arr: return "system" - def snapshotApps(self, epoch, app_snapshot_path_arr, app_version_arr, app_user_data_arr, progress_bar=None): - if not (len(app_snapshot_path_arr) == len(app_version_arr) == len(app_user_data_arr)): - print("error in common.snapshotApp: the lengths of app_snapshot_path_arr, app_version_arr, and app_user_data_arr do not match.") + def snapshotApps( + self, + epoch, + app_snapshot_path_arr, + app_version_arr, + app_user_data_arr, + progress_bar=None, + ): + if not ( + len(app_snapshot_path_arr) == len(app_version_arr) == len(app_user_data_arr) + ): + print( + "error in common.snapshotApp: the lengths of app_snapshot_path_arr, app_version_arr, and app_user_data_arr do not match." + ) return 1 fails = [] @@ -303,7 +423,14 @@ class myUtils: snapshot_path = app_snapshot_path_arr[i] version = app_version_arr[i] user_data = app_user_data_arr[i] - command = ['tar', 'cafv', f"{snapshot_path}{epoch}_{version}.tar.zst", "-C", f"{user_data}", "."] + command = [ + "tar", + "cafv", + f"{snapshot_path}{epoch}_{version}.tar.zst", + "-C", + f"{user_data}", + ".", + ] try: if not os.path.exists(snapshot_path): @@ -312,13 +439,18 @@ class myUtils: subprocess.run(command, check=True, env=self.new_env) if progress_bar: GLib.idle_add(progress_bar.set_visible, True) - GLib.idle_add(progress_bar.set_fraction, (i + 1.0) / len(app_snapshot_path_arr)) + GLib.idle_add( + progress_bar.set_fraction, + (i + 1.0) / len(app_snapshot_path_arr), + ) except subprocess.CalledProcessError as e: print("error in common.snapshotApp:", e) fails.append(user_data) - if(int(time.time()) == epoch): # Wait 1s if the snapshot is made too quickly, to prevent overriding a snapshot file - subprocess.run(['sleep', '1s']) + if ( + int(time.time()) == epoch + ): # Wait 1s if the snapshot is made too quickly, to prevent overriding a snapshot file + subprocess.run(["sleep", "1s"]) if progress_bar: GLib.idle_add(progress_bar.set_visible, False) diff --git a/src/downgrade_window.py b/src/downgrade_window.py index dde2526..23bc348 100644 --- a/src/downgrade_window.py +++ b/src/downgrade_window.py @@ -4,12 +4,13 @@ import subprocess import os import pathlib + @Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/downgrade.ui") class DowngradeWindow(Adw.Window): __gtype_name__ = "DowngradeWindow" - - new_env = dict( os.environ ) - new_env['LC_ALL'] = 'C' + + new_env = dict(os.environ) + new_env["LC_ALL"] = "C" cancel_button = Gtk.Template.Child() apply_button = Gtk.Template.Child() @@ -34,14 +35,28 @@ class DowngradeWindow(Adw.Window): 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 + 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 = [] @@ -67,14 +82,24 @@ class DowngradeWindow(Adw.Window): self.versions_group.add(group_button) for i in range(len(self.versions)): version = self.versions[i] - date_time = version[2].split(' ') - date = date_time[0].split('-') + 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])) + 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('(') - row = Adw.ActionRow(title=GLib.markup_escape_text(change[0]), subtitle=str(display_time)) + change = version[1].split("(") + row = Adw.ActionRow( + title=GLib.markup_escape_text(change[0]), subtitle=str(display_time) + ) row.set_tooltip_text(_("Commit Hash: {}").format(version[0])) select = Gtk.CheckButton() select.connect("toggled", self.selectionHandler, i) @@ -98,18 +123,26 @@ class DowngradeWindow(Adw.Window): 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))) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not downgrade {}").format(self.app_name)) + ) return - + if self.mask_row.get_active(): if self.my_utils.maskFlatpak(self.app_id, self.install_type) != 0: - self.parent_window.toast_overlay.add_toast(Adw.Toast.new(_("Could not disable updates for {}").format(self.app_name))) + self.parent_window.toast_overlay.add_toast( + Adw.Toast.new( + _("Could not disable updates for {}").format(self.app_name) + ) + ) self.parent_window.refresh_list_of_flatpaks(self, False) self.close() def downgradeThread(self): - self.response = self.my_utils.downgradeFlatpak(self.app_ref, self.commit_to_use, self.install_type) + self.response = self.my_utils.downgradeFlatpak( + self.app_ref, self.commit_to_use, self.install_type + ) def onApply(self): self.set_title(_("Downgrading…")) @@ -118,7 +151,7 @@ class DowngradeWindow(Adw.Window): 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()) @@ -152,8 +185,12 @@ class DowngradeWindow(Adw.Window): self.add_controller(event_controller) self.set_title(_("Fetching Releases…")) self.set_transient_for(parent_window) - self.mask_row.set_subtitle(_("Ensure that {} will never be updated to a newer version").format(self.app_name)) + self.mask_row.set_subtitle( + _("Ensure that {} will never be updated to a newer version").format( + self.app_name + ) + ) self.generateList() - self.present() \ No newline at end of file + self.present() diff --git a/src/filter_window.py b/src/filter_window.py index ecfb677..cd03401 100644 --- a/src/filter_window.py +++ b/src/filter_window.py @@ -4,6 +4,7 @@ import subprocess import os import pathlib + @Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/filter.ui") class FilterWindow(Adw.Window): __gtype_name__ = "FilterWindow" @@ -15,7 +16,6 @@ class FilterWindow(Adw.Window): remotes_expander = Gtk.Template.Child() runtimes_expander = Gtk.Template.Child() - def key_handler(self, _a, event, _c, _d): if event == Gdk.KEY_Escape: self.close() @@ -35,10 +35,12 @@ class FilterWindow(Adw.Window): self.apply_button.set_sensitive(False) return - if self.apps_switch.get_active() and\ - (not self.runtimes_switch.get_active()) and\ - (not self.remotes_expander_switch.get_active()) and\ - (not self.runtimes_expander_switch.get_active()): + if ( + self.apps_switch.get_active() + and (not self.runtimes_switch.get_active()) + and (not self.remotes_expander_switch.get_active()) + and (not self.runtimes_expander_switch.get_active()) + ): self.apply_button.set_sensitive(False) return @@ -69,7 +71,7 @@ class FilterWindow(Adw.Window): def runtimesEnableHandler(self, switch, is_enabled): self.runtimes_expander.set_enable_expansion(is_enabled) - + for i in range(len(self.runtime_checkboxes)): self.runtime_checkboxes[i].set_active(not is_enabled) @@ -82,21 +84,25 @@ class FilterWindow(Adw.Window): self.filter_list[4].append(runtime) else: self.filter_list[4].remove(runtime) - + self.isListApplicable() def generateList(self): self.remotes_expander_switch = Gtk.Switch(valign=Gtk.Align.CENTER) self.runtimes_expander_switch = Gtk.Switch(valign=Gtk.Align.CENTER) - + dependent_runtimes = self.my_utils.getDependentRuntimes() - if len(self.host_remotes) < 2: # Don't give the ability to filter by remotes if there is only 1 + if ( + len(self.host_remotes) < 2 + ): # Don't give the ability to filter by remotes if there is only 1 self.remotes_expander.set_visible(False) - if len(dependent_runtimes) < 2: # Don't give the ability to filter by runtimes if there is only 1 + if ( + len(dependent_runtimes) < 2 + ): # Don't give the ability to filter by runtimes if there is only 1 self.runtimes_expander.set_visible(False) - + self.remote_checkboxes = [] total = 0 for i in range(len(self.host_remotes)): @@ -125,7 +131,9 @@ class FilterWindow(Adw.Window): remote_row.add_suffix(remote_check) remote_row.set_activatable_widget(remote_check) - remote_check.connect("toggled", self.remoteCheckHandler, install_type, name) + remote_check.connect( + "toggled", self.remoteCheckHandler, install_type, name + ) self.remote_checkboxes.append(remote_check) remote_check.set_active(True) except: @@ -154,7 +162,7 @@ class FilterWindow(Adw.Window): if not self.remotes_expander_switch.get_active(): self.filter_list[3] = "all" if not self.runtimes_expander_switch.get_active(): - self.filter_list[4] = "all" + self.filter_list[4] = "all" def disableFilterToggle(self, _widget): self.app_window.filter_button.set_active(self.has_apply_button_been_clicked) @@ -176,8 +184,12 @@ class FilterWindow(Adw.Window): self.add_controller(event_controller) # Connections - self.apply_button.connect("clicked", lambda *_: self.setHas_apply_button_been_clicked(True)) - self.apply_button.connect("clicked", lambda *_: main_window.applyFilter(self.filter_list)) + self.apply_button.connect( + "clicked", lambda *_: self.setHas_apply_button_been_clicked(True) + ) + self.apply_button.connect( + "clicked", lambda *_: main_window.applyFilter(self.filter_list) + ) self.apply_button.connect("clicked", lambda *_: self.close()) self.cancel_button.connect("clicked", lambda *_: self.close()) @@ -191,7 +203,7 @@ class FilterWindow(Adw.Window): # Calls self.apps_switch.set_active(True) self.set_size_request(260, 230) - if not self.host_remotes[0][0] == '': + if not self.host_remotes[0][0] == "": self.generateList() else: self.remotes_expander.set_visible(False) @@ -199,5 +211,3 @@ class FilterWindow(Adw.Window): self.filter_list[2] = "all" self.filter_list[3] = "all" self.filter_list[4] = "all" - - diff --git a/src/main.py b/src/main.py index 5ba3474..5a4fb94 100644 --- a/src/main.py +++ b/src/main.py @@ -32,6 +32,7 @@ from .orphans_window import OrphansWindow from .search_install_window import SearchInstallWindow from .const import Config + class WarehouseApplication(Adw.Application): """The main application singleton class.""" @@ -48,22 +49,54 @@ class WarehouseApplication(Adw.Application): self.create_action("preferences", self.on_preferences_action) self.create_action("search", self.on_search_action, ["f"]) self.create_action("manage-data-folders", self.manage_data_shortcut) - self.create_action("toggle-batch-mode", self.batch_mode_shortcut, ["b", "Return"]) - self.create_action("toggle-batch-mode-keypad", self.batch_mode_shortcut, ["KP_Enter"]) # This action is not added to the shortcuts window - self.create_action("manage-data-folders", self.manage_data_shortcut, ["d"]) - self.create_action("refresh-list", self.refresh_list_shortcut, ["r", "F5"]) - self.create_action("show-remotes-window", self.show_remotes_shortcut, ["m"]) + self.create_action( + "toggle-batch-mode", + self.batch_mode_shortcut, + ["b", "Return"], + ) + self.create_action( + "toggle-batch-mode-keypad", self.batch_mode_shortcut, ["KP_Enter"] + ) # This action is not added to the shortcuts window + self.create_action( + "manage-data-folders", self.manage_data_shortcut, ["d"] + ) + self.create_action( + "refresh-list", self.refresh_list_shortcut, ["r", "F5"] + ) + self.create_action( + "show-remotes-window", self.show_remotes_shortcut, ["m"] + ) self.create_action("set-filter", self.filters_shortcut, ["t"]) self.create_action("install-from-file", self.install_from_file, ["o"]) self.create_action("open-menu", self.main_menu_shortcut, ["F10"]) # self.create_action("open-search-install", self.open_search_install, ["i"]) - gtk_version = str(Gtk.MAJOR_VERSION) + "." + str(Gtk.MINOR_VERSION) + "." + str(Gtk.MICRO_VERSION) - adw_version = str(Adw.MAJOR_VERSION) + "." + str(Adw.MINOR_VERSION) + "." + str(Adw.MICRO_VERSION) + gtk_version = ( + str(Gtk.MAJOR_VERSION) + + "." + + str(Gtk.MINOR_VERSION) + + "." + + str(Gtk.MICRO_VERSION) + ) + adw_version = ( + str(Adw.MAJOR_VERSION) + + "." + + str(Adw.MINOR_VERSION) + + "." + + str(Adw.MICRO_VERSION) + ) os_string = GLib.get_os_info("NAME") + " " + GLib.get_os_info("VERSION") lang = GLib.environ_getenv(GLib.get_environ(), "LANG") - self.troubleshooting = self.troubleshooting.format( os = os_string, wv = self.version, gtk = gtk_version, adw = adw_version, profile = Config.PROFILE, app_id = self.get_application_id(), lang = lang ) + self.troubleshooting = self.troubleshooting.format( + os=os_string, + wv=self.version, + gtk=gtk_version, + adw=adw_version, + profile=Config.PROFILE, + app_id=self.get_application_id(), + lang=lang, + ) def open_search_install(self, widget, _): SearchInstallWindow(self.props.active_window).present() @@ -129,25 +162,37 @@ class WarehouseApplication(Adw.Application): application_icon="io.github.flattool.Warehouse", developer_name="Heliguy", version=self.version, - developers=["Heliguy https://github.com/heliguy4599", "kramo https://kramo.hu"], - artists=["Heliguy https://github.com/heliguy4599", "kramo https://kramo.hu", "Amy https://github.com/AtiusAmy", "eryn https://github.com/hericiumvevo"], - copyright='© 2023 Heliguy', + developers=[ + "Heliguy https://github.com/heliguy4599", + "kramo https://kramo.hu", + ], + artists=[ + "Heliguy https://github.com/heliguy4599", + "kramo https://kramo.hu", + "Amy https://github.com/AtiusAmy", + "eryn https://github.com/hericiumvevo", + ], + copyright="© 2023 Heliguy", license_type=Gtk.License.GPL_3_0_ONLY, debug_info=self.troubleshooting, # Translators: do one of the following, one per line: Your Name, Your Name , Your Name https://websi.te translator_credits=_("translator-credits"), debug_info_filename="{}.txt".format(self.get_application_id()), - website='https://github.com/flattool/warehouse', - support_url='https://matrix.to/#/#warehouse-development:matrix.org', - issue_url='https://github.com/flattool/warehouse/issues') + website="https://github.com/flattool/warehouse", + support_url="https://matrix.to/#/#warehouse-development:matrix.org", + issue_url="https://github.com/flattool/warehouse/issues", + ) about.add_link(_("Donate"), "https://github.com/flattool/warehouse/issues") - about.add_credit_section(_("Contributors"), [ - # Contributors: do one of the following, one per line: Your Name, Your Name , Your Name https://websi.te - "Win ", - "Óscar Fernández Díaz", - "Runar https://github.com/runarcn", - "skøldis " - ]) + about.add_credit_section( + _("Contributors"), + [ + # Contributors: do one of the following, one per line: Your Name, Your Name , Your Name https://websi.te + "Win ", + "Óscar Fernández Díaz", + "Runar https://github.com/runarcn", + "skøldis ", + ], + ) about.present() def on_preferences_action(self, widget, _): @@ -155,7 +200,9 @@ class WarehouseApplication(Adw.Application): print("app.preferences action activated") def on_search_action(self, widget, _): - self.props.active_window.search_bar.set_search_mode(not self.props.active_window.search_bar.get_search_mode()) + self.props.active_window.search_bar.set_search_mode( + not self.props.active_window.search_bar.get_search_mode() + ) def create_action(self, name, callback, shortcuts=None): """Add an application action. diff --git a/src/orphans_window.py b/src/orphans_window.py index 70a140c..04157fe 100644 --- a/src/orphans_window.py +++ b/src/orphans_window.py @@ -4,6 +4,7 @@ import subprocess import os import pathlib + @Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/orphans.ui") class OrphansWindow(Adw.Window): __gtype_name__ = "OrphansWindow" @@ -37,7 +38,7 @@ class OrphansWindow(Adw.Window): def key_handler(self, _a, event, _c, _d): if event == Gdk.KEY_Escape: self.close() - + def selectionHandler(self, widget, dir_name): if widget.get_active(): self.selected_dirs.append(dir_name) @@ -45,9 +46,13 @@ class OrphansWindow(Adw.Window): self.selected_dirs.remove(dir_name) if len(self.selected_dirs) == 0: - self.set_title(self.window_title) # Set the window title back to what it was when there are no selected dirs + self.set_title( + self.window_title + ) # Set the window title back to what it was when there are no selected dirs else: - self.set_title(("{} selected").format(str(len(self.selected_dirs)))) # Set the window title to the amount of selected dirs + self.set_title( + ("{} selected").format(str(len(self.selected_dirs))) + ) # Set the window title to the amount of selected dirs if len(self.selected_dirs) == 0: self.install_button.set_sensitive(False) @@ -67,12 +72,14 @@ class OrphansWindow(Adw.Window): self.generateList() self.progress_bar.set_visible(False) self.app_window.refresh_list_of_flatpaks(self, False) - self.disconnect(self.no_close_id) # Make window able to close + self.disconnect(self.no_close_id) # Make window able to close self.search_button.set_sensitive(True) if self.my_utils.install_success: self.toast_overlay.add_toast(Adw.Toast.new(_("Installed successfully"))) else: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not install some apps"))) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not install some apps")) + ) def installHandler(self): self.main_stack.set_visible_child(self.installing) @@ -80,15 +87,20 @@ class OrphansWindow(Adw.Window): self.set_title(self.window_title) self.keep_checking = True task = Gio.Task.new(None, None, self.installCallback) - task.run_in_thread(lambda _task, _obj, _data, _cancellable, id_list=self.selected_dirs, remote=self.selected_remote, app_type=self.selected_remote_type, progress_bar=self.progress_bar: self.my_utils.installFlatpak(id_list, remote, app_type, progress_bar)) - - def installButtonHandler(self, button): + task.run_in_thread( + lambda _task, _obj, _data, _cancellable, id_list=self.selected_dirs, remote=self.selected_remote, app_type=self.selected_remote_type, progress_bar=self.progress_bar: self.my_utils.installFlatpak( + id_list, remote, app_type, progress_bar + ) + ) + def installButtonHandler(self, button): def remote_select_handler(button, index): if not button.get_active(): return self.selected_remote = self.host_remotes[index][0] - self.selected_remote_type = self.my_utils.getInstallType(self.host_remotes[index][7]) + self.selected_remote_type = self.my_utils.getInstallType( + self.host_remotes[index][7] + ) def onResponse(dialog, response_id, _function): if response_id == "cancel": @@ -96,9 +108,15 @@ class OrphansWindow(Adw.Window): self.installHandler() self.progress_bar.set_visible(True) self.action_bar.set_visible(False) - self.no_close_id = self.connect("close-request", lambda event: True) # Make window unable to close - - dialog = Adw.MessageDialog.new(self, _("Attempt to Install?"), _("Warehouse will attempt to install apps matching the selected data.")) + self.no_close_id = self.connect( + "close-request", lambda event: True + ) # Make window unable to close + + dialog = Adw.MessageDialog.new( + self, + _("Attempt to Install?"), + _("Warehouse will attempt to install apps matching the selected data."), + ) dialog.set_close_response("cancel") dialog.add_response("cancel", _("Cancel")) dialog.add_response("continue", _("Install")) @@ -135,7 +153,7 @@ class OrphansWindow(Adw.Window): else: remote_row.set_subtitle(_("Unknown install type")) - if remote_row.get_title() == '-': + if remote_row.get_title() == "-": remote_row.set_title(self.host_remotes[i][0]) if total_added > 0: @@ -146,7 +164,7 @@ class OrphansWindow(Adw.Window): total_added += 1 remote_select_buttons[0].set_active(True) - + if total_added > 1: dialog.set_extra_child(remotes_scroll) @@ -154,7 +172,6 @@ class OrphansWindow(Adw.Window): dialog.present() def trashHandler(self, button): - def onResponse(dialog, response_id, _function): if response_id == "cancel": return @@ -163,8 +180,10 @@ class OrphansWindow(Adw.Window): self.my_utils.trashFolder(path) self.select_all_button.set_active(False) self.generateList() - - dialog = Adw.MessageDialog.new(self, _("Trash folders?"), _("These folders will be sent to the trash.")) + + dialog = Adw.MessageDialog.new( + self, _("Trash folders?"), _("These folders will be sent to the trash.") + ) dialog.connect("response", onResponse, dialog.choose_finish) dialog.set_close_response("cancel") dialog.add_response("cancel", _("Cancel")) @@ -176,7 +195,9 @@ class OrphansWindow(Adw.Window): try: Gio.AppInfo.launch_default_for_uri(f"file://{path}", None) except GLib.GError: - properties_toast_overlay.add_toast(Adw.Toast.new(_("Could not open folder"))) + properties_toast_overlay.add_toast( + Adw.Toast.new(_("Could not open folder")) + ) def sizeCallBack(self, row_index): row = self.list_of_data.get_row_at_index(row_index) @@ -191,8 +212,10 @@ class OrphansWindow(Adw.Window): self.data_rows = [] self.host_flatpaks = self.my_utils.getHostFlatpaks() - if self.host_flatpaks == [['', '']]: - self.app_window.toast_overlay.add_toast(Adw.Toast.new(_("Could not manage data"))) + if self.host_flatpaks == [["", ""]]: + self.app_window.toast_overlay.add_toast( + Adw.Toast.new(_("Could not manage data")) + ) self.this_just_crashes_the_window_so_it_doesnt_open() return @@ -221,12 +244,24 @@ class OrphansWindow(Adw.Window): self.data_rows.append([dir_row]) path = self.user_data_path + dir_name index = len(self.data_rows) - 1 - task = Gio.Task.new(None, None, lambda *_, index=index: self.sizeCallBack(index)) - task.run_in_thread(lambda _task, _obj, _data, _cancellable, *_, index=index: self.sizeThread(index, path)) + task = Gio.Task.new( + None, None, lambda *_, index=index: self.sizeCallBack(index) + ) + task.run_in_thread( + lambda _task, _obj, _data, _cancellable, *_, index=index: self.sizeThread( + index, path + ) + ) - open_row_button = Gtk.Button(icon_name="document-open-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("Open User Data Folder")) + open_row_button = Gtk.Button( + icon_name="document-open-symbolic", + valign=Gtk.Align.CENTER, + tooltip_text=_("Open User Data Folder"), + ) open_row_button.add_css_class("flat") - open_row_button.connect("clicked", self.open_button_handler, (self.user_data_path + dir_name)) + open_row_button.connect( + "clicked", self.open_button_handler, (self.user_data_path + dir_name) + ) dir_row.add_suffix(open_row_button) select_button = Gtk.CheckButton() @@ -247,7 +282,7 @@ class OrphansWindow(Adw.Window): self.action_bar.set_visible(True) def filter_func(self, row): - if (self.search_entry.get_text().lower() in row.get_title().lower()): + if self.search_entry.get_text().lower() in row.get_title().lower(): self.is_result = True return True @@ -276,7 +311,9 @@ class OrphansWindow(Adw.Window): def __init__(self, main_window, **kwargs): super().__init__(**kwargs) - self.my_utils = myUtils(self) # Access common utils and set the window to this window + self.my_utils = myUtils( + self + ) # Access common utils and set the window to this window self.host_remotes = self.my_utils.getHostRemotes() self.host_flatpaks = self.my_utils.getHostFlatpaks() @@ -294,7 +331,7 @@ class OrphansWindow(Adw.Window): self.add_controller(event_controller) self.install_button.connect("clicked", self.installButtonHandler) - if self.host_remotes[0][0] == '': + if self.host_remotes[0][0] == "": self.install_button.set_visible(False) self.trash_button.connect("clicked", self.trashHandler) self.select_all_button.connect("toggled", self.selectAllHandler) @@ -304,4 +341,4 @@ class OrphansWindow(Adw.Window): self.search_entry.connect("search-changed", self.on_invalidate) self.search_bar.connect("notify", self.on_change) self.search_bar.connect_entry(self.search_entry) - self.oepn_folder_button.connect("clicked", self.open_button_handler) \ No newline at end of file + self.oepn_folder_button.connect("clicked", self.open_button_handler) diff --git a/src/properties_window.py b/src/properties_window.py index e45b0eb..1ff378a 100644 --- a/src/properties_window.py +++ b/src/properties_window.py @@ -4,12 +4,13 @@ import subprocess import os import pathlib + @Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/properties.ui") class PropertiesWindow(Adw.Window): __gtype_name__ = "PropertiesWindow" - - new_env = dict( os.environ ) - new_env['LC_ALL'] = 'C' + + new_env = dict(os.environ) + new_env["LC_ALL"] = "C" host_home = str(pathlib.Path.home()) user_data_path = host_home + "/.var/app/" @@ -81,9 +82,19 @@ class PropertiesWindow(Adw.Window): def generateLower(self): column_headers = [ - _('Name'), _('Description'), _('App ID'), _('Version'), _('Branch'), - _('Arch'), _('Origin'), _('Installation'), _('Ref'), _('Active Commit'), - _('Latest Commit'), _('Installed Size'), _('Options') + _("Name"), + _("Description"), + _("App ID"), + _("Version"), + _("Branch"), + _("Arch"), + _("Origin"), + _("Installation"), + _("Ref"), + _("Active Commit"), + _("Latest Commit"), + _("Installed Size"), + _("Options"), ] for i in range(len(column_headers)): @@ -93,7 +104,10 @@ class PropertiesWindow(Adw.Window): row = Adw.ActionRow(title=column_headers[i], activatable=True) row.add_suffix(Gtk.Image.new_from_icon_name("edit-copy-symbolic")) row.set_subtitle(GLib.markup_escape_text(self.current_flatpak[i])) - row.connect("activated", lambda *_a, row=row: self.copyItem(row.get_subtitle(), row.get_title())) + row.connect( + "activated", + lambda *_a, row=row: self.copyItem(row.get_subtitle(), row.get_title()), + ) self.lower.add(row) def viewAppsHandler(self, widget): @@ -121,16 +135,20 @@ class PropertiesWindow(Adw.Window): self.open_data.set_visible(False) self.trash_data.set_visible(False) else: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not trash user data"))) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not trash user data")) + ) - dialog = Adw.MessageDialog.new(self, _("Send {}'s User Data to the Trash?").format(self.app_name)) + dialog = Adw.MessageDialog.new( + self, _("Send {}'s User Data to the Trash?").format(self.app_name) + ) dialog.add_response("cancel", _("Cancel")) dialog.set_close_response("cancel") dialog.add_response("continue", _("Trash Data")) dialog.set_response_appearance("continue", Adw.ResponseAppearance.DESTRUCTIVE) dialog.connect("response", onResponse, dialog.choose_finish) dialog.present() - + def __init__(self, flatpak_index, host_flatpaks, parent_window, **kwargs): super().__init__(**kwargs) self.my_utils = myUtils(self) @@ -147,27 +165,47 @@ class PropertiesWindow(Adw.Window): self.user_data_path += self.app_id self.details.connect("activated", self.show_details) - self.runtime_copy.connect("clicked", lambda *_: self.copyItem(self.runtime.get_subtitle(), self.runtime.get_title())) + self.runtime_copy.connect( + "clicked", + lambda *_: self.copyItem( + self.runtime.get_subtitle(), self.runtime.get_title() + ), + ) self.runtime_properties.connect("clicked", lambda *_: self.close()) - self.runtime_properties.connect("clicked", lambda *_: self.showPropertiesHandler()) + self.runtime_properties.connect( + "clicked", lambda *_: self.showPropertiesHandler() + ) self.view_apps.connect("activated", self.viewAppsHandler) self.trash_data.connect("clicked", lambda *_: self.trashDataHandler()) - + if "eol" in self.current_flatpak[12]: self.eol_app_banner.set_revealed(True) - self.eol_app_banner.set_title(_("{} has reached its End of Life and will not receive any security updates").format(self.app_name)) + self.eol_app_banner.set_title( + _( + "{} has reached its End of Life and will not receive any security updates" + ).format(self.app_name) + ) if self.current_flatpak[13] in parent_window.eol_list: self.eol_runtime_banner.set_revealed(True) - self.eol_runtime_banner.set_title(_("{}'s runtime has reached its End of Life and will not receive any security updates").format(self.app_name)) + self.eol_runtime_banner.set_title( + _( + "{}'s runtime has reached its End of Life and will not receive any security updates" + ).format(self.app_name) + ) - if self.app_id in self.my_utils.getHostMasks("system") or self.app_id in self.my_utils.getHostMasks("user"): + if self.app_id in self.my_utils.getHostMasks( + "system" + ) or self.app_id in self.my_utils.getHostMasks("user"): self.mask_banner.set_revealed(True) - self.mask_banner.set_title(_("{} is masked and will not be updated").format(self.app_name)) + self.mask_banner.set_title( + _("{} is masked and will not be updated").format(self.app_name) + ) def key_handler(_a, event, _c, _d): if event == Gdk.KEY_Escape: self.close() + event_controller = Gtk.EventControllerKey() event_controller.connect("key-pressed", key_handler) self.add_controller(event_controller) @@ -178,4 +216,4 @@ class PropertiesWindow(Adw.Window): self.set_title(_("{} Properties").format(self.app_name)) self.set_size_request(260, 230) self.set_transient_for(parent_window) - self.present() \ No newline at end of file + self.present() diff --git a/src/remotes_window.py b/src/remotes_window.py index 09f2408..61682a0 100644 --- a/src/remotes_window.py +++ b/src/remotes_window.py @@ -4,6 +4,7 @@ import subprocess import os import re + @Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/remotes.ui") class RemotesWindow(Adw.Window): __gtype_name__ = "RemotesWindow" @@ -34,7 +35,12 @@ class RemotesWindow(Adw.Window): self.toast_overlay.add_toast(Adw.Toast.new(text)) def get_host_flatpaks(self): - output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "list", "--columns=all"], capture_output=True, text=True, env=self.new_env).stdout + output = subprocess.run( + ["flatpak-spawn", "--host", "flatpak", "list", "--columns=all"], + capture_output=True, + text=True, + env=self.new_env, + ).stdout lines = output.strip().split("\n") columns = lines[0].split("\t") data = [columns] @@ -50,7 +56,15 @@ class RemotesWindow(Adw.Window): name = self.host_remotes[index][0] title = self.host_remotes[index][1] install_type = self.host_remotes[index][7] - command = ['flatpak-spawn', '--host', 'flatpak', 'remote-delete', '--force', name, f'--{install_type}'] + command = [ + "flatpak-spawn", + "--host", + "flatpak", + "remote-delete", + "--force", + name, + f"--{install_type}", + ] try: subprocess.run(command, capture_output=True, check=True, env=self.new_env) except subprocess.CalledProcessError as e: @@ -63,7 +77,9 @@ class RemotesWindow(Adw.Window): title = self.host_remotes[index][1] install_type = self.host_remotes[index][7] - body_text = _("Any installed apps from {} will stop receiving updates").format(name) + body_text = _("Any installed apps from {} will stop receiving updates").format( + name + ) dialog = Adw.MessageDialog.new(self, _("Remove {}?").format(title), body_text) dialog.set_close_response("cancel") dialog.add_response("cancel", _("Cancel")) @@ -82,11 +98,24 @@ class RemotesWindow(Adw.Window): type = "user" try: - command = ['flatpak-spawn', '--host', 'flatpak', 'remote-modify', name, f"--{type}", "--enable"] + command = [ + "flatpak-spawn", + "--host", + "flatpak", + "remote-modify", + name, + f"--{type}", + "--enable", + ] subprocess.run(command, capture_output=False, check=True, env=self.new_env) except subprocess.CalledProcessError as e: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not enable {}").format(name))) - print(f"error in remotes_window.enable_handler: could not enable remote {name}:", e) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not enable {}").format(name)) + ) + print( + f"error in remotes_window.enable_handler: could not enable remote {name}:", + e, + ) self.generate_list() @@ -95,11 +124,26 @@ class RemotesWindow(Adw.Window): if response == "cancel": return try: - command = ['flatpak-spawn', '--host', 'flatpak', 'remote-modify', name, f"--{type}", "--disable"] - subprocess.run(command, capture_output=False, check=True, env=self.new_env) + command = [ + "flatpak-spawn", + "--host", + "flatpak", + "remote-modify", + name, + f"--{type}", + "--disable", + ] + subprocess.run( + command, capture_output=False, check=True, env=self.new_env + ) except subprocess.CalledProcessError as e: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not disable {}").format(name))) - print(f"error in remotes_window.enable_handler: could not disable remote {name}:", e) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not disable {}").format(name)) + ) + print( + f"error in remotes_window.enable_handler: could not disable remote {name}:", + e, + ) self.generate_list() @@ -114,7 +158,9 @@ class RemotesWindow(Adw.Window): popoever.popdown() - body_text = _("Any installed apps from {} will stop receiving updates").format(name) + body_text = _("Any installed apps from {} will stop receiving updates").format( + name + ) dialog = Adw.MessageDialog.new(self, _("Disable {}?").format(title), body_text) dialog.set_close_response("cancel") dialog.add_response("cancel", _("Cancel")) @@ -130,7 +176,10 @@ class RemotesWindow(Adw.Window): type = "system" else: self.make_toast(_("Could not view apps").format(to_copy)) - print("error in remotes_window.view_apps(): remote installation type is not either system or user. type is:", type) + print( + "error in remotes_window.view_apps(): remote installation type is not either system or user. type is:", + type, + ) return self.app_window.should_open_filter_window = False self.app_window.filter_button.set_active(True) @@ -140,9 +189,13 @@ class RemotesWindow(Adw.Window): def generate_list(self): if self.show_disabled_button.get_active(): - self.show_disabled_button_button_content.set_icon_name("eye-open-negative-filled-symbolic") + self.show_disabled_button_button_content.set_icon_name( + "eye-open-negative-filled-symbolic" + ) else: - self.show_disabled_button_button_content.set_icon_name("eye-not-looking-symbolic") + self.show_disabled_button_button_content.set_icon_name( + "eye-not-looking-symbolic" + ) self.host_remotes = self.my_utils.getHostRemotes() self.host_flatpaks = self.get_host_flatpaks() @@ -164,28 +217,55 @@ class RemotesWindow(Adw.Window): install_type = self.host_remotes[i][7] remote_row = Adw.ActionRow(title=title) - more = Gtk.MenuButton(icon_name="view-more-symbolic", valign=Gtk.Align.CENTER) + more = Gtk.MenuButton( + icon_name="view-more-symbolic", valign=Gtk.Align.CENTER + ) more.add_css_class("flat") options = Gtk.Popover() - options_box = Gtk.Box(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, orientation=Gtk.Orientation.VERTICAL) - + options_box = Gtk.Box( + halign=Gtk.Align.CENTER, + valign=Gtk.Align.CENTER, + orientation=Gtk.Orientation.VERTICAL, + ) + filter_button = Gtk.Button() - filter_button.set_child(Adw.ButtonContent(icon_name="funnel-symbolic", label=_("Set Filter"))) + filter_button.set_child( + Adw.ButtonContent( + icon_name="funnel-symbolic", label=_("Set Filter") + ) + ) filter_button.add_css_class("flat") - filter_button.connect("clicked", lambda *_, i=i: self.view_paks(self.host_remotes[i][7], self.host_remotes[i][0])) + filter_button.connect( + "clicked", + lambda *_, i=i: self.view_paks( + self.host_remotes[i][7], self.host_remotes[i][0] + ), + ) enable_button = Gtk.Button(visible=False) - enable_button.set_child(Adw.ButtonContent(icon_name="eye-open-negative-filled-symbolic", label=_("Enable"))) + enable_button.set_child( + Adw.ButtonContent( + icon_name="eye-open-negative-filled-symbolic", label=_("Enable") + ) + ) enable_button.add_css_class("flat") enable_button.connect("clicked", self.enable_handler, i) disable_button = Gtk.Button() - disable_button.set_child(Adw.ButtonContent(icon_name="eye-not-looking-symbolic", label=_("Disable"))) + disable_button.set_child( + Adw.ButtonContent( + icon_name="eye-not-looking-symbolic", label=_("Disable") + ) + ) disable_button.add_css_class("flat") disable_button.connect("clicked", self.disable_handler, i, options) remove_button = Gtk.Button() - remove_button.set_child(Adw.ButtonContent(icon_name="user-trash-symbolic", label=_("Remove"))) + remove_button.set_child( + Adw.ButtonContent( + icon_name="user-trash-symbolic", label=_("Remove") + ) + ) remove_button.add_css_class("flat") remove_button.connect("clicked", self.remove_handler, i, options) @@ -196,7 +276,11 @@ class RemotesWindow(Adw.Window): options.set_child(options_box) more.set_popover(options) - copy_button = Gtk.Button(icon_name="edit-copy-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("Copy remote name")) + copy_button = Gtk.Button( + icon_name="edit-copy-symbolic", + valign=Gtk.Align.CENTER, + tooltip_text=_("Copy remote name"), + ) copy_button.add_css_class("flat") copy_button.connect("clicked", rowCopyHandler, name) @@ -207,7 +291,7 @@ class RemotesWindow(Adw.Window): if install_type == "disabled": if not self.show_disabled_button.get_active(): continue - + remote_row.set_subtitle(_("Disabled")) enable_button.set_visible(True) disable_button.set_visible(False) @@ -227,23 +311,61 @@ class RemotesWindow(Adw.Window): self.rows_in_list.append(remote_row) self.no_remotes.set_visible(False) except Exception as e: - print("error in remotes_window.generate_list: could not add remote. error:", e) + print( + "error in remotes_window.generate_list: could not add remote. error:", + e, + ) # Popular remotes for i in range(len(self.rows_in_popular_list)): self.popular_remotes_list.remove(self.rows_in_popular_list[i]) - + self.rows_in_popular_list = [] remotes = [ - # [Name to show in GUI, Name of remote for system, Link to repo to add, Description of remote] - ["AppCenter", "appcenter", "https://flatpak.elementary.io/repo.flatpakrepo", _("The open source, pay-what-you-want app store from elementary")], - ["Flathub", "flathub", "https://dl.flathub.org/repo/flathub.flatpakrepo", _("Central repository of Flatpak applications")], - ["Flathub beta", "flathub-beta", "https://flathub.org/beta-repo/flathub-beta.flatpakrepo", _("Beta builds of Flatpak applications")], - ["Fedora", "fedora", "oci+https://registry.fedoraproject.org", _("Flatpaks packaged by Fedora Linux")], - ["GNOME Nightly", "gnome-nightly", "https://nightly.gnome.org/gnome-nightly.flatpakrepo", _("The latest beta GNOME Apps and Runtimes")], - ["KDE Testing Applications", "kdeapps", "https://distribute.kde.org/kdeapps.flatpakrepo", _("Beta KDE Apps and Runtimes")], - ["WebKit Developer SDK", "webkit-sdk", "https://software.igalia.com/flatpak-refs/webkit-sdk.flatpakrepo", _("Central repository of the WebKit Developer and Runtime SDK")], + # [Name to show in GUI, Name of remote for system, Link to repo to add, Description of remote] + [ + "AppCenter", + "appcenter", + "https://flatpak.elementary.io/repo.flatpakrepo", + _("The open source, pay-what-you-want app store from elementary"), + ], + [ + "Flathub", + "flathub", + "https://dl.flathub.org/repo/flathub.flatpakrepo", + _("Central repository of Flatpak applications"), + ], + [ + "Flathub beta", + "flathub-beta", + "https://flathub.org/beta-repo/flathub-beta.flatpakrepo", + _("Beta builds of Flatpak applications"), + ], + [ + "Fedora", + "fedora", + "oci+https://registry.fedoraproject.org", + _("Flatpaks packaged by Fedora Linux"), + ], + [ + "GNOME Nightly", + "gnome-nightly", + "https://nightly.gnome.org/gnome-nightly.flatpakrepo", + _("The latest beta GNOME Apps and Runtimes"), + ], + [ + "KDE Testing Applications", + "kdeapps", + "https://distribute.kde.org/kdeapps.flatpakrepo", + _("Beta KDE Apps and Runtimes"), + ], + [ + "WebKit Developer SDK", + "webkit-sdk", + "https://software.igalia.com/flatpak-refs/webkit-sdk.flatpakrepo", + _("Central repository of the WebKit Developer and Runtime SDK"), + ], ] host_remotes = self.my_utils.getHostRemotes() @@ -257,9 +379,11 @@ class RemotesWindow(Adw.Window): for i in range(len(remotes)): if remotes[i][1] in host_remotes_names: continue - + total_added += 1 - row = Adw.ActionRow(title=remotes[i][0], subtitle=(remotes[i][2]), activatable=True) + row = Adw.ActionRow( + title=remotes[i][0], subtitle=(remotes[i][2]), activatable=True + ) row.connect("activated", self.add_handler, remotes[i][1], remotes[i][2]) row.add_suffix(Gtk.Image.new_from_icon_name("right-large-symbolic")) self.rows_in_popular_list.append(row) @@ -275,8 +399,13 @@ class RemotesWindow(Adw.Window): try: subprocess.run(command, capture_output=True, check=True, env=self.new_env) except subprocess.CalledProcessError as e: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not add {}").format(self.name_to_add))) - print("error in remotes_window.addRemoteThread: could not add remote. error:", e) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not add {}").format(self.name_to_add)) + ) + print( + "error in remotes_window.addRemoteThread: could not add remote. error:", + e, + ) def on_add_response(self, _dialog, response_id, _function, row): if response_id == "cancel": @@ -292,9 +421,20 @@ class RemotesWindow(Adw.Window): self.name_to_add = self.name_to_add.strip() self.url_to_add = self.url_to_add.strip() - command = ['flatpak-spawn', '--host', 'flatpak', 'remote-add', '--if-not-exists', self.name_to_add, self.url_to_add, install_type] + command = [ + "flatpak-spawn", + "--host", + "flatpak", + "remote-add", + "--if-not-exists", + self.name_to_add, + self.url_to_add, + install_type, + ] task = Gio.Task.new(None, None, self.addRemoteCallback) - task.run_in_thread(lambda _task, _obj, _data, _cancellable: self.addRemoteThread(command)) + task.run_in_thread( + lambda _task, _obj, _data, _cancellable: self.addRemoteThread(command) + ) def add_handler(self, row, name="", link=""): dialog = Adw.MessageDialog.new(self, _("Add Flatpak Remote")) @@ -308,7 +448,7 @@ class RemotesWindow(Adw.Window): def name_update(widget): is_enabled = True self.name_to_add = widget.get_text() - name_pattern = re.compile(r'^[a-zA-Z\-]+$') + name_pattern = re.compile(r"^[a-zA-Z\-]+$") if not name_pattern.match(self.name_to_add): is_enabled = False @@ -325,7 +465,7 @@ class RemotesWindow(Adw.Window): def url_update(widget): is_enabled = True self.url_to_add = widget.get_text() - url_pattern = re.compile(r'^[a-zA-Z0-9\-._~:/?#[\]@!$&\'()*+,;=]+$') + url_pattern = re.compile(r"^[a-zA-Z0-9\-._~:/?#[\]@!$&\'()*+,;=]+$") if not url_pattern.match(self.url_to_add): is_enabled = False @@ -354,7 +494,7 @@ class RemotesWindow(Adw.Window): info_box = Gtk.Box(orientation="vertical") entry_list = Gtk.ListBox(selection_mode="none", margin_bottom=12) entry_list.add_css_class("boxed-list") - + name_entry = Adw.EntryRow(title=_("Name")) name_entry.set_text(name) name_entry.connect("changed", name_update) @@ -370,13 +510,18 @@ class RemotesWindow(Adw.Window): install_type_list = Gtk.ListBox(selection_mode="none") install_type_list.add_css_class("boxed-list") - user_row = Adw.ActionRow(title=_("User"), subtitle=_("Remote will be available to only you")) + user_row = Adw.ActionRow( + title=_("User"), subtitle=_("Remote will be available to only you") + ) user_check = Gtk.CheckButton(active=True) user_check.connect("toggled", set_user) user_row.add_prefix(user_check) user_row.set_activatable_widget(user_check) - system_row = Adw.ActionRow(title=_("System"), subtitle=_("Remote will be available to every user on the system")) + system_row = Adw.ActionRow( + title=_("System"), + subtitle=_("Remote will be available to every user on the system"), + ) system_check = Gtk.CheckButton() system_row.add_prefix(system_check) system_check.set_group(user_check) @@ -398,11 +543,32 @@ class RemotesWindow(Adw.Window): def addRemoteFromFileThread(self, filepath, system_or_user, name): try: - subprocess.run(['flatpak-spawn', '--host', 'flatpak', 'remote-add', '--if-not-exists', name, filepath, f"--{system_or_user}"], capture_output=True, check=True, env=self.new_env) - self.toast_overlay.add_toast(Adw.Toast.new(_("{} successfully added").format(name))) + subprocess.run( + [ + "flatpak-spawn", + "--host", + "flatpak", + "remote-add", + "--if-not-exists", + name, + filepath, + f"--{system_or_user}", + ], + capture_output=True, + check=True, + env=self.new_env, + ) + self.toast_overlay.add_toast( + Adw.Toast.new(_("{} successfully added").format(name)) + ) except subprocess.CalledProcessError as e: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not add {}").format(self.name_to_add))) - print("error in remotes_window.addRemoteFromFileThread: could not add remote. error:", e) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not add {}").format(self.name_to_add)) + ) + print( + "error in remotes_window.addRemoteFromFileThread: could not add remote. error:", + e, + ) def addRemoteFromFile(self, filepath): def response(dialog, response, _a): @@ -415,12 +581,16 @@ class RemotesWindow(Adw.Window): user_or_system = "system" task = Gio.Task.new(None, None, self.addRemoteCallback) - task.run_in_thread(lambda *_: self.addRemoteFromFileThread(filepath, user_or_system, name_row.get_text())) + task.run_in_thread( + lambda *_: self.addRemoteFromFileThread( + filepath, user_or_system, name_row.get_text() + ) + ) def name_update(widget): is_enabled = True self.name_to_add = widget.get_text() - name_pattern = re.compile(r'^[a-zA-Z\-]+$') + name_pattern = re.compile(r"^[a-zA-Z\-]+$") if not name_pattern.match(self.name_to_add): is_enabled = False @@ -436,7 +606,7 @@ class RemotesWindow(Adw.Window): self.should_pulse = True - name = filepath.split('/') + name = filepath.split("/") name = name[len(name) - 1] dialog = Adw.MessageDialog.new(self, _("Add {}?").format(name)) @@ -452,8 +622,13 @@ class RemotesWindow(Adw.Window): options_list = Gtk.ListBox(selection_mode="none", margin_top=15) name_row = Adw.EntryRow(title=_("Name")) name_row.connect("changed", name_update) - user_row = Adw.ActionRow(title=_("User"), subtitle=_("Remote will be available to only you")) - system_row = Adw.ActionRow(title=_("System"), subtitle=_("Remote will be available to every user on the system")) + user_row = Adw.ActionRow( + title=_("User"), subtitle=_("Remote will be available to only you") + ) + system_row = Adw.ActionRow( + title=_("System"), + subtitle=_("Remote will be available to every user on the system"), + ) user_check = Gtk.CheckButton() system_check = Gtk.CheckButton() @@ -473,7 +648,7 @@ class RemotesWindow(Adw.Window): user_check.set_active(True) options_list.add_css_class("boxed-list") Gtk.Window.present(dialog) - + def file_callback(self, object, result): try: file = object.open_finish(result) @@ -499,8 +674,8 @@ class RemotesWindow(Adw.Window): self.host_remotes = [] self.host_flatpaks = [] self.app_window = main_window - self.new_env = dict( os.environ ) - self.new_env['LC_ALL'] = 'C' + self.new_env = dict(os.environ) + self.new_env["LC_ALL"] = "C" self.should_pulse = False # Window Stuffs @@ -514,12 +689,16 @@ class RemotesWindow(Adw.Window): self.refresh.connect("clicked", lambda *_: self.generate_list()) self.set_transient_for(main_window) - self.add_from_file.add_suffix(Gtk.Image.new_from_icon_name("right-large-symbolic")) + self.add_from_file.add_suffix( + Gtk.Image.new_from_icon_name("right-large-symbolic") + ) self.add_from_file.connect("activated", self.addFromFileHandler) - self.custom_remote.add_suffix(Gtk.Image.new_from_icon_name("right-large-symbolic")) + self.custom_remote.add_suffix( + Gtk.Image.new_from_icon_name("right-large-symbolic") + ) self.custom_remote.connect("activated", self.add_handler) self.show_disabled_button.connect("clicked", lambda *_: self.generate_list()) # Calls self.generate_list() - # self.show_new_remote_options() \ No newline at end of file + # self.show_new_remote_options() diff --git a/src/search_install_window.py b/src/search_install_window.py index cf9f9d5..af1b5e8 100644 --- a/src/search_install_window.py +++ b/src/search_install_window.py @@ -4,8 +4,13 @@ import subprocess import os import pathlib -@Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/search_install.ui") -class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when search is changed + +@Gtk.Template( + resource_path="/io/github/flattool/Warehouse/../data/ui/search_install.ui" +) +class SearchInstallWindow( + Adw.Window +): # TODO: stop execution of thread when search is changed __gtype_name__ = "SearchInstallWindow" results_list_box = Gtk.Template.Child() @@ -25,7 +30,9 @@ class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when se def searchResponse(self, a, b): self.results_list_box.remove_all() print(self.search_results) - if (self.is_debug and len(self.search_results) == 5) or (len(self.search_results) == 1 and len(self.search_results[0]) == 1): #This is unreliable with G_DEBUG + if (self.is_debug and len(self.search_results) == 5) or ( + len(self.search_results) == 1 and len(self.search_results[0]) == 1 + ): # This is unreliable with G_DEBUG self.main_stack.set_visible_child(self.no_results) return if len(self.search_results) > 50: @@ -35,12 +42,20 @@ class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when se for i in range(len(self.search_results)): try: print("creating row {}".format(str(i))) - row = Adw.ActionRow(title=GLib.markup_escape_text(self.search_results[i][0]), subtitle=self.search_results[i][2]) + row = Adw.ActionRow( + title=GLib.markup_escape_text(self.search_results[i][0]), + subtitle=self.search_results[i][2], + ) print("row {} is {}".format(str(i), self.search_results[i][0])) check = Gtk.CheckButton() check.add_css_class("selection-mode") check.connect("toggled", self.on_check) - label = Gtk.Label(label=self.search_results[i][3], justify=Gtk.Justification.RIGHT, wrap=True, hexpand=True) + label = Gtk.Label( + label=self.search_results[i][3], + justify=Gtk.Justification.RIGHT, + wrap=True, + hexpand=True, + ) row.add_suffix(label) row.add_suffix(check) row.set_activatable_widget(check) @@ -52,11 +67,20 @@ class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when se print(button.get_active()) def searchThread(self): - command = ["flatpak-spawn", "--host", "flatpak", "search", "--columns=all", self.to_search] + command = [ + "flatpak-spawn", + "--host", + "flatpak", + "search", + "--columns=all", + self.to_search, + ] if self.remote_to_search: command += self.remote_to_search - output = subprocess.run(command, capture_output=True, text=True, env=self.new_env).stdout + output = subprocess.run( + command, capture_output=True, text=True, env=self.new_env + ).stdout lines = output.strip().split("\n") columns = lines[0].split("\t") data = [columns] @@ -83,7 +107,7 @@ class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when se remotes_pop = Gtk.Popover() remotes_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) # remotes_pop.set_size_request(400, 1) # why? - remotes_pop.set_child(remotes_box) # don't use ScrolledWindows in popovers! + remotes_pop.set_child(remotes_box) # don't use ScrolledWindows in popovers! # why not just comment this code out and leave it unimplemented— it does nothing of use for i in range(1, 3): @@ -107,8 +131,8 @@ class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when se self.my_utils = myUtils(self) self.search_results = [] self.to_search = "" - self.new_env = dict( os.environ ) - self.new_env['LC_ALL'] = 'C' + self.new_env = dict(os.environ) + self.new_env["LC_ALL"] = "C" event_controller = Gtk.EventControllerKey() event_controller.connect("key-pressed", self.key_handler) self.cancel_button.connect("clicked", lambda *_: self.close()) @@ -130,6 +154,3 @@ class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when se self.remote_to_search = [] self.main_stack.set_visible_child(self.blank_page) - - - diff --git a/src/snapshots_window.py b/src/snapshots_window.py index 69818f5..5d34863 100644 --- a/src/snapshots_window.py +++ b/src/snapshots_window.py @@ -5,15 +5,18 @@ import os import pathlib import time + @Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/snapshots.ui") class SnapshotsWindow(Adw.Window): __gtype_name__ = "SnapshotsWindow" - - new_env = dict( os.environ ) - new_env['LC_ALL'] = 'C' + + new_env = dict(os.environ) + new_env["LC_ALL"] = "C" host_home = str(pathlib.Path.home()) user_data_path = host_home + "/.var/app/" - snapshots_path = host_home + "/.var/app/io.github.flattool.Warehouse/data/Snapshots/" + snapshots_path = ( + host_home + "/.var/app/io.github.flattool.Warehouse/data/Snapshots/" + ) snapshots_group = Gtk.Template.Child() main_stack = Gtk.Template.Child() @@ -28,7 +31,7 @@ class SnapshotsWindow(Adw.Window): def showListOrEmpty(self): try: - self.disconnect(self.no_close_id) # Make window able to close + self.disconnect(self.no_close_id) # Make window able to close except: pass @@ -51,7 +54,7 @@ class SnapshotsWindow(Adw.Window): snapshot_files = os.listdir(self.snapshots_of_app_path) to_trash = [] - + for i in range(len(snapshot_files)): if not snapshot_files[i].endswith(".tar.zst"): # Find all files that aren't snapshots @@ -81,8 +84,13 @@ class SnapshotsWindow(Adw.Window): task = Gio.Task() task.run_in_thread(sizeThread) - - label = Gtk.Label(label=_("Version {}").format(split_file[1]), hexpand=True, wrap=True, justify=Gtk.Justification.RIGHT) + + label = Gtk.Label( + label=_("Version {}").format(split_file[1]), + hexpand=True, + wrap=True, + justify=Gtk.Justification.RIGHT, + ) row.add_suffix(label) apply = Gtk.Button(icon_name="check-plain-symbolic", valign=Gtk.Align.CENTER) @@ -97,7 +105,7 @@ class SnapshotsWindow(Adw.Window): self.snapshots_group.insert(row, 0) self.main_stack.set_visible_child(self.outerbox) self.open_folder_button.set_sensitive(True) - + def trash_snapshot(self, button, file, row): def on_response(dialog, response, func): if response == "cancel": @@ -109,9 +117,15 @@ class SnapshotsWindow(Adw.Window): self.my_utils.trashFolder(self.snapshots_of_app_path) self.showListOrEmpty() else: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not trash snapshot"))) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not trash snapshot")) + ) - dialog = Adw.MessageDialog.new(self, _("Trash Snapshot?"), _("This snapshot and its contents will be sent to the trash.")) + dialog = Adw.MessageDialog.new( + self, + _("Trash Snapshot?"), + _("This snapshot and its contents will be sent to the trash."), + ) dialog.add_response("cancel", _("Cancel")) dialog.set_close_response("cancel") dialog.add_response("continue", _("Trash Snapshot")) @@ -123,14 +137,25 @@ class SnapshotsWindow(Adw.Window): epoch = int(time.time()) def thread(): - response = self.my_utils.snapshotApps(epoch, [self.snapshots_of_app_path], [self.app_version], [self.app_user_data]) + response = self.my_utils.snapshotApps( + epoch, + [self.snapshots_of_app_path], + [self.app_version], + [self.app_user_data], + ) if response != 0: - GLib.idle_add(self.toast_overlay.add_toast(Adw.Toast.new(_("Could not create snapshot")))) + GLib.idle_add( + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not create snapshot")) + ) + ) return if self.showListOrEmpty() == "list": self.create_row(f"{epoch}_{self.app_version}.tar.zst") - self.no_close_id = self.connect("close-request", lambda event: True) # Make window unable to close + self.no_close_id = self.connect( + "close-request", lambda event: True + ) # Make window unable to close self.loading_label.set_label(_("Creating Snapshot…")) self.action_bar.set_revealed(False) self.main_stack.set_visible_child(self.loading) @@ -140,19 +165,33 @@ class SnapshotsWindow(Adw.Window): def apply_snapshot(self, button, file, row): self.applied = False + def thread(): try: subprocess.run( - ['tar', '--zstd', '-xvf', f"{self.snapshots_of_app_path}{file}", "-C", f"{self.app_user_data}"], - check=True, env=self.new_env + [ + "tar", + "--zstd", + "-xvf", + f"{self.snapshots_of_app_path}{file}", + "-C", + f"{self.app_user_data}", + ], + check=True, + env=self.new_env, ) self.applied = True except subprocess.CalledProcessError as e: - print("error in snapshots_window.apply_snapshot.thread: CalledProcessError:", e) + print( + "error in snapshots_window.apply_snapshot.thread: CalledProcessError:", + e, + ) def callback(): if not self.applied: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not apply snapshot"))) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not apply snapshot")) + ) else: self.toast_overlay.add_toast(Adw.Toast.new(_("Snapshot applied"))) self.parent_window.refresh_list_of_flatpaks(self, False) @@ -168,23 +207,35 @@ class SnapshotsWindow(Adw.Window): if os.path.exists(to_trash): a = self.my_utils.trashFolder(to_trash) if a != 0: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not apply snapshot"))) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not apply snapshot")) + ) return data = Gio.File.new_for_path(self.app_user_data) data.make_directory() if not os.path.exists(data.get_path()): - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not apply snapshot"))) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not apply snapshot")) + ) return - self.no_close_id = self.connect("close-request", lambda event: True) # Make window unable to close + self.no_close_id = self.connect( + "close-request", lambda event: True + ) # Make window unable to close self.loading_label.set_label(_("Applying Snapshot…")) self.action_bar.set_revealed(False) self.main_stack.set_visible_child(self.loading) task = Gio.Task.new(None, None, lambda *_: callback()) task.run_in_thread(lambda *_: thread()) - - dialog = Adw.MessageDialog.new(self, _("Apply Snapshot?"), _("Applying this snapshot will trash any current user data for {}.").format(self.app_name)) + + dialog = Adw.MessageDialog.new( + self, + _("Apply Snapshot?"), + _("Applying this snapshot will trash any current user data for {}.").format( + self.app_name + ), + ) dialog.add_response("cancel", _("Cancel")) dialog.set_close_response("cancel") dialog.add_response("continue", _("Apply Snapshot")) @@ -215,7 +266,11 @@ class SnapshotsWindow(Adw.Window): self.app_user_data = self.user_data_path + self.app_id + "/" self.parent_window = parent_window - if self.app_version == "" or self.app_version == "-" or self.app_version == None: + if ( + self.app_version == "" + or self.app_version == "-" + or self.app_version == None + ): self.app_version = 0.0 if not os.path.exists(self.snapshots_path): @@ -225,9 +280,11 @@ class SnapshotsWindow(Adw.Window): # Calls self.generateList() - self.open_folder_button.connect("clicked", self.open_button_handler, self.snapshots_of_app_path) + self.open_folder_button.connect( + "clicked", self.open_button_handler, self.snapshots_of_app_path + ) self.new_snapshot.connect("clicked", lambda *_: self.createSnapshot()) - + event_controller = Gtk.EventControllerKey() event_controller.connect("key-pressed", self.key_handler) self.add_controller(event_controller) @@ -235,4 +292,4 @@ class SnapshotsWindow(Adw.Window): # Window stuffs self.set_title(_("{} Snapshots").format(self.app_name)) self.set_transient_for(parent_window) - self.set_size_request(0, 230) \ No newline at end of file + self.set_size_request(0, 230) diff --git a/src/window.py b/src/window.py index 55bc396..8f1f2c6 100644 --- a/src/window.py +++ b/src/window.py @@ -33,6 +33,7 @@ from .const import Config from .app_row_widget import AppRow + @Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/window.ui") class WarehouseWindow(Adw.ApplicationWindow): __gtype_name__ = "WarehouseWindow" @@ -86,7 +87,9 @@ class WarehouseWindow(Adw.ApplicationWindow): total_selected = 0 def filter_func(self, row): - if (self.search_entry.get_text().lower() in row.get_title().lower()) or (self.search_entry.get_text().lower() in row.get_subtitle().lower()): + if (self.search_entry.get_text().lower() in row.get_title().lower()) or ( + self.search_entry.get_text().lower() in row.get_subtitle().lower() + ): self.is_result = True return True @@ -114,10 +117,14 @@ class WarehouseWindow(Adw.ApplicationWindow): self.refresh_list_of_flatpaks(self, False) self.toast_overlay.add_toast(Adw.Toast.new(_("Uninstalled successfully"))) else: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not uninstall some apps"))) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not uninstall some apps")) + ) def uninstallFlatpakThread(self, ref_arr, id_arr, type_arr, should_trash): - self.my_utils.uninstallFlatpak(ref_arr, type_arr, should_trash, self.main_progress_bar) + self.my_utils.uninstallFlatpak( + ref_arr, type_arr, should_trash, self.main_progress_bar + ) def uninstallFlatpak(self, should_trash): ref_arr = [] @@ -125,7 +132,7 @@ class WarehouseWindow(Adw.ApplicationWindow): type_arr = [] self.currently_uninstalling = True i = 0 - while(self.flatpaks_list_box.get_row_at_index(i) != None): + while self.flatpaks_list_box.get_row_at_index(i) != None: current = self.flatpaks_list_box.get_row_at_index(i) if current.tickbox.get_active() == True: ref_arr.append(current.app_ref) @@ -134,14 +141,18 @@ class WarehouseWindow(Adw.ApplicationWindow): i += 1 self.set_title(self.main_window_title) task = Gio.Task.new(None, None, self.uninstallFlatpakCallback) - task.run_in_thread(lambda _task, _obj, _data, _cancellable, ref_arr=ref_arr, id_arr=id_arr, type_arr=type_arr, should_trash=should_trash: self.uninstallFlatpakThread(ref_arr, id_arr, type_arr, should_trash)) + task.run_in_thread( + lambda _task, _obj, _data, _cancellable, ref_arr=ref_arr, id_arr=id_arr, type_arr=type_arr, should_trash=should_trash: self.uninstallFlatpakThread( + ref_arr, id_arr, type_arr, should_trash + ) + ) def batchUninstallButtonHandler(self, _widget): has_user_data = False def batchUninstallResponse(_idk, response_id, _widget): if response_id == "cancel": - return 1 + return 1 try: should_trash = trash_check.get_active() @@ -150,32 +161,48 @@ class WarehouseWindow(Adw.ApplicationWindow): self.uninstallButtonsEnable(False) - self.no_close = self.connect("close-request", lambda event: True) # Make window unable to close + self.no_close = self.connect( + "close-request", lambda event: True + ) # Make window unable to close self.main_stack.set_visible_child(self.uninstalling) self.search_button.set_sensitive(False) self.uninstallFlatpak(should_trash) # Create Widgets - dialog = Adw.MessageDialog.new(self, _("Uninstall Selected Apps?"), _("It will not be possible to use these apps after removal.")) + dialog = Adw.MessageDialog.new( + self, + _("Uninstall Selected Apps?"), + _("It will not be possible to use these apps after removal."), + ) # Check to see if at least one app in the list has user data i = 0 - while(True): + while True: current = self.flatpaks_list_box.get_row_at_index(i) i += 1 - if(current == None): + if current == None: break - if current.tickbox.get_active() and os.path.exists(f"{self.user_data_path}{current.app_id}"): + if current.tickbox.get_active() and os.path.exists( + f"{self.user_data_path}{current.app_id}" + ): has_user_data = True break if has_user_data: # Create Widgets options_box = Gtk.Box(orientation="vertical") - header = Gtk.Label(label=_("App Settings & Data"), halign="start", margin_top=10) + header = Gtk.Label( + label=_("App Settings & Data"), halign="start", margin_top=10 + ) options_list = Gtk.ListBox(selection_mode="none", margin_top=15) - keep_data = Adw.ActionRow(title=_("Keep"), subtitle=_("Allow restoring these apps' settings and content")) - trash_data = Adw.ActionRow(title=_("Trash"), subtitle=_("Send these apps' settings and content to the trash")) + keep_data = Adw.ActionRow( + title=_("Keep"), + subtitle=_("Allow restoring these apps' settings and content"), + ) + trash_data = Adw.ActionRow( + title=_("Trash"), + subtitle=_("Send these apps' settings and content to the trash"), + ) keep_check = Gtk.CheckButton() trash_check = Gtk.CheckButton() @@ -209,7 +236,9 @@ class WarehouseWindow(Adw.ApplicationWindow): def uninstallButtonHandler(self, row, name, ref, id): if self.currently_uninstalling: - self.toast_overlay.add_toast(Adw.Toast.new(_("Cannot uninstall while already uninstalling"))) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Cannot uninstall while already uninstalling")) + ) return def uninstallResponse(_idk, response_id, _widget): @@ -226,7 +255,9 @@ class WarehouseWindow(Adw.ApplicationWindow): self.uninstallButtonsEnable(False) - self.no_close = self.connect("close-request", lambda event: True) # Make window unable to close + self.no_close = self.connect( + "close-request", lambda event: True + ) # Make window unable to close self.main_stack.set_visible_child(self.uninstalling) self.search_button.set_sensitive(False) self.uninstallFlatpak(should_trash) @@ -234,15 +265,27 @@ class WarehouseWindow(Adw.ApplicationWindow): row.tickbox.set_active(True) # Create Widgets - dialog = Adw.MessageDialog.new(self, _("Uninstall {}?").format(name), _("It will not be possible to use {} after removal.").format(name)) + dialog = Adw.MessageDialog.new( + self, + _("Uninstall {}?").format(name), + _("It will not be possible to use {} after removal.").format(name), + ) if os.path.exists(f"{self.user_data_path}{id}"): # Create Widgets for Trash options_box = Gtk.Box(orientation="vertical") - header = Gtk.Label(label=_("App Settings & Data"), halign="start", margin_top=10) + header = Gtk.Label( + label=_("App Settings & Data"), halign="start", margin_top=10 + ) options_list = Gtk.ListBox(selection_mode="none", margin_top=15) - keep_data = Adw.ActionRow(title=_("Keep"), subtitle=_("Allow restoring this app's settings and content")) - trash_data = Adw.ActionRow(title=_("Trash"), subtitle=_("Send this app's settings and content to the trash")) + keep_data = Adw.ActionRow( + title=_("Keep"), + subtitle=_("Allow restoring this app's settings and content"), + ) + trash_data = Adw.ActionRow( + title=_("Trash"), + subtitle=_("Send this app's settings and content to the trash"), + ) keep_check = Gtk.CheckButton(active=True) trash_check = Gtk.CheckButton() @@ -283,7 +326,7 @@ class WarehouseWindow(Adw.ApplicationWindow): def create_row(self, index): row = AppRow(self, self.host_flatpaks, index) self.flatpaks_list_box.insert(row, index) - + def generate_list_of_flatpaks(self): self.host_flatpaks = self.my_utils.getHostFlatpaks() self.dependent_runtimes = self.my_utils.getDependentRuntimes() @@ -328,14 +371,20 @@ class WarehouseWindow(Adw.ApplicationWindow): return result = self.my_utils.trashFolder(f"{self.user_data_path}{id}") if result != 0: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not trash user data"))) + self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not trash user data")) + ) return self.lookup_action(f"open-data{index}").set_enabled(False) self.lookup_action(f"trash{index}").set_enabled(False) self.toast_overlay.add_toast(Adw.Toast.new(_("Trashed user data"))) - dialog = Adw.MessageDialog.new(self,_("Send {}'s User Data to the Trash?").format(name)) - dialog.set_body(_("Your files and data for this app will be sent to the trash.")) + dialog = Adw.MessageDialog.new( + self, _("Send {}'s User Data to the Trash?").format(name) + ) + dialog.set_body( + _("Your files and data for this app will be sent to the trash.") + ) dialog.add_response("cancel", _("Cancel")) dialog.set_close_response("cancel") dialog.add_response("continue", _("Trash Data")) @@ -344,12 +393,18 @@ class WarehouseWindow(Adw.ApplicationWindow): dialog.present() def maskFlatpak(self, row): - is_masked = row.mask_label.get_visible() # Check the visibility of the mask label to see if the flatpak is masked + is_masked = ( + row.mask_label.get_visible() + ) # Check the visibility of the mask label to see if the flatpak is masked result = [] def callback(): if result[0] == 1: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not disable updates for {}").format(row.app_name))) + self.toast_overlay.add_toast( + Adw.Toast.new( + _("Could not disable updates for {}").format(row.app_name) + ) + ) return row.set_masked(not is_masked) self.lookup_action(f"mask{row.index}").set_enabled(is_masked) @@ -359,13 +414,23 @@ class WarehouseWindow(Adw.ApplicationWindow): if response == "cancel": return task = Gio.Task.new(None, None, lambda *_: callback()) - task.run_in_thread(lambda *_: result.append(self.my_utils.maskFlatpak(row.app_id, row.install_type, is_masked))) + task.run_in_thread( + lambda *_: result.append( + self.my_utils.maskFlatpak(row.app_id, row.install_type, is_masked) + ) + ) if is_masked: onContinue(self, None) else: - dialog = Adw.MessageDialog.new(self, _("Disable Updates for {}?").format(row.app_name)) - dialog.set_body(_("This will mask {} ensuring it will never recieve any feature or security updates.").format(row.app_name)) + dialog = Adw.MessageDialog.new( + self, _("Disable Updates for {}?").format(row.app_name) + ) + dialog.set_body( + _( + "This will mask {} ensuring it will never recieve any feature or security updates." + ).format(row.app_name) + ) dialog.add_response("cancel", _("Cancel")) dialog.set_close_response("cancel") dialog.add_response("continue", _("Disable Updates")) @@ -380,10 +445,12 @@ class WarehouseWindow(Adw.ApplicationWindow): def runCallback(self, _a, _b): if not self.my_utils.run_app_error: return - + error = self.my_utils.run_app_error_message dialog = Adw.MessageDialog.new(self, _("Could not Run App"), error) - copy_button = Gtk.Button(label=_("Copy"), halign=Gtk.Align.CENTER, margin_top=12) + copy_button = Gtk.Button( + label=_("Copy"), halign=Gtk.Align.CENTER, margin_top=12 + ) copy_button.add_css_class("pill") copy_button.add_css_class("suggested-action") copy_button.connect("clicked", lambda *_: self.clipboard.set(error)) @@ -402,7 +469,7 @@ class WarehouseWindow(Adw.ApplicationWindow): def batch_mode_handler(self, widget): batch_mode = widget.get_active() i = 0 - while(self.flatpaks_list_box.get_row_at_index(i) != None): + while self.flatpaks_list_box.get_row_at_index(i) != None: current = self.flatpaks_list_box.get_row_at_index(i) current.set_selectable(batch_mode) i += 1 @@ -428,7 +495,7 @@ class WarehouseWindow(Adw.ApplicationWindow): return i = 0 trashReturnCodes = 0 - while(True): + while True: current = self.flatpaks_list_box.get_row_at_index(i) i += 1 if current == None: @@ -437,16 +504,30 @@ class WarehouseWindow(Adw.ApplicationWindow): continue trash = self.my_utils.trashFolder(f"{self.user_data_path}{current.app_id}") if trash == 1: - self.toast_overlay.add_toast(Adw.Toast.new(_("{} has no data to trash").format(current.app_name))) + self.toast_overlay.add_toast( + Adw.Toast.new(_("{} has no data to trash").format(current.app_name)) + ) continue if trash == 2: - self.toast_overlay.add_toast(Adw.Toast.new(_("Could not trash {}'s data").format(current.app_name))) + self.toast_overlay.add_toast( + Adw.Toast.new( + _("Could not trash {}'s data").format(current.app_name) + ) + ) continue - self.lookup_action(f"open-data{current.index}").set_enabled(False) # Disable the Open User Data dropdown option when the data was deleted - self.lookup_action(f"trash{current.index}").set_enabled(False) # Disable the Trash User Data dropdown option when the data was deleted + self.lookup_action(f"open-data{current.index}").set_enabled( + False + ) # Disable the Open User Data dropdown option when the data was deleted + self.lookup_action(f"trash{current.index}").set_enabled( + False + ) # Disable the Trash User Data dropdown option when the data was deleted def batchCleanHandler(self, widget): - dialog = Adw.MessageDialog.new(self, _("Trash Selected Apps' User Data?"), _("Your files and data for these apps will be sent to the trash.")) + dialog = Adw.MessageDialog.new( + self, + _("Trash Selected Apps' User Data?"), + _("Your files and data for these apps will be sent to the trash."), + ) dialog.set_close_response("cancel") dialog.add_response("cancel", _("Cancel")) dialog.add_response("continue", _("Trash Data")) @@ -458,18 +539,22 @@ class WarehouseWindow(Adw.ApplicationWindow): self.set_select_all(widget.get_active()) def batchSnapshotHandler(self, widget): - def batchSnapshotResponse(dialog, response, _a): if response == "cancel": return i = 0 - snapshots_path = self.host_home + "/.var/app/io.github.flattool.Warehouse/data/Snapshots/" + snapshots_path = ( + self.host_home + + "/.var/app/io.github.flattool.Warehouse/data/Snapshots/" + ) snapshot_arr = [] app_ver_arr = [] app_data_arr = [] epoch = int(time.time()) - self.no_close = self.connect("close-request", lambda event: True) # Make window unable to close - while(self.flatpaks_list_box.get_row_at_index(i) != None): + self.no_close = self.connect( + "close-request", lambda event: True + ) # Make window unable to close + while self.flatpaks_list_box.get_row_at_index(i) != None: current = self.flatpaks_list_box.get_row_at_index(i) i += 1 if current.tickbox.get_active() == False: @@ -479,11 +564,21 @@ class WarehouseWindow(Adw.ApplicationWindow): snapshot_arr.append(snapshots_path + current.app_id + "/") app_ver_arr.append(current.app_version) app_data_arr.append(f"{self.user_data_path}{current.app_id}") - + def thread(): - capture = self.my_utils.snapshotApps(epoch, snapshot_arr, app_ver_arr, app_data_arr, self.main_progress_bar) + capture = self.my_utils.snapshotApps( + epoch, + snapshot_arr, + app_ver_arr, + app_data_arr, + self.main_progress_bar, + ) if capture != 0: - GLib.idle_add(lambda *_: self.toast_overlay.add_toast(Adw.Toast.new(_("Could not snapshot some apps")))) + GLib.idle_add( + lambda *_: self.toast_overlay.add_toast( + Adw.Toast.new(_("Could not snapshot some apps")) + ) + ) def callback(*args): self.main_stack.set_visible_child(self.main_box) @@ -503,17 +598,22 @@ class WarehouseWindow(Adw.ApplicationWindow): task = Gio.Task.new(None, None, callback) task.run_in_thread(lambda *_: thread()) - dialog = Adw.MessageDialog.new(self, _("Create Snapshots?"), _("Snapshots are backups of the app's user data. They can be reapplied at any time. This could take a while.")) + dialog = Adw.MessageDialog.new( + self, + _("Create Snapshots?"), + _( + "Snapshots are backups of the app's user data. They can be reapplied at any time. This could take a while." + ), + ) dialog.set_close_response("cancel") dialog.add_response("cancel", _("Cancel")) dialog.add_response("continue", _("Create Snapshots")) dialog.connect("response", batchSnapshotResponse, dialog.choose_finish) Gtk.Window.present(dialog) - def set_select_all(self, should_select_all): i = 0 - while(self.flatpaks_list_box.get_row_at_index(i) != None): + while self.flatpaks_list_box.get_row_at_index(i) != None: current = self.flatpaks_list_box.get_row_at_index(i) if current.get_visible() == True: current.tickbox.set_active(should_select_all) @@ -551,10 +651,10 @@ class WarehouseWindow(Adw.ApplicationWindow): def copyNames(self, widget, _a): to_copy = "" i = 0 - while(True): + while True: current = self.flatpaks_list_box.get_row_at_index(i) i += 1 - if(current == None): + if current == None: break if current.tickbox.get_active(): to_copy += f"{current.app_name}\n" @@ -564,10 +664,10 @@ class WarehouseWindow(Adw.ApplicationWindow): def copyIDs(self, widget, _a): to_copy = "" i = 0 - while(True): + while True: current = self.flatpaks_list_box.get_row_at_index(i) i += 1 - if(current == None): + if current == None: break if current.tickbox.get_active(): to_copy += f"{current.app_id}\n" @@ -577,10 +677,10 @@ class WarehouseWindow(Adw.ApplicationWindow): def copyRefs(self, widget, _a): to_copy = "" i = 0 - while(True): + while True: current = self.flatpaks_list_box.get_row_at_index(i) i += 1 - if(current == None): + if current == None: break if current.tickbox.get_active(): to_copy += f"{current.app_ref}\n" @@ -614,34 +714,34 @@ class WarehouseWindow(Adw.ApplicationWindow): self.set_select_all(False) index = 0 - while(self.flatpaks_list_box.get_row_at_index(index) != None): + while self.flatpaks_list_box.get_row_at_index(index) != None: current = self.flatpaks_list_box.get_row_at_index(index) visible = True if show_apps == False and current.is_runtime == False: visible = False - + if show_runtimes == False and current.is_runtime == True: visible = False - if (not 'all' in filter_install_type): + if not "all" in filter_install_type: if not current.install_type in filter_install_type: visible = False - if (not 'all' in filter_remotes_list): + if not "all" in filter_remotes_list: if not current.origin_remote in filter_remotes_list: visible = False - if (not 'all' in filter_runtimes_list): + if not "all" in filter_runtimes_list: if not current.dependent_runtime in filter_runtimes_list: visible = False - + if visible == True: total_visible += 1 - + current.set_visible(visible) index += 1 - + if total_visible == 0: self.main_stack.set_visible_child(self.no_matches) self.search_button.set_sensitive(False) @@ -659,7 +759,9 @@ class WarehouseWindow(Adw.ApplicationWindow): self.toast_overlay.add_toast(Adw.Toast.new(_("Could not install app"))) def installThread(self, filepath, user_or_system): - self.my_utils.installFlatpak([filepath], None, user_or_system, self.main_progress_bar) + self.my_utils.installFlatpak( + [filepath], None, user_or_system, self.main_progress_bar + ) def install_file(self, filepath): def response(dialog, response, _a): @@ -675,7 +777,7 @@ class WarehouseWindow(Adw.ApplicationWindow): task = Gio.Task.new(None, None, self.installCallback) task.run_in_thread(lambda *_: self.installThread(filepath, user_or_system)) - name = filepath.split('/') + name = filepath.split("/") name = name[len(name) - 1] dialog = Adw.MessageDialog.new(self, _("Install {}?").format(name)) @@ -688,8 +790,13 @@ class WarehouseWindow(Adw.ApplicationWindow): # Create Widgets options_box = Gtk.Box(orientation="vertical") options_list = Gtk.ListBox(selection_mode="none", margin_top=15) - user_row = Adw.ActionRow(title=_("User"), subtitle=_("The app will be available to only you")) - system_row = Adw.ActionRow(title=_("System"), subtitle=_("The app will be available to every user on the system")) + user_row = Adw.ActionRow( + title=_("User"), subtitle=_("The app will be available to only you") + ) + system_row = Adw.ActionRow( + title=_("System"), + subtitle=_("The app will be available to every user on the system"), + ) user_check = Gtk.CheckButton() system_check = Gtk.CheckButton() @@ -751,23 +858,33 @@ class WarehouseWindow(Adw.ApplicationWindow): self.filter_list = [True, False, ["all"], ["all"], ["all"]] self.set_size_request(0, 230) self.settings = Gio.Settings.new("io.github.flattool.Warehouse") - self.settings.bind("window-width", self, "default-width", Gio.SettingsBindFlags.DEFAULT) - self.settings.bind("window-height", self, "default-height", Gio.SettingsBindFlags.DEFAULT) - self.settings.bind("is-maximized", self, "maximized", Gio.SettingsBindFlags.DEFAULT) - self.settings.bind("is-fullscreen", self, "fullscreened", Gio.SettingsBindFlags.DEFAULT) + self.settings.bind( + "window-width", self, "default-width", Gio.SettingsBindFlags.DEFAULT + ) + self.settings.bind( + "window-height", self, "default-height", Gio.SettingsBindFlags.DEFAULT + ) + self.settings.bind( + "is-maximized", self, "maximized", Gio.SettingsBindFlags.DEFAULT + ) + self.settings.bind( + "is-fullscreen", self, "fullscreened", Gio.SettingsBindFlags.DEFAULT + ) - self.new_env = dict( os.environ ) - self.new_env['LC_ALL'] = 'C' + self.new_env = dict(os.environ) + self.new_env["LC_ALL"] = "C" - if self.host_flatpaks == [['', '']]: + if self.host_flatpaks == [["", ""]]: self.windowSetEmpty(True) return self.flatpaks_list_box.set_filter_func(self.filter_func) - + task = Gio.Task() - task.run_in_thread(lambda *_: GLib.idle_add(lambda *_: self.generate_list_of_flatpaks())) - + task.run_in_thread( + lambda *_: GLib.idle_add(lambda *_: self.generate_list_of_flatpaks()) + ) + self.search_entry.connect("search-changed", self.on_invalidate) self.search_bar.connect_entry(self.search_entry) self.search_bar.connect("notify", self.on_change) @@ -775,7 +892,9 @@ class WarehouseWindow(Adw.ApplicationWindow): self.batch_mode_button.connect("toggled", self.batch_mode_handler) self.batch_clean_button.connect("clicked", self.batchCleanHandler) self.batch_uninstall_button.connect("clicked", self.batchUninstallButtonHandler) - self.batch_select_all_button.connect("clicked", self.batchSelectAllButtonHandler) + self.batch_select_all_button.connect( + "clicked", self.batchSelectAllButtonHandler + ) self.batch_snapshot_button.connect("clicked", self.batchSnapshotHandler) self.batchActionsEnable(False) event_controller = Gtk.EventControllerKey() @@ -796,4 +915,3 @@ class WarehouseWindow(Adw.ApplicationWindow): if Config.DEVEL: self.add_css_class("devel") -