diff --git a/data/eye-closed-symbolic.svg b/data/eye-closed-symbolic.svg
new file mode 100644
index 0000000..26417e9
--- /dev/null
+++ b/data/eye-closed-symbolic.svg
@@ -0,0 +1,2 @@
+
+
diff --git a/data/zoodex.gresource.xml b/data/zoodex.gresource.xml
index 9d21967..4b79334 100644
--- a/data/zoodex.gresource.xml
+++ b/data/zoodex.gresource.xml
@@ -2,6 +2,8 @@
application.css
+
+ eye-closed-symbolic.svg
eye-outline-filled-symbolic.svg
diff --git a/src/ui/components/collatable_media_grid/collatable_film_grid.rs b/src/ui/components/collatable_media_grid/collatable_film_grid.rs
index 8da5f15..763d2ff 100644
--- a/src/ui/components/collatable_media_grid/collatable_film_grid.rs
+++ b/src/ui/components/collatable_media_grid/collatable_film_grid.rs
@@ -41,6 +41,9 @@ impl SimpleComponent for CollatableFilmGrid {
FilmCollationMenuOutput::SortBy(sorting, direction) => {
FilmGridInput::SortBy(sorting, direction)
}
+ FilmCollationMenuOutput::ApplyWatchedFilter(watched_filter) => {
+ FilmGridInput::ApplyWatchedFilter(watched_filter)
+ }
},
);
diff --git a/src/ui/components/media_collation_menu/film_collation_menu.rs b/src/ui/components/media_collation_menu/film_collation_menu.rs
index be32ef0..7a3e997 100644
--- a/src/ui/components/media_collation_menu/film_collation_menu.rs
+++ b/src/ui/components/media_collation_menu/film_collation_menu.rs
@@ -1,28 +1,35 @@
use gtk4::prelude::{
- BoxExt, ButtonExt, EntryExt, ListBoxRowExt, ObjectExt, OrientableExt, PopoverExt, WidgetExt,
+ BoxExt, ButtonExt, EntryExt, ListBoxRowExt, ObjectExt, OrientableExt, PopoverExt,
+ ToggleButtonExt, WidgetExt,
};
-use gtk4::{Align, Button, Entry, Label, ListBox, MenuButton, Orientation, Popover};
+use gtk4::{Align, Button, Entry, Label, ListBox, MenuButton, Orientation, Popover, ToggleButton};
use relm4::{ComponentParts, ComponentSender, SimpleComponent, component};
use crate::ui::components::sorting_popover_entry::sorting_popover_entry;
+use crate::ui::filtering::WatchedFilter;
use crate::ui::sorting::{FilmsSorting, SortingDirection};
+use crate::ui::widget_extensions::ComponentSenderExt;
pub struct FilmCollationMenu {
sorted_by: FilmsSorting,
sort_direction: SortingDirection,
+ watched_filter: Option,
}
#[derive(Debug)]
pub enum FilmCollationMenuInput {
SortBy(FilmsSorting),
ToggleSortOrder,
+ ToggleWatchedFilter,
+ ToggleUnwatchedFilter,
}
#[derive(Debug)]
pub enum FilmCollationMenuOutput {
SortBy(FilmsSorting, SortingDirection),
+ ApplyWatchedFilter(Option),
}
#[component(pub)]
@@ -89,12 +96,33 @@ impl SimpleComponent for FilmCollationMenu {
},
},
},
+
Entry {
set_width_request: 230,
set_placeholder_text: Some("Search"),
set_secondary_icon_name: Some("system-search-symbolic"),
set_secondary_icon_sensitive: false,
},
+
+ gtk4::Box {
+ set_orientation: Orientation::Horizontal,
+ set_css_classes: &["linked"],
+
+ ToggleButton {
+ set_icon_name: "eye-outline-filled-symbolic",
+ #[watch]
+ #[block_signal(watched_toggled)]
+ set_active: model.watched_filter == Some(WatchedFilter::OnlyWatched),
+ connect_toggled => FilmCollationMenuInput::ToggleWatchedFilter @watched_toggled,
+ },
+ ToggleButton {
+ set_icon_name: "eye-closed-symbolic",
+ #[watch]
+ #[block_signal(unwatched_toggled)]
+ set_active: model.watched_filter == Some(WatchedFilter::OnlyUnwatched),
+ connect_toggled => FilmCollationMenuInput::ToggleUnwatchedFilter @unwatched_toggled,
+ },
+ },
}
}
@@ -106,6 +134,7 @@ impl SimpleComponent for FilmCollationMenu {
let model = FilmCollationMenu {
sorted_by: FilmsSorting::Name,
sort_direction: SortingDirection::Ascending,
+ watched_filter: None,
};
let widgets = view_output!();
ComponentParts { model, widgets }
@@ -120,7 +149,7 @@ impl SimpleComponent for FilmCollationMenu {
FilmCollationMenuInput::SortBy(sorting) => {
self.sorted_by = sorting;
self.sort_direction = SortingDirection::Ascending;
- sender.output_sender().emit(FilmCollationMenuOutput::SortBy(
+ sender.emit_output(FilmCollationMenuOutput::SortBy(
sorting,
SortingDirection::Ascending,
));
@@ -130,11 +159,37 @@ impl SimpleComponent for FilmCollationMenu {
SortingDirection::Ascending => SortingDirection::Descending,
SortingDirection::Descending => SortingDirection::Ascending,
};
- sender.output_sender().emit(FilmCollationMenuOutput::SortBy(
+ sender.emit_output(FilmCollationMenuOutput::SortBy(
self.sorted_by,
self.sort_direction,
));
}
+ FilmCollationMenuInput::ToggleWatchedFilter => {
+ match self.watched_filter {
+ Some(WatchedFilter::OnlyWatched) => {
+ self.watched_filter = None;
+ }
+ _ => {
+ self.watched_filter = Some(WatchedFilter::OnlyWatched);
+ }
+ }
+ sender.emit_output(FilmCollationMenuOutput::ApplyWatchedFilter(
+ self.watched_filter,
+ ));
+ }
+ FilmCollationMenuInput::ToggleUnwatchedFilter => {
+ match self.watched_filter {
+ Some(WatchedFilter::OnlyUnwatched) => {
+ self.watched_filter = None;
+ }
+ _ => {
+ self.watched_filter = Some(WatchedFilter::OnlyUnwatched);
+ }
+ }
+ sender.emit_output(FilmCollationMenuOutput::ApplyWatchedFilter(
+ self.watched_filter,
+ ));
+ }
}
}
}
diff --git a/src/ui/components/media_collation_menu/series_collation_menu.rs b/src/ui/components/media_collation_menu/series_collation_menu.rs
index 478b8a7..c998282 100644
--- a/src/ui/components/media_collation_menu/series_collation_menu.rs
+++ b/src/ui/components/media_collation_menu/series_collation_menu.rs
@@ -6,6 +6,7 @@ use relm4::{ComponentParts, ComponentSender, SimpleComponent, component};
use crate::ui::components::sorting_popover_entry::sorting_popover_entry;
use crate::ui::sorting::{SeriesSorting, SortingDirection};
+use crate::ui::widget_extensions::ComponentSenderExt;
@@ -118,24 +119,20 @@ impl SimpleComponent for SeriesCollationMenu {
SeriesCollationMenuInput::SortBy(sorting) => {
self.sorted_by = sorting;
self.sort_direction = SortingDirection::Ascending;
- sender
- .output_sender()
- .emit(SeriesCollationMenuOutput::SortBy(
- sorting,
- SortingDirection::Ascending,
- ));
+ sender.emit_output(SeriesCollationMenuOutput::SortBy(
+ sorting,
+ SortingDirection::Ascending,
+ ));
}
SeriesCollationMenuInput::ToggleSortOrder => {
self.sort_direction = match self.sort_direction {
SortingDirection::Ascending => SortingDirection::Descending,
SortingDirection::Descending => SortingDirection::Ascending,
};
- sender
- .output_sender()
- .emit(SeriesCollationMenuOutput::SortBy(
- self.sorted_by,
- self.sort_direction,
- ));
+ sender.emit_output(SeriesCollationMenuOutput::SortBy(
+ self.sorted_by,
+ self.sort_direction,
+ ));
}
}
}
diff --git a/src/ui/components/media_details/film_details.rs b/src/ui/components/media_details/film_details.rs
index 5914f17..99837d7 100644
--- a/src/ui/components/media_details/film_details.rs
+++ b/src/ui/components/media_details/film_details.rs
@@ -4,6 +4,7 @@ use gtk4::{Align, Button, IconSize, Image, Justification, Label, Orientation, To
use relm4::{Component, ComponentParts, ComponentSender, RelmWidgetExt, component};
use crate::persist::data_manager::{DataManager, DataManagerError};
+use crate::ui::widget_extensions::ComponentSenderExt;
use crate::views::overview::FilmOverview;
@@ -97,9 +98,7 @@ impl Component for FilmDetails {
match message {
FilmDetailsInput::WatchedStatusChanged(watched) => {
self.film_overview.watched = watched;
- sender
- .output_sender()
- .emit(FilmDetailsOutput::WatchedStatusChanged(watched));
+ sender.emit_output(FilmDetailsOutput::WatchedStatusChanged(watched));
sender.oneshot_command(clone!(
#[strong(rename_to = uuid)]
diff --git a/src/ui/components/media_grid/film_grid.rs b/src/ui/components/media_grid/film_grid.rs
index 5397968..c9b8c3a 100644
--- a/src/ui/components/media_grid/film_grid.rs
+++ b/src/ui/components/media_grid/film_grid.rs
@@ -6,6 +6,7 @@ use relm4::{Component, ComponentParts, ComponentSender, component};
use crate::persist::data_manager::{DataManager, DataManagerError};
use crate::ui::components::media_grid_item::FilmGridItem;
use crate::ui::factory_sorting::sort_factory_vec;
+use crate::ui::filtering::WatchedFilter;
use crate::ui::sorting::{
FilmsSorting, SortingDirection, cmp_films_by_name, cmp_films_by_rel_date, cmp_films_by_runtime,
};
@@ -20,6 +21,7 @@ pub struct FilmGrid {
#[derive(Debug)]
pub enum FilmGridInput {
SortBy(FilmsSorting, SortingDirection),
+ ApplyWatchedFilter(Option),
}
#[derive(Debug)]
@@ -96,6 +98,7 @@ impl Component for FilmGrid {
}
});
}
+ FilmGridInput::ApplyWatchedFilter(_watched_filter) => {}
}
}
diff --git a/src/ui/filtering.rs b/src/ui/filtering.rs
new file mode 100644
index 0000000..8f00bf5
--- /dev/null
+++ b/src/ui/filtering.rs
@@ -0,0 +1,5 @@
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum WatchedFilter {
+ OnlyWatched,
+ OnlyUnwatched,
+}
diff --git a/src/ui/mod.rs b/src/ui/mod.rs
index c92a42f..31ba8b6 100644
--- a/src/ui/mod.rs
+++ b/src/ui/mod.rs
@@ -1,5 +1,6 @@
mod components;
mod factory_sorting;
+mod filtering;
mod sorting;
mod widget_extensions;
diff --git a/src/ui/widget_extensions.rs b/src/ui/widget_extensions.rs
index a3405dd..d01fc87 100644
--- a/src/ui/widget_extensions.rs
+++ b/src/ui/widget_extensions.rs
@@ -3,6 +3,7 @@ use gtk4::prelude::{BoxExt, IsA};
use gtk4::{Label, Widget};
use libadwaita::Dialog;
use libadwaita::prelude::AdwDialogExt;
+use relm4::{Component, ComponentSender};
@@ -66,3 +67,15 @@ impl AttrListExt for AttrList {
self.insert(AttrFontDesc::new(&font_desc));
}
}
+
+
+
+pub trait ComponentSenderExt {
+ fn emit_output(&self, message: C::Output);
+}
+
+impl ComponentSenderExt for ComponentSender {
+ fn emit_output(&self, message: C::Output) {
+ self.output_sender().emit(message);
+ }
+}