Compare commits

..

2 commits

Author SHA1 Message Date
b4d75c3c2e
Implement combining filters for film grid
Refactored filtering logic into separate functions.
2026-01-29 15:53:55 +01:00
e49b82743d
Make component message verbiage simpler and more consistent 2026-01-29 14:24:28 +01:00
9 changed files with 139 additions and 135 deletions

View file

@ -38,13 +38,13 @@ impl SimpleComponent for CollatableFilmGrid {
let collation_menu = FilmCollationMenu::builder().launch(()).forward( let collation_menu = FilmCollationMenu::builder().launch(()).forward(
film_grid.sender(), film_grid.sender(),
|message| match message { |message| match message {
FilmCollationMenuOutput::SortBy(sorting, direction) => { FilmCollationMenuOutput::SortedBy(sorting, direction) => {
FilmGridInput::SortBy(sorting, direction) FilmGridInput::SortBy(sorting, direction)
} }
FilmCollationMenuOutput::ApplyWatchedFilter(watched_filter) => { FilmCollationMenuOutput::WatchFilterApplied(watched_filter) => {
FilmGridInput::ApplyWatchedFilter(watched_filter) FilmGridInput::ApplyWatchFilter(watched_filter)
} }
FilmCollationMenuOutput::ApplyNameFilter(name_filter) => { FilmCollationMenuOutput::NameFilterApplied(name_filter) => {
FilmGridInput::ApplyNameFilter(name_filter) FilmGridInput::ApplyNameFilter(name_filter)
} }
}, },

View file

@ -39,7 +39,7 @@ impl SimpleComponent for CollatableSeriesGrid {
SeriesCollationMenu::builder() SeriesCollationMenu::builder()
.launch(()) .launch(())
.forward(series_grid.sender(), |message| match message { .forward(series_grid.sender(), |message| match message {
SeriesCollationMenuOutput::SortBy(sorting, direction) => { SeriesCollationMenuOutput::SortedBy(sorting, direction) => {
SeriesGridInput::SortBy(sorting, direction) SeriesGridInput::SortBy(sorting, direction)
} }
}); });

View file

@ -6,7 +6,7 @@ use gtk4::{Align, Button, Entry, Label, ListBox, MenuButton, Orientation, Popove
use relm4::{ComponentParts, ComponentSender, SimpleComponent, component}; use relm4::{ComponentParts, ComponentSender, SimpleComponent, component};
use crate::ui::components::sorting_popover_entry::sorting_popover_entry; use crate::ui::components::sorting_popover_entry::sorting_popover_entry;
use crate::ui::filtering::WatchedFilter; use crate::ui::filtering::WatchFilter;
use crate::ui::sorting::{FilmsSorting, SortingDirection}; use crate::ui::sorting::{FilmsSorting, SortingDirection};
use crate::ui::widget_extensions::ComponentSenderExt; use crate::ui::widget_extensions::ComponentSenderExt;
@ -15,7 +15,7 @@ use crate::ui::widget_extensions::ComponentSenderExt;
pub struct FilmCollationMenu { pub struct FilmCollationMenu {
sorted_by: FilmsSorting, sorted_by: FilmsSorting,
sort_direction: SortingDirection, sort_direction: SortingDirection,
watched_filter: Option<WatchedFilter>, watch_filter: Option<WatchFilter>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -24,14 +24,14 @@ pub enum FilmCollationMenuInput {
ToggleSortOrder, ToggleSortOrder,
ToggleWatchedFilter, ToggleWatchedFilter,
ToggleUnwatchedFilter, ToggleUnwatchedFilter,
NameFilterSet(String), SetNameFilter(String),
} }
#[derive(Debug)] #[derive(Debug)]
pub enum FilmCollationMenuOutput { pub enum FilmCollationMenuOutput {
SortBy(FilmsSorting, SortingDirection), SortedBy(FilmsSorting, SortingDirection),
ApplyWatchedFilter(Option<WatchedFilter>), WatchFilterApplied(Option<WatchFilter>),
ApplyNameFilter(Option<String>), NameFilterApplied(Option<String>),
} }
#[component(pub)] #[component(pub)]
@ -106,7 +106,7 @@ impl SimpleComponent for FilmCollationMenu {
set_secondary_icon_sensitive: false, set_secondary_icon_sensitive: false,
connect_changed[sender] => move |entry| { connect_changed[sender] => move |entry| {
sender.input(FilmCollationMenuInput::NameFilterSet(entry.text().to_string())); sender.input(FilmCollationMenuInput::SetNameFilter(entry.text().to_string()));
}, },
}, },
@ -118,14 +118,14 @@ impl SimpleComponent for FilmCollationMenu {
set_icon_name: "eye-outline-filled-symbolic", set_icon_name: "eye-outline-filled-symbolic",
#[watch] #[watch]
#[block_signal(watched_toggled)] #[block_signal(watched_toggled)]
set_active: model.watched_filter == Some(WatchedFilter::OnlyWatched), set_active: model.watch_filter == Some(WatchFilter::OnlyWatched),
connect_toggled => FilmCollationMenuInput::ToggleWatchedFilter @watched_toggled, connect_toggled => FilmCollationMenuInput::ToggleWatchedFilter @watched_toggled,
}, },
ToggleButton { ToggleButton {
set_icon_name: "eye-closed-symbolic", set_icon_name: "eye-closed-symbolic",
#[watch] #[watch]
#[block_signal(unwatched_toggled)] #[block_signal(unwatched_toggled)]
set_active: model.watched_filter == Some(WatchedFilter::OnlyUnwatched), set_active: model.watch_filter == Some(WatchFilter::OnlyUnwatched),
connect_toggled => FilmCollationMenuInput::ToggleUnwatchedFilter @unwatched_toggled, connect_toggled => FilmCollationMenuInput::ToggleUnwatchedFilter @unwatched_toggled,
}, },
}, },
@ -140,7 +140,7 @@ impl SimpleComponent for FilmCollationMenu {
let model = FilmCollationMenu { let model = FilmCollationMenu {
sorted_by: FilmsSorting::Name, sorted_by: FilmsSorting::Name,
sort_direction: SortingDirection::Ascending, sort_direction: SortingDirection::Ascending,
watched_filter: None, watch_filter: None,
}; };
let widgets = view_output!(); let widgets = view_output!();
ComponentParts { model, widgets } ComponentParts { model, widgets }
@ -159,7 +159,7 @@ impl SimpleComponent for FilmCollationMenu {
FilmsSorting::ReleaseDate => SortingDirection::Descending, FilmsSorting::ReleaseDate => SortingDirection::Descending,
FilmsSorting::Runtime => SortingDirection::Ascending, FilmsSorting::Runtime => SortingDirection::Ascending,
}; };
sender.emit_output(FilmCollationMenuOutput::SortBy( sender.emit_output(FilmCollationMenuOutput::SortedBy(
sorting, sorting,
self.sort_direction, self.sort_direction,
)); ));
@ -169,42 +169,44 @@ impl SimpleComponent for FilmCollationMenu {
SortingDirection::Ascending => SortingDirection::Descending, SortingDirection::Ascending => SortingDirection::Descending,
SortingDirection::Descending => SortingDirection::Ascending, SortingDirection::Descending => SortingDirection::Ascending,
}; };
sender.emit_output(FilmCollationMenuOutput::SortBy( sender.emit_output(FilmCollationMenuOutput::SortedBy(
self.sorted_by, self.sorted_by,
self.sort_direction, self.sort_direction,
)); ));
} }
FilmCollationMenuInput::ToggleWatchedFilter => { FilmCollationMenuInput::ToggleWatchedFilter => {
match self.watched_filter { match self.watch_filter {
Some(WatchedFilter::OnlyWatched) => { Some(WatchFilter::OnlyWatched) => {
self.watched_filter = None; self.watch_filter = None;
} }
_ => { _ => {
self.watched_filter = Some(WatchedFilter::OnlyWatched); self.watch_filter = Some(WatchFilter::OnlyWatched);
} }
} }
sender.emit_output(FilmCollationMenuOutput::ApplyWatchedFilter( sender.emit_output(FilmCollationMenuOutput::WatchFilterApplied(
self.watched_filter, self.watch_filter,
)); ));
} }
FilmCollationMenuInput::ToggleUnwatchedFilter => { FilmCollationMenuInput::ToggleUnwatchedFilter => {
match self.watched_filter { match self.watch_filter {
Some(WatchedFilter::OnlyUnwatched) => { Some(WatchFilter::OnlyUnwatched) => {
self.watched_filter = None; self.watch_filter = None;
} }
_ => { _ => {
self.watched_filter = Some(WatchedFilter::OnlyUnwatched); self.watch_filter = Some(WatchFilter::OnlyUnwatched);
} }
} }
sender.emit_output(FilmCollationMenuOutput::ApplyWatchedFilter( sender.emit_output(FilmCollationMenuOutput::WatchFilterApplied(
self.watched_filter, self.watch_filter,
)); ));
} }
FilmCollationMenuInput::NameFilterSet(name_filter) => { FilmCollationMenuInput::SetNameFilter(name_filter) => {
if name_filter.is_empty() { if name_filter.is_empty() {
sender.emit_output(FilmCollationMenuOutput::ApplyNameFilter(None)); sender.emit_output(FilmCollationMenuOutput::NameFilterApplied(None));
} else { } else {
sender.emit_output(FilmCollationMenuOutput::ApplyNameFilter(Some(name_filter))); sender.emit_output(FilmCollationMenuOutput::NameFilterApplied(Some(
name_filter,
)));
} }
} }
} }

View file

@ -23,7 +23,7 @@ pub enum SeriesCollationMenuInput {
#[derive(Debug)] #[derive(Debug)]
pub enum SeriesCollationMenuOutput { pub enum SeriesCollationMenuOutput {
SortBy(SeriesSorting, SortingDirection), SortedBy(SeriesSorting, SortingDirection),
} }
#[component(pub)] #[component(pub)]
@ -122,7 +122,7 @@ impl SimpleComponent for SeriesCollationMenu {
SeriesSorting::Name => SortingDirection::Ascending, SeriesSorting::Name => SortingDirection::Ascending,
SeriesSorting::FirstReleaseDate => SortingDirection::Descending, SeriesSorting::FirstReleaseDate => SortingDirection::Descending,
}; };
sender.emit_output(SeriesCollationMenuOutput::SortBy( sender.emit_output(SeriesCollationMenuOutput::SortedBy(
sorting, sorting,
self.sort_direction, self.sort_direction,
)); ));
@ -132,7 +132,7 @@ impl SimpleComponent for SeriesCollationMenu {
SortingDirection::Ascending => SortingDirection::Descending, SortingDirection::Ascending => SortingDirection::Descending,
SortingDirection::Descending => SortingDirection::Ascending, SortingDirection::Descending => SortingDirection::Ascending,
}; };
sender.emit_output(SeriesCollationMenuOutput::SortBy( sender.emit_output(SeriesCollationMenuOutput::SortedBy(
self.sorted_by, self.sorted_by,
self.sort_direction, self.sort_direction,
)); ));

View file

@ -15,22 +15,22 @@ pub struct FilmDetails {
#[derive(Debug)] #[derive(Debug)]
pub enum FilmDetailsInput { pub enum FilmDetailsInput {
ToggleWatchedStatus, ToggleWatchStatus,
ToggleDownloadedStatus, ToggleDownloadStatus,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum FilmDetailsOutput { pub enum FilmDetailsOutput {
WatchedStatusChanged(bool), WatchStatusChanged(bool),
DownloadedStatusChanged(bool), DownloadStatusChanged(bool),
} }
#[derive(Debug)] #[derive(Debug)]
pub enum FilmDetailsCmdOutput { pub enum FilmDetailsCmdOutput {
WatchedStatusPersistSucceeded, WatchStatusPersistSucceeded,
WatchedStatusPersistFailed(DataManagerError), WatchStatusPersistFailed(DataManagerError),
DownloadedStatusPersistSucceeded, DownloadStatusPersistSucceeded,
DownloadedStatusPersistFailed(DataManagerError), DownloadStatusPersistFailed(DataManagerError),
} }
#[component(pub)] #[component(pub)]
@ -66,14 +66,14 @@ impl Component for FilmDetails {
#[watch] #[watch]
set_label: if model.film_overview.watched { "Watched" } else { "Watch" }, set_label: if model.film_overview.watched { "Watched" } else { "Watch" },
set_active: model.film_overview.watched, set_active: model.film_overview.watched,
connect_toggled => FilmDetailsInput::ToggleWatchedStatus, connect_toggled => FilmDetailsInput::ToggleWatchStatus,
}, },
ToggleButton { ToggleButton {
#[watch] #[watch]
set_label: if model.film_overview.downloaded { "Downloaded" } else { "Mark downloaded" }, set_label: if model.film_overview.downloaded { "Downloaded" } else { "Mark downloaded" },
set_active: model.film_overview.downloaded, set_active: model.film_overview.downloaded,
connect_toggled => FilmDetailsInput::ToggleDownloadedStatus, connect_toggled => FilmDetailsInput::ToggleDownloadStatus,
}, },
}, },
@ -108,10 +108,10 @@ impl Component for FilmDetails {
_root: &gtk4::Box, _root: &gtk4::Box,
) { ) {
match message { match message {
FilmDetailsInput::ToggleWatchedStatus => { FilmDetailsInput::ToggleWatchStatus => {
let watched = !self.film_overview.watched; let watched = !self.film_overview.watched;
self.film_overview.watched = watched; self.film_overview.watched = watched;
sender.emit_output(FilmDetailsOutput::WatchedStatusChanged(watched)); sender.emit_output(FilmDetailsOutput::WatchStatusChanged(watched));
sender.oneshot_command(clone!( sender.oneshot_command(clone!(
#[strong(rename_to = uuid)] #[strong(rename_to = uuid)]
@ -119,16 +119,16 @@ impl Component for FilmDetails {
async move { async move {
let result = DataManager::set_film_watched_status(uuid.as_str(), watched).await; let result = DataManager::set_film_watched_status(uuid.as_str(), watched).await;
match result { match result {
Ok(()) => FilmDetailsCmdOutput::WatchedStatusPersistSucceeded, Ok(()) => FilmDetailsCmdOutput::WatchStatusPersistSucceeded,
Err(error) => FilmDetailsCmdOutput::WatchedStatusPersistFailed(error), Err(error) => FilmDetailsCmdOutput::WatchStatusPersistFailed(error),
} }
} }
)); ));
} }
FilmDetailsInput::ToggleDownloadedStatus => { FilmDetailsInput::ToggleDownloadStatus => {
let downloaded = !self.film_overview.downloaded; let downloaded = !self.film_overview.downloaded;
self.film_overview.downloaded = downloaded; self.film_overview.downloaded = downloaded;
sender.emit_output(FilmDetailsOutput::DownloadedStatusChanged(downloaded)); sender.emit_output(FilmDetailsOutput::DownloadStatusChanged(downloaded));
sender.oneshot_command(clone!( sender.oneshot_command(clone!(
#[strong(rename_to = uuid)] #[strong(rename_to = uuid)]
@ -136,8 +136,8 @@ impl Component for FilmDetails {
async move { async move {
let result = DataManager::set_film_downloaded_status(uuid.as_str(), downloaded).await; let result = DataManager::set_film_downloaded_status(uuid.as_str(), downloaded).await;
match result { match result {
Ok(()) => FilmDetailsCmdOutput::DownloadedStatusPersistSucceeded, Ok(()) => FilmDetailsCmdOutput::DownloadStatusPersistSucceeded,
Err(error) => FilmDetailsCmdOutput::DownloadedStatusPersistFailed(error), Err(error) => FilmDetailsCmdOutput::DownloadStatusPersistFailed(error),
} }
} }
)); ));
@ -152,12 +152,12 @@ impl Component for FilmDetails {
_root: &gtk4::Box, _root: &gtk4::Box,
) { ) {
match message { match message {
FilmDetailsCmdOutput::WatchedStatusPersistSucceeded => {} FilmDetailsCmdOutput::WatchStatusPersistSucceeded => {}
FilmDetailsCmdOutput::WatchedStatusPersistFailed(error) => { FilmDetailsCmdOutput::WatchStatusPersistFailed(error) => {
println!("Watched status persist failed: {error:?}"); println!("Watched status persist failed: {error:?}");
} }
FilmDetailsCmdOutput::DownloadedStatusPersistSucceeded => {} FilmDetailsCmdOutput::DownloadStatusPersistSucceeded => {}
FilmDetailsCmdOutput::DownloadedStatusPersistFailed(error) => { FilmDetailsCmdOutput::DownloadStatusPersistFailed(error) => {
println!("Downloaded status persist failed: {error:?}"); println!("Downloaded status persist failed: {error:?}");
} }
} }

View file

@ -6,7 +6,7 @@ use relm4::{Component, ComponentParts, ComponentSender, component};
use crate::persist::data_manager::{DataManager, DataManagerError}; use crate::persist::data_manager::{DataManager, DataManagerError};
use crate::ui::components::media_grid_item::{FilmGridItem, FilmGridItemInput}; use crate::ui::components::media_grid_item::{FilmGridItem, FilmGridItemInput};
use crate::ui::factory_sorting::sort_factory_vec; use crate::ui::factory_sorting::sort_factory_vec;
use crate::ui::filtering::WatchedFilter; use crate::ui::filtering::WatchFilter;
use crate::ui::sorting::{ use crate::ui::sorting::{
FilmsSorting, SortingDirection, cmp_films_by_name, cmp_films_by_rel_date, cmp_films_by_runtime, FilmsSorting, SortingDirection, cmp_films_by_name, cmp_films_by_rel_date, cmp_films_by_runtime,
}; };
@ -16,12 +16,14 @@ use crate::views::overview::FilmOverview;
pub struct FilmGrid { pub struct FilmGrid {
items: FactoryVecDeque<FilmGridItem>, items: FactoryVecDeque<FilmGridItem>,
watch_filter: Option<WatchFilter>,
name_filter: Option<String>,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum FilmGridInput { pub enum FilmGridInput {
SortBy(FilmsSorting, SortingDirection), SortBy(FilmsSorting, SortingDirection),
ApplyWatchedFilter(Option<WatchedFilter>), ApplyWatchFilter(Option<WatchFilter>),
ApplyNameFilter(Option<String>), ApplyNameFilter(Option<String>),
} }
@ -64,7 +66,11 @@ impl Component for FilmGrid {
let items = FactoryVecDeque::builder() let items = FactoryVecDeque::builder()
.launch(widgets.grid.clone()) .launch(widgets.grid.clone())
.detach(); .detach();
let model = FilmGrid { items }; let model = FilmGrid {
items,
watch_filter: None,
name_filter: None,
};
sender.oneshot_command(async move { sender.oneshot_command(async move {
let overview = DataManager::films_overview().await; let overview = DataManager::films_overview().await;
@ -83,8 +89,6 @@ impl Component for FilmGrid {
_sender: ComponentSender<FilmGrid>, _sender: ComponentSender<FilmGrid>,
_root: &ScrolledWindow, _root: &ScrolledWindow,
) { ) {
// TODO: Make combining filters work properly or, indeed, at all.
match message { match message {
FilmGridInput::SortBy(sorting, direction) => { FilmGridInput::SortBy(sorting, direction) => {
let mut items = self.items.guard(); let mut items = self.items.guard();
@ -101,49 +105,14 @@ impl Component for FilmGrid {
} }
}); });
} }
FilmGridInput::ApplyWatchedFilter(watched_filter) => match watched_filter { FilmGridInput::ApplyWatchFilter(watch_filter) => {
Some(WatchedFilter::OnlyWatched) => { self.watch_filter = watch_filter;
for (index, item) in self.items.iter().enumerate() { self.apply_filters();
if item.film().watched { }
self.items.send(index, FilmGridItemInput::SetVisible(true)); FilmGridInput::ApplyNameFilter(name_filter) => {
} else { self.name_filter = name_filter;
self.items.send(index, FilmGridItemInput::SetVisible(false)); self.apply_filters();
} }
}
}
Some(WatchedFilter::OnlyUnwatched) => {
for (index, item) in self.items.iter().enumerate() {
if item.film().watched {
self.items.send(index, FilmGridItemInput::SetVisible(false));
} else {
self.items.send(index, FilmGridItemInput::SetVisible(true));
}
}
}
None => {
self.items.broadcast(FilmGridItemInput::SetVisible(true));
}
},
FilmGridInput::ApplyNameFilter(name_filter) => match name_filter {
Some(name_filter) => {
let name_filter = name_filter.to_lowercase();
for (index, item) in self.items.iter().enumerate() {
let name = item.film().name.to_lowercase();
let name_matches = name.contains(name_filter.as_str());
let orig_name = item.film().original_name.as_deref().map(str::to_lowercase);
let orig_name_matches =
orig_name.is_some_and(|orig_name| orig_name.contains(name_filter.as_str()));
if name_matches || orig_name_matches {
self.items.send(index, FilmGridItemInput::SetVisible(true));
} else {
self.items.send(index, FilmGridItemInput::SetVisible(false));
}
}
}
None => {
self.items.broadcast(FilmGridItemInput::SetVisible(true));
}
},
} }
} }
@ -172,3 +141,36 @@ impl Component for FilmGrid {
} }
} }
} }
impl FilmGrid {
fn apply_filters(&mut self) {
for (index, item) in self.items.iter().enumerate() {
let show_item = film_matches_watch_filter(item.film(), self.watch_filter)
&& film_matches_name_filter(item.film(), self.name_filter.as_deref());
self
.items
.send(index, FilmGridItemInput::SetVisible(show_item));
}
}
}
fn film_matches_watch_filter(film: &FilmOverview, filter: Option<WatchFilter>) -> bool {
if let Some(watch_filter) = filter {
match watch_filter {
WatchFilter::OnlyWatched => film.watched,
WatchFilter::OnlyUnwatched => !film.watched,
}
} else {
true
}
}
fn film_matches_name_filter(film: &FilmOverview, filter: Option<&str>) -> bool {
if let Some(name_filter) = filter {
let name_filter = name_filter.to_lowercase();
let name = film.name.to_lowercase();
name.contains(name_filter.as_str())
} else {
true
}
}

View file

@ -28,6 +28,15 @@ impl FilmGridItem {
} }
} }
#[derive(Clone, Copy, Debug)]
pub enum FilmGridItemInput {
ClickOnItem,
CloseDetails,
ChangeWatchStatus(bool),
ChangeDownloadStatus(bool),
SetVisible(bool),
}
#[derive(Debug)] #[derive(Debug)]
pub enum FilmGridItemCmdOutput { pub enum FilmGridItemCmdOutput {
PosterReady(Texture), PosterReady(Texture),
@ -35,15 +44,6 @@ pub enum FilmGridItemCmdOutput {
PosterFailed(DataManagerError), PosterFailed(DataManagerError),
} }
#[derive(Clone, Copy, Debug)]
pub enum FilmGridItemInput {
ItemClicked,
DetailsClosed,
WatchedStatusChanged(bool),
DownloadedStatusChanged(bool),
SetVisible(bool),
}
#[factory(pub)] #[factory(pub)]
impl FactoryComponent for FilmGridItem { impl FactoryComponent for FilmGridItem {
type Init = FilmOverview; type Init = FilmOverview;
@ -60,7 +60,7 @@ impl FactoryComponent for FilmGridItem {
set_visible: self.visible, set_visible: self.visible,
Button { Button {
connect_clicked => FilmGridItemInput::ItemClicked, connect_clicked => FilmGridItemInput::ClickOnItem,
set_css_classes: &["flat", "media-grid-item"], set_css_classes: &["flat", "media-grid-item"],
gtk4::Box { gtk4::Box {
@ -150,7 +150,7 @@ impl FactoryComponent for FilmGridItem {
}), }),
#[watch] #[watch]
set_child: self.details.as_ref().map(ComponentController::widget), set_child: self.details.as_ref().map(ComponentController::widget),
connect_closed => FilmGridItemInput::DetailsClosed, connect_closed => FilmGridItemInput::CloseDetails,
}, },
} }
@ -183,27 +183,27 @@ impl FactoryComponent for FilmGridItem {
fn update(&mut self, message: FilmGridItemInput, sender: FactorySender<FilmGridItem>) { fn update(&mut self, message: FilmGridItemInput, sender: FactorySender<FilmGridItem>) {
match message { match message {
FilmGridItemInput::ItemClicked => { FilmGridItemInput::ClickOnItem => {
let details_controller = FilmDetails::builder().launch(self.film.clone()).forward( let details_controller = FilmDetails::builder().launch(self.film.clone()).forward(
sender.input_sender(), sender.input_sender(),
|film_details_output| match film_details_output { |film_details_output| match film_details_output {
FilmDetailsOutput::WatchedStatusChanged(watched) => { FilmDetailsOutput::WatchStatusChanged(watched) => {
FilmGridItemInput::WatchedStatusChanged(watched) FilmGridItemInput::ChangeWatchStatus(watched)
} }
FilmDetailsOutput::DownloadedStatusChanged(downloaded) => { FilmDetailsOutput::DownloadStatusChanged(downloaded) => {
FilmGridItemInput::DownloadedStatusChanged(downloaded) FilmGridItemInput::ChangeDownloadStatus(downloaded)
} }
}, },
); );
self.details = Some(details_controller); self.details = Some(details_controller);
} }
FilmGridItemInput::DetailsClosed => { FilmGridItemInput::CloseDetails => {
self.details = None; self.details = None;
} }
FilmGridItemInput::WatchedStatusChanged(watched) => { FilmGridItemInput::ChangeWatchStatus(watched) => {
self.film.watched = watched; self.film.watched = watched;
} }
FilmGridItemInput::DownloadedStatusChanged(downloaded) => { FilmGridItemInput::ChangeDownloadStatus(downloaded) => {
self.film.downloaded = downloaded; self.film.downloaded = downloaded;
} }
FilmGridItemInput::SetVisible(visible) => { FilmGridItemInput::SetVisible(visible) => {

View file

@ -27,6 +27,12 @@ impl SeriesGridItem {
} }
} }
#[derive(Debug)]
pub enum SeriesGridItemInput {
ClickOnItem,
CloseDetails,
}
#[derive(Debug)] #[derive(Debug)]
pub enum SeriesGridItemCmdOutput { pub enum SeriesGridItemCmdOutput {
PosterReady(Texture), PosterReady(Texture),
@ -34,12 +40,6 @@ pub enum SeriesGridItemCmdOutput {
PosterFailed(DataManagerError), PosterFailed(DataManagerError),
} }
#[derive(Debug)]
pub enum SeriesGridItemInput {
ItemClicked,
DetailsClosed,
}
#[factory(pub)] #[factory(pub)]
impl FactoryComponent for SeriesGridItem { impl FactoryComponent for SeriesGridItem {
type Init = SeriesOverview; type Init = SeriesOverview;
@ -53,7 +53,7 @@ impl FactoryComponent for SeriesGridItem {
root = FlowBoxChild { root = FlowBoxChild {
set_focusable: false, set_focusable: false,
Button { Button {
connect_clicked => SeriesGridItemInput::ItemClicked, connect_clicked => SeriesGridItemInput::ClickOnItem,
set_css_classes: &["flat", "media-grid-item"], set_css_classes: &["flat", "media-grid-item"],
gtk4::Box { gtk4::Box {
set_orientation: Orientation::Vertical, set_orientation: Orientation::Vertical,
@ -113,7 +113,7 @@ impl FactoryComponent for SeriesGridItem {
}), }),
#[watch] #[watch]
set_child: self.details.as_ref().map(ComponentController::widget), set_child: self.details.as_ref().map(ComponentController::widget),
connect_closed => SeriesGridItemInput::DetailsClosed, connect_closed => SeriesGridItemInput::CloseDetails,
}, },
} }
@ -145,13 +145,13 @@ impl FactoryComponent for SeriesGridItem {
fn update(&mut self, message: SeriesGridItemInput, _sender: FactorySender<SeriesGridItem>) { fn update(&mut self, message: SeriesGridItemInput, _sender: FactorySender<SeriesGridItem>) {
match message { match message {
SeriesGridItemInput::ItemClicked => { SeriesGridItemInput::ClickOnItem => {
let details_controller = SeriesDetails::builder() let details_controller = SeriesDetails::builder()
.launch(self.series.clone()) .launch(self.series.clone())
.detach(); .detach();
self.details = Some(details_controller); self.details = Some(details_controller);
} }
SeriesGridItemInput::DetailsClosed => { SeriesGridItemInput::CloseDetails => {
self.details = None; self.details = None;
} }
} }

View file

@ -1,5 +1,5 @@
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum WatchedFilter { pub enum WatchFilter {
OnlyWatched, OnlyWatched,
OnlyUnwatched, OnlyUnwatched,
} }