Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data/music.metainfo.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
<issue url="https://github.com/elementary/music/issues/762">Search mechanism in the app</issue>
<issue url="https://github.com/elementary/music/issues/777">Ctrl+Q to Quit app</issue>
<issue url="https://github.com/elementary/music/issues/787">Ability to remove a track</issue>
<issue url="https://github.com/elementary/music/issues/794">Search function only shows first occurrence of search term</issue>
<issue url="https://github.com/elementary/music/issues/798">Gap below album cover when setting text size greater than 1</issue>
<issue url="https://github.com/elementary/music/issues/803">NowPlaying area resizes when playing song with long artist name</issue>
</issues>
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ config_file = configure_file(
)

adw_dep = dependency('libadwaita-1', version: '>=1.4.0')
granite_dep = dependency('granite-7', version: '>=7.6.0')
granite_dep = dependency('granite-7', version: '>=7.6.0') # Granite.Bin
gstreamer_dep = dependency('gstreamer-1.0')
gstreamer_pbutils_dep = dependency('gstreamer-pbutils-1.0')
gstreamer_tag_dep = dependency('gstreamer-tag-1.0')
Expand Down
1 change: 1 addition & 0 deletions po/POTFILES
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ src/MainWindow.vala
src/PlaybackManager.vala
src/Views/NowPlayingView.vala
src/Widgets/AlbumImage.vala
src/Widgets/SearchBar.vala
src/Widgets/SeekBar.vala
41 changes: 26 additions & 15 deletions src/MainWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ public class Music.MainWindow : Gtk.ApplicationWindow {
private const string ACTION_OPEN = "action-open";

private Granite.Placeholder queue_placeholder;
private Granite.Placeholder search_placeholder;
private Gtk.Button repeat_button;
private Gtk.Button shuffle_button;
private SearchBar search_bar;
private Gtk.ListView queue_listview;
private Gtk.Revealer search_revealer;
private Gtk.ScrolledWindow scrolled;
private Gtk.SearchEntry search_entry;
private Gtk.SingleSelection selection_model;
private Gtk.Stack queue_stack;
private Settings settings;
Expand All @@ -30,12 +31,10 @@ public class Music.MainWindow : Gtk.ApplicationWindow {

repeat_button = new Gtk.Button ();

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

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

playback_manager.bind_property (
Expand All @@ -55,7 +54,12 @@ public class Music.MainWindow : Gtk.ApplicationWindow {
icon = new ThemedIcon ("playlist-queue")
};

selection_model = new Gtk.SingleSelection (playback_manager.queue_liststore);
search_placeholder = new Granite.Placeholder ("") {
description = _("Try changing search terms"),
icon = new ThemedIcon ("edit-find-symbolic")
};

selection_model = new Gtk.SingleSelection (search_bar.filter_model);

var factory = new Gtk.SignalListItemFactory ();

Expand All @@ -71,6 +75,7 @@ public class Music.MainWindow : Gtk.ApplicationWindow {

queue_stack = new Gtk.Stack ();
queue_stack.add_child (queue_placeholder);
queue_stack.add_child (search_placeholder);
queue_stack.add_child (scrolled);

var drop_target = new Gtk.DropTarget (typeof (Gdk.FileList), Gdk.DragAction.COPY);
Expand Down Expand Up @@ -201,6 +206,13 @@ public class Music.MainWindow : Gtk.ApplicationWindow {
return false;
});

playback_manager.queue_liststore.items_changed.connect (() => {
if (playback_manager.n_items == 0) {
queue_stack.visible_child = queue_placeholder;
search_bar.search_entry.text = "";
}
});

playback_manager.invalids_found.connect ((count) => {
error_toast.title = ngettext (
"%d invalid file was not added to the queue",
Expand Down Expand Up @@ -234,14 +246,7 @@ public class Music.MainWindow : Gtk.ApplicationWindow {

selection_model.items_changed.connect (on_items_changed);

search_entry.search_changed.connect (() => {
int pos = playback_manager.find_title (search_entry.text);
if (pos >= 0) {
queue_listview.scroll_to (pos, SELECT, null);
}
});

search_entry.activate.connect (() => {
search_bar.activated.connect (() => {
var selected = selection_model.get_selected ();
if (selected != -1) {
var selected_audio = (AudioObject) selection_model.get_item (selected);
Expand All @@ -252,7 +257,7 @@ public class Music.MainWindow : Gtk.ApplicationWindow {

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

Expand Down Expand Up @@ -330,6 +335,12 @@ public class Music.MainWindow : Gtk.ApplicationWindow {
private void on_items_changed () {
if (selection_model.n_items > 0) {
queue_stack.visible_child = scrolled;
return;
}

if (search_bar.search_entry.text != "") {
search_placeholder.title = _("No Results for “%s”").printf (search_bar.search_entry.text);
queue_stack.visible_child = search_placeholder;
} else {
queue_stack.visible_child = queue_placeholder;
}
Expand Down
22 changes: 0 additions & 22 deletions src/PlaybackManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -412,28 +412,6 @@ 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
52 changes: 52 additions & 0 deletions src/Widgets/SearchBar.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* SPDX-License-Identifier: LGPL-3.0-or-later
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
*/

public class Music.SearchBar : Granite.Bin {
public signal void activated ();

public ListModel list_model { get; construct; }

public Gtk.SearchEntry search_entry { get; private set; }

/**
* The new model with the search applied. Make sure to use this one in further UI
* instead of the old given model.
*/
public Gtk.FilterListModel filter_model { get; private set; }

private Gtk.StringFilter filter;

public SearchBar (ListModel list_model) {
Object (list_model: list_model);
}

construct {
var expression = new Gtk.PropertyExpression (typeof (AudioObject), null, "title");

filter = new Gtk.StringFilter (expression) {
ignore_case = true,
match_mode = SUBSTRING
};

filter_model = new Gtk.FilterListModel (list_model, filter);

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

child = search_entry;

search_entry.search_changed.connect (on_search_changed);
search_entry.activate.connect (() => activated ());
}

private void on_search_changed () {
filter.search = search_entry.text;
}

public void start_search () {
search_entry.grab_focus ();
}
}
1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ sources = [
'DBus/MprisRoot.vala',
'Views/NowPlayingView.vala',
'Widgets/AlbumImage.vala',
'Widgets/SearchBar.vala',
'Widgets/SeekBar.vala',
'Widgets/TrackRow.vala',
]
Expand Down