kill custom selection model
This commit is contained in:
parent
8de2adde18
commit
ba1a5f3f39
5 changed files with 33 additions and 176 deletions
|
@ -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);
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue