2024-10-13 14:24:25 +00:00
|
|
|
class Ui.PlayQueueStore : Object, ListModel, Gtk.SelectionModel {
|
|
|
|
public ListStore inner = new ListStore (typeof (Song));
|
|
|
|
public uint playing_index { get; private set; default = 0; }
|
2024-10-12 12:57:37 +00:00
|
|
|
|
2024-10-13 15:21:29 +00:00
|
|
|
public signal void begin_playback (Song song);
|
|
|
|
public signal void prepare_next (Song? song);
|
|
|
|
public signal void playback_continues (Song song);
|
|
|
|
public signal void stop_playback ();
|
2024-10-10 20:04:55 +00:00
|
|
|
|
2024-10-13 14:24:25 +00:00
|
|
|
construct {
|
|
|
|
this.inner.items_changed.connect ((position, removed, added) => {
|
2024-10-13 15:43:55 +00:00
|
|
|
bool emit_signal = false;
|
|
|
|
|
2024-10-13 14:24:25 +00:00
|
|
|
if (this.playing_index >= position) {
|
|
|
|
if (this.playing_index < position+removed) {
|
|
|
|
this.playing_index = position;
|
|
|
|
if (this.playing_index < this.inner.get_n_items ()) {
|
2024-10-13 15:43:24 +00:00
|
|
|
emit_signal = true;
|
2024-10-13 15:21:29 +00:00
|
|
|
this.begin_playback ((Song) this.inner.get_item (this.playing_index));
|
|
|
|
this.prepare_next ((Song?) this.inner.get_item (this.playing_index+1));
|
2024-10-13 14:24:25 +00:00
|
|
|
} else {
|
2024-10-13 15:21:29 +00:00
|
|
|
this.stop_playback ();
|
2024-10-13 14:24:25 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.playing_index += added;
|
|
|
|
this.playing_index -= removed;
|
|
|
|
}
|
|
|
|
} else {
|
2024-10-13 15:21:29 +00:00
|
|
|
this.prepare_next ((Song?) this.inner.get_item (this.playing_index+1));
|
2024-10-13 14:24:25 +00:00
|
|
|
}
|
2024-10-12 16:35:42 +00:00
|
|
|
|
2024-10-13 14:24:25 +00:00
|
|
|
this.items_changed (position, removed, added);
|
2024-10-13 15:43:24 +00:00
|
|
|
if (emit_signal) {
|
2024-10-13 14:24:25 +00:00
|
|
|
this.selection_changed (this.playing_index, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2024-10-12 16:35:42 +00:00
|
|
|
|
2024-10-13 15:21:29 +00:00
|
|
|
public void song_transition () {
|
|
|
|
this.playing_index += 1;
|
|
|
|
this.selection_changed (this.playing_index-1, 2);
|
|
|
|
this.playback_continues ((Song) this.inner.get_item (this.playing_index));
|
|
|
|
this.prepare_next ((Song?) this.inner.get_item (this.playing_index+1));
|
|
|
|
}
|
2024-10-12 16:35:42 +00:00
|
|
|
|
2024-10-13 15:21:29 +00:00
|
|
|
public void playback_finished () {
|
|
|
|
this.playing_index += 1;
|
|
|
|
assert (this.playing_index == this.inner.get_n_items ());
|
|
|
|
this.selection_changed (this.playing_index-1, 1);
|
2024-10-10 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2024-10-13 14:24:25 +00:00
|
|
|
Gtk.Bitset get_selection_in_range (uint position, uint n_items) {
|
|
|
|
var bitset = new Gtk.Bitset.empty ();
|
|
|
|
if (this.playing_index < this.inner.get_n_items ()) {
|
|
|
|
bitset.add (playing_index);
|
|
|
|
}
|
|
|
|
return bitset;
|
2024-10-10 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2024-10-13 14:24:25 +00:00
|
|
|
bool is_selected (uint position) {
|
|
|
|
return position == this.playing_index;
|
2024-10-10 09:53:52 +00:00
|
|
|
}
|
2024-10-11 06:57:01 +00:00
|
|
|
|
2024-10-13 14:24:25 +00:00
|
|
|
bool select_all () {
|
|
|
|
return false;
|
2024-10-12 16:35:42 +00:00
|
|
|
}
|
|
|
|
|
2024-10-13 14:24:25 +00:00
|
|
|
bool select_item (uint position, bool unselect_rest) {
|
|
|
|
if (!unselect_rest) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
var previous = this.playing_index;
|
|
|
|
this.playing_index = position;
|
2024-10-12 16:35:42 +00:00
|
|
|
|
2024-10-13 14:24:25 +00:00
|
|
|
if (previous < this.inner.get_n_items ()) {
|
|
|
|
this.selection_changed (previous, 1);
|
2024-10-12 16:35:42 +00:00
|
|
|
}
|
2024-10-13 14:24:25 +00:00
|
|
|
this.selection_changed (position, 1);
|
|
|
|
|
2024-10-13 15:21:29 +00:00
|
|
|
this.begin_playback ((Song) this.inner.get_item (this.playing_index));
|
|
|
|
this.prepare_next ((Song) this.inner.get_item (this.playing_index+1));
|
2024-10-13 14:24:25 +00:00
|
|
|
|
|
|
|
return true;
|
2024-10-11 08:22:05 +00:00
|
|
|
}
|
2024-10-12 12:28:05 +00:00
|
|
|
|
2024-10-13 14:24:25 +00:00
|
|
|
bool select_range (uint position, uint n_items, bool unselect_rest) {
|
|
|
|
return false;
|
|
|
|
}
|
2024-10-12 12:28:05 +00:00
|
|
|
|
2024-10-13 14:24:25 +00:00
|
|
|
bool set_selection (Gtk.Bitset selected, Gtk.Bitset mask) {
|
|
|
|
return false;
|
|
|
|
}
|
2024-10-12 16:35:42 +00:00
|
|
|
|
2024-10-13 14:24:25 +00:00
|
|
|
bool unselect_all () {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool unselect_item (uint position) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool unselect_range (uint position, uint n_items) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object? get_item (uint position) {
|
|
|
|
return this.inner.get_item (position);
|
|
|
|
}
|
|
|
|
|
|
|
|
Type get_item_type () {
|
|
|
|
return this.inner.get_item_type ();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint get_n_items () {
|
|
|
|
return this.inner.get_n_items ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[GtkTemplate (ui = "/eu/callcc/audrey/ui/play_queue.ui")]
|
|
|
|
public class Ui.PlayQueue : Adw.NavigationPage {
|
|
|
|
[GtkChild] private unowned Gtk.ColumnView view;
|
|
|
|
PlayQueueStore store = new PlayQueueStore ();
|
|
|
|
|
2024-10-13 15:21:29 +00:00
|
|
|
public signal void begin_playback (Song song);
|
|
|
|
public signal void prepare_next (Song? next_song);
|
|
|
|
public signal void playback_continues (Song song);
|
|
|
|
public signal void stop_playback ();
|
2024-10-13 14:24:25 +00:00
|
|
|
|
|
|
|
public bool can_clear_all { get; private set; default = false; }
|
|
|
|
|
|
|
|
construct {
|
|
|
|
this.view.model = this.store;
|
|
|
|
|
2024-10-13 15:21:29 +00:00
|
|
|
this.store.begin_playback.connect ((song) => this.begin_playback (song));
|
|
|
|
this.store.prepare_next.connect ((next_song) => this.prepare_next (next_song));
|
|
|
|
this.store.playback_continues.connect ((song) => this.playback_continues (song));
|
|
|
|
this.store.stop_playback.connect (() => this.stop_playback ());
|
2024-10-13 14:24:25 +00:00
|
|
|
}
|
|
|
|
|
2024-10-13 15:43:24 +00:00
|
|
|
[GtkCallback] public void clear () {
|
|
|
|
this.store.inner.remove_all ();
|
|
|
|
this.can_clear_all = false;
|
|
|
|
}
|
|
|
|
|
2024-10-13 14:24:25 +00:00
|
|
|
public void queue (Song song) {
|
|
|
|
this.store.inner.append (song);
|
|
|
|
}
|
|
|
|
|
2024-10-13 15:21:29 +00:00
|
|
|
internal void song_transition () {
|
|
|
|
this.store.song_transition ();
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void playback_finished () {
|
|
|
|
this.store.playback_finished ();
|
2024-10-12 12:28:05 +00:00
|
|
|
}
|
2024-10-12 12:57:37 +00:00
|
|
|
|
|
|
|
internal void restart () {
|
2024-10-13 14:24:25 +00:00
|
|
|
this.store.select_item (0, true);
|
2024-10-12 12:57:37 +00:00
|
|
|
}
|
2024-10-12 13:36:47 +00:00
|
|
|
|
|
|
|
public void skip_forward () {
|
2024-10-13 14:24:25 +00:00
|
|
|
this.store.select_item (this.store.playing_index+1, true);
|
2024-10-12 13:36:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void skip_backward () {
|
2024-10-13 14:24:25 +00:00
|
|
|
if (this.store.playing_index >= 1) {
|
|
|
|
this.store.select_item (this.store.playing_index-1, true);
|
2024-10-12 13:36:47 +00:00
|
|
|
}
|
2024-10-12 16:35:42 +00:00
|
|
|
}
|
2024-10-13 15:43:24 +00:00
|
|
|
|
|
|
|
[GtkCallback] private void on_delete_cell_setup (Object object) {
|
|
|
|
var cell = (Gtk.ColumnViewCell) object;
|
|
|
|
var button = new Gtk.Button.from_icon_name ("edit-delete");
|
|
|
|
button.add_css_class ("flat");
|
|
|
|
button.clicked.connect (() => {
|
|
|
|
this.store.inner.remove (cell.position);
|
|
|
|
});
|
|
|
|
cell.child = button;
|
|
|
|
}
|
2024-10-10 09:53:52 +00:00
|
|
|
}
|