mirror of
				https://github.com/johrpan/musicus.git
				synced 2025-10-26 19:57:25 +01:00 
			
		
		
		
	Handle current item on playlist page
This commit is contained in:
		
							parent
							
								
									7d21617e9a
								
							
						
					
					
						commit
						7110401f61
					
				
					 8 changed files with 83 additions and 32 deletions
				
			
		|  | @ -7,7 +7,7 @@ edition = "2021" | ||||||
| adw = { package = "libadwaita", version = "0.5", features = ["v1_4"] } | adw = { package = "libadwaita", version = "0.5", features = ["v1_4"] } | ||||||
| chrono = "0.4" | chrono = "0.4" | ||||||
| gettext-rs = { version = "0.7", features = ["gettext-system"] } | 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" | log = "0.4" | ||||||
| once_cell = "1" | once_cell = "1" | ||||||
| rand = "0.8" | rand = "0.8" | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ template $MusicusPlaylistPage : Adw.Bin { | ||||||
|     Gtk.ScrolledWindow { |     Gtk.ScrolledWindow { | ||||||
|       hscrollbar-policy: never; |       hscrollbar-policy: never; | ||||||
| 
 | 
 | ||||||
|       Adw.Clamp { |       Adw.ClampScrollable { | ||||||
|         maximum-size: 1000; |         maximum-size: 1000; | ||||||
|         tightening-threshold: 600; |         tightening-threshold: 600; | ||||||
| 
 | 
 | ||||||
|  | @ -30,6 +30,7 @@ template $MusicusPlaylistPage : Adw.Bin { | ||||||
|           margin-start: 12; |           margin-start: 12; | ||||||
|           margin-end: 12; |           margin-end: 12; | ||||||
|           single-click-activate: true; |           single-click-activate: true; | ||||||
|  |           activate => $select_item() swapped; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -5,6 +5,8 @@ template $MusicusPlaylistTile : Gtk.Box { | ||||||
|   styles ["playlisttile"] |   styles ["playlisttile"] | ||||||
| 
 | 
 | ||||||
|   Adw.Bin { |   Adw.Bin { | ||||||
|  |     valign: end; | ||||||
|  |     margin-bottom: 12; | ||||||
|     width-request: 48; |     width-request: 48; | ||||||
| 
 | 
 | ||||||
|     Gtk.Image playing_icon { |     Gtk.Image playing_icon { | ||||||
|  |  | ||||||
|  | @ -14,10 +14,26 @@ mod imp { | ||||||
|         pub playing: Cell<bool>, |         pub playing: Cell<bool>, | ||||||
|         #[property(get, construct_only)] |         #[property(get, construct_only)] | ||||||
|         pub playlist: OnceCell<gio::ListStore>, |         pub playlist: OnceCell<gio::ListStore>, | ||||||
|         #[property(get, set)] |         #[property(get, set = Self::set_current_index)] | ||||||
|         pub current_index: Cell<u32>, |         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] |     #[glib::object_subclass] | ||||||
|     impl ObjectSubclass for MusicusPlayer { |     impl ObjectSubclass for MusicusPlayer { | ||||||
|         const NAME: &'static str = "MusicusPlayer"; |         const NAME: &'static str = "MusicusPlayer"; | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| use gtk::{glib, glib::Properties, prelude::*, subclass::prelude::*}; | use gtk::{glib, glib::Properties, prelude::*, subclass::prelude::*}; | ||||||
| use std::{ | use std::{ | ||||||
|     cell::OnceCell, |     cell::{Cell, OnceCell}, | ||||||
|     path::{Path, PathBuf}, |     path::{Path, PathBuf}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -10,6 +10,9 @@ mod imp { | ||||||
|     #[derive(Properties, Default)] |     #[derive(Properties, Default)] | ||||||
|     #[properties(wrapper_type = super::PlaylistItem)] |     #[properties(wrapper_type = super::PlaylistItem)] | ||||||
|     pub struct PlaylistItem { |     pub struct PlaylistItem { | ||||||
|  |         #[property(get, set)] | ||||||
|  |         pub is_playing: Cell<bool>, | ||||||
|  | 
 | ||||||
|         #[property(get, construct_only)] |         #[property(get, construct_only)] | ||||||
|         pub is_title: OnceCell<bool>, |         pub is_title: OnceCell<bool>, | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| use crate::{player::MusicusPlayer, playlist_tile::PlaylistTile}; | use crate::{player::MusicusPlayer, playlist_tile::PlaylistTile}; | ||||||
| use adw::subclass::prelude::*; | 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 once_cell::sync::Lazy; | ||||||
| use std::cell::OnceCell; | use std::cell::OnceCell; | ||||||
| 
 | 
 | ||||||
|  | @ -10,7 +10,7 @@ mod imp { | ||||||
|     use super::*; |     use super::*; | ||||||
| 
 | 
 | ||||||
|     #[derive(Properties, Debug, Default, gtk::CompositeTemplate)] |     #[derive(Properties, Debug, Default, gtk::CompositeTemplate)] | ||||||
|     #[properties(wrapper_type = super::MusicusPlayer)] |     #[properties(wrapper_type = super::MusicusPlaylistPage)] | ||||||
|     #[template(file = "data/ui/playlist_page.blp")] |     #[template(file = "data/ui/playlist_page.blp")] | ||||||
|     pub struct MusicusPlaylistPage { |     pub struct MusicusPlaylistPage { | ||||||
|         #[property(get, construct_only)] |         #[property(get, construct_only)] | ||||||
|  | @ -63,7 +63,13 @@ mod imp { | ||||||
|                 let item = item.downcast_ref::<gtk::ListItem>().unwrap(); |                 let item = item.downcast_ref::<gtk::ListItem>().unwrap(); | ||||||
|                 let tile = item.child().and_downcast::<PlaylistTile>().unwrap(); |                 let tile = item.child().and_downcast::<PlaylistTile>().unwrap(); | ||||||
|                 let playlist_item = item.item().and_downcast::<PlaylistItem>().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)); |             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, _: >k::ListView) { | ||||||
|  |         self.player().set_current_index(index); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     #[template_callback] |     #[template_callback] | ||||||
|     fn close(&self, _: >k::Button) { |     fn close(&self, _: >k::Button) { | ||||||
|         self.emit_by_name::<()>("close", &[]); |         self.emit_by_name::<()>("close", &[]); | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| use crate::playlist_item::PlaylistItem; | use crate::playlist_item::PlaylistItem; | ||||||
| use gtk::{glib, prelude::*, subclass::prelude::*}; | use gtk::{glib, prelude::*, subclass::prelude::*}; | ||||||
|  | use std::cell::RefCell; | ||||||
| 
 | 
 | ||||||
| mod imp { | mod imp { | ||||||
|     use super::*; |     use super::*; | ||||||
|  | @ -15,6 +16,8 @@ mod imp { | ||||||
|         pub performances_label: TemplateChild<gtk::Label>, |         pub performances_label: TemplateChild<gtk::Label>, | ||||||
|         #[template_child] |         #[template_child] | ||||||
|         pub part_title_label: TemplateChild<gtk::Label>, |         pub part_title_label: TemplateChild<gtk::Label>, | ||||||
|  | 
 | ||||||
|  |         pub binding: RefCell<Option<glib::Binding>>, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[glib::object_subclass] |     #[glib::object_subclass] | ||||||
|  | @ -47,9 +50,14 @@ impl PlaylistTile { | ||||||
|         glib::Object::new() |         glib::Object::new() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn set_item(&self, item: &PlaylistItem) { |     pub fn set_item(&self, item: Option<&PlaylistItem>) { | ||||||
|         let imp = self.imp(); |         let imp = self.imp(); | ||||||
| 
 | 
 | ||||||
|  |         if let Some(binding) = &*imp.binding.borrow() { | ||||||
|  |             binding.unbind(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if let Some(item) = item { | ||||||
|             if let Some(title) = item.title() { |             if let Some(title) = item.title() { | ||||||
|                 imp.title_label.set_label(&title); |                 imp.title_label.set_label(&title); | ||||||
|                 imp.title_label.set_visible(true); |                 imp.title_label.set_visible(true); | ||||||
|  | @ -66,9 +74,12 @@ impl PlaylistTile { | ||||||
|             } else { |             } else { | ||||||
|                 imp.obj().set_margin_bottom(24); |                 imp.obj().set_margin_bottom(24); | ||||||
|             } |             } | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     pub fn set_playing(&self, playing: bool) { |             imp.binding.replace(Some( | ||||||
|         self.imp().playing_icon.set_visible(playing); |                 item.bind_property("is-playing", &imp.playing_icon.get(), "visible") | ||||||
|  |                     .sync_create() | ||||||
|  |                     .build(), | ||||||
|  |             )); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2,9 +2,9 @@ use crate::{ | ||||||
|     home_page::MusicusHomePage, library::MusicusLibrary, player::MusicusPlayer, |     home_page::MusicusHomePage, library::MusicusLibrary, player::MusicusPlayer, | ||||||
|     playlist_page::MusicusPlaylistPage, welcome_page::MusicusWelcomePage, |     playlist_page::MusicusPlaylistPage, welcome_page::MusicusWelcomePage, | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| use adw::subclass::prelude::*; | use adw::subclass::prelude::*; | ||||||
| use gtk::{gio, glib, glib::clone, prelude::*}; | use gtk::{gio, glib, glib::clone, prelude::*}; | ||||||
|  | use std::cell::OnceCell; | ||||||
| 
 | 
 | ||||||
| mod imp { | mod imp { | ||||||
|     use super::*; |     use super::*; | ||||||
|  | @ -13,6 +13,7 @@ mod imp { | ||||||
|     #[template(file = "data/ui/window.blp")] |     #[template(file = "data/ui/window.blp")] | ||||||
|     pub struct MusicusWindow { |     pub struct MusicusWindow { | ||||||
|         pub player: MusicusPlayer, |         pub player: MusicusPlayer, | ||||||
|  |         pub playlist_page: OnceCell<MusicusPlaylistPage>, | ||||||
| 
 | 
 | ||||||
|         #[template_child] |         #[template_child] | ||||||
|         pub stack: TemplateChild<gtk::Stack>, |         pub stack: TemplateChild<gtk::Stack>, | ||||||
|  | @ -79,6 +80,7 @@ mod imp { | ||||||
|             }); |             }); | ||||||
| 
 | 
 | ||||||
|             self.stack.add_named(&playlist_page, Some("playlist")); |             self.stack.add_named(&playlist_page, Some("playlist")); | ||||||
|  |             self.playlist_page.set(playlist_page).unwrap(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -140,12 +142,13 @@ impl MusicusWindow { | ||||||
| 
 | 
 | ||||||
|     #[template_callback] |     #[template_callback] | ||||||
|     fn show_playlist(&self, button: >k::ToggleButton) { |     fn show_playlist(&self, button: >k::ToggleButton) { | ||||||
|         self.imp() |         let imp = self.imp(); | ||||||
|             .stack | 
 | ||||||
|             .set_visible_child_name(if button.is_active() { |         if button.is_active() { | ||||||
|                 "playlist" |             imp.playlist_page.get().unwrap().scroll_to_current(); | ||||||
|  |             imp.stack.set_visible_child_name("playlist"); | ||||||
|         } else { |         } else { | ||||||
|                 "navigation" |             imp.stack.set_visible_child_name("navigation"); | ||||||
|             }); |         }; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue