mirror of
https://github.com/morgan9e/warehouse
synced 2026-04-15 00:34:42 +09:00
Add keyboard shortcuts!
This commit is contained in:
@@ -1,70 +1,24 @@
|
||||
using Gtk 4.0;
|
||||
|
||||
ShortcutsWindow help_overlay {
|
||||
modal: true;
|
||||
|
||||
ShortcutsSection {
|
||||
section-name: "shortcuts";
|
||||
// max-height: 8;
|
||||
|
||||
ShortcutsGroup {
|
||||
title: _("App Management");
|
||||
|
||||
ShortcutsShortcut {
|
||||
title: _("Search");
|
||||
action-name: "app.search";
|
||||
}
|
||||
|
||||
ShortcutsShortcut {
|
||||
title: _("Set Filters");
|
||||
action-name: "app.set-filter";
|
||||
}
|
||||
|
||||
ShortcutsShortcut {
|
||||
title: _("Refresh");
|
||||
action-name: "app.refresh";
|
||||
}
|
||||
|
||||
ShortcutsShortcut {
|
||||
title: _("Toggle Selection Mode");
|
||||
action-name: "app.toggle-batch-mode";
|
||||
}
|
||||
}
|
||||
ShortcutsGroup {
|
||||
title: _("More Functions");
|
||||
|
||||
ShortcutsShortcut {
|
||||
title: _("Manage Leftover Data");
|
||||
action-name: "app.manage-data-folders";
|
||||
}
|
||||
|
||||
ShortcutsShortcut {
|
||||
title: _("Manage Remotes");
|
||||
action-name: "app.show-remotes-window";
|
||||
}
|
||||
|
||||
ShortcutsShortcut {
|
||||
title: _("Install From File");
|
||||
action-name: "app.install-from-file";
|
||||
}
|
||||
}
|
||||
ShortcutsGroup {
|
||||
title: _("General");
|
||||
|
||||
ShortcutsShortcut {
|
||||
title: _("Open Menu");
|
||||
action-name: "app.open-menu";
|
||||
}
|
||||
|
||||
ShortcutsShortcut {
|
||||
title: _("Show Shortcuts");
|
||||
action-name: "win.show-help-overlay";
|
||||
}
|
||||
|
||||
ShortcutsShortcut {
|
||||
title: _("Quit");
|
||||
action-name: "app.quit";
|
||||
}
|
||||
}
|
||||
}
|
||||
modal: true;
|
||||
ShortcutsSection {
|
||||
section-name: "shortcuts";
|
||||
// max-height: 8;
|
||||
ShortcutsGroup {
|
||||
title: _("General");
|
||||
ShortcutsShortcut {
|
||||
title: _("Open Menu");
|
||||
action-name: "app.open-menu";
|
||||
}
|
||||
ShortcutsShortcut {
|
||||
title: _("Show Shortcuts");
|
||||
action-name: "win.show-help-overlay";
|
||||
}
|
||||
ShortcutsShortcut {
|
||||
title: _("Quit");
|
||||
action-name: "app.quit";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
161
src/main.py
161
src/main.py
@@ -32,10 +32,10 @@ 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",
|
||||
@@ -43,9 +43,6 @@ class WarehouseApplication(Adw.Application):
|
||||
)
|
||||
self.create_action("about", self.on_about_action)
|
||||
self.create_action("preferences", self.on_preferences_action)
|
||||
self.create_action("quit", lambda *_: self.quit(), ["<primary>q"])
|
||||
self.create_action("refresh", self.on_refresh_shortcut, ["<primary>r", "F5"])
|
||||
self.create_action("open-menu", lambda *_: self.props.active_window.main_menu.popup(), ["F10"])
|
||||
|
||||
self.create_action("show-packages-page", lambda *_: self.props.active_window.switch_page_shortcut_handler("p"), ["<primary>p"])
|
||||
self.create_action("show-remotes-page", lambda *_: self.props.active_window.switch_page_shortcut_handler("m"), ["<primary>m"])
|
||||
@@ -53,8 +50,20 @@ class WarehouseApplication(Adw.Application):
|
||||
self.create_action("show-snapshots-page", lambda *_: self.props.active_window.switch_page_shortcut_handler("s"), ["<primary>s"])
|
||||
self.create_action("show-install-page", lambda *_: self.props.active_window.switch_page_shortcut_handler("i"), ["<primary>i"])
|
||||
|
||||
self.create_action("quit", lambda *_: self.quit(), ["<primary>q"])
|
||||
self.create_action("refresh", lambda *_: self.props.active_window.refresh_handler(), ["<primary>r", "F5"])
|
||||
self.create_action("open-menu", lambda *_: self.props.active_window.main_menu.popup(), ["F10"])
|
||||
self.create_action("open-files", self.on_open_files_shortcut, ["<primary>o"])
|
||||
self.create_action("toggle-select-mode", self.on_toggle_select_mode_shortcut, ["<primary>b", "<primary>Return", "<primary>KP_Enter"])
|
||||
self.create_action("toggle-search-mode", self.on_toggle_search_mode_shortcut, ["<primary>f"])
|
||||
self.create_action("filter", self.on_filter_shortcut, ["<primary>t"])
|
||||
self.create_action("new", self.on_new_shortcut, ["<primary>n"])
|
||||
self.create_action("delete", self.on_delete_shortcut, ["BackSpace", "Delete"])
|
||||
self.create_action("active-data-view", lambda *_: self.on_data_view_shortcut(True), ["<Alt>1"])
|
||||
self.create_action("leftover-data-view", lambda *_: self.on_data_view_shortcut(False), ["<Alt>2"])
|
||||
|
||||
self.is_dialog_open = False
|
||||
|
||||
|
||||
gtk_version = (
|
||||
str(Gtk.MAJOR_VERSION)
|
||||
+ "."
|
||||
@@ -71,7 +80,7 @@ class WarehouseApplication(Adw.Application):
|
||||
)
|
||||
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,
|
||||
@@ -82,33 +91,108 @@ class WarehouseApplication(Adw.Application):
|
||||
lang=lang,
|
||||
)
|
||||
|
||||
def on_refresh_shortcut(self, *args):
|
||||
self.props.active_window.refresh_handler()
|
||||
|
||||
# def file_callback(self, object, result):
|
||||
# window = self.props.active_window
|
||||
# try:
|
||||
# file = object.open_finish(result)
|
||||
# window.install_file(file.get_path())
|
||||
# except GLib.GError:
|
||||
# pass
|
||||
|
||||
# def install_from_file(self, widget, _a):
|
||||
# window = self.props.active_window
|
||||
|
||||
# filter = Gtk.FileFilter(name=_("Flatpaks"))
|
||||
# filter.add_suffix("flatpak")
|
||||
# filter.add_suffix("flatpakref")
|
||||
# filters = Gio.ListStore.new(Gtk.FileFilter)
|
||||
# filters.append(filter)
|
||||
# file_chooser = Gtk.FileDialog()
|
||||
# file_chooser.set_filters(filters)
|
||||
# file_chooser.set_default_filter(filter)
|
||||
# file_chooser.open(window, None, self.file_callback)
|
||||
|
||||
def on_open_files_shortcut(self, *args):
|
||||
window = self.props.active_window
|
||||
|
||||
def file_choose_callback(object, result):
|
||||
files = object.open_multiple_finish(result)
|
||||
window.on_file_drop(None, files, None, None)
|
||||
|
||||
file_filter = Gtk.FileFilter(name=_("Flatpaks & Remotes"))
|
||||
file_filter.add_suffix("flatpak")
|
||||
file_filter.add_suffix("flatpakref")
|
||||
file_filter.add_suffix("flatpakrepo")
|
||||
filters = Gio.ListStore.new(Gtk.FileFilter)
|
||||
filters.append(file_filter)
|
||||
file_chooser = Gtk.FileDialog()
|
||||
file_chooser.set_filters(filters)
|
||||
file_chooser.set_default_filter(file_filter)
|
||||
file_chooser.open_multiple(window, None, file_choose_callback)
|
||||
|
||||
def on_toggle_select_mode_shortcut(self, *args):
|
||||
try:
|
||||
button = self.props.active_window.stack.get_visible_child().select_button
|
||||
button.set_active(not button.get_active())
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def on_toggle_search_mode_shortcut(self, *args):
|
||||
try:
|
||||
button = self.props.active_window.stack.get_visible_child().search_button
|
||||
button.set_active(not button.get_active())
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def on_filter_shortcut(self, *args):
|
||||
try:
|
||||
button = self.props.active_window.stack.get_visible_child().filter_button
|
||||
button.set_active(not button.get_active())
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
button = self.props.active_window.stack.get_visible_child().sort_button
|
||||
button.set_active(True)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
button = self.props.active_window.stack.get_visible_child().show_disabled_button
|
||||
if button.get_visible():
|
||||
button.set_active(not button.get_active())
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def on_new_shortcut(self, *args):
|
||||
page = self.props.active_window.stack.get_visible_child()
|
||||
try:
|
||||
page.new_custom_handler()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
page.on_new()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def on_delete_shortcut(self, *args):
|
||||
page = self.props.active_window.stack.get_visible_child()
|
||||
try:
|
||||
if not page.select_button.get_active():
|
||||
return
|
||||
|
||||
page.selection_uninstall()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
if not page.select_button.get_active():
|
||||
return
|
||||
|
||||
page.trash_handler()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
if not page.select_button.get_active():
|
||||
return
|
||||
|
||||
page.select_trash_handler()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def on_data_view_shortcut(self, is_active):
|
||||
page = self.props.active_window.stack.get_visible_child()
|
||||
try:
|
||||
adp = page.adp
|
||||
ldp = page.ldp
|
||||
page.stack.set_visible_child(adp if is_active else ldp)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def do_activate(self):
|
||||
"""Called when the application is activated.
|
||||
|
||||
|
||||
We raise the application's main window, creating it if
|
||||
necessary.
|
||||
"""
|
||||
@@ -116,7 +200,7 @@ class WarehouseApplication(Adw.Application):
|
||||
if not win:
|
||||
win = WarehouseWindow(application=self)
|
||||
win.present()
|
||||
|
||||
|
||||
def on_about_action(self, widget, _a):
|
||||
"""Callback for the app.about action."""
|
||||
about = Adw.AboutDialog(
|
||||
@@ -156,18 +240,17 @@ class WarehouseApplication(Adw.Application):
|
||||
],
|
||||
)
|
||||
about.present(self.props.active_window)
|
||||
|
||||
|
||||
def on_preferences_action(self, widget, _):
|
||||
"""Callback for the app.preferences action."""
|
||||
print("app.preferences action activated")
|
||||
|
||||
|
||||
def create_action(self, name, callback, shortcuts=None):
|
||||
"""Add an application action.
|
||||
|
||||
|
||||
Args:
|
||||
name: the name of the action
|
||||
callback: the function to be called when the action is
|
||||
activated
|
||||
callback: the function to be called when the action is activated
|
||||
shortcuts: an optional list of accelerators
|
||||
"""
|
||||
action = Gio.SimpleAction.new(name, None)
|
||||
@@ -175,7 +258,7 @@ class WarehouseApplication(Adw.Application):
|
||||
self.add_action(action)
|
||||
if shortcuts:
|
||||
self.set_accels_for_action(f"app.{name}", shortcuts)
|
||||
|
||||
|
||||
def main(version):
|
||||
"""The application's entry point."""
|
||||
app = WarehouseApplication()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from gi.repository import Adw, Gtk, GLib, Gio
|
||||
from gi.repository import Adw, Gtk, GLib, Gio, Gdk
|
||||
from .host_info import HostInfo
|
||||
from .app_row import AppRow
|
||||
from .error_toast import ErrorToast
|
||||
@@ -47,13 +47,13 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
uninstall_button = gtc()
|
||||
properties_page = gtc()
|
||||
filters_page = gtc()
|
||||
|
||||
|
||||
# Referred to in the main window
|
||||
# It is used to determine if a new page should be made or not
|
||||
# This must be set to the created object from within the class's __init__ method
|
||||
instance = None
|
||||
page_name = "packages"
|
||||
|
||||
|
||||
def set_status(self, to_set):
|
||||
|
||||
if to_set is self.scrolled_window:
|
||||
@@ -61,12 +61,12 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
self.select_button.set_sensitive(True)
|
||||
self.filter_button.set_sensitive(True)
|
||||
self.filters_page.set_sensitive(True)
|
||||
|
||||
|
||||
self.search_button.set_sensitive(True)
|
||||
self.search_entry.set_editable(True)
|
||||
else:
|
||||
self.select_button.set_sensitive(False)
|
||||
|
||||
|
||||
if to_set is self.no_packages:
|
||||
self.properties_page.stack.set_visible_child(self.properties_page.error_tbv)
|
||||
self.filter_button.set_sensitive(False)
|
||||
@@ -78,7 +78,7 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
self.filters_page.set_sensitive(True)
|
||||
if not self.packages_split.get_collapsed():
|
||||
self.filter_button.set_active(True)
|
||||
|
||||
|
||||
if to_set is self.no_results:
|
||||
self.filters_page.set_sensitive(False)
|
||||
|
||||
@@ -93,7 +93,7 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
else:
|
||||
self.stack.set_visible_child(self.packages_split)
|
||||
self.status_stack.set_visible_child(to_set)
|
||||
|
||||
|
||||
def apply_filters(self):
|
||||
i = 0
|
||||
show_apps = self.filter_settings.get_boolean("show-apps")
|
||||
@@ -112,20 +112,20 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
visible = False
|
||||
if runtimes_list != "all" and (row.package.is_runtime or row.package.dependant_runtime and not row.package.dependant_runtime.info["ref"] in runtimes_list):
|
||||
visible = False
|
||||
|
||||
|
||||
row.set_visible(visible)
|
||||
if visible:
|
||||
total_visible += 1
|
||||
else:
|
||||
row.check_button.set_active(False)
|
||||
|
||||
|
||||
if total_visible == 0:
|
||||
self.set_status(self.no_filter_results)
|
||||
else:
|
||||
GLib.idle_add(lambda *_: self.set_status(self.scrolled_window))
|
||||
if self.current_row_for_properties and not self.current_row_for_properties.get_visible():
|
||||
self.select_first_visible_row()
|
||||
|
||||
|
||||
def select_first_visible_row(self):
|
||||
first_visible_row = None
|
||||
i = 0
|
||||
@@ -135,11 +135,11 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
first_visible_row = row
|
||||
self.current_row_for_properties = row
|
||||
break
|
||||
|
||||
|
||||
if not first_visible_row is None:
|
||||
self.packages_list_box.select_row(first_visible_row)
|
||||
self.properties_page.set_properties(first_visible_row.package)
|
||||
|
||||
|
||||
def row_select_handler(self, row):
|
||||
if row.check_button.get_active():
|
||||
self.selected_rows.append(row)
|
||||
@@ -154,17 +154,17 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
self.packages_navpage.set_title(_("Packages"))
|
||||
self.copy_button.set_sensitive(False)
|
||||
self.uninstall_button.set_sensitive(False)
|
||||
|
||||
|
||||
def select_all_handler(self, *args):
|
||||
i = 0
|
||||
while row := self.packages_list_box.get_row_at_index(i):
|
||||
i += 1
|
||||
row.check_button.set_active(row.get_visible())
|
||||
|
||||
|
||||
def row_rclick_handler(self, row):
|
||||
self.select_button.set_active(True)
|
||||
GLib.idle_add(lambda *_, button=row.check_button: button.set_active(not button.get_active()))
|
||||
|
||||
|
||||
def generate_list(self, *args):
|
||||
self.properties_page.nav_view.pop_to_page(self.properties_page.inner_nav_page)
|
||||
self.packages_list_box.remove_all()
|
||||
@@ -175,7 +175,7 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
if len(HostInfo.flatpaks) == 0:
|
||||
self.set_status(self.no_packages)
|
||||
return
|
||||
|
||||
|
||||
for package in HostInfo.flatpaks:
|
||||
row = AppRow(package, self.row_rclick_handler)
|
||||
package.app_row = row
|
||||
@@ -191,19 +191,19 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
self.packages_toast_overlay.add_toast(ErrorToast(_("Error getting Flatpak '{}'").format(package.info["name"]), str(e)).toast)
|
||||
|
||||
self.packages_list_box.append(row)
|
||||
|
||||
|
||||
self.apply_filters()
|
||||
self.select_first_visible_row()
|
||||
|
||||
|
||||
self.scrolled_window.set_vadjustment(Gtk.Adjustment.new(0,0,0,0,0,0)) # Scroll list to top
|
||||
|
||||
|
||||
def row_activate_handler(self, list_box, row):
|
||||
self.properties_page.set_properties(row.package)
|
||||
self.properties_page.nav_view.pop()
|
||||
self.packages_split.set_show_content(True)
|
||||
self.filter_button.set_active(False)
|
||||
self.current_row_for_properties = row
|
||||
|
||||
|
||||
def filter_func(self, row):
|
||||
search_text = self.search_entry.get_text().lower()
|
||||
title = row.get_title().lower()
|
||||
@@ -211,14 +211,14 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
if row.get_visible() and (search_text in title or search_text in subtitle):
|
||||
self.is_result = True
|
||||
return True
|
||||
|
||||
|
||||
def set_selection_mode(self, is_enabled):
|
||||
i = 0
|
||||
while row := self.packages_list_box.get_row_at_index(i):
|
||||
i += 1
|
||||
GLib.idle_add(row.check_button.set_active, False)
|
||||
GLib.idle_add(row.check_button.set_visible, is_enabled)
|
||||
|
||||
|
||||
def selection_copy(self, box, row):
|
||||
self.copy_pop.popdown()
|
||||
info = ""
|
||||
@@ -233,7 +233,7 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
case self.copy_refs:
|
||||
info = "ref"
|
||||
feedback = _("Refs")
|
||||
|
||||
|
||||
to_copy = []
|
||||
for row in self.selected_rows:
|
||||
to_copy.append(row.package.info[info])
|
||||
@@ -243,8 +243,11 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
self.packages_toast_overlay.add_toast(Adw.Toast(title=_("Copied {}").format(feedback)))
|
||||
except Exception as e:
|
||||
self.packages_toast_overlay.add_toast(ErrorToast(_("Could not copy {}").format(feedback), str(e)).toast)
|
||||
|
||||
|
||||
def selection_uninstall(self, *args):
|
||||
if len(self.selected_rows) < 1:
|
||||
return
|
||||
|
||||
def on_response(should_trash):
|
||||
GLib.idle_add(lambda *_: self.set_status(self.uninstalling))
|
||||
error = [None]
|
||||
@@ -256,7 +259,7 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
cmd.append(row.package.info["ref"])
|
||||
if should_trash and os.path.exists(row.package.data_path):
|
||||
to_trash.append(row.package.data_path)
|
||||
|
||||
|
||||
try:
|
||||
subprocess.run(cmd, check=True, capture_output=True)
|
||||
if should_trash and len(to_trash) > 0:
|
||||
@@ -265,7 +268,7 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
error[0] = cpe
|
||||
except Exception as e:
|
||||
error[0] = e
|
||||
|
||||
|
||||
def callback(*args):
|
||||
self.main_window.refresh_handler()
|
||||
HostInfo.main_window.remove_refresh_lockout("batch uninstalling packages")
|
||||
@@ -274,49 +277,57 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
GLib.idle_add(lambda *args: self.packages_toast_overlay.add_toast(ErrorToast(_("Could not uninstall packages"), details).toast))
|
||||
else:
|
||||
GLib.idle_add(lambda *args: self.packages_toast_overlay.add_toast(Adw.Toast(title=_("Uninstalled Packages"))))
|
||||
|
||||
|
||||
Gio.Task.new(None, None, callback).run_in_thread(thread)
|
||||
|
||||
|
||||
dialog = UninstallDialog(on_response, True)
|
||||
dialog.present(self.main_window)
|
||||
|
||||
|
||||
def start_loading(self):
|
||||
self.packages_navpage.set_title(_("Packages"))
|
||||
self.select_button.set_active(False)
|
||||
self.set_status(self.loading_packages)
|
||||
|
||||
|
||||
def end_loading(self):
|
||||
GLib.idle_add(lambda *_: self.generate_list())
|
||||
|
||||
|
||||
def select_button_handler(self, button):
|
||||
self.set_selection_mode(button.get_active())
|
||||
|
||||
|
||||
def filter_button_handler(self, button):
|
||||
if button.get_active():
|
||||
self.content_stack.set_visible_child(self.filters_page)
|
||||
self.packages_split.set_show_content(True)
|
||||
else:
|
||||
self.content_stack.set_visible_child(self.properties_page)
|
||||
|
||||
self.packages_split.set_show_content(False)
|
||||
|
||||
def filter_page_handler(self, *args):
|
||||
if self.packages_split.get_collapsed() and not self.packages_split.get_show_content():
|
||||
self.filter_button.set_active(False)
|
||||
|
||||
|
||||
def on_invalidate(self, row):
|
||||
current_status = self.status_stack.get_visible_child()
|
||||
if not current_status is self.no_results:
|
||||
self.prev_status = current_status
|
||||
|
||||
|
||||
self.is_result = False
|
||||
self.packages_list_box.invalidate_filter()
|
||||
if self.is_result:
|
||||
self.set_status(self.prev_status)
|
||||
else:
|
||||
self.set_status(self.no_results)
|
||||
|
||||
|
||||
def sort_func(self, row1, row2):
|
||||
return row1.package.info["name"].lower() > row2.package.info["name"].lower()
|
||||
|
||||
|
||||
def key_handler(self, controller, keyval, keycode, state):
|
||||
if keyval == Gdk.KEY_Escape:
|
||||
if self.select_button.get_active():
|
||||
self.select_button.set_active(False)
|
||||
elif self.filter_button.get_active():
|
||||
self.filter_button.set_active(False)
|
||||
|
||||
def __init__(self, main_window, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@@ -334,8 +345,10 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
self.prev_status = None
|
||||
self.selected_rows = []
|
||||
self.current_row_for_properties = None
|
||||
event_controller = Gtk.EventControllerKey()
|
||||
|
||||
# Apply
|
||||
self.add_controller(event_controller)
|
||||
self.loading_view.set_content(self.loading_packages)
|
||||
self.packages_list_box.set_filter_func(self.filter_func)
|
||||
self.packages_list_box.set_sort_func(self.sort_func)
|
||||
@@ -344,6 +357,7 @@ class PackagesPage(Adw.BreakpointBin):
|
||||
self.__class__.instance = self
|
||||
|
||||
# Connections
|
||||
event_controller.connect("key-pressed", self.key_handler)
|
||||
self.search_entry.connect("search-changed", self.on_invalidate)
|
||||
self.search_bar.set_key_capture_widget(main_window)
|
||||
self.packages_list_box.connect("row-activated", self.row_activate_handler)
|
||||
|
||||
@@ -4,30 +4,39 @@ from gi.repository import Adw, Gtk, GLib, Gio, Pango
|
||||
class UninstallDialog(Adw.AlertDialog):
|
||||
__gtype_name__ = "UninstallDialog"
|
||||
gtc = Gtk.Template.Child
|
||||
|
||||
|
||||
group = gtc()
|
||||
trash = gtc()
|
||||
|
||||
is_open = False
|
||||
|
||||
def on_response(self, dialog, response):
|
||||
self.__class__.is_open = False
|
||||
if response != "continue":
|
||||
return
|
||||
|
||||
|
||||
self.continue_callback(self.trash.get_active())
|
||||
|
||||
|
||||
def present(self, *args, **kwargs):
|
||||
if self.__class__.is_open:
|
||||
return
|
||||
|
||||
self.__class__.is_open = True
|
||||
super().present(*args, **kwargs)
|
||||
|
||||
def __init__(self, continue_callback, show_trash_option, package_name=None, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
if package_name:
|
||||
self.set_heading(GLib.markup_escape_text(_("Uninstall {}?").format(package_name)))
|
||||
self.set_body(GLib.markup_escape_text(_("It will not be possible to use {} after removal").format(package_name)))
|
||||
else:
|
||||
self.set_heading(GLib.markup_escape_text(_("Uninstall Packages?")))
|
||||
self.set_body(GLib.markup_escape_text(_("It will not be possible to use these packages after removal")))
|
||||
|
||||
|
||||
self.continue_callback = continue_callback
|
||||
self.add_response("cancel", _("Cancel"))
|
||||
self.add_response("continue", _("Uninstall"))
|
||||
self.set_response_appearance("continue", Adw.ResponseAppearance.DESTRUCTIVE)
|
||||
self.connect("response", self.on_response)
|
||||
self.group.set_title(GLib.markup_escape_text(_("App Settings & Content")))
|
||||
self.group.set_visible(show_trash_option)
|
||||
self.group.set_visible(show_trash_option)
|
||||
|
||||
@@ -18,6 +18,7 @@ class AddRemoteDialog(Adw.Dialog):
|
||||
name_row = gtc()
|
||||
url_row = gtc()
|
||||
installation_chooser = gtc()
|
||||
is_open = False
|
||||
|
||||
def on_apply(self, *args):
|
||||
self.parent_page.status_stack.set_visible_child(self.parent_page.adding_view)
|
||||
@@ -75,6 +76,16 @@ class AddRemoteDialog(Adw.Dialog):
|
||||
|
||||
self.apply_button.set_sensitive(self.title_passes and self.name_passes and self.url_passes)
|
||||
|
||||
def present(self, *args, **kwargs):
|
||||
if self.__class__.is_open:
|
||||
return
|
||||
|
||||
self.__class__.is_open = True
|
||||
super().present(*args, **kwargs)
|
||||
|
||||
def on_close(self, *args):
|
||||
self.__class__.is_open = False
|
||||
|
||||
def __init__(self, main_window, parent_page, remote_info=None, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@@ -112,6 +123,7 @@ class AddRemoteDialog(Adw.Dialog):
|
||||
self.apply_button.set_sensitive(False)
|
||||
|
||||
# Connections
|
||||
self.connect("closed", self.on_close)
|
||||
self.cancel_button.connect("clicked", lambda *_: self.close())
|
||||
self.apply_button.connect("clicked", self.on_apply)
|
||||
self.title_row.connect("changed", self.check_entries)
|
||||
|
||||
@@ -260,6 +260,9 @@ class RemotesPage(Adw.NavigationPage):
|
||||
total_visible += 1
|
||||
|
||||
self.none_visible.set_visible(total_visible == 0)
|
||||
|
||||
def new_custom_handler(self, *args):
|
||||
AddRemoteDialog(self.main_window, self).present(self.main_window)
|
||||
|
||||
def __init__(self, main_window, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
@@ -274,7 +277,7 @@ class RemotesPage(Adw.NavigationPage):
|
||||
|
||||
# Connections
|
||||
self.file_remote_row.connect("activated", lambda *_: self.add_file_handler())
|
||||
self.custom_remote_row.connect("activated", lambda *_: AddRemoteDialog(main_window, self).present(main_window))
|
||||
self.custom_remote_row.connect("activated", self.new_custom_handler)
|
||||
self.search_entry.connect("search-changed", self.on_search)
|
||||
self.show_disabled_button.connect("toggled", self.show_disabled_handler)
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ class NewSnapshotDialog(Adw.Dialog):
|
||||
scrolled_window = gtc()
|
||||
no_results = gtc()
|
||||
stack = gtc()
|
||||
is_open = False
|
||||
|
||||
def row_gesture_handler(self, row):
|
||||
row.check_button.set_active(not row.check_button.get_active())
|
||||
@@ -68,6 +69,7 @@ class NewSnapshotDialog(Adw.Dialog):
|
||||
return False
|
||||
|
||||
def on_close(self, *args):
|
||||
self.__class__.is_open = False
|
||||
self.search_button.set_active(False)
|
||||
for row in self.selected_rows.copy():
|
||||
GLib.idle_add(lambda *_, row=row: row.check_button.set_active(False))
|
||||
@@ -149,16 +151,20 @@ class NewSnapshotDialog(Adw.Dialog):
|
||||
row.set_activatable(False)
|
||||
self.selected_rows.append(row)
|
||||
self.listbox.append(row)
|
||||
|
||||
|
||||
def enter_handler(self, *args):
|
||||
if self.create_button.get_sensitive():
|
||||
self.create_button.activate()
|
||||
|
||||
def present(self, *args, **kwargs):
|
||||
if self.__class__.is_open:
|
||||
return
|
||||
|
||||
super().present(*args, **kwargs)
|
||||
self.__class__.is_open = True
|
||||
if not self.search_button.get_visible():
|
||||
self.name_entry.grab_focus()
|
||||
|
||||
|
||||
def __init__(self, snapshot_page, loading_status, on_done=None, packages=None, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import os, subprocess, json, re
|
||||
class SnapshotBox(Gtk.Box):
|
||||
__gtype_name__ = "SnapshotBox"
|
||||
gtc = Gtk.Template.Child
|
||||
|
||||
|
||||
title = gtc()
|
||||
date = gtc()
|
||||
version = gtc()
|
||||
@@ -18,7 +18,7 @@ class SnapshotBox(Gtk.Box):
|
||||
rename_entry = gtc()
|
||||
apply_rename = gtc()
|
||||
trash_button = gtc()
|
||||
|
||||
|
||||
def create_json(self):
|
||||
try:
|
||||
data = {
|
||||
@@ -31,7 +31,7 @@ class SnapshotBox(Gtk.Box):
|
||||
|
||||
except Exception as e:
|
||||
self.toast_overlay.add_toast(ErrorToast(_("Could not write data"), str(e)).toast)
|
||||
|
||||
|
||||
def update_json(self, key, value):
|
||||
try:
|
||||
with open(self.json_path, 'r+') as file:
|
||||
@@ -40,14 +40,14 @@ class SnapshotBox(Gtk.Box):
|
||||
file.seek(0)
|
||||
json.dump(data, file, indent=4)
|
||||
file.truncate()
|
||||
|
||||
|
||||
except Exception as e:
|
||||
self.toast_overlay.add_toast(ErrorToast(_("Could not write data"), str(e)).toast)
|
||||
|
||||
|
||||
def load_from_json(self):
|
||||
if not os.path.exists(self.json_path):
|
||||
self.create_json()
|
||||
|
||||
|
||||
try:
|
||||
with open(self.json_path, 'r') as file:
|
||||
data = json.load(file)
|
||||
@@ -59,15 +59,15 @@ class SnapshotBox(Gtk.Box):
|
||||
|
||||
except Exception as e:
|
||||
self.toast_overlay.add_toast(ErrorToast(_("Could not write data"), str(e)).toast)
|
||||
|
||||
|
||||
def on_rename(self, widget):
|
||||
if not self.valid_checker():
|
||||
return
|
||||
|
||||
|
||||
self.update_json('name', self.rename_entry.get_text().strip())
|
||||
self.load_from_json()
|
||||
self.rename_menu.popdown()
|
||||
|
||||
|
||||
def valid_checker(self, *args):
|
||||
text = self.rename_entry.get_text().strip()
|
||||
valid = not ("/" in text or "\0" in text) and len(text) > 0
|
||||
@@ -78,10 +78,13 @@ class SnapshotBox(Gtk.Box):
|
||||
self.rename_entry.add_css_class("error")
|
||||
|
||||
return valid
|
||||
|
||||
|
||||
def on_trash(self, button):
|
||||
error = [None]
|
||||
path = f"{self.snapshots_path}{self.folder}"
|
||||
if self.snapshot_page.is_trash_dialog_open:
|
||||
return
|
||||
|
||||
def thread(*args):
|
||||
try:
|
||||
subprocess.run(['gio', 'trash', path], capture_output=True, text=True, check=True)
|
||||
@@ -89,21 +92,23 @@ class SnapshotBox(Gtk.Box):
|
||||
error[0] = cpe.stderr
|
||||
except Exception as e:
|
||||
error[0] = str(e)
|
||||
|
||||
|
||||
def callback(*args):
|
||||
if not error[0] is None:
|
||||
self.toast_overlay.add_toast(ErrorToast(_("Could not trash snapshot"), error[0]).toast)
|
||||
return
|
||||
|
||||
|
||||
self.parent_page.on_trash()
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Trashed snapshot")))
|
||||
|
||||
|
||||
def on_response(_, response):
|
||||
self.snapshot_page.is_trash_dialog_open = False
|
||||
if response != "continue":
|
||||
return
|
||||
|
||||
|
||||
Gio.Task.new(None, None, callback).run_in_thread(thread)
|
||||
|
||||
|
||||
self.snapshot_page.is_trash_dialog_open = True
|
||||
dialog = Adw.AlertDialog(heading=_("Trash Snapshot?"), body=_("This snapshot will be sent to the trash"))
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
dialog.add_response("continue", _("Trash"))
|
||||
@@ -128,7 +133,7 @@ class SnapshotBox(Gtk.Box):
|
||||
return False # Stop the timeout
|
||||
else:
|
||||
return True # Continue the timeout
|
||||
|
||||
|
||||
def on_apply(self, button):
|
||||
def on_response(dialog, response):
|
||||
if response != "continue":
|
||||
@@ -141,7 +146,7 @@ class SnapshotBox(Gtk.Box):
|
||||
self.snapshot_page.workers.append(self.worker)
|
||||
self.worker.extract()
|
||||
GLib.timeout_add(200, self.get_fraction)
|
||||
|
||||
|
||||
has_data = os.path.exists(self.worker.new_path)
|
||||
dialog = Adw.AlertDialog(
|
||||
heading=_("Apply Snapshot?"),
|
||||
@@ -154,7 +159,7 @@ class SnapshotBox(Gtk.Box):
|
||||
|
||||
def __init__(self, parent_page, folder, snapshots_path, toast_overlay, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
self.snapshot_page = parent_page.parent_page
|
||||
self.toast_overlay = toast_overlay
|
||||
self.app_id = snapshots_path.split('/')[-2].strip()
|
||||
@@ -163,11 +168,11 @@ class SnapshotBox(Gtk.Box):
|
||||
new_path=f"{HostInfo.home}/.var/app/{self.app_id}/",
|
||||
toast_overlay=self.toast_overlay,
|
||||
)
|
||||
|
||||
|
||||
split_folder = folder.split('_')
|
||||
if len(split_folder) < 2:
|
||||
return
|
||||
|
||||
|
||||
self.parent_page = parent_page
|
||||
self.folder = folder
|
||||
self.snapshots_path = snapshots_path
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from gi.repository import Adw, Gtk, GLib, Gio
|
||||
from gi.repository import Adw, Gtk, GLib, Gio, Gdk
|
||||
from .host_info import HostInfo
|
||||
from .error_toast import ErrorToast
|
||||
from .app_row import AppRow
|
||||
@@ -12,7 +12,7 @@ import os, subprocess
|
||||
|
||||
class LeftoverSnapshotRow(Adw.ActionRow):
|
||||
__gtype_name__ = "LeftoverSnapshotRow"
|
||||
|
||||
|
||||
def idle_stuff(self):
|
||||
self.set_title(self.name)
|
||||
icon = Gtk.Image.new_from_icon_name("application-x-executable-symbolic")
|
||||
@@ -22,7 +22,7 @@ class LeftoverSnapshotRow(Adw.ActionRow):
|
||||
|
||||
def gesture_handler(self, *args):
|
||||
self.on_long_press(self)
|
||||
|
||||
|
||||
def __init__(self, folder, on_long_press, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@@ -44,7 +44,7 @@ class LeftoverSnapshotRow(Adw.ActionRow):
|
||||
# Connections
|
||||
self.rclick_gesture.connect("released", self.gesture_handler)
|
||||
self.long_press_gesture.connect("pressed", self.gesture_handler)
|
||||
|
||||
|
||||
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/snapshot_page/snapshot_page.ui")
|
||||
class SnapshotPage(Adw.BreakpointBin):
|
||||
__gtype_name__ = "SnapshotPage"
|
||||
@@ -87,6 +87,7 @@ class SnapshotPage(Adw.BreakpointBin):
|
||||
# This must be set to the created object from within the class's __init__ method
|
||||
instance = None
|
||||
page_name = "snapshots"
|
||||
is_trash_dialog_open = False
|
||||
|
||||
def sort_snapshots(self, *args):
|
||||
self.active_snapshot_paks.clear()
|
||||
@@ -126,11 +127,11 @@ class SnapshotPage(Adw.BreakpointBin):
|
||||
subprocess.run(['gio', 'trash', f'{HostInfo.snapshots_path}{folder}'])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def long_press_handler(self, row):
|
||||
self.select_button.set_active(True)
|
||||
row.check_button.set_active(not row.check_button.get_active())
|
||||
|
||||
|
||||
def generate_active_list(self):
|
||||
for pak in self.active_snapshot_paks:
|
||||
row = AppRow(pak, self.long_press_handler)
|
||||
@@ -359,7 +360,7 @@ class SnapshotPage(Adw.BreakpointBin):
|
||||
if len(packages) == 0:
|
||||
self.toast_overlay.add_toast(Adw.Toast(title=_("No apps in your selection can be snapshotted")))
|
||||
return
|
||||
|
||||
|
||||
self.new_snapshot_dialog = NewSnapshotDialog(self, self.snapshotting_status, self.refresh, packages)
|
||||
self.new_snapshot_dialog.present(HostInfo.main_window)
|
||||
|
||||
@@ -378,7 +379,7 @@ class SnapshotPage(Adw.BreakpointBin):
|
||||
id_to_tar[app_id] = tarlist
|
||||
if len(tarlist) < 1:
|
||||
id_to_tar.pop(app_id, None)
|
||||
|
||||
|
||||
return id_to_tar
|
||||
|
||||
def get_total_fraction(self):
|
||||
@@ -422,7 +423,7 @@ class SnapshotPage(Adw.BreakpointBin):
|
||||
biggest_tar = tar
|
||||
|
||||
id_to_tar[app_id] = tar
|
||||
|
||||
|
||||
for app_id, tar in id_to_tar.items():
|
||||
worker = TarWorker(
|
||||
existing_path=f"{HostInfo.snapshots_path}{app_id}/{tar}",
|
||||
@@ -431,7 +432,7 @@ class SnapshotPage(Adw.BreakpointBin):
|
||||
)
|
||||
self.workers.append(worker)
|
||||
worker.extract()
|
||||
|
||||
|
||||
if len(self.workers) > 0:
|
||||
self.snapshotting_status.title_label.set_label(_("Applying Snapshots"))
|
||||
self.snapshotting_status.progress_bar.set_fraction(0.0)
|
||||
@@ -456,7 +457,14 @@ class SnapshotPage(Adw.BreakpointBin):
|
||||
AttemptInstallDialog(package_names, lambda is_valid: self.select_button.set_active(not is_valid))
|
||||
|
||||
def select_trash_handler(self):
|
||||
if (
|
||||
self.is_trash_dialog_open
|
||||
or len(self.selected_active_rows) + len(self.selected_leftover_rows) < 1
|
||||
):
|
||||
return
|
||||
|
||||
def on_response(dialog, response):
|
||||
self.is_trash_dialog_open = False
|
||||
to_trash = []
|
||||
if response != "continue":
|
||||
return
|
||||
@@ -474,7 +482,8 @@ class SnapshotPage(Adw.BreakpointBin):
|
||||
self.toast_overlay.add_toast(Adw.Toast(title=_("Trashed snapshots")))
|
||||
except subprocess.CalledProcessError as cpe:
|
||||
self.toast_overlay.add_toast(ErrorToast(_("Could not trash snapshots"), cpe.stderr).toast)
|
||||
|
||||
|
||||
self.is_trash_dialog_open = True
|
||||
dialog = Adw.AlertDialog(heading=_("Trash Snapshots?"), body=_("These apps' snapshots will be sent to the trash"))
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
dialog.add_response("continue", _("Trash"))
|
||||
@@ -494,7 +503,11 @@ class SnapshotPage(Adw.BreakpointBin):
|
||||
self.install_handler()
|
||||
case self.trash_snapshots:
|
||||
self.select_trash_handler()
|
||||
|
||||
|
||||
def key_handler(self, controller, keyval, keycode, state):
|
||||
if keyval == Gdk.KEY_Escape:
|
||||
self.select_button.set_active(False)
|
||||
|
||||
def __init__(self, main_window, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@@ -509,8 +522,19 @@ class SnapshotPage(Adw.BreakpointBin):
|
||||
self.list_page = SnapshotsListPage(self)
|
||||
self.snapshotting_status = LoadingStatus("Initial Title", _("This could take a while"), True, self.on_cancel)
|
||||
self.new_snapshot_dialog = None
|
||||
event_controller = Gtk.EventControllerKey()
|
||||
|
||||
# Apply
|
||||
self.add_controller(event_controller)
|
||||
self.search_bar.set_key_capture_widget(HostInfo.main_window)
|
||||
self.loading_view.set_content(LoadingStatus(_("Loading Snapshots"), _("This should only take a moment")))
|
||||
self.snapshotting_view.set_content(self.snapshotting_status)
|
||||
self.split_view.set_content(self.list_page)
|
||||
self.active_listbox.set_sort_func(self.sort_func)
|
||||
self.leftover_listbox.set_sort_func(self.sort_func)
|
||||
|
||||
# Connections
|
||||
event_controller.connect("key-pressed", self.key_handler)
|
||||
self.active_listbox.connect("row-activated", self.active_select_handler)
|
||||
self.leftover_listbox.connect("row-activated", self.leftover_select_handler)
|
||||
self.open_button.connect("clicked", self.open_snapshots_folder)
|
||||
@@ -522,11 +546,3 @@ class SnapshotPage(Adw.BreakpointBin):
|
||||
self.select_all_button.connect("clicked", self.select_all_handler)
|
||||
self.copy_button.connect("clicked", self.select_copy_handler)
|
||||
self.more_menu.connect("row-activated", self.more_menu_handler)
|
||||
|
||||
# Apply
|
||||
self.search_bar.set_key_capture_widget(HostInfo.main_window)
|
||||
self.loading_view.set_content(LoadingStatus(_("Loading Snapshots"), _("This should only take a moment")))
|
||||
self.snapshotting_view.set_content(self.snapshotting_status)
|
||||
self.split_view.set_content(self.list_page)
|
||||
self.active_listbox.set_sort_func(self.sort_func)
|
||||
self.leftover_listbox.set_sort_func(self.sort_func)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from gi.repository import Adw, Gtk, GLib, Gio, Pango
|
||||
from gi.repository import Adw, Gtk, GLib, Gio, Gdk
|
||||
from .error_toast import ErrorToast
|
||||
from .data_box import DataBox
|
||||
from .data_subpage import DataSubpage
|
||||
@@ -12,7 +12,7 @@ import os, subprocess
|
||||
class UserDataPage(Adw.BreakpointBin):
|
||||
__gtype_name__ = 'UserDataPage'
|
||||
gtc = Gtk.Template.Child
|
||||
|
||||
|
||||
bpt = gtc()
|
||||
status_stack = gtc()
|
||||
loading_view = gtc()
|
||||
@@ -52,6 +52,7 @@ class UserDataPage(Adw.BreakpointBin):
|
||||
page_name = "user-data"
|
||||
data_path = f"{HostInfo.home}/.var/app"
|
||||
bpt_is_applied = False
|
||||
is_trash_dialog_open = False
|
||||
|
||||
def sort_data(self, *args):
|
||||
self.data_flatpaks.clear()
|
||||
@@ -156,6 +157,7 @@ class UserDataPage(Adw.BreakpointBin):
|
||||
|
||||
def trash_handler(self, *args):
|
||||
error = [None]
|
||||
child = self.stack.get_visible_child()
|
||||
|
||||
def thread(path):
|
||||
cmd = ['gio', 'trash'] + path
|
||||
@@ -175,10 +177,10 @@ class UserDataPage(Adw.BreakpointBin):
|
||||
self.toast_overlay.add_toast(Adw.Toast(title=_("Trashed data")))
|
||||
|
||||
def on_response(dialog, response):
|
||||
self.is_trash_dialog_open = False
|
||||
if response != "continue":
|
||||
return
|
||||
|
||||
child = self.stack.get_visible_child()
|
||||
to_trash = []
|
||||
for box in child.selected_boxes:
|
||||
to_trash.append(box.data_path)
|
||||
@@ -191,6 +193,10 @@ class UserDataPage(Adw.BreakpointBin):
|
||||
child.set_visible_child(child.loading_data)
|
||||
Gio.Task.new(None, None, callback).run_in_thread(lambda *_: thread(to_trash))
|
||||
|
||||
if len(child.selected_boxes) < 1 or self.is_trash_dialog_open:
|
||||
return
|
||||
|
||||
self.is_trash_dialog_open = True
|
||||
dialog = Adw.AlertDialog(heading=_("Trash Data?"), body=_("Data will be sent to the trash"))
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
dialog.add_response("continue", _("Continue"))
|
||||
@@ -230,6 +236,10 @@ class UserDataPage(Adw.BreakpointBin):
|
||||
self.install_handler()
|
||||
case self.more_trash:
|
||||
self.trash_handler()
|
||||
|
||||
def key_handler(self, controller, keyval, keycode, state):
|
||||
if keyval == Gdk.KEY_Escape:
|
||||
self.select_button.set_active(False)
|
||||
|
||||
def __init__(self, main_window, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
@@ -243,17 +253,19 @@ class UserDataPage(Adw.BreakpointBin):
|
||||
self.leftover_data = []
|
||||
self.total_items = 0
|
||||
self.settings = Gio.Settings.new("io.github.flattool.Warehouse.data_page")
|
||||
|
||||
self.sort_modes_to_buttons = {
|
||||
"name": self.sort_name,
|
||||
"id": self.sort_id,
|
||||
"size": self.sort_size,
|
||||
}
|
||||
self.buttons_to_sort_modes = {}
|
||||
event_controller = Gtk.EventControllerKey()
|
||||
|
||||
# Apply
|
||||
self.add_controller(event_controller)
|
||||
for key, button in self.sort_modes_to_buttons.items():
|
||||
self.buttons_to_sort_modes[button] = key
|
||||
|
||||
# Apply
|
||||
self.stack.add_titled_with_icon(
|
||||
child=self.adp,
|
||||
name="active",
|
||||
@@ -268,6 +280,7 @@ class UserDataPage(Adw.BreakpointBin):
|
||||
)
|
||||
|
||||
# Connections
|
||||
event_controller.connect("key-pressed", self.key_handler)
|
||||
self.open_button.connect("clicked", self.open_data_folder)
|
||||
self.stack.connect("notify::visible-child", self.view_change_handler)
|
||||
self.select_button.connect("toggled", self.select_toggle_handler)
|
||||
|
||||
Reference in New Issue
Block a user