Handle current item on playlist page

This commit is contained in:
Elias Projahn 2023-10-26 11:48:42 +02:00
parent 7d21617e9a
commit 7110401f61
8 changed files with 83 additions and 32 deletions

View file

@ -14,10 +14,26 @@ mod imp {
pub playing: Cell<bool>,
#[property(get, construct_only)]
pub playlist: OnceCell<gio::ListStore>,
#[property(get, set)]
#[property(get, set = Self::set_current_index)]
pub current_index: Cell<u32>,
}
impl MusicusPlayer {
pub fn set_current_index(&self, index: u32) {
let playlist = self.playlist.get().unwrap();
if let Some(item) = playlist.item(self.current_index.get()) {
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);
}
}
}
#[glib::object_subclass]
impl ObjectSubclass for MusicusPlayer {
const NAME: &'static str = "MusicusPlayer";

View file

@ -1,6 +1,6 @@
use gtk::{glib, glib::Properties, prelude::*, subclass::prelude::*};
use std::{
cell::OnceCell,
cell::{Cell, OnceCell},
path::{Path, PathBuf},
};
@ -10,6 +10,9 @@ mod imp {
#[derive(Properties, Default)]
#[properties(wrapper_type = super::PlaylistItem)]
pub struct PlaylistItem {
#[property(get, set)]
pub is_playing: Cell<bool>,
#[property(get, construct_only)]
pub is_title: OnceCell<bool>,

View file

@ -1,6 +1,6 @@
use crate::{player::MusicusPlayer, playlist_tile::PlaylistTile};
use adw::subclass::prelude::*;
use gtk::{glib, glib::subclass::Signal, glib::Properties, prelude::*};
use gtk::{glib, glib::subclass::Signal, glib::Properties, prelude::*, ListScrollFlags};
use once_cell::sync::Lazy;
use std::cell::OnceCell;
@ -10,7 +10,7 @@ mod imp {
use super::*;
#[derive(Properties, Debug, Default, gtk::CompositeTemplate)]
#[properties(wrapper_type = super::MusicusPlayer)]
#[properties(wrapper_type = super::MusicusPlaylistPage)]
#[template(file = "data/ui/playlist_page.blp")]
pub struct MusicusPlaylistPage {
#[property(get, construct_only)]
@ -63,7 +63,13 @@ mod imp {
let item = item.downcast_ref::<gtk::ListItem>().unwrap();
let tile = item.child().and_downcast::<PlaylistTile>().unwrap();
let playlist_item = item.item().and_downcast::<PlaylistItem>().unwrap();
tile.set_item(&playlist_item);
tile.set_item(Some(&playlist_item));
});
factory.connect_unbind(|_, item| {
let item = item.downcast_ref::<gtk::ListItem>().unwrap();
let tile = item.child().and_downcast::<PlaylistTile>().unwrap();
tile.set_item(None);
});
self.playlist.set_factory(Some(&factory));
@ -93,6 +99,15 @@ impl MusicusPlaylistPage {
})
}
pub fn scroll_to_current(&self) {
self.imp().playlist.scroll_to(self.player().current_index(), ListScrollFlags::NONE, None);
}
#[template_callback]
fn select_item(&self, index: u32, _: &gtk::ListView) {
self.player().set_current_index(index);
}
#[template_callback]
fn close(&self, _: &gtk::Button) {
self.emit_by_name::<()>("close", &[]);

View file

@ -1,5 +1,6 @@
use crate::playlist_item::PlaylistItem;
use gtk::{glib, prelude::*, subclass::prelude::*};
use std::cell::RefCell;
mod imp {
use super::*;
@ -15,6 +16,8 @@ mod imp {
pub performances_label: TemplateChild<gtk::Label>,
#[template_child]
pub part_title_label: TemplateChild<gtk::Label>,
pub binding: RefCell<Option<glib::Binding>>,
}
#[glib::object_subclass]
@ -47,28 +50,36 @@ impl PlaylistTile {
glib::Object::new()
}
pub fn set_item(&self, item: &PlaylistItem) {
pub fn set_item(&self, item: Option<&PlaylistItem>) {
let imp = self.imp();
if let Some(title) = item.title() {
imp.title_label.set_label(&title);
imp.title_label.set_visible(true);
if let Some(binding) = &*imp.binding.borrow() {
binding.unbind();
}
if let Some(performances) = item.performers() {
imp.performances_label.set_label(&performances);
imp.performances_label.set_visible(true);
}
if let Some(item) = item {
if let Some(title) = item.title() {
imp.title_label.set_label(&title);
imp.title_label.set_visible(true);
}
if let Some(part_title) = item.part_title() {
imp.part_title_label.set_label(&part_title);
imp.part_title_label.set_visible(true);
} else {
imp.obj().set_margin_bottom(24);
}
}
if let Some(performances) = item.performers() {
imp.performances_label.set_label(&performances);
imp.performances_label.set_visible(true);
}
pub fn set_playing(&self, playing: bool) {
self.imp().playing_icon.set_visible(playing);
if let Some(part_title) = item.part_title() {
imp.part_title_label.set_label(&part_title);
imp.part_title_label.set_visible(true);
} else {
imp.obj().set_margin_bottom(24);
}
imp.binding.replace(Some(
item.bind_property("is-playing", &imp.playing_icon.get(), "visible")
.sync_create()
.build(),
));
}
}
}

View file

@ -2,9 +2,9 @@ use crate::{
home_page::MusicusHomePage, library::MusicusLibrary, player::MusicusPlayer,
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,6 +13,7 @@ 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>,
@ -79,6 +80,7 @@ mod imp {
});
self.stack.add_named(&playlist_page, Some("playlist"));
self.playlist_page.set(playlist_page).unwrap();
}
}
@ -140,12 +142,13 @@ impl MusicusWindow {
#[template_callback]
fn show_playlist(&self, button: &gtk::ToggleButton) {
self.imp()
.stack
.set_visible_child_name(if button.is_active() {
"playlist"
} else {
"navigation"
});
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");
};
}
}