extensions-app: Overhaul search

Instead of awkwardly filtering two different lists, use a separate
search page that filters a single list, similar to what libadwaita
does for preference windows.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3067>
This commit is contained in:
Florian Müllner 2023-12-20 14:32:31 +01:00 committed by Marge Bot
parent 7907b9754b
commit 1667b36abd
2 changed files with 57 additions and 23 deletions

View File

@ -49,6 +49,10 @@
</object> </object>
</property> </property>
</object> </object>
<object class="GtkFilterListModel" id="searchListModel">
<property name="model">sortModel</property>
<property name="filter">searchFilter</property>
</object>
<template class="ExtensionsWindow" parent="AdwApplicationWindow"> <template class="ExtensionsWindow" parent="AdwApplicationWindow">
<property name="default-width">800</property> <property name="default-width">800</property>
<property name="default-height">500</property> <property name="default-height">500</property>
@ -219,6 +223,42 @@
</property> </property>
</object> </object>
</child> </child>
<child>
<object class="GtkStackPage">
<property name="name">search</property>
<property name="child">
<object class="AdwPreferencesPage">
<child>
<object class="AdwPreferencesGroup">
<child>
<object class="GtkListBox" id="searchList">
<property name="selection-mode">none</property>
<accessibility>
<property name="label" translatable="yes">Search Results</property>
</accessibility>
<style>
<class name="boxed-list"/>
</style>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">noresults</property>
<property name="child">
<object class="AdwStatusPage">
<property name="icon-name">org.gnome.Extensions-symbolic</property>
<property name="title" translatable="yes">No Results Found</property>
<property name="description" translatable="yes">Try a different search.</property>
</object>
</property>
</object>
</child>
<child> <child>
<object class="GtkStackPage"> <object class="GtkStackPage">
<property name="name">placeholder</property> <property name="name">placeholder</property>

View File

@ -22,13 +22,14 @@ export const ExtensionsWindow = GObject.registerClass({
'searchFilter', 'searchFilter',
'userListModel', 'userListModel',
'systemListModel', 'systemListModel',
'searchListModel',
'userGroup', 'userGroup',
'userList', 'userList',
'systemGroup', 'systemGroup',
'systemList', 'systemList',
'searchList',
'mainStack', 'mainStack',
'searchBar', 'searchBar',
'searchButton',
'searchEntry', 'searchEntry',
'updatesBanner', 'updatesBanner',
], ],
@ -60,24 +61,14 @@ export const ExtensionsWindow = GObject.registerClass({
this._searchEntry.connect('search-changed', this._searchEntry.connect('search-changed',
() => (this._searchFilter.search = this._searchEntry.text)); () => (this._searchFilter.search = this._searchEntry.text));
this._searchBar.connect('notify::search-mode-enabled',
() => this._syncVisiblePage());
this._searchListModel.connect('notify::n-items',
() => this._syncVisiblePage());
this._userList.set_placeholder(new Gtk.Label({
label: _('No Matches'),
margin_start: 12,
margin_end: 12,
margin_top: 12,
margin_bottom: 12,
}));
this._userList.connect('row-activated', (_list, row) => row.activate()); this._userList.connect('row-activated', (_list, row) => row.activate());
this._userGroup.connect('notify::visible', () => this._syncVisiblePage()); this._userGroup.connect('notify::visible', () => this._syncVisiblePage());
this._systemList.set_placeholder(new Gtk.Label({
label: _('No Matches'),
margin_start: 12,
margin_end: 12,
margin_top: 12,
margin_bottom: 12,
}));
this._systemList.connect('row-activated', (_list, row) => row.activate()); this._systemList.connect('row-activated', (_list, row) => row.activate());
this._systemGroup.connect('notify::visible', () => this._syncVisiblePage()); this._systemGroup.connect('notify::visible', () => this._syncVisiblePage());
@ -92,14 +83,12 @@ export const ExtensionsWindow = GObject.registerClass({
this._sortModel.model = extensionManager.extensions; this._sortModel.model = extensionManager.extensions;
this._userList.bind_model(new Gtk.FilterListModel({ this._userList.bind_model(this._userListModel,
filter: this._searchFilter, extension => new ExtensionRow(extension));
model: this._userListModel, this._systemList.bind_model(this._systemListModel,
}), extension => new ExtensionRow(extension)); extension => new ExtensionRow(extension));
this._systemList.bind_model(new Gtk.FilterListModel({ this._searchList.bind_model(this._searchListModel,
filter: this._searchFilter, extension => new ExtensionRow(extension));
model: this._systemListModel,
}), extension => new ExtensionRow(extension));
extensionManager.connect('extensions-loaded', extensionManager.connect('extensions-loaded',
() => this._extensionsLoaded()); () => this._extensionsLoaded());
@ -187,9 +176,14 @@ export const ExtensionsWindow = GObject.registerClass({
_syncVisiblePage() { _syncVisiblePage() {
const {extensionManager} = this.application; const {extensionManager} = this.application;
const {searchModeEnabled} = this._searchBar;
if (extensionManager.failed) if (extensionManager.failed)
this._mainStack.visible_child_name = 'noshell'; this._mainStack.visible_child_name = 'noshell';
else if (searchModeEnabled && this._searchListModel.get_n_items() > 0)
this._mainStack.visible_child_name = 'search';
else if (searchModeEnabled)
this._mainStack.visible_child_name = 'noresults';
else if (this._userGroup.visible || this._systemGroup.visible) else if (this._userGroup.visible || this._systemGroup.visible)
this._mainStack.visible_child_name = 'main'; this._mainStack.visible_child_name = 'main';
else else