mod imp { use adw::prelude::*; use adw::subclass::prelude::*; use glib::subclass::InitializingObject; use gtk::{gdk, glib}; use std::cell::{Cell, RefCell}; #[derive(gtk::CompositeTemplate, glib::Properties, Default)] #[template(resource = "/eu/callcc/audrey/window.ui")] #[properties(wrapper_type = super::Window)] pub struct Window { #[template_child] pub(super) playbar: TemplateChild, #[property(get, set)] playbin: RefCell, #[property(get, set, default = false)] can_click_shuffle_all: Cell, #[property(get, set, nullable)] playing_cover_art: RefCell>, #[property(get, set, nullable)] song: RefCell>, pub(super) setup: crate::ui::Setup, pub(super) api: RefCell>, } #[glib::object_subclass] impl ObjectSubclass for Window { const NAME: &'static str = "AudreyUiWindow"; type Type = super::Window; type ParentType = adw::ApplicationWindow; fn class_init(klass: &mut Self::Class) { klass.bind_template(); klass.bind_template_callbacks(); } fn instance_init(obj: &InitializingObject) { obj.init_template(); } } #[glib::derived_properties] impl ObjectImpl for Window {} impl WidgetImpl for Window {} impl WindowImpl for Window {} impl ApplicationWindowImpl for Window {} impl AdwApplicationWindowImpl for Window {} #[gtk::template_callbacks] impl Window { #[template_callback] fn show_playbar_cover_art(&self, stack_child: Option<&str>) -> bool { stack_child != Some("play-queue") } #[template_callback] async fn shuffle_all(&self) { /* this.can_click_shuffle_all = false; this.playbin.clear (); api.get_random_songs.begin (null, (song) => { this.playbin.append_track (song); }, (obj, res) => { try { api.get_random_songs.end (res); } catch (Error e) { error ("could not get random songs: %s", e.message); } this.can_click_shuffle_all = true; this.playbin.select_track (0); });*/ todo!() } #[template_callback] fn show_setup_dialog(&self) { self.setup.present(Some(self.obj().as_ref())); } pub(super) fn now_playing(&self, _song: &crate::playbin::Song) { /* this.song = song; // api.scrobble.begin (this.song.id); TODO if (this.cancel_loading_art != null) { this.cancel_loading_art.cancel (); } this.cancel_loading_art = new GLib.Cancellable (); this.playing_cover_art = null; // TODO: preload next art somehow this.cover_art_loading = true; string song_id = this.song.id; this.api.cover_art.begin (song_id, -1, Priority.DEFAULT, this.cancel_loading_art, (obj, res) => { try { this.playing_cover_art = Gdk.Texture.for_pixbuf (this.api.cover_art.end (res)); this.cover_art_loading = false; } catch (Error e) { if (!(e is IOError.CANCELLED)) { warning ("could not load cover for %s: %s", song_id, e.message); this.cover_art_loading = false; } } }); */ todo!() } } } use adw::prelude::*; use adw::subclass::prelude::*; use gtk::{gdk, gio, glib}; glib::wrapper! { pub struct Window(ObjectSubclass) @extends adw::ApplicationWindow, gtk::ApplicationWindow, gtk::Window, gtk::Widget, @implements gio::ActionGroup, gio::ActionMap, gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Native, gtk::Root, gtk::ShortcutManager; } impl Window { pub fn new(app: &impl IsA) -> Self { let window: Self = glib::Object::builder().property("application", app).build(); window .playbin() .bind_property("volume", &*window.imp().playbar, "volume") .bidirectional() .sync_create() .build(); window.imp().setup.connect_closure( "connected", false, glib::closure_local!( #[weak] window, move |_setup: crate::ui::Setup, api: crate::subsonic_vala::Client| { window.imp().api.replace(Some(api.clone())); window.playbin().set_api(&api); window.set_can_click_shuffle_all(true); } ), ); window.imp().setup.load(); window.playbin().connect_closure( "new-track", false, glib::closure_local!( #[weak] window, move |_playbin: crate::Playbin, song: crate::playbin::Song| { window.imp().now_playing(&song); } ), ); window.playbin().connect_closure( "stopped", false, glib::closure_local!( #[weak] window, move |_playbin: crate::Playbin| { window.set_playing_cover_art(None::); window.set_song(None::); } ), ); window } }