Skip to content

Commit

Permalink
gui: MediaKeys, simpler layout, performance fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jpochyla committed Apr 6, 2021
1 parent 2511ed8 commit 73ab385
Show file tree
Hide file tree
Showing 21 changed files with 376 additions and 190 deletions.
105 changes: 105 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions psst-core/src/audio_player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ impl Player {
PlayerCommand::Preload { item } => self.preload(item),
PlayerCommand::Pause => self.pause(),
PlayerCommand::Resume => self.resume(),
PlayerCommand::PauseOrResume => self.pause_or_resume(),
PlayerCommand::Previous => self.previous(),
PlayerCommand::Next => self.next(),
PlayerCommand::Stop => self.stop(),
Expand Down Expand Up @@ -464,6 +465,16 @@ impl Player {
}
}

fn pause_or_resume(&mut self) {
match &self.state {
PlayerState::Playing { .. } => self.pause(),
PlayerState::Paused { .. } => self.resume(),
_ => {
// Do nothing.
}
}
}

fn previous(&mut self) {
if self.is_near_playback_start() {
self.queue.skip_to_previous();
Expand Down Expand Up @@ -537,6 +548,7 @@ pub enum PlayerCommand {
},
Pause,
Resume,
PauseOrResume,
Previous,
Next,
Stop,
Expand Down
1 change: 1 addition & 0 deletions psst-gui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ platform-dirs = "0.3"
rand = "0.8"
serde = { version = "1.0", features = ["derive", "rc"] }
serde_json = "1.0"
souvlaki = { git = "https://github.com/jpochyla/souvlaki", branch = "macos" }
ureq = { version = "2.1", features = ["json"] }
3 changes: 2 additions & 1 deletion psst-gui/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ pub const UPDATE_SEARCH_RESULTS: Selector<Result<SearchResults, Error>> =

// Library

pub const LOAD_LIBRARY: Selector = Selector::new("app.load-library");
pub const LOAD_SAVED_TRACKS: Selector = Selector::new("app.load-saved-tracks");
pub const LOAD_SAVED_ALBUMS: Selector = Selector::new("app.load-saved-albums");
pub const LOAD_PLAYLISTS: Selector = Selector::new("app.load-playlists");
pub const UPDATE_SAVED_ALBUMS: Selector<Result<Vector<Album>, Error>> =
Selector::new("app.update-saved-albums");
Expand Down
9 changes: 6 additions & 3 deletions psst-gui/src/controller/nav.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ impl NavController {
fn load_route_data(&self, ctx: &mut EventCtx, data: &mut State) {
match &data.route {
Nav::Home => {}
Nav::SavedTracks => {
ctx.submit_command(cmd::LOAD_SAVED_TRACKS);
}
Nav::SavedAlbums => {
ctx.submit_command(cmd::LOAD_SAVED_ALBUMS);
}
Nav::SearchResults(query) => {
ctx.submit_command(cmd::LOAD_SEARCH_RESULTS.with(query.to_owned()));
}
Expand All @@ -23,9 +29,6 @@ impl NavController {
Nav::PlaylistDetail(link) => {
ctx.submit_command(cmd::LOAD_PLAYLIST_DETAIL.with(link.to_owned()));
}
Nav::Library => {
ctx.submit_command(cmd::LOAD_LIBRARY);
}
}
}
}
Expand Down
57 changes: 54 additions & 3 deletions psst-gui/src/controller/playback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,22 @@ use psst_core::{
session::SessionHandle,
};

#[cfg(target_os = "macos")]
use souvlaki::platform::macos::MediaControlsExtMacOs;
use souvlaki::{MediaControlEvent, MediaControls, MediaMetadata, MediaPlayback};

use crate::{
cmd,
data::{Config, PlaybackOrigin, QueueBehavior, QueuedTrack, State, TrackId},
data::{
Config, Playback, PlaybackOrigin, PlaybackState, QueueBehavior, QueuedTrack, State, TrackId,
},
};

pub struct PlaybackController {
sender: Option<Sender<PlayerEvent>>,
thread: Option<JoinHandle<()>>,
output_thread: Option<JoinHandle<()>>,
media_controls: Option<MediaControls>,
}

impl PlaybackController {
Expand All @@ -35,6 +42,7 @@ impl PlaybackController {
sender: None,
thread: None,
output_thread: None,
media_controls: None,
}
}

Expand Down Expand Up @@ -67,9 +75,18 @@ impl PlaybackController {
output.start_playback(source).expect("Playback failed");
});

let mut media_controls = MediaControls::create().unwrap();
media_controls.attach({
let sender = sender.clone();
move |event| {
Self::handle_media_control_event(event, &sender);
}
});

self.sender.replace(sender);
self.thread.replace(thread);
self.output_thread.replace(output_thread);
self.media_controls.replace(media_controls);
}

fn service_events(mut player: Player, event_sink: ExtEventSink, widget_id: WidgetId) {
Expand Down Expand Up @@ -123,6 +140,35 @@ impl PlaybackController {
}
}

fn handle_media_control_event(event: MediaControlEvent, sender: &Sender<PlayerEvent>) {
let cmd = match event {
MediaControlEvent::Play => PlayerEvent::Command(PlayerCommand::Resume),
MediaControlEvent::Pause => PlayerEvent::Command(PlayerCommand::Pause),
MediaControlEvent::Toggle => PlayerEvent::Command(PlayerCommand::PauseOrResume),
MediaControlEvent::Next => PlayerEvent::Command(PlayerCommand::Next),
MediaControlEvent::Previous => PlayerEvent::Command(PlayerCommand::Previous),
};
sender.send(cmd).unwrap();
}

fn update_media_controls(&mut self, playback: &Playback) {
if let Some(media_controls) = self.media_controls.as_mut() {
media_controls.set_playback(match playback.state {
PlaybackState::Loading | PlaybackState::Stopped => MediaPlayback::Stopped,
PlaybackState::Playing => MediaPlayback::Playing,
PlaybackState::Paused => MediaPlayback::Paused,
});
let title = playback.now_playing.as_ref().map(|c| c.item.name.clone());
let album = playback.now_playing.as_ref().map(|c| c.item.album_name());
let artist = playback.now_playing.as_ref().map(|c| c.item.artist_name());
media_controls.set_metadata(MediaMetadata {
title: title.as_deref(),
album: album.as_deref(),
artist: artist.as_deref(),
});
}
}

fn send(&mut self, event: PlayerEvent) {
self.sender.as_mut().unwrap().send(event).unwrap();
}
Expand Down Expand Up @@ -198,6 +244,7 @@ where

if let Some(queued) = data.queued_track(item) {
data.loading_playback(queued.track, queued.origin);
self.update_media_controls(&data.playback);
} else {
log::warn!("loaded item not found in playback queue");
}
Expand All @@ -209,6 +256,7 @@ where

if let Some(queued) = data.queued_track(item) {
data.start_playback(queued.track, queued.origin, progress.to_owned());
self.update_media_controls(&data.playback);
} else {
log::warn!("played item not found in playback queue");
}
Expand All @@ -221,10 +269,12 @@ where
}
Event::Command(cmd) if cmd.is(cmd::PLAYBACK_PAUSING) => {
data.pause_playback();
self.update_media_controls(&data.playback);
ctx.set_handled();
}
Event::Command(cmd) if cmd.is(cmd::PLAYBACK_RESUMING) => {
data.resume_playback();
self.update_media_controls(&data.playback);
ctx.set_handled();
}
Event::Command(cmd) if cmd.is(cmd::PLAYBACK_BLOCKED) => {
Expand All @@ -233,11 +283,12 @@ where
}
Event::Command(cmd) if cmd.is(cmd::PLAYBACK_STOPPED) => {
data.stop_playback();
self.update_media_controls(&data.playback);
ctx.set_handled();
}
Event::Command(cmd) if cmd.is(cmd::UPDATE_AUDIO_ANALYSIS) => {
let (track_id, result) = cmd.get_unchecked(cmd::UPDATE_AUDIO_ANALYSIS);
data.playback.current.as_mut().map(|current| {
data.playback.now_playing.as_mut().map(|current| {
if current.analysis.is_deferred(track_id) {
current.analysis.resolve_or_reject(result.to_owned());
}
Expand Down Expand Up @@ -286,7 +337,7 @@ where
}
Event::Command(cmd) if cmd.is(cmd::PLAY_SEEK) => {
let fraction = cmd.get_unchecked(cmd::PLAY_SEEK);
data.playback.current.as_ref().map(|current| {
data.playback.now_playing.as_ref().map(|current| {
let position =
Duration::from_secs_f64(current.item.duration.as_secs_f64() * fraction);
self.seek(position);
Expand Down
Loading

0 comments on commit 73ab385

Please sign in to comment.