mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 11:47:25 +01:00
Add medium screen
This commit is contained in:
parent
d12b85afc6
commit
29b8a9c2c5
4 changed files with 166 additions and 4 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
use super::RecordingScreen;
|
use super::{MediumScreen, RecordingScreen};
|
||||||
use crate::editors::EnsembleEditor;
|
use crate::editors::EnsembleEditor;
|
||||||
use crate::navigator::{NavigatorWindow, NavigationHandle, Screen};
|
use crate::navigator::{NavigatorWindow, NavigationHandle, Screen};
|
||||||
use crate::widgets;
|
use crate::widgets;
|
||||||
|
|
@ -99,8 +99,12 @@ impl Screen<Ensemble, ()> for EnsembleScreen {
|
||||||
row.set_activatable(true);
|
row.set_activatable(true);
|
||||||
row.set_title(Some(&medium.name));
|
row.set_title(Some(&medium.name));
|
||||||
|
|
||||||
|
let medium = medium.to_owned();
|
||||||
row.connect_activated(clone!(@weak this => move |_| {
|
row.connect_activated(clone!(@weak this => move |_| {
|
||||||
// TODO: Show medium screen.
|
let medium = medium.clone();
|
||||||
|
spawn!(@clone this, async move {
|
||||||
|
push!(this.handle, MediumScreen, medium.clone()).await;
|
||||||
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
row.upcast()
|
row.upcast()
|
||||||
|
|
|
||||||
151
crates/musicus/src/screens/medium.rs
Normal file
151
crates/musicus/src/screens/medium.rs
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
use crate::navigator::{NavigationHandle, Screen};
|
||||||
|
use crate::widgets;
|
||||||
|
use crate::widgets::{List, Section, Widget};
|
||||||
|
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);
|
||||||
|
|
||||||
|
let list = List::new();
|
||||||
|
let section = Section::new("Recordings", &list.widget);
|
||||||
|
widget.add_content(§ion.widget);
|
||||||
|
widget.ready();
|
||||||
|
|
||||||
|
let this = Rc::new(Self {
|
||||||
|
handle,
|
||||||
|
medium,
|
||||||
|
widget,
|
||||||
|
list,
|
||||||
|
items,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.widget.set_back_cb(clone!(@weak this => move || {
|
||||||
|
this.handle.pop(None);
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
this.widget.add_action(&gettext("Edit medium"), clone!(@weak this => move || {
|
||||||
|
// TODO: Show medium editor.
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.widget.add_action(&gettext("Delete medium"), clone!(@weak this => move || {
|
||||||
|
// TODO: Delete medium and maybe also the tracks?
|
||||||
|
}));
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
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 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.list.update(this.items.len());
|
||||||
|
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for MediumScreen {
|
||||||
|
fn get_widget(&self) -> gtk::Widget {
|
||||||
|
self.widget.widget.clone().upcast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,9 @@ pub use ensemble::*;
|
||||||
pub mod main;
|
pub mod main;
|
||||||
pub use main::*;
|
pub use main::*;
|
||||||
|
|
||||||
|
pub mod medium;
|
||||||
|
pub use medium::*;
|
||||||
|
|
||||||
pub mod person;
|
pub mod person;
|
||||||
pub use person::*;
|
pub use person::*;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{WorkScreen, RecordingScreen};
|
use super::{MediumScreen, WorkScreen, RecordingScreen};
|
||||||
use crate::editors::PersonEditor;
|
use crate::editors::PersonEditor;
|
||||||
use crate::navigator::{NavigatorWindow, NavigationHandle, Screen};
|
use crate::navigator::{NavigatorWindow, NavigationHandle, Screen};
|
||||||
use crate::widgets;
|
use crate::widgets;
|
||||||
|
|
@ -130,8 +130,12 @@ impl Screen<Person, ()> for PersonScreen {
|
||||||
row.set_activatable(true);
|
row.set_activatable(true);
|
||||||
row.set_title(Some(&medium.name));
|
row.set_title(Some(&medium.name));
|
||||||
|
|
||||||
|
let medium = medium.to_owned();
|
||||||
row.connect_activated(clone!(@weak this => move |_| {
|
row.connect_activated(clone!(@weak this => move |_| {
|
||||||
// TODO: Show medium screen.
|
let medium = medium.clone();
|
||||||
|
spawn!(@clone this, async move {
|
||||||
|
push!(this.handle, MediumScreen, medium.clone()).await;
|
||||||
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
row.upcast()
|
row.upcast()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue