mirror of
				https://github.com/johrpan/musicus.git
				synced 2025-10-26 19:57:25 +01:00 
			
		
		
		
	program: Initialize from settings
This commit is contained in:
		
							parent
							
								
									6d11ee9705
								
							
						
					
					
						commit
						f4c36de342
					
				
					 5 changed files with 183 additions and 59 deletions
				
			
		|  | @ -17,5 +17,20 @@ | ||||||
| 			<default>''</default> | 			<default>''</default> | ||||||
| 			<summary>Path to the music library</summary> | 			<summary>Path to the music library</summary> | ||||||
| 		</key> | 		</key> | ||||||
|  | 		<key name="program1" type="s"> | ||||||
|  | 			<!-- Translators: Configuration for the default programs in JSON. Please only translate the values of "title" and "description". --> | ||||||
|  | 			<default l10n="messages">'{"title":"Just play some music","description":"Randomly select some music. Customize programs using the button in the top right.","design":"Program1","prefer_recently_added":0.0,"prefer_least_recently_played":0.0,"play_full_recordings":true}'</default> | ||||||
|  | 			<summary>Default settings for program 1</summary> | ||||||
|  | 		</key> | ||||||
|  | 		<key name="program2" type="s"> | ||||||
|  | 			<!-- Translators: Configuration for the default programs in JSON. Please only translate the values of "title" and "description". --> | ||||||
|  | 			<default l10n="messages">'{"title":"What\'s new?","description":"Recordings that you recently added to your music library.","design":"Program2","prefer_recently_added":1.0,"prefer_least_recently_played":0.0,"play_full_recordings":true}'</default> | ||||||
|  | 			<summary>Default settings for program 2</summary> | ||||||
|  | 		</key> | ||||||
|  | 		<key name="program3" type="s"> | ||||||
|  | 			<!-- Translators: Configuration for the default programs in JSON. Please only translate the values of "title" and "description". --> | ||||||
|  | 			<default l10n="messages">'{"title":"A long time ago","description":"Works that you haven\'t listend to for a long time.","design":"Program3","prefer_recently_added":-1.0,"prefer_least_recently_played":1.0,"play_full_recordings":false}'</default> | ||||||
|  | 			<summary>Default settings for program 3</summary> | ||||||
|  | 		</key> | ||||||
| 	</schema> | 	</schema> | ||||||
| </schemalist> | </schemalist> | ||||||
|  |  | ||||||
|  | @ -5,7 +5,8 @@ use crate::{ | ||||||
|     library::{LibraryQuery, MusicusLibrary}, |     library::{LibraryQuery, MusicusLibrary}, | ||||||
|     player::MusicusPlayer, |     player::MusicusPlayer, | ||||||
|     playlist_item::PlaylistItem, |     playlist_item::PlaylistItem, | ||||||
|     program_tile::{MusicusProgramTile, Program, ProgramTileDesign}, |     program::Program, | ||||||
|  |     program_tile::MusicusProgramTile, | ||||||
|     recording_tile::MusicusRecordingTile, |     recording_tile::MusicusRecordingTile, | ||||||
|     search_entry::MusicusSearchEntry, |     search_entry::MusicusSearchEntry, | ||||||
|     search_tag::Tag, |     search_tag::Tag, | ||||||
|  | @ -14,6 +15,7 @@ use crate::{ | ||||||
| 
 | 
 | ||||||
| use adw::subclass::{navigation_page::NavigationPageImpl, prelude::*}; | use adw::subclass::{navigation_page::NavigationPageImpl, prelude::*}; | ||||||
| use gtk::{ | use gtk::{ | ||||||
|  |     gio, | ||||||
|     glib::{self, clone, Properties}, |     glib::{self, clone, Properties}, | ||||||
|     prelude::*, |     prelude::*, | ||||||
| }; | }; | ||||||
|  | @ -107,29 +109,19 @@ mod imp { | ||||||
|                 .sync_create() |                 .sync_create() | ||||||
|                 .build(); |                 .build(); | ||||||
| 
 | 
 | ||||||
|             self.programs_flow_box |             let settings = gio::Settings::new("de.johrpan.musicus"); | ||||||
|                 .append(&MusicusProgramTile::new(Program { |             let program1 = Program::deserialize(&settings.string("program1")).unwrap(); | ||||||
|                         title: "Just play some music".to_string(), |             let program2 = Program::deserialize(&settings.string("program2")).unwrap(); | ||||||
|                         description: "Randomly select some music. Customize programs using the button in the top right." |             let program3 = Program::deserialize(&settings.string("program3")).unwrap(); | ||||||
|                             .to_string(), |  | ||||||
|                         design: Some(ProgramTileDesign::Program1) |  | ||||||
|                     }, |  | ||||||
|                 )); |  | ||||||
| 
 | 
 | ||||||
|             self.programs_flow_box |             self.programs_flow_box | ||||||
|                 .append(&MusicusProgramTile::new(Program { |                 .append(&MusicusProgramTile::new(program1)); | ||||||
|                     title: "What's new?".to_string(), |  | ||||||
|                     description: "Recordings that you recently added to your music library." |  | ||||||
|                         .to_string(), |  | ||||||
|                     design: Some(ProgramTileDesign::Program2), |  | ||||||
|                 })); |  | ||||||
| 
 | 
 | ||||||
|             self.programs_flow_box |             self.programs_flow_box | ||||||
|                 .append(&MusicusProgramTile::new(Program { |                 .append(&MusicusProgramTile::new(program2)); | ||||||
|                     title: "A long time ago".to_string(), | 
 | ||||||
|                     description: "Works that you haven't listend to for a long time.".to_string(), |             self.programs_flow_box | ||||||
|                     design: Some(ProgramTileDesign::Program3), |                 .append(&MusicusProgramTile::new(program3)); | ||||||
|                 })); |  | ||||||
| 
 | 
 | ||||||
|             self.obj().query(&LibraryQuery::default()); |             self.obj().query(&LibraryQuery::default()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ mod player_bar; | ||||||
| mod playlist_item; | mod playlist_item; | ||||||
| mod playlist_page; | mod playlist_page; | ||||||
| mod playlist_tile; | mod playlist_tile; | ||||||
|  | mod program; | ||||||
| mod program_tile; | mod program_tile; | ||||||
| mod recording_tile; | mod recording_tile; | ||||||
| mod search_entry; | mod search_entry; | ||||||
|  |  | ||||||
							
								
								
									
										119
									
								
								src/program.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								src/program.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,119 @@ | ||||||
|  | use std::cell::{Cell, RefCell}; | ||||||
|  | 
 | ||||||
|  | use anyhow::Result; | ||||||
|  | use gtk::{glib, glib::Properties, prelude::*, subclass::prelude::*}; | ||||||
|  | use serde::{Deserialize, Serialize}; | ||||||
|  | 
 | ||||||
|  | use crate::library::LibraryQuery; | ||||||
|  | 
 | ||||||
|  | mod imp { | ||||||
|  |     use super::*; | ||||||
|  | 
 | ||||||
|  |     #[derive(Properties, Serialize, Deserialize, Default)] | ||||||
|  |     #[properties(wrapper_type = super::Program)] | ||||||
|  |     pub struct Program { | ||||||
|  |         #[property(get, set)] | ||||||
|  |         pub title: RefCell<Option<String>>, | ||||||
|  | 
 | ||||||
|  |         #[property(get, set)] | ||||||
|  |         pub description: RefCell<Option<String>>, | ||||||
|  | 
 | ||||||
|  |         #[property(get, set, builder(ProgramDesign::default()))] | ||||||
|  |         pub design: Cell<ProgramDesign>, | ||||||
|  | 
 | ||||||
|  |         #[property(get, set)] | ||||||
|  |         pub composer_id: RefCell<Option<String>>, | ||||||
|  | 
 | ||||||
|  |         #[property(get, set)] | ||||||
|  |         pub performer_id: RefCell<Option<String>>, | ||||||
|  | 
 | ||||||
|  |         #[property(get, set)] | ||||||
|  |         pub ensemble_id: RefCell<Option<String>>, | ||||||
|  | 
 | ||||||
|  |         #[property(get, set)] | ||||||
|  |         pub work_id: RefCell<Option<String>>, | ||||||
|  | 
 | ||||||
|  |         #[property(get, set)] | ||||||
|  |         pub album_id: RefCell<Option<String>>, | ||||||
|  | 
 | ||||||
|  |         #[property(get, set)] | ||||||
|  |         pub prefer_recently_added: Cell<f64>, | ||||||
|  | 
 | ||||||
|  |         #[property(get, set)] | ||||||
|  |         pub prefer_least_recently_played: Cell<f64>, | ||||||
|  | 
 | ||||||
|  |         #[property(get, set)] | ||||||
|  |         pub play_full_recordings: Cell<bool>, | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[glib::object_subclass] | ||||||
|  |     impl ObjectSubclass for Program { | ||||||
|  |         const NAME: &'static str = "MusicusProgram"; | ||||||
|  |         type Type = super::Program; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[glib::derived_properties] | ||||||
|  |     impl ObjectImpl for Program {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | glib::wrapper! { | ||||||
|  |     pub struct Program(ObjectSubclass<imp::Program>); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Program { | ||||||
|  |     pub fn new(title: &str, description: &str, design: ProgramDesign) -> Self { | ||||||
|  |         glib::Object::builder() | ||||||
|  |             .property("title", title) | ||||||
|  |             .property("description", description) | ||||||
|  |             .property("design", design) | ||||||
|  |             .build() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn from_query(query: LibraryQuery) -> Self { | ||||||
|  |         glib::Object::builder() | ||||||
|  |             .property("composer-id", query.composer.map(|p| p.person_id)) | ||||||
|  |             .property("performer-id", query.performer.map(|p| p.person_id)) | ||||||
|  |             .property("ensemble-id", query.ensemble.map(|e| e.ensemble_id)) | ||||||
|  |             .property("prefer-recently-added", 0.25) | ||||||
|  |             .property("prefer-least-recently-played", 0.5) | ||||||
|  |             .property("play-full-recordings", true) | ||||||
|  |             .build() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn deserialize(input: &str) -> Result<Self> { | ||||||
|  |         let data: imp::Program = serde_json::from_str(input)?; | ||||||
|  | 
 | ||||||
|  |         let obj = glib::Object::builder() | ||||||
|  |             .property("title", &*data.title.borrow()) | ||||||
|  |             .property("description", &*data.description.borrow()) | ||||||
|  |             .property("design", data.design.get()) | ||||||
|  |             .property("prefer-recently-added", data.prefer_recently_added.get()) | ||||||
|  |             .property("prefer-least-recently-played", data.prefer_least_recently_played.get()) | ||||||
|  |             .property("play-full-recordings", data.play_full_recordings.get()) | ||||||
|  |             .build(); | ||||||
|  | 
 | ||||||
|  |         Ok(obj) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn serialize(&self) -> String { | ||||||
|  |         serde_json::to_string(self.imp()).unwrap() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(glib::Enum, Serialize, Deserialize, Eq, PartialEq, Clone, Copy, Debug)] | ||||||
|  | #[enum_type(name = "MusicusProgramDesign")] | ||||||
|  | pub enum ProgramDesign { | ||||||
|  |     Generic, | ||||||
|  |     Program1, | ||||||
|  |     Program2, | ||||||
|  |     Program3, | ||||||
|  |     Program4, | ||||||
|  |     Program5, | ||||||
|  |     Program6, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Default for ProgramDesign { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self::Generic | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,21 +1,29 @@ | ||||||
| use adw::prelude::WidgetExt; |  | ||||||
| use gtk::{glib, subclass::prelude::*}; |  | ||||||
| use std::cell::OnceCell; | use std::cell::OnceCell; | ||||||
| 
 | 
 | ||||||
|  | use gtk::{ | ||||||
|  |     glib::{self, Properties}, | ||||||
|  |     prelude::*, | ||||||
|  |     subclass::prelude::*, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | use crate::program::{Program, ProgramDesign}; | ||||||
|  | 
 | ||||||
| mod imp { | mod imp { | ||||||
|     use super::*; |     use super::*; | ||||||
| 
 | 
 | ||||||
|     #[derive(Debug, Default, gtk::CompositeTemplate)] |     #[derive(Properties, Debug, Default, gtk::CompositeTemplate)] | ||||||
|  |     #[properties(wrapper_type = super::MusicusProgramTile)] | ||||||
|     #[template(file = "data/ui/program_tile.blp")] |     #[template(file = "data/ui/program_tile.blp")] | ||||||
|     pub struct MusicusProgramTile { |     pub struct MusicusProgramTile { | ||||||
|  |         #[property(get, construct_only)] | ||||||
|  |         pub program: OnceCell<Program>, | ||||||
|  | 
 | ||||||
|         #[template_child] |         #[template_child] | ||||||
|         pub edit_button: TemplateChild<gtk::Button>, |         pub edit_button: TemplateChild<gtk::Button>, | ||||||
|         #[template_child] |         #[template_child] | ||||||
|         pub title_label: TemplateChild<gtk::Label>, |         pub title_label: TemplateChild<gtk::Label>, | ||||||
|         #[template_child] |         #[template_child] | ||||||
|         pub description_label: TemplateChild<gtk::Label>, |         pub description_label: TemplateChild<gtk::Label>, | ||||||
| 
 |  | ||||||
|         pub program: OnceCell<Program>, |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[glib::object_subclass] |     #[glib::object_subclass] | ||||||
|  | @ -33,7 +41,9 @@ mod imp { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     #[glib::derived_properties] | ||||||
|     impl ObjectImpl for MusicusProgramTile {} |     impl ObjectImpl for MusicusProgramTile {} | ||||||
|  | 
 | ||||||
|     impl WidgetImpl for MusicusProgramTile {} |     impl WidgetImpl for MusicusProgramTile {} | ||||||
|     impl FlowBoxChildImpl for MusicusProgramTile {} |     impl FlowBoxChildImpl for MusicusProgramTile {} | ||||||
| } | } | ||||||
|  | @ -45,46 +55,33 @@ glib::wrapper! { | ||||||
| 
 | 
 | ||||||
| impl MusicusProgramTile { | impl MusicusProgramTile { | ||||||
|     pub fn new(program: Program) -> Self { |     pub fn new(program: Program) -> Self { | ||||||
|         let obj: Self = glib::Object::new(); |         let obj: Self = glib::Object::builder() | ||||||
|  |             .property("program", &program) | ||||||
|  |             .build(); | ||||||
|  | 
 | ||||||
|         let imp = obj.imp(); |         let imp = obj.imp(); | ||||||
| 
 | 
 | ||||||
|         if let Some(design) = program.design { |         if program.design() != ProgramDesign::Generic { | ||||||
|             obj.add_css_class("highlight"); |             obj.add_css_class("highlight"); | ||||||
|             obj.add_css_class(match design { |             obj.add_css_class(match program.design() { | ||||||
|                 ProgramTileDesign::Program1 => "program1", |                 ProgramDesign::Generic => "generic", | ||||||
|                 ProgramTileDesign::Program2 => "program2", |                 ProgramDesign::Program1 => "program1", | ||||||
|                 ProgramTileDesign::Program3 => "program3", |                 ProgramDesign::Program2 => "program2", | ||||||
|                 ProgramTileDesign::Program4 => "program4", |                 ProgramDesign::Program3 => "program3", | ||||||
|                 ProgramTileDesign::Program5 => "program5", |                 ProgramDesign::Program4 => "program4", | ||||||
|                 ProgramTileDesign::Program6 => "program6", |                 ProgramDesign::Program5 => "program5", | ||||||
|  |                 ProgramDesign::Program6 => "program6", | ||||||
|             }) |             }) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         imp.title_label.set_label(&program.title); |         if let Some(title) = program.title() { | ||||||
|         imp.description_label.set_label(&program.description); |             imp.title_label.set_label(&title); | ||||||
|         imp.program.set(program).unwrap(); |         } | ||||||
|  | 
 | ||||||
|  |         if let Some(description) = program.description() { | ||||||
|  |             imp.description_label.set_label(&description); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         obj |         obj | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     pub fn program(&self) -> &Program { |  | ||||||
|         self.imp().program.get().unwrap() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Default)] |  | ||||||
| pub struct Program { |  | ||||||
|     pub title: String, |  | ||||||
|     pub description: String, |  | ||||||
|     pub design: Option<ProgramTileDesign>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Copy, Debug)] |  | ||||||
| pub enum ProgramTileDesign { |  | ||||||
|     Program1, |  | ||||||
|     Program2, |  | ||||||
|     Program3, |  | ||||||
|     Program4, |  | ||||||
|     Program5, |  | ||||||
|     Program6, |  | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue