wip translate window.vala
This commit is contained in:
parent
34bec8fdae
commit
8a6a056b36
10 changed files with 213 additions and 171 deletions
|
@ -16,7 +16,7 @@ template $AudreyUiWindow: Adw.ApplicationWindow {
|
|||
Button {
|
||||
icon-name: "media-playlist-shuffle";
|
||||
sensitive: bind template.can_click_shuffle_all;
|
||||
clicked => $shuffle_all ();
|
||||
clicked => $shuffle_all () swapped;
|
||||
}
|
||||
|
||||
title-widget: Adw.ViewSwitcher {
|
||||
|
@ -27,7 +27,7 @@ template $AudreyUiWindow: Adw.ApplicationWindow {
|
|||
[end]
|
||||
Button {
|
||||
icon-name: "applications-system";
|
||||
clicked => $show_setup_dialog ();
|
||||
clicked => $show_setup_dialog () swapped;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,12 +46,9 @@ mod imp {
|
|||
crate::Mpris::setup(conn.object_server(), &window)
|
||||
.await
|
||||
.expect("could not serve mpris");
|
||||
crate::mpris::Player::setup(
|
||||
conn.object_server(),
|
||||
&window.playbin().unwrap(),
|
||||
)
|
||||
.await
|
||||
.expect("could not serve mpris player");
|
||||
crate::mpris::Player::setup(conn.object_server(), &window.playbin())
|
||||
.await
|
||||
.expect("could not serve mpris player");
|
||||
|
||||
drop(window); // don't keep this alive
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ audrey_sources = [
|
|||
'playbin.vala',
|
||||
'rust.vapi',
|
||||
'subsonic.vala',
|
||||
'ui/window.vala',
|
||||
]
|
||||
|
||||
audrey_deps = [
|
||||
|
|
|
@ -19,12 +19,18 @@ pub mod ffi {
|
|||
|
||||
extern "C" {
|
||||
pub fn audrey_playbin_get_type() -> glib::ffi::GType;
|
||||
pub fn audrey_playbin_new() -> *mut AudreyPlaybin;
|
||||
pub fn audrey_playbin_get_state(self_: *mut AudreyPlaybin) -> super::state::ffi::State;
|
||||
pub fn audrey_playbin_pause(self_: *mut AudreyPlaybin);
|
||||
pub fn audrey_playbin_play(self_: *mut AudreyPlaybin);
|
||||
pub fn audrey_playbin_stop(self_: *mut AudreyPlaybin);
|
||||
pub fn audrey_playbin_clear(self_: *mut AudreyPlaybin);
|
||||
pub fn audrey_playbin_get_volume(self_: *mut AudreyPlaybin) -> std::ffi::c_int;
|
||||
pub fn audrey_playbin_set_volume(self_: *mut AudreyPlaybin, volume: std::ffi::c_int);
|
||||
pub fn audrey_playbin_set_api(
|
||||
self_: *mut AudreyPlaybin,
|
||||
api: *mut crate::subsonic_vala::client::ffi::AudreySubsonicClient,
|
||||
);
|
||||
pub fn audrey_playbin_seek(self_: *mut AudreyPlaybin, position: f64);
|
||||
pub fn audrey_playbin_go_to_next_track(self_: *mut AudreyPlaybin);
|
||||
pub fn audrey_playbin_go_to_prev_track(self_: *mut AudreyPlaybin);
|
||||
|
@ -61,6 +67,12 @@ glib::wrapper! {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for Playbin {
|
||||
fn default() -> Self {
|
||||
unsafe { from_glib_none(ffi::audrey_playbin_new()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Playbin {
|
||||
pub fn state(&self) -> State {
|
||||
unsafe { glib::translate::from_glib(ffi::audrey_playbin_get_state(self.to_glib_none().0)) }
|
||||
|
@ -134,6 +146,10 @@ impl Playbin {
|
|||
unsafe { ffi::audrey_playbin_stop(self.to_glib_none().0) }
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
unsafe { ffi::audrey_playbin_clear(self.to_glib_none().0) }
|
||||
}
|
||||
|
||||
pub fn play_queue(&self) -> gio::ListModel {
|
||||
unsafe { from_glib_none(ffi::audrey_playbin_get_play_queue(self.to_glib_none().0)) }
|
||||
}
|
||||
|
@ -167,4 +183,8 @@ impl Playbin {
|
|||
glib::spawn_future_local(f(self_, param_spec));
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_api(&self, api: &crate::subsonic_vala::Client) {
|
||||
unsafe { ffi::audrey_playbin_set_api(self.to_glib_none().0, api.to_glib_none().0) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,4 +43,20 @@ namespace Audrey {
|
|||
public void save ();
|
||||
}
|
||||
|
||||
public class Ui.Window : Adw.ApplicationWindow {
|
||||
public int volume { get; set; }
|
||||
public bool mute { get; set; }
|
||||
|
||||
public PlaybinSong? song { get; }
|
||||
public Gdk.Paintable? playing_cover_art { get; set; }
|
||||
|
||||
public bool cover_art_loading { get; set; }
|
||||
|
||||
public Playbin playbin { get; }
|
||||
|
||||
public Window (Gtk.Application app);
|
||||
|
||||
public bool can_click_shuffle_all { get; }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
mod client;
|
||||
pub mod client;
|
||||
pub use client::Client;
|
||||
|
||||
mod song;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
mod ffi {
|
||||
pub mod ffi {
|
||||
use gtk::glib;
|
||||
use std::ffi::c_char;
|
||||
|
||||
|
|
|
@ -158,6 +158,12 @@ glib::wrapper! {
|
|||
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
|
||||
}
|
||||
|
||||
impl Default for Setup {
|
||||
fn default() -> Self {
|
||||
glib::Object::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Setup {
|
||||
pub fn load(&self) {
|
||||
glib::spawn_future_local(glib::clone!(
|
||||
|
|
189
src/ui/window.rs
189
src/ui/window.rs
|
@ -1,45 +1,184 @@
|
|||
pub mod ffi {
|
||||
use gtk::glib;
|
||||
mod imp {
|
||||
use adw::prelude::*;
|
||||
use adw::subclass::prelude::*;
|
||||
use glib::subclass::InitializingObject;
|
||||
use gtk::{gdk, glib};
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct AudreyUiWindow {
|
||||
parent_instance: adw::ffi::AdwApplicationWindow,
|
||||
#[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<crate::ui::Playbar>,
|
||||
|
||||
#[property(get, set)]
|
||||
playbin: RefCell<crate::Playbin>,
|
||||
|
||||
#[property(get, set, default = false)]
|
||||
can_click_shuffle_all: Cell<bool>,
|
||||
|
||||
#[property(get, set, nullable)]
|
||||
playing_cover_art: RefCell<Option<gdk::Paintable>>,
|
||||
|
||||
#[property(get, set, nullable)]
|
||||
song: RefCell<Option<crate::playbin::Song>>,
|
||||
|
||||
pub(super) setup: crate::ui::Setup,
|
||||
pub(super) api: RefCell<Option<crate::subsonic_vala::Client>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct AudreyUiWindowClass {
|
||||
parent_class: adw::ffi::AdwApplicationWindowClass,
|
||||
#[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<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn audrey_ui_window_get_type() -> glib::ffi::GType;
|
||||
pub fn audrey_ui_window_new(app: *mut gtk::ffi::GtkApplication) -> *mut AudreyUiWindow;
|
||||
pub fn audrey_ui_window_get_playbin(
|
||||
self_: *mut AudreyUiWindow,
|
||||
) -> *mut crate::playbin::ffi::AudreyPlaybin;
|
||||
#[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 glib::translate::{from_glib_none, ToGlibPtr};
|
||||
use gtk::{gio, glib};
|
||||
use adw::subclass::prelude::*;
|
||||
use gtk::{gdk, gio, glib};
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct Window(Object<ffi::AudreyUiWindow, ffi::AudreyUiWindowClass>)
|
||||
pub struct Window(ObjectSubclass<imp::Window>)
|
||||
@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;
|
||||
|
||||
match fn {
|
||||
type_ => || ffi::audrey_ui_window_get_type(),
|
||||
}
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub fn new(app: &impl IsA<gtk::Application>) -> Self {
|
||||
unsafe { from_glib_none(ffi::audrey_ui_window_new(app.as_ref().to_glib_none().0)) }
|
||||
}
|
||||
let window: Self = glib::Object::builder().property("application", app).build();
|
||||
|
||||
pub fn playbin(&self) -> Option<crate::Playbin> {
|
||||
unsafe { from_glib_none(ffi::audrey_ui_window_get_playbin(self.to_glib_none().0)) }
|
||||
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::<gdk::Paintable>);
|
||||
window.set_song(None::<crate::playbin::Song>);
|
||||
}
|
||||
),
|
||||
);
|
||||
|
||||
window
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
[GtkTemplate (ui = "/eu/callcc/audrey/window.ui")]
|
||||
public class Audrey.Ui.Window : Adw.ApplicationWindow {
|
||||
[GtkChild] public unowned PlayQueue play_queue;
|
||||
[GtkChild] public unowned Playbar playbar;
|
||||
//[GtkChild] public unowned Adw.ButtonRow shuffle_all_tracks;
|
||||
|
||||
private Setup setup;
|
||||
|
||||
private Subsonic.Client api;
|
||||
|
||||
public int volume {
|
||||
get { return this.playbin.volume; }
|
||||
set { this.playbin.volume = value; }
|
||||
}
|
||||
public bool mute {
|
||||
get { return this.playbin.mute; }
|
||||
set { this.playbin.mute = value; }
|
||||
}
|
||||
|
||||
public PlaybinSong? song { get; private set; }
|
||||
public Gdk.Paintable? playing_cover_art { get; set; default = null; }
|
||||
|
||||
private Cancellable cancel_loading_art;
|
||||
public bool cover_art_loading { get; set; default = false; }
|
||||
|
||||
public Playbin playbin { get; private set; default = new Playbin (); }
|
||||
|
||||
public Window (Gtk.Application app) {
|
||||
Object (application: app);
|
||||
|
||||
this.playbin.bind_property("volume", this.playbar, "volume", BindingFlags.BIDIRECTIONAL | BindingFlags.SYNC_CREATE);
|
||||
}
|
||||
|
||||
private void now_playing (PlaybinSong 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;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
construct {
|
||||
/*
|
||||
Bus.own_name (
|
||||
BusType.SESSION,
|
||||
"org.mpris.MediaPlayer2.audrey",
|
||||
BusNameOwnerFlags.NONE,
|
||||
(conn) => {
|
||||
try {
|
||||
this.mpris_player = new MprisPlayer (conn, this.playbin);
|
||||
|
||||
conn.register_object ("/org/mpris/MediaPlayer2", this.mpris_player);
|
||||
} catch (IOError e) {
|
||||
error ("could not register dbus service: %s", e.message);
|
||||
}
|
||||
},
|
||||
() => {},
|
||||
() => { error ("could not acquire dbus name"); });
|
||||
*/
|
||||
|
||||
this.setup = new Setup ();
|
||||
|
||||
this.setup.connected.connect ((api) => {
|
||||
this.api = api;
|
||||
this.playbin.api = api;
|
||||
//this.mpris_player.api = api;
|
||||
this.can_click_shuffle_all = true;
|
||||
});
|
||||
this.setup.load ();
|
||||
|
||||
this.playbin.new_track.connect (() => {
|
||||
this.now_playing (this.playbin.play_queue.get_item (this.playbin.play_queue_position) as PlaybinSong);
|
||||
});
|
||||
|
||||
this.playbin.stopped.connect (() => {
|
||||
this.playing_cover_art = null;
|
||||
this.song = null;
|
||||
});
|
||||
}
|
||||
|
||||
[GtkCallback] private void show_setup_dialog () {
|
||||
this.setup.present (this);
|
||||
}
|
||||
|
||||
public bool can_click_shuffle_all { get; private set; default = false; }
|
||||
|
||||
[GtkCallback] private void shuffle_all () {
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
[GtkCallback] private bool show_playbar_cover_art (string? stack_child) {
|
||||
return stack_child != "play-queue";
|
||||
}
|
||||
|
||||
public override bool close_request () {
|
||||
// stop playback on close
|
||||
this.playbin.stop ();
|
||||
return false;
|
||||
}
|
||||
|
||||
~Window () {
|
||||
debug ("destroying main window");
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue