Implement combining filters for film grid

Refactored filtering logic into separate functions.
This commit is contained in:
Reinout Meliesie 2026-01-29 15:53:55 +01:00
commit b4d75c3c2e
Signed by: zedfrigg
GPG key ID: 3AFCC06481308BC6

View file

@ -16,6 +16,8 @@ use crate::views::overview::FilmOverview;
pub struct FilmGrid {
items: FactoryVecDeque<FilmGridItem>,
watch_filter: Option<WatchFilter>,
name_filter: Option<String>,
}
#[derive(Debug)]
@ -64,7 +66,11 @@ impl Component for FilmGrid {
let items = FactoryVecDeque::builder()
.launch(widgets.grid.clone())
.detach();
let model = FilmGrid { items };
let model = FilmGrid {
items,
watch_filter: None,
name_filter: None,
};
sender.oneshot_command(async move {
let overview = DataManager::films_overview().await;
@ -83,8 +89,6 @@ impl Component for FilmGrid {
_sender: ComponentSender<FilmGrid>,
_root: &ScrolledWindow,
) {
// TODO: Make combining filters work properly or, indeed, at all.
match message {
FilmGridInput::SortBy(sorting, direction) => {
let mut items = self.items.guard();
@ -101,49 +105,14 @@ impl Component for FilmGrid {
}
});
}
FilmGridInput::ApplyWatchFilter(watched_filter) => match watched_filter {
Some(WatchFilter::OnlyWatched) => {
for (index, item) in self.items.iter().enumerate() {
if item.film().watched {
self.items.send(index, FilmGridItemInput::SetVisible(true));
} else {
self.items.send(index, FilmGridItemInput::SetVisible(false));
}
}
}
Some(WatchFilter::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));
}
},
FilmGridInput::ApplyWatchFilter(watch_filter) => {
self.watch_filter = watch_filter;
self.apply_filters();
}
FilmGridInput::ApplyNameFilter(name_filter) => {
self.name_filter = name_filter;
self.apply_filters();
}
}
}
@ -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
}
}