player screen: Improve playlist visuals

This commit is contained in:
Elias Projahn 2022-02-09 23:13:47 +01:00
parent ee8399e93d
commit b050a7f0ea
5 changed files with 150 additions and 55 deletions

View file

@ -17,6 +17,7 @@
<file preprocess="xml-stripblanks">ui/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_row.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/work_editor.ui</file>

View 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>

View file

@ -1,7 +1,6 @@
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::{List, Widget};
use crate::widgets::{List, TrackRow, Widget};
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
use gtk_macros::get_widget;
use musicus_backend::db::Track;
@ -9,6 +8,7 @@ use std::cell::{Cell, RefCell};
use std::rc::Rc;
/// Elements for visually representing the playlist.
#[derive(Clone)]
enum ListItem {
/// A playable 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] {
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(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()
TrackRow::new(track, first, playing).get_widget()
}
ListItem::Separator => {
let separator = gtk::Separator::new(gtk::Orientation::Horizontal);
separator.upcast()
gtk::ListBoxRowBuilder::new()
.selectable(false)
.activatable(false)
.child(&gtk::Separator::new(gtk::Orientation::Horizontal))
.build()
.upcast()
}
};
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();
this

View file

@ -21,6 +21,9 @@ pub use screen::*;
pub mod section;
pub use section::*;
pub mod track_row;
pub use track_row::TrackRow;
mod indexed_list_model;
/// Something that can be represented as a GTK widget.

View 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()
}
}