diff --git a/src/playbin.vala b/src/playbin.vala index 1dec26b..48a265b 100644 --- a/src/playbin.vala +++ b/src/playbin.vala @@ -1,10 +1,10 @@ -enum PlaybinState { +public enum PlaybinState { STOPPED, PAUSED, PLAYING, } -class Playbin : GLib.Object { +public class Playbin : GLib.Object { private Mpv.Handle mpv = new Mpv.Handle (); public PlaybinState state { get; private set; default = PlaybinState.STOPPED; } @@ -45,15 +45,7 @@ class Playbin : GLib.Object { public Subsonic.Client api { get; set; default = null; } - private ListModel _play_queue = null; - public ListModel play_queue { - get { return _play_queue; } - set { - assert (_play_queue == null); // only set this once - _play_queue = value; - value.items_changed.connect (on_play_queue_items_changed); - } - } + public ListStore play_queue { get; private set; } private void on_play_queue_items_changed (ListModel play_queue, uint position, uint removed, uint added) { for (uint i = 0; i < removed; i += 1) { @@ -74,6 +66,9 @@ class Playbin : GLib.Object { } public Playbin () { + this.play_queue = new ListStore (typeof (Subsonic.Song)); + this.play_queue.items_changed.connect (this.on_play_queue_items_changed); + assert (this.mpv.initialize () >= 0); assert (this.mpv.set_property_string ("user-agent", Audrey.Const.user_agent) >= 0); assert (this.mpv.set_property_string ("video", "no") >= 0); diff --git a/src/ui/play_queue.blp b/src/ui/play_queue.blp index 862453d..552a47d 100644 --- a/src/ui/play_queue.blp +++ b/src/ui/play_queue.blp @@ -16,7 +16,13 @@ template $UiPlayQueue: Adw.NavigationPage { ScrolledWindow { ListView view { - model: bind template.selection; + single-click-activate: true; + + activate => $on_row_activated (); + + model: NoSelection { + model: bind template.playbin as <$Playbin>.play_queue; + }; factory: SignalListItemFactory { setup => $on_song_list_setup (); diff --git a/src/ui/play_queue.vala b/src/ui/play_queue.vala index 9e06c2c..c841706 100644 --- a/src/ui/play_queue.vala +++ b/src/ui/play_queue.vala @@ -14,25 +14,25 @@ class Ui.PlayQueueSong : Gtk.ListBoxRow { [GtkTemplate (ui = "/eu/callcc/audrey/ui/play_queue.ui")] public class Ui.PlayQueue : Adw.NavigationPage { - public PlayQueueSelection selection { get; default = new PlayQueueSelection (); } - - private GLib.ListStore _store; - public GLib.ListStore store { - get { return _store; } + private Playbin _playbin; + public Playbin playbin { + get { return _playbin; } set { - // can only be set once - assert (_store == null); - _store = value; - _store.items_changed.connect (this.on_store_items_changed); - this.can_clear_all = _store.get_n_items () > 0; - this.selection.model = _store; + assert (_playbin == null); // only set once + _playbin = value; + + _playbin.play_queue.items_changed.connect (this.on_store_items_changed); + this.can_clear_all = _playbin.play_queue.get_n_items () > 0; + + _playbin.notify["play-queue-position"].connect (() => { + }); } } public bool can_clear_all { get; private set; } [GtkCallback] private void on_clear () { - this.store.remove_all (); + this.playbin.play_queue.remove_all (); } private void on_store_items_changed (GLib.ListModel store, uint position, uint removed, uint added) { @@ -41,7 +41,9 @@ public class Ui.PlayQueue : Adw.NavigationPage { [GtkCallback] private void on_song_list_setup (Gtk.SignalListItemFactory factory, Object object) { var item = object as Gtk.ListItem; - item.child = new PlayQueueSong (); + var child = new PlayQueueSong (); + + item.child = child; } [GtkCallback] private void on_song_list_bind (Gtk.SignalListItemFactory factory, Object object) { @@ -51,146 +53,8 @@ public class Ui.PlayQueue : Adw.NavigationPage { child.position = item.position+1; child.song = item.item as Subsonic.Song; } -} -// this is a custom SelectionModel that lets us only signal the -// selection has changed on user interaction -public class PlayQueueSelection : GLib.Object, GLib.ListModel, Gtk.SelectionModel { - private GLib.ListModel _model; - public GLib.ListModel model { - get { return _model; } - set { - // can only be set once - assert (_model == null); - _model = value; - _model.items_changed.connect (this.on_model_items_changed); - } - } - - // if current_position == model.get_n_items (), play queue is stopped - public uint current_position { get; private set; } - - // emitted when a track is purposefully selected - public signal void user_selected (uint position); - - // only called by playbin - // does not emit user_selected - internal void playbin_select (uint new_position) { - var previous_position = this.current_position; - this.current_position = new_position; - - if (previous_position < this.get_n_items ()) { - if (new_position < this.get_n_items ()) { - if (previous_position < new_position) { - this.selection_changed (previous_position, new_position-previous_position+1); - } else { - this.selection_changed (new_position, previous_position-new_position+1); - } - } else { - this.selection_changed (previous_position, 1); - } - } else { - if (new_position < this.get_n_items ()) { - this.selection_changed (new_position, 1); - } - } - } - - // called by anything else that wishes to switch tracks - // emits user_selected - public void user_select (uint position) - requires (position < this.get_n_items ()) - { - this.user_selected (position); - } - - private void on_model_items_changed (GLib.ListModel model, uint position, uint removed, uint added) { - // FIXME: potentially try to see if the current item was reordered - // see what Gtk.SingleSelection does - - bool emit_signal = false; - - if (this.current_position >= position) { - if (this.current_position < position+removed && added == 0) { - if (position < this.get_n_items ()) emit_signal = true; - this.current_position = position; - } else { - this.current_position += added; - this.current_position -= removed; - } - } - - this.items_changed (position, removed, added); - if (emit_signal) this.selection_changed (position, 1); - // user_select doesnt need to be signalled, since the playqueue - // handles this on its own - } - - // Gtk.SelectionModel methods - - Gtk.Bitset get_selection_in_range (uint position, uint n_items) - requires (position+n_items <= this.get_n_items ()) - { - var bitset = new Gtk.Bitset.empty (); - bitset.add (this.current_position); - return bitset; - } - - bool is_selected (uint position) - requires (position < this.get_n_items ()) - { - return position == this.current_position; - } - - bool select_all () { - return false; - } - - bool select_item (uint position, bool unselect_rest) - requires (position < this.get_n_items ()) - { - if (!unselect_rest) { - return false; - } - - this.user_select (position); - - return true; - } - - bool select_range (uint position, uint n_items, bool unselect_rest) { - return false; - } - - bool set_selection (Gtk.Bitset selected, Gtk.Bitset mask) { - return false; - } - - bool unselect_all () { - return false; - } - - bool unselect_item (uint position) { - return false; - } - - bool unselect_range (uint position, uint n_items) { - return false; - } - - // GLib.ListModel methods - - Object? get_item (uint position) { - if (this.model == null) return null; - return this.model.get_item (position); - } - - Type get_item_type () { - return this.model.get_item_type (); - } - - uint get_n_items () { - if (this.model == null) return 0; - return this.model.get_n_items (); + [GtkCallback] private void on_row_activated (uint position) { + playbin.select_track (position); } } diff --git a/src/ui/window.blp b/src/ui/window.blp index fe9ed93..f9f806c 100644 --- a/src/ui/window.blp +++ b/src/ui/window.blp @@ -82,7 +82,7 @@ template $UiWindow: Adw.ApplicationWindow { title: _("Play queue"); child: $UiPlayQueue play_queue { - store: bind template.play_queue_store; + playbin: bind template.playbin; }; } } diff --git a/src/ui/window.vala b/src/ui/window.vala index a45a9d7..8625341 100644 --- a/src/ui/window.vala +++ b/src/ui/window.vala @@ -27,7 +27,6 @@ class Ui.Window : Adw.ApplicationWindow { public Gdk.Paintable playing_cover_art { get; set; } public Playbin playbin { get; private set; default = new Playbin (); } - public ListStore play_queue_store { get; private set; default = new ListStore (typeof (Subsonic.Song)); } public Window (Gtk.Application app) { Object (application: app); @@ -48,8 +47,6 @@ class Ui.Window : Adw.ApplicationWindow { // () => {}, // () => { error ("could not acquire dbus name"); }); - this.playbin.play_queue = this.play_queue_store; - this.setup = new Setup (); this.setup.connected.connect ((api) => { @@ -59,7 +56,6 @@ class Ui.Window : Adw.ApplicationWindow { this.playbin.now_playing.connect ((playbin, now, next) => { this.song = now; api.scrobble.begin (this.song.id); - this.play_queue.selection.playbin_select (playbin.play_queue_position); if (this.cancel_loading_art != null) { this.cancel_loading_art.cancel (); @@ -89,16 +85,12 @@ class Ui.Window : Adw.ApplicationWindow { this.playing_cover_art = Gdk.Paintable.empty (1, 1); }); - this.play_queue.selection.user_selected.connect ((position) => { - this.playbin.select_track (position); - }); - this.shuffle_all_tracks.sensitive = true; this.shuffle_all_tracks.activated.connect (() => { this.shuffle_all_tracks.sensitive = false; - this.play_queue_store.remove_all (); + this.playbin.play_queue.remove_all (); api.get_random_songs.begin (null, (song) => { - this.play_queue_store.append (song); + this.playbin.play_queue.append (song); }, (obj, res) => { try { api.get_random_songs.end (res);