abstract buffering pulse thing

This commit is contained in:
Erica Z 2024-11-24 19:01:40 +01:00
parent f8a6e09866
commit 455bf60433
4 changed files with 72 additions and 37 deletions

View file

@ -17,6 +17,8 @@ use gtk::{gio, glib};
pub mod mpv; pub mod mpv;
pub mod util;
fn init_tracing() { fn init_tracing() {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {

View file

@ -1,11 +1,12 @@
use crate::model::Song; use crate::model::Song;
use crate::util::buffering::BufferingPulseController;
use crate::{mpris, mpv}; use crate::{mpris, mpv};
use adw::prelude::*; use adw::prelude::*;
use adw::subclass::prelude::*; use adw::subclass::prelude::*;
use glib::subclass::InitializingObject; use glib::subclass::InitializingObject;
use glib::JoinHandle; use glib::JoinHandle;
use gtk::{gdk, gio, glib}; use gtk::{gdk, gio, glib};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, OnceCell, RefCell};
use std::rc::Rc; use std::rc::Rc;
use tracing::{event, span, Level}; use tracing::{event, span, Level};
use zbus::object_server::InterfaceRef; use zbus::object_server::InterfaceRef;
@ -78,7 +79,8 @@ mod imp {
loading_cover_handle: RefCell<Option<JoinHandle<()>>>, loading_cover_handle: RefCell<Option<JoinHandle<()>>>,
buffering_timeout: Cell<Option<glib::SourceId>>, playbar_buffering: OnceCell<BufferingPulseController>,
time_pos_notify_timeout: Cell<Option<glib::SourceId>>, time_pos_notify_timeout: Cell<Option<glib::SourceId>>,
mpris_player: RefCell<Option<InterfaceRef<mpris::Player>>>, mpris_player: RefCell<Option<InterfaceRef<mpris::Player>>>,
@ -140,7 +142,8 @@ mod imp {
loading_cover_handle: Default::default(), loading_cover_handle: Default::default(),
buffering_timeout: Default::default(), playbar_buffering: Default::default(),
time_pos_notify_timeout: Default::default(), time_pos_notify_timeout: Default::default(),
mpris_player: Default::default(), mpris_player: Default::default(),
@ -539,33 +542,9 @@ mod imp {
) )
} }
fn buffering_start(&self) { fn playbar_buffering(&self) -> &BufferingPulseController {
let started_buffering = std::time::Instant::now(); self.playbar_buffering
let window = self.obj().downgrade(); .get_or_init(|| BufferingPulseController::new(&self.playbar.pulse_bar()))
if let Some(source) = self.buffering_timeout.replace(Some(glib::timeout_add_local(
std::time::Duration::from_millis(100),
move || {
window
.upgrade()
.map_or(glib::ControlFlow::Break, move |window| {
// 3 second period from gnome hig
if started_buffering.elapsed() > std::time::Duration::from_secs(3) {
window.imp().playbar.set_show_pulse_bar(true);
window.imp().playbar.pulse_bar().pulse();
}
glib::ControlFlow::Continue
})
},
))) {
source.remove()
}
}
fn buffering_end(&self) {
if let Some(source) = self.buffering_timeout.take() {
source.remove();
}
self.playbar.set_show_pulse_bar(false);
} }
fn on_property_change(&self, event: crate::mpv::event::PropertyEvent) { fn on_property_change(&self, event: crate::mpv::event::PropertyEvent) {
@ -734,7 +713,7 @@ mod imp {
event!(target: "audrey::playback", Level::DEBUG, "StartFile"); event!(target: "audrey::playback", Level::DEBUG, "StartFile");
self.obj().notify("song"); self.obj().notify("song");
self.buffering_start(); self.playbar_buffering().start();
let song = self.obj().song().unwrap(); let song = self.obj().song().unwrap();
@ -879,7 +858,7 @@ mod imp {
self.state.set(State::Seeking); self.state.set(State::Seeking);
self.obj().notify("time-pos"); self.obj().notify("time-pos");
self.buffering_start(); self.playbar_buffering().stop();
let time_pos = self.obj().time_pos(); let time_pos = self.obj().time_pos();
if let Some(iface_ref) = self.mpris_player() { if let Some(iface_ref) = self.mpris_player() {
@ -910,7 +889,7 @@ mod imp {
self.state.set(State::Active); self.state.set(State::Active);
event!(target: "audrey::playback", Level::DEBUG, "PlaybackRestart"); event!(target: "audrey::playback", Level::DEBUG, "PlaybackRestart");
self.buffering_end(); self.playbar_buffering().stop();
if let Some(queued_seek) = self.queued_seek.take() { if let Some(queued_seek) = self.queued_seek.take() {
// a seek was tried before and failed, try again now // a seek was tried before and failed, try again now
@ -943,7 +922,7 @@ mod imp {
self.obj().notify("time-pos"); self.obj().notify("time-pos");
self.obj().notify("song"); self.obj().notify("song");
self.buffering_end(); self.playbar_buffering().stop();
if let Err(err) = event.reason { if let Err(err) = event.reason {
event!(Level::ERROR, "end file error: {err}"); event!(Level::ERROR, "end file error: {err}");
@ -964,9 +943,6 @@ mod imp {
if let Some(source) = self.time_pos_notify_timeout.take() { if let Some(source) = self.time_pos_notify_timeout.take() {
source.remove(); source.remove();
} }
if let Some(source) = self.buffering_timeout.take() {
source.remove();
}
} }
} }
} }

1
src/util.rs Normal file
View file

@ -0,0 +1 @@
pub mod buffering;

56
src/util/buffering.rs Normal file
View file

@ -0,0 +1,56 @@
use adw::{glib, prelude::*};
use std::cell::Cell;
use std::time::Duration;
// gnome HIG: "Progress needs to be indicated whenever an operation takes more than around three
// seconds."
const PULSE_DELAY: Duration = Duration::from_secs(3);
const PULSE_PERIOD: Duration = Duration::from_millis(100);
pub struct BufferingPulseController {
progress_bar: gtk::ProgressBar,
handle: Cell<Option<glib::JoinHandle<()>>>,
}
impl BufferingPulseController {
pub fn new(progress_bar: &gtk::ProgressBar) -> Self {
Self {
progress_bar: progress_bar.clone(),
handle: Cell::new(None),
}
}
pub fn start(&self) {
let progress_bar = self.progress_bar.clone();
let prev_handle = self
.handle
.replace(Some(glib::spawn_future_local(async move {
glib::timeout_future(PULSE_DELAY).await;
progress_bar.set_visible(true);
loop {
progress_bar.pulse();
glib::timeout_future(PULSE_PERIOD).await;
}
})));
if let Some(handle) = prev_handle {
handle.abort();
}
}
pub fn stop(&self) {
if let Some(handle) = self.handle.take() {
handle.abort();
}
self.progress_bar.set_visible(false);
}
}
impl Drop for BufferingPulseController {
fn drop(&mut self) {
if let Some(handle) = self.handle.take() {
handle.abort();
}
}
}