From 198c7bbd9cebf2427427e74393abc342ac75fafa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 19 Dec 2023 18:45:04 +0100 Subject: [PATCH] extensions-app: Turn Extension into a GObject This makes the Extension class usable as item-type in models, and allows us to use property bindings. Part-of: --- .../extensions-app/js/extensionManager.js | 146 ++++++++++++++++-- subprojects/extensions-app/js/extensionRow.js | 18 ++- 2 files changed, 143 insertions(+), 21 deletions(-) diff --git a/subprojects/extensions-app/js/extensionManager.js b/subprojects/extensions-app/js/extensionManager.js index 25f02618e..7671fb75e 100644 --- a/subprojects/extensions-app/js/extensionManager.js +++ b/subprojects/extensions-app/js/extensionManager.js @@ -25,8 +25,69 @@ function loadInterfaceXML(iface) { return null; } -class Extension { +const Extension = GObject.registerClass({ + GTypeName: 'Extension', + Properties: { + 'uuid': GObject.ParamSpec.string( + 'uuid', null, null, + GObject.ParamFlags.READABLE, + ''), + 'name': GObject.ParamSpec.string( + 'name', null, null, + GObject.ParamFlags.READABLE, + ''), + 'description': GObject.ParamSpec.string( + 'description', null, null, + GObject.ParamFlags.READABLE, + ''), + 'state': GObject.ParamSpec.int( + 'state', null, null, + GObject.ParamFlags.READABLE, + 1, 99, ExtensionState.INITIALIZED), + 'creator': GObject.ParamSpec.string( + 'creator', null, null, + GObject.ParamFlags.READABLE, + ''), + 'url': GObject.ParamSpec.string( + 'url', null, null, + GObject.ParamFlags.READABLE, + ''), + 'version': GObject.ParamSpec.string( + 'version', null, null, + GObject.ParamFlags.READABLE, + ''), + 'error': GObject.ParamSpec.string( + 'error', null, null, + GObject.ParamFlags.READABLE, + ''), + 'has-error': GObject.ParamSpec.boolean( + 'has-error', null, null, + GObject.ParamFlags.READABLE, + false), + 'has-prefs': GObject.ParamSpec.boolean( + 'has-prefs', null, null, + GObject.ParamFlags.READABLE, + false), + 'has-update': GObject.ParamSpec.boolean( + 'has-update', null, null, + GObject.ParamFlags.READABLE, + false), + 'has-version': GObject.ParamSpec.boolean( + 'has-version', null, null, + GObject.ParamFlags.READABLE, + false), + 'can-change': GObject.ParamSpec.boolean( + 'can-change', null, null, + GObject.ParamFlags.READABLE, + false), + 'is-user': GObject.ParamSpec.boolean( + 'is-user', null, null, + GObject.ParamFlags.READABLE, + false), + }, +}, class Extension extends GObject.Object { constructor(variant) { + super(); this.update(variant); } @@ -43,30 +104,79 @@ class Extension { if (this._uuid !== uuid) throw new Error(`Invalid update of extension ${this._uuid} with data from ${uuid}`); + this.freeze_notify(); + const {name} = metadata; - this._name = name; - [this._keywords] = GLib.str_tokenize_and_fold(name, null); + if (this._name !== name) { + [this._keywords] = GLib.str_tokenize_and_fold(name, null); + + this._name = name; + this.notify('name'); + } const [desc] = metadata.description.split('\n'); - this._description = desc; + if (this._description !== desc) { + this._description = desc; + this.notify('description'); + } - this._type = type; - this._errorDetail = error; - this._state = state; + if (this._type !== type) { + this._type = type; + this.notify('is-user'); + } + + if (this._errorDetail !== error) { + this._errorDetail = error; + this.notify('error'); + } + + if (this._state !== state) { + const hadError = this.hasError; + this._state = state; + this.notify('state'); + + if (this.hasError !== hadError) { + this.notify('has-error'); + this.notify('error'); + } + } const creator = metadata.creator ?? ''; - this._creator = creator; + if (this._creator !== creator) { + this._creator = creator; + this.notify('creator'); + } const url = metadata.url ?? ''; - this._url = url; + if (this._url !== url) { + this._url = url; + this.notify('url'); + } const version = String( metadata['version-name'] || metadata['version'] || ''); - this._version = version; + if (this._version !== version) { + this._version = version; + this.notify('version'); + this.notify('has-version'); + } - this._hasPrefs = hasPrefs; - this._hasUpdate = hasUpdate; - this._canChange = canChange; + if (this._hasPrefs !== hasPrefs) { + this._hasPrefs = hasPrefs; + this.notify('has-prefs'); + } + + if (this._hasUpdate !== hasUpdate) { + this._hasUpdate = hasUpdate; + this.notify('has-update'); + } + + if (this._canChange !== canChange) { + this._canChange = canChange; + this.notify('can-change'); + } + + this.thaw_notify(); } get uuid() { @@ -148,7 +258,9 @@ class Extension { get isUser() { return this._type === ExtensionType.PER_USER; } -} +}); +const {$gtype: TYPE_EXTENSION} = Extension; +export {TYPE_EXTENSION as Extension}; export const ExtensionManager = GObject.registerClass({ Properties: { @@ -166,9 +278,9 @@ export const ExtensionManager = GObject.registerClass({ false), }, Signals: { - 'extension-added': {param_types: [GObject.TYPE_JSOBJECT]}, - 'extension-removed': {param_types: [GObject.TYPE_JSOBJECT]}, - 'extension-changed': {param_types: [GObject.TYPE_JSOBJECT], flags: GObject.SignalFlags.DETAILED}, + 'extension-added': {param_types: [Extension]}, + 'extension-removed': {param_types: [Extension]}, + 'extension-changed': {param_types: [Extension], flags: GObject.SignalFlags.DETAILED}, 'extensions-loaded': {}, }, }, class ExtensionManager extends GObject.Object { diff --git a/subprojects/extensions-app/js/extensionRow.js b/subprojects/extensions-app/js/extensionRow.js index d2bb2c498..9085566cb 100644 --- a/subprojects/extensions-app/js/extensionRow.js +++ b/subprojects/extensions-app/js/extensionRow.js @@ -4,10 +4,17 @@ import Gio from 'gi://Gio'; import GObject from 'gi://GObject'; import {ExtensionState} from './misc/extensionUtils.js'; +import {Extension} from './extensionManager.js'; export const ExtensionRow = GObject.registerClass({ GTypeName: 'ExtensionRow', Template: 'resource:///org/gnome/Extensions/ui/extension-row.ui', + Properties: { + 'extension': GObject.ParamSpec.object( + 'extension', null, null, + GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, + Extension), + }, InternalChildren: [ 'detailsPopover', 'descriptionLabel', @@ -19,11 +26,10 @@ export const ExtensionRow = GObject.registerClass({ 'actionsBox', ], }, class ExtensionRow extends Adw.ActionRow { - _init(extension) { - super._init(); + constructor(extension) { + super({extension}); this._app = Gio.Application.get_default(); - this._extension = extension; this._actionGroup = new Gio.SimpleActionGroup(); this.insert_action_group('row', this._actionGroup); @@ -89,7 +95,11 @@ export const ExtensionRow = GObject.registerClass({ } get extension() { - return this._extension; + return this._extension ?? null; + } + + set extension(ext) { + this._extension = ext; } _updateState() {