diff --git a/src/collection.rs b/src/collection.rs deleted file mode 100644 index f25c10a..0000000 --- a/src/collection.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std :: path :: * ; - - - -pub struct Collection { - pub films : Vec , - pub series : Vec , -} - -# [ derive (Clone) ] pub struct Film { - pub uuid : String , - pub name : String , - pub original_name : Option , - pub release_date : String , // TODO: Switch to chrono types, I think rusqlite has crate option for it - pub runtime_minutes : u32 , - pub poster_file_path : Option , -} - -# [ derive (Clone) ] pub struct Series { - pub uuid : String , - pub name : String , - pub original_name : Option , - pub poster_file_path : Option , -} - -pub struct Season <'l> { - pub uuid : String , - pub name : Option , - pub series : & 'l Series , -} - -pub struct Episode <'l> { - pub uuid : String , - pub name : Option , - pub release_date : String , - pub season : & 'l Season <'l> , - pub video_file_path : Option , -} diff --git a/src/main.rs b/src/main.rs index daf9904..1b1ae0b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ -mod collection ; mod error ; mod persistence ; mod ui ; @@ -44,8 +43,9 @@ fn show_window ( app : & Application ) { spawn_future_local ( async move { async_unit_result_context ( async { - let collection = get_collection_from_file () . await ? ; - ui . render_collection (collection) ; + let collection = Collection :: new () . await ? ; + let collection_overview = collection . get_overview () . await ; + ui . render_collection_overview (collection_overview) ; Ok (()) } , |error| { diff --git a/src/persistence.rs b/src/persistence.rs index f8e46a8..2bad8d7 100644 --- a/src/persistence.rs +++ b/src/persistence.rs @@ -8,42 +8,73 @@ use { std :: path :: * , } ; -use crate :: { collection :: * , error :: { * , ZoodexError :: * } } ; +use crate :: error :: { * , ZoodexError :: * } ; -pub async fn get_collection_from_file () -> Result { - let sqlite_client = ClientBuilder :: new () - . path ("zoodex.sqlite") - . flags ( OpenFlags :: SQLITE_OPEN_READ_ONLY | OpenFlags :: SQLITE_OPEN_NO_MUTEX ) - . open () - . await ? ; +pub struct Collection { sqlite_client : Client } - let collection = sqlite_client . conn ( |sqlite_connection| { - let films = sqlite_connection - . prepare ( " - select uuid , name , original_name , release_date , runtime_minutes , poster_file_path - from films - order by release_date desc - " ) ? - . query (()) ? - . map (row_to_film) - . collect () ? ; - let series = sqlite_connection - . prepare ( " - select uuid , name , original_name , poster_file_path - from series - " ) ? - . query (()) ? - . map (row_to_series) - . collect () ? ; - Ok ( Collection { films , series } ) - } ) . await ? ; +impl Collection { + pub async fn new () -> Result { + let sqlite_client = ClientBuilder :: new () + . path ("zoodex.sqlite") + . flags ( OpenFlags :: SQLITE_OPEN_READ_WRITE | OpenFlags :: SQLITE_OPEN_NO_MUTEX ) + . open () + . await ? ; + Ok ( Self { sqlite_client } ) + } - Ok (collection) + pub async fn get_overview ( & self ) -> CollectionOverview { + self . sqlite_client . conn ( |sqlite_connection| { + let films = sqlite_connection + . prepare ( " + select uuid , name , original_name , release_date , runtime_minutes , poster_file_path + from films + order by release_date desc + " ) ? + . query (()) ? + . map (row_to_film_overview) + . collect () ? ; + + let series = sqlite_connection + . prepare ( " + select series . uuid , series . name , series . original_name , series . poster_file_path , + min ( episodes . release_date ) + from series , seasons , episodes + where series . uuid = seasons . series and seasons . uuid = episodes . season + group by series . uuid + " ) ? + . query (()) ? + . map (row_to_series_overview) + . collect () ? ; + + Ok ( CollectionOverview { films , series } ) + } ) . await . unwrap () + } } -fn row_to_film ( row : & Row ) -> rusqlite :: Result { +pub struct CollectionOverview { + pub films : Vec , + pub series : Vec , +} + +# [ derive (Clone) ] pub struct FilmOverview { + pub uuid : String , + pub name : String , + pub original_name : Option , + pub release_date : String , // TODO: Switch to chrono types, I think rusqlite has crate option for it + pub runtime_minutes : u32 , + pub poster_file_path : Option , +} +# [ derive (Clone) ] pub struct SeriesOverview { + pub uuid : String , + pub name : String , + pub original_name : Option , + pub first_release_date : String , // TODO: Switch to chrono types, I think rusqlite has crate option for it + pub poster_file_path : Option , +} + +fn row_to_film_overview ( row : & Row ) -> rusqlite :: Result { let uuid = row . get (0) ? ; let name = row . get (1) ? ; let original_name = row . get (2) ? ; @@ -52,7 +83,7 @@ fn row_to_film ( row : & Row ) -> rusqlite :: Result { let poster_file_path = row . get :: < _ , Option > (5) ? . map ( PathBuf :: from ) ; - Ok ( Film { + Ok ( FilmOverview { uuid , name , original_name , @@ -61,15 +92,15 @@ fn row_to_film ( row : & Row ) -> rusqlite :: Result { poster_file_path , } ) } - -fn row_to_series ( row : & Row ) -> rusqlite :: Result { +fn row_to_series_overview ( row : & Row ) -> rusqlite :: Result { let uuid = row . get (0) ? ; let name = row . get (1) ? ; let original_name = row . get (2) ? ; let poster_file_path = row. get :: < _ , Option > (3) ? . map ( PathBuf :: from ) ; + let first_release_date = row . get (4) ? ; - Ok ( Series { uuid , name , original_name , poster_file_path } ) + Ok ( SeriesOverview { uuid , name , original_name , first_release_date , poster_file_path } ) } impl From for ZoodexError { diff --git a/src/ui/collatable_container/collated_grid.rs b/src/ui/collatable_container/collated_grid.rs index 5fca71f..409e74a 100644 --- a/src/ui/collatable_container/collated_grid.rs +++ b/src/ui/collatable_container/collated_grid.rs @@ -9,21 +9,21 @@ use { std :: { cell :: * , iter :: * , path :: Path } , } ; -use crate :: { collection :: * , ui :: { collatable_container :: * , component :: * } } ; +use crate :: ui :: { collatable_container :: * , component :: * } ; pub struct CollatedFilmsGrid { - film_widget_pairs : RefCell < Vec < ( Film , Box ) > > , + film_widget_pairs : RefCell < Vec < ( FilmOverview , Box ) > > , grid_widget : FlowBox , } pub struct CollatedSeriesGrid { - series_widget_pairs : RefCell < Vec < ( Series , Box ) > > , + series_widget_pairs : RefCell < Vec < ( SeriesOverview , Box ) > > , grid_widget : FlowBox , } impl CollatedFilmsGrid { - pub fn new ( films : Vec , sorting : FilmsSorting ) -> Self { + pub fn new ( films : Vec , sorting : FilmsSorting ) -> Self { let grid_widget = flow_box ! ( @ orientation : Horizontal ; @ homogeneous : true ; @@ -37,7 +37,7 @@ impl CollatedFilmsGrid { component } - pub fn set_films ( & self , films : Vec , sorting : FilmsSorting ) { + pub fn set_films ( & self , films : Vec , sorting : FilmsSorting ) { let widgets = films . iter () . map (create_film_entry) . collect :: < Vec <_> > () ; @@ -57,7 +57,7 @@ impl CollatedFilmsGrid { } } - fn sort_film_widget_pairs ( & self , sorting : FilmsSorting ) -> Vec < ( Film , Box ) > { + fn sort_film_widget_pairs ( & self , sorting : FilmsSorting ) -> Vec < ( FilmOverview , Box ) > { let mut sorted = Vec :: from ( self . film_widget_pairs . borrow () . as_slice () ) ; @@ -76,7 +76,7 @@ impl CollatedFilmsGrid { } } impl CollatedSeriesGrid { - pub fn new ( series : Vec , sorting : SeriesSorting ) -> Self { + pub fn new ( series : Vec , sorting : SeriesSorting ) -> Self { let grid_widget = flow_box ! ( @ orientation : Horizontal ; @ homogeneous : true ; @@ -90,7 +90,7 @@ impl CollatedSeriesGrid { component } - pub fn set_series ( & self , series : Vec , sorting : SeriesSorting ) { + pub fn set_series ( & self , series : Vec , sorting : SeriesSorting ) { let widgets = series . iter () . map (create_series_entry) . collect :: < Vec <_> > () ; @@ -110,7 +110,7 @@ impl CollatedSeriesGrid { } } - fn sort_series_widget_pairs ( & self , sorting : SeriesSorting ) -> Vec < ( Series , Box ) > { + fn sort_series_widget_pairs ( & self , sorting : SeriesSorting ) -> Vec < ( SeriesOverview , Box ) > { let mut sorted = Vec :: from ( self . series_widget_pairs . borrow () . as_slice () ) ; @@ -134,7 +134,7 @@ impl Component for CollatedSeriesGrid { fn get_widget ( & self ) -> & FlowBox { & self . grid_widget } } -pub fn create_film_entry ( film : & Film ) -> Box { +pub fn create_film_entry ( film : & FilmOverview ) -> Box { create_collection_item ( film . name . as_str () , film . original_name . as_deref () , @@ -142,7 +142,7 @@ pub fn create_film_entry ( film : & Film ) -> Box { & create_film_details (film) , ) } -pub fn create_series_entry ( series : & Series ) -> Box { +pub fn create_series_entry ( series : & SeriesOverview ) -> Box { create_collection_item ( series . name . as_str () , series . original_name . as_deref () , @@ -201,7 +201,7 @@ fn create_collection_item ( container } -fn create_film_details ( film : & Film ) -> Box { +fn create_film_details ( film : & FilmOverview ) -> Box { g_box ! ( @ orientation : Horizontal ; @ halign : Center ; @@ -210,12 +210,11 @@ fn create_film_details ( film : & Film ) -> Box { label ! ( format ! ( "{}m" , film . runtime_minutes ) . as_str () ) , ) } -fn create_series_details ( series : & Series ) -> Box { +fn create_series_details ( series : & SeriesOverview ) -> Box { g_box ! ( @ orientation : Horizontal ; @ halign : Center ; @ spacing : 20 ; - // TODO - label ! ("????") , + label ! ( series . first_release_date . as_str () ) , ) } diff --git a/src/ui/collatable_container/mod.rs b/src/ui/collatable_container/mod.rs index c70b5b4..7e723c6 100644 --- a/src/ui/collatable_container/mod.rs +++ b/src/ui/collatable_container/mod.rs @@ -4,7 +4,7 @@ mod collation_menu ; use gtk4 :: { * , Orientation :: * , prelude :: * } ; use crate :: { - collection :: * , + persistence :: * , ui :: { component :: * , utility :: * , collatable_container :: { collated_grid :: * , collation_menu :: * } , @@ -63,7 +63,7 @@ pub struct CollatableSeriesContainer { } impl CollatableFilmsContainer { - pub fn new ( films : Vec ) -> Self { + pub fn new ( films : Vec ) -> Self { let collated_grid = leak ( CollatedFilmsGrid :: new ( films , FilmsSorting :: default () ) ) ; let film_collation_menu = FilmCollationMenu :: new ( |sorting| @@ -81,12 +81,12 @@ impl CollatableFilmsContainer { Self { collated_grid , widget } } - pub fn set_films ( & self , films : Vec ) { + pub fn set_films ( & self , films : Vec ) { self . collated_grid . set_films ( films , FilmsSorting :: default () ) ; } } impl CollatableSeriesContainer { - pub fn new ( series : Vec ) -> Self { + pub fn new ( series : Vec ) -> Self { let collated_grid = leak ( CollatedSeriesGrid :: new ( series , SeriesSorting :: default () ) ) ; let series_collation_menu = SeriesCollationMenu :: new ( |sorting| { @@ -105,7 +105,7 @@ impl CollatableSeriesContainer { Self { collated_grid , widget } } - pub fn set_series ( & self , series : Vec ) { + pub fn set_series ( & self , series : Vec ) { self . collated_grid . set_series ( series , SeriesSorting :: default () ) ; } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 8d27a8d..b29b48f 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -10,7 +10,7 @@ use { } ; use crate :: { - collection :: * , + persistence :: * , ui :: { application_header_bar :: * , collatable_container :: * , @@ -53,7 +53,7 @@ impl UI { pub fn close_window ( & self ) { self . window . close () } - pub fn render_collection ( & self , collection : Collection ) { + pub fn render_collection_overview ( & self , collection : CollectionOverview ) { self . films_component . set_films ( collection . films ) ; self . series_component . set_series ( collection . series ) ; }