mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
fix(plugins): pass pluginApi as initial property to prevent binding warnings. Eliminate the need for fallback chains in plugins code.
hot reload
This commit is contained in:
@@ -61,24 +61,52 @@ Item {
|
||||
enabled: BarWidgetRegistry.isPluginWidget(root.widgetId)
|
||||
|
||||
function onPluginWidgetRegistryUpdated() {
|
||||
// Force the loader to reload by toggling active
|
||||
if (BarWidgetRegistry.hasWidget(root.widgetId)) {
|
||||
root.reloadCounter++;
|
||||
// Plugin widgets use setSource, so also trigger reload directly
|
||||
if (root._isPlugin && loader.active)
|
||||
root._loadPluginWidget();
|
||||
Logger.d("BarWidgetLoader", "Plugin widget registry updated, reloading:", root.widgetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly property bool _isPlugin: BarWidgetRegistry.isPluginWidget(widgetId)
|
||||
|
||||
function _loadPluginWidget() {
|
||||
var comp = BarWidgetRegistry.getWidget(root.widgetId);
|
||||
if (!comp)
|
||||
return;
|
||||
var pluginId = root.widgetId.replace("plugin:", "");
|
||||
var api = PluginService.getPluginAPI(pluginId);
|
||||
loader.setSource(comp.url, api ? {
|
||||
"pluginApi": api
|
||||
} : {});
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
anchors.fill: parent
|
||||
asynchronous: true
|
||||
active: root.checkWidgetExists() && (root.reloadCounter >= 0)
|
||||
|
||||
sourceComponent: {
|
||||
// Depend on reloadCounter to force re-fetch of component
|
||||
var _ = root.reloadCounter;
|
||||
return root.checkWidgetExists() ? BarWidgetRegistry.getWidget(root.widgetId) : null;
|
||||
// Core widgets use sourceComponent; plugin widgets use setSource()
|
||||
// so pluginApi is available from the first binding evaluation.
|
||||
// Binding is set imperatively to avoid sourceComponent interfering with setSource.
|
||||
Component.onCompleted: {
|
||||
if (root._isPlugin) {
|
||||
root._loadPluginWidget();
|
||||
} else {
|
||||
sourceComponent = Qt.binding(function () {
|
||||
var _ = root.reloadCounter;
|
||||
return root.checkWidgetExists() ? BarWidgetRegistry.getWidget(root.widgetId) : null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && root._isPlugin)
|
||||
root._loadPluginWidget();
|
||||
}
|
||||
|
||||
// Unregister when the loaded item is destroyed (Loader deactivated or sourceComponent changed)
|
||||
@@ -119,17 +147,6 @@ Item {
|
||||
item.screen = widgetScreen;
|
||||
}
|
||||
|
||||
// Inject plugin API for plugin widgets
|
||||
// The API is fully populated (settings/translations already loaded) by PluginService
|
||||
if (BarWidgetRegistry.isPluginWidget(widgetId)) {
|
||||
var pluginId = widgetId.replace("plugin:", "");
|
||||
var api = PluginService.getPluginAPI(pluginId);
|
||||
if (api && item.hasOwnProperty("pluginApi")) {
|
||||
item.pluginApi = api;
|
||||
Logger.d("BarWidgetLoader", "Injected plugin API for", widgetId);
|
||||
}
|
||||
}
|
||||
|
||||
// Unregister any previous registration before registering the new instance
|
||||
root._unregister();
|
||||
|
||||
|
||||
@@ -288,12 +288,37 @@ Variants {
|
||||
required property var modelData
|
||||
required property int index
|
||||
property var _maskRegion: null
|
||||
readonly property bool _isPlugin: DesktopWidgetRegistry.isPluginWidget(modelData.id)
|
||||
|
||||
sourceComponent: {
|
||||
// Access registeredWidgets and pluginReloadCounter to create reactive binding
|
||||
var _ = root.pluginReloadCounter;
|
||||
var widgets = root.registeredWidgets;
|
||||
return widgets[modelData.id] || null;
|
||||
// Core widgets use sourceComponent; plugin widgets use setSource()
|
||||
// so pluginApi is available from the first binding evaluation.
|
||||
// Binding is set imperatively to avoid sourceComponent interfering with setSource.
|
||||
Component.onCompleted: {
|
||||
if (_isPlugin) {
|
||||
_loadPluginWidget();
|
||||
} else {
|
||||
sourceComponent = Qt.binding(function () {
|
||||
var _ = root.pluginReloadCounter;
|
||||
var widgets = root.registeredWidgets;
|
||||
return widgets[modelData.id] || null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && _isPlugin)
|
||||
_loadPluginWidget();
|
||||
}
|
||||
|
||||
function _loadPluginWidget() {
|
||||
var comp = root.registeredWidgets[modelData.id];
|
||||
if (!comp)
|
||||
return;
|
||||
var pluginId = modelData.id.replace("plugin:", "");
|
||||
var api = PluginService.getPluginAPI(pluginId);
|
||||
setSource(comp.url, api ? {
|
||||
"pluginApi": api
|
||||
} : {});
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
@@ -309,15 +334,6 @@ Variants {
|
||||
var newRegions = window._maskRegions.slice();
|
||||
newRegions.push(_maskRegion);
|
||||
window._maskRegions = newRegions;
|
||||
|
||||
// Inject plugin API for plugin widgets
|
||||
if (DesktopWidgetRegistry.isPluginWidget(modelData.id)) {
|
||||
var pluginId = modelData.id.replace("plugin:", "");
|
||||
var api = PluginService.getPluginAPI(pluginId);
|
||||
if (api && item.hasOwnProperty("pluginApi")) {
|
||||
item.pluginApi = api;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,11 +22,35 @@ Item {
|
||||
return (item && item.visible) ? item[prop] : 0;
|
||||
}
|
||||
|
||||
readonly property bool _isPlugin: ControlCenterWidgetRegistry.isPluginWidget(widgetId)
|
||||
|
||||
function _loadPluginWidget() {
|
||||
var comp = ControlCenterWidgetRegistry.getWidget(widgetId);
|
||||
if (!comp)
|
||||
return;
|
||||
var pluginId = widgetId.substring(7); // Remove "plugin:" prefix
|
||||
var api = PluginService.getPluginAPI(pluginId);
|
||||
loader.setSource(comp.url, api ? {
|
||||
"pluginApi": api
|
||||
} : {});
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
anchors.fill: parent
|
||||
asynchronous: false
|
||||
sourceComponent: ControlCenterWidgetRegistry.getWidget(widgetId)
|
||||
|
||||
// Core widgets use sourceComponent; plugin widgets use setSource()
|
||||
// so pluginApi is available from the first binding evaluation.
|
||||
Component.onCompleted: {
|
||||
if (root._isPlugin) {
|
||||
root._loadPluginWidget();
|
||||
} else {
|
||||
sourceComponent = Qt.binding(function () {
|
||||
return ControlCenterWidgetRegistry.getWidget(widgetId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
if (!item)
|
||||
@@ -44,12 +68,6 @@ Item {
|
||||
item.screen = widgetScreen;
|
||||
}
|
||||
|
||||
// Pass pluginApi for plugin widgets
|
||||
if (ControlCenterWidgetRegistry.isPluginWidget(widgetId) && item.hasOwnProperty("pluginApi")) {
|
||||
var pluginId = widgetId.substring(7); // Remove "plugin:" prefix
|
||||
item.pluginApi = PluginService.getPluginAPI(pluginId);
|
||||
}
|
||||
|
||||
// Call custom onLoaded if it exists
|
||||
if (item.hasOwnProperty("onLoaded")) {
|
||||
item.onLoaded();
|
||||
|
||||
@@ -164,16 +164,14 @@ SmartPanel {
|
||||
// Get plugin API
|
||||
var api = PluginService.getPluginAPI(pluginId);
|
||||
|
||||
// Activate loader and set component simultaneously
|
||||
// Use setSource with initial properties so pluginApi is available
|
||||
// from the first binding evaluation (before onLoaded)
|
||||
root.contentLoader.active = true;
|
||||
root.contentLoader.sourceComponent = component;
|
||||
root.contentLoader.setSource(component.url, api ? {
|
||||
"pluginApi": api
|
||||
} : {});
|
||||
|
||||
// Immediately inject API (before any bindings evaluate)
|
||||
if (root.contentLoader.item) {
|
||||
if (root.contentLoader.item.hasOwnProperty("pluginApi")) {
|
||||
root.contentLoader.item.pluginApi = api;
|
||||
}
|
||||
|
||||
root.pluginInstance = root.contentLoader.item;
|
||||
root.currentPluginId = pluginId;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user