make star button work

This commit is contained in:
Erica Z 2024-12-01 01:09:57 +01:00
parent 720b73f2a8
commit 5b0a7124a8
7 changed files with 84 additions and 3 deletions

View file

@ -110,8 +110,8 @@ template $AudreyUiPlayQueueSong: Box {
Button {
focusable: true;
// TODO icon-name: bind $star_button_icon_name (template.song as <$AudreyModelSong>.starred) as <string>;
icon-name: bind $star_button_icon_name() as <string>;
icon-name: bind $heart_button_icon_name(template.song as <$AudreyModelSong>.starred) as <string>;
clicked => $on_heart_button_clicked() swapped;
styles [
"flat"

View file

@ -176,10 +176,11 @@ template $AudreyUiPlaybar: Adw.Bin {
}
Button {
icon-name: "heart-empty-symbolic"; // placeholder
icon-name: bind $heart_button_icon_name(template.song as <$AudreyModelSong>.starred) as <string>;
halign: end;
valign: center;
sensitive: bind template.idle-active inverted;
clicked => $on_heart_button_clicked() swapped;
}
Button {

View file

@ -94,6 +94,7 @@ template $AudreyUiWindow: Adw.ApplicationWindow {
duration: bind template.duration;
idle-active: bind template.idle-active;
playlist-count: bind template.playlist-count;
client: bind template.client;
}
}
}

View file

@ -32,6 +32,8 @@ mod imp {
track: Cell<i64>,
#[property(get, set)]
cover_art: RefCell<String>,
#[property(get, set)]
starred: Cell<bool>,
#[property(get, set)]
stream_url: RefCell<String>,

View file

@ -299,6 +299,16 @@ impl Client {
pub fn stream_url(&self, id: &str) -> url::Url {
self.url(&["rest", "stream"], &[("id", id)])
}
pub async fn star(&self, id: &str) -> Result<(), Error> {
let url = self.url(&["rest", "star"], &[("id", id)]);
self.get_bytes(url).await.map(|_| ())
}
pub async fn unstar(&self, id: &str) -> Result<(), Error> {
let url = self.url(&["rest", "unstar"], &[("id", id)]);
self.get_bytes(url).await.map(|_| ())
}
}
impl Drop for Client {

View file

@ -3,6 +3,7 @@ use adw::prelude::*;
use glib::subclass::InitializingObject;
use gtk::{gdk, gio, glib, subclass::prelude::*};
use std::cell::{Cell, RefCell};
use tracing::{event, Level};
mod imp {
use super::*;
@ -35,6 +36,9 @@ mod imp {
drag_pos: Cell<(i32, i32)>,
drag_widget: Cell<Option<gtk::ListBox>>,
#[property(get, set)]
client: RefCell<Option<crate::wrappers::Client>>,
}
#[glib::object_subclass]
@ -174,6 +178,37 @@ mod imp {
self.obj()
.set_current(playlist_pos == self.position.get() as i64);
}
// FIXME: duplicated in playbar....
#[template_callback]
fn heart_button_icon_name(&self, starred: bool) -> &'static str {
if starred {
"heart-full-symbolic"
} else {
"heart-empty-symbolic"
}
}
#[template_callback]
async fn on_heart_button_clicked(&self) {
// TODO: disable button while await ongoing?? consider making star/unstar methods in
// the model class and add a semaphore there for serialization
// FIXME: doesn't update all if track is duplicated in the play queue
let song = self.obj().song().unwrap();
let client = self.obj().client().unwrap();
if song.starred() {
match client.unstar(&song.id()).await {
Ok(()) => song.set_starred(false),
Err(err) => event!(Level::ERROR, "could not unstar song {}: {err}", song.id()),
}
} else {
match client.star(&song.id()).await {
Ok(()) => song.set_starred(true),
Err(err) => event!(Level::ERROR, "could not star song {}: {err}", song.id()),
}
}
}
}
}
@ -199,6 +234,7 @@ impl Song {
self.set_song(&song);
self.set_position(position);
self.set_playlist_pos(window.playlist_pos());
self.set_client(window.client().unwrap());
song.need_thumbnail(
window.client().as_ref().unwrap(),

View file

@ -43,6 +43,9 @@ mod imp {
#[property(get, set)]
_show_pulse_bar: Cell<bool>,
#[property(get, set)]
client: RefCell<Option<crate::wrappers::Client>>,
}
#[glib::object_subclass]
@ -162,6 +165,34 @@ mod imp {
fn song_album(&self, song: Option<&Song>) -> String {
song.map(Song::album).unwrap_or_default()
}
#[template_callback]
fn heart_button_icon_name(&self, starred: bool) -> &'static str {
if starred {
"heart-full-symbolic"
} else {
"heart-empty-symbolic"
}
}
#[template_callback]
async fn on_heart_button_clicked(&self) {
// TODO: disable button while await ongoing??
let song = self.obj().song().unwrap();
let client = self.obj().client().unwrap();
if song.starred() {
match client.unstar(&song.id()).await {
Ok(()) => song.set_starred(false),
Err(err) => event!(Level::ERROR, "could not unstar song {}: {err}", song.id()),
}
} else {
match client.star(&song.id()).await {
Ok(()) => song.set_starred(true),
Err(err) => event!(Level::ERROR, "could not star song {}: {err}", song.id()),
}
}
}
}
impl Drop for Playbar {