diff --git a/po/flattool-gui.pot b/po/flattool-gui.pot index db58444..d584091 100644 --- a/po/flattool-gui.pot +++ b/po/flattool-gui.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: flattool-gui\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-02 14:45-0400\n" +"POT-Creation-Date: 2023-09-02 15:21-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -25,245 +25,156 @@ msgstr "" msgid "No description" msgstr "" -#: src/window.py:28 +#: src/window.py:29 msgid "Flattwol" msgstr "" -#: src/window.py:133 +#: src/window.py:134 msgid "The app will be removed from your system." msgstr "" -#: src/window.py:135 src/window.py:292 src/window.py:403 src/window.py:617 -#: src/window.py:650 +#: src/window.py:136 src/window.py:293 src/window.py:495 src/window.py:528 msgid "Cancel" msgstr "" -#: src/window.py:136 src/window.py:651 src/window.blp:77 +#: src/window.py:137 src/window.py:529 src/window.blp:77 msgid "Uninstall" msgstr "" -#: src/window.py:140 +#: src/window.py:141 msgid "" "The app will be removed from your system. Optionally, you can also trash its " "user data." msgstr "" -#: src/window.py:141 src/window.py:652 +#: src/window.py:142 src/window.py:530 msgid "Uninstall and Trash Data" msgstr "" -#: src/window.py:149 +#: src/window.py:150 msgid "Manage Leftover Data" msgstr "" -#: src/window.py:174 +#: src/window.py:175 msgid "No Data" msgstr "" -#: src/window.py:174 +#: src/window.py:175 msgid "There is no leftover user data" msgstr "" -#: src/window.py:175 src/window.blp:101 +#: src/window.py:176 src/window.blp:101 msgid "Please Wait" msgstr "" -#: src/window.py:175 +#: src/window.py:176 msgid "" "Flattool is attempting to install the selected apps. This could take a while." msgstr "" -#: src/window.py:211 +#: src/window.py:212 msgid "~" msgstr "" -#: src/window.py:237 +#: src/window.py:238 msgid "Can't trash {}" msgstr "" -#: src/window.py:242 +#: src/window.py:243 msgid "Successfilly trashed data" msgstr "" -#: src/window.py:264 +#: src/window.py:265 msgid "Can't install {}" msgstr "" -#: src/window.py:271 +#: src/window.py:272 msgid "Installed all apps" msgstr "" -#: src/window.py:290 +#: src/window.py:291 msgid "Choose a Remote" msgstr "" -#: src/window.py:296 +#: src/window.py:297 msgid "" "Choose the Flatpak Remote Repository where attempted app downloads will be " "from." msgstr "" -#: src/window.py:306 +#: src/window.py:307 msgid "Continue" msgstr "" -#: src/window.py:313 +#: src/window.py:314 msgid "Select All" msgstr "" -#: src/window.py:317 +#: src/window.py:318 msgid "Trash Selected" msgstr "" -#: src/window.py:322 +#: src/window.py:323 msgid "Attempt to Install Selected" msgstr "" -#: src/window.py:348 +#: src/window.py:349 msgid "{} Selected" msgstr "" -#: src/window.py:356 -msgid "Properties of {}" -msgstr "" - -#: src/window.py:393 src/window.py:611 -msgid "Trashed user data" -msgstr "" - -#: src/window.py:397 -msgid "Can't trash data" -msgstr "" - -#: src/window.py:400 -msgid "Send {}'s User Data to the Trash?" -msgstr "" - -#: src/window.py:401 -msgid "Your user files and data for this app will be sent to the trash." -msgstr "" - -#: src/window.py:404 -msgid "Send Data to Trash" -msgstr "" - -#: src/window.py:414 -msgid "Can't open folder" -msgstr "" - -#: src/window.py:418 -msgid "Copied {}" -msgstr "" - -#: src/window.py:446 -msgid "Open Data Folder" -msgstr "" - -#: src/window.py:458 -msgid "Name" -msgstr "" - -#: src/window.py:458 -msgid "Description" -msgstr "" - -#: src/window.py:458 -msgid "App ID" -msgstr "" - -#: src/window.py:458 -msgid "Version" -msgstr "" - -#: src/window.py:458 -msgid "Branch" -msgstr "" - -#: src/window.py:458 -msgid "Arch" -msgstr "" - -#: src/window.py:458 -msgid "Origin" -msgstr "" - -#: src/window.py:458 -msgid "Installation" -msgstr "" - -#: src/window.py:458 -msgid "Ref" -msgstr "" - -#: src/window.py:458 -msgid "Active Commit" -msgstr "" - -#: src/window.py:458 -msgid "Latest Commit" -msgstr "" - -#: src/window.py:458 -msgid "Installed Size" -msgstr "" - -#: src/window.py:458 -msgid "Options" -msgstr "" - -#: src/window.py:465 -msgid "Copy {}" -msgstr "" - -#: src/window.py:532 +#: src/window.py:410 msgid "Uninstall {}" msgstr "" -#: src/window.py:537 +#: src/window.py:415 msgid "View Properties" msgstr "" -#: src/window.py:563 +#: src/window.py:441 msgid "List refreshed" msgstr "" -#: src/window.py:593 +#: src/window.py:471 msgid "Copied selected app IDs" msgstr "" -#: src/window.py:606 +#: src/window.py:484 msgid "No user data for {}" msgstr "" -#: src/window.py:609 +#: src/window.py:487 msgid "Can't trash user data for {}" msgstr "" -#: src/window.py:615 +#: src/window.py:489 +msgid "Trashed user data" +msgstr "" + +#: src/window.py:493 msgid "Delete Selected User Data?" msgstr "" -#: src/window.py:615 +#: src/window.py:493 msgid "This user data will be sent to the trash." msgstr "" -#: src/window.py:618 +#: src/window.py:496 msgid "Trash Data" msgstr "" -#: src/window.py:641 +#: src/window.py:519 msgid "Can't uninstall {}" msgstr "" -#: src/window.py:643 +#: src/window.py:521 msgid "Uninstalled apps" msgstr "" -#: src/window.py:648 +#: src/window.py:526 msgid "Uninstall Selected Apps?" msgstr "" -#: src/window.py:648 +#: src/window.py:526 msgid "Optionally, you can also trash their user data" msgstr "" diff --git a/src/meson.build b/src/meson.build index 5c8bf6d..48624f1 100644 --- a/src/meson.build +++ b/src/meson.build @@ -40,6 +40,7 @@ flattool_gui_sources = [ '__init__.py', 'main.py', 'window.py', + 'show_properties_window.py', ] install_data(flattool_gui_sources, install_dir: moduledir) diff --git a/src/show_properties_window.py b/src/show_properties_window.py new file mode 100644 index 0000000..3d26073 --- /dev/null +++ b/src/show_properties_window.py @@ -0,0 +1,126 @@ +from gi.repository import Gtk, Adw, GLib, Gdk, Gio +import subprocess +#import pathlib +import os + +def show_properties_window(widget, index, window): + properties_window = Adw.Window(title=_("Properties of {}").format(window.host_flatpaks[index][0])) + properties_window.set_default_size(350, 600) + properties_window.set_size_request(250, 0) + properties_window.set_modal(True) + properties_window.set_resizable(True) + properties_window.set_transient_for(window) + properties_scroll = Gtk.ScrolledWindow() + properties_toast_overlay = Adw.ToastOverlay() + properties_toast_overlay.set_child(properties_scroll) + properties_box = Gtk.Box(orientation="vertical", vexpand=True) + properties_clamp = Adw.Clamp() + properties_scroll.set_child(properties_clamp) + properties_clamp.set_child(properties_box) + properties_title_bar = Adw.ToolbarView() + properties_title_bar.add_top_bar(Gtk.HeaderBar()) + properties_title_bar.set_content(properties_toast_overlay) + user_data_list = Gtk.ListBox(selection_mode="none", margin_top=12, margin_bottom=0, margin_start=12, margin_end=12) + user_data_row = Adw.ActionRow(title="No User Data") + user_data_list.append(user_data_row) + user_data_list.add_css_class("boxed-list") + + def key_handler(_a, event, _c, _d): + if event == Gdk.KEY_Escape: + properties_window.close() + + event_controller = Gtk.EventControllerKey() + event_controller.connect("key-pressed", key_handler) + properties_window.add_controller(event_controller) + + app_name = window.host_flatpaks[index][0] + app_id = window.host_flatpaks[index][2] + data_folder = window.user_data_path + app_id + + def on_response(_a, response_id, _b): + if response_id != "continue": + return + if window.trash_folder(data_folder) == 0: + properties_toast_overlay.add_toast(Adw.Toast.new(_("Trashed user data"))) + user_data_list.remove(user_data_row) + user_data_list.append(Adw.ActionRow(title="No User Data")) + else: + properties_toast_overlay.add_toast(Adw.Toast.new(_("Can't trash data"))) + + def clean_button_handler(_widget): + dialog = Adw.MessageDialog.new(window, _("Send {}'s User Data to the Trash?").format(app_name)) + dialog.set_body(_("Your user files and data for this app will be sent to the trash.")) + dialog.set_close_response("cancel") + dialog.add_response("cancel", _("Cancel")) + dialog.add_response("continue", _("Send Data to Trash")) + dialog.set_response_appearance("continue", Adw.ResponseAppearance.DESTRUCTIVE) + dialog.set_transient_for(properties_window) + dialog.connect("response", on_response, dialog.choose_finish) + Gtk.Window.present(dialog) + + def open_button_handler(_widget): + try: + Gio.AppInfo.launch_default_for_uri(f"file://{path}", None) + except GLib.GError: + properties_toast_overlay.add_toast(Adw.Toast.new(_("Can't open folder"))) + + def copy_button_handler(widget, title, to_copy): + window.clipboard.set(to_copy) + properties_toast_overlay.add_toast(Adw.Toast.new(_("Copied {}").format(title))) + + try: + icon_path = window.icon_theme.lookup_icon(window.host_flatpaks[index][2], None, 512, 1, window.get_direction(), 0).get_file().get_path() + except GLib.GError: + icon_path = None + if icon_path: + image = Gtk.Image.new_from_file(icon_path) + image.add_css_class("icon-dropshadow") + image.set_size_request(100, 100) + image.set_margin_top(12) + properties_box.append(image) + if "runtime" in window.host_flatpaks[index][12]: + image = Gtk.Image.new_from_icon_name("system-run-symbolic") + image.set_icon_size(Gtk.IconSize.LARGE) + image.set_margin_top(12) + properties_box.append(image) + + + properties_list = Gtk.ListBox(selection_mode="none", margin_top=12, margin_bottom=12, margin_start=12, margin_end=12) + properties_list.add_css_class("boxed-list") + + path = str(window.user_data_path) + window.host_flatpaks[index][2] + + if os.path.exists(path): + user_data_row.set_title("User Data") + user_data_row.set_subtitle(f"{path}\n~{window.get_size_format(window.get_directory_size(path))}") + + open_button = Gtk.Button(icon_name="document-open-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("Open Data Folder")) + open_button.add_css_class("flat") + open_button.connect("clicked", open_button_handler) + user_data_row.add_suffix(open_button) + + clean_button = Gtk.Button(icon_name="brush-symbolic", valign=Gtk.Align.CENTER, tooltip_text="Send User Data to the Trash") + clean_button.add_css_class("flat") + clean_button.connect("clicked", clean_button_handler) + user_data_row.add_suffix(clean_button) + + properties_box.append(user_data_list) + + column_headers = [_('Name'), _('Description'), _('App ID'), _('Version'), _('Branch'), _('Arch'), _('Origin'), _('Installation'), _('Ref'), _('Active Commit'), _('Latest Commit'), _('Installed Size'), _('Options')] + for column in range(len(window.host_flatpaks[index])): + if window.host_flatpaks[index][column] == "": + continue + row_item = Adw.ActionRow(title=column_headers[column]) + row_item.set_subtitle(GLib.markup_escape_text(window.host_flatpaks[index][column])) + + properties_copy_button = Gtk.Button(icon_name="edit-copy-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("Copy {}").format(column_headers[column])) + properties_copy_button.add_css_class("flat") + properties_copy_button.connect("clicked", copy_button_handler, column_headers[column], window.host_flatpaks[index][column]) + row_item.add_suffix(properties_copy_button) + + properties_list.append(row_item) + + properties_box.append(properties_list) + + properties_window.set_content(properties_title_bar) + properties_window.present() diff --git a/src/window.py b/src/window.py index ba0fd29..201ba3d 100644 --- a/src/window.py +++ b/src/window.py @@ -17,6 +17,7 @@ # SPDX-License-Identifier: GPL-3.0-only from gi.repository import GLib, Gtk, Adw, Gdk, Gio +from .show_properties_window import show_properties_window import subprocess import pathlib import shutil @@ -352,129 +353,6 @@ class FlattoolGuiWindow(Adw.ApplicationWindow): generate_list(self, False) orphans_window.present() - def show_properties_window(self, widget, index): - properties_window = Adw.Window(title=_("Properties of {}").format(self.host_flatpaks[index][0])) - properties_window.set_default_size(350, 600) - properties_window.set_size_request(250, 0) - properties_window.set_modal(True) - properties_window.set_resizable(True) - properties_window.set_transient_for(self) - properties_scroll = Gtk.ScrolledWindow() - properties_toast_overlay = Adw.ToastOverlay() - properties_toast_overlay.set_child(properties_scroll) - properties_box = Gtk.Box(orientation="vertical", vexpand=True) - properties_clamp = Adw.Clamp() - properties_scroll.set_child(properties_clamp) - properties_clamp.set_child(properties_box) - properties_title_bar = Adw.ToolbarView() - properties_title_bar.add_top_bar(Gtk.HeaderBar()) - properties_title_bar.set_content(properties_toast_overlay) - user_data_list = Gtk.ListBox(selection_mode="none", margin_top=12, margin_bottom=0, margin_start=12, margin_end=12) - user_data_row = Adw.ActionRow(title="No User Data") - user_data_list.append(user_data_row) - user_data_list.add_css_class("boxed-list") - - def key_handler(_a, event, _c, _d): - if event == Gdk.KEY_Escape: - properties_window.close() - - event_controller = Gtk.EventControllerKey() - event_controller.connect("key-pressed", key_handler) - properties_window.add_controller(event_controller) - - app_name = self.host_flatpaks[index][0] - app_id = self.host_flatpaks[index][2] - data_folder = self.user_data_path + app_id - - def on_response(_a, response_id, _b): - if response_id != "continue": - return - if self.trash_folder(data_folder) == 0: - properties_toast_overlay.add_toast(Adw.Toast.new(_("Trashed user data"))) - user_data_list.remove(user_data_row) - user_data_list.append(Adw.ActionRow(title="No User Data")) - else: - properties_toast_overlay.add_toast(Adw.Toast.new(_("Can't trash data"))) - - def clean_button_handler(_widget): - dialog = Adw.MessageDialog.new(self, _("Send {}'s User Data to the Trash?").format(app_name)) - dialog.set_body(_("Your user files and data for this app will be sent to the trash.")) - dialog.set_close_response("cancel") - dialog.add_response("cancel", _("Cancel")) - dialog.add_response("continue", _("Send Data to Trash")) - dialog.set_response_appearance("continue", Adw.ResponseAppearance.DESTRUCTIVE) - dialog.set_transient_for(properties_window) - dialog.connect("response", on_response, dialog.choose_finish) - Gtk.Window.present(dialog) - - def open_button_handler(_widget): - try: - Gio.AppInfo.launch_default_for_uri(f"file://{path}", None) - except: - properties_toast_overlay.add_toast(Adw.Toast.new(_("Can't open folder"))) - - def copy_button_handler(widget, title, to_copy): - self.clipboard.set(to_copy) - properties_toast_overlay.add_toast(Adw.Toast.new(_("Copied {}").format(title))) - - try: - icon_path = self.icon_theme.lookup_icon(self.host_flatpaks[index][2], None, 512, 1, self.get_direction(), 0).get_file().get_path() - except GLib.GError: - icon_path = None - if icon_path: - image = Gtk.Image.new_from_file(icon_path) - image.add_css_class("icon-dropshadow") - image.set_size_request(100, 100) - image.set_margin_top(12) - properties_box.append(image) - if "runtime" in self.host_flatpaks[index][12]: - image = Gtk.Image.new_from_icon_name("system-run-symbolic") - image.set_icon_size(Gtk.IconSize.LARGE) - image.set_margin_top(12) - properties_box.append(image) - - - properties_list = Gtk.ListBox(selection_mode="none", margin_top=12, margin_bottom=12, margin_start=12, margin_end=12) - properties_list.add_css_class("boxed-list") - - path = str(self.user_data_path) + self.host_flatpaks[index][2] - - if os.path.exists(path): - user_data_row.set_title("User Data") - user_data_row.set_subtitle(f"{path}\n~{self.get_size_format(self.get_directory_size(path))}") - - open_button = Gtk.Button(icon_name="document-open-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("Open Data Folder")) - open_button.add_css_class("flat") - open_button.connect("clicked", open_button_handler) - user_data_row.add_suffix(open_button) - - clean_button = Gtk.Button(icon_name="brush-symbolic", valign=Gtk.Align.CENTER, tooltip_text="Send User Data to the Trash") - clean_button.add_css_class("flat") - clean_button.connect("clicked", clean_button_handler) - user_data_row.add_suffix(clean_button) - - properties_box.append(user_data_list) - - column_headers = [_('Name'), _('Description'), _('App ID'), _('Version'), _('Branch'), _('Arch'), _('Origin'), _('Installation'), _('Ref'), _('Active Commit'), _('Latest Commit'), _('Installed Size'), _('Options')] - for column in range(len(self.host_flatpaks[index])): - if self.host_flatpaks[index][column] == "": - continue - row_item = Adw.ActionRow(title=column_headers[column]) - row_item.set_subtitle(GLib.markup_escape_text(self.host_flatpaks[index][column])) - - properties_copy_button = Gtk.Button(icon_name="edit-copy-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("Copy {}").format(column_headers[column])) - properties_copy_button.add_css_class("flat") - properties_copy_button.connect("clicked", copy_button_handler, column_headers[column], self.host_flatpaks[index][column]) - row_item.add_suffix(properties_copy_button) - row_item.set_activatable_widget(properties_copy_button) - - properties_list.append(row_item) - - properties_box.append(properties_list) - - properties_window.set_content(properties_title_bar) - properties_window.present() - selected_host_flatpak_indexes = [] def generate_list_of_flatpaks(self): @@ -536,7 +414,7 @@ class FlattoolGuiWindow(Adw.ApplicationWindow): 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", self.show_properties_window, index) + properties_button.connect("clicked", show_properties_window, index, self) flatpak_row.add_suffix(properties_button) select_flatpak_tickbox = Gtk.CheckButton(halign=Gtk.Align.CENTER)