mirror of
				https://github.com/johrpan/musicus.git
				synced 2025-10-26 19:57:25 +01:00 
			
		
		
		
	Actually import from medium editor
This commit is contained in:
		
							parent
							
								
									5348b7750b
								
							
						
					
					
						commit
						aa6b5c6ac4
					
				
					 13 changed files with 328 additions and 239 deletions
				
			
		|  | @ -12,5 +12,4 @@ DROP TABLE "performances"; | ||||||
| DROP TABLE "mediums"; | DROP TABLE "mediums"; | ||||||
| DROP TABLE "track_sets"; | DROP TABLE "track_sets"; | ||||||
| DROP TABLE "tracks"; | DROP TABLE "tracks"; | ||||||
| DROP TABLE "files"; |  | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -72,11 +72,7 @@ CREATE TABLE "tracks" ( | ||||||
|     "id" TEXT NOT NULL PRIMARY KEY, |     "id" TEXT NOT NULL PRIMARY KEY, | ||||||
|     "track_set" TEXT NOT NULL REFERENCES "track_sets"("id") ON DELETE CASCADE, |     "track_set" TEXT NOT NULL REFERENCES "track_sets"("id") ON DELETE CASCADE, | ||||||
|     "index" INTEGER NOT NULL, |     "index" INTEGER NOT NULL, | ||||||
|     "work_parts" TEXT NOT NULL |     "work_parts" TEXT NOT NULL, | ||||||
| ); |     "path" TEXT NOT NULL | ||||||
| 
 |  | ||||||
| CREATE TABLE "files" ( |  | ||||||
|     "file_name" TEXT NOT NULL PRIMARY KEY, |  | ||||||
|     "track" TEXT NOT NULL REFERENCES "tracks"("id") |  | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,7 +2,11 @@ | ||||||
| <interface> | <interface> | ||||||
|   <requires lib="gtk+" version="3.24"/> |   <requires lib="gtk+" version="3.24"/> | ||||||
|   <requires lib="libhandy" version="1.0"/> |   <requires lib="libhandy" version="1.0"/> | ||||||
|   <object class="GtkBox" id="widget"> |   <object class="GtkStack" id="widget"> | ||||||
|  |     <property name="visible">True</property> | ||||||
|  |     <property name="transition-type">crossfade</property> | ||||||
|  |     <child> | ||||||
|  |       <object class="GtkBox"> | ||||||
|         <property name="visible">True</property> |         <property name="visible">True</property> | ||||||
|         <property name="orientation">vertical</property> |         <property name="orientation">vertical</property> | ||||||
|         <child> |         <child> | ||||||
|  | @ -54,6 +58,13 @@ | ||||||
|             </child> |             </child> | ||||||
|           </object> |           </object> | ||||||
|         </child> |         </child> | ||||||
|  |         <child> | ||||||
|  |           <object class="GtkInfoBar" id="info_bar"> | ||||||
|  |             <property name="visible">True</property> | ||||||
|  |             <property name="can-focus">False</property> | ||||||
|  |             <property name="revealed">False</property> | ||||||
|  |           </object> | ||||||
|  |         </child> | ||||||
|         <child> |         <child> | ||||||
|           <object class="GtkScrolledWindow"> |           <object class="GtkScrolledWindow"> | ||||||
|             <property name="visible">True</property> |             <property name="visible">True</property> | ||||||
|  | @ -106,6 +117,23 @@ | ||||||
|                                 </child> |                                 </child> | ||||||
|                               </object> |                               </object> | ||||||
|                             </child> |                             </child> | ||||||
|  |                             <child> | ||||||
|  |                               <object class="HdyActionRow"> | ||||||
|  |                                 <property name="visible">True</property> | ||||||
|  |                                 <property name="can-focus">True</property> | ||||||
|  |                                 <property name="activatable">True</property> | ||||||
|  |                                 <property name="title" translatable="yes">Publish to the server</property> | ||||||
|  |                                 <property name="activatable-widget">publish_switch</property> | ||||||
|  |                                 <child> | ||||||
|  |                                   <object class="GtkSwitch" id="publish_switch"> | ||||||
|  |                                     <property name="visible">True</property> | ||||||
|  |                                     <property name="can-focus">True</property> | ||||||
|  |                                     <property name="valign">center</property> | ||||||
|  |                                     <property name="active">True</property> | ||||||
|  |                                   </object> | ||||||
|  |                                 </child> | ||||||
|  |                               </object> | ||||||
|  |                             </child> | ||||||
|                           </object> |                           </object> | ||||||
|                         </child> |                         </child> | ||||||
|                       </object> |                       </object> | ||||||
|  | @ -156,4 +184,18 @@ | ||||||
|           </object> |           </object> | ||||||
|         </child> |         </child> | ||||||
|       </object> |       </object> | ||||||
|  |       <packing> | ||||||
|  |         <property name="name">content</property> | ||||||
|  |       </packing> | ||||||
|  |     </child> | ||||||
|  |     <child> | ||||||
|  |       <object class="GtkSpinner"> | ||||||
|  |         <property name="visible">True</property> | ||||||
|  |         <property name="active">True</property> | ||||||
|  |       </object> | ||||||
|  |       <packing> | ||||||
|  |         <property name="name">loading</property> | ||||||
|  |       </packing> | ||||||
|  |     </child> | ||||||
|  |   </object> | ||||||
| </interface> | </interface> | ||||||
|  |  | ||||||
|  | @ -1,54 +0,0 @@ | ||||||
| use super::schema::files; |  | ||||||
| use super::Database; |  | ||||||
| use anyhow::Result; |  | ||||||
| use diesel::prelude::*; |  | ||||||
| 
 |  | ||||||
| /// Table data to associate audio files with tracks.
 |  | ||||||
| #[derive(Insertable, Queryable, Debug, Clone)] |  | ||||||
| #[table_name = "files"] |  | ||||||
| struct FileRow { |  | ||||||
|     pub file_name: String, |  | ||||||
|     pub track: String, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Database { |  | ||||||
|     /// Insert or update a file. This assumes that the track is already in the
 |  | ||||||
|     /// database.
 |  | ||||||
|     pub fn update_file(&self, file_name: &str, track_id: &str) -> Result<()> { |  | ||||||
|         let row = FileRow { |  | ||||||
|             file_name: file_name.to_owned(), |  | ||||||
|             track: track_id.to_owned(), |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         diesel::insert_into(files::table) |  | ||||||
|             .values(row) |  | ||||||
|             .execute(&self.connection)?; |  | ||||||
| 
 |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Delete an existing file. This will not delete the file from the file
 |  | ||||||
|     /// system but just the representing row from the database.
 |  | ||||||
|     pub fn delete_file(&self, file_name: &str) -> Result<()> { |  | ||||||
|         diesel::delete(files::table.filter(files::file_name.eq(file_name))) |  | ||||||
|             .execute(&self.connection)?; |  | ||||||
| 
 |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Get the file name of the audio file for the specified track.
 |  | ||||||
|     pub fn get_file(&self, track_id: &str) -> Result<Option<String>> { |  | ||||||
|         let row = files::table |  | ||||||
|             .filter(files::track.eq(track_id)) |  | ||||||
|             .load::<FileRow>(&self.connection)? |  | ||||||
|             .into_iter() |  | ||||||
|             .next(); |  | ||||||
| 
 |  | ||||||
|         let file_name = match row { |  | ||||||
|             Some(row) => Some(row.file_name), |  | ||||||
|             None => None, |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         Ok(file_name) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| use super::generate_id; | use super::generate_id; | ||||||
| use super::schema::{mediums, track_sets, tracks}; | use super::schema::{mediums, recordings, track_sets, tracks}; | ||||||
| use super::{Database, Recording}; | use super::{Database, Recording}; | ||||||
| use anyhow::{anyhow, Error, Result}; | use anyhow::{anyhow, Error, Result}; | ||||||
| use diesel::prelude::*; | use diesel::prelude::*; | ||||||
|  | @ -41,6 +41,11 @@ pub struct Track { | ||||||
|     /// The work parts that are played on this track. They are indices to the
 |     /// The work parts that are played on this track. They are indices to the
 | ||||||
|     /// work parts of the work that is associated with the recording.
 |     /// work parts of the work that is associated with the recording.
 | ||||||
|     pub work_parts: Vec<usize>, |     pub work_parts: Vec<usize>, | ||||||
|  | 
 | ||||||
|  |     /// The path to the audio file containing this track. This will not be
 | ||||||
|  |     /// included when communicating with the server.
 | ||||||
|  |     #[serde(skip)] | ||||||
|  |     pub path: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Table data for a [`Medium`].
 | /// Table data for a [`Medium`].
 | ||||||
|  | @ -70,6 +75,7 @@ struct TrackRow { | ||||||
|     pub track_set: String, |     pub track_set: String, | ||||||
|     pub index: i32, |     pub index: i32, | ||||||
|     pub work_parts: String, |     pub work_parts: String, | ||||||
|  |     pub path: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Database { | impl Database { | ||||||
|  | @ -83,7 +89,28 @@ impl Database { | ||||||
|             // This will also delete the track sets and tracks.
 |             // This will also delete the track sets and tracks.
 | ||||||
|             self.delete_medium(medium_id)?; |             self.delete_medium(medium_id)?; | ||||||
| 
 | 
 | ||||||
|  |             // Add the new medium.
 | ||||||
|  | 
 | ||||||
|  |             let medium_row = MediumRow { | ||||||
|  |                 id: medium_id.to_owned(), | ||||||
|  |                 name: medium.name.clone(), | ||||||
|  |                 discid: medium.discid.clone(), | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             diesel::insert_into(mediums::table) | ||||||
|  |                 .values(medium_row) | ||||||
|  |                 .execute(&self.connection)?; | ||||||
|  | 
 | ||||||
|             for (index, track_set) in medium.tracks.iter().enumerate() { |             for (index, track_set) in medium.tracks.iter().enumerate() { | ||||||
|  |                 // Add associated items from the server, if they don't already
 | ||||||
|  |                 // exist.
 | ||||||
|  | 
 | ||||||
|  |                 if self.get_recording(&track_set.recording.id)?.is_none() { | ||||||
|  |                     self.update_recording(track_set.recording.clone())?; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // Add the actual track set data.
 | ||||||
|  | 
 | ||||||
|                 let track_set_id = generate_id(); |                 let track_set_id = generate_id(); | ||||||
| 
 | 
 | ||||||
|                 let track_set_row = TrackSetRow { |                 let track_set_row = TrackSetRow { | ||||||
|  | @ -110,6 +137,7 @@ impl Database { | ||||||
|                         track_set: track_set_id.clone(), |                         track_set: track_set_id.clone(), | ||||||
|                         index: index as i32, |                         index: index as i32, | ||||||
|                         work_parts, |                         work_parts, | ||||||
|  |                         path: track.path.clone(), | ||||||
|                     }; |                     }; | ||||||
| 
 | 
 | ||||||
|                     diesel::insert_into(tracks::table) |                     diesel::insert_into(tracks::table) | ||||||
|  | @ -147,6 +175,35 @@ impl Database { | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Get all tracks for a recording.
 | ||||||
|  |     pub fn get_tracks(&self, recording_id: &str) -> Result<Vec<Track>> { | ||||||
|  |         let mut tracks: Vec<Track> = Vec::new(); | ||||||
|  | 
 | ||||||
|  |         let rows = tracks::table | ||||||
|  |             .inner_join(track_sets::table.on(track_sets::id.eq(tracks::track_set))) | ||||||
|  |             .inner_join(recordings::table.on(recordings::id.eq(track_sets::recording))) | ||||||
|  |             .filter(recordings::id.eq(recording_id)) | ||||||
|  |             .select(tracks::table::all_columns()) | ||||||
|  |             .load::<TrackRow>(&self.connection)?; | ||||||
|  | 
 | ||||||
|  |         for row in rows { | ||||||
|  |             let work_parts = row | ||||||
|  |                 .work_parts | ||||||
|  |                 .split(',') | ||||||
|  |                 .map(|part_index| Ok(str::parse(part_index)?)) | ||||||
|  |                 .collect::<Result<Vec<usize>>>()?; | ||||||
|  | 
 | ||||||
|  |             let track = Track { | ||||||
|  |                 work_parts, | ||||||
|  |                 path: row.path.clone(), | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             tracks.push(track); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Ok(tracks) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /// Retrieve all available information on a medium from related tables.
 |     /// Retrieve all available information on a medium from related tables.
 | ||||||
|     fn get_medium_data(&self, row: MediumRow) -> Result<Medium> { |     fn get_medium_data(&self, row: MediumRow) -> Result<Medium> { | ||||||
|         let track_set_rows = track_sets::table |         let track_set_rows = track_sets::table | ||||||
|  | @ -177,7 +234,10 @@ impl Database { | ||||||
|                     .map(|part_index| Ok(str::parse(part_index)?)) |                     .map(|part_index| Ok(str::parse(part_index)?)) | ||||||
|                     .collect::<Result<Vec<usize>>>()?; |                     .collect::<Result<Vec<usize>>>()?; | ||||||
| 
 | 
 | ||||||
|                 let track = Track { work_parts }; |                 let track = Track { | ||||||
|  |                     work_parts, | ||||||
|  |                     path: track_row.path.clone(), | ||||||
|  |                 }; | ||||||
| 
 | 
 | ||||||
|                 tracks.push(track); |                 tracks.push(track); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -19,9 +19,6 @@ pub use recordings::*; | ||||||
| pub mod thread; | pub mod thread; | ||||||
| pub use thread::*; | pub use thread::*; | ||||||
| 
 | 
 | ||||||
| pub mod files; |  | ||||||
| pub use files::*; |  | ||||||
| 
 |  | ||||||
| pub mod works; | pub mod works; | ||||||
| pub use works::*; | pub use works::*; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,13 +5,6 @@ table! { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| table! { |  | ||||||
|     files (file_name) { |  | ||||||
|         file_name -> Text, |  | ||||||
|         track -> Text, |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| table! { | table! { | ||||||
|     instrumentations (id) { |     instrumentations (id) { | ||||||
|         id -> BigInt, |         id -> BigInt, | ||||||
|  | @ -76,6 +69,7 @@ table! { | ||||||
|         track_set -> Text, |         track_set -> Text, | ||||||
|         index -> Integer, |         index -> Integer, | ||||||
|         work_parts -> Text, |         work_parts -> Text, | ||||||
|  |         path -> Text, | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -106,7 +100,6 @@ table! { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| joinable!(files -> tracks (track)); |  | ||||||
| joinable!(instrumentations -> instruments (instrument)); | joinable!(instrumentations -> instruments (instrument)); | ||||||
| joinable!(instrumentations -> works (work)); | joinable!(instrumentations -> works (work)); | ||||||
| joinable!(performances -> ensembles (ensemble)); | joinable!(performances -> ensembles (ensemble)); | ||||||
|  | @ -124,7 +117,6 @@ joinable!(works -> persons (composer)); | ||||||
| 
 | 
 | ||||||
| allow_tables_to_appear_in_same_query!( | allow_tables_to_appear_in_same_query!( | ||||||
|     ensembles, |     ensembles, | ||||||
|     files, |  | ||||||
|     instrumentations, |     instrumentations, | ||||||
|     instruments, |     instruments, | ||||||
|     mediums, |     mediums, | ||||||
|  |  | ||||||
|  | @ -31,9 +31,7 @@ enum Action { | ||||||
|     UpdateMedium(Medium, Sender<Result<()>>), |     UpdateMedium(Medium, Sender<Result<()>>), | ||||||
|     GetMedium(String, Sender<Result<Option<Medium>>>), |     GetMedium(String, Sender<Result<Option<Medium>>>), | ||||||
|     DeleteMedium(String, Sender<Result<()>>), |     DeleteMedium(String, Sender<Result<()>>), | ||||||
|     UpdateFile(String, String, Sender<Result<()>>), |     GetTracks(String, Sender<Result<Vec<Track>>>), | ||||||
|     DeleteFile(String, Sender<Result<()>>), |  | ||||||
|     GetFile(String, Sender<Result<Option<String>>>), |  | ||||||
|     Stop(Sender<()>), |     Stop(Sender<()>), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -136,14 +134,8 @@ impl DbThread { | ||||||
|                     DeleteMedium(id, sender) => { |                     DeleteMedium(id, sender) => { | ||||||
|                         sender.send(db.delete_medium(&id)).unwrap(); |                         sender.send(db.delete_medium(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     UpdateFile(file_name, track_id, sender) => { |                     GetTracks(recording_id, sender) => { | ||||||
|                         sender.send(db.update_file(&file_name, &track_id)).unwrap(); |                         sender.send(db.get_tracks(&recording_id)).unwrap(); | ||||||
|                     } |  | ||||||
|                     DeleteFile(file_name, sender) => { |  | ||||||
|                         sender.send(db.delete_file(&file_name)).unwrap(); |  | ||||||
|                     } |  | ||||||
|                     GetFile(track_id, sender) => { |  | ||||||
|                         sender.send(db.get_file(&track_id)).unwrap(); |  | ||||||
|                     } |                     } | ||||||
|                     Stop(sender) => { |                     Stop(sender) => { | ||||||
|                         sender.send(()).unwrap(); |                         sender.send(()).unwrap(); | ||||||
|  | @ -347,38 +339,10 @@ impl DbThread { | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Insert or update a file. This assumes that the track is already in the
 |     /// Get all tracks for a recording.
 | ||||||
|     /// database.
 |     pub async fn get_tracks(&self, recording_id: &str) -> Result<Vec<Track>> { | ||||||
|     pub async fn update_file(&self, file_name: &str, track_id: &str) -> Result<()> { |  | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
| 
 |         self.action_sender.send(GetTracks(recording_id.to_owned(), sender))?; | ||||||
|         self.action_sender.send(UpdateFile( |  | ||||||
|             file_name.to_owned(), |  | ||||||
|             track_id.to_owned(), |  | ||||||
|             sender, |  | ||||||
|         ))?; |  | ||||||
| 
 |  | ||||||
|         receiver.await? |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Delete an existing file. This will not delete the file from the file
 |  | ||||||
|     /// system but just the representing row from the database.
 |  | ||||||
|     pub async fn delete_file(&self, file_name: &str) -> Result<()> { |  | ||||||
|         let (sender, receiver) = oneshot::channel(); |  | ||||||
| 
 |  | ||||||
|         self.action_sender |  | ||||||
|             .send(DeleteFile(file_name.to_owned(), sender))?; |  | ||||||
| 
 |  | ||||||
|         receiver.await? |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Get the file name of the audio file for the specified track.
 |  | ||||||
|     pub async fn get_file(&self, track_id: &str) -> Result<Option<String>> { |  | ||||||
|         let (sender, receiver) = oneshot::channel(); |  | ||||||
| 
 |  | ||||||
|         self.action_sender |  | ||||||
|             .send(GetFile(track_id.to_owned(), sender))?; |  | ||||||
| 
 |  | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,6 +13,9 @@ pub struct DiscSource { | ||||||
|     /// The MusicBrainz DiscID of the CD.
 |     /// The MusicBrainz DiscID of the CD.
 | ||||||
|     pub discid: String, |     pub discid: String, | ||||||
| 
 | 
 | ||||||
|  |     /// The path to the temporary directory where the audio files will be.
 | ||||||
|  |     pub path: PathBuf, | ||||||
|  | 
 | ||||||
|     /// The tracks on this disc.
 |     /// The tracks on this disc.
 | ||||||
|     pub tracks: Vec<TrackSource>, |     pub tracks: Vec<TrackSource>, | ||||||
| } | } | ||||||
|  | @ -96,6 +99,7 @@ impl DiscSource { | ||||||
|         let disc = DiscSource { |         let disc = DiscSource { | ||||||
|             discid: id, |             discid: id, | ||||||
|             tracks, |             tracks, | ||||||
|  |             path: tmp_dir, | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         Ok(disc) |         Ok(disc) | ||||||
|  |  | ||||||
|  | @ -1,8 +1,10 @@ | ||||||
| use super::disc_source::DiscSource; | use super::disc_source::DiscSource; | ||||||
| use super::track_set_editor::{TrackSetData, TrackSetEditor}; | use super::track_set_editor::{TrackSetData, TrackSetEditor}; | ||||||
|  | use crate::database::{generate_id, Medium, Track, TrackSet}; | ||||||
| use crate::backend::Backend; | use crate::backend::Backend; | ||||||
| use crate::widgets::{Navigator, NavigatorScreen}; | use crate::widgets::{Navigator, NavigatorScreen}; | ||||||
| use crate::widgets::new_list::List; | use crate::widgets::new_list::List; | ||||||
|  | use anyhow::Result; | ||||||
| use glib::clone; | use glib::clone; | ||||||
| use glib::prelude::*; | use glib::prelude::*; | ||||||
| use gtk::prelude::*; | use gtk::prelude::*; | ||||||
|  | @ -15,11 +17,12 @@ use std::rc::Rc; | ||||||
| pub struct MediumEditor { | pub struct MediumEditor { | ||||||
|     backend: Rc<Backend>, |     backend: Rc<Backend>, | ||||||
|     source: Rc<DiscSource>, |     source: Rc<DiscSource>, | ||||||
|     widget: gtk::Box, |     widget: gtk::Stack, | ||||||
|     done_button: gtk::Button, |     done_button: gtk::Button, | ||||||
|     done_stack: gtk::Stack, |     done_stack: gtk::Stack, | ||||||
|     done: gtk::Image, |     done: gtk::Image, | ||||||
|     name_entry: gtk::Entry, |     name_entry: gtk::Entry, | ||||||
|  |     publish_switch: gtk::Switch, | ||||||
|     track_set_list: List, |     track_set_list: List, | ||||||
|     track_sets: RefCell<Vec<TrackSetData>>, |     track_sets: RefCell<Vec<TrackSetData>>, | ||||||
|     navigator: RefCell<Option<Rc<Navigator>>>, |     navigator: RefCell<Option<Rc<Navigator>>>, | ||||||
|  | @ -32,12 +35,13 @@ impl MediumEditor { | ||||||
| 
 | 
 | ||||||
|         let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/medium_editor.ui"); |         let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/medium_editor.ui"); | ||||||
| 
 | 
 | ||||||
|         get_widget!(builder, gtk::Box, widget); |         get_widget!(builder, gtk::Stack, widget); | ||||||
|         get_widget!(builder, gtk::Button, back_button); |         get_widget!(builder, gtk::Button, back_button); | ||||||
|         get_widget!(builder, gtk::Button, done_button); |         get_widget!(builder, gtk::Button, done_button); | ||||||
|         get_widget!(builder, gtk::Stack, done_stack); |         get_widget!(builder, gtk::Stack, done_stack); | ||||||
|         get_widget!(builder, gtk::Image, done); |         get_widget!(builder, gtk::Image, done); | ||||||
|         get_widget!(builder, gtk::Entry, name_entry); |         get_widget!(builder, gtk::Entry, name_entry); | ||||||
|  |         get_widget!(builder, gtk::Switch, publish_switch); | ||||||
|         get_widget!(builder, gtk::Button, add_button); |         get_widget!(builder, gtk::Button, add_button); | ||||||
|         get_widget!(builder, gtk::Frame, frame); |         get_widget!(builder, gtk::Frame, frame); | ||||||
| 
 | 
 | ||||||
|  | @ -52,6 +56,7 @@ impl MediumEditor { | ||||||
|             done_stack, |             done_stack, | ||||||
|             done, |             done, | ||||||
|             name_entry, |             name_entry, | ||||||
|  |             publish_switch, | ||||||
|             track_set_list: list, |             track_set_list: list, | ||||||
|             track_sets: RefCell::new(Vec::new()), |             track_sets: RefCell::new(Vec::new()), | ||||||
|             navigator: RefCell::new(None), |             navigator: RefCell::new(None), | ||||||
|  | @ -66,6 +71,22 @@ impl MediumEditor { | ||||||
|             } |             } | ||||||
|         })); |         })); | ||||||
| 
 | 
 | ||||||
|  |         this.done_button.connect_clicked(clone!(@strong this => move |_| { | ||||||
|  |             let context = glib::MainContext::default(); | ||||||
|  |             let clone = this.clone(); | ||||||
|  |             context.spawn_local(async move { | ||||||
|  |                 clone.widget.set_visible_child_name("loading"); | ||||||
|  |                 match clone.clone().save().await { | ||||||
|  |                     Ok(_) => (), | ||||||
|  |                     Err(err) => { | ||||||
|  |                         println!("{:?}", err); | ||||||
|  |                         // clone.info_bar.set_revealed(true);
 | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |             }); | ||||||
|  |         })); | ||||||
|  | 
 | ||||||
|         add_button.connect_clicked(clone!(@strong this => move |_| { |         add_button.connect_clicked(clone!(@strong this => move |_| { | ||||||
|             let navigator = this.navigator.borrow().clone(); |             let navigator = this.navigator.borrow().clone(); | ||||||
|             if let Some(navigator) = navigator { |             if let Some(navigator) = navigator { | ||||||
|  | @ -130,6 +151,79 @@ impl MediumEditor { | ||||||
| 
 | 
 | ||||||
|         this |         this | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /// Save the medium and possibly upload it to the server.
 | ||||||
|  |     async fn save(self: Rc<Self>) -> Result<()> { | ||||||
|  |         let name = self.name_entry.get_text().to_string(); | ||||||
|  | 
 | ||||||
|  |         // Create a new directory in the music library path for the imported medium.
 | ||||||
|  | 
 | ||||||
|  |         let mut path = self.backend.get_music_library_path().unwrap().clone(); | ||||||
|  |         path.push(&name); | ||||||
|  |         std::fs::create_dir(&path)?; | ||||||
|  | 
 | ||||||
|  |         // Convert the track set data to real track sets.
 | ||||||
|  | 
 | ||||||
|  |         let mut track_sets = Vec::new(); | ||||||
|  | 
 | ||||||
|  |         for track_set_data in &*self.track_sets.borrow() { | ||||||
|  |             let mut tracks = Vec::new(); | ||||||
|  | 
 | ||||||
|  |             for track_data in &track_set_data.tracks { | ||||||
|  |                 // Copy the corresponding audio file to the music library.
 | ||||||
|  | 
 | ||||||
|  |                 let track_source = &self.source.tracks[track_data.track_source]; | ||||||
|  |                 let file_name = format!("track_{:02}.flac", track_source.number); | ||||||
|  | 
 | ||||||
|  |                 let mut track_path = path.clone(); | ||||||
|  |                 track_path.push(&file_name); | ||||||
|  | 
 | ||||||
|  |                 std::fs::copy(&track_source.path, &track_path)?; | ||||||
|  | 
 | ||||||
|  |                 // Create the real track.
 | ||||||
|  | 
 | ||||||
|  |                 let track = Track { | ||||||
|  |                     work_parts: track_data.work_parts.clone(), | ||||||
|  |                     path: track_path.to_str().unwrap().to_owned(), | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 tracks.push(track); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             let track_set = TrackSet { | ||||||
|  |                 recording: track_set_data.recording.clone(), | ||||||
|  |                 tracks, | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             track_sets.push(track_set); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let medium = Medium { | ||||||
|  |             id: generate_id(), | ||||||
|  |             name: self.name_entry.get_text().to_string(), | ||||||
|  |             discid: Some(self.source.discid.clone()), | ||||||
|  |             tracks: track_sets, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         let upload = self.publish_switch.get_active(); | ||||||
|  |         if upload { | ||||||
|  |             // self.backend.post_medium(&medium).await?;
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         self.backend | ||||||
|  |             .db() | ||||||
|  |             .update_medium(medium.clone()) | ||||||
|  |             .await?; | ||||||
|  | 
 | ||||||
|  |         self.backend.library_changed(); | ||||||
|  | 
 | ||||||
|  |         let navigator = self.navigator.borrow().clone(); | ||||||
|  |         if let Some(navigator) = navigator { | ||||||
|  |             navigator.clone().pop(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl NavigatorScreen for MediumEditor { | impl NavigatorScreen for MediumEditor { | ||||||
|  |  | ||||||
|  | @ -141,10 +141,6 @@ impl TrackSetEditor { | ||||||
|                     let mut tracks = Vec::new(); |                     let mut tracks = Vec::new(); | ||||||
| 
 | 
 | ||||||
|                     for index in selection { |                     for index in selection { | ||||||
|                         let track = Track { |  | ||||||
|                             work_parts: Vec::new(), |  | ||||||
|                         }; |  | ||||||
| 
 |  | ||||||
|                         let data = TrackData { |                         let data = TrackData { | ||||||
|                             track_source: index, |                             track_source: index, | ||||||
|                             work_parts: Vec::new(), |                             work_parts: Vec::new(), | ||||||
|  |  | ||||||
|  | @ -43,7 +43,6 @@ sources = files( | ||||||
|   'backend/mod.rs', |   'backend/mod.rs', | ||||||
|   'backend/secure.rs', |   'backend/secure.rs', | ||||||
|   'database/ensembles.rs', |   'database/ensembles.rs', | ||||||
|   'database/files.rs', |  | ||||||
|   'database/instruments.rs', |   'database/instruments.rs', | ||||||
|   'database/medium.rs', |   'database/medium.rs', | ||||||
|   'database/mod.rs', |   'database/mod.rs', | ||||||
|  |  | ||||||
|  | @ -76,15 +76,15 @@ impl RecordingScreen { | ||||||
|             title_label.set_ellipsize(pango::EllipsizeMode::End); |             title_label.set_ellipsize(pango::EllipsizeMode::End); | ||||||
|             title_label.set_halign(gtk::Align::Start); |             title_label.set_halign(gtk::Align::Start); | ||||||
| 
 | 
 | ||||||
|             // let file_name_label = gtk::Label::new(Some(&track.file_name));
 |             let file_name_label = gtk::Label::new(Some(&track.path)); | ||||||
|             // file_name_label.set_ellipsize(pango::EllipsizeMode::End);
 |             file_name_label.set_ellipsize(pango::EllipsizeMode::End); | ||||||
|             // file_name_label.set_opacity(0.5);
 |             file_name_label.set_opacity(0.5); | ||||||
|             // file_name_label.set_halign(gtk::Align::Start);
 |             file_name_label.set_halign(gtk::Align::Start); | ||||||
| 
 | 
 | ||||||
|             let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0); |             let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0); | ||||||
|             vbox.set_border_width(6); |             vbox.set_border_width(6); | ||||||
|             vbox.add(&title_label); |             vbox.add(&title_label); | ||||||
|             // vbox.add(&file_name_label);
 |             vbox.add(&file_name_label); | ||||||
| 
 | 
 | ||||||
|             vbox.upcast() |             vbox.upcast() | ||||||
|         })); |         })); | ||||||
|  | @ -138,16 +138,16 @@ impl RecordingScreen { | ||||||
|         let context = glib::MainContext::default(); |         let context = glib::MainContext::default(); | ||||||
|         let clone = result.clone(); |         let clone = result.clone(); | ||||||
|         context.spawn_local(async move { |         context.spawn_local(async move { | ||||||
|             // let tracks = clone
 |             let tracks = clone | ||||||
|             //     .backend
 |                 .backend | ||||||
|             //     .db()
 |                 .db() | ||||||
|             //     .get_tracks(&clone.recording.id)
 |                 .get_tracks(&clone.recording.id) | ||||||
|             //     .await
 |                 .await | ||||||
|             //     .unwrap();
 |                 .unwrap(); | ||||||
| 
 | 
 | ||||||
|             // list.show_items(tracks.clone());
 |             list.show_items(tracks.clone()); | ||||||
|             // clone.stack.set_visible_child_name("content");
 |             clone.stack.set_visible_child_name("content"); | ||||||
|             // clone.tracks.replace(tracks);
 |             clone.tracks.replace(tracks); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         result |         result | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Elias Projahn
						Elias Projahn