From a61219f08639afd11db25109be6b9715d37cf075 Mon Sep 17 00:00:00 2001 From: Cleboost Date: Sun, 29 Jun 2025 19:49:15 +0200 Subject: [PATCH 1/4] Refactor playlist widget layout and placeholder Refactors the playlist widget to improve layout handling for horizontal and sidebar modes, using a unified text_content widget with conditional description display. Replaces the generic placeholder image with a music note icon for playlists without cover art. --- psst-gui/src/ui/playlist.rs | 111 +++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 46 deletions(-) diff --git a/psst-gui/src/ui/playlist.rs b/psst-gui/src/ui/playlist.rs index 5a5015aa..690a54ec 100644 --- a/psst-gui/src/ui/playlist.rs +++ b/psst-gui/src/ui/playlist.rs @@ -3,7 +3,7 @@ use std::{cell::RefCell, cmp::Ordering, rc::Rc, sync::Arc}; use druid::{ im::Vector, widget::{Button, Either, Flex, Label, LensWrap, LineBreaking, List, TextBox}, - Insets, Lens, LensExt, LocalizedString, Menu, MenuItem, Selector, Size, UnitPoint, Widget, + Lens, LensExt, LocalizedString, Menu, MenuItem, Selector, Size, UnitPoint, Widget, WidgetExt, WindowDesc, }; use itertools::Itertools; @@ -18,7 +18,7 @@ use crate::{ error::Error, ui::menu, webapi::WebApi, - widget::{Async, Empty, MyWidgetExt, RemoteImage, ThemeScope}, + widget::{icons, Async, Empty, MyWidgetExt, RemoteImage, ThemeScope}, }; use super::{playable, theme, track, utils}; @@ -47,21 +47,7 @@ pub fn list_widget() -> impl Widget { Async::new( utils::spinner_widget, || { - List::new(|| { - Label::raw() - .with_line_break_mode(LineBreaking::WordWrap) - .with_text_size(theme::TEXT_SIZE_SMALL) - .lens(Ctx::data().then(Playlist::name)) - .expand_width() - .padding(Insets::uniform_xy(theme::grid(2.0), theme::grid(0.6))) - .link() - .on_left_click(|ctx, _, playlist, _| { - ctx.submit_command( - cmd::NAVIGATE.with(Nav::PlaylistDetail(playlist.data.link())), - ); - }) - .context_menu(playlist_menu_ctx) - }) + List::new(|| playlist_widget(false)) }, utils::error_widget, ) @@ -326,24 +312,57 @@ pub fn playlist_widget(horizontal: bool) -> impl Widget> { .with_line_break_mode(LineBreaking::Clip) .lens(Ctx::data().then(Playlist::name)); - let playlist_description = Label::raw() - .with_line_break_mode(LineBreaking::WordWrap) - .with_text_color(theme::PLACEHOLDER_COLOR) - .with_text_size(theme::TEXT_SIZE_SMALL) - .lens(Ctx::data().then(Playlist::description)); - - let (playlist_name, playlist_description) = if horizontal { - ( - playlist_name.fix_width(playlist_image_size).align_left(), - playlist_description - .fix_width(playlist_image_size) - .align_left(), - ) + let text_content = if horizontal { + // Mode horizontal : permet les retours à la ligne + let name_widget = playlist_name.fix_width(playlist_image_size).align_left(); + let description_widget = Label::raw() + .with_line_break_mode(LineBreaking::WordWrap) + .with_text_color(theme::PLACEHOLDER_COLOR) + .with_text_size(theme::TEXT_SIZE_SMALL) + .lens(Ctx::data().then(Playlist::description)) + .fix_width(playlist_image_size) + .align_left(); + + Either::new( + |ctx: &WithCtx, _| !ctx.data.description.is_empty(), + Flex::column() + .with_child(name_widget) + .with_spacer(2.0) + .with_child(description_widget), + Flex::column() + .with_child( + Label::raw() + .with_line_break_mode(LineBreaking::WordWrap) + .with_text_size(theme::TEXT_SIZE_NORMAL) + .lens(Ctx::data().then(Playlist::name)) + .fix_width(playlist_image_size) + .align_left() + ) + .align_vertical(UnitPoint::CENTER) + ).boxed() } else { - ( - playlist_name.align_left(), - playlist_description.align_left(), - ) + // Mode sidebar : comportement simple + let name_widget = playlist_name.align_left(); + let description_widget = Label::raw() + .with_text_color(theme::PLACEHOLDER_COLOR) + .with_text_size(theme::TEXT_SIZE_SMALL) + .lens(Ctx::data().then(Playlist::description)) + .align_left(); + + Either::new( + |ctx: &WithCtx, _| !ctx.data.description.is_empty(), + Flex::column() + .with_child(name_widget) + .with_spacer(2.0) + .with_child(description_widget), + Flex::column() + .with_child( + Label::raw() + .with_text_size(theme::TEXT_SIZE_NORMAL) + .lens(Ctx::data().then(Playlist::name)) + ) + .align_vertical(UnitPoint::CENTER) + ).boxed() }; let playlist = if horizontal { @@ -351,10 +370,7 @@ pub fn playlist_widget(horizontal: bool) -> impl Widget> { .with_child(playlist_image) .with_default_spacer() .with_child( - Flex::column() - .with_child(playlist_name) - .with_spacer(2.0) - .with_child(playlist_description) + text_content .align_horizontal(UnitPoint::CENTER) .align_vertical(UnitPoint::TOP) .fix_size(theme::grid(16.0), theme::grid(8.0)), @@ -364,13 +380,7 @@ pub fn playlist_widget(horizontal: bool) -> impl Widget> { Flex::row() .with_child(playlist_image) .with_default_spacer() - .with_flex_child( - Flex::column() - .with_child(playlist_name) - .with_spacer(2.0) - .with_child(playlist_description), - 1.0, - ) + .with_flex_child(text_content, 1.0) .padding(theme::grid(1.0)) }; @@ -383,9 +393,18 @@ pub fn playlist_widget(horizontal: bool) -> impl Widget> { .context_menu(playlist_menu_ctx) } +fn music_note_placeholder_widget(size: f64) -> impl Widget { + icons::MUSIC_NOTE + .scale((size * 0.6, size * 0.6)) + .with_color(theme::PLACEHOLDER_COLOR) + .center() + .background(theme::BACKGROUND_DARK) + .fix_size(size, size) +} + fn cover_widget(size: f64) -> impl Widget { RemoteImage::new( - utils::placeholder_widget(), + music_note_placeholder_widget(size), move |playlist: &Playlist, _| playlist.image(size, size).map(|image| image.url.clone()), ) .fix_size(size, size) From 09b69abe6ef42e4db916aee805b9dba68476a8c6 Mon Sep 17 00:00:00 2001 From: Cleboost Date: Sun, 29 Jun 2025 19:49:20 +0200 Subject: [PATCH 2/4] Add WebP image support to client and dependencies Added 'webp' to the image crate features in Cargo.toml and updated the WebApi client to recognize and handle WebP images. This enables the application to process WebP image formats in addition to JPEG and PNG. --- psst-gui/Cargo.toml | 1 + psst-gui/src/webapi/client.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/psst-gui/Cargo.toml b/psst-gui/Cargo.toml index 769d5572..7b771401 100644 --- a/psst-gui/Cargo.toml +++ b/psst-gui/Cargo.toml @@ -42,6 +42,7 @@ druid = { git = "https://github.com/jpochyla/druid", branch = "psst", features = "image", "jpeg", "png", + "webp", "serde", ] } druid-enums = { git = "https://github.com/jpochyla/druid-enums" } diff --git a/psst-gui/src/webapi/client.rs b/psst-gui/src/webapi/client.rs index 6fcd0888..6064ad1e 100644 --- a/psst-gui/src/webapi/client.rs +++ b/psst-gui/src/webapi/client.rs @@ -1479,6 +1479,7 @@ impl WebApi { let format = match infer::get(body.as_slice()) { Some(kind) if kind.mime_type() == "image/jpeg" => Some(ImageFormat::Jpeg), Some(kind) if kind.mime_type() == "image/png" => Some(ImageFormat::Png), + Some(kind) if kind.mime_type() == "image/webp" => Some(ImageFormat::WebP), _ => None, }; From 8ed14f65f54bceb2147c90b0086194d9277e9cf5 Mon Sep 17 00:00:00 2001 From: Cleboost Date: Sun, 29 Jun 2025 20:05:45 +0200 Subject: [PATCH 3/4] Remove vertical alignment from playlist image Deleted the call to .align_vertical(UnitPoint::CENTER) for the playlist image in the playlist_widget function. This changes the alignment behavior of the image in the UI. --- psst-gui/src/ui/playlist.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/psst-gui/src/ui/playlist.rs b/psst-gui/src/ui/playlist.rs index 690a54ec..824e55ec 100644 --- a/psst-gui/src/ui/playlist.rs +++ b/psst-gui/src/ui/playlist.rs @@ -338,7 +338,6 @@ pub fn playlist_widget(horizontal: bool) -> impl Widget> { .fix_width(playlist_image_size) .align_left() ) - .align_vertical(UnitPoint::CENTER) ).boxed() } else { // Mode sidebar : comportement simple From 5dbb961cfa6efe5709a000415fe6d43cd90fe078 Mon Sep 17 00:00:00 2001 From: Cleboost Date: Sun, 29 Jun 2025 20:09:09 +0200 Subject: [PATCH 4/4] Remove French comments from playlist_widget Removed French-language comments from the playlist_widget function that were used during development, in order to improve code clarity and maintain consistency in documentation. --- psst-gui/src/ui/playlist.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/psst-gui/src/ui/playlist.rs b/psst-gui/src/ui/playlist.rs index 824e55ec..7ba5af8c 100644 --- a/psst-gui/src/ui/playlist.rs +++ b/psst-gui/src/ui/playlist.rs @@ -313,7 +313,6 @@ pub fn playlist_widget(horizontal: bool) -> impl Widget> { .lens(Ctx::data().then(Playlist::name)); let text_content = if horizontal { - // Mode horizontal : permet les retours à la ligne let name_widget = playlist_name.fix_width(playlist_image_size).align_left(); let description_widget = Label::raw() .with_line_break_mode(LineBreaking::WordWrap) @@ -340,7 +339,6 @@ pub fn playlist_widget(horizontal: bool) -> impl Widget> { ) ).boxed() } else { - // Mode sidebar : comportement simple let name_widget = playlist_name.align_left(); let description_widget = Label::raw() .with_text_color(theme::PLACEHOLDER_COLOR)