202 lines
5.3 KiB
Rust
202 lines
5.3 KiB
Rust
mod collated_grid;
|
|
mod collation_menu;
|
|
|
|
use std::cmp::Ordering;
|
|
use std::fmt::Debug;
|
|
|
|
use gtk4::prelude::{BoxExt, OrientableExt};
|
|
use gtk4::{Box, Orientation, ScrolledWindow};
|
|
use relm4_macros::view;
|
|
|
|
use crate::data_manager::{FilmOverview, MediaOverview, SeriesOverview};
|
|
use crate::ui::collatable_container::collated_grid::CollatedMediaGrid;
|
|
use crate::ui::collatable_container::collation_menu::MediaCollationMenu;
|
|
use crate::ui::component::Component;
|
|
use crate::ui::utility::{vertical_filler, view_expr};
|
|
use crate::utility::leak;
|
|
|
|
|
|
|
|
pub trait MediaSorting<P: MediaProperty>: Clone + Copy + Debug + Default {
|
|
fn new(property: P, direction: SortingDirection) -> Self;
|
|
fn get_property(&self) -> P;
|
|
fn get_direction(&self) -> SortingDirection;
|
|
}
|
|
|
|
pub trait MediaProperty: Clone + Copy + Debug + PartialEq {}
|
|
|
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
|
pub enum FilmProperty {
|
|
#[default]
|
|
Name,
|
|
ReleaseDate,
|
|
Runtime,
|
|
}
|
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
|
pub enum SeriesProperty {
|
|
#[default]
|
|
Name,
|
|
FirstReleaseDate,
|
|
}
|
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
|
pub enum SortingDirection {
|
|
#[default]
|
|
Ascending,
|
|
Descending,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Default)]
|
|
pub struct FilmsSorting {
|
|
property: FilmProperty,
|
|
direction: SortingDirection,
|
|
}
|
|
#[derive(Clone, Copy, Debug, Default)]
|
|
pub struct SeriesSorting {
|
|
property: SeriesProperty,
|
|
direction: SortingDirection,
|
|
}
|
|
|
|
impl MediaSorting<FilmProperty> for FilmsSorting {
|
|
fn new(property: FilmProperty, direction: SortingDirection) -> Self {
|
|
Self {
|
|
property,
|
|
direction,
|
|
}
|
|
}
|
|
fn get_property(&self) -> FilmProperty {
|
|
self.property
|
|
}
|
|
fn get_direction(&self) -> SortingDirection {
|
|
self.direction
|
|
}
|
|
}
|
|
impl MediaSorting<SeriesProperty> for SeriesSorting {
|
|
fn new(property: SeriesProperty, direction: SortingDirection) -> Self {
|
|
Self {
|
|
property,
|
|
direction,
|
|
}
|
|
}
|
|
fn get_property(&self) -> SeriesProperty {
|
|
self.property
|
|
}
|
|
fn get_direction(&self) -> SortingDirection {
|
|
self.direction
|
|
}
|
|
}
|
|
|
|
impl MediaProperty for FilmProperty {}
|
|
impl MediaProperty for SeriesProperty {}
|
|
|
|
pub struct CollatableMediaContainer<A: MediaAdapter> {
|
|
collated_grid: &'static CollatedMediaGrid<A>,
|
|
widget: Box,
|
|
}
|
|
|
|
impl<A: MediaAdapter> CollatableMediaContainer<A> {
|
|
pub fn new(on_media_selected: impl Fn(A::Overview) + 'static) -> Self {
|
|
let collated_grid = leak(CollatedMediaGrid::new(on_media_selected));
|
|
let collation_menu = MediaCollationMenu::new::<A>(|sorting| collated_grid.set_sorting(sorting));
|
|
|
|
view! {
|
|
widget = gtk4::Box {
|
|
set_orientation: Orientation::Vertical,
|
|
append: collation_menu.get_widget(),
|
|
append: &view_expr! {
|
|
ScrolledWindow {
|
|
set_propagate_natural_height: true,
|
|
set_child: Some(&vertical_filler(collated_grid.get_widget())),
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
Self {
|
|
collated_grid,
|
|
widget,
|
|
}
|
|
}
|
|
|
|
pub async fn set_media(&self, media: Vec<A::Overview>) {
|
|
self
|
|
.collated_grid
|
|
.set_media(media, A::Sorting::default())
|
|
.await;
|
|
}
|
|
}
|
|
|
|
pub trait MediaAdapter: 'static {
|
|
type Overview: MediaOverview;
|
|
type Sorting: MediaSorting<Self::Property>;
|
|
type Property: MediaProperty;
|
|
fn compare_by(
|
|
media_1: &Self::Overview,
|
|
media_2: &Self::Overview,
|
|
sorting: Self::Sorting,
|
|
) -> Ordering;
|
|
fn get_property_descriptions() -> &'static [(Self::Property, &'static str)];
|
|
}
|
|
|
|
impl<A: MediaAdapter> Component for CollatableMediaContainer<A> {
|
|
fn get_widget(&self) -> &Box {
|
|
&self.widget
|
|
}
|
|
}
|
|
|
|
pub struct FilmsAdapter {}
|
|
pub struct SeriesAdapter {}
|
|
|
|
impl MediaAdapter for FilmsAdapter {
|
|
type Overview = FilmOverview;
|
|
type Sorting = FilmsSorting;
|
|
type Property = FilmProperty;
|
|
|
|
fn compare_by(film_1: &FilmOverview, film_2: &FilmOverview, sorting: FilmsSorting) -> Ordering {
|
|
let ordering = match sorting.property {
|
|
FilmProperty::Name => film_1.name.cmp(&film_2.name),
|
|
FilmProperty::ReleaseDate => film_1.release_date.cmp(&film_2.release_date),
|
|
FilmProperty::Runtime => film_1.runtime_minutes.cmp(&film_2.runtime_minutes),
|
|
};
|
|
match sorting.direction {
|
|
SortingDirection::Ascending => ordering,
|
|
SortingDirection::Descending => ordering.reverse(),
|
|
}
|
|
}
|
|
|
|
fn get_property_descriptions() -> &'static [(FilmProperty, &'static str)] {
|
|
leak([
|
|
(FilmProperty::Name, "Name"),
|
|
(FilmProperty::ReleaseDate, "Release date"),
|
|
(FilmProperty::Runtime, "Runtime"),
|
|
])
|
|
}
|
|
}
|
|
impl MediaAdapter for SeriesAdapter {
|
|
type Overview = SeriesOverview;
|
|
type Sorting = SeriesSorting;
|
|
type Property = SeriesProperty;
|
|
|
|
fn compare_by(
|
|
series_1: &SeriesOverview,
|
|
series_2: &SeriesOverview,
|
|
sorting: SeriesSorting,
|
|
) -> Ordering {
|
|
let ordering = match sorting.property {
|
|
SeriesProperty::Name => series_1.name.cmp(&series_2.name),
|
|
SeriesProperty::FirstReleaseDate => series_1
|
|
.first_release_date
|
|
.cmp(&series_2.first_release_date),
|
|
};
|
|
match sorting.direction {
|
|
SortingDirection::Ascending => ordering,
|
|
SortingDirection::Descending => ordering.reverse(),
|
|
}
|
|
}
|
|
|
|
fn get_property_descriptions() -> &'static [(SeriesProperty, &'static str)] {
|
|
leak([
|
|
(SeriesProperty::Name, "Name"),
|
|
(SeriesProperty::FirstReleaseDate, "First release date"),
|
|
])
|
|
}
|
|
}
|