diff --git a/bottles/frontend/bottle-details-view-subpage.blp b/bottles/frontend/bottle-details-view-subpage.blp
new file mode 100644
index 0000000000..967cd6d1d0
--- /dev/null
+++ b/bottles/frontend/bottle-details-view-subpage.blp
@@ -0,0 +1,55 @@
+using Gtk 4.0;
+using Adw 1;
+
+template $BottleDetailsViewSubpage: Adw.NavigationPage {
+ title: bind content_title.title;
+ tag: "subpage";
+
+ child: Adw.ToolbarView {
+ [top]
+ Adw.HeaderBar content_headerbar {
+ show-start-title-buttons: false;
+
+ title-widget: Adw.WindowTitle content_title {};
+
+ [end]
+ Box box_actions {}
+
+ [end]
+ MenuButton btn_operations {
+ visible: false;
+ tooltip-text: _("Operations");
+ popover: pop_tasks;
+
+ Spinner spinner_tasks {}
+
+ styles [
+ "flat",
+ ]
+ }
+ }
+
+ content: Stack stack_bottle {
+ transition-type: crossfade;
+ };
+ };
+}
+
+Popover pop_tasks {
+ Box {
+ orientation: vertical;
+ spacing: 3;
+
+ Box {
+ orientation: vertical;
+
+ ListBox list_tasks {
+ selection-mode: none;
+
+ styles [
+ "content",
+ ]
+ }
+ }
+ }
+}
diff --git a/bottles/frontend/bottle-details-view.blp b/bottles/frontend/bottle-details-view.blp
index 5c4797a0ad..a54fd93e93 100644
--- a/bottles/frontend/bottle-details-view.blp
+++ b/bottles/frontend/bottle-details-view.blp
@@ -1,103 +1,17 @@
using Gtk 4.0;
using Adw 1;
-template $BottleDetailsView: Adw.Bin {
- Adw.Leaflet leaflet {
- can-navigate-back: true;
- can-unfold: false;
- hexpand: true;
-
- Box {
- orientation: vertical;
-
- Adw.HeaderBar sidebar_headerbar {
- show-end-title-buttons: false;
-
- title-widget: Adw.WindowTitle sidebar_title {
- title: _("Details");
- };
-
- [start]
- Button btn_back {
- icon-name: "go-previous-symbolic";
- tooltip-text: _("Go Back");
- }
-
- [end]
- Box default_actions {}
- }
-
- Box default_view {}
+template $BottleDetailsView: Adw.NavigationPage {
+ title: _("Details");
+ tag: "details";
+
+ child: Adw.ToolbarView {
+ [top]
+ Adw.HeaderBar {
+ [end]
+ Box default_actions {}
}
- Adw.LeafletPage {
- navigatable: false;
-
- child: Separator panel_separator {
- orientation: vertical;
-
- styles [
- "sidebar",
- ]
- };
- }
-
- Box content {
- orientation: vertical;
-
- Adw.HeaderBar content_headerbar {
- show-start-title-buttons: false;
-
- title-widget: Adw.WindowTitle content_title {};
-
- [start]
- Button btn_back_sidebar {
- icon-name: "go-previous-symbolic";
- tooltip-text: _("Go Back");
- visible: false;
- }
-
- [end]
- Box box_actions {}
-
- [end]
- MenuButton btn_operations {
- visible: false;
- tooltip-text: _("Operations");
- popover: pop_tasks;
-
- Spinner spinner_tasks {}
-
- styles [
- "flat",
- ]
- }
- }
-
- Stack stack_bottle {
- transition-type: crossfade;
- hexpand: true;
- vexpand: true;
- }
- }
- }
-}
-
-Popover pop_tasks {
- Box {
- orientation: vertical;
- spacing: 3;
-
- Box {
- orientation: vertical;
-
- ListBox list_tasks {
- selection-mode: none;
-
- styles [
- "content",
- ]
- }
- }
- }
+ content: Box default_view {};
+ };
}
diff --git a/bottles/frontend/bottle_details_page.py b/bottles/frontend/bottle_details_page.py
index 57e44ee046..9d03659e35 100644
--- a/bottles/frontend/bottle_details_page.py
+++ b/bottles/frontend/bottle_details_page.py
@@ -106,8 +106,7 @@ def __init__(self, details, config, **kwargs):
# common variables and references
self.window = details.window
self.manager = details.window.manager
- self.stack_bottle = details.stack_bottle
- self.leaflet = details.leaflet
+ self.stack_bottle = details.details_view_subpage.stack_bottle
self.details = details
self.config = config
self.show_hidden = False
@@ -154,10 +153,12 @@ def __change_page(self, _widget, page_name):
the page is not available, it will show the "bottle" page.
"""
if page_name == "taskmanager":
- self.details.view_taskmanager.update(config=self.config)
+ self.details.details_view_subpage.view_taskmanager.update(
+ config=self.config
+ )
try:
self.stack_bottle.set_visible_child_name(page_name)
- self.leaflet.navigate(Adw.NavigationDirection.FORWARD)
+ self.window.main_leaf.push(self.details.details_view_subpage)
except: # pylint: disable=bare-except
pass
diff --git a/bottles/frontend/bottle_details_view.py b/bottles/frontend/bottle_details_view.py
index afe50ab1f8..8a567cb859 100644
--- a/bottles/frontend/bottle_details_view.py
+++ b/bottles/frontend/bottle_details_view.py
@@ -33,68 +33,48 @@
from bottles.frontend.details_task_manager_view import DetailsTaskManagerView
-@Gtk.Template(resource_path="/com/usebottles/bottles/bottle-details-view.ui")
-class BottleDetailsView(Adw.Bin):
- """
- This class is the starting point for all the pages concerning the
- bottle (details, preferences, dependencies ..).
- """
-
- __gtype_name__ = "BottleDetailsView"
- __pages = {}
+@Gtk.Template(resource_path="/com/usebottles/bottles/bottle-details-view-subpage.ui")
+class BottleDetailsViewSubpage(Adw.NavigationPage):
+ __gtype_name__ = "BottleDetailsViewSubpage"
- # region Widgets
- leaflet = Gtk.Template.Child()
- default_view = Gtk.Template.Child()
- stack_bottle = Gtk.Template.Child()
- sidebar_headerbar = Gtk.Template.Child()
- content_headerbar = Gtk.Template.Child()
- default_actions = Gtk.Template.Child()
- box_actions = Gtk.Template.Child()
- content_title = Gtk.Template.Child()
- btn_back = Gtk.Template.Child()
- btn_back_sidebar = Gtk.Template.Child()
- btn_operations = Gtk.Template.Child()
- list_tasks = Gtk.Template.Child()
- pop_tasks = Gtk.Template.Child()
spinner_tasks = Gtk.Template.Child()
+ pop_tasks = Gtk.Template.Child()
+ list_tasks = Gtk.Template.Child()
+ btn_operations = Gtk.Template.Child()
+ content_title = Gtk.Template.Child()
+ box_actions = Gtk.Template.Child()
+ content_headerbar = Gtk.Template.Child()
+ stack_bottle = Gtk.Template.Child()
# endregion
- def __init__(self, window, config: BottleConfig | None = None, **kwargs):
+ def __init__(
+ self, details_view, window, config: BottleConfig | None = None, **kwargs
+ ):
super().__init__(**kwargs)
- # common variables and references
- if config is None:
- config = BottleConfig()
-
+ self.details_view = details_view
self.window = window
- self.manager = window.manager
- self.versioning_manager = window.manager.versioning_manager
self.config = config
- self.queue = QueueManager(add_fn=self.lock_back, end_fn=self.unlock_back)
- self.view_bottle = BottleDetailsPage(self, config)
- self.view_installers = DetailsInstallersView(self, config)
- self.view_dependencies = DetailsDependenciesView(self, config)
- self.view_preferences = DetailsPreferencesPage(self, config)
- self.view_versioning = DetailsVersioningPage(self, config)
- self.view_taskmanager = DetailsTaskManagerView(self, config)
-
- self.btn_back.connect("clicked", self.go_back)
- self.btn_back_sidebar.connect("clicked", self.go_back_sidebar)
- self.window.main_leaf.connect("notify::visible-child", self.unload_view)
- self.default_actions.append(self.view_bottle.actions)
-
- # region signals
- self.stack_bottle.connect("notify::visible-child", self.__on_page_change)
self.btn_operations.connect("activate", self.__on_operations_toggled)
self.btn_operations.connect("notify::visible", self.__spin_tasks_toggle)
- self.leaflet.connect("notify::folded", self.__on_leaflet_folded)
- # endregion
+ self.stack_bottle.connect("notify::visible-child", self.__on_page_change)
RunAsync(self.build_pages)
+ def __spin_tasks_toggle(self, widget, *_args):
+ if widget.get_visible():
+ self.spinner_tasks.start()
+ self.spinner_tasks.set_visible(True)
+ else:
+ self.spinner_tasks.stop()
+ self.spinner_tasks.set_visible(False)
+
+ def __on_operations_toggled(self, widget):
+ if not self.list_tasks.get_first_child():
+ widget.set_visible(False)
+
def set_title(self, title, subtitle: str = ""):
"""
This function is used to set the title of the BottleDetailsView
@@ -103,17 +83,24 @@ def set_title(self, title, subtitle: str = ""):
self.content_title.set_title(title)
self.content_title.set_subtitle(subtitle)
- def __on_leaflet_folded(self, widget, *_args):
- folded = widget.get_folded()
- self.sidebar_headerbar.set_show_end_title_buttons(folded)
- self.content_headerbar.set_show_start_title_buttons(folded)
- self.btn_back_sidebar.set_visible(folded)
+ def set_actions(self, widget: Gtk.Widget = None):
+ """
+ This function is used to set the actions buttons in the headerbar.
+ """
+ while self.box_actions.get_first_child():
+ self.box_actions.remove(self.box_actions.get_first_child())
+
+ if widget:
+ self.box_actions.append(widget)
+
+ def unload_view(self, *_args):
+ while self.stack_bottle.get_first_child():
+ self.stack_bottle.remove(self.stack_bottle.get_first_child())
def __on_page_change(self, *_args):
"""
Update headerbar title according to the current page.
"""
- self.window.toggle_selection_mode(False)
page = self.stack_bottle.get_visible_child_name()
self.set_title(self.__pages[page]["title"], self.__pages[page]["description"])
@@ -163,7 +150,7 @@ def build_pages(self):
def ui_update():
if self.view_bottle.get_parent() is None:
- self.default_view.append(self.view_bottle)
+ self.details_view.default_view.append(self.view_bottle)
self.stack_bottle.add_named(self.view_preferences, "preferences")
self.stack_bottle.add_named(self.view_dependencies, "dependencies")
@@ -176,17 +163,53 @@ def ui_update():
GLib.idle_add(ui_update)
- def set_actions(self, widget: Gtk.Widget = None):
- """
- This function is used to set the actions buttons in the headerbar.
- """
- while self.box_actions.get_first_child():
- self.box_actions.remove(self.box_actions.get_first_child())
- if widget:
- self.box_actions.append(widget)
+@Gtk.Template(resource_path="/com/usebottles/bottles/bottle-details-view.ui")
+class BottleDetailsView(Adw.NavigationPage):
+ """
+ This class is the starting point for all the pages concerning the
+ bottle (details, preferences, dependencies ..).
+ """
+
+ __gtype_name__ = "BottleDetailsView"
+ __pages = {}
+
+ # region Widgets
+ default_view = Gtk.Template.Child()
+ default_actions = Gtk.Template.Child()
+
+ # endregion
+
+ def __init__(self, window, config: BottleConfig | None = None, **kwargs):
+ super().__init__(**kwargs)
- def set_config(self, config: BottleConfig, rebuild_pages=True):
+ # common variables and references
+ if config is None:
+ config = BottleConfig()
+
+ self.window = window
+ self.manager = window.manager
+ self.versioning_manager = window.manager.versioning_manager
+ self.config = config
+ self.queue = QueueManager(add_fn=self.lock_back, end_fn=self.unlock_back)
+
+ self.details_view_subpage = BottleDetailsViewSubpage(self, window, config)
+ self.details_view_subpage.view_bottle = BottleDetailsPage(self, config)
+ self.details_view_subpage.view_installers = DetailsInstallersView(self, config)
+ self.details_view_subpage.view_dependencies = DetailsDependenciesView(
+ self, config
+ )
+ self.details_view_subpage.view_preferences = DetailsPreferencesPage(
+ self, config
+ )
+ self.details_view_subpage.view_versioning = DetailsVersioningPage(self, config)
+ self.details_view_subpage.view_taskmanager = DetailsTaskManagerView(
+ self, config
+ )
+
+ self.default_actions.append(self.details_view_subpage.view_bottle.actions)
+
+ def set_config(self, config: BottleConfig):
"""
This function update widgets according to the bottle
configuration. It also temporarily disable the functions
@@ -196,46 +219,17 @@ def set_config(self, config: BottleConfig, rebuild_pages=True):
self.config = config
# update widgets data with bottle configuration
- self.view_bottle.set_config(config=config)
- self.view_preferences.set_config(config=config)
- self.view_taskmanager.set_config(config=config)
- self.view_installers.update(config=config)
- self.view_versioning.update(config=config)
-
- if rebuild_pages:
- self.build_pages()
-
- def __on_operations_toggled(self, widget):
- if not self.list_tasks.get_first_child():
- widget.set_visible(False)
-
- def __spin_tasks_toggle(self, widget, *_args):
- if widget.get_visible():
- self.spinner_tasks.start()
- self.spinner_tasks.set_visible(True)
- else:
- self.spinner_tasks.stop()
- self.spinner_tasks.set_visible(False)
-
- def go_back(self, _widget=False):
- self.window.main_leaf.navigate(Adw.NavigationDirection.BACK)
-
- def go_back_sidebar(self, *_args):
- self.leaflet.navigate(Adw.NavigationDirection.BACK)
-
- def unload_view(self, *_args):
- while self.stack_bottle.get_first_child():
- self.stack_bottle.remove(self.stack_bottle.get_first_child())
+ self.details_view_subpage.view_bottle.set_config(config=config)
+ self.details_view_subpage.view_preferences.set_config(config=config)
+ self.details_view_subpage.view_taskmanager.set_config(config=config)
+ self.details_view_subpage.view_installers.update(config=config)
+ self.details_view_subpage.view_versioning.update(config=config)
@GtkUtils.run_in_main_loop
- def lock_back(self):
- self.btn_back.set_sensitive(False)
- self.btn_back.set_tooltip_text(_("Operations in progress, please wait."))
+ def lock_back(self): ...
@GtkUtils.run_in_main_loop
- def unlock_back(self):
- self.btn_back.set_sensitive(True)
- self.btn_back.set_tooltip_text(_("Return to your bottles."))
+ def unlock_back(self): ...
def update_runner_label(self, runner: str):
- self.view_bottle.label_runner.set_text(runner)
+ self.details_view_subpage.view_bottle.label_runner.set_text(runner)
diff --git a/bottles/frontend/bottles-list-view.blp b/bottles/frontend/bottles-list-view.blp
index 299ca52141..dab0859f67 100644
--- a/bottles/frontend/bottles-list-view.blp
+++ b/bottles/frontend/bottles-list-view.blp
@@ -1,68 +1,49 @@
using Gtk 4.0;
using Adw 1;
-template $BottlesListView: Adw.Bin {
- ScrolledWindow {
- Box {
- hexpand: true;
- vexpand: true;
- orientation: vertical;
+template $BottlesListView: Stack {
+ StackPage {
+ name: "bottles-list-page";
+ child: Adw.PreferencesPage {
+ Adw.PreferencesGroup group_bottles {
+ ListBox list_bottles {
+ selection-mode: none;
- SearchBar search_bar {
- SearchEntry entry_search {
- placeholder-text: _("Search your bottles…");
- }
- }
-
- Adw.PreferencesPage pref_page {
- Adw.PreferencesGroup group_bottles {
- ListBox list_bottles {
- selection-mode: none;
-
- styles [
- "boxed-list",
- ]
- }
- }
-
- Adw.PreferencesGroup group_steam {
- title: _("Steam Proton");
-
- ListBox list_steam {
- selection-mode: none;
-
- styles [
- "boxed-list",
- ]
- }
+ styles [
+ "boxed-list",
+ ]
}
}
- Adw.StatusPage bottle_status {
- title: _("Bottles");
- hexpand: true;
- vexpand: true;
+ Adw.PreferencesGroup group_steam {
+ title: _("Steam Proton");
- child: Button btn_create {
- valign: center;
- halign: center;
- label: _("Create New Bottle…");
+ ListBox list_steam {
+ selection-mode: none;
styles [
- "suggested-action",
- "pill",
+ "boxed-list",
]
- };
+ }
}
+ };
+ }
- Adw.StatusPage no_bottles_found {
- visible: false;
- icon-name: "system-search-symbolic";
- title: _("No Results Found");
- description: _("Try a different search.");
- hexpand: true;
- vexpand: true;
- }
- }
+ StackPage {
+ name: "empty-page";
+ child: Adw.StatusPage {
+ title: _("Bottles");
+
+ child: Button create_button {
+ valign: center;
+ halign: center;
+ label: _("Create New Bottle…");
+
+ styles [
+ "suggested-action",
+ "pill",
+ ]
+ };
+ };
}
}
diff --git a/bottles/frontend/bottles.gresource.xml b/bottles/frontend/bottles.gresource.xml
index de4e8a7636..ad2404316d 100644
--- a/bottles/frontend/bottles.gresource.xml
+++ b/bottles/frontend/bottles.gresource.xml
@@ -24,6 +24,7 @@
local-resource-row.ui
exclusion-pattern-row.ui
bottle-details-view.ui
+ bottle-details-view-subpage.ui
bottle-details-page.ui
details-dependencies-view.ui
details-installers-view.ui
diff --git a/bottles/frontend/bottles_list_view.py b/bottles/frontend/bottles_list_view.py
index e2cffa18c2..c7538cb8d8 100644
--- a/bottles/frontend/bottles_list_view.py
+++ b/bottles/frontend/bottles_list_view.py
@@ -115,7 +115,7 @@ def set_path(_dialog, response):
def show_details(self, widget=None, config=None):
if config is None:
config = self.config
- self.window.page_details.view_preferences.update_combo_components()
+ self.window.page_details.details_view_subpage.view_preferences.update_combo_components()
self.window.show_details_view(config=config)
def disable(self):
@@ -124,7 +124,7 @@ def disable(self):
@Gtk.Template(resource_path="/com/usebottles/bottles/bottles-list-view.ui")
-class BottlesListView(Adw.Bin):
+class BottlesListView(Gtk.Stack):
__gtype_name__ = "BottlesListView"
__bottles = {}
@@ -133,12 +133,7 @@ class BottlesListView(Adw.Bin):
list_steam = Gtk.Template.Child()
group_bottles = Gtk.Template.Child()
group_steam = Gtk.Template.Child()
- pref_page = Gtk.Template.Child()
- bottle_status = Gtk.Template.Child()
- btn_create = Gtk.Template.Child()
- entry_search = Gtk.Template.Child()
- search_bar = Gtk.Template.Child()
- no_bottles_found = Gtk.Template.Child()
+ create_button = Gtk.Template.Child()
# endregion
@@ -150,32 +145,18 @@ def __init__(self, window, arg_bottle=None, **kwargs):
self.arg_bottle = arg_bottle
# connect signals
- self.btn_create.connect("clicked", self.window.show_add_view)
- self.entry_search.connect("changed", self.__search_bottles)
+ self.create_button.connect("clicked", self.window.show_add_view)
# backend signals
SignalManager.connect(
Signals.ManagerLocalBottlesLoaded, self.update_bottles_list
)
- self.bottle_status.set_icon_name(APP_ID)
+ status_page = self.get_child_by_name("empty-page")
+ status_page.set_icon_name(APP_ID)
self.update_bottles_list()
- def __search_bottles(self, widget, event=None, data=None):
- """
- This function search in the list of bottles the
- text written in the search entry.
- """
- terms = widget.get_text()
- self.list_bottles.set_filter_func(self.__filter_bottles, terms)
- self.list_steam.set_filter_func(self.__filter_bottles, terms)
-
- @staticmethod
- def __filter_bottles(row, terms=None):
- text = row.get_title().lower()
- return terms.lower() in text
-
def update_bottles_list(self, *args) -> None:
self.__bottles = {}
while self.list_bottles.get_first_child():
@@ -187,8 +168,11 @@ def update_bottles_list(self, *args) -> None:
local_bottles = self.window.manager.local_bottles
is_empty_local_bottles = len(local_bottles) == 0
- self.pref_page.set_visible(not is_empty_local_bottles)
- self.bottle_status.set_visible(is_empty_local_bottles)
+ if is_empty_local_bottles:
+ self.set_visible_child_name("empty-page")
+ return
+
+ self.set_visible_child_name("bottles-list-page")
for name, config in local_bottles.items():
_entry = BottleRow(self.window, config)
diff --git a/bottles/frontend/details-versioning-page.blp b/bottles/frontend/details-versioning-page.blp
index 99bc65a74b..8217093e6e 100644
--- a/bottles/frontend/details-versioning-page.blp
+++ b/bottles/frontend/details-versioning-page.blp
@@ -1,24 +1,32 @@
using Gtk 4.0;
using Adw 1;
-template $DetailsVersioningPage: Adw.PreferencesPage {
- Adw.PreferencesPage pref_page {
- Adw.PreferencesGroup {
- ListBox list_states {
- selection-mode: none;
+template $DetailsVersioningPage: Adw.Bin {
+ child: Stack {
+ StackPage {
+ name: "states-list-page";
+ child: Adw.PreferencesPage {
+ Adw.PreferencesGroup {
+ ListBox list_states {
+ selection-mode: none;
- styles [
- "boxed-list",
- ]
- }
+ styles [
+ "boxed-list",
+ ]
+ }
+ }
+ };
}
- }
- Adw.StatusPage status_page {
- icon-name: "preferences-system-time-symbolic";
- title: _("No Snapshots Found");
- description: _("Create your first snapshot to start saving states of your preferences.");
- }
+ StackPage {
+ name: "empty-page";
+ child: Adw.StatusPage {
+ icon-name: "preferences-system-time-symbolic";
+ title: _("No Snapshots Found");
+ description: _("Create your first snapshot to start saving states of your preferences.");
+ };
+ }
+ };
}
Popover pop_context {
diff --git a/bottles/frontend/details_versioning_page.py b/bottles/frontend/details_versioning_page.py
index d83408f328..d09d313387 100644
--- a/bottles/frontend/details_versioning_page.py
+++ b/bottles/frontend/details_versioning_page.py
@@ -28,7 +28,7 @@
@Gtk.Template(resource_path="/com/usebottles/bottles/details-versioning-page.ui")
-class DetailsVersioningPage(Adw.PreferencesPage):
+class DetailsVersioningPage(Adw.Bin):
__gtype_name__ = "DetailsVersioningPage"
__registry = []
@@ -39,8 +39,6 @@ class DetailsVersioningPage(Adw.PreferencesPage):
btn_save = Gtk.Template.Child()
btn_help = Gtk.Template.Child()
entry_state_message = Gtk.Template.Child()
- status_page = Gtk.Template.Child()
- pref_page = Gtk.Template.Child()
btn_add = Gtk.Template.Child()
ev_controller = Gtk.EventControllerKey.new()
@@ -62,6 +60,8 @@ def __init__(self, details, config, **kwargs):
self.btn_help.connect("clicked", open_doc_url, "bottles/versioning")
self.entry_state_message.connect("activate", self.add_state)
+ self.stack = self.get_child()
+
def empty_list(self):
for r in self.__registry:
if r.get_parent() is not None:
@@ -99,10 +99,10 @@ def new_state(_state, active):
self.list_states.append(entry)
def callback(result, error=False):
- self.status_page.set_visible(not result.status)
- self.pref_page.set_visible(result.status)
- self.list_states.set_visible(result.status)
- self.list_states.set_sensitive(result.status)
+ if result.status:
+ self.stack.set_visible_child_name("states-list-page")
+ else:
+ self.stack.set_visible_child_name("empty-page")
def process_states():
GLib.idle_add(self.empty_list)
diff --git a/bottles/frontend/importer-view.blp b/bottles/frontend/importer-view.blp
index 7cd80ccd7b..3dd9b43f5b 100644
--- a/bottles/frontend/importer-view.blp
+++ b/bottles/frontend/importer-view.blp
@@ -1,19 +1,13 @@
using Gtk 4.0;
using Adw 1;
-template $ImporterView: Adw.Bin {
- Box {
- orientation: vertical;
-
- HeaderBar headerbar {
- title-widget: Adw.WindowTitle window_title {};
-
- [start]
- Button btn_back {
- tooltip-text: _("Go Back");
- icon-name: "go-previous-symbolic";
- }
+template $ImporterView: Adw.NavigationPage {
+ title: _("Import");
+ tag: "import";
+ child: Adw.ToolbarView {
+ [top]
+ Adw.HeaderBar {
[end]
Box box_actions {
MenuButton btn_import_backup {
@@ -29,25 +23,31 @@ template $ImporterView: Adw.Bin {
}
}
- Adw.PreferencesPage {
- Adw.StatusPage status_page {
- vexpand: true;
- icon-name: "document-save-symbolic";
- title: _("No Prefixes Found");
- description: _("No external prefixes were found. Does Bottles have access to them?\nUse the icon on the top to import a bottle from a backup.");
- }
+ content: Stack stack {
+ StackPage {
+ name: "importer-page";
+ child: Adw.PreferencesPage {
+ Adw.PreferencesGroup group_prefixes {
- Adw.PreferencesGroup group_prefixes {
- visible: false;
+ ListBox list_prefixes {
+ styles [
+ "boxed-list",
+ ]
+ }
+ }
+ };
+ }
- ListBox list_prefixes {
- styles [
- "boxed-list",
- ]
- }
+ StackPage {
+ name: "empty-page";
+ child: Adw.StatusPage {
+ icon-name: "document-save-symbolic";
+ title: _("No Prefixes Found");
+ description: _("No external prefixes were found. Does Bottles have access to them? Use the icon on the top to import a bottle from a backup.");
+ };
}
- }
- }
+ };
+ };
}
Popover pop_backup {
diff --git a/bottles/frontend/importer_view.py b/bottles/frontend/importer_view.py
index 4a2256f220..f6186abab0 100644
--- a/bottles/frontend/importer_view.py
+++ b/bottles/frontend/importer_view.py
@@ -27,7 +27,7 @@
@Gtk.Template(resource_path="/com/usebottles/bottles/importer-view.ui")
-class ImporterView(Adw.Bin):
+class ImporterView(Adw.NavigationPage):
__gtype_name__ = "ImporterView"
# region Widgets
@@ -35,9 +35,8 @@ class ImporterView(Adw.Bin):
btn_find_prefixes = Gtk.Template.Child()
btn_import_config = Gtk.Template.Child()
btn_import_full = Gtk.Template.Child()
- btn_back = Gtk.Template.Child()
group_prefixes = Gtk.Template.Child()
- status_page = Gtk.Template.Child()
+ stack = Gtk.Template.Child()
# endregion
@@ -50,12 +49,13 @@ def __init__(self, window, **kwargs):
self.import_manager = window.manager.import_manager
# connect signals
- self.btn_back.connect("clicked", self.go_back)
self.btn_find_prefixes.connect("clicked", self.__find_prefixes)
self.btn_import_full.connect("clicked", self.__import_full_bck)
self.btn_import_config.connect("clicked", self.__import_config_bck)
- def __find_prefixes(self, widget):
+ self.__find_prefixes()
+
+ def __find_prefixes(self, *args):
"""
This function remove all entries from the list_prefixes, ask the
manager to find all prefixes in the system and add them to the list
@@ -63,14 +63,13 @@ def __find_prefixes(self, widget):
@GtkUtils.run_in_main_loop
def update(result, error=False):
- widget.set_sensitive(True)
if result.ok:
wineprefixes = result.data.get("wineprefixes")
if len(wineprefixes) == 0:
+ self.stack.set_visible_child_name("empty-page")
return
- self.status_page.set_visible(False)
- self.group_prefixes.set_visible(True)
+ self.stack.set_visible_child_name("importer-page")
while self.list_prefixes.get_first_child():
_w = self.list_prefixes.get_first_child()
@@ -79,8 +78,6 @@ def update(result, error=False):
for prefix in result.data.get("wineprefixes"):
self.list_prefixes.append(ImporterRow(self, prefix))
- widget.set_sensitive(False)
-
RunAsync(self.import_manager.search_wineprefixes, callback=update)
@GtkUtils.run_in_main_loop
@@ -162,6 +159,3 @@ def set_path(_dialog, response):
dialog.set_modal(True)
dialog.connect("response", set_path)
dialog.show()
-
- def go_back(self, *_args):
- self.window.main_leaf.navigate(Adw.NavigationDirection.BACK)
diff --git a/bottles/frontend/installer_dialog.py b/bottles/frontend/installer_dialog.py
index 775c1648ff..bbfd54f2de 100644
--- a/bottles/frontend/installer_dialog.py
+++ b/bottles/frontend/installer_dialog.py
@@ -188,8 +188,7 @@ def set_status(result, error=False):
def __installed(self):
self.set_deletable(False)
self.stack.set_visible_child_name("page_installed")
- self.window.page_details.view_bottle.update_programs()
- self.window.page_details.go_back_sidebar()
+ self.window.page_details.details_view_subpage.view_bottle.update_programs()
def __error(self, error):
self.set_deletable(True)
diff --git a/bottles/frontend/main.py b/bottles/frontend/main.py
index 35855da872..69f43658a6 100644
--- a/bottles/frontend/main.py
+++ b/bottles/frontend/main.py
@@ -299,7 +299,7 @@ def __new_bottle(self, *args):
self.win.show_add_view()
def __show_importer_view(self, widget=False, *args):
- self.win.main_leaf.set_visible_child(self.win.page_importer)
+ self.win.main_leaf.push(self.win.page_importer)
def __show_about_dialog(self, *_args):
developers = [
diff --git a/bottles/frontend/meson.build b/bottles/frontend/meson.build
index 5bf84dd5d2..ce461f4c3e 100644
--- a/bottles/frontend/meson.build
+++ b/bottles/frontend/meson.build
@@ -19,6 +19,7 @@ blueprints = custom_target('blueprints',
'details-task-manager-view.blp',
'details-versioning-page.blp',
'bottle-details-view.blp',
+ 'bottle-details-view-subpage.blp',
'bottle-picker-dialog.blp',
'crash-report-dialog.blp',
'dependencies-check-dialog.blp',
diff --git a/bottles/frontend/operation.py b/bottles/frontend/operation.py
index 086519a5e8..0dee315ab5 100644
--- a/bottles/frontend/operation.py
+++ b/bottles/frontend/operation.py
@@ -59,11 +59,13 @@ def __init__(self, window):
def _new_widget(self, title, cancellable=True) -> TaskRow:
"""create TaskRow widget & add to task list"""
task_entry = TaskRow(self.window, title, cancellable)
- self.window.page_details.list_tasks.append(task_entry)
+ self.window.page_details.details_view_subpage.list_tasks.append(task_entry)
return task_entry
def _set_task_btn_visible(self, visible: bool):
- self.window.page_details.btn_operations.set_visible(visible)
+ self.window.page_details.details_view_subpage.btn_operations.set_visible(
+ visible
+ )
def task_added_handler(self, res: Result):
"""handler for Signals.TaskAdded"""
@@ -86,7 +88,9 @@ def task_removed_handler(self, res: Result):
if task_id not in self._TASK_WIDGETS:
return
- self.window.page_details.list_tasks.remove(self._TASK_WIDGETS[task_id])
+ self.window.page_details.details_view_subpage.list_tasks.remove(
+ self._TASK_WIDGETS[task_id]
+ )
del self._TASK_WIDGETS[task_id]
if len(self._TASK_WIDGETS) == 0:
diff --git a/bottles/frontend/program_row.py b/bottles/frontend/program_row.py
index 620cd041e5..001d962e4b 100644
--- a/bottles/frontend/program_row.py
+++ b/bottles/frontend/program_row.py
@@ -65,7 +65,7 @@ def __init__(
# common variables and references
self.window = window
- self.view_bottle = window.page_details.view_bottle
+ self.view_bottle = window.page_details.details_view_subpage.view_bottle
self.manager = window.manager
self.config = config
self.program = program
diff --git a/bottles/frontend/window.blp b/bottles/frontend/window.blp
index cc3bf7155f..901e732b8e 100644
--- a/bottles/frontend/window.blp
+++ b/bottles/frontend/window.blp
@@ -5,73 +5,87 @@ template $BottlesWindow: Adw.ApplicationWindow {
title: "Bottles";
close-request => $on_close_request();
- Adw.ToastOverlay toasts {
- Adw.Leaflet main_leaf {
- can-unfold: false;
- can-navigate-back: false;
-
- Box {
- orientation: vertical;
-
- HeaderBar headerbar {
- title-widget: Adw.ViewSwitcherTitle view_switcher_title {
- title: "Bottles";
- stack: stack_main;
- };
+ Adw.Breakpoint {
+ condition ("max-width: 450sp")
+ setters {
+ headerbar.title-widget: null;
+ view_switcher_bar.reveal: true;
+ }
+ }
- Button btn_add {
- tooltip-text: _("Create New Bottle");
- icon-name: "list-add-symbolic";
+ content: Adw.ToastOverlay toasts {
+ Adw.NavigationView main_leaf {
+ Adw.NavigationPage {
+ tag: "overview-page";
+ title: _("Overview");
+ child: Adw.ToolbarView {
+ [top]
+ Adw.HeaderBar headerbar {
+ title-widget: Adw.ViewSwitcher view_switcher_title {
+ policy: wide;
+ stack: stack_main;
+ };
+
+ Button btn_add {
+ tooltip-text: _("Create New Bottle");
+ icon-name: "list-add-symbolic";
+ }
+
+ Box box_actions {}
+
+ [end]
+ MenuButton {
+ icon-name: "open-menu-symbolic";
+ menu-model: primary_menu;
+ tooltip-text: _("Main Menu");
+ primary: true;
+ }
+
+ [end]
+ ToggleButton btn_search {
+ tooltip-text: _("Search");
+ icon-name: "system-search-symbolic";
+ visible: false;
+ }
+
+ [end]
+ Button btn_donate {
+ tooltip-text: _("Donate");
+ icon-name: "emblem-favorite-symbolic";
+ }
+
+ [end]
+ Button btn_noconnection {
+ visible: false;
+ tooltip-text: _("You don\'t seem connected to the internet. Without it you will not be able to download essential components. Click this icon when you have reestablished the connection.");
+ icon-name: "network-error-symbolic";
+ }
}
- Box box_actions {}
-
- styles [
- "titlebar",
- ]
-
- [end]
- MenuButton {
- icon-name: "open-menu-symbolic";
- menu-model: primary_menu;
- tooltip-text: _("Main Menu");
- primary: true;
- }
+ [top]
+ Adw.Clamp {
+ maximum-size: 400;
- [end]
- ToggleButton btn_search {
- tooltip-text: _("Search");
- icon-name: "system-search-symbolic";
- visible: false;
+ child: SearchBar search_bar {
+ SearchEntry entry_search {
+ hexpand: true;
+ placeholder-text: _("Search your bottles…");
+ }
+ };
}
- [end]
- Button btn_donate {
- tooltip-text: _("Donate");
- icon-name: "emblem-favorite-symbolic";
- }
+ content: Adw.ViewStack stack_main {
+ enable-transitions: true;
+ };
- [end]
- Button btn_noconnection {
- visible: false;
- tooltip-text: _("You don\'t seem connected to the internet. Without it you will not be able to download essential components. Click this icon when you have reestablished the connection.");
- icon-name: "network-error-symbolic";
+ [bottom]
+ Adw.ViewSwitcherBar view_switcher_bar {
+ stack: stack_main;
}
- }
-
- SearchBar searchbar {}
-
- Adw.ViewStack stack_main {
- vexpand: true;
- }
-
- Adw.ViewSwitcherBar view_switcher_bar {
- stack: stack_main;
- reveal: bind view_switcher_title.title-visible;
- }
+ };
}
}
- }
+ };
}
menu primary_menu {
diff --git a/bottles/frontend/window.py b/bottles/frontend/window.py
index c627e8de9b..5c2eeac31d 100644
--- a/bottles/frontend/window.py
+++ b/bottles/frontend/window.py
@@ -60,11 +60,11 @@ class BottlesWindow(Adw.ApplicationWindow):
btn_donate = Gtk.Template.Child()
btn_noconnection = Gtk.Template.Child()
box_actions = Gtk.Template.Child()
- headerbar = Gtk.Template.Child()
view_switcher_title = Gtk.Template.Child()
- view_switcher_bar = Gtk.Template.Child()
main_leaf = Gtk.Template.Child()
toasts = Gtk.Template.Child()
+ entry_search = Gtk.Template.Child()
+ search_bar = Gtk.Template.Child()
# endregion
# Common variables
@@ -132,7 +132,6 @@ def response(dialog, response, *args):
self.stack_main.add_named(
child=self.page_loading, name="page_loading"
).set_visible(False)
- self.headerbar.add_css_class("flat")
# Signal connections
self.btn_donate.connect(
@@ -143,6 +142,7 @@ def response(dialog, response, *args):
self.btn_add.connect("clicked", self.show_add_view)
self.btn_noconnection.connect("clicked", self.check_for_connection)
self.stack_main.connect("notify::visible-child", self.__on_page_changed)
+ self.entry_search.connect("changed", self.__search_bottles)
# backend signal handlers
self.task_syncer = TaskSyncer(self)
@@ -224,11 +224,8 @@ def set_manager(result: Manager, error=None):
self.page_importer = ImporterView(self)
self.page_library = LibraryView(self)
- self.main_leaf.append(self.page_details)
- self.main_leaf.append(self.page_importer)
-
- self.main_leaf.get_page(self.page_details).set_navigatable(False)
- self.main_leaf.get_page(self.page_importer).set_navigatable(False)
+ self.main_leaf.add(self.page_details)
+ self.main_leaf.add(self.page_importer)
self.stack_main.add_titled(
child=self.page_list, name="page_list", title=_("Bottles")
@@ -237,10 +234,10 @@ def set_manager(result: Manager, error=None):
child=self.page_library, name="page_library", title=_("Library")
).set_icon_name("library-symbolic")
- self.page_list.search_bar.set_key_capture_widget(self)
+ self.search_bar.set_key_capture_widget(self)
self.btn_search.bind_property(
"active",
- self.page_list.search_bar,
+ self.search_bar,
"search-mode-enabled",
GObject.BindingFlags.BIDIRECTIONAL,
)
@@ -261,7 +258,6 @@ def set_manager(result: Manager, error=None):
)
self.lock_ui(False)
- self.headerbar.get_style_context().remove_class("flat")
user_defined_bottles_path = self.manager.data_mgr.get(
UserDataKeys.CustomBottlesPath
@@ -295,6 +291,16 @@ def get_manager():
self.check_crash_log()
+ def __search_bottles(self, widget, event=None, data=None):
+ terms = widget.get_text()
+ self.page_list.list_bottles.set_filter_func(self.__filter_bottles, terms)
+ self.page_list.list_steam.set_filter_func(self.__filter_bottles, terms)
+
+ @staticmethod
+ def __filter_bottles(row, terms=None):
+ text = row.get_title().lower()
+ return terms.lower() in text
+
def send_notification(self, title, text, image="", ignore_user=False):
"""
This method is used to send a notification to the user using
@@ -315,7 +321,7 @@ def go_back(self, *_args):
self.main_leaf.navigate(direction=Adw.NavigationDirection.BACK)
def show_details_view(self, widget=False, config: BottleConfig | None = None):
- self.main_leaf.set_visible_child(self.page_details)
+ self.main_leaf.push(self.page_details)
self.page_details.set_config(config or BottleConfig())
def show_loading_view(self, widget=False):
@@ -334,7 +340,7 @@ def show_list_view(self, widget=False):
self.stack_main.set_visible_child_name("page_list")
def show_importer_view(self, widget=False):
- self.main_leaf.set_visible_child(self.page_importer)
+ self.main_leaf.push(self.page_importer)
def show_prefs_view(self, widget=False, view=0):
preferences_window = PreferencesWindow(self)
@@ -358,13 +364,6 @@ def check_crash_log(self):
if crash_log:
CrashReportDialog(self, crash_log).present()
- def toggle_selection_mode(self, status: bool = True):
- context = self.headerbar.get_style_context()
- if status:
- context.add_class("selection-mode")
- else:
- context.remove_class("selection-mode")
-
def lock_ui(self, status: bool = True):
widgets = [
self.btn_add,