Compare commits
2 commits
1b8a59bef5
...
371c966be8
Author | SHA1 | Date | |
---|---|---|---|
371c966be8 | |||
e7e7341c89 |
14 changed files with 36 additions and 441 deletions
|
@ -128,7 +128,6 @@ template $AudreyUiWindow: Adw.ApplicationWindow {
|
||||||
[bottom]
|
[bottom]
|
||||||
$AudreyUiPlaybar playbar {
|
$AudreyUiPlaybar playbar {
|
||||||
song: bind template.song;
|
song: bind template.song;
|
||||||
playbin: bind template.playbin;
|
|
||||||
playing_cover_art: bind template.playing_cover_art;
|
playing_cover_art: bind template.playing_cover_art;
|
||||||
show_cover_art: bind $show_playbar_cover_art (stack.visible-child-name) as <bool>;
|
show_cover_art: bind $show_playbar_cover_art (stack.visible-child-name) as <bool>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,13 @@ pub mod ui;
|
||||||
pub mod mpris;
|
pub mod mpris;
|
||||||
pub use mpris::Mpris;
|
pub use mpris::Mpris;
|
||||||
|
|
||||||
pub mod playbin;
|
pub mod playbin_song;
|
||||||
pub use playbin::Playbin;
|
pub use playbin_song::Song as PlaybinSong;
|
||||||
|
|
||||||
pub mod subsonic;
|
pub mod subsonic;
|
||||||
pub mod subsonic_vala;
|
|
||||||
|
|
||||||
pub mod playbin2;
|
pub mod playbin2;
|
||||||
|
pub type Playbin = playbin2::Playbin<PlaybinSong>;
|
||||||
|
|
||||||
mod signal;
|
mod signal;
|
||||||
pub use signal::{Signal, SignalEmitter, SignalHandler};
|
pub use signal::{Signal, SignalEmitter, SignalHandler};
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
|
use crate::{Playbin, PlaybinSong};
|
||||||
use gtk::glib::spawn_future_local;
|
use gtk::glib::spawn_future_local;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use zbus::zvariant::{ObjectPath, OwnedObjectPath, OwnedValue, Value};
|
use zbus::zvariant::{ObjectPath, OwnedObjectPath, OwnedValue, Value};
|
||||||
|
|
||||||
use crate::playbin::Song as PlaybinSong;
|
|
||||||
type Playbin = crate::playbin2::Playbin<PlaybinSong>;
|
|
||||||
|
|
||||||
const MICROSECONDS: f64 = 1e6; // in a second
|
const MICROSECONDS: f64 = 1e6; // in a second
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -37,7 +35,7 @@ struct MetadataMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetadataMap {
|
impl MetadataMap {
|
||||||
fn from_playbin_song(song: Option<&crate::playbin::Song>) -> Self {
|
fn from_playbin_song(song: Option<&PlaybinSong>) -> Self {
|
||||||
song.map(|song| MetadataMap {
|
song.map(|song| MetadataMap {
|
||||||
// use a unique growing counter to identify tracks
|
// use a unique growing counter to identify tracks
|
||||||
track_id: Some({
|
track_id: Some({
|
||||||
|
|
190
src/playbin.rs
190
src/playbin.rs
|
@ -1,190 +0,0 @@
|
||||||
pub mod song;
|
|
||||||
pub use song::Song;
|
|
||||||
|
|
||||||
mod state;
|
|
||||||
pub use state::State;
|
|
||||||
|
|
||||||
pub mod ffi {
|
|
||||||
use gtk::{gio, glib};
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AudreyPlaybin {
|
|
||||||
parent_instance: glib::gobject_ffi::GObject,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AudreyPlaybinClass {
|
|
||||||
parent_class: glib::gobject_ffi::GObjectClass,
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
pub fn audrey_playbin_get_position(self_: *mut AudreyPlaybin) -> f64;
|
|
||||||
pub fn audrey_playbin_get_duration(self_: *mut AudreyPlaybin) -> f64;
|
|
||||||
pub fn audrey_playbin_get_mute(self_: *mut AudreyPlaybin) -> glib::ffi::gboolean;
|
|
||||||
pub fn audrey_playbin_set_mute(self_: *mut AudreyPlaybin, mute: glib::ffi::gboolean);
|
|
||||||
pub fn audrey_playbin_get_play_queue_position(
|
|
||||||
self_: *mut AudreyPlaybin,
|
|
||||||
) -> std::ffi::c_uint;
|
|
||||||
pub fn audrey_playbin_get_play_queue_length(self_: *mut AudreyPlaybin) -> std::ffi::c_uint;
|
|
||||||
pub fn audrey_playbin_move_track(
|
|
||||||
self_: *mut AudreyPlaybin,
|
|
||||||
from: std::ffi::c_uint,
|
|
||||||
to: std::ffi::c_uint,
|
|
||||||
);
|
|
||||||
pub fn audrey_playbin_remove_track(self_: *mut AudreyPlaybin, position: std::ffi::c_uint);
|
|
||||||
pub fn audrey_playbin_select_track(self_: *mut AudreyPlaybin, position: std::ffi::c_uint);
|
|
||||||
pub fn audrey_playbin_get_play_queue(
|
|
||||||
self_: *mut AudreyPlaybin,
|
|
||||||
) -> *mut gio::ffi::GListModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use adw::prelude::*;
|
|
||||||
use glib::translate::{from_glib, from_glib_none, IntoGlib, ToGlibPtr};
|
|
||||||
use gtk::{gio, glib};
|
|
||||||
|
|
||||||
glib::wrapper! {
|
|
||||||
pub struct Playbin(Object<ffi::AudreyPlaybin, ffi::AudreyPlaybinClass>);
|
|
||||||
|
|
||||||
match fn {
|
|
||||||
type_ => || ffi::audrey_playbin_get_type(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pause(&self) {
|
|
||||||
unsafe { ffi::audrey_playbin_pause(self.to_glib_none().0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn play(&self) {
|
|
||||||
unsafe { ffi::audrey_playbin_play(self.to_glib_none().0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn volume(&self) -> i32 {
|
|
||||||
unsafe { ffi::audrey_playbin_get_volume(self.to_glib_none().0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_volume(&self, value: i32) {
|
|
||||||
unsafe { ffi::audrey_playbin_set_volume(self.to_glib_none().0, value) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn seek(&self, position: f64) {
|
|
||||||
unsafe { ffi::audrey_playbin_seek(self.to_glib_none().0, position) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn go_to_next_track(&self) {
|
|
||||||
unsafe { ffi::audrey_playbin_go_to_next_track(self.to_glib_none().0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn go_to_prev_track(&self) {
|
|
||||||
unsafe { ffi::audrey_playbin_go_to_prev_track(self.to_glib_none().0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn position(&self) -> f64 {
|
|
||||||
unsafe { ffi::audrey_playbin_get_position(self.to_glib_none().0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn duration(&self) -> f64 {
|
|
||||||
unsafe { ffi::audrey_playbin_get_duration(self.to_glib_none().0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mute(&self) -> bool {
|
|
||||||
unsafe { from_glib(ffi::audrey_playbin_get_mute(self.to_glib_none().0)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_mute(&self, mute: bool) {
|
|
||||||
unsafe { ffi::audrey_playbin_set_mute(self.to_glib_none().0, mute.into_glib()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn play_queue_position(&self) -> u32 {
|
|
||||||
unsafe { ffi::audrey_playbin_get_play_queue_position(self.to_glib_none().0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn play_queue_length(&self) -> u32 {
|
|
||||||
unsafe { ffi::audrey_playbin_get_play_queue_length(self.to_glib_none().0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn move_track(&self, from: u32, to: u32) {
|
|
||||||
unsafe { ffi::audrey_playbin_move_track(self.to_glib_none().0, from, to) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_track(&self, position: u32) {
|
|
||||||
unsafe { ffi::audrey_playbin_remove_track(self.to_glib_none().0, position) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn select_track(&self, position: u32) {
|
|
||||||
unsafe { ffi::audrey_playbin_select_track(self.to_glib_none().0, position) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stop(&self) {
|
|
||||||
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)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn connect_new_track<F: Fn(&Self, &Song) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
|
||||||
self.connect_closure(
|
|
||||||
"new-track",
|
|
||||||
false,
|
|
||||||
glib::closure_local!(|playbin, song| f(playbin, song)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn connect_seeked<F: Fn(&Self, f64) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
|
||||||
self.connect_closure(
|
|
||||||
"seeked",
|
|
||||||
false,
|
|
||||||
glib::closure_local!(|playbin, position| f(playbin, position)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: this would be useful in other places, probably
|
|
||||||
pub fn connect_notify_future_local<
|
|
||||||
F: Fn(&Self, &glib::ParamSpec) -> U + 'static,
|
|
||||||
U: std::future::Future<Output = ()> + 'static,
|
|
||||||
>(
|
|
||||||
&self,
|
|
||||||
name: &str,
|
|
||||||
f: F,
|
|
||||||
) {
|
|
||||||
self.connect_notify_local(Some(name), move |self_, param_spec| {
|
|
||||||
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) }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
pub mod ffi {
|
|
||||||
use gtk::glib;
|
|
||||||
|
|
||||||
pub type State = std::ffi::c_int;
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
pub fn audrey_playbin_state_get_type() -> glib::ffi::GType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use glib::prelude::*;
|
|
||||||
use gtk::glib;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub enum State {
|
|
||||||
Stopped,
|
|
||||||
Paused,
|
|
||||||
Playing,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl glib::translate::FromGlib<ffi::State> for State {
|
|
||||||
unsafe fn from_glib(value: ffi::State) -> Self {
|
|
||||||
match value {
|
|
||||||
0 => Self::Stopped,
|
|
||||||
1 => Self::Paused,
|
|
||||||
2 => Self::Playing,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'a> glib::value::FromValue<'a> for State {
|
|
||||||
type Checker = glib::value::GenericValueTypeChecker<Self>;
|
|
||||||
|
|
||||||
unsafe fn from_value(value: &'a glib::Value) -> Self {
|
|
||||||
use glib::translate::ToGlibPtr;
|
|
||||||
|
|
||||||
glib::translate::from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StaticType for State {
|
|
||||||
fn static_type() -> glib::Type {
|
|
||||||
unsafe { glib::translate::from_glib(ffi::audrey_playbin_state_get_type()) }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
pub mod client;
|
|
||||||
pub use client::Client;
|
|
||||||
|
|
||||||
mod song;
|
|
||||||
pub use song::Song;
|
|
|
@ -1,48 +0,0 @@
|
||||||
pub mod ffi {
|
|
||||||
use gtk::glib;
|
|
||||||
use std::ffi::c_char;
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AudreySubsonicClient {
|
|
||||||
parent_instance: glib::gobject_ffi::GObject,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AudreySubsonicClientClass {
|
|
||||||
parent_class: glib::gobject_ffi::GObjectClass,
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
pub fn audrey_subsonic_client_get_type() -> glib::ffi::GType;
|
|
||||||
pub fn audrey_subsonic_client_new_with_token(
|
|
||||||
server_url: *mut c_char,
|
|
||||||
username: *mut c_char,
|
|
||||||
token: *mut c_char,
|
|
||||||
salt: *mut c_char,
|
|
||||||
) -> *mut AudreySubsonicClient;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use glib::translate::{from_glib_none, ToGlibPtr};
|
|
||||||
use gtk::glib;
|
|
||||||
|
|
||||||
glib::wrapper! {
|
|
||||||
pub struct Client(Object<ffi::AudreySubsonicClient, ffi::AudreySubsonicClientClass>);
|
|
||||||
|
|
||||||
match fn {
|
|
||||||
type_ => || ffi::audrey_subsonic_client_get_type(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Client {
|
|
||||||
pub fn with_token(server_url: &str, username: &str, token: &str, salt: &str) -> Self {
|
|
||||||
unsafe {
|
|
||||||
from_glib_none(ffi::audrey_subsonic_client_new_with_token(
|
|
||||||
server_url.to_glib_none().0,
|
|
||||||
username.to_glib_none().0,
|
|
||||||
token.to_glib_none().0,
|
|
||||||
salt.to_glib_none().0,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
mod ffi {
|
|
||||||
use gtk::glib;
|
|
||||||
use std::ffi::*;
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct AudreySubsonicSong {
|
|
||||||
pub id: *mut c_char,
|
|
||||||
pub title: *mut c_char,
|
|
||||||
pub album: *mut c_char,
|
|
||||||
pub artist: *mut c_char,
|
|
||||||
pub track: i64,
|
|
||||||
pub year: i64,
|
|
||||||
pub starred: *mut glib::ffi::GDateTime,
|
|
||||||
pub duration: i64,
|
|
||||||
pub play_count: i64,
|
|
||||||
pub genre: *mut c_char,
|
|
||||||
pub cover_art: *mut c_char,
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
pub fn audrey_subsonic_song_copy(ptr: *const AudreySubsonicSong)
|
|
||||||
-> *mut AudreySubsonicSong;
|
|
||||||
pub fn audrey_subsonic_song_free(ptr: *mut AudreySubsonicSong);
|
|
||||||
pub fn audrey_subsonic_song_get_type() -> glib::ffi::GType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use gtk::glib;
|
|
||||||
|
|
||||||
glib::wrapper! {
|
|
||||||
pub struct Song(BoxedInline<ffi::AudreySubsonicSong>);
|
|
||||||
|
|
||||||
match fn {
|
|
||||||
copy => |ptr| ffi::audrey_subsonic_song_copy(ptr),
|
|
||||||
free => |ptr| ffi::audrey_subsonic_song_free(ptr),
|
|
||||||
type_ => || ffi::audrey_subsonic_song_get_type(),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,14 +2,12 @@ pub mod song;
|
||||||
pub use song::Song;
|
pub use song::Song;
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use crate::playbin::Song as PlaybinSong;
|
use crate::{Playbin, PlaybinSong};
|
||||||
use adw::{gio, glib, prelude::*, subclass::prelude::*};
|
use adw::{gio, glib, prelude::*, subclass::prelude::*};
|
||||||
use glib::{subclass::InitializingObject, WeakRef};
|
use glib::{subclass::InitializingObject, WeakRef};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
type Playbin = crate::playbin2::Playbin<PlaybinSong>;
|
|
||||||
|
|
||||||
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
||||||
#[template(resource = "/eu/callcc/audrey/play_queue.ui")]
|
#[template(resource = "/eu/callcc/audrey/play_queue.ui")]
|
||||||
#[properties(wrapper_type = super::PlayQueue)]
|
#[properties(wrapper_type = super::PlayQueue)]
|
||||||
|
@ -78,10 +76,7 @@ mod imp {
|
||||||
|
|
||||||
child.bind(
|
child.bind(
|
||||||
item.position(),
|
item.position(),
|
||||||
item.item()
|
item.item().unwrap().downcast_ref::<PlaybinSong>().unwrap(),
|
||||||
.unwrap()
|
|
||||||
.downcast_ref::<crate::playbin::Song>()
|
|
||||||
.unwrap(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,13 +104,11 @@ mod imp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::playbin::Song as PlaybinSong;
|
use crate::Playbin;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
type Playbin = crate::playbin2::Playbin<PlaybinSong>;
|
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct PlayQueue(ObjectSubclass<imp::PlayQueue>)
|
pub struct PlayQueue(ObjectSubclass<imp::PlayQueue>)
|
||||||
@extends adw::Bin, gtk::Widget,
|
@extends adw::Bin, gtk::Widget,
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
mod imp {
|
mod imp {
|
||||||
use crate::playbin::Song as PlaybinSong;
|
|
||||||
use crate::signal::SignalHandler;
|
use crate::signal::SignalHandler;
|
||||||
|
use crate::{Playbin, PlaybinSong};
|
||||||
use glib::{subclass::InitializingObject, WeakRef};
|
use glib::{subclass::InitializingObject, WeakRef};
|
||||||
use gtk::{gdk, gio, glib, prelude::*, subclass::prelude::*};
|
use gtk::{gdk, gio, glib, prelude::*, subclass::prelude::*};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
type Playbin = crate::playbin2::Playbin<PlaybinSong>;
|
|
||||||
|
|
||||||
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
||||||
#[template(resource = "/eu/callcc/audrey/play_queue_song.ui")]
|
#[template(resource = "/eu/callcc/audrey/play_queue_song.ui")]
|
||||||
#[properties(wrapper_type = super::Song)]
|
#[properties(wrapper_type = super::Song)]
|
||||||
|
@ -167,15 +165,13 @@ mod imp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::playbin::Song as PlaybinSong;
|
use crate::{Playbin, PlaybinSong};
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use glib::Object;
|
use glib::Object;
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
type Playbin = crate::playbin2::Playbin<PlaybinSong>;
|
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct Song(ObjectSubclass<imp::Song>)
|
pub struct Song(ObjectSubclass<imp::Song>)
|
||||||
@extends gtk::Box, gtk::Widget,
|
@extends gtk::Box, gtk::Widget,
|
||||||
|
@ -199,7 +195,7 @@ impl Song {
|
||||||
Rc::clone(self.imp().playbin.borrow().as_ref().unwrap())
|
Rc::clone(self.imp().playbin.borrow().as_ref().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind(&self, position: u32, song: &crate::playbin::Song) {
|
pub fn bind(&self, position: u32, song: &PlaybinSong) {
|
||||||
self.set_displayed_position(position + 1);
|
self.set_displayed_position(position + 1);
|
||||||
self.set_song(song);
|
self.set_song(song);
|
||||||
self.set_current(self.playbin().current_entry() == Some(position as usize));
|
self.set_current(self.playbin().current_entry() == Some(position as usize));
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
mod imp {
|
mod imp {
|
||||||
|
use crate::PlaybinSong;
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use glib::subclass::InitializingObject;
|
use glib::subclass::InitializingObject;
|
||||||
|
@ -11,7 +12,7 @@ mod imp {
|
||||||
#[template(resource = "/eu/callcc/audrey/playbar.ui")]
|
#[template(resource = "/eu/callcc/audrey/playbar.ui")]
|
||||||
pub struct Playbar {
|
pub struct Playbar {
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
song: RefCell<Option<crate::playbin::Song>>,
|
song: RefCell<Option<PlaybinSong>>,
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
playing_cover_art: RefCell<Option<gdk::Paintable>>,
|
playing_cover_art: RefCell<Option<gdk::Paintable>>,
|
||||||
#[property(get, set, default = true)]
|
#[property(get, set, default = true)]
|
||||||
|
@ -53,17 +54,17 @@ mod imp {
|
||||||
#[gtk::template_callbacks]
|
#[gtk::template_callbacks]
|
||||||
impl Playbar {
|
impl Playbar {
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn song_title(&self, song: Option<&crate::playbin::Song>) -> Option<GString> {
|
fn song_title(&self, song: Option<&PlaybinSong>) -> Option<GString> {
|
||||||
song.map(|song| song.title())
|
song.map(|song| song.title())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn song_artist(&self, song: Option<&crate::playbin::Song>) -> Option<GString> {
|
fn song_artist(&self, song: Option<&PlaybinSong>) -> Option<GString> {
|
||||||
song.map(|song| song.artist())
|
song.map(|song| song.artist())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn song_album(&self, song: Option<&crate::playbin::Song>) -> Option<GString> {
|
fn song_album(&self, song: Option<&PlaybinSong>) -> Option<GString> {
|
||||||
song.map(|song| song.album())
|
song.map(|song| song.album())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,25 +73,6 @@ mod imp {
|
||||||
gformat!("{:02}:{:02}", (s as i64) / 64, (s as i64) % 60)
|
gformat!("{:02}:{:02}", (s as i64) / 64, (s as i64) % 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
|
||||||
fn playbin_active(&self, state: crate::playbin::State) -> bool {
|
|
||||||
true // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
#[template_callback]
|
|
||||||
fn can_press_play(&self, state: crate::playbin::State, n_items: u32) -> bool {
|
|
||||||
true // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
#[template_callback]
|
|
||||||
fn play_pause_icon_name(&self, state: crate::playbin::State) -> &'static str {
|
|
||||||
/*
|
|
||||||
match state {
|
|
||||||
crate::playbin::State::Playing => "media-playback-pause",
|
|
||||||
_ => "media-playback-start",
|
|
||||||
}*/todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn mute_button_icon_name(&self, mute: bool) -> &'static str {
|
fn mute_button_icon_name(&self, mute: bool) -> &'static str {
|
||||||
if mute {
|
if mute {
|
||||||
|
@ -112,21 +94,24 @@ mod imp {
|
||||||
if range.adjustment().lower() < range.adjustment().upper() {
|
if range.adjustment().lower() < range.adjustment().upper() {
|
||||||
playbin.seek(value);
|
playbin.seek(value);
|
||||||
}
|
}
|
||||||
false*/todo!()
|
false*/
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn on_skip_forward_clicked(&self) {
|
fn on_skip_forward_clicked(&self) {
|
||||||
/*
|
/*
|
||||||
let playbin = self.playbin.upgrade().unwrap();
|
let playbin = self.playbin.upgrade().unwrap();
|
||||||
playbin.go_to_next_track();*/todo!()
|
playbin.go_to_next_track();*/
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn on_skip_backward_clicked(&self) {
|
fn on_skip_backward_clicked(&self) {
|
||||||
/*
|
/*
|
||||||
let playbin = self.playbin.upgrade().unwrap();
|
let playbin = self.playbin.upgrade().unwrap();
|
||||||
playbin.go_to_prev_track();*/todo!()
|
playbin.go_to_prev_track();*/
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
@ -138,7 +123,8 @@ mod imp {
|
||||||
if new_position < 0.0 {
|
if new_position < 0.0 {
|
||||||
new_position = 0.0;
|
new_position = 0.0;
|
||||||
}
|
}
|
||||||
playbin.seek(new_position);*/todo!()
|
playbin.seek(new_position);*/
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
@ -150,7 +136,8 @@ mod imp {
|
||||||
if new_position > playbin.duration() {
|
if new_position > playbin.duration() {
|
||||||
new_position = playbin.duration();
|
new_position = playbin.duration();
|
||||||
}
|
}
|
||||||
playbin.seek(new_position);*/todo!()
|
playbin.seek(new_position);*/
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
@ -162,7 +149,8 @@ mod imp {
|
||||||
playbin.pause();
|
playbin.pause();
|
||||||
} else {
|
} else {
|
||||||
playbin.play();
|
playbin.play();
|
||||||
}*/todo!()
|
}*/
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
|
|
@ -45,16 +45,7 @@ mod imp {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::derived_properties]
|
#[glib::derived_properties]
|
||||||
impl ObjectImpl for Setup {
|
impl ObjectImpl for Setup {}
|
||||||
fn signals() -> &'static [Signal] {
|
|
||||||
static SIGNALS: OnceLock<Vec<Signal>> = OnceLock::new();
|
|
||||||
SIGNALS.get_or_init(|| {
|
|
||||||
vec![Signal::builder("connected")
|
|
||||||
.param_types([crate::subsonic_vala::Client::static_type()])
|
|
||||||
.build()]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WidgetImpl for Setup {}
|
impl WidgetImpl for Setup {}
|
||||||
|
|
||||||
|
@ -121,34 +112,6 @@ mod imp {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// please REMOVEME once we've killed vala
|
|
||||||
fn get_random_salt(length: usize) -> String {
|
|
||||||
use rand::Rng;
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
std::iter::repeat(())
|
|
||||||
// 0.9: s/distributions/distr
|
|
||||||
.map(|()| rng.sample(rand::distributions::Alphanumeric))
|
|
||||||
.map(char::from)
|
|
||||||
.take(length)
|
|
||||||
.collect::<String>()
|
|
||||||
}
|
|
||||||
let new_salt = get_random_salt(8);
|
|
||||||
use md5::Digest;
|
|
||||||
let mut hasher = md5::Md5::new();
|
|
||||||
hasher.update(self.obj().password().as_bytes());
|
|
||||||
hasher.update(new_salt.as_bytes());
|
|
||||||
let new_token_bytes = hasher.finalize();
|
|
||||||
let new_token = base16ct::lower::encode_string(&new_token_bytes);
|
|
||||||
|
|
||||||
let vala_api = crate::subsonic_vala::Client::with_token(
|
|
||||||
&self.obj().server_url(),
|
|
||||||
&self.obj().username(),
|
|
||||||
&new_token,
|
|
||||||
&new_salt,
|
|
||||||
);
|
|
||||||
self.obj().set_authn_can_edit(true);
|
|
||||||
|
|
||||||
self.obj().emit_by_name::<()>("connected", &[&vala_api]);
|
|
||||||
self.connected.emit(self.obj().as_ref(), Rc::new(api));
|
self.connected.emit(self.obj().as_ref(), Rc::new(api));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
mod imp {
|
mod imp {
|
||||||
|
use crate::{Playbin, PlaybinSong};
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use glib::subclass::InitializingObject;
|
use glib::subclass::InitializingObject;
|
||||||
|
@ -6,7 +7,7 @@ mod imp {
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
impl crate::playbin2::PlaybinEntry for crate::playbin::Song {
|
impl crate::playbin2::PlaybinEntry for PlaybinSong {
|
||||||
fn url(&self) -> url::Url {
|
fn url(&self) -> url::Url {
|
||||||
self.stream_url()
|
self.stream_url()
|
||||||
}
|
}
|
||||||
|
@ -22,9 +23,6 @@ mod imp {
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) play_queue: TemplateChild<crate::ui::PlayQueue>,
|
pub(super) play_queue: TemplateChild<crate::ui::PlayQueue>,
|
||||||
|
|
||||||
#[property(get, set)]
|
|
||||||
playbin: RefCell<crate::Playbin>,
|
|
||||||
|
|
||||||
#[property(get, set, default = false)]
|
#[property(get, set, default = false)]
|
||||||
can_click_shuffle_all: Cell<bool>,
|
can_click_shuffle_all: Cell<bool>,
|
||||||
|
|
||||||
|
@ -32,11 +30,11 @@ mod imp {
|
||||||
playing_cover_art: RefCell<Option<gdk::Paintable>>,
|
playing_cover_art: RefCell<Option<gdk::Paintable>>,
|
||||||
|
|
||||||
#[property(get, set, nullable)]
|
#[property(get, set, nullable)]
|
||||||
song: RefCell<Option<crate::playbin::Song>>,
|
song: RefCell<Option<PlaybinSong>>,
|
||||||
|
|
||||||
pub(super) setup: crate::ui::Setup,
|
pub(super) setup: crate::ui::Setup,
|
||||||
|
|
||||||
pub(super) playbin2: Rc<crate::playbin2::Playbin<crate::playbin::Song>>,
|
pub(super) playbin2: Rc<Playbin>,
|
||||||
pub(super) api2: RefCell<Option<Rc<crate::subsonic::Client>>>,
|
pub(super) api2: RefCell<Option<Rc<crate::subsonic::Client>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +136,7 @@ mod imp {
|
||||||
let api = api.as_ref().unwrap();
|
let api = api.as_ref().unwrap();
|
||||||
for song in api.get_random_songs(10).await.unwrap().into_iter() {
|
for song in api.get_random_songs(10).await.unwrap().into_iter() {
|
||||||
self.playbin2
|
self.playbin2
|
||||||
.push_entry(crate::playbin::Song::from_child(api, &song));
|
.push_entry(PlaybinSong::from_child(api, &song));
|
||||||
}
|
}
|
||||||
self.obj().set_can_click_shuffle_all(true);
|
self.obj().set_can_click_shuffle_all(true);
|
||||||
}
|
}
|
||||||
|
@ -148,7 +146,7 @@ mod imp {
|
||||||
self.setup.present(Some(self.obj().as_ref()));
|
self.setup.present(Some(self.obj().as_ref()));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn now_playing(&self, _song: &crate::playbin::Song) {
|
pub(super) fn now_playing(&self, _song: PlaybinSong) {
|
||||||
/*
|
/*
|
||||||
this.song = song;
|
this.song = song;
|
||||||
// api.scrobble.begin (this.song.id); TODO
|
// api.scrobble.begin (this.song.id); TODO
|
||||||
|
@ -185,6 +183,7 @@ mod imp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::PlaybinSong;
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use gtk::{gdk, gio, glib};
|
use gtk::{gdk, gio, glib};
|
||||||
|
@ -286,19 +285,6 @@ impl Window {
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
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
|
window
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue