mod collated_grid ; mod collation_menu ; use gtk4 :: { Box , ScrolledWindow } ; use gtk4 :: Orientation :: * ; use gtk4 :: prelude :: * ; use std :: cmp :: * ; use std :: fmt :: * ; use crate :: data_manager :: * ; use crate :: ui :: component :: * ; use crate :: ui :: utility :: * ; use crate :: ui :: collatable_container :: collated_grid :: * ; use crate :: ui :: collatable_container :: collation_menu :: * ; use crate :: utility :: * ; 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 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 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 , widget : Box , } impl < A : MediaAdapter > CollatableMediaContainer { 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 :: ( |sorting| collated_grid . set_sorting (sorting) , ) ; let widget = view_expr ! { gtk4 :: Box { set_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 { 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" ) , ] ) } }