diff --git a/src/meson.build b/src/meson.build
index 4b1ef9e..816b91b 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -22,6 +22,7 @@ blueprints = custom_target('blueprints',
'snapshot_page/snapshot_page.blp',
'snapshot_page/snapshots_list_page.blp',
'snapshot_page/snapshot_box.blp',
+ 'snapshot_page/new_snapshot_dialog.blp',
'install_page/install_page.blp',
'install_page/result_row.blp',
'install_page/select_page.blp',
@@ -88,6 +89,7 @@ warehouse_sources = [
'snapshot_page/snapshot_page.py',
'snapshot_page/snapshots_list_page.py',
'snapshot_page/snapshot_box.py',
+ 'snapshot_page/new_snapshot_dialog.py',
'install_page/install_page.py',
'install_page/result_row.py',
'install_page/select_page.py',
diff --git a/src/snapshot_page/new_snapshot_dialog.blp b/src/snapshot_page/new_snapshot_dialog.blp
new file mode 100644
index 0000000..eed8004
--- /dev/null
+++ b/src/snapshot_page/new_snapshot_dialog.blp
@@ -0,0 +1,72 @@
+using Gtk 4.0;
+using Adw 1;
+
+template $NewSnapshotDialog : Adw.Dialog {
+ follows-content-size: true;
+ width-request: 400;
+ Adw.NavigationView nav_view {
+ Adw.NavigationPage app_list_page {
+ title: _("Choose Applications");
+ Adw.ToolbarView {
+ [top]
+ Adw.HeaderBar {
+ show-start-title-buttons: false;
+ show-end-title-buttons: false;
+ [start]
+ Button list_cancel_button {
+ label: _("Cancel");
+ }
+ [start]
+ ToggleButton search_button {
+ icon-name: "loupe-large-symbolic";
+ tooltip-text: _("Search Apps");
+ }
+ [end]
+ Button next_button {
+ // sensitive: false;
+ label: _("Next");
+ styles ["suggested-action"]
+ }
+ }
+ [top]
+ SearchBar search_bar {
+ search-mode-enabled: bind search_button.active bidirectional;
+ key-capture-widget: template;
+ SearchEntry search_entry {
+ hexpand: true;
+ placeholder-text: _("Search Apps");
+ }
+ }
+ ScrolledWindow {
+ propagate-natural-height: true;
+ propagate-natural-width: true;
+ ListBox listbox {
+ valign: start;
+ margin-start: 12;
+ margin-bottom: 12;
+ margin-top: 12;
+ margin-end: 12;
+ selection-mode: none;
+ styles ["boxed-list"]
+ }
+ }
+ }
+ }
+ Adw.NavigationPage details_page {
+ title: _("New Snapshot");
+ Adw.ToolbarView {
+ [top]
+ Adw.HeaderBar {
+ show-start-title-buttons: false;
+ show-end-title-buttons: false;
+ [end]
+ Button create_button {
+ // sensitive: false;
+ label: _("Snapshot");
+ styles ["suggested-action"]
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/snapshot_page/new_snapshot_dialog.py b/src/snapshot_page/new_snapshot_dialog.py
new file mode 100644
index 0000000..a978554
--- /dev/null
+++ b/src/snapshot_page/new_snapshot_dialog.py
@@ -0,0 +1,64 @@
+from gi.repository import Adw, Gtk, GLib, Gio
+from .host_info import HostInfo
+from .error_toast import ErrorToast
+from .loading_status import LoadingStatus
+from .app_row import AppRow
+import subprocess, os
+
+@Gtk.Template(resource_path="/io/github/flattool/Warehouse/snapshot_page/new_snapshot_dialog.ui")
+class NewSnapshotDialog(Adw.Dialog):
+ __gtype_name__ = "NewSnapshotDialog"
+ gtc = Gtk.Template.Child
+
+ nav_view = gtc()
+
+ app_list_page = gtc()
+ list_cancel_button = gtc()
+ next_button = gtc()
+ listbox = gtc()
+
+ details_page = gtc()
+ create_button = gtc()
+
+ def row_gesture_handler(self, row):
+ row.check_button.set_active(not row.check_button.get_active())
+
+ def row_select_handler(self, row):
+ if row.check_button.get_active():
+ self.selected_rows.append(row)
+ else:
+ self.selected_rows.remove(row)
+
+ if (total := len(self.selected_rows)) > 0:
+ self.app_list_page.set_title(_("{} Selected").format(total))
+ else:
+ self.app_list_page.set_title(_("Choose Applications"))
+
+ def generate_list(self, *args):
+ for package in HostInfo.flatpaks:
+ if package.is_runtime or not os.path.exists(package.data_path):
+ continue
+ row = AppRow(package, self.row_gesture_handler)
+ row.check_button.set_visible(True)
+ row.check_button.connect("toggled", lambda *_, row=row: self.row_select_handler(row))
+ row.set_activatable(True)
+ row.set_activatable_widget(row.check_button)
+ GLib.idle_add(lambda *_, row=row: self.listbox.append(row))
+
+ def sort_func(self, row1, row2):
+ return row1.get_title().lower() > row2.get_title().lower()
+
+ def __init__(self, **kwargs):
+ super().__init__(**kwargs)
+
+ # Extra Object Creations
+ self.rows = []
+ self.selected_rows = []
+
+ # Connections
+ self.list_cancel_button.connect("clicked", lambda *_: self.close())
+ self.next_button.connect("clicked", lambda *_: self.nav_view.push(self.details_page))
+
+ # Apply
+ Gio.Task.new(None, None, None).run_in_thread(self.generate_list)
+ self.listbox.set_sort_func(self.sort_func)
diff --git a/src/snapshot_page/snapshot_page.py b/src/snapshot_page/snapshot_page.py
index 4a2cac5..3a99cf3 100644
--- a/src/snapshot_page/snapshot_page.py
+++ b/src/snapshot_page/snapshot_page.py
@@ -5,6 +5,7 @@ from .app_row import AppRow
from .snapshots_list_page import SnapshotsListPage
from .sidebar_button import SidebarButton
from .loading_status import LoadingStatus
+from .new_snapshot_dialog import NewSnapshotDialog
import os, subprocess
class LeftoverSnapshotRow(Adw.ActionRow):
@@ -184,6 +185,7 @@ class SnapshotPage(Adw.BreakpointBin):
self.leftover_listbox.connect("row-activated", self.leftover_select_handler)
self.open_button.connect("clicked", self.open_snapshots_folder, self.toast_overlay)
self.status_open_button.connect("clicked", self.open_snapshots_folder, self.no_snapshots_toast)
+ self.new_button.connect("clicked", lambda *_: NewSnapshotDialog().present(HostInfo.main_window))
# Apply
self.loading_view.set_content(LoadingStatus(_("Loading Snapshots"), _("This should only take a moment")))
diff --git a/src/warehouse.gresource.xml b/src/warehouse.gresource.xml
index 1e78244..ba13402 100644
--- a/src/warehouse.gresource.xml
+++ b/src/warehouse.gresource.xml
@@ -20,6 +20,7 @@
snapshot_page/snapshot_page.ui
snapshot_page/snapshots_list_page.ui
snapshot_page/snapshot_box.ui
+ snapshot_page/new_snapshot_dialog.ui
install_page/install_page.ui
install_page/result_row.ui
install_page/select_page.ui