Skip to content

Commit

Permalink
Merge pull request #838 from marhkb/feat/containers-panel/optional-li…
Browse files Browse the repository at this point in the history
…st-view-mode

feat(containers-panel): Allow switching between grid and list view
  • Loading branch information
marhkb authored Oct 12, 2024
2 parents 577bb66 + 280b888 commit f0d3915
Show file tree
Hide file tree
Showing 13 changed files with 701 additions and 104 deletions.
9 changes: 9 additions & 0 deletions data/com.github.marhkb.Pods.gschema.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@
<summary>The last used view</summary>
<description></description>
</key>
<key name="containers-view" type="s">
<choices>
<choice value='grid'/>
<choice value='list'/>
</choices>
<default>'grid'</default>
<summary>Containers representation</summary>
<description></description>
</key>
<key name="hide-intermediate-images" type="b">
<default>false</default>
<summary>Whether to hide intermediate images</summary>
Expand Down
1 change: 1 addition & 0 deletions data/com.github.marhkb.Pods.metainfo.xml.in.in
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
<li>The search entry to a toggle button in the headerbar. (#830)</li>
<li>Search is now possible in the connection chooser page. (#830)</li>
<li>The control elements of the header bar are now moved to a lower bar if space becomes too tight. (#837)</li>
<li>Allow switching between grid and list view in the containers panel. (#838)</li>
</ul>
</description>
</release>
Expand Down
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,9 @@ fn init() {
view::ContainerTerminalPage::static_type();
view::ContainerVolumeRow::static_type();
view::ContainersCountBar::static_type();
view::ContainersGridView::static_type();
view::ContainersGroup::static_type();
view::ContainersListView::static_type();
view::ContainersPanel::static_type();
view::ContainersPrunePage::static_type();
view::ContainersRow::static_type();
Expand Down
2 changes: 2 additions & 0 deletions src/resources.gresource.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
<file compressed="true" preprocess="xml-stripblanks">view/container_terminal_page.ui</file>
<file compressed="true" preprocess="xml-stripblanks">view/container_volume_row.ui</file>
<file compressed="true" preprocess="xml-stripblanks">view/containers_count_bar.ui</file>
<file compressed="true" preprocess="xml-stripblanks">view/containers_grid_view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">view/containers_group.ui</file>
<file compressed="true" preprocess="xml-stripblanks">view/containers_list_view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">view/containers_panel.ui</file>
<file compressed="true" preprocess="xml-stripblanks">view/containers_prune_page.ui</file>
<file compressed="true" preprocess="xml-stripblanks">view/containers_row.ui</file>
Expand Down
164 changes: 141 additions & 23 deletions src/view/container_row.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::cell::RefCell;

use adw::prelude::*;
use adw::subclass::prelude::*;
use gettextrs::gettext;
Expand All @@ -8,6 +10,7 @@ use gtk::glib;
use gtk::CompositeTemplate;

use crate::model;
use crate::model::prelude::*;
use crate::utils;
use crate::view;
use crate::widget;
Expand All @@ -19,30 +22,42 @@ mod imp {
#[properties(wrapper_type = super::ContainerRow)]
#[template(resource = "/com/github/marhkb/Pods/ui/view/container_row.ui")]
pub(crate) struct ContainerRow {
pub(super) bindings: RefCell<Vec<glib::Binding>>,
#[property(get, set, construct, nullable)]
pub(super) container: glib::WeakRef<model::Container>,
#[template_child]
pub(super) spinner: TemplateChild<widget::Spinner>,
// #[template_child]
// pub(super) name_label: TemplateChild<gtk::Label>,
// #[template_child]
// pub(super) repo_label: TemplateChild<gtk::Label>,
#[template_child]
pub(super) check_button_revealer: TemplateChild<gtk::Revealer>,
#[template_child]
pub(super) check_button: TemplateChild<gtk::CheckButton>,
#[template_child]
pub(super) name_label: TemplateChild<gtk::Label>,
#[template_child]
pub(super) pod_image: TemplateChild<gtk::Image>,
#[template_child]
pub(super) repo_label: TemplateChild<gtk::Label>,
#[template_child]
pub(super) ports_flow_box: TemplateChild<gtk::FlowBox>,
#[template_child]
pub(super) stats_box: TemplateChild<gtk::Box>,
#[template_child]
pub(super) cpu_bar: TemplateChild<widget::CircularProgressBar>,
#[template_child]
pub(super) mem_bar: TemplateChild<widget::CircularProgressBar>,
#[template_child]
pub(super) end_box_revealer: TemplateChild<gtk::Revealer>,
}

#[glib::object_subclass]
impl ObjectSubclass for ContainerRow {
const NAME: &'static str = "PdsContainerRow";
type Type = super::ContainerRow;
type ParentType = adw::ActionRow;
type ParentType = gtk::ListBoxRow;

fn class_init(klass: &mut Self::Class) {
klass.bind_template();
klass.bind_template_callbacks();

klass.install_action("container-row.activate", None, |widget, _, _| {
widget.activate();
Expand Down Expand Up @@ -76,9 +91,20 @@ mod imp {
let container_list_expr =
container_expr.chain_property::<model::Container>("container-list");

let selection_mode_expr =
container_list_expr.chain_property::<model::ContainerList>("selection-mode");

selection_mode_expr.bind(&*self.check_button_revealer, "reveal-child", Some(obj));
selection_mode_expr
.chain_closure::<bool>(closure!(|_: Self::Type, is_selection_mode: bool| {
!is_selection_mode
}))
.bind(&*self.end_box_revealer, "reveal-child", Some(obj));

let status_expr = container_expr.chain_property::<model::Container>("status");
let health_status_expr =
container_expr.chain_property::<model::Container>("health-status");
let pod_expr = container_expr.chain_property::<model::Container>("pod");
let stats_expr = container_expr.chain_property::<model::Container>("stats");

container_expr
Expand Down Expand Up @@ -137,14 +163,33 @@ mod imp {
}
}),
)
.bind(obj, "title", Some(obj));
.bind(&*self.name_label, "label", Some(obj));

pod_expr
.chain_closure::<bool>(closure!(
|_: Self::Type, pod: Option<model::Pod>| pod.is_some()
))
.bind(&*self.pod_image, "visible", Some(obj));

gtk::ClosureExpression::new::<bool>(
[
&pod_expr,
&container_expr
.chain_property::<model::Container>("ports")
.chain_property::<model::PortMappingList>("len"),
],
closure!(|_: Self::Type, pod: Option<&model::Pod>, len: u32| {
pod.is_none() && len > 0
}),
)
.bind(&*self.ports_flow_box, "visible", Some(obj));

container_expr
.chain_property::<model::Container>("image-name")
.chain_closure::<String>(closure!(|_: Self::Type, name: Option<String>| {
utils::escape(&utils::format_option(name))
}))
.bind(obj, "subtitle", Some(obj));
.bind(&*self.repo_label, "label", Some(obj));

status_expr
.chain_closure::<bool>(closure!(
Expand Down Expand Up @@ -194,13 +239,78 @@ mod imp {

impl WidgetImpl for ContainerRow {}
impl ListBoxRowImpl for ContainerRow {}
impl PreferencesRowImpl for ContainerRow {}
impl ActionRowImpl for ContainerRow {}

#[gtk::template_callbacks]
impl ContainerRow {
#[template_callback]
fn on_notify_container(&self) {
let mut bindings = self.bindings.borrow_mut();
while let Some(binding) = bindings.pop() {
binding.unbind();
}

let obj = &*self.obj();

if let Some(container) = obj.container() {
let binding = container
.bind_property("selected", &*self.check_button, "active")
.flags(glib::BindingFlags::SYNC_CREATE | glib::BindingFlags::BIDIRECTIONAL)
.build();

bindings.push(binding);

if !container.has_pod() {
self.ports_flow_box.bind_model(
Some(&container.ports()),
clone!(@weak obj => @default-panic, move |item| {
let port_mapping =
item.downcast_ref::<model::PortMapping>().unwrap();

let label = gtk::Label::builder()
.css_classes([
"status-badge-small",
"numeric",
])
.halign(gtk::Align::Center)
.label(format!(
"{}/{}",
port_mapping.host_port(),
port_mapping.protocol()
))
.build();

let css_classes = utils::css_classes(&label);
super::ContainerRow::this_expression("container")
.chain_property::<model::Container>("status")
.chain_closure::<Vec<String>>(closure!(
|_: super::ContainerRow, status: model::ContainerStatus| {
css_classes
.iter()
.cloned()
.chain(Some(String::from(
super::super::container_status_css_class(status)
)))
.collect::<Vec<_>>()
}
))
.bind(&label, "css-classes", Some(&obj));

gtk::FlowBoxChild::builder()
.halign(gtk::Align::Start)
.child(&label)
.build()
.upcast()
}),
);
}
}
}
}
}

glib::wrapper! {
pub(crate) struct ContainerRow(ObjectSubclass<imp::ContainerRow>)
@extends gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow, adw::ActionRow,
@extends gtk::Widget, gtk::ListBoxRow,
@implements gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget;
}

Expand Down Expand Up @@ -248,19 +358,27 @@ impl ContainerRow {

fn activate(&self) {
if let Some(container) = self.container().as_ref() {
let nav_page = adw::NavigationPage::builder()
.child(&view::ContainerDetailsPage::from(container))
.build();

Self::this_expression("container")
.chain_property::<model::Container>("name")
.chain_closure::<String>(closure!(|_: Self, name: &str| gettext!(
"Container {}",
name
)))
.bind(&nav_page, "title", Some(self));

utils::navigation_view(self).push(&nav_page);
if container
.container_list()
.map(|list| list.is_selection_mode())
.unwrap_or(false)
{
container.select();
} else {
let nav_page = adw::NavigationPage::builder()
.child(&view::ContainerDetailsPage::from(container))
.build();

Self::this_expression("container")
.chain_property::<model::Container>("name")
.chain_closure::<String>(closure!(|_: Self, name: &str| gettext!(
"Container {}",
name
)))
.bind(&nav_page, "title", Some(self));

utils::navigation_view(self).push(&nav_page);
}
}
}
}
Loading

0 comments on commit f0d3915

Please sign in to comment.