diff --git a/io.github.flattool.Warehouse.json b/io.github.flattool.Warehouse.json index ca2f685..047651d 100644 --- a/io.github.flattool.Warehouse.json +++ b/io.github.flattool.Warehouse.json @@ -44,6 +44,7 @@ "name" : "warehouse", "builddir" : true, "buildsystem" : "meson", + "config-opts": [ "-Dprofile=development" ], "sources" : [ { "type" : "dir", diff --git a/meson.build b/meson.build index ae25ec8..a36cacf 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('warehouse', - version: '1.3.1.beta', + version: '1.3.1', meson_version: '>= 0.62.0', default_options: [ 'warning_level=2', 'werror=false', ], ) @@ -7,8 +7,6 @@ project('warehouse', i18n = import('i18n') gnome = import('gnome') - - subdir('data') subdir('src') subdir('po') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..db3076f --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,9 @@ +option( + 'profile', + type: 'combo', + choices: [ + 'default', + 'development' + ], + value: 'default' +) \ No newline at end of file diff --git a/src/brush-symbolic.svg b/src/brush-symbolic.svg deleted file mode 100644 index 45fdd8f..0000000 --- a/src/brush-symbolic.svg +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/common.py b/src/common.py index e96a0bd..4331959 100644 --- a/src/common.py +++ b/src/common.py @@ -143,14 +143,17 @@ class myUtils: sorted_array = sorted(data, key=lambda item: item[0].lower()) return sorted_array - def getDependantRuntimes(self): + def getDependentRuntimes(self): paks = self.getHostFlatpaks() - dependant_runtimes = [] + dependent_runtimes = [] for i in range(len(paks)): current = paks[i] - if current[13] not in dependant_runtimes and current[13] != "": - dependant_runtimes.append(current[13]) - return(dependant_runtimes) + try: + if current[13] not in dependent_runtimes and current[13] != "": + dependent_runtimes.append(current[13]) + except: + print("Could not get dependent runtime") + 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 diff --git a/src/const.py.in b/src/const.py.in new file mode 100644 index 0000000..1f7da55 --- /dev/null +++ b/src/const.py.in @@ -0,0 +1,8 @@ +#!@PYTHON@ +# SPDX-License-Identifier: GPL-3.0-or-later + +class Config: + DEVEL = '@DEVEL@' == 'Development' + PROFILE = '@DEVEL@' + APP_ID = '@APPID@' + VERSION = '@VERSION@' \ No newline at end of file diff --git a/src/downgrade.blp b/src/downgrade.blp index fde194e..00211d3 100644 --- a/src/downgrade.blp +++ b/src/downgrade.blp @@ -1,54 +1,60 @@ using Gtk 4.0; using Adw 1; -template DowngradeWindow : Adw.Window { - default-width: 500; - default-height: 450; - modal: true; +template DowngradeWindow: Adw.Window { + default-width: 500; + default-height: 450; + modal: true; - Adw.ToolbarView main_toolbar_view { - [top] - HeaderBar header_bar { - show-title-buttons: false; + Adw.ToolbarView main_toolbar_view { + [top] + HeaderBar header_bar { + show-title-buttons: false; - [start] - Button cancel_button { - label: _("Cancel"); - } - [end] - Button apply_button { - sensitive: false; - label: _("Downgrade"); - styles["suggested-action"] - } - } - content: - Adw.ToastOverlay toast_overlay { - Stack main_stack { - Overlay main_overlay { - [overlay] - ProgressBar progress_bar { - pulse-step: 0.7; - can-target: false; - styles["osd"] - } + [start] + Button cancel_button { + label: _("Cancel"); + } - Adw.PreferencesPage outerbox { - - Adw.PreferencesGroup { - Adw.SwitchRow mask_row { - title: _("Disable Updates"); - active: true; - } - } + [end] + Button apply_button { + sensitive: false; + label: _("Downgrade"); - Adw.PreferencesGroup versions_group { - title: _("Select a Release"); - description: _("This will uninstall the current release and install the chosen one instead. Note that downgrading can cause issues."); - } - } - } - } - }; + styles [ + "suggested-action" + ] + } } -} \ No newline at end of file + + content: Adw.ToastOverlay toast_overlay { + Stack main_stack { + Overlay main_overlay { + [overlay] + ProgressBar progress_bar { + pulse-step: 0.7; + can-target: false; + + styles [ + "osd" + ] + } + + Adw.PreferencesPage outerbox { + Adw.PreferencesGroup { + Adw.SwitchRow mask_row { + title: _("Disable Updates"); + active: true; + } + } + + Adw.PreferencesGroup versions_group { + title: _("Select a Release"); + description: _("This will uninstall the current release and install the chosen one instead. Note that downgrading can cause issues."); + } + } + } + } + }; + } +} diff --git a/src/filter.blp b/src/filter.blp index c1ae00a..439f4d1 100644 --- a/src/filter.blp +++ b/src/filter.blp @@ -1,86 +1,98 @@ using Gtk 4.0; using Adw 1; -template FilterWindow : Adw.Window { - default-width: 500; - default-height: 450; - title: _("Set Filters"); - modal: true; +template FilterWindow: Adw.Window { + default-width: 500; + default-height: 450; + title: _("Set Filters"); + modal: true; - Adw.ToolbarView main_toolbar_view { - [top] - HeaderBar header_bar { - show-title-buttons: false; + Adw.ToolbarView main_toolbar_view { + [top] + HeaderBar header_bar { + show-title-buttons: false; - [start] - Button cancel_button { - label: _("Cancel"); - } - [end] - Button apply_button { - label: _("Apply"); - styles["suggested-action"] - } - } - content: - Adw.ToastOverlay toast_overlay { - Stack main_stack { - Overlay main_overlay { - ScrolledWindow scrolled_window { - vexpand: true; - Adw.Clamp{ - Box outerbox { - orientation: vertical; + [start] + Button cancel_button { + label: _("Cancel"); + } - ListBox install_type_list { - margin-top: 12; - margin-bottom: 12; - margin-start: 12; - margin-end: 12; - hexpand: true; - valign: start; - selection-mode: none; - styles["boxed-list"] - - Adw.ActionRow apps_row { - title: _("Show Apps"); + [end] + Button apply_button { + label: _("Apply"); - Switch apps_switch { - valign: center; - } - - activatable-widget: apps_switch; - } - Adw.ActionRow runtimes_row { - title: _("Show Runtimes"); - - Switch runtimes_switch { - valign: center; - } - - activatable-widget: runtimes_switch; - } - Adw.ExpanderRow remotes_expander { - enable-expansion: false; - title: _("Filter Apps by Remotes"); - } - Adw.ExpanderRow runtimes_expander { - enable-expansion: false; - title: _("Filter Apps by Runtime"); - } - } - // Button remove_filters_button { - // visible: false; - // margin-bottom: 18; - // halign: center; - // label: _("Clear Filters"); - // styles ["pill"] - // } - } - } - } - } - } - }; + styles [ + "suggested-action" + ] + } } -} \ No newline at end of file + + content: Adw.ToastOverlay toast_overlay { + Stack main_stack { + Overlay main_overlay { + ScrolledWindow scrolled_window { + vexpand: true; + + Adw.Clamp { + Box outerbox { + orientation: vertical; + + ListBox install_type_list { + margin-top: 12; + margin-bottom: 12; + margin-start: 12; + margin-end: 12; + hexpand: true; + valign: start; + selection-mode: none; + + styles [ + "boxed-list" + ] + + Adw.ActionRow apps_row { + title: _("Show Apps"); + + Switch apps_switch { + valign: center; + } + + activatable-widget: apps_switch; + } + + Adw.ActionRow runtimes_row { + title: _("Show Runtimes"); + + Switch runtimes_switch { + valign: center; + } + + activatable-widget: runtimes_switch; + } + + Adw.ExpanderRow remotes_expander { + enable-expansion: false; + title: _("Filter Apps by Remotes"); + } + + Adw.ExpanderRow runtimes_expander { + enable-expansion: false; + title: _("Filter Apps by Runtime"); + } + } + + // Button remove_filters_button { + // visible: false; + // margin-bottom: 18; + // halign: center; + // label: _("Clear Filters"); + // styles ["pill"] + // } + } + } + } + } + } + }; + } +} diff --git a/src/filter_window.py b/src/filter_window.py index f82201a..74da607 100644 --- a/src/filter_window.py +++ b/src/filter_window.py @@ -88,39 +88,42 @@ class FilterWindow(Adw.Window): self.remotes_expander_switch = Gtk.Switch(valign=Gtk.Align.CENTER) self.runtimes_expander_switch = Gtk.Switch(valign=Gtk.Align.CENTER) - dependant_runtimes = self.my_utils.getDependantRuntimes() + 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 self.remotes_expander.set_visible(False) - if len(dependant_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 = [] for i in range(len(self.host_remotes)): - name = self.host_remotes[i][0] - title = self.host_remotes[i][1] - install_type = self.host_remotes[i][7] - url = self.host_remotes[i][2] - remote_row = Adw.ActionRow(title=title, subtitle=url) - if title == "-": - remote_row.set_title(name) - self.remotes_expander.add_row(remote_row) - label = Gtk.Label(label=("{} wide").format(install_type)) - label.add_css_class("subtitle") - remote_check = Gtk.CheckButton() - remote_row.add_suffix(label) - remote_row.add_suffix(remote_check) - remote_row.set_activatable_widget(remote_check) - remote_check.connect("toggled", self.remoteCheckHandler, install_type, name) - self.remote_checkboxes.append(remote_check) - remote_check.set_active(True) + try: + name = self.host_remotes[i][0] + title = self.host_remotes[i][1] + install_type = self.host_remotes[i][7] + url = self.host_remotes[i][2] + remote_row = Adw.ActionRow(title=title, subtitle=url) + if title == "-": + remote_row.set_title(name) + self.remotes_expander.add_row(remote_row) + label = Gtk.Label(label=("{} wide").format(install_type)) + label.add_css_class("subtitle") + remote_check = Gtk.CheckButton() + remote_row.add_suffix(label) + remote_row.add_suffix(remote_check) + remote_row.set_activatable_widget(remote_check) + remote_check.connect("toggled", self.remoteCheckHandler, install_type, name) + self.remote_checkboxes.append(remote_check) + remote_check.set_active(True) + except: + print("Could not make remote row") self.remotes_expander_switch.connect("state-set", self.remotesEnableHandler) self.remotes_expander.add_suffix(self.remotes_expander_switch) self.runtime_checkboxes = [] - for i in range(len(dependant_runtimes)): - current = dependant_runtimes[i] + for i in range(len(dependent_runtimes)): + current = dependent_runtimes[i] runtime_row = Adw.ActionRow(title=current) runtime_check = Gtk.CheckButton() runtime_check.connect("toggled", self.runtimeCheckHandler, current) diff --git a/src/flatpak-symbolic.svg b/src/flatpak-symbolic.svg new file mode 100644 index 0000000..0c0fa45 --- /dev/null +++ b/src/flatpak-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/src/main.py b/src/main.py index 68680f7..cae4fe6 100644 --- a/src/main.py +++ b/src/main.py @@ -30,10 +30,14 @@ from .window import WarehouseWindow from .remotes_window import RemotesWindow from .orphans_window import OrphansWindow from .search_install_window import SearchInstallWindow +from .const import Config class WarehouseApplication(Adw.Application): """The main application singleton class.""" + troubleshooting = "OS: {os}\nWarehouse version: {wv}\nGTK: {gtk}\nlibadwaita: {adw}\nApp ID: {app_id}\nProfile: {profile}\nLanguage: {lang}" + version = Config.VERSION + def __init__(self): super().__init__( application_id="io.github.flattool.Warehouse", @@ -54,6 +58,13 @@ class WarehouseApplication(Adw.Application): 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) + 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 ) + def open_search_install(self, widget, _): SearchInstallWindow(self.props.active_window).present() @@ -117,11 +128,13 @@ class WarehouseApplication(Adw.Application): application_name="Warehouse", application_icon="io.github.flattool.Warehouse", developer_name="Heliguy", - version="1.3.1.beta", + version=self.version, # TODO: make this version number automatically loaded from meson 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, + 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') diff --git a/src/meson.build b/src/meson.build index bef7d6e..cb76511 100644 --- a/src/meson.build +++ b/src/meson.build @@ -31,7 +31,15 @@ python = import('python') conf = configuration_data() conf.set('PYTHON', python.find_installation('python3').full_path()) -conf.set('VERSION', meson.project_version()) +conf.set('APPID', 'io.github.flattool.Warehouse') # TODO: dynamic version and appID +if get_option('profile') == 'development' + vcs_tag = run_command('git', 'rev-parse', '--short', 'HEAD').stdout().strip() + conf.set('DEVEL', 'Development') + conf.set('VERSION', meson.project_version() + '.dev-' + vcs_tag) +else + conf.set('DEVEL', 'Default') + conf.set('VERSION', meson.project_version()) +endif conf.set('localedir', join_paths(get_option('prefix'), get_option('localedir'))) conf.set('pkgdatadir', pkgdatadir) @@ -68,4 +76,13 @@ warehouse_sources = [ 'properties.blp', ] +configure_file( + input: 'const.py.in', + output: 'const.py', + configuration: conf, + install: true, + install_dir: moduledir, + install_mode: 'r-xr--r--', +) + install_data(warehouse_sources, install_dir: moduledir) diff --git a/src/orphans.blp b/src/orphans.blp index 7bb7dab..483ba9d 100644 --- a/src/orphans.blp +++ b/src/orphans.blp @@ -1,103 +1,134 @@ using Gtk 4.0; using Adw 1; -template OrphansWindow : Adw.Window { - default-width: 500; - default-height: 450; +template $OrphansWindow: Adw.Window { + default-width: 500; + default-height: 450; - Adw.ToolbarView main_toolbar_view { - [top] - HeaderBar header_bar { - [start] - ToggleButton search_button { - icon-name: "system-search-symbolic"; - tooltip-text: _("Search List"); - } - [end] - Button oepn_folder_button { - icon-name: "document-open-symbolic"; - tooltip-text: _("Open Data Folder"); - } - } - [top] - SearchBar search_bar { - search-mode-enabled: bind-property search_button.active bidirectional; - key-capture-widget: OrphansWindow; - Adw.Clamp{ - maximum-size: 577; - hexpand: true; - SearchEntry search_entry {} - } - } - content: - Adw.ToastOverlay toast_overlay { - Overlay main_overlay { - Stack main_stack { - Box main_box { - orientation: vertical; - ScrolledWindow scrolled_window { - vexpand: true; - Adw.Clamp{ - ListBox list_of_data { - margin-top: 12; - margin-bottom: 12; - margin-start: 12; - margin-end: 12; - hexpand: true; - valign: start; - selection-mode: none; - styles["boxed-list"] - } - } - } - } - Box installing { - orientation: vertical; - spacing: 10; - margin-top: 40; - margin-bottom: 20; - halign: center; - valign: center; - Spinner spinner { - margin-bottom: 35; - width-request: 30; - height-request: 30; - opacity: 0.5; - spinning: true; - } - Label { - label: _("Installing…"); - styles["title-1", "title"] - } - Label { - label: _("This could take a while."); - styles["description", "body"] - } - } - Adw.StatusPage no_data { - icon-name: "check-plain-symbolic"; - title: _("No Leftover Data"); - description: _("There is no leftover user data"); - } - } - } - }; - [bottom] - ActionBar action_bar { - [start] - ToggleButton select_all_button { - label: _("Select All"); - } - [end] - Button trash_button { - label: _("Trash"); - sensitive: false; - } - [end] - Button install_button { - label: _("Install"); - sensitive: false; - } - } + Adw.ToolbarView main_toolbar_view { + [top] + HeaderBar header_bar { + [start] + ToggleButton search_button { + icon-name: "system-search-symbolic"; + tooltip-text: _("Search List"); + } + + [end] + Button oepn_folder_button { + icon-name: "document-open-symbolic"; + tooltip-text: _("Open Data Folder"); + } } -} \ No newline at end of file + + [top] + SearchBar search_bar { + search-mode-enabled: bind search_button.active bidirectional; + key-capture-widget: main_toolbar_view; + + Adw.Clamp { + maximum-size: 577; + hexpand: true; + + SearchEntry search_entry {} + } + } + + content: Adw.ToastOverlay toast_overlay { + Overlay main_overlay { + Stack main_stack { + Box main_box { + orientation: vertical; + + ScrolledWindow scrolled_window { + vexpand: true; + + Adw.Clamp { + ListBox list_of_data { + margin-top: 12; + margin-bottom: 12; + margin-start: 12; + margin-end: 12; + hexpand: true; + valign: start; + selection-mode: none; + + styles [ + "boxed-list" + ] + } + } + } + } + + Box installing { + orientation: vertical; + spacing: 10; + margin-top: 40; + margin-bottom: 20; + halign: center; + valign: center; + + Spinner spinner { + margin-bottom: 35; + width-request: 30; + height-request: 30; + opacity: 0.5; + spinning: true; + } + + Label { + label: _("Installing…"); + + styles [ + "title-1", + "title" + ] + } + + Label { + label: _("This could take a while."); + + styles [ + "description", + "body" + ] + } + } + + Adw.StatusPage no_data { + icon-name: "check-plain-symbolic"; + title: _("No Leftover Data"); + description: _("There is no leftover user data"); + } + + Adw.StatusPage no_results { + icon-name: "system-search-symbolic"; + title: _("No Results Found"); + description: _("Try a different search term"); + } + } + } + }; + + [bottom] + ActionBar action_bar { + [start] + ToggleButton select_all_button { + label: _("Select All"); + } + + [end] + Button trash_button { + label: _("Trash"); + sensitive: false; + } + + [end] + Button install_button { + label: _("Install"); + sensitive: false; + } + } + } +} diff --git a/src/orphans_window.py b/src/orphans_window.py index 59cc3f8..35b485c 100644 --- a/src/orphans_window.py +++ b/src/orphans_window.py @@ -16,6 +16,7 @@ class OrphansWindow(Adw.Window): toast_overlay = Gtk.Template.Child() main_stack = Gtk.Template.Child() no_data = Gtk.Template.Child() + no_results = Gtk.Template.Child() action_bar = Gtk.Template.Child() search_bar = Gtk.Template.Child() search_entry = Gtk.Template.Child() @@ -30,6 +31,7 @@ class OrphansWindow(Adw.Window): selected_remote = "" selected_remote_install_type = "" no_close_id = 0 + is_result = False def key_handler(self, _a, event, _c, _d): if event == Gdk.KEY_Escape: @@ -188,7 +190,10 @@ class OrphansWindow(Adw.Window): # This is a list that only holds IDs of install flatpaks id_list = [] for i in range(len(self.host_flatpaks)): - id_list.append(self.host_flatpaks[i][2]) + try: + id_list.append(self.host_flatpaks[i][2]) + except: + print("Could not get data") for i in range(len(dir_list)): dir_name = dir_list[i] @@ -229,8 +234,32 @@ class OrphansWindow(Adw.Window): def filter_func(self, row): if (self.search_entry.get_text().lower() in row.get_title().lower()): + self.is_result = True return True + def on_invalidate(self, row): + if self.list_of_data.get_row_at_index(0) == None: + self.main_stack.set_visible_child(self.no_data) + self.action_bar.set_visible(False) + else: + self.main_stack.set_visible_child(self.main_box) + self.action_bar.set_visible(True) + + self.is_result = False + self.list_of_data.invalidate_filter() + if self.is_result == False: + self.main_stack.set_visible_child(self.no_results) + self.action_bar.set_visible(False) + + def on_change(self, prop, prop2): + if self.search_bar.get_search_mode() == False: + if self.list_of_data.get_row_at_index(0) == None: + self.main_stack.set_visible_child(self.no_data) + self.action_bar.set_visible(False) + else: + self.main_stack.set_visible_child(self.main_box) + self.action_bar.set_visible(True) + def __init__(self, main_window, **kwargs): super().__init__(**kwargs) self.my_utils = myUtils(self) # Access common utils and set the window to this window @@ -258,6 +287,7 @@ class OrphansWindow(Adw.Window): self.main_overlay.add_overlay(self.progress_bar) self.list_of_data.set_filter_func(self.filter_func) - self.search_entry.connect("search-changed", lambda *_: self.list_of_data.invalidate_filter()) + 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 diff --git a/src/popular_remotes.blp b/src/popular_remotes.blp index 9c0ebb1..d0d11e9 100644 --- a/src/popular_remotes.blp +++ b/src/popular_remotes.blp @@ -1,49 +1,59 @@ using Gtk 4.0; using Adw 1; -template PopularRemotesWindow : Adw.Window { - default-width: 450; - default-height: 530; - title: ""; +template PopularRemotesWindow: Adw.Window { + default-width: 450; + default-height: 530; + title: ""; - Adw.ToolbarView main_toolbar_view { - [top] - HeaderBar header_bar { - } - content: - Adw.ToastOverlay toast_overlay { - vexpand: true; - Adw.StatusPage { - valign: start; - title: _("Add Remote"); - description: _("Choose from a list of popular remotes or add a new one."); - Adw.Clamp { - Box { - orientation: vertical; - ListBox list_of_remotes { - hexpand: true; - valign: start; - selection-mode: none; - styles["boxed-list"] - } - ListBox custom_list { - hexpand: true; - valign: start; - selection-mode: none; - styles["boxed-list"] + Adw.ToolbarView main_toolbar_view { + [top] + HeaderBar header_bar {} - Adw.ActionRow add_from_file { - title: _("Add a Repo File"); - activatable: true; - } - Adw.ActionRow custom_remote { - title: _("Add a Custom Remote"); - activatable: true; - } - } - } - } + content: Adw.ToastOverlay toast_overlay { + vexpand: true; + + Adw.StatusPage { + valign: start; + title: _("Add Remote"); + description: _("Choose from a list of popular remotes or add a new one."); + + Adw.Clamp { + Box { + orientation: vertical; + + ListBox list_of_remotes { + hexpand: true; + valign: start; + selection-mode: none; + + styles [ + "boxed-list" + ] } - }; - } -} \ No newline at end of file + + ListBox custom_list { + hexpand: true; + valign: start; + selection-mode: none; + + styles [ + "boxed-list" + ] + + Adw.ActionRow add_from_file { + title: _("Add a Repo File"); + activatable: true; + } + + Adw.ActionRow custom_remote { + title: _("Add a Custom Remote"); + activatable: true; + } + } + } + } + } + }; + } +} diff --git a/src/properties.blp b/src/properties.blp index 4946094..896907a 100644 --- a/src/properties.blp +++ b/src/properties.blp @@ -1,103 +1,129 @@ using Gtk 4.0; using Adw 1; -template PropertiesWindow : Adw.Window { - default-width: 350; - default-height: 600; - modal: true; +template PropertiesWindow: Adw.Window { + default-width: 350; + default-height: 600; + modal: true; - Adw.ToolbarView main_toolbar_view { - [top] - HeaderBar header_bar { - } - content: - Adw.ToastOverlay toast_overlay { + Adw.ToolbarView main_toolbar_view { + [top] + HeaderBar header_bar {} + + content: Adw.ToastOverlay toast_overlay { + Box { + orientation: vertical; + + Adw.Banner eol_app_banner {} + + Adw.Banner eol_runtime_banner {} + + Adw.Banner mask_banner {} + + ScrolledWindow { + Adw.Clamp { Box { - orientation: vertical; - Adw.Banner eol_app_banner { + orientation: vertical; + hexpand: false; + vexpand: true; + spacing: 12; + margin-top: 12; + margin-start: 12; + margin-end: 12; + margin-bottom: 12; + + Image app_icon { + pixel-size: 100; + + styles [ + "icon-dropshadow" + ] + } + + Adw.PreferencesGroup upper { + Adw.ActionRow data_row { + title: _("Loading User Data…"); + + [suffix] + Button open_data { + icon-name: "document-open-symbolic"; + tooltip-text: _("Open User Data Folder"); + valign: center; + visible: false; + + styles [ + "flat" + ] + } + + [suffix] + Button trash_data { + icon-name: "user-trash-symbolic"; + tooltip-text: _("Trash User Data"); + valign: center; + visible: false; + + styles [ + "flat" + ] + } + + [suffix] + Spinner spinner { + spinning: true; + } } - Adw.Banner eol_runtime_banner { + + Adw.ActionRow view_apps { + title: _("Show Apps Using this Runtime"); + activatable: true; + + [suffix] + Image { + icon-name: "funnel-symbolic"; + } } - Adw.Banner mask_banner { + + Adw.ActionRow runtime { + title: _("Runtime"); + + [suffix] + Button runtime_properties { + icon-name: "info-symbolic"; + valign: center; + + styles [ + "flat" + ] + } + + [suffix] + Button runtime_copy { + icon-name: "edit-copy-symbolic"; + valign: center; + + styles [ + "flat" + ] + } } - ScrolledWindow { - Adw.Clamp { - Box { - orientation: vertical; - hexpand: false; - vexpand: true; - spacing: 12; - margin-top: 12; - margin-start: 12; - margin-end: 12; - margin-bottom: 12; - Image app_icon { - pixel-size: 100; - styles["icon-dropshadow"] - } - Adw.PreferencesGroup upper { - Adw.ActionRow data_row { - title: _("Loading User Data…"); - [suffix] - Button open_data { - icon-name: "document-open-symbolic"; - tooltip-text: _("Open User Data Folder"); - valign: center; - visible: false; - styles["flat"] - } - [suffix] - Button trash_data { - icon-name: "brush-symbolic"; - tooltip-text: _("Trash User Data"); - valign: center; - visible: false; - styles["flat"] - } - [suffix] - Spinner spinner { - spinning: true; - } - } - Adw.ActionRow view_apps { - title: _("Show Apps Using this Runtime"); - activatable: true; - [suffix] - Image { - icon-name: "funnel-symbolic"; - } - } - Adw.ActionRow runtime { - title: _("Runtime"); - [suffix] - Button runtime_properties { - icon-name: "info-symbolic"; - valign: center; - styles["flat"] - } - [suffix] - Button runtime_copy { - icon-name: "edit-copy-symbolic"; - valign: center; - styles["flat"] - } - } - Adw.ActionRow details { - title: _("Show Details in Store"); - activatable: true; - [suffix] - Image { - icon-name: "arrow2-top-right-symbolic"; - } - } - } - Adw.PreferencesGroup lower { - - } - } - } + + Adw.ActionRow details { + title: _("Show Details in Store"); + activatable: true; + + [suffix] + Image { + icon-name: "arrow2-top-right-symbolic"; + } } + } + + Adw.PreferencesGroup lower {} } - }; - } -} \ No newline at end of file + } + } + } + }; + } +} diff --git a/src/remotes.blp b/src/remotes.blp index b97837c..575c40c 100644 --- a/src/remotes.blp +++ b/src/remotes.blp @@ -1,53 +1,62 @@ using Gtk 4.0; using Adw 1; -template RemotesWindow : Adw.Window { - default-width: 500; - default-height: 450; +template RemotesWindow: Adw.Window { + default-width: 500; + default-height: 450; - Adw.ToolbarView main_toolbar_view { - [top] - HeaderBar header_bar { - Button add_button { - Adw.ButtonContent { - label: _("Add Remote"); - icon-name: "plus-large-symbolic"; - } - } + Adw.ToolbarView main_toolbar_view { + [top] + HeaderBar header_bar { + Button add_button { + Adw.ButtonContent { + label: _("Add Remote"); + icon-name: "plus-large-symbolic"; } - content: - Adw.ToastOverlay toast_overlay { - Stack stack { - Overlay main_overlay { - [overlay] - ProgressBar progress_bar { - visible: false; - pulse-step: 0.7; - can-target: false; - styles ["osd"] - } - ScrolledWindow scroll { - vexpand: true; - Adw.Clamp{ - ListBox remotes_list { - margin-top: 12; - margin-bottom: 12; - margin-start: 12; - margin-end: 12; - hexpand: true; - valign: start; - selection-mode: none; - styles["boxed-list"] - } - } - } - } - Adw.StatusPage no_remotes { - icon-name: "error-symbolic"; - title: _("No Remotes"); - description: _("Warehouse cannot see the list of remotes or the system has no remotes added"); - } - } - }; + } } -} \ No newline at end of file + + content: Adw.ToastOverlay toast_overlay { + Stack stack { + Overlay main_overlay { + [overlay] + ProgressBar progress_bar { + visible: false; + pulse-step: 0.7; + can-target: false; + + styles [ + "osd" + ] + } + + ScrolledWindow scroll { + vexpand: true; + + Adw.Clamp { + ListBox remotes_list { + margin-top: 12; + margin-bottom: 12; + margin-start: 12; + margin-end: 12; + hexpand: true; + valign: start; + selection-mode: none; + + styles [ + "boxed-list" + ] + } + } + } + } + + Adw.StatusPage no_remotes { + icon-name: "error-symbolic"; + title: _("No Remotes"); + description: _("Warehouse cannot see the list of remotes or the system has no remotes added"); + } + } + }; + } +} diff --git a/src/remotes_window.py b/src/remotes_window.py index c9adea3..7bb4317 100644 --- a/src/remotes_window.py +++ b/src/remotes_window.py @@ -78,25 +78,28 @@ class RemotesWindow(Adw.Window): self.stack.set_visible_child(self.main_overlay) for i in range(len(self.host_remotes)): - name = self.host_remotes[i][0] - title = self.host_remotes[i][1] - install_type = self.host_remotes[i][7] - url = self.host_remotes[i][2] - remote_row = Adw.ActionRow(title=title, subtitle=name) - if title == "-": - remote_row.set_title(name) - self.remotes_list.append(remote_row) - label = Gtk.Label(label=("{} wide").format(install_type), valign=Gtk.Align.CENTER) - label.add_css_class("subtitle") - remote_row.add_suffix(label) - 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) - remove_button = Gtk.Button(icon_name="user-trash-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("Remove {}").format(name)) - remove_button.add_css_class("flat") - remove_button.connect("clicked", self.remove_handler, i) - remote_row.add_suffix(copy_button) - remote_row.add_suffix(remove_button) + try: + name = self.host_remotes[i][0] + title = self.host_remotes[i][1] + install_type = self.host_remotes[i][7] + url = self.host_remotes[i][2] + remote_row = Adw.ActionRow(title=title, subtitle=name) + if title == "-": + remote_row.set_title(name) + self.remotes_list.append(remote_row) + label = Gtk.Label(label=("{} wide").format(install_type), valign=Gtk.Align.CENTER) + label.add_css_class("subtitle") + remote_row.add_suffix(label) + 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) + remove_button = Gtk.Button(icon_name="user-trash-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("Remove {}").format(name)) + remove_button.add_css_class("flat") + remove_button.connect("clicked", self.remove_handler, i) + remote_row.add_suffix(copy_button) + remote_row.add_suffix(remove_button) + except: + print("Could not get remote") def addRemoteCallback(self, _a, _b): self.should_pulse = False diff --git a/src/search_install.blp b/src/search_install.blp index 1780cfc..23d2bbf 100644 --- a/src/search_install.blp +++ b/src/search_install.blp @@ -1,80 +1,125 @@ using Gtk 4.0; using Adw 1; -template SearchInstallWindow : Adw.Window { - default-width: 500; - default-height: 450; - title: _("Install From Online"); - modal: true; +template $SearchInstallWindow: Adw.Window { + default-width: 500; + default-height: 450; + title: _("Install From The Web…"); + modal: true; - Adw.ToolbarView main_toolbar_view { - [top] - HeaderBar header_bar { - show-title-buttons: false; - [start] - Button cancel_button { - label: _("Cancel"); - } - [end] - Button install_button { - label: _("Install"); - styles["suggested-action"] - } - } - [top] - Adw.Clamp { - Box { - margin-top: 6; - margin-start: 6; - margin-end: 6; - styles["linked"] - [start] - SearchEntry search_entry { - hexpand: true; - placeholder-text: _("Search for Flatpaks, press Enter to search."); - } - [start] - MenuButton remotes_dropdown { - label: _("All Remotes"); - } - } - } - content: - Adw.ToastOverlay toast_overlay { - Stack main_stack { - Overlay main_overlay { - [overlay] - ProgressBar progress_bar { - pulse-step: 0.7; - can-target: false; - styles["osd"] - } - ScrolledWindow { - Adw.Clamp { - ListBox results_list_box { - margin-top: 12; - margin-bottom: 12; - margin-start: 12; - margin-end: 12; - hexpand: true; - valign: start; - selection-mode: none; - styles["boxed-list"] - } - } - } - } - Adw.StatusPage no_results { - icon-name: "error-symbolic"; - title: _("No matches found"); - description: _("Try a different search term"); - } - Adw.StatusPage too_many { - icon-name: "error-symbolic"; - title: _("Too many results"); - description: _("Try being more specific with your search"); - } - } - }; + Adw.ToolbarView main_toolbar_view { + [top] + HeaderBar header_bar { + show-title-buttons: false; + + [start] + Button cancel_button { + label: _("Cancel"); + } + + [end] + Button install_button { + label: _("Install"); + + styles [ + "suggested-action" + ] + } } -} \ No newline at end of file + + [top] + Adw.Clamp { + Box { + margin-top: 6; + margin-start: 6; + margin-end: 6; + + styles [ + "linked" + ] + + [start] + SearchEntry search_entry { + hexpand: true; + placeholder-text: _("Search for Flatpaks…"); + } + + [start] + MenuButton remotes_dropdown { + label: _("All Remotes"); + } + + [start] + Button search_button { + tooltip-text: _("Search"); + icon-name: "system-search-symbolic"; + } + } + } + + content: Adw.ToastOverlay toast_overlay { + Stack main_stack { + Overlay main_overlay { + [overlay] + ProgressBar progress_bar { + pulse-step: 0.7; + can-target: false; + + styles [ + "osd" + ] + } + + ScrolledWindow { + Adw.Clamp { + ListBox results_list_box { + margin-top: 12; + margin-bottom: 12; + margin-start: 12; + margin-end: 12; + hexpand: true; + valign: start; + selection-mode: none; + + styles [ + "boxed-list" + ] + } + } + } + } + + Adw.StatusPage no_results { + icon-name: "system-search-symbolic"; + title: _("No Results Found"); + description: _("Try a different search term"); + } + + Adw.StatusPage blank_page { + title: _("Search for Flatpaks"); + icon-name: "flatpak-symbolic"; + description: _("Search for Flatpaks that you want to install"); + } + + Adw.StatusPage loading_page { + title: C_("Shown with a spinner while search operation is pending", "Searching…"); + + Spinner { + spinning: true; + height-request: 32; + width-request: 32; + margin-top: 0; + halign: center; + valign: center; + } + } + + Adw.StatusPage too_many { + icon-name: "error-symbolic"; + title: _("Too many results"); + description: _("Try being more specific with your search"); + } + } + }; + } +} diff --git a/src/search_install_window.py b/src/search_install_window.py index 15ea8d6..1f78659 100644 --- a/src/search_install_window.py +++ b/src/search_install_window.py @@ -5,7 +5,7 @@ import os import pathlib @Gtk.Template(resource_path="/io/github/flattool/Warehouse/search_install.ui") -class SearchInstallWindow (Adw.Window): +class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when search is changed __gtype_name__ = "SearchInstallWindow" results_list_box = Gtk.Template.Child() @@ -14,14 +14,18 @@ class SearchInstallWindow (Adw.Window): no_results = Gtk.Template.Child() too_many = Gtk.Template.Child() cancel_button = Gtk.Template.Child() - # search_bar = Gtk.Template.Child() + blank_page = Gtk.Template.Child() + loading_page = Gtk.Template.Child() + search_button = Gtk.Template.Child() search_entry = Gtk.Template.Child() remotes_dropdown = Gtk.Template.Child() + is_debug = GLib.environ_getenv(GLib.get_environ(), "G_MESSAGES_DEBUG") == "all" + def searchResponse(self, a, b): self.results_list_box.remove_all() print(self.search_results) - if len(self.search_results) == 1 and len(self.search_results[0]) == 1: + 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: @@ -29,15 +33,20 @@ class SearchInstallWindow (Adw.Window): return self.main_stack.set_visible_child(self.main_overlay) for i in range(len(self.search_results)): - row = Adw.ActionRow(title=GLib.markup_escape_text(self.search_results[i][0]), subtitle=self.search_results[i][2]) - 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) - row.add_suffix(label) - row.add_suffix(check) - row.set_activatable_widget(check) - self.results_list_box.append(row) + 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]) + 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) + row.add_suffix(label) + row.add_suffix(check) + row.set_activatable_widget(check) + self.results_list_box.append(row) + except: + print("Could not create row") def on_check(self, button): print(button.get_active()) @@ -58,10 +67,11 @@ class SearchInstallWindow (Adw.Window): self.search_results = data def onSearch(self, widget): - self.to_search = widget.get_text() + self.main_stack.set_visible_child(self.loading_page) + self.to_search = self.search_entry.get_text() if len(self.to_search) < 1 or " " in self.to_search: self.results_list_box.remove_all() - self.main_stack.set_visible_child(self.no_results) + self.main_stack.set_visible_child(self.blank_page) return task = Gio.Task.new(None, None, self.searchResponse) task.run_in_thread(lambda *_: self.searchThread()) @@ -72,10 +82,10 @@ class SearchInstallWindow (Adw.Window): def remotesChooserCreator(self): remotes_pop = Gtk.Popover() remotes_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - remotes_pop.set_size_request(400, 1) - scroll = Gtk.ScrolledWindow() - remotes_pop.set_child(scroll) - scroll.set_child(remotes_box) + # remotes_pop.set_size_request(400, 1) # why? + 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): x = 0 height = remotes_pop.get_size(x) @@ -109,6 +119,7 @@ class SearchInstallWindow (Adw.Window): self.set_transient_for(parent_window) # self.search_bar.connect_entry(self.search_entry) self.search_entry.connect("activate", self.onSearch) + self.search_button.connect("clicked", self.onSearch) self.search_entry.connect("changed", lambda *_: self.search_entry.grab_focus()) # self.search_entry.set_key_capture_widget(self.results_list_box) self.search_entry.grab_focus() @@ -118,6 +129,7 @@ class SearchInstallWindow (Adw.Window): self.remotesChooserCreator() self.remote_to_search = [] + self.main_stack.set_visible_child(self.blank_page) diff --git a/src/snapshots.blp b/src/snapshots.blp index 6451c52..b02609c 100644 --- a/src/snapshots.blp +++ b/src/snapshots.blp @@ -1,64 +1,77 @@ using Gtk 4.0; using Adw 1; -template SnapshotsWindow : Adw.Window { - default-width: 500; - default-height: 455; - modal: true; +template SnapshotsWindow: Adw.Window { + default-width: 500; + default-height: 455; + modal: true; - Adw.ToolbarView main_toolbar_view { - [top] - HeaderBar header_bar { - [start] - Button new_snapshot { - Adw.ButtonContent { - label: _("New Snapshot"); - icon-name: "plus-large-symbolic"; - } - } - [end] - Button oepn_folder_button { - icon-name: "document-open-symbolic"; - tooltip-text: _("Open Snapshots Folder"); - } + Adw.ToolbarView main_toolbar_view { + [top] + HeaderBar header_bar { + [start] + Button new_snapshot { + Adw.ButtonContent { + label: _("New Snapshot"); + icon-name: "plus-large-symbolic"; } - content: - Adw.ToastOverlay toast_overlay { - Overlay main_overlay { - [overlay] - ProgressBar progress_bar { - pulse-step: 0.7; - can-target: false; - visible: false; - styles["osd"] - } - Stack main_stack { - ScrolledWindow outerbox { - Adw.Clamp { - ListBox snapshots_group { - margin-top: 12; - margin-bottom: 12; - margin-start: 12; - margin-end: 12; - valign: start; - selection-mode: none; - styles["boxed-list"] - } - } - } - Adw.StatusPage no_snapshots { - title: _("No Snapshots"); - description: _("Snapshots are backups of the app's user data. They can be reapplied at any time."); - icon-name: "clock-alt-symbolic"; + } - Button new_snapshot_pill { - label: _("New Snapshot"); - halign: center; - styles["pill", "suggested-action"] - } - } - } - } - }; + [end] + Button oepn_folder_button { + icon-name: "document-open-symbolic"; + tooltip-text: _("Open Snapshots Folder"); + } } -} \ No newline at end of file + + content: Adw.ToastOverlay toast_overlay { + Overlay main_overlay { + [overlay] + ProgressBar progress_bar { + pulse-step: 0.7; + can-target: false; + visible: false; + + styles [ + "osd" + ] + } + + Stack main_stack { + ScrolledWindow outerbox { + Adw.Clamp { + ListBox snapshots_group { + margin-top: 12; + margin-bottom: 12; + margin-start: 12; + margin-end: 12; + valign: start; + selection-mode: none; + + styles [ + "boxed-list" + ] + } + } + } + + Adw.StatusPage no_snapshots { + title: _("No Snapshots"); + description: _("Snapshots are backups of the app's user data. They can be reapplied at any time."); + icon-name: "clock-alt-symbolic"; + + Button new_snapshot_pill { + label: _("New Snapshot"); + halign: center; + + styles [ + "pill", + "suggested-action" + ] + } + } + } + } + }; + } +} diff --git a/src/user-trash-symbolic.svg b/src/user-trash-symbolic.svg new file mode 100644 index 0000000..b6f8bd1 --- /dev/null +++ b/src/user-trash-symbolic.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/warehouse.gresource.xml b/src/warehouse.gresource.xml index 0f1b0e9..02c2dc7 100644 --- a/src/warehouse.gresource.xml +++ b/src/warehouse.gresource.xml @@ -17,13 +17,14 @@ selection-mode-symbolic.svg error-symbolic.svg - brush-symbolic.svg + user-trash-symbolic.svg folder-visiting-symbolic.svg info-symbolic.svg check-plain-symbolic.svg paper-filled-symbolic.svg plus-large-symbolic.svg funnel-symbolic.svg + flatpak-symbolic.svg right-large-symbolic.svg view-more-symbolic.svg clock-alt-symbolic.svg diff --git a/src/window.blp b/src/window.blp index c358326..c2aa0cb 100644 --- a/src/window.blp +++ b/src/window.blp @@ -1,8 +1,7 @@ using Gtk 4.0; using Adw 1; -template WarehouseWindow : Adw.ApplicationWindow { - styles["devel"] +template $WarehouseWindow: Adw.ApplicationWindow { Adw.ToolbarView main_toolbar_view { [top] HeaderBar header_bar { @@ -11,7 +10,7 @@ template WarehouseWindow : Adw.ApplicationWindow { icon-name: "view-refresh-symbolic"; tooltip-text: _("Refresh List"); } - + [start] ToggleButton search_button { icon-name: "system-search-symbolic"; @@ -30,32 +29,37 @@ template WarehouseWindow : Adw.ApplicationWindow { tooltip-text: _("Main Menu"); menu-model: primary_menu; } - + [end] ToggleButton batch_mode_button { icon-name: "selection-mode-symbolic"; tooltip-text: _("Toggle Selection Mode"); } } + [top] SearchBar search_bar { - search-mode-enabled: bind-property search_button.active bidirectional; - key-capture-widget: WarehouseWindow; - Adw.Clamp{ + search-mode-enabled: bind search_button.active bidirectional; + key-capture-widget: main_toolbar_view; + + Adw.Clamp { maximum-size: 577; hexpand: true; + SearchEntry search_entry {} } } - content: - Adw.ToastOverlay toast_overlay { + + content: Adw.ToastOverlay toast_overlay { Overlay main_overlay { Stack main_stack { Box main_box { orientation: vertical; + ScrolledWindow scrolled_window { vexpand: true; - Adw.Clamp{ + + Adw.Clamp { ListBox flatpaks_list_box { margin-top: 12; margin-bottom: 12; @@ -64,11 +68,15 @@ template WarehouseWindow : Adw.ApplicationWindow { hexpand: true; valign: start; selection-mode: none; - styles["boxed-list"] + + styles [ + "boxed-list" + ] } } } } + Box installing { orientation: vertical; spacing: 10; @@ -76,22 +84,34 @@ template WarehouseWindow : Adw.ApplicationWindow { margin-bottom: 20; halign: center; valign: center; + Spinner { margin-bottom: 35; - width-request: 30; + width-request: 30; height-request: 30; opacity: 0.5; spinning: true; } + Label { label: _("Installing…"); - styles["title-1", "title"] + + styles [ + "title-1", + "title" + ] } + Label { label: _("This could take a while."); - styles["description", "body"] + + styles [ + "description", + "body" + ] } } + Box uninstalling { orientation: vertical; spacing: 10; @@ -99,53 +119,77 @@ template WarehouseWindow : Adw.ApplicationWindow { margin-bottom: 20; halign: center; valign: center; + Spinner { margin-bottom: 35; - width-request: 30; + width-request: 30; height-request: 30; opacity: 0.5; spinning: true; } + Label { label: _("Uninstalling…"); - styles["title-1", "title"] + + styles [ + "title-1", + "title" + ] } + Label { label: _("This could take a while."); - styles["description", "body"] + + styles [ + "description", + "body" + ] } } + Adw.StatusPage no_flatpaks { icon-name: "error-symbolic"; title: _("No Flatpaks Found"); description: _("There are either no Flatpaks that match the current filter, Warehouse cannot see the list of installed Flatpaks, or the system has no Flatpaks installed."); } + + Adw.StatusPage no_results { + icon-name: "system-search-symbolic"; + title: _("No Results Found"); + description: _("Try a different search term"); + } } } }; + [bottom] ActionBar batch_mode_bar { revealed: false; + [start] ToggleButton batch_select_all_button { label: _("Select All"); } + [end] Button batch_uninstall_button { icon-name: "user-trash-symbolic"; tooltip-text: _("Uninstall Selected Apps"); } + [end] Button batch_clean_button { icon-name: "brush-symbolic"; tooltip-text: _("Send Selected Apps' Data to the Trash"); } + [end] MenuButton batch_copy_button { icon-name: "edit-copy-symbolic"; tooltip-text: _("Open Copy Menu"); menu-model: copy_menu; } + [end] Button batch_snapshot_button { icon-name: "clock-alt-symbolic"; @@ -158,14 +202,13 @@ template WarehouseWindow : Adw.ApplicationWindow { menu primary_menu { section { - item { - label: _("Install From File"); + label: _("Install From File…"); action: "app.install-from-file"; } item { - label: _("Manage Leftover Data"); + label: _("Manage Leftover Data…"); action: "app.manage-data-folders"; } @@ -173,14 +216,13 @@ menu primary_menu { label: _("_Preferences"); action: "app.preferences"; }*/ - item { - label: _("Manage Remotes"); + label: _("Manage Remotes…"); action: "app.show-remotes-window"; } item { - label: _("Install from Search"); + label: _("Install From The Web…"); action: "app.open-search-install"; } @@ -202,7 +244,7 @@ menu copy_menu { label: _("Copy Names"); action: "win.copy-names"; } - + item { label: _("Copy IDs"); action: "win.copy-ids"; @@ -222,4 +264,4 @@ menu row_menu { //action: "win.open-app"; } } -} \ No newline at end of file +} diff --git a/src/window.py b/src/window.py index 534f15d..265b98f 100644 --- a/src/window.py +++ b/src/window.py @@ -28,6 +28,7 @@ from .common import myUtils from .remotes_window import RemotesWindow from .downgrade_window import DowngradeWindow from .snapshots_window import SnapshotsWindow +from .const import Config from .app_row_widget import AppRow @@ -42,6 +43,7 @@ class WarehouseWindow(Adw.ApplicationWindow): toast_overlay = Gtk.Template.Child() refresh_button = Gtk.Template.Child() no_flatpaks = Gtk.Template.Child() + no_results = Gtk.Template.Child() main_stack = Gtk.Template.Child() batch_mode_button = Gtk.Template.Child() batch_mode_bar = Gtk.Template.Child() @@ -70,12 +72,15 @@ class WarehouseWindow(Adw.ApplicationWindow): no_close = None re_get_flatpaks = False currently_uninstalling = False + is_result = False + is_empty = False selected_rows = [] flatpak_rows = [] # ^ {Row visibility, Row selected, the row itself, properties, row menu, select, the flatpak row from `flatpak list`, mask label} 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()): + self.is_result = True return True def removeRow(self, row): @@ -255,6 +260,7 @@ class WarehouseWindow(Adw.ApplicationWindow): self.batch_mode_button.set_sensitive(not is_empty) self.search_button.set_sensitive(not is_empty) self.filter_button.set_sensitive(not is_empty) + self.is_empty = is_empty if is_empty: self.batch_mode_button.set_active(False) @@ -393,11 +399,17 @@ class WarehouseWindow(Adw.ApplicationWindow): self.user_mask_list = self.my_utils.getHostMasks("user") for index in range(len(self.host_flatpaks)): - if "eol" in self.host_flatpaks[index][12]: - self.eol_list.append(self.host_flatpaks[index][8]) + try: + if "eol" in self.host_flatpaks[index][12]: + self.eol_list.append(self.host_flatpaks[index][8]) + except: + print("Could not find EOL") for index in range(len(self.host_flatpaks)): - self.creat_row(index) + try: + self.creat_row(index) + except: + print("Could not create row") self.windowSetEmpty(not self.flatpaks_list_box.get_row_at_index(0)) self.applyFilter(self.filter_list) @@ -746,6 +758,28 @@ class WarehouseWindow(Adw.ApplicationWindow): else: self.toast_overlay.add_toast(Adw.Toast.new(_("File type not supported"))) + def on_invalidate(self, row): + if self.is_empty: + self.batch_mode_button.set_active(False) + self.main_stack.set_visible_child(self.no_flatpaks) + else: + self.main_stack.set_visible_child(self.main_box) + + self.is_result = False + self.flatpaks_list_box.invalidate_filter() + if self.is_result == False: + self.main_stack.set_visible_child(self.no_results) + + def on_change(self, prop, prop2): + if self.search_bar.get_search_mode() == False: + if self.is_empty: + self.batch_mode_button.set_active(False) + self.main_stack.set_visible_child(self.no_flatpaks) + else: + self.main_stack.set_visible_child(self.main_box) + + + def __init__(self, **kwargs): super().__init__(**kwargs) self.my_utils = myUtils(self) @@ -767,8 +801,9 @@ class WarehouseWindow(Adw.ApplicationWindow): self.flatpaks_list_box.set_filter_func(self.filter_func) self.generate_list_of_flatpaks() - self.search_entry.connect("search-changed", lambda *_: self.flatpaks_list_box.invalidate_filter()) + 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) self.refresh_button.connect("clicked", self.refresh_list_of_flatpaks, True) self.batch_mode_button.connect("toggled", self.batch_mode_handler) self.batch_clean_button.connect("clicked", self.batchCleanHandler) @@ -791,6 +826,9 @@ class WarehouseWindow(Adw.ApplicationWindow): file_drop.connect("drop", self.drop_callback) self.scrolled_window.add_controller(file_drop) + if Config.DEVEL: + self.add_css_class("devel") +