Convert more spaces to tabs for indentation

This commit is contained in:
Heliguy
2024-10-27 23:25:26 -04:00
parent 860cefa4f4
commit cde215524d
21 changed files with 1603 additions and 1603 deletions

View File

@@ -2,59 +2,59 @@ using Gtk 4.0;
using Adw 1;
template $ChangeVersionPage : Adw.NavigationPage {
title: _("Change Versions");
Adw.ToolbarView {
[top]
Adw.HeaderBar {
}
Adw.ToastOverlay toast_overlay {
ScrolledWindow scrolled_window {}
}
[bottom]
ActionBar action_bar {
revealed: false;
[center]
Button apply_button {
sensitive: bind action_bar.revealed;
halign: center;
margin-top: 3;
margin-bottom: 3;
Adw.ButtonContent {
label: _("Change Version");
icon-name: "double-ended-arrows-vertical-symbolic";
}
styles ["suggested-action", "pill"]
}
}
}
title: _("Change Versions");
Adw.ToolbarView {
[top]
Adw.HeaderBar {
}
Adw.ToastOverlay toast_overlay {
ScrolledWindow scrolled_window {}
}
[bottom]
ActionBar action_bar {
revealed: false;
[center]
Button apply_button {
sensitive: bind action_bar.revealed;
halign: center;
margin-top: 3;
margin-bottom: 3;
Adw.ButtonContent {
label: _("Change Version");
icon-name: "double-ended-arrows-vertical-symbolic";
}
styles ["suggested-action", "pill"]
}
}
}
}
Adw.Clamp versions_clamp {
Box {
margin-start: 12;
margin-end: 12;
margin-top: 12;
margin-bottom: 12;
spacing: 12;
orientation: vertical;
halign: fill;
hexpand: true;
Box {
margin-start: 12;
margin-end: 12;
margin-top: 12;
margin-bottom: 12;
spacing: 12;
orientation: vertical;
halign: fill;
hexpand: true;
CheckButton root_group_check_button {
visible: false;
active: true;
}
CheckButton root_group_check_button {
visible: false;
active: true;
}
Adw.PreferencesGroup mask_group {
Adw.SwitchRow mask_row {
title: _("Disable Updates");
active: true;
}
}
Adw.PreferencesGroup mask_group {
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.");
}
}
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.");
}
}
}

View File

@@ -2,42 +2,42 @@ using Gtk 4.0;
using Adw 1;
template $AppRow : Adw.ActionRow {
activatable: true;
[prefix]
Image image {
icon-size: large;
icon-name: "application-x-executable-symbolic";
}
[suffix]
Image eol_package_package_status_icon {
icon-name: "error-symbolic";
tooltip-text: _("This package is End Of Life, and will not receive any security updates");
visible: false;
styles["error"]
}
[suffix]
Image eol_runtime_status_icon {
icon-name: "error-symbolic";
tooltip-text: _("This app's runtime is End Of Life, and will not receive any security updates");
visible: false;
styles["error"]
}
[suffix]
Image pinned_status_icon {
icon-name: "pin-symbolic";
tooltip-text: _("This runtime will never be automatically removed");
visible: false;
}
[suffix]
Image masked_status_icon {
icon-name: "software-update-urgent-symbolic";
tooltip-text: _("Updates are disabled for this package");
visible: false;
}
[suffix]
CheckButton check_button {
margin-start: 6;
styles["selection-mode"]
visible: false;
}
activatable: true;
[prefix]
Image image {
icon-size: large;
icon-name: "application-x-executable-symbolic";
}
[suffix]
Image eol_package_package_status_icon {
icon-name: "error-symbolic";
tooltip-text: _("This package is End Of Life, and will not receive any security updates");
visible: false;
styles["error"]
}
[suffix]
Image eol_runtime_status_icon {
icon-name: "error-symbolic";
tooltip-text: _("This app's runtime is End Of Life, and will not receive any security updates");
visible: false;
styles["error"]
}
[suffix]
Image pinned_status_icon {
icon-name: "pin-symbolic";
tooltip-text: _("This runtime will never be automatically removed");
visible: false;
}
[suffix]
Image masked_status_icon {
icon-name: "software-update-urgent-symbolic";
tooltip-text: _("Updates are disabled for this package");
visible: false;
}
[suffix]
CheckButton check_button {
margin-start: 6;
styles["selection-mode"]
visible: false;
}
}

View File

@@ -2,7 +2,7 @@ using Gtk 4.0;
using Adw 1;
template $AttemptInstallDialog : Adw.AlertDialog {
heading: _("Attempt an Install?");
heading: _("Attempt an Install?");
body: _("Warehouse will try to install the matching packages.");
responses [
cancel: _("Cancel"),

View File

@@ -2,56 +2,56 @@ using Gtk 4.0;
using Adw 1;
template $LoadingStatus : ScrolledWindow {
Box {
orientation: vertical;
valign: center;
halign: fill;
spacing: 12;
margin-start: 12;
margin-end: 12;
margin-top: 12;
margin-bottom: 12;
Adw.Spinner {
height-request: 30;
margin-bottom: 12;
opacity: 0.5;
}
Label title_label {
label: "No Title Set";
wrap: true;
justify: center;
styles ["title-1"]
}
Label description_label {
label: "No Description Set";
wrap: true;
justify: center;
styles ["description", "body"]
}
Adw.Clamp progress_clamp {
margin-start: 24;
margin-end: 24;
margin-top: 12;
margin-bottom: 12;
maximum-size: 400;
Box {
halign: fill;
hexpand: true;
spacing: 12;
ProgressBar progress_bar {
halign: fill;
hexpand: true;
valign: center;
}
Label progress_label {
valign: center;
}
}
}
Button button {
label: _("Cancel");
styles ["pill"]
halign: center;
}
}
Box {
orientation: vertical;
valign: center;
halign: fill;
spacing: 12;
margin-start: 12;
margin-end: 12;
margin-top: 12;
margin-bottom: 12;
Adw.Spinner {
height-request: 30;
margin-bottom: 12;
opacity: 0.5;
}
Label title_label {
label: "No Title Set";
wrap: true;
justify: center;
styles ["title-1"]
}
Label description_label {
label: "No Description Set";
wrap: true;
justify: center;
styles ["description", "body"]
}
Adw.Clamp progress_clamp {
margin-start: 24;
margin-end: 24;
margin-top: 12;
margin-bottom: 12;
maximum-size: 400;
Box {
halign: fill;
hexpand: true;
spacing: 12;
ProgressBar progress_bar {
halign: fill;
hexpand: true;
valign: center;
}
Label progress_label {
valign: center;
}
}
}
Button button {
label: _("Cancel");
styles ["pill"]
halign: center;
}
}
}

View File

@@ -2,23 +2,23 @@ from gi.repository import Gtk, GLib
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/gtk/loading_status.ui")
class LoadingStatus(Gtk.ScrolledWindow):
__gtype_name__ = 'LoadingStatus'
gtc = Gtk.Template.Child
__gtype_name__ = 'LoadingStatus'
gtc = Gtk.Template.Child
title_label = gtc()
description_label = gtc()
progress_clamp = gtc()
progress_bar = gtc()
progress_label = gtc()
button = gtc()
title_label = gtc()
description_label = gtc()
progress_clamp = gtc()
progress_bar = gtc()
progress_label = gtc()
button = gtc()
def __init__(self, title, description, show_progress=False, on_cancel=None, **kwargs):
super().__init__(**kwargs)
def __init__(self, title, description, show_progress=False, on_cancel=None, **kwargs):
super().__init__(**kwargs)
self.title_label.set_label(GLib.markup_escape_text(title))
self.description_label.set_label(GLib.markup_escape_text(description))
self.progress_clamp.set_visible(show_progress)
if on_cancel is None:
self.button.set_visible(False)
else:
self.button.connect("clicked", lambda *_: on_cancel())
self.title_label.set_label(GLib.markup_escape_text(title))
self.description_label.set_label(GLib.markup_escape_text(description))
self.progress_clamp.set_visible(show_progress)
if on_cancel is None:
self.button.set_visible(False)
else:
self.button.connect("clicked", lambda *_: on_cancel())

View File

@@ -2,18 +2,18 @@ from gi.repository import Gtk
from .host_info import HostInfo
class SidebarButton(Gtk.Button):
__gtype_name__ = "SidebarButton"
__gtype_name__ = "SidebarButton"
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Extra Object Creation
main_split = HostInfo.main_window.main_split
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Extra Object Creation
main_split = HostInfo.main_window.main_split
# Connections
main_split.connect("notify::collapsed", lambda *_: self.set_visible(main_split.get_collapsed()))
self.connect("clicked", lambda *_: main_split.set_show_sidebar(True))
# Connections
main_split.connect("notify::collapsed", lambda *_: self.set_visible(main_split.get_collapsed()))
self.connect("clicked", lambda *_: main_split.set_show_sidebar(True))
# Apply
self.set_icon_name("dock-left-symbolic")
self.set_tooltip_text(_("Show Sidebar"))
# Apply
self.set_icon_name("dock-left-symbolic")
self.set_tooltip_text(_("Show Sidebar"))

View File

@@ -2,40 +2,40 @@ using Gtk 4.0;
using Adw 1;
template $FileInstallDialog : Adw.Dialog {
follows-content-size: true;
Adw.ToolbarView {
[top]
Adw.HeaderBar {
show-start-title-buttons: false;
show-end-title-buttons: false;
[start]
Button cancel_button {
label: _("Cancel");
}
[end]
Button apply_button {
styles ["suggested-action"]
label: _("Install");
}
}
ScrolledWindow content_page {
propagate-natural-height: true;
propagate-natural-width: true;
Adw.Clamp {
margin-start: 12;
margin-end: 12;
margin-bottom: 12;
margin-top: 6;
Box {
orientation: vertical;
spacing: 12;
Adw.PreferencesGroup packages_group {
title: _("Review Selection");
}
$InstallationChooser installation_chooser {
}
}
}
}
}
follows-content-size: true;
Adw.ToolbarView {
[top]
Adw.HeaderBar {
show-start-title-buttons: false;
show-end-title-buttons: false;
[start]
Button cancel_button {
label: _("Cancel");
}
[end]
Button apply_button {
styles ["suggested-action"]
label: _("Install");
}
}
ScrolledWindow content_page {
propagate-natural-height: true;
propagate-natural-width: true;
Adw.Clamp {
margin-start: 12;
margin-end: 12;
margin-bottom: 12;
margin-top: 6;
Box {
orientation: vertical;
spacing: 12;
Adw.PreferencesGroup packages_group {
title: _("Review Selection");
}
$InstallationChooser installation_chooser {
}
}
}
}
}
}

View File

@@ -2,106 +2,106 @@ using Gtk 4.0;
using Adw 1;
template $InstallPage : Adw.BreakpointBin {
width-request: 1;
width-request: 1;
height-request: 1;
Adw.Breakpoint break_point {
Adw.Breakpoint break_point {
condition ("max-width: 600")
setters {
multi_view.layout: skinny;
multi_view.layout: skinny;
}
}
Adw.NavigationPage {
title: _("Install Packages");
Adw.ToastOverlay toast_overlay {
Stack status_stack {
Adw.ToolbarView loading_view {
[top]
Adw.HeaderBar {
[start]
$SidebarButton {}
}
}
Adw.ToolbarView installing_view {
[top]
Adw.HeaderBar {
[start]
$SidebarButton {}
}
}
Adw.MultiLayoutView multi_view {
Adw.Layout wide {
Adw.NavigationSplitView split_view {
sidebar-width-fraction: 0.5;
max-sidebar-width: 999999999;
sidebar:
Adw.NavigationPage {
title: _("Select Source");
Adw.LayoutSlot {
id: "select_page";
}
}
;
content:
Adw.NavigationPage {
title: _("Pending Packages");
Adw.LayoutSlot {
id: "pending_page";
}
}
;
}
}
Adw.Layout skinny {
Adw.BottomSheet bottom_sheet {
[content]
Box {
margin-bottom: bind bottom_sheet.bottom-bar-height;
Adw.LayoutSlot {
id: "select_page";
}
}
[sheet]
Adw.LayoutSlot {
id: "pending_page";
}
}
}
[select_page]
$SelectPage select_page {}
[pending_page]
$PendingPage pending_page {}
}
}
}
}
Adw.NavigationPage {
title: _("Install Packages");
Adw.ToastOverlay toast_overlay {
Stack status_stack {
Adw.ToolbarView loading_view {
[top]
Adw.HeaderBar {
[start]
$SidebarButton {}
}
}
Adw.ToolbarView installing_view {
[top]
Adw.HeaderBar {
[start]
$SidebarButton {}
}
}
Adw.MultiLayoutView multi_view {
Adw.Layout wide {
Adw.NavigationSplitView split_view {
sidebar-width-fraction: 0.5;
max-sidebar-width: 999999999;
sidebar:
Adw.NavigationPage {
title: _("Select Source");
Adw.LayoutSlot {
id: "select_page";
}
}
;
content:
Adw.NavigationPage {
title: _("Pending Packages");
Adw.LayoutSlot {
id: "pending_page";
}
}
;
}
}
Adw.Layout skinny {
Adw.BottomSheet bottom_sheet {
[content]
Box {
margin-bottom: bind bottom_sheet.bottom-bar-height;
Adw.LayoutSlot {
id: "select_page";
}
}
[sheet]
Adw.LayoutSlot {
id: "pending_page";
}
}
}
[select_page]
$SelectPage select_page {}
[pending_page]
$PendingPage pending_page {}
}
}
}
}
}
Revealer bottom_child {
reveal-child: false;
Box {
margin-top: 12;
margin-bottom: 14;
spacing: 12;
halign: center;
valign: center;
styles ["flat"]
[start]
Image {
icon-name: "flatpak-symbolic";
icon-size: normal;
}
[center]
Label bottom_label {
label: _("Pending Packages");
styles ["heading"]
}
[end]
Image {
icon-name: "right-large-symbolic";
icon-size: normal;
}
}
reveal-child: false;
Box {
margin-top: 12;
margin-bottom: 14;
spacing: 12;
halign: center;
valign: center;
styles ["flat"]
[start]
Image {
icon-name: "flatpak-symbolic";
icon-size: normal;
}
[center]
Label bottom_label {
label: _("Pending Packages");
styles ["heading"]
}
[end]
Image {
icon-name: "right-large-symbolic";
icon-size: normal;
}
}
}

View File

@@ -9,89 +9,89 @@ from .error_toast import ErrorToast
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/install_page/install_page.ui")
class InstallPage(Adw.BreakpointBin):
__gtype_name__ = "InstallPage"
gtc = Gtk.Template.Child
break_point = gtc()
split_view = gtc()
multi_view = gtc()
select_page = gtc()
pending_page = gtc()
status_stack = gtc()
loading_view = gtc()
installing_view = gtc()
bottom_sheet = gtc()
bottom_child = gtc()
bottom_label = 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 = "install"
current_installation = ""
current_remote = None
did_error = False
def start_loading(self):
self.total_added_packages = 0
self.bottom_bar_visual_handler(False)
self.status_stack.set_visible_child(self.loading_view)
self.select_page.start_loading()
self.pending_page.reset()
def end_loading(self):
self.select_page.end_loading()
self.status_stack.set_visible_child(self.multi_view)
def install_callback(self):
HostInfo.main_window.refresh_handler()
if not self.did_error:
HostInfo.main_window.toast_overlay.add_toast(Adw.Toast(title=_("Installed Packages")))
def install_error_callback(self, user_facing_label, error_message):
self.did_error = True
GLib.idle_add(lambda *_: HostInfo.main_window.toast_overlay.add_toast(ErrorToast(user_facing_label, error_message).toast))
def install_packages(self, package_requests):
self.did_error = False
if PackageInstallWorker.install(package_requests, self.installing_status, self.install_callback, self.install_error_callback):
self.status_stack.set_visible_child(self.installing_view)
def bottom_bar_visual_handler(self, is_added):
total = self.total_added_packages
if total == 0:
self.bottom_child.set_reveal_child(False)
self.bottom_sheet.set_bottom_bar(None)
elif total == 1:
self.bottom_label.set_label(_("{} Pending Package").format(1))
if is_added:
self.bottom_sheet.set_bottom_bar(self.bottom_child)
self.bottom_child.set_reveal_child(True)
else:
self.bottom_label.set_label(_("{} Pending Packages").format(total))
def package_added(self):
self.total_added_packages += 1
self.bottom_bar_visual_handler(True)
def package_removed(self):
self.total_added_packages -= 1
self.bottom_bar_visual_handler(False)
def __init__(self, main_window, **kwargs):
super().__init__(**kwargs)
self.instance = self
# Extra Object Creation
self.installing_status = LoadingStatus(_("Installing Packages"), _("This could take a while"), True, PackageInstallWorker.cancel)
self.total_added_packages = 0
# Connections
# Apply
self.select_page.results_page.pending_page = self.pending_page
self.select_page.results_page.install_page = self
self.loading_view.set_content(LoadingStatus(_("Loading Installation Options"), _("This should only take a moment")))
self.installing_view.set_content(self.installing_status)
__gtype_name__ = "InstallPage"
gtc = Gtk.Template.Child
break_point = gtc()
split_view = gtc()
multi_view = gtc()
select_page = gtc()
pending_page = gtc()
status_stack = gtc()
loading_view = gtc()
installing_view = gtc()
bottom_sheet = gtc()
bottom_child = gtc()
bottom_label = 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 = "install"
current_installation = ""
current_remote = None
did_error = False
def start_loading(self):
self.total_added_packages = 0
self.bottom_bar_visual_handler(False)
self.status_stack.set_visible_child(self.loading_view)
self.select_page.start_loading()
self.pending_page.reset()
def end_loading(self):
self.select_page.end_loading()
self.status_stack.set_visible_child(self.multi_view)
def install_callback(self):
HostInfo.main_window.refresh_handler()
if not self.did_error:
HostInfo.main_window.toast_overlay.add_toast(Adw.Toast(title=_("Installed Packages")))
def install_error_callback(self, user_facing_label, error_message):
self.did_error = True
GLib.idle_add(lambda *_: HostInfo.main_window.toast_overlay.add_toast(ErrorToast(user_facing_label, error_message).toast))
def install_packages(self, package_requests):
self.did_error = False
if PackageInstallWorker.install(package_requests, self.installing_status, self.install_callback, self.install_error_callback):
self.status_stack.set_visible_child(self.installing_view)
def bottom_bar_visual_handler(self, is_added):
total = self.total_added_packages
if total == 0:
self.bottom_child.set_reveal_child(False)
self.bottom_sheet.set_bottom_bar(None)
elif total == 1:
self.bottom_label.set_label(_("{} Pending Package").format(1))
if is_added:
self.bottom_sheet.set_bottom_bar(self.bottom_child)
self.bottom_child.set_reveal_child(True)
else:
self.bottom_label.set_label(_("{} Pending Packages").format(total))
def package_added(self):
self.total_added_packages += 1
self.bottom_bar_visual_handler(True)
def package_removed(self):
self.total_added_packages -= 1
self.bottom_bar_visual_handler(False)
def __init__(self, main_window, **kwargs):
super().__init__(**kwargs)
self.instance = self
# Extra Object Creation
self.installing_status = LoadingStatus(_("Installing Packages"), _("This could take a while"), True, PackageInstallWorker.cancel)
self.total_added_packages = 0
# Connections
# Apply
self.select_page.results_page.pending_page = self.pending_page
self.select_page.results_page.install_page = self
self.loading_view.set_content(LoadingStatus(_("Loading Installation Options"), _("This should only take a moment")))
self.installing_view.set_content(self.installing_status)

View File

@@ -2,40 +2,40 @@ using Gtk 4.0;
using Adw 1;
template $PendingPage : Adw.NavigationPage {
title: _("Pending Packages");
Stack stack {
Adw.ToolbarView none_pending {
[top]
Adw.HeaderBar {
}
Adw.StatusPage {
icon-name: "flatpak-symbolic";
title: _("Add Packages");
description: _("Packages queued to install will show up here");
}
}
Adw.ToolbarView main_view {
[top]
Adw.HeaderBar {
}
Adw.PreferencesPage preferences_page {
}
[bottom]
ActionBar pending_action_bar {
revealed: true;
[center]
Button install_button {
margin-top: 3;
margin-bottom: 3;
sensitive: bind pending_action_bar.revealed;
styles ["pill", "suggested-action"]
Adw.ButtonContent {
can-shrink: true;
icon-name: "arrow-pointing-at-line-down-symbolic";
label: _("Install");
}
}
}
}
}
title: _("Pending Packages");
Stack stack {
Adw.ToolbarView none_pending {
[top]
Adw.HeaderBar {
}
Adw.StatusPage {
icon-name: "flatpak-symbolic";
title: _("Add Packages");
description: _("Packages queued to install will show up here");
}
}
Adw.ToolbarView main_view {
[top]
Adw.HeaderBar {
}
Adw.PreferencesPage preferences_page {
}
[bottom]
ActionBar pending_action_bar {
revealed: true;
[center]
Button install_button {
margin-top: 3;
margin-bottom: 3;
sensitive: bind pending_action_bar.revealed;
styles ["pill", "suggested-action"]
Adw.ButtonContent {
can-shrink: true;
icon-name: "arrow-pointing-at-line-down-symbolic";
label: _("Install");
}
}
}
}
}
}

View File

@@ -3,126 +3,126 @@ from .host_info import HostInfo
from .result_row import ResultRow
class AddedGroup(Adw.PreferencesGroup):
__gtype_name__ = "AddedGroup"
def add_row(self, row):
self.rows.append(row)
self.add(row)
def rem_row(self, row):
if row in self.rows:
self.rows.remove(row)
self.remove(row)
def remove_all(self, *args):
while len(self.rows) > 0 and (row := self.rows[0]):
row.activate()
def __init__(self, remote, installation, **kwargs):
super().__init__(**kwargs)
self.remote = remote
self.installation = installation
self.rows = []
self.set_title(f"{remote.title}")
self.set_description(_("Installation: {}").format(installation))
remove_all = Gtk.Button(
child=Adw.ButtonContent(
icon_name="list-remove-all-symbolic",
label=_("Remove All"),
),
valign = Gtk.Align.CENTER,
)
remove_all.add_css_class("flat")
remove_all.connect("clicked", self.remove_all)
self.set_header_suffix(remove_all)
__gtype_name__ = "AddedGroup"
def add_row(self, row):
self.rows.append(row)
self.add(row)
def rem_row(self, row):
if row in self.rows:
self.rows.remove(row)
self.remove(row)
def remove_all(self, *args):
while len(self.rows) > 0 and (row := self.rows[0]):
row.activate()
def __init__(self, remote, installation, **kwargs):
super().__init__(**kwargs)
self.remote = remote
self.installation = installation
self.rows = []
self.set_title(f"{remote.title}")
self.set_description(_("Installation: {}").format(installation))
remove_all = Gtk.Button(
child=Adw.ButtonContent(
icon_name="list-remove-all-symbolic",
label=_("Remove All"),
),
valign = Gtk.Align.CENTER,
)
remove_all.add_css_class("flat")
remove_all.connect("clicked", self.remove_all)
self.set_header_suffix(remove_all)
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/install_page/pending_page.ui")
class PendingPage(Adw.NavigationPage):
__gtype_name__ = "PendingPage"
gtc = Gtk.Template.Child
stack = gtc()
main_view = gtc()
none_pending = gtc()
preferences_page = gtc()
install_button = gtc()
def add_package_row(self, row):
self.added_packages.append(row.package)
row.set_state(ResultRow.PackageState.SELECTED)
key = f"{row.package.remote}<>{row.package.installation}"
added_row = ResultRow(row.package, ResultRow.PackageState.ADDED, row.origin_list_box)
group = None
try:
group = self.groups[key]
group.add_row(added_row)
except KeyError:
group = AddedGroup(added_row.package.remote, added_row.package.installation)
group.add_row(added_row)
self.groups[key] = group
self.preferences_page.add(group)
added_row.connect("activated", self.remove_package_row, group)
self.stack.set_visible_child(self.main_view)
def remove_package_row(self, row, group):
# row.origin_row.set_state(ResultRow.PackageState.NEW)
for item in row.origin_list_box:
if item.state == ResultRow.PackageState.SELECTED and item.package.is_similar(row.package):
item.set_state(ResultRow.PackageState.NEW)
break
group.rem_row(row)
if row.package in self.added_packages:
self.added_packages.remove(row.package)
if len(group.rows) == 0:
key = f"{row.package.remote}<>{row.package.installation}"
self.groups.pop(key, None)
self.preferences_page.remove(group)
if len(self.added_packages) == 0:
self.stack.set_visible_child(self.none_pending)
install_page = HostInfo.main_window.pages[HostInfo.main_window.install_row]
install_page.package_removed()
def on_install(self, *args):
package_requests = []
for key, group in self.groups.items():
item = {
"remote": group.remote.name,
"installation": group.installation,
"package_names": [],
"extra_flags": [],
}
for row in group.rows:
item['package_names'].append(row.package.app_id)
package_requests.append(item)
install_page = HostInfo.main_window.pages[HostInfo.main_window.install_row]
install_page.install_packages(package_requests)
def reset(self):
for key, group in self.groups.items():
self.preferences_page.remove(group)
self.groups.clear()
self.added_packages.clear()
self.stack.set_visible_child(self.none_pending)
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Extra Object Creation
self.groups = {} # remote<>installation: adw.preference_group
self.added_packages = []
# Connections
self.install_button.connect("clicked", self.on_install)
# Apply
__gtype_name__ = "PendingPage"
gtc = Gtk.Template.Child
stack = gtc()
main_view = gtc()
none_pending = gtc()
preferences_page = gtc()
install_button = gtc()
def add_package_row(self, row):
self.added_packages.append(row.package)
row.set_state(ResultRow.PackageState.SELECTED)
key = f"{row.package.remote}<>{row.package.installation}"
added_row = ResultRow(row.package, ResultRow.PackageState.ADDED, row.origin_list_box)
group = None
try:
group = self.groups[key]
group.add_row(added_row)
except KeyError:
group = AddedGroup(added_row.package.remote, added_row.package.installation)
group.add_row(added_row)
self.groups[key] = group
self.preferences_page.add(group)
added_row.connect("activated", self.remove_package_row, group)
self.stack.set_visible_child(self.main_view)
def remove_package_row(self, row, group):
# row.origin_row.set_state(ResultRow.PackageState.NEW)
for item in row.origin_list_box:
if item.state == ResultRow.PackageState.SELECTED and item.package.is_similar(row.package):
item.set_state(ResultRow.PackageState.NEW)
break
group.rem_row(row)
if row.package in self.added_packages:
self.added_packages.remove(row.package)
if len(group.rows) == 0:
key = f"{row.package.remote}<>{row.package.installation}"
self.groups.pop(key, None)
self.preferences_page.remove(group)
if len(self.added_packages) == 0:
self.stack.set_visible_child(self.none_pending)
install_page = HostInfo.main_window.pages[HostInfo.main_window.install_row]
install_page.package_removed()
def on_install(self, *args):
package_requests = []
for key, group in self.groups.items():
item = {
"remote": group.remote.name,
"installation": group.installation,
"package_names": [],
"extra_flags": [],
}
for row in group.rows:
item['package_names'].append(row.package.app_id)
package_requests.append(item)
install_page = HostInfo.main_window.pages[HostInfo.main_window.install_row]
install_page.install_packages(package_requests)
def reset(self):
for key, group in self.groups.items():
self.preferences_page.remove(group)
self.groups.clear()
self.added_packages.clear()
self.stack.set_visible_child(self.none_pending)
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Extra Object Creation
self.groups = {} # remote<>installation: adw.preference_group
self.added_packages = []
# Connections
self.install_button.connect("clicked", self.on_install)
# Apply

View File

@@ -2,48 +2,48 @@ using Gtk 4.0;
using Adw 1;
template $ResultRow : Adw.ActionRow {
activatable: true;
title: "No title set";
subtitle: "No subtitle set";
tooltip-text: _("Add Package to Queue");
activatable: true;
title: "No title set";
subtitle: "No subtitle set";
tooltip-text: _("Add Package to Queue");
Box {
orientation: vertical;
valign: center;
spacing: 4;
margin-end: 4;
Label version_label {
styles ["subtitle"]
label: "";
justify: right;
halign: end;
hexpand: true;
wrap: true;
}
Label branch_label {
styles ["subtitle"]
label: "";
justify: right;
halign: end;
hexpand: true;
wrap: true;
}
}
[suffix]
Image add_image {
icon-name: "plus-large-symbolic";
}
[suffix]
Image selected_image {
icon-name: "check-plain-symbolic";
}
[suffix]
Image sub_image {
icon-name: "minus-large-symbolic";
}
[suffix]
Image installed_image {
icon-name: "selection-mode-symbolic";
styles ["success"]
}
Box {
orientation: vertical;
valign: center;
spacing: 4;
margin-end: 4;
Label version_label {
styles ["subtitle"]
label: "";
justify: right;
halign: end;
hexpand: true;
wrap: true;
}
Label branch_label {
styles ["subtitle"]
label: "";
justify: right;
halign: end;
hexpand: true;
wrap: true;
}
}
[suffix]
Image add_image {
icon-name: "plus-large-symbolic";
}
[suffix]
Image selected_image {
icon-name: "check-plain-symbolic";
}
[suffix]
Image sub_image {
icon-name: "minus-large-symbolic";
}
[suffix]
Image installed_image {
icon-name: "selection-mode-symbolic";
styles ["success"]
}
}

View File

@@ -3,67 +3,67 @@ from enum import Enum
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/install_page/result_row.ui")
class ResultRow(Adw.ActionRow):
__gtype_name__ = "ResultRow"
gtc = Gtk.Template.Child
__gtype_name__ = "ResultRow"
gtc = Gtk.Template.Child
version_label = gtc()
branch_label = gtc()
add_image = gtc()
sub_image = gtc()
selected_image = gtc()
installed_image = gtc()
version_label = gtc()
branch_label = gtc()
add_image = gtc()
sub_image = gtc()
selected_image = gtc()
installed_image = gtc()
class PackageState(Enum):
NEW = 0
SELECTED = 1
ADDED = 2
INSTALLED = 3
class PackageState(Enum):
NEW = 0
SELECTED = 1
ADDED = 2
INSTALLED = 3
def idle_stuff(self):
self.set_title(GLib.markup_escape_text(self.package.name))
self.set_subtitle(self.package.app_id)
self.version_label.set_label(GLib.markup_escape_text(self.package.version))
self.branch_label.set_label(GLib.markup_escape_text(self.package.branch))
self.version_label.set_visible(len(self.version_label.get_label()) != 0)
self.branch_label.set_visible(len(self.branch_label.get_label()) != 0)
def idle_stuff(self):
self.set_title(GLib.markup_escape_text(self.package.name))
self.set_subtitle(self.package.app_id)
self.version_label.set_label(GLib.markup_escape_text(self.package.version))
self.branch_label.set_label(GLib.markup_escape_text(self.package.branch))
self.version_label.set_visible(len(self.version_label.get_label()) != 0)
self.branch_label.set_visible(len(self.branch_label.get_label()) != 0)
def set_state(self, state):
if state == self.state:
return
def set_state(self, state):
if state == self.state:
return
self.state = state
self.add_image.set_visible(False)
self.sub_image.set_visible(False)
self.selected_image.set_visible(False)
self.installed_image.set_visible(False)
match state:
case self.PackageState.NEW:
self.set_sensitive(True)
self.set_tooltip_text(_("Add Package to Queue"))
self.add_image.set_visible(True)
case self.PackageState.SELECTED:
self.set_sensitive(False)
self.set_tooltip_text(_("Package has been Added to Queue"))
self.selected_image.set_visible(True)
case self.PackageState.ADDED:
self.set_sensitive(True)
self.set_tooltip_text(_("Remove Package from Queue"))
self.sub_image.set_visible(True)
case self.PackageState.INSTALLED:
self.set_sensitive(False)
self.set_tooltip_text(_("This Package is Already Installed"))
self.installed_image.set_visible(True)
self.state = state
self.add_image.set_visible(False)
self.sub_image.set_visible(False)
self.selected_image.set_visible(False)
self.installed_image.set_visible(False)
match state:
case self.PackageState.NEW:
self.set_sensitive(True)
self.set_tooltip_text(_("Add Package to Queue"))
self.add_image.set_visible(True)
case self.PackageState.SELECTED:
self.set_sensitive(False)
self.set_tooltip_text(_("Package has been Added to Queue"))
self.selected_image.set_visible(True)
case self.PackageState.ADDED:
self.set_sensitive(True)
self.set_tooltip_text(_("Remove Package from Queue"))
self.sub_image.set_visible(True)
case self.PackageState.INSTALLED:
self.set_sensitive(False)
self.set_tooltip_text(_("This Package is Already Installed"))
self.installed_image.set_visible(True)
def __init__(self, package, package_state, origin_list_box, **kwargs):
super().__init__(**kwargs)
def __init__(self, package, package_state, origin_list_box, **kwargs):
super().__init__(**kwargs)
# Extra Object Creation
self.state = None
self.package = package
self.origin_list_box = origin_list_box
# Extra Object Creation
self.state = None
self.package = package
self.origin_list_box = origin_list_box
# Connections
# Connections
# Apply
GLib.idle_add(self.idle_stuff)
self.set_state(package_state)
# Apply
GLib.idle_add(self.idle_stuff)
self.set_state(package_state)

View File

@@ -2,53 +2,53 @@ using Gtk 4.0;
using Adw 1;
template $ResultsPage : Adw.NavigationPage {
title: _("Search a Remote");
Adw.ToolbarView {
[top]
Adw.HeaderBar {}
[top]
Adw.Clamp {
maximum-size: 577;
margin-top: 3;
margin-bottom: 3;
margin-start: 6;
margin-end: 6;
SearchEntry search_entry {
search-delay: 500;
halign: fill;
// hexpand: true;
placeholder-text: _("Search for Packages");
}
}
Stack stack {
Adw.StatusPage new_search {
icon-name: "loupe-large-symbolic";
title: _("Search for Flatpaks");
description: _("Search for Flatpaks you want to install");
}
Adw.StatusPage too_many {
icon-name: "error-symbolic";
title: _("Too Many Results");
description: _("Try being more specific with your search");
}
ScrolledWindow results_view {
Adw.Clamp {
ListBox results_list {
margin-start: 12;
margin-end: 12;
margin-top: 12;
margin-bottom: 12;
styles ["boxed-list"]
selection-mode: none;
valign: start;
}
}
}
Adw.StatusPage no_results {
icon-name: "loupe-large-symbolic";
title: _("No Results Found");
description: _("Try a different search term");
}
}
}
title: _("Search a Remote");
Adw.ToolbarView {
[top]
Adw.HeaderBar {}
[top]
Adw.Clamp {
maximum-size: 577;
margin-top: 3;
margin-bottom: 3;
margin-start: 6;
margin-end: 6;
SearchEntry search_entry {
search-delay: 500;
halign: fill;
// hexpand: true;
placeholder-text: _("Search for Packages");
}
}
Stack stack {
Adw.StatusPage new_search {
icon-name: "loupe-large-symbolic";
title: _("Search for Flatpaks");
description: _("Search for Flatpaks you want to install");
}
Adw.StatusPage too_many {
icon-name: "error-symbolic";
title: _("Too Many Results");
description: _("Try being more specific with your search");
}
ScrolledWindow results_view {
Adw.Clamp {
ListBox results_list {
margin-start: 12;
margin-end: 12;
margin-top: 12;
margin-bottom: 12;
styles ["boxed-list"]
selection-mode: none;
valign: start;
}
}
}
Adw.StatusPage no_results {
icon-name: "loupe-large-symbolic";
title: _("No Results Found");
description: _("Try a different search term");
}
}
}
}

View File

@@ -6,137 +6,137 @@ from .error_toast import ErrorToast
import subprocess
class AddedPackage:
def __eq__(self, other):
return (
self.name == other.name
and self.app_id == other.app_id
and self.branch == other.branch
and self.version == other.version
and self.remote == other.remote
and self.installation == other.installation
)
def __eq__(self, other):
return (
self.name == other.name
and self.app_id == other.app_id
and self.branch == other.branch
and self.version == other.version
and self.remote == other.remote
and self.installation == other.installation
)
def is_similar(self, other):
return (
self.app_id == other.app_id
and self.branch == other.branch
and self.version == other.version
)
def is_similar(self, other):
return (
self.app_id == other.app_id
and self.branch == other.branch
and self.version == other.version
)
def __init__(self, name, app_id, branch, version, remote, installation):
self.name = name
self.app_id = app_id
self.branch = branch
self.version = version
self.remote = remote
self.installation = installation
def __init__(self, name, app_id, branch, version, remote, installation):
self.name = name
self.app_id = app_id
self.branch = branch
self.version = version
self.remote = remote
self.installation = installation
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/install_page/results_page.ui")
class ResultsPage(Adw.NavigationPage):
__gtype_name__ = "ResultsPage"
gtc = Gtk.Template.Child
search_entry = gtc()
results_list = gtc()
stack = gtc()
new_search = gtc()
too_many = gtc()
results_view= gtc()
no_results = gtc()
def show_remote(self, row, remote, installation, nav_view=None):
self.remote = remote
self.installation = installation
self.set_title(_("Search {}").format(remote.title))
self.search_entry.set_text("")
self.search_entry.grab_focus()
if nav_view:
nav_view.push(self)
def add_package_row(self, row):
self.pending_page.add_package_row(row)
if not self.install_page is None:
self.install_page.package_added()
def on_search(self, *args):
self.packages.clear()
self.stack.set_visible_child(self.loading)
self.results_list.remove_all()
search_text = self.search_entry.get_text()
if search_text == "":
self.stack.set_visible_child(self.new_search)
return
def thread(*args):
installation = ""
if self.installation == "user" or self.installation == "system":
installation = f"--{self.installation}"
else:
installation = f"--installation={self.installation}"
try:
output = subprocess.run(
['flatpak-spawn', '--host', 'flatpak', 'search', '--columns=all', installation, self.search_entry.get_text()],
check=True, text=True, capture_output=True
).stdout.split('\n')
if len(output) > 100:
GLib.idle_add(lambda *_: self.stack.set_visible_child(self.too_many))
return
for line in output:
line = line.strip()
info = line.split('\t')
if len(info) != 6:
continue
remotes = info[5].split(',')
if not self.remote.name in remotes:
continue
package = AddedPackage(info[0], info[2], info[4], info[3], self.remote, self.installation)
row = ResultRow(package, ResultRow.PackageState.NEW, self.results_list)
for item in self.pending_page.added_packages:
if package.is_similar(item):
row.set_state(ResultRow.PackageState.SELECTED)
if package.app_id in HostInfo.id_to_flatpak:
installed_package = HostInfo.id_to_flatpak[package.app_id]
if installed_package.info["id"] == package.app_id and installed_package.info["branch"] == package.branch:
row.set_state(ResultRow.PackageState.INSTALLED)
row.connect("activated", self.add_package_row)
self.packages.append(package)
GLib.idle_add(lambda *_, _row=row: self.results_list.append(_row))
if len(self.packages) > 0:
GLib.idle_add(lambda *_: self.stack.set_visible_child(self.results_view))
else:
GLib.idle_add(lambda *_: self.stack.set_visible_child(self.no_results))
except subprocess.CalledProcessError as cpe:
GLib.idle_add(lambda *_, cpe=cpe: HostInfo.main_window.toast_overlay.add_toast(ErrorToast("Could not search for package", cpe.stderr).toast))
GLib.idle_add(lambda *_: self.install_page.select_page.nav_view.pop())
Gio.Task().run_in_thread(thread)
def on_back(self, *args):
self.results_list.remove_all()
self.stack.set_visible_child(self.new_search)
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Extra Object Creation
self.remote = None
self.installation = None
self.packages = []
self.pending_page = None
self.loading = LoadingStatus(_("Searching"), _("This should only take a moment"))
self.install_page = None
# Connections
self.search_entry.connect("search-changed", self.on_search)
# Apply
self.stack.add_child(self.loading)
__gtype_name__ = "ResultsPage"
gtc = Gtk.Template.Child
search_entry = gtc()
results_list = gtc()
stack = gtc()
new_search = gtc()
too_many = gtc()
results_view= gtc()
no_results = gtc()
def show_remote(self, row, remote, installation, nav_view=None):
self.remote = remote
self.installation = installation
self.set_title(_("Search {}").format(remote.title))
self.search_entry.set_text("")
self.search_entry.grab_focus()
if nav_view:
nav_view.push(self)
def add_package_row(self, row):
self.pending_page.add_package_row(row)
if not self.install_page is None:
self.install_page.package_added()
def on_search(self, *args):
self.packages.clear()
self.stack.set_visible_child(self.loading)
self.results_list.remove_all()
search_text = self.search_entry.get_text()
if search_text == "":
self.stack.set_visible_child(self.new_search)
return
def thread(*args):
installation = ""
if self.installation == "user" or self.installation == "system":
installation = f"--{self.installation}"
else:
installation = f"--installation={self.installation}"
try:
output = subprocess.run(
['flatpak-spawn', '--host', 'flatpak', 'search', '--columns=all', installation, self.search_entry.get_text()],
check=True, text=True, capture_output=True
).stdout.split('\n')
if len(output) > 100:
GLib.idle_add(lambda *_: self.stack.set_visible_child(self.too_many))
return
for line in output:
line = line.strip()
info = line.split('\t')
if len(info) != 6:
continue
remotes = info[5].split(',')
if not self.remote.name in remotes:
continue
package = AddedPackage(info[0], info[2], info[4], info[3], self.remote, self.installation)
row = ResultRow(package, ResultRow.PackageState.NEW, self.results_list)
for item in self.pending_page.added_packages:
if package.is_similar(item):
row.set_state(ResultRow.PackageState.SELECTED)
if package.app_id in HostInfo.id_to_flatpak:
installed_package = HostInfo.id_to_flatpak[package.app_id]
if installed_package.info["id"] == package.app_id and installed_package.info["branch"] == package.branch:
row.set_state(ResultRow.PackageState.INSTALLED)
row.connect("activated", self.add_package_row)
self.packages.append(package)
GLib.idle_add(lambda *_, _row=row: self.results_list.append(_row))
if len(self.packages) > 0:
GLib.idle_add(lambda *_: self.stack.set_visible_child(self.results_view))
else:
GLib.idle_add(lambda *_: self.stack.set_visible_child(self.no_results))
except subprocess.CalledProcessError as cpe:
GLib.idle_add(lambda *_, cpe=cpe: HostInfo.main_window.toast_overlay.add_toast(ErrorToast("Could not search for package", cpe.stderr).toast))
GLib.idle_add(lambda *_: self.install_page.select_page.nav_view.pop())
Gio.Task().run_in_thread(thread)
def on_back(self, *args):
self.results_list.remove_all()
self.stack.set_visible_child(self.new_search)
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Extra Object Creation
self.remote = None
self.installation = None
self.packages = []
self.pending_page = None
self.loading = LoadingStatus(_("Searching"), _("This should only take a moment"))
self.install_page = None
# Connections
self.search_entry.connect("search-changed", self.on_search)
# Apply
self.stack.add_child(self.loading)

View File

@@ -2,49 +2,49 @@ using Gtk 4.0;
using Adw 1;
template $SelectPage : Adw.NavigationPage {
title: _("Install Packages");
title: _("Install Packages");
Adw.ToastOverlay toast_overlay {
Adw.NavigationView nav_view {
Adw.NavigationPage select_nav_page {
title: _("Install Packages");
Adw.ToolbarView {
[top]
Adw.HeaderBar {
[start]
$SidebarButton {}
}
Adw.PreferencesPage {
Adw.PreferencesGroup remotes_group {
title: _("Search in a Remote");
description: _("Choose a remote to search for new packages");
}
Adw.PreferencesGroup no_remotes {
title: _("Online Searches Disabled");
description: _("Your system has no remotes added to search from");
visible: bind remotes_group.visible inverted;
Adw.ActionRow add_remote_row {
title: _("Add a Remote");
subtitle: _("Add a remote to your system to enable online searching");
activatable: true;
[suffix]
Image {
icon-name: "right-large-symbolic";
}
}
}
Adw.PreferencesGroup local_group {
title: _("Add Packages");
description: _("Install packages from files on your system");
Adw.ButtonRow open_row {
title: _("Open Files");
start-icon-name: "folder-open-symbolic";
}
}
}
}
}
$ResultsPage results_page {}
}
}
Adw.ToastOverlay toast_overlay {
Adw.NavigationView nav_view {
Adw.NavigationPage select_nav_page {
title: _("Install Packages");
Adw.ToolbarView {
[top]
Adw.HeaderBar {
[start]
$SidebarButton {}
}
Adw.PreferencesPage {
Adw.PreferencesGroup remotes_group {
title: _("Search in a Remote");
description: _("Choose a remote to search for new packages");
}
Adw.PreferencesGroup no_remotes {
title: _("Online Searches Disabled");
description: _("Your system has no remotes added to search from");
visible: bind remotes_group.visible inverted;
Adw.ActionRow add_remote_row {
title: _("Add a Remote");
subtitle: _("Add a remote to your system to enable online searching");
activatable: true;
[suffix]
Image {
icon-name: "right-large-symbolic";
}
}
}
Adw.PreferencesGroup local_group {
title: _("Add Packages");
description: _("Install packages from files on your system");
Adw.ButtonRow open_row {
title: _("Open Files");
start-icon-name: "folder-open-symbolic";
}
}
}
}
}
$ResultsPage results_page {}
}
}
}

View File

@@ -7,83 +7,83 @@ from .file_install_dialog import FileInstallDialog
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/install_page/select_page.ui")
class SelectPage(Adw.NavigationPage):
__gtype_name__ = "SelectPage"
gtc = Gtk.Template.Child
nav_view = gtc()
results_page = gtc()
remotes_group = gtc()
add_remote_row = gtc()
open_row = gtc()
def start_loading(self):
self.nav_view.pop()
for row in self.remote_rows:
self.remotes_group.remove(row)
self.remote_rows.clear()
def end_loading(self):
for installation, remotes in HostInfo.remotes.items():
for remote in remotes:
if remote.disabled:
continue
row = Adw.ActionRow(title=remote.title, subtitle=_("Installation: {}").format(installation), activatable=True)
row.add_suffix(Gtk.Image(icon_name="right-large-symbolic"))
row.connect("activated", self.results_page.show_remote, remote, installation, self.nav_view)
self.remotes_group.add(row)
self.remote_rows.append(row)
self.remotes_group.set_visible(len(self.remote_rows) != 0)
def local_install_apply_callback(self, installation, file_names):
install_page = HostInfo.main_window.pages[HostInfo.main_window.install_row]
requests = []
for file in file_names:
# sadly flatpak doesn't support multiple local installs in one command :(
requests.append({
"remote": "local_file",
"installation": installation,
"package_names": [file.get_path()],
"extra_flags": [],
})
install_page.install_packages(requests)
def file_dialog_handler(self, files):
FileInstallDialog(self, files, self.local_install_apply_callback).present(HostInfo.main_window)
def file_choose_callback(self, object, result):
try:
files = object.open_multiple_finish(result)
if not files:
HostInfo.main_window.toast_overlay.add_toast(ErrorToast(_("Could not add files"), _("No files were found to install")))
return
self.file_dialog_handler(files)
except GLib.GError as gle:
if not (gle.domain == "gtk-dialog-error-quark" and gle.code == 2):
HostInfo.main_window.toast_overlay.add_toast(ErrorToast(_("Could not add files"), str(gle)).toast)
def on_open(self, *args):
file_filter = Gtk.FileFilter(name=_("Flatpaks"))
file_filter.add_suffix("flatpak")
file_filter.add_suffix("flatpakref")
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(HostInfo.main_window, None, self.file_choose_callback)
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Extra Object Creation
self.remote_rows = []
# Connections
self.add_remote_row.connect("activated", lambda *_: HostInfo.main_window.activate_row(HostInfo.main_window.remotes_row))
self.nav_view.connect("popped", self.results_page.on_back)
self.open_row.connect("activated", self.on_open)
__gtype_name__ = "SelectPage"
gtc = Gtk.Template.Child
nav_view = gtc()
results_page = gtc()
remotes_group = gtc()
add_remote_row = gtc()
open_row = gtc()
def start_loading(self):
self.nav_view.pop()
for row in self.remote_rows:
self.remotes_group.remove(row)
self.remote_rows.clear()
def end_loading(self):
for installation, remotes in HostInfo.remotes.items():
for remote in remotes:
if remote.disabled:
continue
row = Adw.ActionRow(title=remote.title, subtitle=_("Installation: {}").format(installation), activatable=True)
row.add_suffix(Gtk.Image(icon_name="right-large-symbolic"))
row.connect("activated", self.results_page.show_remote, remote, installation, self.nav_view)
self.remotes_group.add(row)
self.remote_rows.append(row)
self.remotes_group.set_visible(len(self.remote_rows) != 0)
def local_install_apply_callback(self, installation, file_names):
install_page = HostInfo.main_window.pages[HostInfo.main_window.install_row]
requests = []
for file in file_names:
# sadly flatpak doesn't support multiple local installs in one command :(
requests.append({
"remote": "local_file",
"installation": installation,
"package_names": [file.get_path()],
"extra_flags": [],
})
install_page.install_packages(requests)
def file_dialog_handler(self, files):
FileInstallDialog(self, files, self.local_install_apply_callback).present(HostInfo.main_window)
def file_choose_callback(self, object, result):
try:
files = object.open_multiple_finish(result)
if not files:
HostInfo.main_window.toast_overlay.add_toast(ErrorToast(_("Could not add files"), _("No files were found to install")))
return
self.file_dialog_handler(files)
except GLib.GError as gle:
if not (gle.domain == "gtk-dialog-error-quark" and gle.code == 2):
HostInfo.main_window.toast_overlay.add_toast(ErrorToast(_("Could not add files"), str(gle)).toast)
def on_open(self, *args):
file_filter = Gtk.FileFilter(name=_("Flatpaks"))
file_filter.add_suffix("flatpak")
file_filter.add_suffix("flatpakref")
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(HostInfo.main_window, None, self.file_choose_callback)
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Extra Object Creation
self.remote_rows = []
# Connections
self.add_remote_row.connect("activated", lambda *_: HostInfo.main_window.activate_row(HostInfo.main_window.remotes_row))
self.nav_view.connect("popped", self.results_page.on_back)
self.open_row.connect("activated", self.on_open)

View File

@@ -31,228 +31,228 @@ from .const import Config
from .error_toast import ErrorToast
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",
flags=Gio.ApplicationFlags.DEFAULT_FLAGS,
)
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("open-menu", lambda *_: self.props.active_window.main_menu.popup(), ["F10"])
self.create_action("refresh", lambda *_: self.props.active_window.refresh_handler(), ["<primary>r", "F5"])
self.create_action("open-files", self.on_open_files_shortcut, ["<primary>o"])
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"])
self.create_action("show-user-data-page", lambda *_: self.props.active_window.switch_page_shortcut_handler("d"), ["<primary>d"])
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("toggle-select-mode", self.on_toggle_select_mode_shortcut, ["<primary>b", "<primary>Return"])
self.create_action("toggle-selection-kp-enter", self.on_toggle_select_mode_shortcut, ["<primary>KP_Enter"]) # Doesn't show in the shortcuts window
self.create_action("search-mode", self.on_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("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)
+ "."
+ 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 on_open_files_shortcut(self, *args):
window = self.props.active_window
def file_choose_callback(object, result):
try:
files = object.open_multiple_finish(result)
if not files:
window.toast_overlay.add_toast(ErrorToast(_("Could not add files"), _("No files were found")).toast)
return
window.on_file_drop(None, files, None, None)
except GLib.GError as gle:
if not (gle.domain == "gtk-dialog-error-quark" and gle.code == 2):
window.toast_overlay.add_toast(ErrorToast(_("Could not add files"), str(gle)).toast)
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_search_mode_shortcut(self, *args):
try:
button = self.props.active_window.stack.get_visible_child().search_button
button.set_active(True)
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.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.
"""
win = self.props.active_window
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(
application_name="Warehouse",
application_icon="io.github.flattool.Warehouse",
developer_name="Heliguy",
version=self.version,
developers=[
"Heliguy https://github.com/heliguy4599",
"kramo https://kramo.page",
],
artists=[
"Heliguy https://github.com/heliguy4599",
"kramo https://kramo.page",
"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,
# Translators: do one of the following, one per line: Your Name, Your Name <email@email.org>, Your Name https://your.website
translator_credits=_("translator-credits"),
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",
)
about.add_link(_("Donate"), "https://ko-fi.com/heliguy")
about.add_credit_section(
_("Contributors"),
[
# Contributors: do one of the following, one per line: Your Name, Your Name <email@email.org>, Your Name https://your.website
"Win <winsdominoes2018@gmail.com>",
"Óscar Fernández Díaz",
"Runar https://github.com/runarcn",
"skøldis <warehouse@turtle.garden>",
"Maxim Therrien <maxim@mtsd.ca>",
],
)
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
shortcuts: an optional list of accelerators
"""
action = Gio.SimpleAction.new(name, None)
action.connect("activate", callback)
self.add_action(action)
if shortcuts:
self.set_accels_for_action(f"app.{name}", shortcuts)
"""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",
flags=Gio.ApplicationFlags.DEFAULT_FLAGS,
)
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("open-menu", lambda *_: self.props.active_window.main_menu.popup(), ["F10"])
self.create_action("refresh", lambda *_: self.props.active_window.refresh_handler(), ["<primary>r", "F5"])
self.create_action("open-files", self.on_open_files_shortcut, ["<primary>o"])
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"])
self.create_action("show-user-data-page", lambda *_: self.props.active_window.switch_page_shortcut_handler("d"), ["<primary>d"])
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("toggle-select-mode", self.on_toggle_select_mode_shortcut, ["<primary>b", "<primary>Return"])
self.create_action("toggle-selection-kp-enter", self.on_toggle_select_mode_shortcut, ["<primary>KP_Enter"]) # Doesn't show in the shortcuts window
self.create_action("search-mode", self.on_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("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)
+ "."
+ 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 on_open_files_shortcut(self, *args):
window = self.props.active_window
def file_choose_callback(object, result):
try:
files = object.open_multiple_finish(result)
if not files:
window.toast_overlay.add_toast(ErrorToast(_("Could not add files"), _("No files were found")).toast)
return
window.on_file_drop(None, files, None, None)
except GLib.GError as gle:
if not (gle.domain == "gtk-dialog-error-quark" and gle.code == 2):
window.toast_overlay.add_toast(ErrorToast(_("Could not add files"), str(gle)).toast)
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_search_mode_shortcut(self, *args):
try:
button = self.props.active_window.stack.get_visible_child().search_button
button.set_active(True)
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.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.
"""
win = self.props.active_window
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(
application_name="Warehouse",
application_icon="io.github.flattool.Warehouse",
developer_name="Heliguy",
version=self.version,
developers=[
"Heliguy https://github.com/heliguy4599",
"kramo https://kramo.page",
],
artists=[
"Heliguy https://github.com/heliguy4599",
"kramo https://kramo.page",
"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,
# Translators: do one of the following, one per line: Your Name, Your Name <email@email.org>, Your Name https://your.website
translator_credits=_("translator-credits"),
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",
)
about.add_link(_("Donate"), "https://ko-fi.com/heliguy")
about.add_credit_section(
_("Contributors"),
[
# Contributors: do one of the following, one per line: Your Name, Your Name <email@email.org>, Your Name https://your.website
"Win <winsdominoes2018@gmail.com>",
"Óscar Fernández Díaz",
"Runar https://github.com/runarcn",
"skøldis <warehouse@turtle.garden>",
"Maxim Therrien <maxim@mtsd.ca>",
],
)
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
shortcuts: an optional list of accelerators
"""
action = Gio.SimpleAction.new(name, None)
action.connect("activate", callback)
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()
return app.run(sys.argv)
"""The application's entry point."""
app = WarehouseApplication()
return app.run(sys.argv)

View File

@@ -2,161 +2,161 @@ using Gtk 4.0;
using Adw 1;
template $WarehouseWindow: Adw.ApplicationWindow {
title: "Warehouse";
width-request: 363;
default-width: 921;
default-height: 450;
Adw.Breakpoint main_breakpoint {
condition ("min-width: 865")
setters {
main_split.collapsed: false;
main_split.max-sidebar-width: 999999999;
}
}
content:
Adw.ToastOverlay toast_overlay {
Overlay {
[overlay]
Revealer file_drop_revealer {
can-target: false;
transition-type: crossfade;
Adw.StatusPage file_drop_view {
icon-name: "folder-open-symbolic";
title: _("Drop to Open");
description: _("Install Flatpaks or Add a Remote");
styles ["drag-overlay-status-page"]
}
}
Adw.OverlaySplitView main_split {
collapsed: true;
show-sidebar: true;
sidebar-width-fraction: 0.2;
min-sidebar-width: 250;
sidebar:
Adw.NavigationPage {
title: "Warehouse";
Adw.ToolbarView main_toolbar_view {
[top]
Adw.HeaderBar header_bar {
[start]
Button refresh_button {
icon-name: "arrow-circular-top-right-symbolic";
tooltip-text: _("Refresh List");
}
[end]
MenuButton main_menu {
icon-name: "open-menu-symbolic";
tooltip-text: _("Main Menu");
menu-model: primary_menu;
}
}
content:
ScrolledWindow {
ListBox navigation_row_listbox {
styles ["navigation-sidebar"]
Box packages_row {
margin-top: 12;
margin-bottom: 12;
margin-start: 6;
margin-end: 6;
spacing: 12;
Image icon {
icon-name: "flatpak-symbolic";
}
Label {
label: _("Packages");
}
}
Box remotes_row {
margin-top: 12;
margin-bottom: 12;
margin-start: 6;
margin-end: 6;
spacing: 12;
Image {
icon-name: "server-pick-symbolic";
}
Label {
label: _("Remotes");
}
}
Box user_data_row {
margin-top: 12;
margin-bottom: 12;
margin-start: 6;
margin-end: 6;
spacing: 12;
Image {
icon-name: "file-manager-symbolic";
}
Label {
label: _("User Data");
}
}
Box snapshots_row {
margin-top: 12;
margin-bottom: 12;
margin-start: 6;
margin-end: 6;
spacing: 12;
Image {
icon-name: "snapshots-alt-symbolic";
}
Label {
label: _("Snapshots");
}
}
Box install_row {
margin-top: 12;
margin-bottom: 12;
margin-start: 6;
margin-end: 6;
spacing: 12;
Image {
icon-name: "arrow-pointing-at-line-down-symbolic";
}
Label {
label: _("Install Packages");
}
}
}
}
;
}
}
;
content:
Stack stack {
}
;
}
}
}
;
title: "Warehouse";
width-request: 363;
default-width: 921;
default-height: 450;
Adw.Breakpoint main_breakpoint {
condition ("min-width: 865")
setters {
main_split.collapsed: false;
main_split.max-sidebar-width: 999999999;
}
}
content:
Adw.ToastOverlay toast_overlay {
Overlay {
[overlay]
Revealer file_drop_revealer {
can-target: false;
transition-type: crossfade;
Adw.StatusPage file_drop_view {
icon-name: "folder-open-symbolic";
title: _("Drop to Open");
description: _("Install Flatpaks or Add a Remote");
styles ["drag-overlay-status-page"]
}
}
Adw.OverlaySplitView main_split {
collapsed: true;
show-sidebar: true;
sidebar-width-fraction: 0.2;
min-sidebar-width: 250;
sidebar:
Adw.NavigationPage {
title: "Warehouse";
Adw.ToolbarView main_toolbar_view {
[top]
Adw.HeaderBar header_bar {
[start]
Button refresh_button {
icon-name: "arrow-circular-top-right-symbolic";
tooltip-text: _("Refresh List");
}
[end]
MenuButton main_menu {
icon-name: "open-menu-symbolic";
tooltip-text: _("Main Menu");
menu-model: primary_menu;
}
}
content:
ScrolledWindow {
ListBox navigation_row_listbox {
styles ["navigation-sidebar"]
Box packages_row {
margin-top: 12;
margin-bottom: 12;
margin-start: 6;
margin-end: 6;
spacing: 12;
Image icon {
icon-name: "flatpak-symbolic";
}
Label {
label: _("Packages");
}
}
Box remotes_row {
margin-top: 12;
margin-bottom: 12;
margin-start: 6;
margin-end: 6;
spacing: 12;
Image {
icon-name: "server-pick-symbolic";
}
Label {
label: _("Remotes");
}
}
Box user_data_row {
margin-top: 12;
margin-bottom: 12;
margin-start: 6;
margin-end: 6;
spacing: 12;
Image {
icon-name: "file-manager-symbolic";
}
Label {
label: _("User Data");
}
}
Box snapshots_row {
margin-top: 12;
margin-bottom: 12;
margin-start: 6;
margin-end: 6;
spacing: 12;
Image {
icon-name: "snapshots-alt-symbolic";
}
Label {
label: _("Snapshots");
}
}
Box install_row {
margin-top: 12;
margin-bottom: 12;
margin-start: 6;
margin-end: 6;
spacing: 12;
Image {
icon-name: "arrow-pointing-at-line-down-symbolic";
}
Label {
label: _("Install Packages");
}
}
}
}
;
}
}
;
content:
Stack stack {
}
;
}
}
}
;
}
menu primary_menu {
section {
/*item {
label: _("_Preferences");
action: "app.preferences";
}*/
// item {
// label: _("Refresh List");
// action: "app.refresh-list";
// }
item {
label: _("_Open Files");
action: "app.open-files";
}
item {
label: _("_Keyboard Shortcuts");
action: "win.show-help-overlay";
}
item {
label: _("_About Warehouse");
action: "app.about";
}
}
section {
/*item {
label: _("_Preferences");
action: "app.preferences";
}*/
// item {
// label: _("Refresh List");
// action: "app.refresh-list";
// }
item {
label: _("_Open Files");
action: "app.open-files";
}
item {
label: _("_Keyboard Shortcuts");
action: "win.show-help-overlay";
}
item {
label: _("_About Warehouse");
action: "app.about";
}
}
}

View File

@@ -28,218 +28,218 @@ from .const import Config
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/main_window/window.ui")
class WarehouseWindow(Adw.ApplicationWindow):
__gtype_name__ = "WarehouseWindow"
gtc = Gtk.Template.Child
main_breakpoint = gtc()
toast_overlay = gtc()
file_drop_revealer = gtc()
main_split = gtc()
file_drop_view = gtc()
stack = gtc()
refresh_button = gtc()
main_menu = gtc()
navigation_row_listbox = gtc()
packages_row = gtc()
remotes_row = gtc()
user_data_row = gtc()
snapshots_row = gtc()
install_row = gtc()
__gtype_name__ = "WarehouseWindow"
gtc = Gtk.Template.Child
main_breakpoint = gtc()
toast_overlay = gtc()
file_drop_revealer = gtc()
main_split = gtc()
file_drop_view = gtc()
stack = gtc()
refresh_button = gtc()
main_menu = gtc()
navigation_row_listbox = gtc()
packages_row = gtc()
remotes_row = gtc()
user_data_row = gtc()
snapshots_row = gtc()
install_row = gtc()
def start_loading(self, *args):
for _, page in self.pages.items():
if page.instance:
page.instance.start_loading()
def start_loading(self, *args):
for _, page in self.pages.items():
if page.instance:
page.instance.start_loading()
def end_loading(self, *args):
for _, page in self.pages.items():
if page.instance:
page.instance.end_loading()
self.refresh_button.set_sensitive(True)
self.refresh_requested = False
self.remove_refresh_lockout("refresh handler direct")
def do_refresh(self):
self.start_loading()
self.refresh_button.set_sensitive(False)
HostInfo.get_flatpaks(callback=self.end_loading)
def end_loading(self, *args):
for _, page in self.pages.items():
if page.instance:
page.instance.end_loading()
self.refresh_button.set_sensitive(True)
self.refresh_requested = False
self.remove_refresh_lockout("refresh handler direct")
def do_refresh(self):
self.start_loading()
self.refresh_button.set_sensitive(False)
HostInfo.get_flatpaks(callback=self.end_loading)
def refresh_handler(self, *args):
if len(self.refresh_lockouts) == 0:
self.add_refresh_lockout("refresh handler direct")
self.do_refresh()
elif "refresh handler direct" in self.refresh_lockouts:
return
else:
self.refresh_requested = True
def add_refresh_lockout(self, reason):
self.refresh_lockouts.append(reason)
self.refresh_button.set_sensitive(False)
def remove_refresh_lockout(self, reason):
if reason in self.refresh_lockouts:
self.refresh_lockouts.remove(reason)
if len(self.refresh_lockouts) == 0:
if self.refresh_requested:
self.do_refresh()
else:
self.refresh_button.set_sensitive(True)
def refresh_handler(self, *args):
if len(self.refresh_lockouts) == 0:
self.add_refresh_lockout("refresh handler direct")
self.do_refresh()
elif "refresh handler direct" in self.refresh_lockouts:
return
else:
self.refresh_requested = True
def add_refresh_lockout(self, reason):
self.refresh_lockouts.append(reason)
self.refresh_button.set_sensitive(False)
def remove_refresh_lockout(self, reason):
if reason in self.refresh_lockouts:
self.refresh_lockouts.remove(reason)
if len(self.refresh_lockouts) == 0:
if self.refresh_requested:
self.do_refresh()
else:
self.refresh_button.set_sensitive(True)
def navigation_handler(self, _, row):
row = row.get_child()
page = self.pages[row]
self.stack.set_visible_child(page)
self.settings.set_string("page-shown", page.page_name)
if self.main_split.get_collapsed():
self.main_split.set_show_sidebar(False)
def navigation_handler(self, _, row):
row = row.get_child()
page = self.pages[row]
self.stack.set_visible_child(page)
self.settings.set_string("page-shown", page.page_name)
if self.main_split.get_collapsed():
self.main_split.set_show_sidebar(False)
def activate_row(self, nav_row):
idx = 0
while row := self.navigation_row_listbox.get_row_at_index(idx):
idx += 1
if row.get_child() is nav_row:
row.activate()
nav_row.grab_focus()
break
def activate_row(self, nav_row):
idx = 0
while row := self.navigation_row_listbox.get_row_at_index(idx):
idx += 1
if row.get_child() is nav_row:
row.activate()
nav_row.grab_focus()
break
def show_saved_page(self):
page_to_show = self.settings.get_string("page-shown")
page_found = False
for row, page in self.pages.items():
self.stack.add_child(page)
def show_saved_page(self):
page_to_show = self.settings.get_string("page-shown")
page_found = False
for row, page in self.pages.items():
self.stack.add_child(page)
if page.page_name == page_to_show:
page_found = True
self.activate_row(row)
if page.page_name == page_to_show:
page_found = True
self.activate_row(row)
if not page_found:
self.navigation_row_listbox.get_row_at_index(0).activate()
def on_file_drop(self, drop_target, value, x, y):
try:
paks = []
remotes = []
for file in value:
path = file.get_path()
if path.endswith(".flatpak") or path.endswith(".flatpakref"):
paks.append(Gio.File.new_for_path(path))
elif path.endswith(".flatpakrepo"):
remotes.append(path)
else:
dialog = Adw.AlertDialog(
heading=_("Unsupported Filetype"),
body=_("Only .flatpak, .flatpakref, and .flatpakrepo files are supported."),
)
dialog.add_response("continue", _("OK"))
dialog.present(self)
return
if len(remotes) > 0 and len(paks) > 0:
dialog = Adw.AlertDialog(
heading=_("Mixed Filetypes"),
body=_("Flatpaks and remotes cannot be installed at the same time."),
)
dialog.add_css_class("error")
dialog.add_response("continue", _("OK"))
dialog.present(self)
return
if len(remotes) > 1:
dialog = Adw.AlertDialog(
heading=_("Too Many Remotes"),
body=_("Only one remote at a time is supported."),
)
dialog.add_response("continue", _("OK"))
dialog.present(self)
return
if len(remotes) == 1:
# Adding a remote
self.activate_row(self.remotes_row)
remotes_page = self.pages[self.remotes_row]
remotes_page.local_file_handler(remotes[0])
elif len(paks) > 0:
# Add packages
self.activate_row(self.install_row)
install_page = self.pages[self.install_row]
install_page.select_page.file_dialog_handler(paks)
except Exception as e:
self.toast_overlay.add_toast(ErrorToast(_("Could not open files"), str(e)).toast)
def on_drop_enter(self, *args):
self.main_split.add_css_class("blurred")
self.file_drop_revealer.set_reveal_child(True)
return 1
def on_drop_leave(self, *args):
self.main_split.remove_css_class("blurred")
self.file_drop_revealer.set_reveal_child(False)
def switch_page_shortcut_handler(self, letter):
self.activate_row(self.shortcut_to_pages[letter])
def key_handler(self, controller, keyval, keycode, state):
page = self.stack.get_visible_child()
if keyval == Gdk.KEY_BackSpace or keyval == Gdk.KEY_Delete:
try:
if page.select_button.get_active():
page.on_backspace_handler()
except AttributeError:
pass
elif keyval == Gdk.KEY_Escape:
try:
page.on_escape_handler()
except AttributeError:
pass
def __init__(self, **kwargs):
super().__init__(**kwargs)
if not page_found:
self.navigation_row_listbox.get_row_at_index(0).activate()
def on_file_drop(self, drop_target, value, x, y):
try:
paks = []
remotes = []
for file in value:
path = file.get_path()
if path.endswith(".flatpak") or path.endswith(".flatpakref"):
paks.append(Gio.File.new_for_path(path))
elif path.endswith(".flatpakrepo"):
remotes.append(path)
else:
dialog = Adw.AlertDialog(
heading=_("Unsupported Filetype"),
body=_("Only .flatpak, .flatpakref, and .flatpakrepo files are supported."),
)
dialog.add_response("continue", _("OK"))
dialog.present(self)
return
if len(remotes) > 0 and len(paks) > 0:
dialog = Adw.AlertDialog(
heading=_("Mixed Filetypes"),
body=_("Flatpaks and remotes cannot be installed at the same time."),
)
dialog.add_css_class("error")
dialog.add_response("continue", _("OK"))
dialog.present(self)
return
if len(remotes) > 1:
dialog = Adw.AlertDialog(
heading=_("Too Many Remotes"),
body=_("Only one remote at a time is supported."),
)
dialog.add_response("continue", _("OK"))
dialog.present(self)
return
if len(remotes) == 1:
# Adding a remote
self.activate_row(self.remotes_row)
remotes_page = self.pages[self.remotes_row]
remotes_page.local_file_handler(remotes[0])
elif len(paks) > 0:
# Add packages
self.activate_row(self.install_row)
install_page = self.pages[self.install_row]
install_page.select_page.file_dialog_handler(paks)
except Exception as e:
self.toast_overlay.add_toast(ErrorToast(_("Could not open files"), str(e)).toast)
def on_drop_enter(self, *args):
self.main_split.add_css_class("blurred")
self.file_drop_revealer.set_reveal_child(True)
return 1
def on_drop_leave(self, *args):
self.main_split.remove_css_class("blurred")
self.file_drop_revealer.set_reveal_child(False)
def switch_page_shortcut_handler(self, letter):
self.activate_row(self.shortcut_to_pages[letter])
def key_handler(self, controller, keyval, keycode, state):
page = self.stack.get_visible_child()
if keyval == Gdk.KEY_BackSpace or keyval == Gdk.KEY_Delete:
try:
if page.select_button.get_active():
page.on_backspace_handler()
except AttributeError:
pass
elif keyval == Gdk.KEY_Escape:
try:
page.on_escape_handler()
except AttributeError:
pass
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Extra Object Creation
HostInfo.main_window = self
ErrorToast.main_window = self
self.settings = Gio.Settings.new("io.github.flattool.Warehouse")
self.pages = {
self.packages_row: PackagesPage(main_window=self),
self.remotes_row: RemotesPage(main_window=self),
self.user_data_row: UserDataPage(main_window=self),
self.snapshots_row: SnapshotPage(main_window=self),
self.install_row: InstallPage(main_window=self),
}
self.shortcut_to_pages = {
"p": self.packages_row,
"m": self.remotes_row,
"d": self.user_data_row,
"s": self.snapshots_row,
"i": self.install_row,
}
self.navigation_row_listbox.connect("row-activated", self.navigation_handler)
self.show_saved_page()
self.refresh_lockouts = []
self.refresh_requested = False
file_drop = Gtk.DropTarget.new(Gdk.FileList, Gdk.DragAction.COPY)
event_controller = Gtk.EventControllerKey()
# Extra Object Creation
HostInfo.main_window = self
ErrorToast.main_window = self
self.settings = Gio.Settings.new("io.github.flattool.Warehouse")
self.pages = {
self.packages_row: PackagesPage(main_window=self),
self.remotes_row: RemotesPage(main_window=self),
self.user_data_row: UserDataPage(main_window=self),
self.snapshots_row: SnapshotPage(main_window=self),
self.install_row: InstallPage(main_window=self),
}
self.shortcut_to_pages = {
"p": self.packages_row,
"m": self.remotes_row,
"d": self.user_data_row,
"s": self.snapshots_row,
"i": self.install_row,
}
self.navigation_row_listbox.connect("row-activated", self.navigation_handler)
self.show_saved_page()
self.refresh_lockouts = []
self.refresh_requested = False
file_drop = Gtk.DropTarget.new(Gdk.FileList, Gdk.DragAction.COPY)
event_controller = Gtk.EventControllerKey()
# Apply
self.add_controller(file_drop)
self.add_controller(event_controller)
self.settings.bind("window-width", self, "default-width", Gio.SettingsBindFlags.DEFAULT)
self.settings.bind("window-height", self, "default-height", Gio.SettingsBindFlags.DEFAULT)
self.settings.bind("is-maximized", self, "maximized", Gio.SettingsBindFlags.DEFAULT)
self.settings.bind("is-fullscreen", self, "fullscreened", Gio.SettingsBindFlags.DEFAULT)
if Config.DEVEL:
self.add_css_class("devel")
# Apply
self.add_controller(file_drop)
self.add_controller(event_controller)
self.settings.bind("window-width", self, "default-width", Gio.SettingsBindFlags.DEFAULT)
self.settings.bind("window-height", self, "default-height", Gio.SettingsBindFlags.DEFAULT)
self.settings.bind("is-maximized", self, "maximized", Gio.SettingsBindFlags.DEFAULT)
self.settings.bind("is-fullscreen", self, "fullscreened", Gio.SettingsBindFlags.DEFAULT)
if Config.DEVEL:
self.add_css_class("devel")
# Connections
file_drop.connect("drop", self.on_file_drop)
file_drop.connect("enter", self.on_drop_enter)
file_drop.connect("leave", self.on_drop_leave)
event_controller.connect("key-pressed", self.key_handler)
self.refresh_button.connect("clicked", self.refresh_handler)
# Apply again
self.start_loading()
HostInfo.get_flatpaks(callback=self.end_loading)
# Connections
file_drop.connect("drop", self.on_file_drop)
file_drop.connect("enter", self.on_drop_enter)
file_drop.connect("leave", self.on_drop_leave)
event_controller.connect("key-pressed", self.key_handler)
self.refresh_button.connect("clicked", self.refresh_handler)
# Apply again
self.start_loading()
HostInfo.get_flatpaks(callback=self.end_loading)

View File

@@ -240,89 +240,89 @@ template $PropertiesPage : Adw.NavigationPage {
}
}
Adw.PreferencesGroup remote_info {
margin-bottom: 12;
title: _("Installation Information");
Adw.ActionRow sdk_row {
styles ["property"]
title: "SDK";
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
Adw.ActionRow origin_row {
styles ["property"]
title: _("Origin");
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
Adw.ActionRow collection_row {
styles ["property"]
title: _("Collection");
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
Adw.ActionRow installation_row {
styles ["property"]
title: _("Installation");
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
}
Adw.PreferencesGroup commit_info {
title: _("Commit Information");
Adw.ActionRow commit_row {
styles ["property"]
title: "Commit";
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
Adw.ActionRow parent_row {
styles ["property"]
title: _("Parent");
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
Adw.ActionRow subject_row {
styles ["property"]
title: _("Subject");
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
Adw.ActionRow date_row {
styles ["property"]
title: _("Date");
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
}
}
}
}
}
}
}
}
}
}
margin-bottom: 12;
title: _("Installation Information");
Adw.ActionRow sdk_row {
styles ["property"]
title: "SDK";
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
Adw.ActionRow origin_row {
styles ["property"]
title: _("Origin");
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
Adw.ActionRow collection_row {
styles ["property"]
title: _("Collection");
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
Adw.ActionRow installation_row {
styles ["property"]
title: _("Installation");
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
}
Adw.PreferencesGroup commit_info {
title: _("Commit Information");
Adw.ActionRow commit_row {
styles ["property"]
title: "Commit";
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
Adw.ActionRow parent_row {
styles ["property"]
title: _("Parent");
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
Adw.ActionRow subject_row {
styles ["property"]
title: _("Subject");
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
Adw.ActionRow date_row {
styles ["property"]
title: _("Date");
activatable: true;
Image {
icon-name: "copy-symbolic";
}
}
}
}
}
}
}
}
}
}
}
}
}
Popover more_menu {
styles ["menu"]
ListBox more_list {
}
styles ["menu"]
ListBox more_list {
}
}