diff --git a/data/com.github.marhkb.Pods.metainfo.xml.in.in b/data/com.github.marhkb.Pods.metainfo.xml.in.in index a64ede07..89780409 100644 --- a/data/com.github.marhkb.Pods.metainfo.xml.in.in +++ b/data/com.github.marhkb.Pods.metainfo.xml.in.in @@ -38,6 +38,16 @@ https://github.com/marhkb/pods/issues + + +

Pods 2.2.0 contains the following changes:

+

Features

+
    +
  • The search entry to a toggle button in the headerbar. (#830)
  • +
  • Search is now possible in the connection chooser page. (#830)
  • +
+
+

Pods 2.1.0 contains the following changes:

diff --git a/src/main.rs b/src/main.rs index 2a07971e..4ef3f021 100644 --- a/src/main.rs +++ b/src/main.rs @@ -240,7 +240,6 @@ fn init() { view::RepoTagSimpleRow::static_type(); view::ScalableTextViewPage::static_type(); view::SearchPanel::static_type(); - view::SearchRow::static_type(); view::VolumeRow::static_type(); view::VolumesGroup::static_type(); view::VolumesPanel::static_type(); diff --git a/src/resources.gresource.xml b/src/resources.gresource.xml index 9dfd3c1b..c88c4535 100644 --- a/src/resources.gresource.xml +++ b/src/resources.gresource.xml @@ -68,7 +68,6 @@ view/repo_tag_simple_row.ui view/scalable_text_view_page.ui view/search_panel.ui - view/search_row.ui view/shortcuts.ui view/top_page.ui view/top_page_action_bar.ui diff --git a/src/view/client_view.rs b/src/view/client_view.rs index 685f6fcd..88f83a6c 100644 --- a/src/view/client_view.rs +++ b/src/view/client_view.rs @@ -10,8 +10,6 @@ use crate::model; use crate::utils; use crate::view; -const ACTION_GLOBAL_SEARCH: &str = "client-view.global-search"; -const ACTION_PANEL_SEARCH: &str = "client-view.panel-search"; const ACTION_SHOW_CONNECTIONS: &str = "client-view.show-connections"; const ACTION_SHOW_ACTIONS: &str = "client-view.show-actions"; const ACTION_CANCEL_OR_DELETE_ACTION: &str = "client-view.cancel-or-delete-action"; @@ -33,13 +31,17 @@ mod imp { #[template_child] pub(super) sidebar_navigation_view: TemplateChild, #[template_child] + pub(super) search_button: TemplateChild, + #[template_child] pub(super) sidebar_list_box: TemplateChild, #[template_child] - pub(super) content_navigation_view: TemplateChild, + pub(super) stack: TemplateChild, + #[template_child] + pub(super) panels_navigation_view: TemplateChild, #[template_child] - pub(super) content_navigation_page: TemplateChild, + pub(super) panels_navigation_page: TemplateChild, #[template_child] - pub(super) panel_stack: TemplateChild, + pub(super) panels_stack: TemplateChild, #[template_child] pub(super) containers_panel: TemplateChild, #[template_child] @@ -49,6 +51,8 @@ mod imp { #[template_child] pub(super) volumes_panel: TemplateChild, #[template_child] + pub(super) search_navigation_view: TemplateChild, + #[template_child] pub(super) color_bin: TemplateChild, } @@ -62,24 +66,6 @@ mod imp { klass.bind_template(); klass.bind_template_callbacks(); - klass.add_binding_action( - gdk::Key::F, - gdk::ModifierType::CONTROL_MASK | gdk::ModifierType::SHIFT_MASK, - ACTION_GLOBAL_SEARCH, - ); - klass.install_action(ACTION_GLOBAL_SEARCH, None, |widget, _, _| { - widget.global_search(); - }); - - klass.add_binding_action( - gdk::Key::F, - gdk::ModifierType::CONTROL_MASK, - ACTION_PANEL_SEARCH, - ); - klass.install_action(ACTION_PANEL_SEARCH, None, |widget, _, _| { - widget.toggle_panel_search(); - }); - klass.install_action(ACTION_SHOW_CONNECTIONS, None, |widget, _, _| { widget.show_connections(); }); @@ -130,7 +116,7 @@ mod imp { self.settings .bind( "last-used-view", - &self.panel_stack.get(), + &self.panels_stack.get(), "visible-child-name", ) .build(); @@ -138,9 +124,7 @@ mod imp { self.sidebar_list_box.set_header_func(|row, _| { row.set_header( row.child() - .filter(|child| { - child.is::() || child.is::() - }) + .filter(gtk::Widget::is::) .map(|_| { gtk::Separator::builder() .orientation(gtk::Orientation::Horizontal) @@ -155,7 +139,7 @@ mod imp { .style_context() .add_provider(&self.css_provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION); - self.on_panel_stack_notify_visible_child(); + self.on_panels_stack_notify_visible_child(); } fn dispose(&self) { @@ -167,11 +151,25 @@ mod imp { #[gtk::template_callbacks] impl ClientView { + #[template_callback] + fn on_key_pressed( + &self, + key: gdk::Key, + _: u32, + _: gdk::ModifierType, + _: >k::EventControllerKey, + ) -> glib::Propagation { + if key == gdk::Key::Escape { + self.search_button.set_active(false); + } + glib::Propagation::Proceed + } + #[template_callback] fn on_notify_client(&self) { self.exit_panel_search_mode(); self.sidebar_navigation_view.pop_to_tag("home"); - self.content_navigation_view.pop_to_tag("home"); + self.panels_navigation_view.pop_to_tag("home"); if let Some(client) = self.obj().client() { self.set_background(client.connection().rgb()); @@ -181,6 +179,7 @@ mod imp { #[template_callback] fn on_navigation_split_view_notify_show_content(&self) { if self.navigation_split_view.is_collapsed() { + self.search_button.set_active(false); self.sidebar_list_box.select_row(gtk::ListBoxRow::NONE); self.exit_selection_mode(); } @@ -190,22 +189,20 @@ mod imp { fn on_navigation_split_view_notify_collapsed(&self) { if !self.navigation_split_view.is_collapsed() { self.navigation_split_view.set_show_content(true); + self.restore_sidebar(); + } + } - self.sidebar_list_box.select_row( - self.sidebar_list_box - .row_at_index( - match self.panel_stack.visible_child_name().unwrap().as_str() { - "containers" => 0, - "pods" => 1, - "images" => 2, - "volumes" => 3, - "info" => 4, - "search" => 5, - _ => unreachable!(), - }, - ) - .as_ref(), - ); + #[template_callback] + fn on_search_button_toggled(&self) { + if self.search_button.is_active() { + self.stack.set_visible_child_name("search"); + self.sidebar_list_box.select_row(gtk::ListBoxRow::NONE); + self.navigation_split_view.set_show_content(true); + } else if !self.navigation_split_view.is_collapsed() { + self.stack.set_visible_child_name("panels"); + self.search_navigation_view.pop_to_tag("home"); + self.restore_sidebar(); } } @@ -214,7 +211,7 @@ mod imp { if let Some(row) = row { let child = row.child().unwrap(); - self.panel_stack + self.panels_stack .set_visible_child_name(if child.is::() { "containers" } else if child.is::() { @@ -225,14 +222,16 @@ mod imp { "volumes" } else if child.is::() { "info" - } else if child.is::() { - "search" } else { unreachable!() }); - self.content_navigation_view.pop_to_tag("home"); + self.stack.set_visible_child_name("panels"); + self.panels_navigation_view.pop_to_tag("home"); + self.search_navigation_view.pop_to_tag("home"); self.navigation_split_view.set_show_content(true); + + self.search_button.set_active(false); } } @@ -242,9 +241,9 @@ mod imp { } #[template_callback] - fn on_panel_stack_notify_visible_child(&self) { - self.content_navigation_page.set_title(&match self - .panel_stack + fn on_panels_stack_notify_visible_child(&self) { + self.panels_navigation_page.set_title(&match self + .panels_stack .visible_child_name() .unwrap() .as_str() @@ -254,13 +253,33 @@ mod imp { "images" => gettext("Images"), "volumes" => gettext("Volumes"), "info" => gettext("Info"), - "search" => gettext("Search"), _ => unreachable!(), }); self.exit_selection_mode(); } + fn restore_sidebar(&self) { + match self.stack.visible_child_name().as_deref() { + Some("search") => self.search_button.set_active(true), + Some("panels") => self.sidebar_list_box.select_row( + self.sidebar_list_box + .row_at_index( + match self.panels_stack.visible_child_name().unwrap().as_str() { + "containers" => 0, + "pods" => 1, + "images" => 2, + "volumes" => 3, + "info" => 4, + _ => unreachable!(), + }, + ) + .as_ref(), + ), + _ => {} + } + } + fn exit_panel_search_mode(&self) { self.containers_panel.set_search_mode(false); self.pods_panel.set_search_mode(false); @@ -298,27 +317,28 @@ glib::wrapper! { impl ClientView { pub(crate) fn navigation_view(&self) -> &adw::NavigationView { - &self.imp().content_navigation_view + &self.imp().panels_navigation_view } - pub(crate) fn global_search(&self) { - self.imp() - .sidebar_list_box - .row_at_index(7) - .as_ref() - .unwrap() - .activate(); + pub(crate) fn toggle_global_search(&self) { + let imp = self.imp(); + if imp.client.upgrade().is_some() { + imp.sidebar_navigation_view.pop_to_tag("home"); + imp.search_button.set_active(!imp.search_button.is_active()); + } } pub(crate) fn toggle_panel_search(&self) { let imp = self.imp(); - match imp.panel_stack.visible_child_name().unwrap().as_str() { - "containers" => imp.containers_panel.toggle_search_mode(), - "pods" => imp.pods_panel.toggle_search_mode(), - "images" => imp.images_panel.toggle_search_mode(), - "volumes" => imp.volumes_panel.toggle_search_mode(), - _ => {} + if imp.stack.visible_child_name().as_deref() == Some("panels") { + match imp.panels_stack.visible_child_name().unwrap().as_str() { + "containers" => imp.containers_panel.toggle_search_mode(), + "pods" => imp.pods_panel.toggle_search_mode(), + "images" => imp.images_panel.toggle_search_mode(), + "volumes" => imp.volumes_panel.toggle_search_mode(), + _ => {} + } } } diff --git a/src/view/client_view.ui b/src/view/client_view.ui index 24df367e..ab328728 100644 --- a/src/view/client_view.ui +++ b/src/view/client_view.ui @@ -47,6 +47,13 @@ + + + + capture + + + @@ -59,21 +66,9 @@ - - client-view.show-actions - Actions - - - PdsClientView - - - - - - PdsClientView - - - + + + system-search-symbolic @@ -94,6 +89,25 @@ + + + client-view.show-actions + Actions + + + PdsClientView + + + + + + PdsClientView + + + + + + @@ -157,10 +171,6 @@ - - - - @@ -223,105 +233,141 @@ Content - + - - home + + panels - - - - True + + - - containers - - - - - PdsClientView - - - - - - + + home - - - pods - - - - PdsClientView - - - - - - + + + True - - - images - - - - - PdsClientView - - - - - - + + + containers + + + + + PdsClientView + + + + + + - - - volumes - - - - - PdsClientView - - - - - - + + + pods + + + + + PdsClientView + + + + + + + + + + images + + + + + PdsClientView + + + + + + + + + + volumes + + + + + PdsClientView + + + + + + + + + + info + + + + PdsClientView + + + + + - - - info - - - - PdsClientView - + + + + + + + + + + search + + + - - search + + home + Home + + + + + + capture + + + PdsClientView + - + diff --git a/src/view/connection_chooser_page.rs b/src/view/connection_chooser_page.rs index 39890056..c39abdf6 100644 --- a/src/view/connection_chooser_page.rs +++ b/src/view/connection_chooser_page.rs @@ -1,8 +1,11 @@ +use std::cell::OnceCell; + use adw::prelude::*; use adw::subclass::prelude::*; use gettextrs::gettext; use glib::clone; use glib::Properties; +use gtk::gdk; use gtk::glib; use gtk::CompositeTemplate; @@ -17,9 +20,16 @@ mod imp { #[properties(wrapper_type = super::ConnectionChooserPage)] #[template(resource = "/com/github/marhkb/Pods/ui/view/connection_chooser_page.ui")] pub(crate) struct ConnectionChooserPage { + pub(super) filter: OnceCell, #[property(get, set, nullable)] pub(crate) connection_manager: glib::WeakRef, #[template_child] + pub(super) filter_button: TemplateChild, + #[template_child] + pub(super) title_stack: TemplateChild, + #[template_child] + pub(super) filter_entry: TemplateChild, + #[template_child] pub(super) connection_list_box: TemplateChild, } @@ -62,17 +72,60 @@ mod imp { #[gtk::template_callbacks] impl ConnectionChooserPage { + #[template_callback] + fn on_filter_button_toggled(&self) { + if self.filter_button.is_active() { + self.filter_entry.grab_focus(); + self.title_stack.set_visible_child(&self.filter_entry.get()); + } else { + self.filter_entry.set_text(""); + self.title_stack.set_visible_child_name("title"); + } + } + + #[template_callback] + fn on_filter_started(&self) { + self.filter_button.set_active(true) + } + + #[template_callback] + fn on_filter_changed(&self) { + self.filter().changed(gtk::FilterChange::Different); + } + + #[template_callback] + fn on_filter_key_pressed( + &self, + key: gdk::Key, + _: u32, + _: gdk::ModifierType, + _: >k::EventControllerKey, + ) -> glib::Propagation { + if key == gdk::Key::Escape { + self.obj().enable_filter_mode(false); + } + // else if key == gdk::Key::KP_Enter { + // self.obj().activate_action(ACTION_SELECT, None).unwrap(); + // } + + glib::Propagation::Proceed + } + #[template_callback] fn on_notify_connection_manager(&self) { let obj = self.obj(); - self.connection_list_box - .bind_model(obj.connection_manager().as_ref(), |item| { - gtk::ListBoxRow::builder() - .selectable(false) - .child(&view::ConnectionRow::from(item.downcast_ref().unwrap())) - .build() - .upcast() - }); + + let model = + gtk::FilterListModel::new(obj.connection_manager(), Some(self.filter().to_owned())); + + // self.connection_list_box.set_filter_func(filter_func); + self.connection_list_box.bind_model(Some(&model), |item| { + gtk::ListBoxRow::builder() + .selectable(false) + .child(&view::ConnectionRow::from(item.downcast_ref().unwrap())) + .build() + .upcast() + }); } #[template_callback] @@ -114,6 +167,27 @@ mod imp { ); } } + + pub(super) fn filter(&self) -> >k::Filter { + let obj = &*self.obj(); + + self.filter.get_or_init(|| { + gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |item| { + let term = obj.imp().filter_entry.text().to_lowercase(); + let connection = item.downcast_ref::().unwrap(); + + connection.name().to_lowercase().contains(&term) + || connection.url().to_lowercase().contains(&term) + } + )) + .upcast() + }) + } } } @@ -122,3 +196,18 @@ glib::wrapper! { @extends gtk::Widget, @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget; } + +impl ConnectionChooserPage { + pub(crate) fn toggle_filter_mode(&self) { + self.enable_filter_mode(!self.imp().filter_button.is_active()); + } + + pub(crate) fn enable_filter_mode(&self, enable: bool) { + let imp = self.imp(); + + imp.filter_button.set_active(enable); + if !enable { + imp.filter().changed(gtk::FilterChange::LessStrict); + } + } +} diff --git a/src/view/connection_chooser_page.ui b/src/view/connection_chooser_page.ui index 6bccafd7..1a8d8da8 100644 --- a/src/view/connection_chooser_page.ui +++ b/src/view/connection_chooser_page.ui @@ -7,12 +7,59 @@ + + + + + + - False + + + system-search-symbolic + Filter + + + + + + + crossfade + + + + title + + + + + + + + + + + + + + + 32 + + + + + + + + + + + + diff --git a/src/view/mod.rs b/src/view/mod.rs index 3354ab56..630f6ca6 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -68,7 +68,6 @@ mod repo_tag_selection_page; mod repo_tag_simple_row; mod scalable_text_view_page; mod search_panel; -mod search_row; mod top_page; mod value_row; mod volume; @@ -155,7 +154,6 @@ pub(crate) use self::scalable_text_view_page::Entity; pub(crate) use self::scalable_text_view_page::Mode as ScalableTextViewMode; pub(crate) use self::scalable_text_view_page::ScalableTextViewPage; pub(crate) use self::search_panel::SearchPanel; -pub(crate) use self::search_row::SearchRow; pub(crate) use self::top_page::TopPage; pub(crate) use self::value_row::ValueRow; pub(crate) use self::volume_creation_page::VolumeCreationPage; diff --git a/src/view/search_row.rs b/src/view/search_row.rs deleted file mode 100644 index 5af9de03..00000000 --- a/src/view/search_row.rs +++ /dev/null @@ -1,40 +0,0 @@ -use adw::subclass::prelude::*; -use gtk::glib; -use gtk::CompositeTemplate; - -use crate::utils; - -mod imp { - use super::*; - - #[derive(Debug, Default, CompositeTemplate)] - #[template(resource = "/com/github/marhkb/Pods/ui/view/search_row.ui")] - pub(crate) struct SearchRow; - - #[glib::object_subclass] - impl ObjectSubclass for SearchRow { - const NAME: &'static str = "PdsSearchRow"; - type Type = super::SearchRow; - type ParentType = gtk::Widget; - - fn class_init(klass: &mut Self::Class) { - klass.bind_template(); - } - - fn instance_init(obj: &glib::subclass::InitializingObject) { - obj.init_template(); - } - } - - impl ObjectImpl for SearchRow { - fn dispose(&self) { - utils::unparent_children(&*self.obj()); - } - } - - impl WidgetImpl for SearchRow {} -} - -glib::wrapper! { - pub(crate) struct SearchRow(ObjectSubclass) @extends gtk::Widget; -} diff --git a/src/view/search_row.ui b/src/view/search_row.ui deleted file mode 100644 index 8ca9cf9c..00000000 --- a/src/view/search_row.ui +++ /dev/null @@ -1,29 +0,0 @@ - - - - diff --git a/src/view/window.rs b/src/view/window.rs index b28aef60..00ede003 100644 --- a/src/view/window.rs +++ b/src/view/window.rs @@ -17,6 +17,8 @@ use crate::utils; use crate::view; const ACTION_CLOSE: &str = "win.close"; +const ACTION_GLOBAL_SEARCH: &str = "win.toggle-global-search"; +const ACTION_SEARCH: &str = "win.toggle-search"; const ACTION_CREATE_CONNECTION: &str = "win.create-connection"; const ACTION_REMOVE_CONNECTION: &str = "win.remove-connection"; @@ -33,6 +35,8 @@ mod imp { #[template_child] pub(super) main_stack: TemplateChild, #[template_child] + pub(super) connection_chooser_page: TemplateChild, + #[template_child] pub(super) client_view: TemplateChild, } @@ -45,6 +49,20 @@ mod imp { fn class_init(klass: &mut Self::Class) { klass.bind_template(); + klass.add_binding_action( + gdk::Key::F, + gdk::ModifierType::CONTROL_MASK | gdk::ModifierType::SHIFT_MASK, + ACTION_GLOBAL_SEARCH, + ); + klass.install_action(ACTION_GLOBAL_SEARCH, None, |widget, _, _| { + widget.toggle_global_search(); + }); + + klass.add_binding_action(gdk::Key::F, gdk::ModifierType::CONTROL_MASK, ACTION_SEARCH); + klass.install_action(ACTION_SEARCH, None, |widget, _, _| { + widget.toggle_search(); + }); + klass.add_binding_action( gdk::Key::N, gdk::ModifierType::CONTROL_MASK | gdk::ModifierType::SHIFT_MASK, @@ -239,6 +257,36 @@ impl Window { glib::Object::builder().property("application", app).build() } + pub(crate) fn toggle_global_search(&self) { + let imp = self.imp(); + + match imp + .main_stack + .visible_child_name() + .unwrap_or_default() + .as_str() + { + "client" => imp.client_view.toggle_global_search(), + "connection-chooser" => imp.connection_chooser_page.toggle_filter_mode(), + _ => {} + } + } + + pub(crate) fn toggle_search(&self) { + let imp = self.imp(); + + match imp + .main_stack + .visible_child_name() + .unwrap_or_default() + .as_str() + { + "client" => imp.client_view.toggle_panel_search(), + "connection-chooser" => imp.connection_chooser_page.toggle_filter_mode(), + _ => {} + } + } + pub(crate) fn connection_manager(&self) -> model::ConnectionManager { self.imp().connection_manager.clone() } diff --git a/src/view/window.ui b/src/view/window.ui index c4096aa0..11c9f2dc 100644 --- a/src/view/window.ui +++ b/src/view/window.ui @@ -31,7 +31,7 @@ connection-chooser - + PdsWindow