diff --git a/src/play_queue.vala b/src/play_queue.vala index 63953ea..bdb4733 100644 --- a/src/play_queue.vala +++ b/src/play_queue.vala @@ -25,9 +25,10 @@ public class Wavelet.PlayQueue : Adw.NavigationPage { // this is the index of the song that will play on next on_stream_start private uint next_stream_index; - public signal void play_now (Song song); - public signal void now_playing (Song song); public signal void play_next (Song? song); + public signal void play_now (Song song); + + public signal void now_playing (Song song); construct { this.songs = new ListStore (typeof (Song)); @@ -69,4 +70,20 @@ public class Wavelet.PlayQueue : Adw.NavigationPage { this.play_next (song); this.play_now (song); } + + public void skip_forward () { + Song song = (Song) this.songs.get_item (this.next_stream_index); + this.play_now (song); + } + + public void skip_backward () { + if (this.next_stream_index <= 1) { + this.next_stream_index = 0; + } else { + this.next_stream_index -= 2; + } + Song song = (Song) this.songs.get_item (this.next_stream_index); + this.play_next (song); + this.play_now (song); + } } diff --git a/src/playbin.vala b/src/playbin.vala index 2d4ac46..f21d5fc 100644 --- a/src/playbin.vala +++ b/src/playbin.vala @@ -86,8 +86,16 @@ class Playbin : Object { assert (this.playbin.query_duration (Gst.Format.TIME, out new_duration)); this.duration = new_duration; + string? next_uri = null; + this.next_uri_lock.lock (); + if (this.next_uri != this.next_uri_locked_in) { + // WHOOPS! didn't actually switch to the track the play queue wanted + // FIXME as it arises + assert (false); + } this.next_uri = null; + this.next_uri_locked_in = null; this.next_uri_lock.unlock (); this.stream_started (); @@ -164,6 +172,11 @@ class Playbin : Object { this.play_now_queued = null; } + // pretend this track was locked in by about-to-finish before + this.next_uri_lock.lock (); + this.next_uri_locked_in = uri; + this.next_uri_lock.unlock (); + yield this.set_state (Gst.State.READY); this.playbin.uri = uri; yield this.set_state (Gst.State.PLAYING); @@ -179,6 +192,7 @@ class Playbin : Object { Mutex next_uri_lock; string? next_uri; + string? next_uri_locked_in; public void set_next_uri (string? next_uri) { this.next_uri_lock.lock (); @@ -191,10 +205,19 @@ class Playbin : Object { private void on_about_to_finish (dynamic Gst.Element playbin) { this.next_uri_lock.lock (); string? next_uri = this.next_uri; + this.next_uri_locked_in = next_uri; this.next_uri_lock.unlock (); if (next_uri != null) { playbin.uri = next_uri; } } + + public void pause () { + this.playbin.set_state (Gst.State.PAUSED); + } + + public void play () { + this.playbin.set_state (Gst.State.PLAYING); + } } diff --git a/src/window.blp b/src/window.blp index a4c2197..033c544 100644 --- a/src/window.blp +++ b/src/window.blp @@ -177,10 +177,12 @@ template $WaveletWindow: Adw.ApplicationWindow { Button { icon-name: "media-skip-backward"; valign: center; + + clicked => $on_skip_backward_clicked (); } Button { - icon-name: "media-playback-start"; + icon-name: bind $play_button_icon_name (template.playing) as ; valign: center; clicked => $on_play_pause_clicked (); @@ -189,6 +191,8 @@ template $WaveletWindow: Adw.ApplicationWindow { Button { icon-name: "media-skip-forward"; valign: center; + + clicked => $on_skip_forward_clicked (); } Button { diff --git a/src/window.vala b/src/window.vala index 6057cd2..2ecf56c 100644 --- a/src/window.vala +++ b/src/window.vala @@ -30,6 +30,8 @@ public class Wavelet.Window : Adw.ApplicationWindow { [GtkChild] public unowned Adw.ButtonRow shuffle_all_tracks; [GtkChild] public unowned Gtk.Button mute; + + public bool playing { get; private set; default = false; } [GtkChild] private unowned Gtk.Scale play_position; public int64 position { get; private set; } @@ -74,6 +76,7 @@ public class Wavelet.Window : Adw.ApplicationWindow { playbin.stream_started.connect (this.play_queue.on_stream_start); this.play_queue.now_playing.connect ((song) => { + this.playing = true; this.song = song; }); @@ -148,9 +151,6 @@ public class Wavelet.Window : Adw.ApplicationWindow { return "%02d:%02d".printf (s/60, s%60); } - [GtkCallback] private void on_play_pause_clicked () { - } - // same timeout logic as https://code.videolan.org/videolan/npapi-vlc/blob/6eae0ffb9cbaf8f6e04423de2ff38daabdf7cae3/npapi/vlcplugin_gtk.cpp#L312 private uint seek_timeout_id = 0; [GtkCallback] private bool on_play_position_seek (Gtk.Range range, Gtk.ScrollType scroll_type, double value) { @@ -164,4 +164,26 @@ public class Wavelet.Window : Adw.ApplicationWindow { } return false; } + + [GtkCallback] private void on_play_pause_clicked () { + if (this.playing) { + this.playbin.pause(); + this.playing = false; + } else { + this.playbin.play(); + this.playing = true; + } + } + + [GtkCallback] private string play_button_icon_name (bool playing) { + return playing ? "media-playback-pause" : "media-playback-start"; + } + + [GtkCallback] private void on_skip_forward_clicked () { + this.play_queue.skip_forward (); + } + + [GtkCallback] private void on_skip_backward_clicked () { + this.play_queue.skip_backward (); + } }