feat: add star indicator for bookmarking

This commit is contained in:
talwat 2025-04-23 14:14:49 +02:00
parent a89854e46f
commit 7cdd2e7694
2 changed files with 30 additions and 5 deletions

View File

@ -2,7 +2,14 @@
//! This also has the code for the underlying //! This also has the code for the underlying
//! audio server which adds new tracks. //! audio server which adds new tracks.
use std::{collections::VecDeque, sync::Arc, time::Duration}; use std::{
collections::VecDeque,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::Duration,
};
use arc_swap::ArcSwapOption; use arc_swap::ArcSwapOption;
use downloader::Downloader; use downloader::Downloader;
@ -48,6 +55,9 @@ pub struct Player {
/// [rodio]'s [`Sink`] which can control playback. /// [rodio]'s [`Sink`] which can control playback.
pub sink: Sink, pub sink: Sink,
/// Whether the current track has been bookmarked.
bookmarked: AtomicBool,
/// The [`TrackInfo`] of the current track. /// The [`TrackInfo`] of the current track.
/// This is [`None`] when lowfi is buffering/loading. /// This is [`None`] when lowfi is buffering/loading.
current: ArcSwapOption<tracks::Info>, current: ArcSwapOption<tracks::Info>,
@ -174,6 +184,7 @@ impl Player {
volume, volume,
list, list,
_handle: handle, _handle: handle,
bookmarked: AtomicBool::new(false),
}; };
Ok((player, SendableOutputStream(stream))) Ok((player, SendableOutputStream(stream)))
@ -383,6 +394,11 @@ impl Player {
continue; continue;
} }
Messages::Bookmark => { Messages::Bookmark => {
if player.bookmarked.load(Ordering::Relaxed) {
continue;
}
player.bookmarked.swap(true, Ordering::Relaxed);
let current = player.current.load(); let current = player.current.load();
let current = current.as_ref().unwrap(); let current = current.as_ref().unwrap();

View File

@ -1,7 +1,11 @@
//! Various different individual components that //! Various different individual components that
//! appear in lowfi's UI, like the progress bar. //! appear in lowfi's UI, like the progress bar.
use std::{ops::Deref as _, sync::Arc, time::Duration}; use std::{
ops::Deref as _,
sync::{atomic::Ordering, Arc},
time::Duration,
};
use crossterm::style::Stylize as _; use crossterm::style::Stylize as _;
use unicode_segmentation::UnicodeSegmentation as _; use unicode_segmentation::UnicodeSegmentation as _;
@ -72,7 +76,7 @@ enum ActionBar {
impl ActionBar { impl ActionBar {
/// Formats the action bar to be displayed. /// Formats the action bar to be displayed.
/// The second value is the character length of the result. /// The second value is the character length of the result.
fn format(&self) -> (String, usize) { fn format(&self, star: bool) -> (String, usize) {
let (word, subject) = match self { let (word, subject) = match self {
Self::Playing(x) => ("playing", Some((x.display_name.clone(), x.width))), Self::Playing(x) => ("playing", Some((x.display_name.clone(), x.width))),
Self::Paused(x) => ("paused", Some((x.display_name.clone(), x.width))), Self::Paused(x) => ("paused", Some((x.display_name.clone(), x.width))),
@ -81,7 +85,12 @@ impl ActionBar {
subject.map_or_else( subject.map_or_else(
|| (word.to_owned(), word.len()), || (word.to_owned(), word.len()),
|(subject, len)| (format!("{} {}", word, subject.bold()), word.len() + 1 + len), |(subject, len)| {
(
format!("{} {}{}", word, if star { "*" } else { "" }, subject.bold()),
word.len() + 1 + len + if star { 1 } else { 0 },
)
},
) )
} }
} }
@ -99,7 +108,7 @@ pub fn action(player: &Player, current: Option<&Arc<Info>>, width: usize) -> Str
ActionBar::Playing(info) ActionBar::Playing(info)
} }
}) })
.format(); .format(player.bookmarked.load(Ordering::Relaxed));
if len > width { if len > width {
let chopped: String = main.graphemes(true).take(width + 1).collect(); let chopped: String = main.graphemes(true).take(width + 1).collect();