Compare commits

..

3 commits

Author SHA1 Message Date
cc2f9f1466 remove track from playlist 2024-10-19 14:39:44 +02:00
a556ca4840 highlight current track 2024-10-19 14:04:52 +02:00
8966c5fff4 drag and drop basics 2024-10-19 13:55:25 +02:00
6 changed files with 104 additions and 7 deletions

View file

@ -63,6 +63,15 @@ public class Playbin : GLib.Object {
(position+i).to_string (), (position+i).to_string (),
}) >= 0); }) >= 0);
} }
if (this.play_queue_position == position && removed > 0) {
if (this.play_queue_position < this.play_queue.get_n_items ()) {
// edge case: new track plays, playlist-pos doesn't change, so now_playing never n gets triggered
this.now_playing (
(Subsonic.Song) this.play_queue.get_item (this.play_queue_position),
(Subsonic.Song?) this.play_queue.get_item (this.play_queue_position+1));
}
}
} }
public Playbin () { public Playbin () {

View file

@ -10,3 +10,7 @@
min-width: 15px; min-width: 15px;
min-height: 15px; min-height: 15px;
} }
.playing .title-label {
font-weight: bold;
}

View file

@ -27,6 +27,7 @@ template $UiPlayQueue: Adw.NavigationPage {
factory: SignalListItemFactory { factory: SignalListItemFactory {
setup => $on_song_list_setup (); setup => $on_song_list_setup ();
bind => $on_song_list_bind (); bind => $on_song_list_bind ();
unbind => $on_song_list_unbind ();
}; };
} }
} }

View file

@ -1,8 +1,50 @@
[GtkTemplate (ui = "/eu/callcc/audrey/ui/play_queue_song.ui")] [GtkTemplate (ui = "/eu/callcc/audrey/ui/play_queue_song.ui")]
class Ui.PlayQueueSong : Gtk.ListBoxRow { class Ui.PlayQueueSong : Gtk.ListBoxRow {
public uint position { get; set; } public bool current {
set {
if (value) {
this.play_icon_name = "media-playback-start";
this.add_css_class ("playing");
} else {
this.play_icon_name = "";
this.remove_css_class ("playing");
}
}
}
public uint displayed_position { get; set; }
public Subsonic.Song song { get; set; } public Subsonic.Song song { get; set; }
public string play_icon_name { get; set; default = ""; }
private Playbin playbin;
public PlayQueueSong (Playbin playbin) {
this.playbin = playbin;
var action_group = new SimpleActionGroup ();
var remove = new SimpleAction ("remove", null);
remove.activate.connect (() => {
this.playbin.play_queue.remove (this.displayed_position-1);
});
action_group.add_action (remove);
this.insert_action_group ("song", action_group);
}
private ulong connection;
public void bind (uint position, Subsonic.Song song) {
this.displayed_position = position+1;
this.song = song;
this.current = this.playbin.play_queue_position == position;
this.connection = this.playbin.notify["play-queue-position"].connect (() => {
this.current = this.playbin.play_queue_position == position;
});
}
public void unbind () {
this.playbin.disconnect (this.connection);
}
[GtkCallback] private string format_duration (int duration) { [GtkCallback] private string format_duration (int duration) {
return "%02d:%02d".printf(duration/60, duration%60); return "%02d:%02d".printf(duration/60, duration%60);
} }
@ -10,6 +52,16 @@ class Ui.PlayQueueSong : Gtk.ListBoxRow {
[GtkCallback] private string star_button_icon_name (DateTime? starred) { [GtkCallback] private string star_button_icon_name (DateTime? starred) {
return starred == null ? "non-starred" : "starred"; return starred == null ? "non-starred" : "starred";
} }
[GtkCallback] private Gdk.ContentProvider? on_drag_prepare (double x, double y) {
return new Gdk.ContentProvider.for_value (this);
}
[GtkCallback] private bool on_drop (Value value, double x, double y) {
var source = value as PlayQueueSong;
print ("dropped %u on %u", source.displayed_position, this.displayed_position);
return false;
}
} }
[GtkTemplate (ui = "/eu/callcc/audrey/ui/play_queue.ui")] [GtkTemplate (ui = "/eu/callcc/audrey/ui/play_queue.ui")]
@ -41,7 +93,7 @@ public class Ui.PlayQueue : Adw.NavigationPage {
[GtkCallback] private void on_song_list_setup (Gtk.SignalListItemFactory factory, Object object) { [GtkCallback] private void on_song_list_setup (Gtk.SignalListItemFactory factory, Object object) {
var item = object as Gtk.ListItem; var item = object as Gtk.ListItem;
var child = new PlayQueueSong (); var child = new PlayQueueSong (this.playbin);
item.child = child; item.child = child;
} }
@ -50,8 +102,14 @@ public class Ui.PlayQueue : Adw.NavigationPage {
var item = object as Gtk.ListItem; var item = object as Gtk.ListItem;
var child = item.child as PlayQueueSong; var child = item.child as PlayQueueSong;
child.position = item.position+1; child.bind (item.position, item.item as Subsonic.Song);
child.song = item.item as Subsonic.Song; }
[GtkCallback] private void on_song_list_unbind (Gtk.SignalListItemFactory factory, Object object) {
var item = object as Gtk.ListItem;
var child = item.child as PlayQueueSong;
child.unbind ();
} }
[GtkCallback] private void on_row_activated (uint position) { [GtkCallback] private void on_row_activated (uint position) {

View file

@ -8,7 +8,7 @@ template $UiPlayQueueSong: ListBoxRow {
spacing: 6; spacing: 6;
Image { Image {
visible: false; //visible: false;
icon-name: "list-drag-handle"; icon-name: "list-drag-handle";
styles [ "drag-handle" ] styles [ "drag-handle" ]
} }
@ -21,7 +21,7 @@ template $UiPlayQueueSong: ListBoxRow {
Image { Image {
focusable: false; focusable: false;
icon-size: normal; icon-size: normal;
//icon-name: "media-playback-start"; icon-name: bind template.play-icon-name;
} }
Label { Label {
@ -30,7 +30,7 @@ template $UiPlayQueueSong: ListBoxRow {
justify: right; justify: right;
styles [ "dim-label", "numeric" ] styles [ "dim-label", "numeric" ]
label: bind template.position; label: bind template.displayed_position;
} }
} }
@ -49,6 +49,7 @@ template $UiPlayQueueSong: ListBoxRow {
margin-start: 9; margin-start: 9;
label: bind template.song as <$SubsonicSong>.title; label: bind template.song as <$SubsonicSong>.title;
styles [ "title-label" ]
} }
} }
@ -111,11 +112,34 @@ template $UiPlayQueueSong: ListBoxRow {
focusable: true; focusable: true;
icon-name: "view-more"; icon-name: "view-more";
styles [ "flat" ] styles [ "flat" ]
popover: PopoverMenu {
menu-model: song-menu;
};
} }
} }
DragSource {
actions: move;
propagation-phase: capture;
prepare => $on_drag_prepare ();
}
DropTarget {
actions: move;
formats: UiPlayQueueSong;
preload: true;
drop => $on_drop ();
}
} }
SizeGroup { SizeGroup {
mode: horizontal; mode: horizontal;
widgets [title_box, artist_box, album_duration_box] widgets [title_box, artist_box, album_duration_box]
} }
menu song-menu {
item ("Remove", "song.remove")
}

View file

@ -83,6 +83,7 @@ class Ui.Window : Adw.ApplicationWindow {
this.playbin.stopped.connect (() => { this.playbin.stopped.connect (() => {
this.playing_cover_art = Gdk.Paintable.empty (1, 1); this.playing_cover_art = Gdk.Paintable.empty (1, 1);
this.song = null;
}); });
this.shuffle_all_tracks.sensitive = true; this.shuffle_all_tracks.sensitive = true;