mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 19:57:25 +01:00
player screen: Improve playlist visuals
This commit is contained in:
parent
ee8399e93d
commit
b050a7f0ea
5 changed files with 150 additions and 55 deletions
|
|
@ -17,6 +17,7 @@
|
||||||
<file preprocess="xml-stripblanks">ui/selector.ui</file>
|
<file preprocess="xml-stripblanks">ui/selector.ui</file>
|
||||||
<file preprocess="xml-stripblanks">ui/source_selector.ui</file>
|
<file preprocess="xml-stripblanks">ui/source_selector.ui</file>
|
||||||
<file preprocess="xml-stripblanks">ui/track_editor.ui</file>
|
<file preprocess="xml-stripblanks">ui/track_editor.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">ui/track_row.ui</file>
|
||||||
<file preprocess="xml-stripblanks">ui/track_selector.ui</file>
|
<file preprocess="xml-stripblanks">ui/track_selector.ui</file>
|
||||||
<file preprocess="xml-stripblanks">ui/track_set_editor.ui</file>
|
<file preprocess="xml-stripblanks">ui/track_set_editor.ui</file>
|
||||||
<file preprocess="xml-stripblanks">ui/work_editor.ui</file>
|
<file preprocess="xml-stripblanks">ui/work_editor.ui</file>
|
||||||
|
|
|
||||||
65
musicus/res/ui/track_row.ui
Normal file
65
musicus/res/ui/track_row.ui
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk" version="4.0"/>
|
||||||
|
<object class="GtkListBoxRow" id="widget">
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">horizontal</property>
|
||||||
|
<property name="margin-top">12</property>
|
||||||
|
<property name="margin-start">6</property>
|
||||||
|
<property name="margin-end">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRevealer" id="playing_revealer">
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="playing_image">
|
||||||
|
<property name="icon-name">media-playback-start-symbolic</property>
|
||||||
|
<property name="margin-top">6</property>
|
||||||
|
<property name="margin-start">12</property>
|
||||||
|
<property name="margin-end">18</property>
|
||||||
|
<property name="valign">start</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="header_box">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="visible">false</property>
|
||||||
|
<property name="margin-bottom">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="work_title_label">
|
||||||
|
<property name="wrap">true</property>
|
||||||
|
<property name="xalign">0.0</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="bold"/>
|
||||||
|
</attributes>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="performances_label">
|
||||||
|
<property name="wrap">true</property>
|
||||||
|
<property name="xalign">0.0</property>
|
||||||
|
<style>
|
||||||
|
<class name="subtitle"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="track_title_label">
|
||||||
|
<property name="wrap">true</property>
|
||||||
|
<property name="xalign">0.0</property>
|
||||||
|
<property name="margin-bottom">12</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::navigator::{NavigationHandle, Screen};
|
use crate::navigator::{NavigationHandle, Screen};
|
||||||
use crate::widgets::{List, Widget};
|
use crate::widgets::{List, TrackRow, Widget};
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use gettextrs::gettext;
|
|
||||||
use glib::clone;
|
use glib::clone;
|
||||||
use gtk_macros::get_widget;
|
use gtk_macros::get_widget;
|
||||||
use musicus_backend::db::Track;
|
use musicus_backend::db::Track;
|
||||||
|
|
@ -9,6 +8,7 @@ use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// Elements for visually representing the playlist.
|
/// Elements for visually representing the playlist.
|
||||||
|
#[derive(Clone)]
|
||||||
enum ListItem {
|
enum ListItem {
|
||||||
/// A playable track.
|
/// A playable track.
|
||||||
Track {
|
Track {
|
||||||
|
|
@ -207,64 +207,36 @@ impl Screen<(), ()> for PlayerScreen {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.list.set_make_widget_cb(clone!(@weak this => @default-panic, move |index| {
|
this.list
|
||||||
|
.set_make_widget_cb(clone!(@weak this => @default-panic, move |index| {
|
||||||
let widget = match this.items.borrow()[index] {
|
let widget = match this.items.borrow()[index] {
|
||||||
ListItem::Track {index, first, playing} => {
|
ListItem::Track {index, first, playing} => {
|
||||||
let track = &this.playlist.borrow()[index];
|
let track = &this.playlist.borrow()[index];
|
||||||
|
TrackRow::new(track, first, playing).get_widget()
|
||||||
let mut parts = Vec::<String>::new();
|
|
||||||
for part in &track.work_parts {
|
|
||||||
parts.push(track.recording.work.parts[*part].title.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
let title = if first {
|
|
||||||
track.recording.work.get_title()
|
|
||||||
} else if parts.is_empty() {
|
|
||||||
gettext("Unknown")
|
|
||||||
} else {
|
|
||||||
parts.join(", ")
|
|
||||||
};
|
|
||||||
|
|
||||||
let row = adw::ActionRowBuilder::new()
|
|
||||||
.selectable(false)
|
|
||||||
.activatable(true)
|
|
||||||
.title(&title)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
if first {
|
|
||||||
let subtitle = if !parts.is_empty() {
|
|
||||||
format!("{}\n{}", track.recording.get_performers(), parts.join(", "))
|
|
||||||
} else {
|
|
||||||
track.recording.get_performers()
|
|
||||||
};
|
|
||||||
|
|
||||||
row.set_subtitle(&subtitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
row.connect_activated(clone!(@weak this => move |_| {
|
|
||||||
this.handle.backend.pl().set_track(index).unwrap();
|
|
||||||
}));
|
|
||||||
|
|
||||||
let icon = if playing {
|
|
||||||
Some("media-playback-start-symbolic")
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let image = gtk::Image::from_icon_name(icon);
|
|
||||||
row.add_prefix(&image);
|
|
||||||
|
|
||||||
row.upcast()
|
|
||||||
}
|
}
|
||||||
ListItem::Separator => {
|
ListItem::Separator => {
|
||||||
let separator = gtk::Separator::new(gtk::Orientation::Horizontal);
|
gtk::ListBoxRowBuilder::new()
|
||||||
separator.upcast()
|
.selectable(false)
|
||||||
|
.activatable(false)
|
||||||
|
.child(>k::Separator::new(gtk::Orientation::Horizontal))
|
||||||
|
.build()
|
||||||
|
.upcast()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
widget
|
widget
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this.list
|
||||||
|
.widget
|
||||||
|
.connect_row_activated(clone!(@weak this => move |_, row| {
|
||||||
|
let list_index = row.index();
|
||||||
|
let list_item = this.items.borrow()[list_index as usize].clone();
|
||||||
|
if let ListItem::Track {index, ..} = list_item {
|
||||||
|
this.handle.backend.pl().set_track(index).unwrap();
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
player.send_data();
|
player.send_data();
|
||||||
|
|
||||||
this
|
this
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,9 @@ pub use screen::*;
|
||||||
pub mod section;
|
pub mod section;
|
||||||
pub use section::*;
|
pub use section::*;
|
||||||
|
|
||||||
|
pub mod track_row;
|
||||||
|
pub use track_row::TrackRow;
|
||||||
|
|
||||||
mod indexed_list_model;
|
mod indexed_list_model;
|
||||||
|
|
||||||
/// Something that can be represented as a GTK widget.
|
/// Something that can be represented as a GTK widget.
|
||||||
|
|
|
||||||
54
musicus/src/widgets/track_row.rs
Normal file
54
musicus/src/widgets/track_row.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
use super::Widget;
|
||||||
|
use gtk::prelude::*;
|
||||||
|
use gtk_macros::get_widget;
|
||||||
|
use musicus_backend::db::Track;
|
||||||
|
|
||||||
|
/// A widget for showing a single track in a list.
|
||||||
|
pub struct TrackRow {
|
||||||
|
/// The actual GTK widget.
|
||||||
|
pub widget: gtk::ListBoxRow,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrackRow {
|
||||||
|
/// Create a new track row.
|
||||||
|
pub fn new(track: &Track, show_header: bool, playing: bool) -> Self {
|
||||||
|
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/track_row.ui");
|
||||||
|
|
||||||
|
get_widget!(builder, gtk::ListBoxRow, widget);
|
||||||
|
get_widget!(builder, gtk::Revealer, playing_revealer);
|
||||||
|
get_widget!(builder, gtk::Image, playing_image);
|
||||||
|
get_widget!(builder, gtk::Box, header_box);
|
||||||
|
get_widget!(builder, gtk::Label, work_title_label);
|
||||||
|
get_widget!(builder, gtk::Label, performances_label);
|
||||||
|
get_widget!(builder, gtk::Label, track_title_label);
|
||||||
|
|
||||||
|
playing_revealer.set_reveal_child(playing);
|
||||||
|
|
||||||
|
let mut parts = Vec::<&str>::new();
|
||||||
|
for part in &track.work_parts {
|
||||||
|
parts.push(&track.recording.work.parts[*part].title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if parts.is_empty() || show_header {
|
||||||
|
work_title_label.set_text(&track.recording.work.get_title());
|
||||||
|
performances_label.set_text(&track.recording.get_performers());
|
||||||
|
header_box.show();
|
||||||
|
} else {
|
||||||
|
playing_image.set_margin_top(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !parts.is_empty() {
|
||||||
|
track_title_label.set_text(&parts.join(", "));
|
||||||
|
} else {
|
||||||
|
track_title_label.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { widget }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for TrackRow {
|
||||||
|
fn get_widget(&self) -> gtk::Widget {
|
||||||
|
self.widget.clone().upcast()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue