show pulsing buffering bar after 3 seconds
This commit is contained in:
parent
88962c629c
commit
38b3902f69
3 changed files with 190 additions and 146 deletions
|
@ -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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue