From 1695caec3bd2c00988bb440894df6f4e8299763e Mon Sep 17 00:00:00 2001 From: heliguy4599 Date: Tue, 3 Oct 2023 03:04:18 -0400 Subject: [PATCH] Make filter way faster, use local C for subcommand --- src/common.py | 16 +-- src/filter_window.py | 2 +- src/popular_remotes_window.py | 5 +- src/remotes.py | 10 +- src/window.blp | 2 +- src/window.py | 197 +++++++++++++++++----------------- 6 files changed, 123 insertions(+), 109 deletions(-) diff --git a/src/common.py b/src/common.py index 7e653b3..69a4b66 100644 --- a/src/common.py +++ b/src/common.py @@ -10,12 +10,14 @@ 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' def trashFolder(self, path): if not os.path.exists(path): return 1 try: - subprocess.run(["flatpak-spawn", "--host", "gio", "trash", path], capture_output=True, check=True) + subprocess.run(["flatpak-spawn", "--host", "gio", "trash", path], capture_output=True, check=True, env=self.new_env) return 0 except subprocess.CalledProcessError: return 2 @@ -76,7 +78,7 @@ class myUtils: return image def getHostRemotes(self): - output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "remotes", "--columns=all"], capture_output=True, text=True).stdout + output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "remotes", "--columns=all"], capture_output=True, text=True, env=self.new_env).stdout lines = output.strip().split("\n") columns = lines[0].split("\t") data = [columns] @@ -99,7 +101,7 @@ class myUtils: return data def getHostFlatpaks(self): - output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "list", "--columns=all"], capture_output=True, text=True).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] @@ -127,7 +129,7 @@ class myUtils: for i in range(len(apps)): command = ['flatpak-spawn', '--host', 'flatpak', 'remove', '-y', f"--{apps[i][2]}", apps[i][0]] try: - subprocess.run(command, capture_output=False, check=True) + subprocess.run(command, capture_output=False, check=True, env=self.new_env) except subprocess.CalledProcessError: fails.append(apps[i]) @@ -143,7 +145,7 @@ class myUtils: pk_command.append(fails[i][0]) try: print(pk_command) - subprocess.run(pk_command, capture_output=False, check=True) + subprocess.run(pk_command, capture_output=False, check=True, env=self.new_env) except subprocess.CalledProcessError: self.uninstall_success = False @@ -166,7 +168,7 @@ class myUtils: for i in range(len(app_arr)): command = ['flatpak-spawn', '--host', 'flatpak', 'install', remote, f"--{user_or_system}", '-y', app_arr[i]] try: - subprocess.run(command, capture_output=False, check=True) + subprocess.run(command, capture_output=False, check=True, env=self.new_env) except subprocess.CalledProcessError: fails.append(app_arr[i]) @@ -175,7 +177,7 @@ class myUtils: for i in range(len(fails)): pk_command.append(fails[i]) try: - subprocess.run(pk_command, capture_output=False, check=True) + subprocess.run(pk_command, capture_output=False, check=True, env=self.new_env) except subprocess.CalledProcessError: self.install_success = False diff --git a/src/filter_window.py b/src/filter_window.py index d821031..1b0e3a5 100644 --- a/src/filter_window.py +++ b/src/filter_window.py @@ -81,7 +81,7 @@ class FilterWindow(Adw.Window): self.add_controller(event_controller) # Connections - self.apply_button.connect("clicked", lambda *_: main_window.updateFilter(self.filter_list)) + 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 *_: main_window.filter_button.set_active(False)) diff --git a/src/popular_remotes_window.py b/src/popular_remotes_window.py index 4916fa7..b580621 100644 --- a/src/popular_remotes_window.py +++ b/src/popular_remotes_window.py @@ -35,7 +35,7 @@ class PopularRemotesWindow(Adw.Window): command = ['flatpak-spawn', '--host', 'flatpak', 'remote-add', '--if-not-exists', self.name_to_add, self.url_to_add, install_type] try: - subprocess.run(command, capture_output=True, check=True) + subprocess.run(command, capture_output=True, check=True, env=self.new_env) except Exception as e: self.toast_overlay.add_toast(Adw.Toast.new(_("Could not add {}").format(self.name_to_add))) print(e) @@ -175,6 +175,9 @@ class PopularRemotesWindow(Adw.Window): self.my_utils = myUtils(self) self.parent_window = parent_window + self.new_env = dict( os.environ ) + self.new_env['LC_ALL'] = 'C' + self.set_modal(True) self.set_transient_for(parent_window) self.generate_list() \ No newline at end of file diff --git a/src/remotes.py b/src/remotes.py index c943ca7..45809f2 100644 --- a/src/remotes.py +++ b/src/remotes.py @@ -2,10 +2,10 @@ from gi.repository import Gtk, Adw, GLib, Gdk, Gio from .common import myUtils from .popular_remotes_window import PopularRemotesWindow import subprocess +import os import re class RemotesWindow(Adw.Window): - def key_handler(self, _a, event, _c, _d): if event == Gdk.KEY_Escape: self.close() @@ -14,7 +14,7 @@ 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).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] @@ -32,7 +32,7 @@ class RemotesWindow(Adw.Window): install_type = self.host_remotes[index][7] command = ['flatpak-spawn', '--host', 'flatpak', 'remote-delete', '--force', name, f'--{install_type}'] try: - subprocess.run(command, capture_output=True, check=True) + subprocess.run(command, capture_output=True, check=True, env=self.new_env) except subprocess.CalledProcessError as e: self.make_toast(_("Could not remove {}").format(title)) self.generate_list() @@ -122,6 +122,8 @@ class RemotesWindow(Adw.Window): self.window_title = _("Manage Remotes") self.host_remotes = [] self.host_flatpaks = [] + self.new_env = dict( os.environ ) + self.new_env['LC_ALL'] = 'C' # Create Widgets self.scroll = Gtk.ScrolledWindow() @@ -134,6 +136,8 @@ class RemotesWindow(Adw.Window): self.user_data_row = Adw.ActionRow(title="No User Data") self.add_button = Gtk.Button(icon_name="plus-large-symbolic", tooltip_text="Add Remote") self.stack = Gtk.Stack() + self.new_env = dict( os.environ ) + self.new_env['LC_ALL'] = 'C' # Apply Widgets self.toolbar.set_content(self.toast_overlay) diff --git a/src/window.blp b/src/window.blp index ff3e302..27d97eb 100644 --- a/src/window.blp +++ b/src/window.blp @@ -58,7 +58,7 @@ template WarehouseWindow : Adw.ApplicationWindow { ScrolledWindow scrolled_window { vexpand: true; Adw.Clamp{ - ListBox list_of_flatpaks{ + ListBox flatpaks_list_box { margin-top: 6; margin-bottom: 24; margin-start: 12; diff --git a/src/window.py b/src/window.py index 40c9e50..328468d 100644 --- a/src/window.py +++ b/src/window.py @@ -29,7 +29,7 @@ from .common import myUtils class WarehouseWindow(Adw.ApplicationWindow): __gtype_name__ = "WarehouseWindow" main_window_title = "Warehouse" - list_of_flatpaks = Gtk.Template.Child() + flatpaks_list_box = Gtk.Template.Child() search_entry = Gtk.Template.Child() search_button = Gtk.Template.Child() search_bar = Gtk.Template.Child() @@ -48,12 +48,11 @@ class WarehouseWindow(Adw.ApplicationWindow): main_toolbar_view = Gtk.Template.Child() filter_button = Gtk.Template.Child() - main_progress_bar = Gtk.ProgressBar(visible=False, pulse_step=0.7) + main_progress_bar = Gtk.ProgressBar(visible=False, pulse_step=0.7, can_target=False) main_progress_bar.add_css_class("osd") clipboard = Gdk.Display.get_default().get_clipboard() host_home = str(pathlib.Path.home()) user_data_path = host_home + "/.var/app/" - show_runtimes = False in_batch_mode = False should_select_all = False host_flatpaks = None @@ -61,6 +60,10 @@ class WarehouseWindow(Adw.ApplicationWindow): should_pulse = True no_close = None re_get_flatpaks = False + selected_rows = [] + flatpak_rows = [] + # ^ {Row visibility, Row selected, the row itself, properties, trash, select, the flatpak row from `flatpak list`} + def main_pulser(self): if self.should_pulse: @@ -77,6 +80,7 @@ class WarehouseWindow(Adw.ApplicationWindow): self.refresh_list_of_flatpaks(_a, False) self.main_toolbar_view.set_sensitive(True) self.disconnect(self.no_close) + self.batch_uninstall_button.set_visible(True) if self.my_utils.uninstall_success: if self.in_batch_mode: self.toast_overlay.add_toast(Adw.Toast.new(_("Uninstalled selected apps"))) @@ -117,10 +121,14 @@ class WarehouseWindow(Adw.ApplicationWindow): except: should_trash = False - self.main_toolbar_view.set_sensitive(False) + #self.main_toolbar_view.set_sensitive(False) + + for i in range(len(self.flatpak_rows)): + self.flatpak_rows[i][4].set_visible(False) + self.batch_uninstall_button.set_visible(False) + self.no_close = self.connect("close-request", lambda event: True) # Make window unable to close self.main_progress_bar.set_visible(True) - self.main_progress_bar.set_can_target(False) self.uninstall_flatpak(self.selected_host_flatpak_indexes, should_trash) # Create Widgets @@ -190,7 +198,11 @@ class WarehouseWindow(Adw.ApplicationWindow): if response_id == "purge": should_trash = True - self.main_toolbar_view.set_sensitive(False) + for i in range(len(self.flatpak_rows)): + self.flatpak_rows[i][4].set_visible(False) + self.batch_uninstall_button.set_visible(False) + + #self.main_toolbar_view.set_sensitive(False) self.no_close = self.connect("close-request", lambda event: True) # Make window unable to close self.main_progress_bar.set_visible(True) self.uninstall_flatpak([index], should_trash) @@ -228,36 +240,25 @@ class WarehouseWindow(Adw.ApplicationWindow): dialog.connect("response", uninstall_response, dialog.choose_finish) Gtk.Window.present(dialog) - selected_host_flatpak_indexes = [] - main_list_select_ticks = [] - main_list_trash_buttons = [] - current_shown_flatpak_indexies = [] + def windowSetEmpty(self, has_row): + self.batch_mode_button.set_sensitive(has_row) + self.search_button.set_sensitive(has_row) + if has_row: + self.main_stack.set_visible_child(self.main_box) + else: + self.batch_mode_button.set_active(False) + self.main_stack.set_visible_child(self.no_flatpaks) + + selected_host_flatpak_indexes = [] + def generate_list_of_flatpaks(self): self.set_title(self.main_window_title) - self.batch_actions_enable(False) + self.flatpak_rows = [] self.selected_host_flatpak_indexes = [] - self.main_list_select_ticks = [] - self.main_list_trash_buttons = [] - self.current_shown_flatpak_indexies = [] self.should_select_all = self.batch_select_all_button.get_active() self.main_stack.set_visible_child(self.main_box) - - def windowSetEmpty(has_row): - self.batch_mode_button.set_sensitive(has_row) - self.search_button.set_sensitive(has_row) - - if has_row: - self.main_stack.set_visible_child(self.main_box) - else: - self.batch_mode_button.set_active(False) - self.main_stack.set_visible_child(self.no_flatpaks) - - # Setting up filter stuff - self.show_apps = self.filter_list[0] - self.show_runtimes = self.filter_list[1] - self.filter_install_type = self.filter_list[2] - self.filter_remotes_list = self.filter_list[3] + self.batch_select_all_button.set_active(False) for index in range(len(self.host_flatpaks)): app_name = self.host_flatpaks[index][0] @@ -267,79 +268,62 @@ class WarehouseWindow(Adw.ApplicationWindow): flatpak_row.add_prefix(self.my_utils.findAppIcon(app_id)) flatpak_row.set_subtitle(app_id) - # Check the filter and skip row if it does not meet the filter - if (not self.show_apps) and (not "runtime" in self.host_flatpaks[index][12]): - continue - - if (not self.show_runtimes) and "runtime" in self.host_flatpaks[index][12]: - continue - - if (not 'all' in self.filter_install_type) and (not self.host_flatpaks[index][7] in self.filter_install_type): - continue - - if (not 'all' in self.filter_remotes_list) and (not self.host_flatpaks[index][6] in self.filter_remotes_list): - continue - - # Change the subtitle from id to ref if the list is set to show runtimes - if self.show_runtimes: - flatpak_row.set_subtitle(app_ref) - 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", show_properties_window, index, self) flatpak_row.add_suffix(properties_button) trash_button = Gtk.Button(icon_name="user-trash-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("Uninstall {}").format(app_name), visible=not self.in_batch_mode) - self.main_list_trash_buttons.append(trash_button) trash_button.add_css_class("flat") trash_button.connect("clicked", self.uninstall_button_handler, index) flatpak_row.add_suffix(trash_button) select_flatpak_tickbox = Gtk.CheckButton(visible=self.in_batch_mode) - self.main_list_select_ticks.append(select_flatpak_tickbox) select_flatpak_tickbox.add_css_class("selection-mode") select_flatpak_tickbox.connect("toggled", self.flatpak_row_select_handler, index) - select_flatpak_tickbox.set_active(self.should_select_all) flatpak_row.add_suffix(select_flatpak_tickbox) - # if self.in_batch_mode: - # flatpak_row.set_activatable_widget(select_flatpak_tickbox) - # trash_button.set_visible(False) - # if self.should_select_all: - # select_flatpak_tickbox.set_active(True) - # self.batch_mode_bar.set_revealed(True) - # else: - # select_flatpak_tickbox.set_visible(False) - # self.batch_mode_bar.set_revealed(False) + if self.in_batch_mode: + flatpak_row.set_activatable_widget(select_flatpak_tickbox) - self.list_of_flatpaks.append(flatpak_row) + self.flatpaks_list_box.append(flatpak_row) + # {Row visibility, Row selected, the row itself, properties, trash, select, the flatpak row from `flatpak list`} + self.flatpak_rows.append([True, False, flatpak_row, properties_button, trash_button, select_flatpak_tickbox, self.host_flatpaks[index]]) - windowSetEmpty(self.list_of_flatpaks.get_row_at_index(0)) + self.windowSetEmpty(self.flatpaks_list_box.get_row_at_index(0)) + self.applyFilter(self.filter_list) def refresh_list_of_flatpaks(self, widget, should_toast): - self.list_of_flatpaks.remove_all() - self.generate_list_of_flatpaks() + self.flatpaks_list_box.remove_all() self.host_flatpaks = self.my_utils.getHostFlatpaks() + self.generate_list_of_flatpaks() if should_toast: self.toast_overlay.add_toast(Adw.Toast.new(_("List refreshed"))) def batch_mode_handler(self, widget): - for i in range(len(self.main_list_select_ticks)): - self.main_list_select_ticks[i].set_visible(widget.get_active()) - self.main_list_trash_buttons[i].set_visible(not widget.get_active()) + for i in range(len(self.flatpak_rows)): + adw_row = self.flatpak_rows[i][2] + trash_button = self.flatpak_rows[i][4] + select_tick = self.flatpak_rows[i][5] + + select_tick.set_visible(widget.get_active()) + trash_button.set_visible(not widget.get_active()) + if widget.get_active(): - self.list_of_flatpaks.get_row_at_index(i).set_activatable(True) - self.list_of_flatpaks.get_row_at_index(i).set_activatable_widget(self.main_list_select_ticks[i]) + adw_row.set_activatable(True) + adw_row.set_activatable_widget(select_tick) else: - self.main_list_select_ticks[i].set_active(False) - self.list_of_flatpaks.get_row_at_index(i).set_activatable(False) + select_tick.set_active(False) + adw_row.set_activatable(False) + self.in_batch_mode = widget.get_active() self.batch_mode_bar.set_revealed(widget.get_active()) + if widget.get_active(): - self.list_of_flatpaks.set_margin_bottom(6) + self.flatpaks_list_box.set_margin_bottom(6) else: + self.flatpaks_list_box.set_margin_bottom(24) self.batch_select_all_button.set_active(False) - self.list_of_flatpaks.set_margin_bottom(24) def batch_actions_enable(self, should_enable): self.batch_copy_button.set_sensitive(should_enable) @@ -375,27 +359,28 @@ class WarehouseWindow(Adw.ApplicationWindow): Gtk.Window.present(dialog) def batch_select_all_handler(self, widget): - for i in range(len(self.main_list_select_ticks)): - self.main_list_select_ticks[i].set_active(widget.get_active()) + for i in range(len(self.flatpak_rows)): + if self.flatpak_rows[i][0]: + self.flatpak_rows[i][5].set_active(widget.get_active()) def batch_key_handler(self, _b, event, _c, _d): if event == Gdk.KEY_Escape: self.batch_mode_button.set_active(False) def flatpak_row_select_handler(self, tickbox, index): - if tickbox.get_active(): - self.selected_host_flatpak_indexes.append(index) - else: - self.selected_host_flatpak_indexes.remove(index) + self.flatpak_rows[index][1] = tickbox.get_active() - buttons_enable = True - if len(self.selected_host_flatpak_indexes) == 0: + total_selected = 0 + for i in range(len(self.flatpak_rows)): + if self.flatpak_rows[i][1]: + total_selected += 1 + if total_selected == 0: buttons_enable = False self.set_title(self.main_window_title) + self.batch_actions_enable(False) else: - self.set_title(f"{len(self.selected_host_flatpak_indexes)} Selected") - - self.batch_actions_enable(buttons_enable) + self.set_title(f"{total_selected} Selected") + self.batch_actions_enable(True) def create_action(self, name, callback, shortcuts=None): """Add a window action. @@ -414,9 +399,9 @@ class WarehouseWindow(Adw.ApplicationWindow): def copyNames(self, widget, _a): to_copy = "" - for i in range(len(self.selected_host_flatpak_indexes)): - host_flatpak_index = self.selected_host_flatpak_indexes[i] - to_copy += f"{(self.host_flatpaks[host_flatpak_index][0])}\n" + for i in range(len(self.flatpak_rows)): + if self.flatpak_rows[i][1]: + to_copy += f"{(self.flatpak_rows[i][6][0])}\n" self.clipboard.set(to_copy) self.toast_overlay.add_toast(Adw.Toast.new(_("Copied selected app names"))) @@ -441,10 +426,7 @@ class WarehouseWindow(Adw.ApplicationWindow): filtwin = FilterWindow(self) filtwin.present() else: - old_list = self.filter_list - self.resetFilterList() - if old_list != self.filter_list: - self.refresh_list_of_flatpaks(self, False) + self.applyFilter() def filterWindowKeyboardHandler(self, widget): self.filter_button.set_active(not self.filter_button.get_active()) @@ -452,21 +434,44 @@ class WarehouseWindow(Adw.ApplicationWindow): def resetFilterList(self): self.filter_list = [True, False, ["all"], ["all"]] - def updateFilter(self, filter): + def applyFilter(self, filter=[True, False, ["all"], ["all"]]): self.filter_list = filter - self.refresh_list_of_flatpaks(self, False) + show_apps = filter[0] + show_runtimes = filter[1] + filter_install_type = filter[2] + filter_remotes_list = filter[3] + + for i in range(len(self.flatpak_rows)): + self.flatpak_rows[i][0] = True + + if (not show_apps) and (not "runtime" in self.flatpak_rows[i][6][12]): + self.flatpak_rows[i][0] = False + + if (not show_runtimes) and "runtime" in self.flatpak_rows[i][6][12]: + self.flatpak_rows[i][0] = False + + if (not 'all' in filter_install_type) and (not self.host_flatpaks[i][7] in filter_install_type): + self.flatpak_rows[i][0] = False + + if (not 'all' in filter_remotes_list) and (not self.host_flatpaks[i][6] in filter_remotes_list): + self.flatpak_rows[i][0] = False + + # # Change the subtitle from id to ref if the list is set to show runtimes + # if self.show_runtimes: + # flatpak_row.set_subtitle(app_ref) + + self.flatpak_rows[i][2].set_visible(self.flatpak_rows[i][0]) def __init__(self, **kwargs): super().__init__(**kwargs) self.my_utils = myUtils(self) - self.filter_list = [] - self.resetFilterList() + self.filter_list = [True, False, ["all"], ["all"]] self.host_flatpaks = self.my_utils.getHostFlatpaks() - self.list_of_flatpaks.set_filter_func(self.filter_func) + self.flatpaks_list_box.set_filter_func(self.filter_func) self.set_size_request(0, 230) self.generate_list_of_flatpaks() - self.search_entry.connect("search-changed", lambda *_: self.list_of_flatpaks.invalidate_filter()) + self.search_entry.connect("search-changed", lambda *_: self.flatpaks_list_box.invalidate_filter()) self.search_bar.connect_entry(self.search_entry) self.refresh_button.connect("clicked", self.refresh_list_of_flatpaks, True) self.batch_mode_button.connect("toggled", self.batch_mode_handler)