Move player bar to separate widget

This commit is contained in:
Elias Projahn 2023-10-27 12:32:40 +02:00
parent f16a27e343
commit 232faa6a2f
8 changed files with 261 additions and 141 deletions

90
data/ui/player_bar.blp Normal file
View file

@ -0,0 +1,90 @@
using Gtk 4.0;
using Adw 1;
template $MusicusPlayerBar : Gtk.Box {
styles ["playerbar"]
orientation: vertical;
margin-start: 6;
margin-end: 6;
margin-top: 12;
margin-bottom: 12;
spacing: 6;
Gtk.Box {
spacing: 6;
Gtk.Box {
valign: center;
hexpand: true;
margin-start: 10;
orientation: vertical;
Gtk.Label title_label {
styles ["title"]
halign: start;
label: _("Title");
ellipsize: end;
}
Gtk.Label subtitle_label {
styles ["subtitle", "dim-label"]
halign: start;
label: _("Subtitle");
ellipsize: end;
}
}
Gtk.Button back_button {
styles ["circular", "flat"]
valign: center;
icon-name: "media-skip-backward-symbolic";
}
Gtk.ToggleButton playlist_button {
styles ["flat", "circular"]
valign: center;
icon-name: "playlist-symbolic";
clicked => $show_playlist() swapped;
}
Gtk.Button forward_button {
styles ["circular", "flat"]
valign: center;
icon-name: "media-skip-forward-symbolic";
}
}
Gtk.Box {
spacing: 6;
Gtk.Button play_button {
styles ["circular", "flat"]
valign: center;
icon-name: "media-playback-start-symbolic";
clicked => $play_pause() swapped;
}
Gtk.Label current_time_label {
styles ["caption", "numeric"]
valign: center;
label: "00:00";
}
Gtk.Scale slider {
valign: center;
hexpand: true;
adjustment: Gtk.Adjustment {
lower: 0;
upper: 1;
value: 0.2;
step-increment: 0.01;
};
}
Gtk.Label remaining_time_label {
styles ["caption", "numeric"]
valign: center;
label: "01:00";
}
}
}

View file

@ -22,93 +22,6 @@ template $MusicusWindow : Adw.ApplicationWindow {
Gtk.Revealer player_bar_revealer {
reveal-child: true;
transition-type: slide_up;
Gtk.Box {
styles ["playerbar"]
orientation: vertical;
margin-start: 6;
margin-end: 6;
margin-top: 12;
margin-bottom: 12;
spacing: 6;
Gtk.Box {
spacing: 6;
Gtk.Box {
valign: center;
hexpand: true;
margin-start: 10;
orientation: vertical;
Gtk.Label title_label {
styles ["title"]
halign: start;
label: _("Title");
ellipsize: end;
}
Gtk.Label subtitle_label {
styles ["subtitle", "dim-label"]
halign: start;
label: _("Subtitle");
ellipsize: end;
}
}
Gtk.Button back_button {
styles ["circular", "flat"]
valign: center;
icon-name: "media-skip-backward-symbolic";
}
Gtk.ToggleButton playlist_button {
styles ["flat", "circular"]
valign: center;
icon-name: "playlist-symbolic";
toggled => $show_playlist() swapped;
}
Gtk.Button forward_button {
styles ["circular", "flat"]
valign: center;
icon-name: "media-skip-forward-symbolic";
}
}
Gtk.Box {
spacing: 6;
Gtk.Button play_button {
styles ["circular", "flat"]
valign: center;
icon-name: "media-playback-start-symbolic";
}
Gtk.Label current_time_label {
styles ["caption", "numeric"]
valign: center;
label: "00:00";
}
Gtk.Scale slider {
valign: center;
hexpand: true;
adjustment: Gtk.Adjustment {
lower: 0;
upper: 1;
value: 0.2;
step-increment: 0.01;
};
}
Gtk.Label remaining_time_label {
styles ["caption", "numeric"]
valign: center;
label: "01:00";
}
}
}
}
}
}

View file

@ -1,4 +1,5 @@
data/ui/home_page.blp
data/ui/player_bar.blp
data/ui/playlist_page.blp
data/ui/playlist_tile.blp
data/ui/recording_tile.blp

View file

@ -3,6 +3,7 @@ mod config;
mod home_page;
mod library;
mod player;
mod player_bar;
mod playlist_item;
mod playlist_page;
mod playlist_tile;

View file

@ -23,13 +23,17 @@ mod imp {
let playlist = self.playlist.get().unwrap();
if let Some(item) = playlist.item(self.current_index.get()) {
item.downcast::<PlaylistItem>().unwrap().set_is_playing(false);
item.downcast::<PlaylistItem>()
.unwrap()
.set_is_playing(false);
}
self.current_index.set(index);
if let Some(item) = playlist.item(index) {
item.downcast::<PlaylistItem>().unwrap().set_is_playing(true);
item.downcast::<PlaylistItem>()
.unwrap()
.set_is_playing(true);
}
}
}
@ -75,6 +79,15 @@ impl MusicusPlayer {
pub fn pause(&self) {
self.set_playing(false)
}
pub fn current_item(&self) -> Option<PlaylistItem> {
let imp = self.imp();
imp.playlist
.get()
.unwrap()
.item(imp.current_index.get())
.and_downcast::<PlaylistItem>()
}
}
impl Default for MusicusPlayer {

128
src/player_bar.rs Normal file
View file

@ -0,0 +1,128 @@
use crate::player::MusicusPlayer;
use gtk::{
glib::{self, subclass::Signal, Properties},
prelude::*,
subclass::prelude::*,
};
use once_cell::sync::Lazy;
use std::cell::RefCell;
mod imp {
use super::*;
#[derive(Properties, Debug, Default, gtk::CompositeTemplate)]
#[properties(wrapper_type = super::PlayerBar)]
#[template(file = "data/ui/player_bar.blp")]
pub struct PlayerBar {
#[property(get, construct_only)]
pub player: RefCell<MusicusPlayer>,
#[template_child]
pub title_label: TemplateChild<gtk::Label>,
#[template_child]
pub subtitle_label: TemplateChild<gtk::Label>,
#[template_child]
pub back_button: TemplateChild<gtk::Button>,
#[template_child]
pub playlist_button: TemplateChild<gtk::ToggleButton>,
#[template_child]
pub forward_button: TemplateChild<gtk::Button>,
#[template_child]
pub play_button: TemplateChild<gtk::Button>,
#[template_child]
pub current_time_label: TemplateChild<gtk::Label>,
#[template_child]
pub slider: TemplateChild<gtk::Scale>,
#[template_child]
pub remaining_time_label: TemplateChild<gtk::Label>,
}
#[glib::object_subclass]
impl ObjectSubclass for PlayerBar {
const NAME: &'static str = "MusicusPlayerBar";
type Type = super::PlayerBar;
type ParentType = gtk::Box;
fn class_init(klass: &mut Self::Class) {
klass.bind_template();
klass.bind_template_instance_callbacks();
}
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
obj.init_template();
}
}
#[glib::derived_properties]
impl ObjectImpl for PlayerBar {
fn signals() -> &'static [Signal] {
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
vec![Signal::builder("show-playlist")
.param_types([glib::Type::BOOL])
.build()]
});
SIGNALS.as_ref()
}
fn constructed(&self) {
self.parent_constructed();
self.player
.borrow()
.bind_property("playing", &self.play_button.get(), "icon-name")
.transform_to(|_, playing| {
Some(if playing {
"media-playback-pause-symbolic"
} else {
"media-playback-start-symbolic"
})
})
.sync_create()
.build();
}
}
impl WidgetImpl for PlayerBar {}
impl BoxImpl for PlayerBar {}
}
glib::wrapper! {
pub struct PlayerBar(ObjectSubclass<imp::PlayerBar>)
@extends gtk::Widget, adw::Bin;
}
#[gtk::template_callbacks]
impl PlayerBar {
pub fn new(player: &MusicusPlayer) -> Self {
glib::Object::builder().property("player", player).build()
}
pub fn connect_show_playlist<F: Fn(&Self, bool) + 'static>(&self, f: F) -> glib::SignalHandlerId {
self.connect_local("show-playlist", true, move |values| {
let obj = values[0].get::<Self>().unwrap();
let show = values[1].get::<bool>().unwrap();
f(&obj, show);
None
})
}
pub fn playlist_hidden(&self) {
self.imp().playlist_button.set_active(false);
}
#[template_callback]
fn show_playlist(&self, button: &gtk::ToggleButton) {
self.emit_by_name::<()>("show-playlist", &[&button.is_active()]);
}
#[template_callback]
fn play_pause(&self, _: &gtk::Button) {
let player = self.player();
if player.playing() {
player.pause();
} else {
player.play();
}
}
}

View file

@ -42,7 +42,7 @@ mod imp {
glib::wrapper! {
pub struct PlaylistTile(ObjectSubclass<imp::PlaylistTile>)
@extends gtk::Widget, gtk::FlowBoxChild;
@extends gtk::Widget, gtk::Box;
}
impl PlaylistTile {

View file

@ -1,10 +1,9 @@
use crate::{
home_page::MusicusHomePage, library::MusicusLibrary, player::MusicusPlayer,
playlist_page::MusicusPlaylistPage, welcome_page::MusicusWelcomePage,
player_bar::PlayerBar, playlist_page::MusicusPlaylistPage, welcome_page::MusicusWelcomePage,
};
use adw::subclass::prelude::*;
use gtk::{gio, glib, glib::clone, prelude::*};
use std::cell::OnceCell;
mod imp {
use super::*;
@ -13,7 +12,6 @@ mod imp {
#[template(file = "data/ui/window.blp")]
pub struct MusicusWindow {
pub player: MusicusPlayer,
pub playlist_page: OnceCell<MusicusPlaylistPage>,
#[template_child]
pub stack: TemplateChild<gtk::Stack>,
@ -21,10 +19,6 @@ mod imp {
pub navigation_view: TemplateChild<adw::NavigationView>,
#[template_child]
pub player_bar_revealer: TemplateChild<gtk::Revealer>,
#[template_child]
pub play_button: TemplateChild<gtk::Button>,
#[template_child]
pub playlist_button: TemplateChild<gtk::ToggleButton>,
}
#[glib::object_subclass]
@ -48,39 +42,31 @@ mod imp {
fn constructed(&self) {
self.parent_constructed();
self.obj().load_window_state();
let player_bar = PlayerBar::new(&self.player);
self.player_bar_revealer.set_child(Some(&player_bar));
let playlist_page = MusicusPlaylistPage::new(&self.player);
self.stack.add_named(&playlist_page, Some("playlist"));
playlist_page.connect_close(clone!(@weak player_bar => move |_| {
player_bar.playlist_hidden();
}));
let stack = self.stack.get();
player_bar.connect_show_playlist(clone!(@weak playlist_page => move |_, show| {
if show {
playlist_page.scroll_to_current();
stack.set_visible_child_name("playlist");
} else {
stack.set_visible_child_name("navigation");
};
}));
self.player
.bind_property("active", &self.player_bar_revealer.get(), "reveal-child")
.sync_create()
.build();
let play_button = self.play_button.get();
self.player
.connect_playing_notify(clone!(@weak play_button => move |player| {
play_button.set_icon_name(if player.playing() {
"media-playback-pause-symbolic"
} else {
"media-playback-start-symbolic"
});
}));
self.play_button
.connect_clicked(clone!(@weak self.player as player => move |_| {
if player.playing() {
player.pause();
} else {
player.play();
}
}));
let playlist_page = MusicusPlaylistPage::new(&self.player);
let playlist_button = self.playlist_button.get();
playlist_page.connect_close(move |_| {
playlist_button.set_active(false);
});
self.stack.add_named(&playlist_page, Some("playlist"));
self.playlist_page.set(playlist_page).unwrap();
}
}
@ -139,16 +125,4 @@ impl MusicusWindow {
.navigation_view
.replace(&[MusicusHomePage::new(&library, &self.imp().player).into()]);
}
#[template_callback]
fn show_playlist(&self, button: &gtk::ToggleButton) {
let imp = self.imp();
if button.is_active() {
imp.playlist_page.get().unwrap().scroll_to_current();
imp.stack.set_visible_child_name("playlist");
} else {
imp.stack.set_visible_child_name("navigation");
};
}
}