show pulsing buffering bar after 3 seconds

This commit is contained in:
Erica Z 2024-11-05 11:33:59 +01:00
parent 88962c629c
commit 38b3902f69
3 changed files with 190 additions and 146 deletions

View file

@ -2,174 +2,186 @@ using Gtk 4.0;
using Adw 1; using Adw 1;
template $AudreyUiPlaybar: Adw.Bin { template $AudreyUiPlaybar: Adw.Bin {
child: CenterBox { child: Overlay {
hexpand: true; [overlay]
ProgressBar pulse_bar {
styles [
"osd"
]
visible: bind template.show-pulse-bar;
valign: start;
}
styles [ child: CenterBox {
"toolbar", hexpand: true;
]
[start] styles [
Box { "toolbar",
AspectFrame { ]
visible: false; // FIXME annoying annoying annoying annoying
// visible: bind template.show_cover_art;
vexpand: true;
ratio: 1.0;
obey-child: false;
child: Picture { [start]
content-fit: scale_down; Box {
paintable: bind template.playing_cover_art; AspectFrame {
}; visible: false; // FIXME annoying annoying annoying annoying
// visible: bind template.show_cover_art;
vexpand: true;
ratio: 1.0;
obey-child: false;
child: Picture {
content-fit: scale_down;
paintable: bind template.playing_cover_art;
};
}
Box {
margin-start: 6;
orientation: vertical;
valign: center;
Label {
styles [
"heading"
]
xalign: 0;
halign: start;
label: bind template.song as <$AudreyPlaybinSong>.title;
ellipsize: end;
}
Label {
styles [
"caption"
]
xalign: 0;
label: bind template.song as <$AudreyPlaybinSong>.artist;
ellipsize: end;
}
Label {
styles [
"caption"
]
xalign: 0;
label: bind template.song as <$AudreyPlaybinSong>.album;
ellipsize: end;
}
}
} }
[center]
Box { Box {
margin-start: 6;
orientation: vertical; orientation: vertical;
valign: center; valign: center;
Label { CenterBox {
styles [ [start]
"heading" Label play_position_label {
] styles [
"caption",
"numeric",
]
xalign: 0; label: bind $format_timestamp(template.position) as <string>;
halign: start; }
label: bind template.song as <$AudreyPlaybinSong>.title;
ellipsize: end; [center]
Scale play_position {
name: "seek-scale";
orientation: horizontal;
width-request: 400;
sensitive: bind template.idle-active inverted;
adjustment: Adjustment {
lower: 0;
value: bind template.position;
upper: bind template.duration;
};
change-value => $on_play_position_seek() swapped;
}
[end]
Label play_duration {
styles [
"caption",
"numeric",
]
label: bind $format_timestamp(template.duration) as <string>;
}
} }
Label { Box {
styles [ halign: center;
"caption" orientation: horizontal;
]
xalign: 0; Button {
label: bind template.song as <$AudreyPlaybinSong>.artist; icon-name: "media-skip-backward";
ellipsize: end; valign: center;
} sensitive: bind template.idle-active inverted;
clicked => $on_skip_backward_clicked() swapped;
}
Label { Button {
styles [ icon-name: "media-seek-backward";
"caption" valign: center;
] sensitive: bind template.idle-active inverted;
clicked => $seek_backward() swapped;
}
xalign: 0; Button {
label: bind template.song as <$AudreyPlaybinSong>.album; icon-name: bind $play_pause_icon_name(template.idle-active, template.pause) as <string>;
ellipsize: end; valign: center;
sensitive: bind $play_pause_sensitive(template.playlist-count) as <bool>;
clicked => $on_play_pause_clicked() swapped;
}
Button {
icon-name: "media-seek-forward";
valign: center;
sensitive: bind template.idle-active inverted;
clicked => $seek_forward() swapped;
}
Button {
icon-name: "media-skip-forward";
valign: center;
sensitive: bind template.idle-active inverted;
clicked => $on_skip_forward_clicked() swapped;
}
} }
} }
}
[center] [end]
Box { Box {
orientation: vertical; Button {
valign: center; icon-name: "non-starred";
valign: center;
CenterBox { sensitive: bind template.idle-active inverted;
[start]
Label play_position_label {
styles [
"caption",
"numeric",
]
label: bind $format_timestamp(template.position) as <string>;
} }
[center] Button {
Scale play_position { icon-name: bind $mute_button_icon_name(template.mute) as <string>;
name: "seek-scale"; valign: center;
clicked => $on_mute_toggle() swapped;
}
Scale {
name: "volume-scale";
orientation: horizontal; orientation: horizontal;
width-request: 400; width-request: 130;
sensitive: bind template.idle-active inverted;
adjustment: Adjustment { adjustment: Adjustment {
lower: 0; lower: 0;
value: bind template.position; value: bind template.volume bidirectional;
upper: bind template.duration; upper: 100;
}; };
change-value => $on_play_position_seek() swapped;
}
[end]
Label play_duration {
styles [
"caption",
"numeric",
]
label: bind $format_timestamp(template.duration) as <string>;
} }
} }
};
Box {
halign: center;
orientation: horizontal;
Button {
icon-name: "media-skip-backward";
valign: center;
sensitive: bind template.idle-active inverted;
clicked => $on_skip_backward_clicked() swapped;
}
Button {
icon-name: "media-seek-backward";
valign: center;
sensitive: bind template.idle-active inverted;
clicked => $seek_backward() swapped;
}
Button {
icon-name: bind $play_pause_icon_name(template.idle-active, template.pause) as <string>;
valign: center;
sensitive: bind $play_pause_sensitive(template.playlist-count) as <bool>;
clicked => $on_play_pause_clicked() swapped;
}
Button {
icon-name: "media-seek-forward";
valign: center;
sensitive: bind template.idle-active inverted;
clicked => $seek_forward() swapped;
}
Button {
icon-name: "media-skip-forward";
valign: center;
sensitive: bind template.idle-active inverted;
clicked => $on_skip_forward_clicked() swapped;
}
}
}
[end]
Box {
Button {
icon-name: "non-starred";
valign: center;
sensitive: bind template.idle-active inverted;
}
Button {
icon-name: bind $mute_button_icon_name(template.mute) as <string>;
valign: center;
clicked => $on_mute_toggle() swapped;
}
Scale {
name: "volume-scale";
orientation: horizontal;
width-request: 130;
adjustment: Adjustment {
lower: 0;
value: bind template.volume bidirectional;
upper: 100;
};
}
}
}; };
} }

View file

@ -11,6 +11,10 @@ mod imp {
#[properties(wrapper_type = super::Playbar)] #[properties(wrapper_type = super::Playbar)]
#[template(resource = "/eu/callcc/audrey/playbar.ui")] #[template(resource = "/eu/callcc/audrey/playbar.ui")]
pub struct Playbar { pub struct Playbar {
#[template_child]
#[property(get)]
pulse_bar: TemplateChild<gtk::ProgressBar>,
#[property(get, set)] #[property(get, set)]
song: RefCell<Option<PlaybinSong>>, song: RefCell<Option<PlaybinSong>>,
#[property(get, set)] #[property(get, set)]
@ -34,6 +38,9 @@ mod imp {
position: Cell<f64>, position: Cell<f64>,
#[property(get, set)] #[property(get, set)]
duration: Cell<f64>, duration: Cell<f64>,
#[property(get, set)]
_show_pulse_bar: Cell<bool>,
} }
#[glib::object_subclass] #[glib::object_subclass]

View file

@ -54,6 +54,8 @@ mod imp {
#[property(type = u32, get = Self::playlist_count)] #[property(type = u32, get = Self::playlist_count)]
_playlist_count: (), _playlist_count: (),
tick_callback: Cell<Option<gtk::TickCallbackId>>,
pub(super) queued_seek: Cell<Option<f64>>, pub(super) queued_seek: Cell<Option<f64>>,
pub(crate) initial_setup_handle: RefCell<Option<JoinHandle<()>>>, pub(crate) initial_setup_handle: RefCell<Option<JoinHandle<()>>>,
@ -103,7 +105,9 @@ mod imp {
_idle_active: (), _idle_active: (),
_playlist_count: (), _playlist_count: (),
queued_seek: Cell::new(None), tick_callback: Default::default(),
queued_seek: Default::default(),
initial_setup_handle: Default::default(), initial_setup_handle: Default::default(),
mpv_event_loop_handle: Default::default(), mpv_event_loop_handle: Default::default(),
@ -202,7 +206,9 @@ mod imp {
}, },
Event::StartFile(_) => { Event::StartFile(_) => {
event!(Level::INFO, "start file event");
window.notify("song"); window.notify("song");
window.imp().buffering_start();
// TODO: load cover art // TODO: load cover art
} }
@ -258,12 +264,12 @@ mod imp {
Event::Seek => { Event::Seek => {
event!(Level::INFO, "seek event"); event!(Level::INFO, "seek event");
// TODO: if doing "buffering" progress bar, show it after a timeout here window.imp().buffering_start();
} }
Event::PlaybackRestart => { Event::PlaybackRestart => {
event!(Level::INFO, "playback restart event"); event!(Level::INFO, "playback restart event");
// TODO: if doing "buffering" progress bar, hide it here window.imp().buffering_end();
if let Some(queued_seek) = window.imp().queued_seek.take() { if let Some(queued_seek) = window.imp().queued_seek.take() {
// a seek was tried before and failed, try again now // a seek was tried before and failed, try again now
@ -478,6 +484,25 @@ mod imp {
Some(song) Some(song)
} }
} }
fn buffering_start(&self) {
let started_buffering = std::time::Instant::now();
self.tick_callback
.replace(Some(self.obj().add_tick_callback(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
})))
.map(gtk::TickCallbackId::remove);
}
fn buffering_end(&self) {
self.tick_callback.take().map(gtk::TickCallbackId::remove);
self.playbar.set_show_pulse_bar(false);
}
} }
impl Drop for Window { impl Drop for Window {