Add player details screen

This commit is contained in:
Elias Projahn 2020-11-07 20:07:26 +01:00
parent 8e952fb6e2
commit eb77c97f9b
24 changed files with 792 additions and 43 deletions

View file

@ -49,6 +49,11 @@ where
for (index, ensemble) in ensembles.iter().enumerate() {
let label = gtk::Label::new(Some(&ensemble.name));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
let row = SelectorRow::new(index.try_into().unwrap(), &label);
row.show_all();
clone.list.insert(&row, -1);

View file

@ -49,6 +49,11 @@ where
for (index, instrument) in instruments.iter().enumerate() {
let label = gtk::Label::new(Some(&instrument.name));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
let row = SelectorRow::new(index.try_into().unwrap(), &label);
row.show_all();
clone.list.insert(&row, -1);

View file

@ -140,6 +140,11 @@ impl PartEditor {
for (index, instrument) in self.instruments.borrow().iter().enumerate() {
let label = gtk::Label::new(Some(&instrument.name));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
let row = SelectorRow::new(index.try_into().unwrap(), &label);
row.show_all();
self.instrument_list.insert(&row, -1);

View file

@ -163,6 +163,11 @@ where
for (index, performer) in self.performers.borrow().iter().enumerate() {
let label = gtk::Label::new(Some(&performer.get_title()));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
let row = SelectorRow::new(index.try_into().unwrap(), &label);
row.show_all();
self.performer_list.insert(&row, -1);

View file

@ -110,6 +110,10 @@ impl RecordingSelectorPersonScreen {
|work: &WorkDescription| {
let label = gtk::Label::new(Some(&work.title));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
label.upcast()
},
|_| true,
@ -213,6 +217,7 @@ impl RecordingSelectorWorkScreen {
performers_label.set_halign(gtk::Align::Start);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
vbox.set_border_width(6);
vbox.add(&work_label);
vbox.add(&performers_label);

View file

@ -71,6 +71,7 @@ impl TracksEditor {
file_name_label.set_halign(gtk::Align::Start);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
vbox.set_border_width(6);
vbox.add(&title_label);
vbox.add(&file_name_label);

View file

@ -341,6 +341,11 @@ where
for (index, instrument) in self.instruments.borrow().iter().enumerate() {
let label = gtk::Label::new(Some(&instrument.name));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
let row = SelectorRow::new(index.try_into().unwrap(), &label);
row.show_all();
self.instrument_list.insert(&row, -1);
@ -365,6 +370,10 @@ where
for (index, part) in self.structure.borrow().iter().enumerate() {
let label = gtk::Label::new(Some(&part.get_title()));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
if part.is_part() {
label.set_margin_start(6);

View file

@ -142,6 +142,11 @@ where
for (index, person) in persons.iter().enumerate() {
let label = gtk::Label::new(Some(&person.name_lf()));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
let row = SelectorRow::new(index.try_into().unwrap(), &label);
row.show_all();
self.person_list.insert(&row, -1);
@ -207,6 +212,11 @@ where
for (index, work) in works.iter().enumerate() {
let label = gtk::Label::new(Some(&work.title));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
let row = SelectorRow::new(index.try_into().unwrap(), &label);
row.show_all();
self.work_list.insert(&row, -1);

View file

@ -57,6 +57,7 @@ sources = files(
'screens/ensemble_screen.rs',
'screens/mod.rs',
'screens/person_screen.rs',
'screens/player_screen.rs',
'screens/recording_screen.rs',
'screens/work_screen.rs',
'widgets/list.rs',

View file

@ -19,11 +19,11 @@ pub struct Player {
current_item: Cell<Option<usize>>,
current_track: Cell<Option<usize>>,
playing: Cell<bool>,
playlist_cb: RefCell<Option<Box<dyn Fn(Vec<PlaylistItem>) -> ()>>>,
track_cb: RefCell<Option<Box<dyn Fn(usize, usize) -> ()>>>,
duration_cb: RefCell<Option<Box<dyn Fn(u64) -> ()>>>,
playing_cb: RefCell<Option<Box<dyn Fn(bool) -> ()>>>,
position_cb: RefCell<Option<Box<dyn Fn(u64) -> ()>>>,
playlist_cbs: RefCell<Vec<Box<dyn Fn(Vec<PlaylistItem>) -> ()>>>,
track_cbs: RefCell<Vec<Box<dyn Fn(usize, usize) -> ()>>>,
duration_cbs: RefCell<Vec<Box<dyn Fn(u64) -> ()>>>,
playing_cbs: RefCell<Vec<Box<dyn Fn(bool) -> ()>>>,
position_cbs: RefCell<Vec<Box<dyn Fn(u64) -> ()>>>,
}
impl Player {
@ -42,11 +42,11 @@ impl Player {
current_item: Cell::new(None),
current_track: Cell::new(None),
playing: Cell::new(false),
playlist_cb: RefCell::new(None),
track_cb: RefCell::new(None),
duration_cb: RefCell::new(None),
playing_cb: RefCell::new(None),
position_cb: RefCell::new(None),
playlist_cbs: RefCell::new(Vec::new()),
track_cbs: RefCell::new(Vec::new()),
duration_cbs: RefCell::new(Vec::new()),
playing_cbs: RefCell::new(Vec::new()),
position_cbs: RefCell::new(Vec::new()),
});
let clone = fragile::Fragile::new(result.clone());
@ -56,8 +56,8 @@ impl Player {
clone.next().unwrap();
} else {
clone.player.stop();
if let Some(cb) = &*clone.playing_cb.borrow() {
clone.playing.replace(false);
for cb in &*clone.playing_cbs.borrow() {
cb(false);
}
}
@ -65,14 +65,14 @@ impl Player {
let clone = fragile::Fragile::new(result.clone());
player.connect_position_updated(move |_, position| {
if let Some(cb) = &*clone.get().position_cb.borrow() {
for cb in &*clone.get().position_cbs.borrow() {
cb(position.mseconds().unwrap());
}
});
let clone = fragile::Fragile::new(result.clone());
player.connect_duration_changed(move |_, duration| {
if let Some(cb) = &*clone.get().duration_cb.borrow() {
for cb in &*clone.get().duration_cbs.borrow() {
cb(duration.mseconds().unwrap());
}
});
@ -80,24 +80,24 @@ impl Player {
result
}
pub fn set_playlist_cb<F: Fn(Vec<PlaylistItem>) -> () + 'static>(&self, cb: F) {
self.playlist_cb.replace(Some(Box::new(cb)));
pub fn add_playlist_cb<F: Fn(Vec<PlaylistItem>) -> () + 'static>(&self, cb: F) {
self.playlist_cbs.borrow_mut().push(Box::new(cb));
}
pub fn set_track_cb<F: Fn(usize, usize) -> () + 'static>(&self, cb: F) {
self.track_cb.replace(Some(Box::new(cb)));
pub fn add_track_cb<F: Fn(usize, usize) -> () + 'static>(&self, cb: F) {
self.track_cbs.borrow_mut().push(Box::new(cb));
}
pub fn set_duration_cb<F: Fn(u64) -> () + 'static>(&self, cb: F) {
self.duration_cb.replace(Some(Box::new(cb)));
pub fn add_duration_cb<F: Fn(u64) -> () + 'static>(&self, cb: F) {
self.duration_cbs.borrow_mut().push(Box::new(cb));
}
pub fn set_playing_cb<F: Fn(bool) -> () + 'static>(&self, cb: F) {
self.playing_cb.replace(Some(Box::new(cb)));
pub fn add_playing_cb<F: Fn(bool) -> () + 'static>(&self, cb: F) {
self.playing_cbs.borrow_mut().push(Box::new(cb));
}
pub fn set_position_cb<F: Fn(u64) -> () + 'static>(&self, cb: F) {
self.position_cb.replace(Some(Box::new(cb)));
pub fn add_position_cb<F: Fn(u64) -> () + 'static>(&self, cb: F) {
self.position_cbs.borrow_mut().push(Box::new(cb));
}
pub fn get_playlist(&self) -> Vec<PlaylistItem> {
@ -135,7 +135,7 @@ impl Player {
was_empty
};
if let Some(cb) = &*self.playlist_cb.borrow() {
for cb in &*self.playlist_cbs.borrow() {
cb(self.playlist.borrow().clone());
}
@ -144,7 +144,7 @@ impl Player {
self.player.play();
self.playing.set(true);
if let Some(cb) = &*self.playing_cb.borrow() {
for cb in &*self.playing_cbs.borrow() {
cb(true);
}
}
@ -158,19 +158,23 @@ impl Player {
self.player.pause();
self.playing.set(false);
if let Some(cb) = &*self.playing_cb.borrow() {
for cb in &*self.playing_cbs.borrow() {
cb(false);
}
} else {
self.player.play();
self.playing.set(true);
if let Some(cb) = &*self.playing_cb.borrow() {
for cb in &*self.playing_cbs.borrow() {
cb(true);
}
}
}
pub fn seek(&self, ms: u64) {
self.player.seek(gstreamer::ClockTime::from_mseconds(ms));
}
pub fn has_previous(&self) -> bool {
if let Some(current_item) = self.current_item.get() {
if let Some(current_track) = self.current_track.get() {
@ -266,7 +270,7 @@ impl Player {
self.current_item.set(Some(current_item));
self.current_track.set(Some(current_track));
if let Some(cb) = &*self.track_cb.borrow() {
for cb in &*self.track_cbs.borrow() {
cb(current_item, current_track);
}
@ -280,11 +284,11 @@ impl Player {
self.current_track.set(None);
self.playlist.replace(Vec::new());
if let Some(cb) = &*self.playing_cb.borrow() {
for cb in &*self.playing_cbs.borrow() {
cb(false);
}
if let Some(cb) = &*self.playlist_cb.borrow() {
for cb in &*self.playlist_cbs.borrow() {
cb(Vec::new());
}
}

View file

@ -63,6 +63,7 @@ impl EnsembleScreen {
performers_label.set_halign(gtk::Align::Start);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
vbox.set_border_width(6);
vbox.add(&work_label);
vbox.add(&performers_label);

View file

@ -4,6 +4,9 @@ pub use ensemble_screen::*;
pub mod person_screen;
pub use person_screen::*;
pub mod player_screen;
pub use player_screen::*;
pub mod work_screen;
pub use work_screen::*;

View file

@ -58,6 +58,10 @@ impl PersonScreen {
|work: &WorkDescription| {
let label = gtk::Label::new(Some(&work.title));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
label.upcast()
},
clone!(@strong search_entry => move |work: &WorkDescription| {
@ -81,6 +85,7 @@ impl PersonScreen {
performers_label.set_halign(gtk::Align::Start);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
vbox.set_border_width(6);
vbox.add(&work_label);
vbox.add(&performers_label);

View file

@ -0,0 +1,336 @@
use crate::player::*;
use crate::widgets::*;
use gettextrs::gettext;
use glib::clone;
use gtk::prelude::*;
use gtk_macros::get_widget;
use std::cell::{Cell, RefCell};
use std::rc::Rc;
struct PlaylistElement {
pub item: usize,
pub track: usize,
pub title: String,
pub subtitle: Option<String>,
pub playable: bool,
}
pub struct PlayerScreen {
pub widget: gtk::Box,
title_label: gtk::Label,
subtitle_label: gtk::Label,
previous_button: gtk::Button,
play_button: gtk::Button,
next_button: gtk::Button,
position_label: gtk::Label,
position: gtk::Adjustment,
duration_label: gtk::Label,
play_image: gtk::Image,
pause_image: gtk::Image,
list: Rc<List<PlaylistElement>>,
player: Rc<RefCell<Option<Rc<Player>>>>,
seeking: Rc<Cell<bool>>,
current_item: Rc<Cell<usize>>,
current_track: Rc<Cell<usize>>,
back_cb: Rc<RefCell<Option<Box<dyn Fn() -> ()>>>>,
}
impl PlayerScreen {
pub fn new() -> Self {
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/player_screen.ui");
get_widget!(builder, gtk::Box, widget);
get_widget!(builder, gtk::Button, back_button);
get_widget!(builder, gtk::Label, title_label);
get_widget!(builder, gtk::Label, subtitle_label);
get_widget!(builder, gtk::Button, previous_button);
get_widget!(builder, gtk::Button, play_button);
get_widget!(builder, gtk::Button, next_button);
get_widget!(builder, gtk::Button, stop_button);
get_widget!(builder, gtk::Label, position_label);
get_widget!(builder, gtk::Scale, position_scale);
get_widget!(builder, gtk::Adjustment, position);
get_widget!(builder, gtk::Label, duration_label);
get_widget!(builder, gtk::Image, play_image);
get_widget!(builder, gtk::Image, pause_image);
get_widget!(builder, gtk::Frame, frame);
let back_cb = Rc::new(RefCell::new(None::<Box<dyn Fn() -> ()>>));
back_button.connect_clicked(clone!(@strong back_cb => move |_| {
if let Some(cb) = &*back_cb.borrow() {
cb();
}
}));
let player = Rc::new(RefCell::new(None::<Rc<Player>>));
let seeking = Rc::new(Cell::new(false));
previous_button.connect_clicked(clone!(@strong player => move |_| {
if let Some(player) = &*player.borrow() {
player.previous().unwrap();
}
}));
play_button.connect_clicked(clone!(@strong player => move |_| {
if let Some(player) = &*player.borrow() {
player.play_pause();
}
}));
next_button.connect_clicked(clone!(@strong player => move |_| {
if let Some(player) = &*player.borrow() {
player.next().unwrap();
}
}));
stop_button.connect_clicked(clone!(@strong player, @strong back_cb => move |_| {
if let Some(player) = &*player.borrow() {
if let Some(cb) = &*back_cb.borrow() {
cb();
}
player.clear();
}
}));
position_scale.connect_button_press_event(clone!(@strong seeking => move |_, _| {
seeking.replace(true);
Inhibit(false)
}));
position_scale.connect_button_release_event(
clone!(@strong seeking, @strong position, @strong player => move |_, _| {
if let Some(player) = &*player.borrow() {
player.seek(position.get_value() as u64);
}
seeking.replace(false);
Inhibit(false)
}),
);
position_scale.connect_value_changed(
clone!(@strong seeking, @strong position, @strong position_label => move |_| {
if seeking.get() {
let ms = position.get_value() as u64;
let min = ms / 60000;
let sec = (ms % 60000) / 1000;
position_label.set_text(&format!("{}:{:02}", min, sec));
}
}),
);
let current_item = Rc::new(Cell::<usize>::new(0));
let current_track = Rc::new(Cell::<usize>::new(0));
let list = List::new(
clone!(
@strong current_item,
@strong current_track
=> move |element: &PlaylistElement| {
let title_label = gtk::Label::new(Some(&element.title));
title_label.set_ellipsize(pango::EllipsizeMode::End);
title_label.set_halign(gtk::Align::Start);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
vbox.add(&title_label);
if let Some(subtitle) = &element.subtitle {
let subtitle_label = gtk::Label::new(Some(&subtitle));
subtitle_label.set_ellipsize(pango::EllipsizeMode::End);
subtitle_label.set_halign(gtk::Align::Start);
subtitle_label.set_opacity(0.5);
vbox.add(&subtitle_label);
}
let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 6);
hbox.set_border_width(6);
if element.playable {
let image = gtk::Image::new();
if element.item == current_item.get() && element.track == current_track.get() {
image.set_from_icon_name(
Some("media-playback-start-symbolic"),
gtk::IconSize::Button,
);
}
hbox.add(&image);
} else if element.item > 0 {
hbox.set_margin_top(18);
}
hbox.add(&vbox);
hbox.upcast()
}
),
|_| true,
"",
);
list.set_selected(clone!(@strong player => move |element| {
if let Some(player) = &*player.borrow() {
player.set_track(element.item, element.track).unwrap();
}
}));
frame.add(&list.widget);
Self {
widget,
title_label,
subtitle_label,
previous_button,
play_button,
next_button,
position_label,
position,
duration_label,
play_image,
pause_image,
list,
player,
seeking,
current_item,
current_track,
back_cb,
}
}
pub fn set_player(&self, player: Option<Rc<Player>>) {
self.player.replace(player.clone());
if let Some(player) = player {
let playlist = Rc::new(RefCell::new(Vec::<PlaylistItem>::new()));
player.add_playlist_cb(clone!(
@strong player,
@strong self.previous_button as previous_button,
@strong self.next_button as next_button,
@strong self.list as list,
@strong playlist
=> move |new_playlist| {
playlist.replace(new_playlist);
previous_button.set_sensitive(player.has_previous());
next_button.set_sensitive(player.has_next());
let mut elements = Vec::new();
for (item_index, item) in playlist.borrow().iter().enumerate() {
elements.push(PlaylistElement {
item: item_index,
track: 0,
title: item.recording.work.get_title(),
subtitle: Some(item.recording.get_performers()),
playable: false,
});
for (track_index, track) in item.tracks.iter().enumerate() {
let mut parts = Vec::<String>::new();
for part in &track.work_parts {
parts.push(item.recording.work.parts[*part].title.clone());
}
let title = if parts.is_empty() {
gettext("Unknown")
} else {
parts.join(", ")
};
elements.push(PlaylistElement {
item: item_index,
track: track_index,
title: title,
subtitle: None,
playable: true,
});
}
}
list.show_items(elements);
}
));
player.add_track_cb(clone!(
@strong player,
@strong playlist,
@strong self.previous_button as previous_button,
@strong self.next_button as next_button,
@strong self.title_label as title_label,
@strong self.subtitle_label as subtitle_label,
@strong self.position_label as position_label,
@strong self.current_item as self_item,
@strong self.current_track as self_track,
@strong self.list as list
=> move |current_item, 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.tracks[current_track];
let mut parts = Vec::<String>::new();
for part in &track.work_parts {
parts.push(item.recording.work.parts[*part].title.clone());
}
let mut title = item.recording.work.get_title();
if !parts.is_empty() {
title = format!("{}: {}", title, parts.join(", "));
}
title_label.set_text(&title);
subtitle_label.set_text(&item.recording.get_performers());
position_label.set_text("0:00");
self_item.replace(current_item);
self_track.replace(current_track);
list.update();
}
));
player.add_duration_cb(clone!(
@strong self.duration_label as duration_label,
@strong self.position as position
=> move |ms| {
let min = ms / 60000;
let sec = (ms % 60000) / 1000;
duration_label.set_text(&format!("{}:{:02}", min, sec));
position.set_upper(ms as f64);
}
));
player.add_playing_cb(clone!(
@strong self.play_button as play_button,
@strong self.play_image as play_image,
@strong self.pause_image as pause_image
=> move |playing| {
if let Some(child) = play_button.get_child() {
play_button.remove( &child);
}
play_button.add(if playing {
&pause_image
} else {
&play_image
});
}
));
player.add_position_cb(clone!(
@strong self.position_label as position_label,
@strong self.position as position,
@strong self.seeking as seeking
=> move |ms| {
if !seeking.get() {
let min = ms / 60000;
let sec = (ms % 60000) / 1000;
position_label.set_text(&format!("{}:{:02}", min, sec));
position.set_value(ms as f64);
}
}
));
}
}
pub fn set_back_cb<F: Fn() -> () + 'static>(&self, cb: F) {
self.back_cb.replace(Some(Box::new(cb)));
}
}

View file

@ -75,6 +75,7 @@ impl RecordingScreen {
file_name_label.set_halign(gtk::Align::Start);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
vbox.set_border_width(6);
vbox.add(&title_label);
vbox.add(&file_name_label);

View file

@ -64,6 +64,7 @@ impl WorkScreen {
performers_label.set_halign(gtk::Align::Start);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
vbox.set_border_width(6);
vbox.add(&work_label);
vbox.add(&performers_label);

View file

@ -88,12 +88,23 @@ where
}
pub fn select_index(&self, index: usize) {
self.widget.select_row(self.widget.get_row_at_index(index.try_into().unwrap()).as_ref());
self.widget.select_row(
self.widget
.get_row_at_index(index.try_into().unwrap())
.as_ref(),
);
}
pub fn show_items(&self, items: Vec<T>) {
self.items.replace(items);
self.update();
}
pub fn invalidate_filter(&self) {
self.widget.invalidate_filter();
}
pub fn update(&self) {
for child in self.widget.get_children() {
self.widget.remove(&child);
}
@ -105,10 +116,6 @@ where
}
}
pub fn invalidate_filter(&self) {
self.widget.invalidate_filter();
}
pub fn clear_selection(&self) {
self.widget.unselect_all();
}

View file

@ -27,6 +27,10 @@ impl PersonList {
|person: &Person| {
let label = gtk::Label::new(Some(&person.name_lf()));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
label.upcast()
},
clone!(@strong search_entry => move |person: &Person| {

View file

@ -17,6 +17,7 @@ pub struct PlayerBar {
play_image: gtk::Image,
pause_image: gtk::Image,
player: Rc<RefCell<Option<Rc<Player>>>>,
playlist_cb: Rc<RefCell<Option<Box<dyn Fn() -> ()>>>>,
}
impl PlayerBar {
@ -31,10 +32,12 @@ impl PlayerBar {
get_widget!(builder, gtk::Button, next_button);
get_widget!(builder, gtk::Label, position_label);
get_widget!(builder, gtk::Label, duration_label);
get_widget!(builder, gtk::Button, playlist_button);
get_widget!(builder, gtk::Image, play_image);
get_widget!(builder, gtk::Image, pause_image);
let player = Rc::new(RefCell::new(None::<Rc<Player>>));
let playlist_cb = Rc::new(RefCell::new(None::<Box<dyn Fn() -> ()>>));
previous_button.connect_clicked(clone!(@strong player => move |_| {
if let Some(player) = &*player.borrow() {
@ -54,6 +57,12 @@ impl PlayerBar {
}
}));
playlist_button.connect_clicked(clone!(@strong playlist_cb => move |_| {
if let Some(cb) = &*playlist_cb.borrow() {
cb();
}
}));
Self {
widget,
title_label,
@ -66,6 +75,7 @@ impl PlayerBar {
play_image,
pause_image,
player: player,
playlist_cb: playlist_cb,
}
}
@ -75,7 +85,7 @@ impl PlayerBar {
if let Some(player) = player {
let playlist = Rc::new(RefCell::new(Vec::<PlaylistItem>::new()));
player.set_playlist_cb(clone!(
player.add_playlist_cb(clone!(
@strong player,
@strong self.widget as widget,
@strong self.previous_button as previous_button,
@ -89,7 +99,7 @@ impl PlayerBar {
}
));
player.set_track_cb(clone!(
player.add_track_cb(clone!(
@strong player,
@strong playlist,
@strong self.previous_button as previous_button,
@ -120,7 +130,7 @@ impl PlayerBar {
}
));
player.set_duration_cb(clone!(
player.add_duration_cb(clone!(
@strong self.duration_label as duration_label
=> move |ms| {
let min = ms / 60000;
@ -129,7 +139,7 @@ impl PlayerBar {
}
));
player.set_playing_cb(clone!(
player.add_playing_cb(clone!(
@strong self.play_button as play_button,
@strong self.play_image as play_image,
@strong self.pause_image as pause_image
@ -146,7 +156,7 @@ impl PlayerBar {
}
));
player.set_position_cb(clone!(
player.add_position_cb(clone!(
@strong self.position_label as position_label
=> move |ms| {
let min = ms / 60000;
@ -158,4 +168,8 @@ impl PlayerBar {
self.widget.set_reveal_child(false);
}
}
pub fn set_playlist_cb<F: Fn() -> () + 'static>(&self, cb: F) {
self.playlist_cb.replace(Some(Box::new(cb)));
}
}

View file

@ -42,6 +42,10 @@ impl PoeList {
|poe: &PersonOrEnsemble| {
let label = gtk::Label::new(Some(&poe.get_title()));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
label.upcast()
},
clone!(@strong search_entry => move |poe: &PersonOrEnsemble| {

View file

@ -90,7 +90,6 @@ impl ObjectImpl for SelectorRowPriv {
self.parent_constructed(object);
let row = object.downcast_ref::<SelectorRow>().unwrap();
row.set_border_width(6);
let child = self.child.borrow();
match child.as_ref() {

View file

@ -20,6 +20,7 @@ pub struct Window {
poe_list: Rc<PoeList>,
navigator: Rc<Navigator>,
player_bar: PlayerBar,
player_screen: PlayerScreen,
}
impl Window {
@ -38,6 +39,9 @@ impl Window {
let backend = Rc::new(Backend::new());
backend.clone().init();
let player_screen = PlayerScreen::new();
stack.add_named(&player_screen.widget, "player_screen");
let poe_list = PoeList::new(backend.clone());
let navigator = Navigator::new(&empty_screen);
navigator.set_back_cb(clone!(@strong leaflet, @strong sidebar_box => move || {
@ -56,6 +60,7 @@ impl Window {
poe_list,
navigator,
player_bar,
player_screen,
});
result.window.set_application(Some(app));
@ -85,6 +90,18 @@ impl Window {
})).show();
}));
result
.player_bar
.set_playlist_cb(clone!(@strong result => move || {
result.stack.set_visible_child_name("player_screen");
}));
result
.player_screen
.set_back_cb(clone!(@strong result => move || {
result.stack.set_visible_child_name("content");
}));
action!(
result.window,
"preferences",
@ -298,7 +315,8 @@ impl Window {
clone.poe_list.clone().reload();
let player = clone.backend.get_player().unwrap();
clone.player_bar.set_player(Some(player));
clone.player_bar.set_player(Some(player.clone()));
clone.player_screen.set_player(Some(player));
}
}
}