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

@ -7,7 +7,7 @@ edition = "2021"
adw = { package = "libadwaita", version = "0.5", features = ["v1_4"] }
chrono = "0.4"
gettext-rs = { version = "0.7", features = ["gettext-system"] }
gtk = { package = "gtk4", version = "0.7", features = ["v4_10", "blueprint"] }
gtk = { package = "gtk4", version = "0.7", features = ["v4_12", "blueprint"] }
log = "0.4"
once_cell = "1"
rand = "0.8"

View file

@ -19,7 +19,7 @@ template $MusicusPlaylistPage : Adw.Bin {
Gtk.ScrolledWindow {
hscrollbar-policy: never;
Adw.Clamp {
Adw.ClampScrollable {
maximum-size: 1000;
tightening-threshold: 600;
@ -30,6 +30,7 @@ template $MusicusPlaylistPage : Adw.Bin {
margin-start: 12;
margin-end: 12;
single-click-activate: true;
activate => $select_item() swapped;
}
}
}

View file

@ -5,6 +5,8 @@ template $MusicusPlaylistTile : Gtk.Box {
styles ["playlisttile"]
Adw.Bin {
valign: end;
margin-bottom: 12;
width-request: 48;
Gtk.Image playing_icon {

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,9 +50,14 @@ 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(binding) = &*imp.binding.borrow() {
binding.unbind();
}
if let Some(item) = item {
if let Some(title) = item.title() {
imp.title_label.set_label(&title);
imp.title_label.set_visible(true);
@ -66,9 +74,12 @@ impl PlaylistTile {
} else {
imp.obj().set_margin_bottom(24);
}
}
pub fn set_playing(&self, playing: bool) {
self.imp().playing_icon.set_visible(playing);
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"
let imp = self.imp();
if button.is_active() {
imp.playlist_page.get().unwrap().scroll_to_current();
imp.stack.set_visible_child_name("playlist");
} else {
"navigation"
});
imp.stack.set_visible_child_name("navigation");
};
}
}