Florian Müllner 41b94ccf11 extensions-app: Remember window state
It's good practice to save and reload the window size and
maximization state, and easy enough to implement, so let's
do that.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3115>
2024-01-13 23:44:35 +01:00

222 lines
7.8 KiB
JavaScript

import Adw from 'gi://Adw?version=1';
import GLib from 'gi://GLib';
import Gio from 'gi://Gio';
import GObject from 'gi://GObject';
import Gtk from 'gi://Gtk?version=4.0';
import Shew from 'gi://Shew';
const Package = imports.package;
import * as Gettext from 'gettext';
import * as Config from './misc/config.js';
import {ExtensionRow} from './extensionRow.js';
Gio._promisify(Gio.DBusConnection.prototype, 'call');
Gio._promisify(Shew.WindowExporter.prototype, 'export');
export const ExtensionsWindow = GObject.registerClass({
GTypeName: 'ExtensionsWindow',
Template: 'resource:///org/gnome/Extensions/ui/extensions-window.ui',
InternalChildren: [
'sortModel',
'searchFilter',
'userListModel',
'systemListModel',
'searchListModel',
'userGroup',
'userList',
'systemGroup',
'systemList',
'searchList',
'mainStack',
'searchBar',
'searchEntry',
'updatesBanner',
],
}, class ExtensionsWindow extends Adw.ApplicationWindow {
_init(params) {
super._init(params);
if (Config.PROFILE === 'development')
this.add_css_class('devel');
this._exporter = new Shew.WindowExporter({window: this});
this._exportedHandle = '';
this.add_action_entries(
[{
name: 'show-about',
activate: () => this._showAbout(),
}, {
name: 'logout',
activate: () => this._logout(),
}, {
name: 'user-extensions-enabled',
state: 'false',
change_state: (a, state) => {
const {extensionManager} = this.application;
extensionManager.userExtensionsEnabled = state.get_boolean();
},
}]);
const settings = new Gio.Settings({
schema_id: 'org.gnome.Extensions',
});
settings.bind('window-width',
this, 'default-width',
Gio.SettingsBindFlags.DEFAULT);
settings.bind('window-height',
this, 'default-height',
Gio.SettingsBindFlags.DEFAULT);
settings.bind('window-maximized',
this, 'maximized',
Gio.SettingsBindFlags.DEFAULT);
this._searchEntry.connect('search-changed',
() => (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.connect('row-activated', (_list, row) => row.activate());
this._userGroup.connect('notify::visible', () => this._syncVisiblePage());
this._systemList.connect('row-activated', (_list, row) => row.activate());
this._systemGroup.connect('notify::visible', () => this._syncVisiblePage());
const {extensionManager} = this.application;
extensionManager.connect('notify::failed',
() => this._syncVisiblePage());
extensionManager.connect('notify::n-updates',
() => this._checkUpdates());
extensionManager.connect('notify::user-extensions-enabled',
this._onUserExtensionsEnabledChanged.bind(this));
this._onUserExtensionsEnabledChanged();
this._sortModel.model = extensionManager.extensions;
this._userList.bind_model(this._userListModel,
extension => new ExtensionRow(extension));
this._systemList.bind_model(this._systemListModel,
extension => new ExtensionRow(extension));
this._searchList.bind_model(this._searchListModel,
extension => new ExtensionRow(extension));
extensionManager.connect('extensions-loaded',
() => this._extensionsLoaded());
}
uninstall(extension) {
const dialog = new Gtk.MessageDialog({
transient_for: this,
modal: true,
text: _('Remove “%s”?').format(extension.name),
secondary_text: _('If you remove the extension, you need to return to download it if you want to enable it again'),
});
dialog.add_button(_('_Cancel'), Gtk.ResponseType.CANCEL);
dialog.add_button(_('_Remove'), Gtk.ResponseType.ACCEPT)
.get_style_context().add_class('destructive-action');
dialog.connect('response', (dlg, response) => {
const {extensionManager} = this.application;
if (response === Gtk.ResponseType.ACCEPT)
extensionManager.uninstallExtension(extension.uuid);
dialog.destroy();
});
dialog.present();
}
async openPrefs(extension) {
if (!this._exportedHandle) {
try {
this._exportedHandle = await this._exporter.export();
} catch (e) {
console.warn(`Failed to export window: ${e.message}`);
}
}
const {extensionManager} = this.application;
extensionManager.openExtensionPrefs(extension.uuid, this._exportedHandle);
}
_showAbout() {
const aboutWindow = new Adw.AboutWindow({
developers: [
'Florian Müllner <fmuellner@gnome.org>',
'Jasper St. Pierre <jstpierre@mecheye.net>',
'Didier Roche <didrocks@ubuntu.com>',
'Romain Vigier <contact@romainvigier.fr>',
],
designers: [
'Allan Day <allanpday@gmail.com>',
'Tobias Bernard <tbernard@gnome.org>',
],
translator_credits: _('translator-credits'),
application_name: _('Extensions'),
license_type: Gtk.License.GPL_2_0,
application_icon: Package.name,
version: Package.version,
developer_name: _('The GNOME Project'),
website: 'https://apps.gnome.org/app/org.gnome.Extensions/',
issue_url: 'https://gitlab.gnome.org/GNOME/gnome-shell/issues/new',
transient_for: this,
});
aboutWindow.present();
}
_logout() {
this.application.get_dbus_connection().call(
'org.gnome.SessionManager',
'/org/gnome/SessionManager',
'org.gnome.SessionManager',
'Logout',
new GLib.Variant('(u)', [0]),
null,
Gio.DBusCallFlags.NONE,
-1,
null);
}
_onUserExtensionsEnabledChanged() {
const {userExtensionsEnabled} = this.application.extensionManager;
const action = this.lookup_action('user-extensions-enabled');
action.set_state(new GLib.Variant('b', userExtensionsEnabled));
}
_syncVisiblePage() {
const {extensionManager} = this.application;
const {searchModeEnabled} = this._searchBar;
if (extensionManager.failed)
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)
this._mainStack.visible_child_name = 'main';
else
this._mainStack.visible_child_name = 'placeholder';
}
_checkUpdates() {
const {nUpdates} = this.application.extensionManager;
this._updatesBanner.title = Gettext.ngettext(
'%d extension will be updated on next login.',
'%d extensions will be updated on next login.',
nUpdates).format(nUpdates);
this._updatesBanner.revealed = nUpdates > 0;
}
_extensionsLoaded() {
this._syncVisiblePage();
this._checkUpdates();
}
});