Skip to content

Commit

Permalink
Implement simple search in playlist (#765)
Browse files Browse the repository at this point in the history
* Add search entry in revealer to queue header

* Implement search and select

* Scroll to selected item

* Start playing selected track on search entry activate

* Add action to focus search entry

* Allow select first row

---------

Co-authored-by: Jeremy Wootten <jeremy@elementaryos.org>
Co-authored-by: Danielle Foré <danielle@elementary.io>
Co-authored-by: Ryan Kornheisl <ryan@skarva.tech>
  • Loading branch information
4 people authored Aug 6, 2024
1 parent 8458cbd commit f8b0df0
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 3 deletions.
10 changes: 9 additions & 1 deletion src/Application.vala
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ public class Music.Application : Gtk.Application {
public const string ACTION_PLAY_PAUSE = "action-play-pause";
public const string ACTION_PREVIOUS = "action-previous";
public const string ACTION_SHUFFLE = "action-shuffle";
public const string ACTION_FIND = "action-find";

private const ActionEntry[] ACTION_ENTRIES = {
{ ACTION_PLAY_PAUSE, action_play_pause, null, "false" },
{ ACTION_NEXT, action_next },
{ ACTION_PREVIOUS, action_previous },
{ ACTION_SHUFFLE, action_shuffle }
{ ACTION_SHUFFLE, action_shuffle },
{ ACTION_FIND, action_find }
};

private PlaybackManager? playback_manager = null;
Expand All @@ -40,6 +42,8 @@ public class Music.Application : Gtk.Application {

add_action_entries (ACTION_ENTRIES, this);

set_accels_for_action (ACTION_PREFIX + ACTION_FIND, {"<Ctrl>F"});

((SimpleAction) lookup_action (ACTION_PLAY_PAUSE)).set_enabled (false);
((SimpleAction) lookup_action (ACTION_PLAY_PAUSE)).set_state (false);
((SimpleAction) lookup_action (ACTION_NEXT)).set_enabled (false);
Expand Down Expand Up @@ -179,6 +183,10 @@ public class Music.Application : Gtk.Application {
playback_manager.shuffle ();
}

private void action_find () {
((MainWindow)active_window).start_search ();
}

private void on_bus_acquired (DBusConnection connection, string name) {
try {
connection.register_object ("/org/mpris/MediaPlayer2", new MprisRoot ());
Expand Down
39 changes: 38 additions & 1 deletion src/MainWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ public class Music.MainWindow : Gtk.ApplicationWindow {
private Gtk.Button repeat_button;
private Gtk.Button shuffle_button;
private Settings settings;
private Gtk.SearchEntry search_entry;
private Gtk.Revealer search_revealer;

construct {
var playback_manager = PlaybackManager.get_default ();
Expand All @@ -20,9 +22,20 @@ public class Music.MainWindow : Gtk.ApplicationWindow {

repeat_button = new Gtk.Button ();

search_entry = new Gtk.SearchEntry () {
placeholder_text = _("Search titles in playlist")
};

search_revealer = new Gtk.Revealer () {
child = search_entry
};

playback_manager.bind_property (
"has-items", search_revealer, "reveal-child", DEFAULT | SYNC_CREATE
);
var queue_header = new Gtk.HeaderBar () {
show_title_buttons = false,
title_widget = new Gtk.Label ("")
title_widget = search_revealer
};
queue_header.add_css_class (Granite.STYLE_CLASS_DEFAULT_DECORATION);
queue_header.pack_start (start_window_controls);
Expand Down Expand Up @@ -171,6 +184,30 @@ public class Music.MainWindow : Gtk.ApplicationWindow {
queue_listbox.row_activated.connect ((row) => {
playback_manager.current_audio = ((TrackRow) row).audio_object;
});

search_entry.search_changed.connect (() => {
int pos = playback_manager.find_title (search_entry.text);
if (pos >= 0) {
queue_listbox.select_row (queue_listbox.get_row_at_index (pos));
var adj = scrolled.vadjustment;
// Search entry is hidden if n_items is zero so no need to check
var ratio = (double)pos / (double)playback_manager.n_items;
adj.@value = adj.upper * ratio;
}
});

search_entry.activate.connect (() => {
var selected = queue_listbox.get_selected_row ();
if (selected != null) {
selected.activate ();
}
});
}

public void start_search () {
if (search_revealer.child_revealed) {
search_entry.grab_focus ();
}
}

private void action_open () {
Expand Down
30 changes: 29 additions & 1 deletion src/PlaybackManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
public class Music.PlaybackManager : Object {
public AudioObject? current_audio { get; set; default = null; }
public ListStore queue_liststore { get; private set; }
public bool has_items { get; private set; }
public uint n_items {
get {
return queue_liststore != null ? queue_liststore.get_n_items () : 0;
}
}
public int64 playback_position { get; private set; }
public signal void invalids_found (int count);

Expand Down Expand Up @@ -50,8 +56,8 @@ public class Music.PlaybackManager : Object {

queue_liststore.items_changed.connect (() => {
var shuffle_action_action = (SimpleAction) GLib.Application.get_default ().lookup_action (Application.ACTION_SHUFFLE);
has_items = queue_liststore.get_n_items () > 0;
shuffle_action_action.set_enabled (queue_liststore.get_n_items () > 1);

update_next_previous_sensitivity ();
});

Expand Down Expand Up @@ -348,6 +354,28 @@ public class Music.PlaybackManager : Object {
}
}

public int find_title (string term) {
var search_object = new AudioObject ("") {
title = term
};

int found_at = -1;
uint position;
if (queue_liststore.find_with_equal_func (
search_object,
(a, b) => {
var term_a = ((AudioObject)a).title.down ();
var term_b = ((AudioObject)b).title.down ();
return term_a.contains (term_b);
},
out position
)) {
found_at = (int)position;
}

return found_at;
}

private void update_next_previous_sensitivity () {
var next_sensitive = false;
var previous_sensitive = false;
Expand Down

0 comments on commit f8b0df0

Please sign in to comment.