mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 19:57:25 +01:00
Use flat track list for mediums
This commit is contained in:
parent
e293972c0d
commit
4f617cb79a
11 changed files with 327 additions and 532 deletions
|
|
@ -7,7 +7,7 @@ use glib::prelude::*;
|
|||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::db::{generate_id, Medium, Track, TrackSet};
|
||||
use musicus_backend::db::{generate_id, Medium};
|
||||
use musicus_backend::import::ImportSession;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -26,7 +26,7 @@ pub struct MediumEditor {
|
|||
status_page: libadwaita::StatusPage,
|
||||
disc_status_page: libadwaita::StatusPage,
|
||||
track_set_list: Rc<List>,
|
||||
track_sets: RefCell<Vec<TrackSetData>>,
|
||||
// track_sets: RefCell<Vec<TrackSetData>>,
|
||||
}
|
||||
|
||||
impl Screen<Arc<ImportSession>, ()> for MediumEditor {
|
||||
|
|
@ -65,7 +65,7 @@ impl Screen<Arc<ImportSession>, ()> for MediumEditor {
|
|||
status_page,
|
||||
disc_status_page,
|
||||
track_set_list: list,
|
||||
track_sets: RefCell::new(Vec::new()),
|
||||
// track_sets: RefCell::new(Vec::new()),
|
||||
});
|
||||
|
||||
// Connect signals and callbacks
|
||||
|
|
@ -89,43 +89,43 @@ impl Screen<Arc<ImportSession>, ()> for MediumEditor {
|
|||
|
||||
add_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
spawn!(@clone this, async move {
|
||||
if let Some(track_set) = push!(this.handle, TrackSetEditor, Arc::clone(&this.session)).await {
|
||||
let length = {
|
||||
let mut track_sets = this.track_sets.borrow_mut();
|
||||
track_sets.push(track_set);
|
||||
track_sets.len()
|
||||
};
|
||||
// if let Some(track_set) = push!(this.handle, TrackSetEditor, Arc::clone(&this.session)).await {
|
||||
// let length = {
|
||||
// let mut track_sets = this.track_sets.borrow_mut();
|
||||
// track_sets.push(track_set);
|
||||
// track_sets.len()
|
||||
// };
|
||||
|
||||
this.track_set_list.update(length);
|
||||
}
|
||||
// this.track_set_list.update(length);
|
||||
// }
|
||||
});
|
||||
}));
|
||||
|
||||
this.track_set_list.set_make_widget_cb(clone!(@weak this => move |index| {
|
||||
let track_set = &this.track_sets.borrow()[index];
|
||||
// this.track_set_list.set_make_widget_cb(clone!(@weak this => move |index| {
|
||||
// let track_set = &this.track_sets.borrow()[index];
|
||||
|
||||
let title = track_set.recording.work.get_title();
|
||||
let subtitle = track_set.recording.get_performers();
|
||||
// let title = track_set.recording.work.get_title();
|
||||
// let subtitle = track_set.recording.get_performers();
|
||||
|
||||
let edit_image = gtk::Image::from_icon_name(Some("document-edit-symbolic"));
|
||||
let edit_button = gtk::Button::new();
|
||||
edit_button.set_has_frame(false);
|
||||
edit_button.set_valign(gtk::Align::Center);
|
||||
edit_button.set_child(Some(&edit_image));
|
||||
// let edit_image = gtk::Image::from_icon_name(Some("document-edit-symbolic"));
|
||||
// let edit_button = gtk::Button::new();
|
||||
// edit_button.set_has_frame(false);
|
||||
// edit_button.set_valign(gtk::Align::Center);
|
||||
// edit_button.set_child(Some(&edit_image));
|
||||
|
||||
let row = libadwaita::ActionRow::new();
|
||||
row.set_activatable(true);
|
||||
row.set_title(Some(&title));
|
||||
row.set_subtitle(Some(&subtitle));
|
||||
row.add_suffix(&edit_button);
|
||||
row.set_activatable_widget(Some(&edit_button));
|
||||
// let row = libadwaita::ActionRow::new();
|
||||
// row.set_activatable(true);
|
||||
// row.set_title(Some(&title));
|
||||
// row.set_subtitle(Some(&subtitle));
|
||||
// row.add_suffix(&edit_button);
|
||||
// row.set_activatable_widget(Some(&edit_button));
|
||||
|
||||
edit_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
// edit_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
// TODO: Implement editing.
|
||||
}));
|
||||
// }));
|
||||
|
||||
row.upcast()
|
||||
}));
|
||||
// row.upcast()
|
||||
// }));
|
||||
|
||||
try_again_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
this.widget.set_visible_child_name("content");
|
||||
|
|
@ -155,68 +155,68 @@ impl Screen<Arc<ImportSession>, ()> for MediumEditor {
|
|||
impl MediumEditor {
|
||||
/// Save the medium and possibly upload it to the server.
|
||||
async fn save(&self) -> Result<()> {
|
||||
let name = self.name_entry.get_text().to_string();
|
||||
// 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.handle.backend.get_music_library_path().unwrap().clone();
|
||||
path.push(&name);
|
||||
std::fs::create_dir(&path)?;
|
||||
// let mut path = self.handle.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();
|
||||
let import_tracks = self.session.tracks();
|
||||
// let mut track_sets = Vec::new();
|
||||
// let import_tracks = self.session.tracks();
|
||||
|
||||
for track_set_data in &*self.track_sets.borrow() {
|
||||
let mut tracks = Vec::new();
|
||||
// for track_set_data in &*self.track_sets.borrow() {
|
||||
// let mut tracks = Vec::new();
|
||||
|
||||
for track_data in &track_set_data.tracks {
|
||||
// for track_data in &track_set_data.tracks {
|
||||
// Copy the corresponding audio file to the music library.
|
||||
|
||||
let import_track = &import_tracks[track_data.track_source];
|
||||
// let import_track = &import_tracks[track_data.track_source];
|
||||
|
||||
let mut track_path = path.clone();
|
||||
track_path.push(import_track.path.file_name().unwrap());
|
||||
// let mut track_path = path.clone();
|
||||
// track_path.push(import_track.path.file_name().unwrap());
|
||||
|
||||
std::fs::copy(&import_track.path, &track_path)?;
|
||||
// std::fs::copy(&import_track.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(),
|
||||
};
|
||||
// let track = Track {
|
||||
// work_parts: track_data.work_parts.clone(),
|
||||
// path: track_path.to_str().unwrap().to_owned(),
|
||||
// };
|
||||
|
||||
tracks.push(track);
|
||||
}
|
||||
// tracks.push(track);
|
||||
// }
|
||||
|
||||
let track_set = TrackSet {
|
||||
recording: track_set_data.recording.clone(),
|
||||
tracks,
|
||||
};
|
||||
// let track_set = TrackSet {
|
||||
// recording: track_set_data.recording.clone(),
|
||||
// tracks,
|
||||
// };
|
||||
|
||||
track_sets.push(track_set);
|
||||
}
|
||||
// track_sets.push(track_set);
|
||||
// }
|
||||
|
||||
let medium = Medium {
|
||||
id: generate_id(),
|
||||
name: self.name_entry.get_text().to_string(),
|
||||
discid: Some(self.session.source_id().to_owned()),
|
||||
tracks: track_sets,
|
||||
};
|
||||
// let medium = Medium {
|
||||
// id: generate_id(),
|
||||
// name: self.name_entry.get_text().to_string(),
|
||||
// discid: Some(self.session.source_id().to_owned()),
|
||||
// tracks: track_sets,
|
||||
// };
|
||||
|
||||
let upload = self.publish_switch.get_active();
|
||||
if upload {
|
||||
self.handle.backend.cl().post_medium(&medium).await?;
|
||||
}
|
||||
// let upload = self.publish_switch.get_active();
|
||||
// if upload {
|
||||
// self.handle.backend.cl().post_medium(&medium).await?;
|
||||
// }
|
||||
|
||||
self.handle.backend
|
||||
.db()
|
||||
.update_medium(medium.clone())
|
||||
.await?;
|
||||
// self.handle.backend
|
||||
// .db()
|
||||
// .update_medium(medium.clone())
|
||||
// .await?;
|
||||
|
||||
self.handle.backend.library_changed();
|
||||
// self.handle.backend.library_changed();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,53 +5,21 @@ use gettextrs::gettext;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::PlaylistItem;
|
||||
use musicus_backend::db::Medium;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Elements for visually representing the contents of the medium.
|
||||
enum ListItem {
|
||||
/// A header shown on top of a track set. The value is the index of the corresponding track set
|
||||
/// within the medium.
|
||||
Header(usize),
|
||||
|
||||
/// A track. The indices are from the track set and the track.
|
||||
Track(usize, usize),
|
||||
|
||||
/// A separator shown between track sets.
|
||||
Separator,
|
||||
}
|
||||
|
||||
/// A screen for showing the contents of a medium.
|
||||
pub struct MediumScreen {
|
||||
handle: NavigationHandle<()>,
|
||||
medium: Medium,
|
||||
widget: widgets::Screen,
|
||||
list: Rc<List>,
|
||||
items: Vec<ListItem>,
|
||||
}
|
||||
|
||||
impl Screen<Medium, ()> for MediumScreen {
|
||||
/// Create a new medium screen for the specified medium and load the
|
||||
/// contents asynchronously.
|
||||
fn new(medium: Medium, handle: NavigationHandle<()>) -> Rc<Self> {
|
||||
let mut items = Vec::new();
|
||||
let mut first = true;
|
||||
|
||||
for (track_set_index, track_set) in medium.tracks.iter().enumerate() {
|
||||
if !first {
|
||||
items.push(ListItem::Separator);
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
items.push(ListItem::Header(track_set_index));
|
||||
|
||||
for (track_index, _) in track_set.tracks.iter().enumerate() {
|
||||
items.push(ListItem::Track(track_set_index, track_index));
|
||||
}
|
||||
}
|
||||
|
||||
let widget = widgets::Screen::new();
|
||||
widget.set_title(&medium.name);
|
||||
|
||||
|
|
@ -65,7 +33,6 @@ impl Screen<Medium, ()> for MediumScreen {
|
|||
medium,
|
||||
widget,
|
||||
list,
|
||||
items,
|
||||
});
|
||||
|
||||
this.widget.set_back_cb(clone!(@weak this => move || {
|
||||
|
|
@ -82,63 +49,35 @@ impl Screen<Medium, ()> for MediumScreen {
|
|||
}));
|
||||
|
||||
section.add_action("media-playback-start-symbolic", clone!(@weak this => move || {
|
||||
for track_set in &this.medium.tracks {
|
||||
let indices = (0..track_set.tracks.len()).collect();
|
||||
|
||||
let playlist_item = PlaylistItem {
|
||||
track_set: track_set.clone(),
|
||||
indices,
|
||||
};
|
||||
|
||||
this.handle.backend.pl().add_item(playlist_item).unwrap();
|
||||
for track in &this.medium.tracks {
|
||||
this.handle.backend.pl().add_item(track.clone()).unwrap();
|
||||
}
|
||||
}));
|
||||
|
||||
this.list.set_make_widget_cb(clone!(@weak this => move |index| {
|
||||
match this.items[index] {
|
||||
ListItem::Header(index) => {
|
||||
let track_set = &this.medium.tracks[index];
|
||||
let recording = &track_set.recording;
|
||||
let track = &this.medium.tracks[index];
|
||||
|
||||
let row = libadwaita::ActionRow::new();
|
||||
row.set_activatable(false);
|
||||
row.set_selectable(false);
|
||||
row.set_title(Some(&recording.work.get_title()));
|
||||
row.set_subtitle(Some(&recording.get_performers()));
|
||||
|
||||
row.upcast()
|
||||
}
|
||||
ListItem::Track(track_set_index, track_index) => {
|
||||
let track_set = &this.medium.tracks[track_set_index];
|
||||
let track = &track_set.tracks[track_index];
|
||||
|
||||
let mut parts = Vec::<String>::new();
|
||||
for part in &track.work_parts {
|
||||
parts.push(track_set.recording.work.parts[*part].title.clone());
|
||||
}
|
||||
|
||||
let title = if parts.is_empty() {
|
||||
gettext("Unknown")
|
||||
} else {
|
||||
parts.join(", ")
|
||||
};
|
||||
|
||||
let row = libadwaita::ActionRow::new();
|
||||
row.set_selectable(false);
|
||||
row.set_activatable(false);
|
||||
row.set_title(Some(&title));
|
||||
row.set_margin_start(12);
|
||||
|
||||
row.upcast()
|
||||
}
|
||||
ListItem::Separator => {
|
||||
let separator = gtk::Separator::new(gtk::Orientation::Horizontal);
|
||||
separator.upcast()
|
||||
}
|
||||
let mut parts = Vec::<String>::new();
|
||||
for part in &track.work_parts {
|
||||
parts.push(track.recording.work.parts[*part].title.clone());
|
||||
}
|
||||
|
||||
let title = if parts.is_empty() {
|
||||
gettext("Unknown")
|
||||
} else {
|
||||
parts.join(", ")
|
||||
};
|
||||
|
||||
let row = libadwaita::ActionRow::new();
|
||||
row.set_selectable(false);
|
||||
row.set_activatable(false);
|
||||
row.set_title(Some(&title));
|
||||
row.set_margin_start(12);
|
||||
|
||||
row.upcast()
|
||||
}));
|
||||
|
||||
this.list.update(this.items.len());
|
||||
this.list.update(this.medium.tracks.len());
|
||||
|
||||
this
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,21 +5,25 @@ use glib::clone;
|
|||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::PlaylistItem;
|
||||
use musicus_backend::db::Track;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Elements for visually representing the playlist.
|
||||
enum ListItem {
|
||||
/// A header shown on top of a track set. This contains an index
|
||||
/// referencing the playlist item containing this track set.
|
||||
Header(usize),
|
||||
/// A playable track.
|
||||
Track {
|
||||
/// Index within the playlist.
|
||||
index: usize,
|
||||
|
||||
/// A playable track. This contains an index to the playlist item, an
|
||||
/// index to the track and whether it is the currently played one.
|
||||
Track(usize, usize, bool),
|
||||
/// Whether this is the first track of the recording.
|
||||
first: bool,
|
||||
|
||||
/// A separator shown between track sets.
|
||||
/// Whether this is the currently played track.
|
||||
playing: bool,
|
||||
},
|
||||
|
||||
/// A separator shown between recordings.
|
||||
Separator,
|
||||
}
|
||||
|
||||
|
|
@ -37,10 +41,9 @@ pub struct PlayerScreen {
|
|||
play_image: gtk::Image,
|
||||
pause_image: gtk::Image,
|
||||
list: Rc<List>,
|
||||
playlist: RefCell<Vec<PlaylistItem>>,
|
||||
playlist: RefCell<Vec<Track>>,
|
||||
items: RefCell<Vec<ListItem>>,
|
||||
seeking: Cell<bool>,
|
||||
current_item: Cell<usize>,
|
||||
current_track: Cell<usize>,
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +90,6 @@ impl Screen<(), ()> for PlayerScreen {
|
|||
items: RefCell::new(Vec::new()),
|
||||
playlist: RefCell::new(Vec::new()),
|
||||
seeking: Cell::new(false),
|
||||
current_item: Cell::new(0),
|
||||
current_track: Cell::new(0),
|
||||
});
|
||||
|
||||
|
|
@ -102,28 +104,26 @@ impl Screen<(), ()> for PlayerScreen {
|
|||
this.show_playlist();
|
||||
}));
|
||||
|
||||
player.add_track_cb(clone!(@weak this, @weak player => @default-return (), move |current_item, current_track| {
|
||||
player.add_track_cb(clone!(@weak this, @weak player => @default-return (), move |current_track| {
|
||||
this.previous_button.set_sensitive(this.handle.backend.pl().has_previous());
|
||||
this.next_button.set_sensitive(this.handle.backend.pl().has_next());
|
||||
|
||||
let item = &this.playlist.borrow()[current_item];
|
||||
let track = &item.track_set.tracks[current_track];
|
||||
let track = &this.playlist.borrow()[current_track];
|
||||
|
||||
let mut parts = Vec::<String>::new();
|
||||
for part in &track.work_parts {
|
||||
parts.push(item.track_set.recording.work.parts[*part].title.clone());
|
||||
parts.push(track.recording.work.parts[*part].title.clone());
|
||||
}
|
||||
|
||||
let mut title = item.track_set.recording.work.get_title();
|
||||
let mut title = track.recording.work.get_title();
|
||||
if !parts.is_empty() {
|
||||
title = format!("{}: {}", title, parts.join(", "));
|
||||
}
|
||||
|
||||
this.title_label.set_text(&title);
|
||||
this.subtitle_label.set_text(&item.track_set.recording.get_performers());
|
||||
this.subtitle_label.set_text(&track.recording.get_performers());
|
||||
this.position_label.set_text("0:00");
|
||||
|
||||
this.current_item.set(current_item);
|
||||
this.current_track.set(current_track);
|
||||
|
||||
this.show_playlist();
|
||||
|
|
@ -205,29 +205,17 @@ impl Screen<(), ()> for PlayerScreen {
|
|||
|
||||
this.list.set_make_widget_cb(clone!(@weak this => move |index| {
|
||||
let widget = match this.items.borrow()[index] {
|
||||
ListItem::Header(item_index) => {
|
||||
let playlist_item = &this.playlist.borrow()[item_index];
|
||||
let recording = &playlist_item.track_set.recording;
|
||||
|
||||
let row = libadwaita::ActionRow::new();
|
||||
row.set_activatable(false);
|
||||
row.set_selectable(false);
|
||||
row.set_title(Some(&recording.work.get_title()));
|
||||
row.set_subtitle(Some(&recording.get_performers()));
|
||||
|
||||
row.upcast()
|
||||
}
|
||||
ListItem::Track(item_index, track_index, playing) => {
|
||||
let playlist_item = &this.playlist.borrow()[item_index];
|
||||
let index = playlist_item.indices[track_index];
|
||||
let track = &playlist_item.track_set.tracks[index];
|
||||
ListItem::Track {index, first, playing} => {
|
||||
let track = &this.playlist.borrow()[index];
|
||||
|
||||
let mut parts = Vec::<String>::new();
|
||||
for part in &track.work_parts {
|
||||
parts.push(playlist_item.track_set.recording.work.parts[*part].title.clone());
|
||||
parts.push(track.recording.work.parts[*part].title.clone());
|
||||
}
|
||||
|
||||
let title = if parts.is_empty() {
|
||||
let title = if first {
|
||||
track.recording.work.get_title()
|
||||
} else if parts.is_empty() {
|
||||
gettext("Unknown")
|
||||
} else {
|
||||
parts.join(", ")
|
||||
|
|
@ -238,8 +226,18 @@ impl Screen<(), ()> for PlayerScreen {
|
|||
row.set_activatable(true);
|
||||
row.set_title(Some(&title));
|
||||
|
||||
if first {
|
||||
let subtitle = if !parts.is_empty() {
|
||||
format!("{}\n{}", track.recording.get_performers(), parts.join(", "))
|
||||
} else {
|
||||
track.recording.get_performers()
|
||||
};
|
||||
|
||||
row.set_subtitle(Some(&subtitle));
|
||||
}
|
||||
|
||||
row.connect_activated(clone!(@weak this => move |_| {
|
||||
this.handle.backend.pl().set_track(item_index, track_index).unwrap();
|
||||
this.handle.backend.pl().set_track(index).unwrap();
|
||||
}));
|
||||
|
||||
let icon = if playing {
|
||||
|
|
@ -272,25 +270,35 @@ impl PlayerScreen {
|
|||
/// Update the user interface according to the playlist.
|
||||
fn show_playlist(&self) {
|
||||
let playlist = self.playlist.borrow();
|
||||
let current_item = self.current_item.get();
|
||||
let current_track = self.current_track.get();
|
||||
|
||||
let mut first = true;
|
||||
let mut items = Vec::new();
|
||||
|
||||
for (item_index, playlist_item) in playlist.iter().enumerate() {
|
||||
if !first {
|
||||
items.push(ListItem::Separator);
|
||||
let mut last_recording_id = "";
|
||||
|
||||
for (index, track) in playlist.iter().enumerate() {
|
||||
let first_track = if track.recording.id != last_recording_id {
|
||||
last_recording_id = &track.recording.id;
|
||||
|
||||
if !first {
|
||||
items.push(ListItem::Separator);
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
false
|
||||
};
|
||||
|
||||
items.push(ListItem::Header(item_index));
|
||||
let item = ListItem::Track {
|
||||
index,
|
||||
first: first_track,
|
||||
playing: index == current_track,
|
||||
};
|
||||
|
||||
for (index, _) in playlist_item.indices.iter().enumerate() {
|
||||
let playing = current_item == item_index && current_track == index;
|
||||
items.push(ListItem::Track(item_index, index, playing));
|
||||
}
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
let length = items.len();
|
||||
|
|
|
|||
|
|
@ -6,29 +6,17 @@ use gettextrs::gettext;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::PlaylistItem;
|
||||
use musicus_backend::db::{Recording, TrackSet};
|
||||
use musicus_backend::db::{Recording, Track};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Representation of one entry within the track list.
|
||||
enum ListItem {
|
||||
/// A track row. This hold an index to the track set and an index to the
|
||||
/// track within the track set.
|
||||
Track(usize, usize),
|
||||
|
||||
/// A separator intended for use between track sets.
|
||||
Separator,
|
||||
}
|
||||
|
||||
/// A screen for showing a recording.
|
||||
pub struct RecordingScreen {
|
||||
handle: NavigationHandle<()>,
|
||||
recording: Recording,
|
||||
widget: widgets::Screen,
|
||||
list: Rc<List>,
|
||||
track_sets: RefCell<Vec<TrackSet>>,
|
||||
items: RefCell<Vec<ListItem>>,
|
||||
tracks: RefCell<Vec<Track>>,
|
||||
}
|
||||
|
||||
impl Screen<Recording, ()> for RecordingScreen {
|
||||
|
|
@ -48,22 +36,12 @@ impl Screen<Recording, ()> for RecordingScreen {
|
|||
recording,
|
||||
widget,
|
||||
list,
|
||||
track_sets: RefCell::new(Vec::new()),
|
||||
items: RefCell::new(Vec::new()),
|
||||
tracks: RefCell::new(Vec::new()),
|
||||
});
|
||||
|
||||
section.add_action("media-playback-start-symbolic", clone!(@weak this => move || {
|
||||
if let Some(player) = this.handle.backend.get_player() {
|
||||
if let Some(track_set) = this.track_sets.borrow().get(0).cloned() {
|
||||
let indices = (0..track_set.tracks.len()).collect();
|
||||
|
||||
let playlist_item = PlaylistItem {
|
||||
track_set,
|
||||
indices,
|
||||
};
|
||||
|
||||
player.add_item(playlist_item).unwrap();
|
||||
}
|
||||
for track in &*this.tracks.borrow() {
|
||||
this.handle.backend.pl().add_item(track.clone()).unwrap();
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
@ -86,47 +64,36 @@ impl Screen<Recording, ()> for RecordingScreen {
|
|||
}));
|
||||
|
||||
this.list.set_make_widget_cb(clone!(@weak this => move |index| {
|
||||
let widget = match this.items.borrow()[index] {
|
||||
ListItem::Track(track_set_index, track_index) => {
|
||||
let track_set = &this.track_sets.borrow()[track_set_index];
|
||||
let track = &track_set.tracks[track_index];
|
||||
let track = &this.tracks.borrow()[index];
|
||||
|
||||
let mut title_parts = Vec::<String>::new();
|
||||
for part in &track.work_parts {
|
||||
title_parts.push(this.recording.work.parts[*part].title.clone());
|
||||
}
|
||||
let mut title_parts = Vec::<String>::new();
|
||||
for part in &track.work_parts {
|
||||
title_parts.push(this.recording.work.parts[*part].title.clone());
|
||||
}
|
||||
|
||||
let title = if title_parts.is_empty() {
|
||||
gettext("Unknown")
|
||||
} else {
|
||||
title_parts.join(", ")
|
||||
};
|
||||
|
||||
let row = libadwaita::ActionRow::new();
|
||||
row.set_title(Some(&title));
|
||||
|
||||
row.upcast()
|
||||
}
|
||||
ListItem::Separator => {
|
||||
let separator = gtk::Separator::new(gtk::Orientation::Horizontal);
|
||||
separator.upcast()
|
||||
}
|
||||
let title = if title_parts.is_empty() {
|
||||
gettext("Unknown")
|
||||
} else {
|
||||
title_parts.join(", ")
|
||||
};
|
||||
|
||||
widget
|
||||
let row = libadwaita::ActionRow::new();
|
||||
row.set_title(Some(&title));
|
||||
|
||||
row.upcast()
|
||||
}));
|
||||
|
||||
// Load the content asynchronously.
|
||||
|
||||
spawn!(@clone this, async move {
|
||||
let track_sets = this.handle
|
||||
let tracks = this.handle
|
||||
.backend
|
||||
.db()
|
||||
.get_track_sets(&this.recording.id)
|
||||
.get_tracks(&this.recording.id)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
this.show_track_sets(track_sets);
|
||||
this.show_tracks(tracks);
|
||||
this.widget.ready();
|
||||
});
|
||||
|
||||
|
|
@ -135,26 +102,10 @@ impl Screen<Recording, ()> for RecordingScreen {
|
|||
}
|
||||
|
||||
impl RecordingScreen {
|
||||
/// Update the track sets variable as well as the user interface.
|
||||
fn show_track_sets(&self, track_sets: Vec<TrackSet>) {
|
||||
let mut first = true;
|
||||
let mut items = Vec::new();
|
||||
|
||||
for (track_set_index, track_set) in track_sets.iter().enumerate() {
|
||||
if !first {
|
||||
items.push(ListItem::Separator);
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
for (track_index, _) in track_set.tracks.iter().enumerate() {
|
||||
items.push(ListItem::Track(track_set_index, track_index));
|
||||
}
|
||||
}
|
||||
|
||||
let length = items.len();
|
||||
self.items.replace(items);
|
||||
self.track_sets.replace(track_sets);
|
||||
/// Update the tracks variable as well as the user interface.
|
||||
fn show_tracks(&self, tracks: Vec<Track>) {
|
||||
let length = tracks.len();
|
||||
self.tracks.replace(tracks);
|
||||
self.list.update(length);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use musicus_backend::{Player, PlaylistItem};
|
||||
use musicus_backend::Player;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ impl PlayerBar {
|
|||
self.player.replace(player.clone());
|
||||
|
||||
if let Some(player) = player {
|
||||
let playlist = Rc::new(RefCell::new(Vec::<PlaylistItem>::new()));
|
||||
let playlist = Rc::new(RefCell::new(Vec::new()));
|
||||
|
||||
player.add_playlist_cb(clone!(
|
||||
@strong player,
|
||||
|
|
@ -107,25 +107,24 @@ impl PlayerBar {
|
|||
@strong self.title_label as title_label,
|
||||
@strong self.subtitle_label as subtitle_label,
|
||||
@strong self.position_label as position_label
|
||||
=> move |current_item, current_track| {
|
||||
=> move |current_track| {
|
||||
previous_button.set_sensitive(player.has_previous());
|
||||
next_button.set_sensitive(player.has_next());
|
||||
|
||||
let item = &playlist.borrow()[current_item];
|
||||
let track = &item.track_set.tracks[current_track];
|
||||
let track = &playlist.borrow()[current_track];
|
||||
|
||||
let mut parts = Vec::<String>::new();
|
||||
for part in &track.work_parts {
|
||||
parts.push(item.track_set.recording.work.parts[*part].title.clone());
|
||||
parts.push(track.recording.work.parts[*part].title.clone());
|
||||
}
|
||||
|
||||
let mut title = item.track_set.recording.work.get_title();
|
||||
let mut title = track.recording.work.get_title();
|
||||
if !parts.is_empty() {
|
||||
title = format!("{}: {}", title, parts.join(", "));
|
||||
}
|
||||
|
||||
title_label.set_text(&title);
|
||||
subtitle_label.set_text(&item.track_set.recording.get_performers());
|
||||
subtitle_label.set_text(&track.recording.get_performers());
|
||||
position_label.set_text("0:00");
|
||||
}
|
||||
));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue