From 0bd56e3ad1621b82808192dd8dd83e0db9403e21 Mon Sep 17 00:00:00 2001 From: heliguy4599 Date: Thu, 10 Oct 2024 23:42:53 -0400 Subject: [PATCH] Implement package reinstalling --- src/packages_page/packages_page.blp | 7 ++ src/packages_page/packages_page.py | 6 ++ src/properties_page/properties_page.py | 119 +++++++++++++++---------- 3 files changed, 83 insertions(+), 49 deletions(-) diff --git a/src/packages_page/packages_page.blp b/src/packages_page/packages_page.blp index 4beb786..5b4c3f9 100644 --- a/src/packages_page/packages_page.blp +++ b/src/packages_page/packages_page.blp @@ -33,6 +33,13 @@ template $PackagesPage : Adw.BreakpointBin { $SidebarButton {} } } + Adw.ToolbarView reinstalling_view { + [top] + Adw.HeaderBar { + [start] + $SidebarButton {} + } + } Adw.NavigationSplitView packages_split { sidebar-width-fraction: 0.5; max-sidebar-width: 999999999; diff --git a/src/packages_page/packages_page.py b/src/packages_page/packages_page.py index e3d2cae..74559fc 100644 --- a/src/packages_page/packages_page.py +++ b/src/packages_page/packages_page.py @@ -7,6 +7,7 @@ from .filters_page import FiltersPage from .sidebar_button import SidebarButton from .uninstall_dialog import UninstallDialog from .loading_status import LoadingStatus +from .package_install_worker import PackageInstallWorker import subprocess, os @Gtk.Template(resource_path="/io/github/flattool/Warehouse/packages_page/packages_page.ui") @@ -20,6 +21,7 @@ class PackagesPage(Adw.BreakpointBin): scrolled_window = gtc() loading_view = gtc() uninstalling_view = gtc() + reinstalling_view = gtc() no_filter_results = gtc() reset_filters_button = gtc() no_packages = gtc() @@ -80,6 +82,8 @@ class PackagesPage(Adw.BreakpointBin): self.stack.set_visible_child(self.loading_view) elif to_set is self.uninstalling: self.stack.set_visible_child(self.uninstalling_view) + elif to_set is self.reinstalling: + self.stack.set_visible_child(self.reinstalling_view) else: self.stack.set_visible_child(self.packages_split) self.status_stack.set_visible_child(to_set) @@ -313,6 +317,8 @@ class PackagesPage(Adw.BreakpointBin): self.loading_packages = LoadingStatus(_("Loading Packages"), _("This should only take a moment")) self.uninstalling = LoadingStatus(_("Uninstalling Packages"), _("This should only take a moment")) self.uninstalling_view.set_content(self.uninstalling) + self.reinstalling = LoadingStatus(_("Reinstalling Package"), _("This could take a while"), True, PackageInstallWorker.cancel) + self.reinstalling_view.set_content(self.reinstalling) self.properties_page = PropertiesPage(main_window, self) self.filters_page = FiltersPage(main_window, self) self.filter_settings = Gio.Settings.new("io.github.flattool.Warehouse.filter") diff --git a/src/properties_page/properties_page.py b/src/properties_page/properties_page.py index 9b92d63..cdb86b0 100644 --- a/src/properties_page/properties_page.py +++ b/src/properties_page/properties_page.py @@ -4,6 +4,7 @@ from .host_info import HostInfo from .change_version_page import ChangeVersionPage from .uninstall_dialog import UninstallDialog from .loading_status import LoadingStatus +from .package_install_worker import PackageInstallWorker import subprocess, os @Gtk.Template(resource_path="/io/github/flattool/Warehouse/properties_page/properties_page.ui") @@ -13,10 +14,10 @@ class PropertiesPage(Adw.NavigationPage): stack = gtc() error_tbv = gtc() loading_tbv = gtc() - + more_menu = gtc() more_list = gtc() - + nav_view = gtc() inner_nav_page = gtc() toast_overlay = gtc() @@ -49,7 +50,7 @@ class PropertiesPage(Adw.NavigationPage): arch_row = gtc() branch_row = gtc() license_row = gtc() - + sdk_row = gtc() origin_row = gtc() collection_row = gtc() @@ -59,14 +60,15 @@ class PropertiesPage(Adw.NavigationPage): parent_row = gtc() subject_row = gtc() date_row = gtc() - + package = None - + def set_properties(self, package, refresh=False): if package == self.package and not refresh: # Do not update the ui if the same app row is clicked return - + + self.reinstall_did_error = False self.package = package pkg_name = package.info["name"] if pkg_name != "": @@ -76,12 +78,12 @@ class PropertiesPage(Adw.NavigationPage): else: self.name.set_visible(False) self.inner_nav_page.set_title(_("Properties")) - + if package.icon_path: GLib.idle_add(lambda *_: self.app_icon.set_from_file(package.icon_path)) else: GLib.idle_add(lambda *_: self.app_icon.set_from_icon_name("application-x-executable-symbolic")) - + self.eol_box.set_visible(package.is_eol) self.pin_row.set_visible(package.is_runtime) self.open_app_button.set_visible(package.is_runtime) @@ -93,29 +95,29 @@ class PropertiesPage(Adw.NavigationPage): has_path = os.path.exists(package.data_path) self.trash_data_button.set_sensitive(has_path) self.open_data_button.set_sensitive(has_path) - + if not self.package.dependant_runtime is None: self.runtime_row.set_visible(True) self.runtime_row.set_subtitle(self.package.dependant_runtime.info["name"]) self.eol_package_package_status_icon.set_visible(self.package.dependant_runtime.is_eol) - + if has_path: self.trash_data_button.set_visible(False) self.open_data_button.set_visible(False) self.data_spinner.set_visible(True) self.data_row.set_subtitle(_("Loading User Data")) - + def callback(size): self.trash_data_button.set_visible(True) self.open_data_button.set_visible(True) self.data_spinner.set_visible(False) self.data_row.set_subtitle(size) - + self.package.get_data_size(lambda size: callback(size)) else: self.data_row.set_subtitle(_("No User Data")) self.data_spinner.set_visible(False) - + cli_info = None try: cli_info = package.get_cli_info() @@ -125,10 +127,10 @@ class PropertiesPage(Adw.NavigationPage): except Exception as e: self.toast_overlay.add_toast(ErrorToast(_("Could not get properties"), str(e)).toast) return - + for key, row in self.info_rows.items(): row.set_visible(False) - + try: subtitle = cli_info[key] row.set_subtitle(subtitle) @@ -141,7 +143,7 @@ class PropertiesPage(Adw.NavigationPage): except Exception as e: self.toast_overlay.add_toast(ErrorToast(_("Could not get properties"), str(e)).toast) continue - + self.mask_label.set_visible(package.is_masked) self.mask_switch.set_active(package.is_masked) self.pin_switch.set_active(package.is_pinned) @@ -150,14 +152,14 @@ class PropertiesPage(Adw.NavigationPage): if self.open_app_button.get_visible(): self.more_list.append(self.view_snapshots) self.more_list.append(self.copy_launch_command) - + self.more_list.append(self.show_details) self.more_list.append(self.reinstall) def open_data_handler(self, *args): if error := self.package.open_data(): self.toast_overlay.add_toast(ErrorToast(_("Could not open data"), str(error)).toast) - + def trash_data_handler(self, *args): def on_choice(dialog, response): if response != 'continue': @@ -170,7 +172,7 @@ class PropertiesPage(Adw.NavigationPage): self.toast_overlay.add_toast(ErrorToast(_("Could not trash data"), cpe.stderr).toast) except Exception as e: self.toast_overlay.add_toast(ErrorToast(_("Could not trash data"), str(e)).toast) - + dialog = Adw.AlertDialog( heading=_("Send {}'s User Data to the Trash?").format(self.package.info["name"]), body=_("Your settings and data for this app will be sent to the trash") @@ -180,7 +182,7 @@ class PropertiesPage(Adw.NavigationPage): dialog.connect("response", on_choice) dialog.set_response_appearance('continue', Adw.ResponseAppearance.DESTRUCTIVE) dialog.present(self.main_window) - + def set_mask_handler(self, *args): state = not self.mask_switch.get_active() def callback(*args): @@ -194,9 +196,9 @@ class PropertiesPage(Adw.NavigationPage): self.toast_overlay.add_toast(Adw.Toast(title=response)) GLib.idle_add(lambda *_: self.mask_switch.set_active(state)) self.package.app_row.masked_status_icon.set_visible(state) - + self.package.set_mask(state, callback) - + def set_pin_handler(self, *args): state = not self.pin_switch.get_active() def callback(*args): @@ -210,9 +212,9 @@ class PropertiesPage(Adw.NavigationPage): self.toast_overlay.add_toast(Adw.Toast(title=response)) GLib.idle_add(lambda *_: self.pin_switch.set_active(state)) self.package.app_row.pinned_status_icon.set_visible(state) - + self.package.set_pin(state, callback) - + def uninstall_handler(self, *args): def on_choice(should_trash): self.packages_page.set_status(self.packages_page.uninstalling) @@ -226,7 +228,7 @@ class PropertiesPage(Adw.NavigationPage): self.toast_overlay.add_toast(ErrorToast(_("Could not trash data"), cpe.stderr).toast) except Exception as e: self.toast_overlay.add_toast(ErrorToast(_("Could not trash data"), str(e)).toast) - + def callback(*args): if fail := self.package.failed_uninstall: fail = fail.stderr if type(fail) == subprocess.CalledProcessError else fail @@ -235,16 +237,16 @@ class PropertiesPage(Adw.NavigationPage): else: self.main_window.refresh_handler() self.packages_page.packages_toast_overlay.add_toast(Adw.Toast(title=_("Uninstalled {}").format(self.package.info["name"]))) - + # name = self.package.info["name"] dialog = UninstallDialog(on_choice, os.path.exists(self.package.data_path), self.package.info["name"]) dialog.present(self.main_window) - + def runtime_row_handler(self, *args): new_page = self.__class__(self.main_window, self.packages_page) new_page.set_properties(self.package.dependant_runtime) self.nav_view.push(new_page) - + def open_app_handler(self, *args): self.toast_overlay.add_toast(Adw.Toast(title=_("Openeing {}…").format(self.package.info["name"]))) @@ -252,17 +254,26 @@ class PropertiesPage(Adw.NavigationPage): if fail := self.package.failed_app_run: fail = fail.stderr if type(fail) == subprocess.CalledProcessError else fail self.toast_overlay.add_toast(ErrorToast(_("Could not open {}").format(self.package.info["name"]), str(fail)).toast) - + self.package.open_app(callback) - + def copy_handler(self, row): HostInfo.clipboard.set(row.get_subtitle()) self.toast_overlay.add_toast(Adw.Toast(title=_("Copied {}").format(row.get_title()))) - + def change_version_handler(self, row): page = ChangeVersionPage(self.main_window, self.package) self.nav_view.push(page) - + + def reinstall_callback(self): + HostInfo.main_window.refresh_handler() + if not self.reinstall_did_error: + HostInfo.main_window.toast_overlay.add_toast(Adw.Toast(title=_("Reinstalled {}").format(self.package.info['name']))) + + def reinstall_error_callback(self, user_facing_label, error_message): + self.reinstall_did_error = True + GLib.idle_add(lambda *_: HostInfo.main_window.toast_overlay.add_toast(ErrorToast(user_facing_label, error_message).toast)) + def more_menu_handler(self, listbox, row): self.more_menu.popdown() match row.get_child(): @@ -271,43 +282,55 @@ class PropertiesPage(Adw.NavigationPage): snapshots_page = HostInfo.main_window.pages[snapshots_row] HostInfo.main_window.activate_row(snapshots_row) snapshots_page.show_snapshot(self.package) - + case self.copy_launch_command: try: HostInfo.clipboard.set(f"flatpak run {self.package.info['ref']}") self.toast_overlay.add_toast(Adw.Toast.new(_("Copied launch command"))) except Exception as e: self.toast_overlay.add_toast(ErrorToast(_("Could not copy launch command"), str(e)).toast) - + case self.show_details: try: Gio.AppInfo.launch_default_for_uri(f"appstream://{self.package.info['id']}", None) except Exception as e: self.toast_overlay.add_toast(ErrorToast(_("Could not show details"), str(e)).toast) - + case self.reinstall: - print("not implemented") - + self.reinstall_did_error = False + PackageInstallWorker.install( + [{ + "installation": self.package.info['installation'], + "remote": self.package.info['origin'], + "package_names": [self.package.info['ref']], + "extra_flags": ["--reinstall"], + }], + self.packages_page.reinstalling, + self.reinstall_callback, + self.reinstall_error_callback, + ) + self.packages_page.set_status(self.packages_page.reinstalling) + def __init__(self, main_window, packages_page, **kwargs): super().__init__(**kwargs) - + # Extra Object Creation self.main_window = main_window self.info_rows = { "version": self.version_row, "installed": self.installed_size_row, - + "id": self.id_row, "ref": self.ref_row, "arch": self.arch_row, "branch": self.branch_row, "license": self.license_row, - + "sdk": self.sdk_row, "origin": self.origin_row, "collection": self.collection_row, "installation": self.installation_row, - + "commit": self.commit_row, "parent": self.parent_row, "subject": self.subject_row, @@ -320,9 +343,10 @@ class PropertiesPage(Adw.NavigationPage): self.copy_launch_command = Gtk.Label(halign=Gtk.Align.START, label=_("Copy Launch Command")) self.show_details = Gtk.Label(halign=Gtk.Align.START, label=_("Show Details")) self.reinstall = Gtk.Label(halign=Gtk.Align.START, label=_("Reinstall")) - + self.reinstall_did_error = False + # Apply - + # Connections self.more_list.connect("row-activated", self.more_menu_handler) self.open_data_button.connect("clicked", self.open_data_handler) @@ -334,9 +358,6 @@ class PropertiesPage(Adw.NavigationPage): self.mask_row.connect("activated", self.set_mask_handler) self.pin_row.connect("activated", self.set_pin_handler) self.change_version_row.connect("activated", self.change_version_handler) - for key in self.info_rows: - row = self.info_rows[key] - if type(row) != Adw.ActionRow: - continue - - row.connect("activated", self.copy_handler) + for key, row in self.info_rows.items(): + if type(row) is Adw.ActionRow: + row.connect("activated", self.copy_handler)