extensions-app: Add extension filtering
It's possible for the list of installed extension to get long enough to make searching more convenient than scrolling. Support that by implementing the standard search pattern[0] with a hidden search bar and a toggle in the headerbar. [0] https://developer.gnome.org/hig/stable/search.html.en https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3382
This commit is contained in:
parent
8eec7ae2d8
commit
9ef59b3b4f
@ -89,6 +89,22 @@
|
|||||||
<property name="pack_type">end</property>
|
<property name="pack_type">end</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkToggleButton" id="searchButton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="icon_name">edit-find-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkSwitch">
|
<object class="GtkSwitch">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -105,6 +121,21 @@
|
|||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSearchBar" id="searchBar">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="search-mode-enabled"
|
||||||
|
bind-source="searchButton"
|
||||||
|
bind-property="active"
|
||||||
|
bind-flags="bidirectional"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSearchEntry" id="searchEntry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="max-width-chars">35</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkStack" id="mainStack">
|
<object class="GtkStack" id="mainStack">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -89,6 +89,9 @@ var ExtensionsWindow = GObject.registerClass({
|
|||||||
'mainBox',
|
'mainBox',
|
||||||
'mainStack',
|
'mainStack',
|
||||||
'scrolledWindow',
|
'scrolledWindow',
|
||||||
|
'searchBar',
|
||||||
|
'searchButton',
|
||||||
|
'searchEntry',
|
||||||
'updatesBar',
|
'updatesBar',
|
||||||
'updatesLabel',
|
'updatesLabel',
|
||||||
],
|
],
|
||||||
@ -122,11 +125,45 @@ var ExtensionsWindow = GObject.registerClass({
|
|||||||
});
|
});
|
||||||
this.add_action(action);
|
this.add_action(action);
|
||||||
|
|
||||||
|
const accelGroup = new Gtk.AccelGroup();
|
||||||
|
this._searchButton.add_accelerator('clicked',
|
||||||
|
accelGroup, Gdk.KEY_f, Gdk.ModifierType.CONTROL_MASK, 0);
|
||||||
|
this._searchButton.add_accelerator('clicked',
|
||||||
|
accelGroup, Gdk.KEY_s, Gdk.ModifierType.CONTROL_MASK, 0);
|
||||||
|
this.add_accel_group(accelGroup);
|
||||||
|
|
||||||
|
this.connect('key-press-event',
|
||||||
|
(w, event) => this._searchBar.handle_event(event));
|
||||||
|
|
||||||
|
this._searchTerms = [];
|
||||||
|
this._searchEntry.connect('search-changed', () => {
|
||||||
|
const { text } = this._searchEntry;
|
||||||
|
if (text === '')
|
||||||
|
this._searchTerms = [];
|
||||||
|
else
|
||||||
|
[this._searchTerms] = GLib.str_tokenize_and_fold(text, null);
|
||||||
|
|
||||||
|
this._userList.invalidate_filter();
|
||||||
|
this._systemList.invalidate_filter();
|
||||||
|
});
|
||||||
|
|
||||||
this._userList.set_sort_func(this._sortList.bind(this));
|
this._userList.set_sort_func(this._sortList.bind(this));
|
||||||
this._userList.set_header_func(this._updateHeader.bind(this));
|
this._userList.set_header_func(this._updateHeader.bind(this));
|
||||||
|
this._userList.set_filter_func(this._filterList.bind(this));
|
||||||
|
this._userList.set_placeholder(new Gtk.Label({
|
||||||
|
label: _('No Matches'),
|
||||||
|
margin: 12,
|
||||||
|
visible: true,
|
||||||
|
}));
|
||||||
|
|
||||||
this._systemList.set_sort_func(this._sortList.bind(this));
|
this._systemList.set_sort_func(this._sortList.bind(this));
|
||||||
this._systemList.set_header_func(this._updateHeader.bind(this));
|
this._systemList.set_header_func(this._updateHeader.bind(this));
|
||||||
|
this._systemList.set_filter_func(this._filterList.bind(this));
|
||||||
|
this._systemList.set_placeholder(new Gtk.Label({
|
||||||
|
label: _('No Matches'),
|
||||||
|
margin: 12,
|
||||||
|
visible: true,
|
||||||
|
}));
|
||||||
|
|
||||||
this._shellProxy.connectSignal('ExtensionStateChanged',
|
this._shellProxy.connectSignal('ExtensionStateChanged',
|
||||||
this._onExtensionStateChanged.bind(this));
|
this._onExtensionStateChanged.bind(this));
|
||||||
@ -215,6 +252,11 @@ var ExtensionsWindow = GObject.registerClass({
|
|||||||
return row1.name.localeCompare(row2.name);
|
return row1.name.localeCompare(row2.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_filterList(row) {
|
||||||
|
return this._searchTerms.every(
|
||||||
|
t => row.keywords.some(k => k.startsWith(t)));
|
||||||
|
}
|
||||||
|
|
||||||
_updateHeader(row, before) {
|
_updateHeader(row, before) {
|
||||||
if (!before || row.get_header())
|
if (!before || row.get_header())
|
||||||
return;
|
return;
|
||||||
@ -352,6 +394,8 @@ var ExtensionRow = GObject.registerClass({
|
|||||||
this._extension = extension;
|
this._extension = extension;
|
||||||
this._prefsModule = null;
|
this._prefsModule = null;
|
||||||
|
|
||||||
|
[this._keywords] = GLib.str_tokenize_and_fold(this.name, null);
|
||||||
|
|
||||||
this._actionGroup = new Gio.SimpleActionGroup();
|
this._actionGroup = new Gio.SimpleActionGroup();
|
||||||
this.insert_action_group('row', this._actionGroup);
|
this.insert_action_group('row', this._actionGroup);
|
||||||
|
|
||||||
@ -470,6 +514,10 @@ var ExtensionRow = GObject.registerClass({
|
|||||||
? this._extension.error : _('The extension had an error');
|
? this._extension.error : _('The extension had an error');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get keywords() {
|
||||||
|
return this._keywords;
|
||||||
|
}
|
||||||
|
|
||||||
_updateState() {
|
_updateState() {
|
||||||
let state = this._extension.state === ExtensionState.ENABLED;
|
let state = this._extension.state === ExtensionState.ENABLED;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user