from gi.repository import Gtk, Adw, GLib, Gdk, Gio from .common import myUtils import subprocess import os import pathlib @Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/properties.ui") class PropertiesWindow(Adw.Dialog): __gtype_name__ = "PropertiesWindow" new_env = dict(os.environ) new_env["LC_ALL"] = "C" host_home = str(pathlib.Path.home()) user_data_path = host_home + "/.var/app/" toast_overlay = Gtk.Template.Child() upper = Gtk.Template.Child() app_icon = Gtk.Template.Child() data_row = Gtk.Template.Child() open_data = Gtk.Template.Child() trash_data = Gtk.Template.Child() spinner = Gtk.Template.Child() details = Gtk.Template.Child() view_apps = Gtk.Template.Child() runtime = Gtk.Template.Child() runtime_properties = Gtk.Template.Child() runtime_copy = Gtk.Template.Child() lower = Gtk.Template.Child() eol_app_banner = Gtk.Template.Child() eol_runtime_banner = Gtk.Template.Child() mask_banner = Gtk.Template.Child() description = Gtk.Template.Child() name = Gtk.Template.Child() def copy_item(self, to_copy, to_toast=None): self.get_clipboard().set(to_copy) if to_toast: self.toast_overlay.add_toast(Adw.Toast.new(_("Copied {}").format(to_toast))) def open_button_handler(self, widget): try: Gio.AppInfo.launch_default_for_uri(f"file://{self.user_data_path}", None) except GLib.GError: self.toast_overlay.add_toast(Adw.Toast.new(_("Could not open folder"))) def show_details(self, widget): try: Gio.AppInfo.launch_default_for_uri(f"appstream://{self.app_id}", None) except GLib.GError: self.toast_overlay.add_toast(Adw.Toast.new(_("Could not show details"))) def get_size_callback(self, *args): self.open_data.set_visible(True) self.open_data.connect("clicked", self.open_button_handler) self.trash_data.set_visible(True) self.data_row.set_title(_("User Data")) self.data_row.set_subtitle(f"~{self.size}") self.spinner.set_visible(False) def get_size_thread(self, *args): self.size = self.my_utils.get_size_with_format(self.user_data_path) def generate_upper(self): image = self.my_utils.find_app_icon(self.app_id) self.runtime.set_subtitle(self.current_flatpak[13]) if image.get_paintable() == None: self.app_icon.set_from_icon_name(image.get_icon_name()) else: self.app_icon.set_from_paintable(image.get_paintable()) if os.path.exists(self.user_data_path): task = Gio.Task.new(None, None, self.get_size_callback) task.run_in_thread(self.get_size_thread) else: self.data_row.set_title("") self.data_row.set_subtitle(_("No User Data")) self.spinner.set_visible(False) if "runtime" in self.current_flatpak[12]: # Pak is a runtime self.runtime.set_visible(False) if self.app_ref in self.parent_window.dependent_runtimes: self.view_apps.set_visible(True) def generate_lower(self): info = self.my_utils.get_flatpak_info(self.app_ref, self.install_type) name_desc = info["name"].split(" - ") self.name.set_label((name_desc[0])) try: self.description.set_label((name_desc[1])) except: pass for key in info.keys(): if key == "name": continue row = Adw.ActionRow( title=GLib.markup_escape_text(key), subtitle=GLib.markup_escape_text(info[key]), activatable=True, ) row.add_suffix(Gtk.Image.new_from_icon_name("edit-copy-symbolic")) row.add_css_class("property") row.connect( "activated", lambda *_a, row=row: self.copy_item( row.get_subtitle(), row.get_title() ), ) self.lower.add(row) def view_apps_handler(self, widget): settings = Gio.Settings.new("io.github.flattool.Warehouse.filter") for key in settings.list_keys(): settings.reset(key) settings.set_string("runtimes-list", f"{self.app_ref},") self.parent_window.apply_filter() self.close() def show_properties_handler(self): runtime = self.current_flatpak[13] for i in range(len(self.host_flatpaks)): # open the properties when the flatpak matches the runtime *and* installation type if runtime in self.host_flatpaks[i][8] and self.install_type in self.host_flatpaks[i][12]: PropertiesWindow(i, self.host_flatpaks, self.parent_window) self.close() return self.toast_overlay.add_toast(Adw.Toast.new(_("Could not show properties"))) def trash_data_handler(self): def on_response(_none, response, widget): if response == "cancel": return if self.my_utils.trash_folder(self.user_data_path) == 0: self.toast_overlay.add_toast(Adw.Toast.new(_("Trashed user data"))) self.data_row.set_title(_("No User Data")) self.data_row.set_subtitle("") 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")) ) dialog = Adw.AlertDialog.new( _("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", on_response, dialog.choose_finish) dialog.present(self) def __init__(self, flatpak_index, host_flatpaks, parent_window, **kwargs): super().__init__(**kwargs) self.my_utils = myUtils(self) self.current_flatpak = host_flatpaks[flatpak_index] self.parent_window = parent_window self.host_flatpaks = host_flatpaks self.flatpak_index = flatpak_index self.app_name = self.current_flatpak[0] self.app_id = self.current_flatpak[2] self.origin_remote = self.current_flatpak[6] self.install_type = self.current_flatpak[7] self.app_ref = self.current_flatpak[8] self.user_data_path += self.app_id self.details.connect("activated", self.show_details) self.runtime_copy.connect( "clicked", lambda *_: self.copy_item( self.runtime.get_subtitle(), self.runtime.get_title() ), ) self.runtime_properties.connect( "clicked", lambda *_: self.show_properties_handler() ) self.view_apps.connect("activated", self.view_apps_handler) self.trash_data.connect("clicked", lambda *_: self.trash_data_handler()) 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) ) 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) ) if self.app_id in self.my_utils.get_host_masks( "system" ) or self.app_id in self.my_utils.get_host_masks("user"): self.mask_banner.set_revealed(True) self.mask_banner.set_title( _("{} is masked and will not be updated").format(self.app_name) ) self.generate_upper() self.generate_lower() self.set_title(_("{} Properties").format(self.app_name)) self.present(parent_window)