mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
desktop widgets: centralize config in desktop widgets tab, variants
always available
This commit is contained in:
@@ -14,7 +14,7 @@ import "settings/SettingsStore.js" as Store
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property int settingsConfigVersion: 3
|
readonly property int settingsConfigVersion: 4
|
||||||
|
|
||||||
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
||||||
|
|
||||||
@@ -450,6 +450,7 @@ Singleton {
|
|||||||
property var systemMonitorVariants: []
|
property var systemMonitorVariants: []
|
||||||
property var desktopWidgetPositions: ({})
|
property var desktopWidgetPositions: ({})
|
||||||
property var desktopWidgetGridSettings: ({})
|
property var desktopWidgetGridSettings: ({})
|
||||||
|
property var desktopWidgetInstances: []
|
||||||
|
|
||||||
function getDesktopWidgetGridSetting(screenKey, property, defaultValue) {
|
function getDesktopWidgetGridSetting(screenKey, property, defaultValue) {
|
||||||
const val = desktopWidgetGridSettings?.[screenKey]?.[property];
|
const val = desktopWidgetGridSettings?.[screenKey]?.[property];
|
||||||
@@ -546,6 +547,73 @@ Singleton {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createDesktopWidgetInstance(widgetType, name, config) {
|
||||||
|
const id = "dw_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
|
||||||
|
const instance = {
|
||||||
|
id: id,
|
||||||
|
widgetType: widgetType,
|
||||||
|
name: name || widgetType,
|
||||||
|
enabled: true,
|
||||||
|
config: config || {},
|
||||||
|
positions: {}
|
||||||
|
};
|
||||||
|
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||||
|
instances.push(instance);
|
||||||
|
desktopWidgetInstances = instances;
|
||||||
|
saveSettings();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDesktopWidgetInstance(instanceId, updates) {
|
||||||
|
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||||
|
const idx = instances.findIndex(inst => inst.id === instanceId);
|
||||||
|
if (idx === -1) return;
|
||||||
|
Object.assign(instances[idx], updates);
|
||||||
|
desktopWidgetInstances = instances;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDesktopWidgetInstanceConfig(instanceId, configUpdates) {
|
||||||
|
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||||
|
const idx = instances.findIndex(inst => inst.id === instanceId);
|
||||||
|
if (idx === -1) return;
|
||||||
|
instances[idx].config = Object.assign({}, instances[idx].config || {}, configUpdates);
|
||||||
|
desktopWidgetInstances = instances;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDesktopWidgetInstancePosition(instanceId, screenKey, positionUpdates) {
|
||||||
|
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||||
|
const idx = instances.findIndex(inst => inst.id === instanceId);
|
||||||
|
if (idx === -1) return;
|
||||||
|
if (!instances[idx].positions) instances[idx].positions = {};
|
||||||
|
instances[idx].positions[screenKey] = Object.assign(
|
||||||
|
{},
|
||||||
|
instances[idx].positions[screenKey] || {},
|
||||||
|
positionUpdates
|
||||||
|
);
|
||||||
|
desktopWidgetInstances = instances;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDesktopWidgetInstance(instanceId) {
|
||||||
|
const instances = (desktopWidgetInstances || []).filter(inst => inst.id !== instanceId);
|
||||||
|
desktopWidgetInstances = instances;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDesktopWidgetInstance(instanceId) {
|
||||||
|
return (desktopWidgetInstances || []).find(inst => inst.id === instanceId) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDesktopWidgetInstancesOfType(widgetType) {
|
||||||
|
return (desktopWidgetInstances || []).filter(inst => inst.widgetType === widgetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEnabledDesktopWidgetInstances() {
|
||||||
|
return (desktopWidgetInstances || []).filter(inst => inst.enabled);
|
||||||
|
}
|
||||||
|
|
||||||
signal forceDankBarLayoutRefresh
|
signal forceDankBarLayoutRefresh
|
||||||
signal forceDockLayoutRefresh
|
signal forceDockLayoutRefresh
|
||||||
signal widgetDataChanged
|
signal widgetDataChanged
|
||||||
|
|||||||
@@ -337,6 +337,7 @@ var SPEC = {
|
|||||||
systemMonitorTopProcessCount: { def: 3 },
|
systemMonitorTopProcessCount: { def: 3 },
|
||||||
systemMonitorTopProcessSortBy: { def: "cpu" },
|
systemMonitorTopProcessSortBy: { def: "cpu" },
|
||||||
systemMonitorGraphInterval: { def: 60 },
|
systemMonitorGraphInterval: { def: 60 },
|
||||||
|
systemMonitorLayoutMode: { def: "auto" },
|
||||||
systemMonitorX: { def: -1 },
|
systemMonitorX: { def: -1 },
|
||||||
systemMonitorY: { def: -1 },
|
systemMonitorY: { def: -1 },
|
||||||
systemMonitorWidth: { def: 320 },
|
systemMonitorWidth: { def: 320 },
|
||||||
@@ -344,7 +345,9 @@ var SPEC = {
|
|||||||
systemMonitorDisplayPreferences: { def: ["all"] },
|
systemMonitorDisplayPreferences: { def: ["all"] },
|
||||||
systemMonitorVariants: { def: [] },
|
systemMonitorVariants: { def: [] },
|
||||||
desktopWidgetPositions: { def: {} },
|
desktopWidgetPositions: { def: {} },
|
||||||
desktopWidgetGridSettings: { def: {} }
|
desktopWidgetGridSettings: { def: {} },
|
||||||
|
|
||||||
|
desktopWidgetInstances: { def: [] }
|
||||||
};
|
};
|
||||||
|
|
||||||
function getValidKeys() {
|
function getValidKeys() {
|
||||||
|
|||||||
@@ -119,6 +119,101 @@ function migrateToVersion(obj, targetVersion) {
|
|||||||
settings.configVersion = 3;
|
settings.configVersion = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentVersion < 4) {
|
||||||
|
console.info("Migrating settings from version", currentVersion, "to version 4");
|
||||||
|
console.info("Migrating desktop widgets to unified desktopWidgetInstances");
|
||||||
|
|
||||||
|
var instances = [];
|
||||||
|
|
||||||
|
if (settings.desktopClockEnabled) {
|
||||||
|
var clockPositions = {};
|
||||||
|
if (settings.desktopClockX !== undefined && settings.desktopClockX >= 0) {
|
||||||
|
clockPositions["default"] = {
|
||||||
|
x: settings.desktopClockX,
|
||||||
|
y: settings.desktopClockY,
|
||||||
|
width: settings.desktopClockWidth || 280,
|
||||||
|
height: settings.desktopClockHeight || 180
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
instances.push({
|
||||||
|
id: "dw_clock_primary",
|
||||||
|
widgetType: "desktopClock",
|
||||||
|
name: "Desktop Clock",
|
||||||
|
enabled: true,
|
||||||
|
config: {
|
||||||
|
style: settings.desktopClockStyle || "analog",
|
||||||
|
transparency: settings.desktopClockTransparency !== undefined ? settings.desktopClockTransparency : 0.8,
|
||||||
|
colorMode: settings.desktopClockColorMode || "primary",
|
||||||
|
customColor: settings.desktopClockCustomColor || "#ffffff",
|
||||||
|
showDate: settings.desktopClockShowDate !== false,
|
||||||
|
showAnalogNumbers: settings.desktopClockShowAnalogNumbers || false,
|
||||||
|
showAnalogSeconds: settings.desktopClockShowAnalogSeconds !== false,
|
||||||
|
displayPreferences: settings.desktopClockDisplayPreferences || ["all"]
|
||||||
|
},
|
||||||
|
positions: clockPositions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.systemMonitorEnabled) {
|
||||||
|
var sysmonPositions = {};
|
||||||
|
if (settings.systemMonitorX !== undefined && settings.systemMonitorX >= 0) {
|
||||||
|
sysmonPositions["default"] = {
|
||||||
|
x: settings.systemMonitorX,
|
||||||
|
y: settings.systemMonitorY,
|
||||||
|
width: settings.systemMonitorWidth || 320,
|
||||||
|
height: settings.systemMonitorHeight || 480
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
instances.push({
|
||||||
|
id: "dw_sysmon_primary",
|
||||||
|
widgetType: "systemMonitor",
|
||||||
|
name: "System Monitor",
|
||||||
|
enabled: true,
|
||||||
|
config: {
|
||||||
|
showHeader: settings.systemMonitorShowHeader !== false,
|
||||||
|
transparency: settings.systemMonitorTransparency !== undefined ? settings.systemMonitorTransparency : 0.8,
|
||||||
|
colorMode: settings.systemMonitorColorMode || "primary",
|
||||||
|
customColor: settings.systemMonitorCustomColor || "#ffffff",
|
||||||
|
showCpu: settings.systemMonitorShowCpu !== false,
|
||||||
|
showCpuGraph: settings.systemMonitorShowCpuGraph !== false,
|
||||||
|
showCpuTemp: settings.systemMonitorShowCpuTemp !== false,
|
||||||
|
showGpuTemp: settings.systemMonitorShowGpuTemp || false,
|
||||||
|
gpuPciId: settings.systemMonitorGpuPciId || "",
|
||||||
|
showMemory: settings.systemMonitorShowMemory !== false,
|
||||||
|
showMemoryGraph: settings.systemMonitorShowMemoryGraph !== false,
|
||||||
|
showNetwork: settings.systemMonitorShowNetwork !== false,
|
||||||
|
showNetworkGraph: settings.systemMonitorShowNetworkGraph !== false,
|
||||||
|
showDisk: settings.systemMonitorShowDisk !== false,
|
||||||
|
showTopProcesses: settings.systemMonitorShowTopProcesses || false,
|
||||||
|
topProcessCount: settings.systemMonitorTopProcessCount || 3,
|
||||||
|
topProcessSortBy: settings.systemMonitorTopProcessSortBy || "cpu",
|
||||||
|
layoutMode: settings.systemMonitorLayoutMode || "auto",
|
||||||
|
graphInterval: settings.systemMonitorGraphInterval || 60,
|
||||||
|
displayPreferences: settings.systemMonitorDisplayPreferences || ["all"]
|
||||||
|
},
|
||||||
|
positions: sysmonPositions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var variants = settings.systemMonitorVariants || [];
|
||||||
|
for (var i = 0; i < variants.length; i++) {
|
||||||
|
var v = variants[i];
|
||||||
|
instances.push({
|
||||||
|
id: v.id,
|
||||||
|
widgetType: "systemMonitor",
|
||||||
|
name: v.name || ("System Monitor " + (i + 2)),
|
||||||
|
enabled: true,
|
||||||
|
config: v.config || {},
|
||||||
|
positions: v.positions || {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.desktopWidgetInstances = instances;
|
||||||
|
settings.configVersion = 4;
|
||||||
|
}
|
||||||
|
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -432,7 +432,9 @@ FocusScope {
|
|||||||
visible: active
|
visible: active
|
||||||
focus: active
|
focus: active
|
||||||
|
|
||||||
sourceComponent: DesktopWidgetsTab {}
|
sourceComponent: DesktopWidgetsTab {
|
||||||
|
parentModal: root.parentModal
|
||||||
|
}
|
||||||
|
|
||||||
onActiveChanged: {
|
onActiveChanged: {
|
||||||
if (active && item)
|
if (active && item)
|
||||||
|
|||||||
@@ -9,7 +9,12 @@ Item {
|
|||||||
property real widgetWidth: 280
|
property real widgetWidth: 280
|
||||||
property real widgetHeight: 200
|
property real widgetHeight: 200
|
||||||
|
|
||||||
property string clockStyle: SettingsData.desktopClockStyle
|
property string instanceId: ""
|
||||||
|
property var instanceData: null
|
||||||
|
readonly property var cfg: instanceData?.config ?? null
|
||||||
|
readonly property bool isInstance: instanceId !== "" && cfg !== null
|
||||||
|
|
||||||
|
property string clockStyle: isInstance ? (cfg.style ?? "analog") : SettingsData.desktopClockStyle
|
||||||
property bool forceSquare: clockStyle === "analog"
|
property bool forceSquare: clockStyle === "analog"
|
||||||
|
|
||||||
property real defaultWidth: {
|
property real defaultWidth: {
|
||||||
@@ -53,12 +58,12 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property bool enabled: SettingsData.desktopClockEnabled
|
property bool enabled: isInstance ? (instanceData?.enabled ?? true) : SettingsData.desktopClockEnabled
|
||||||
property real transparency: SettingsData.desktopClockTransparency
|
property real transparency: isInstance ? (cfg.transparency ?? 0.8) : SettingsData.desktopClockTransparency
|
||||||
property string colorMode: SettingsData.desktopClockColorMode
|
property string colorMode: isInstance ? (cfg.colorMode ?? "primary") : SettingsData.desktopClockColorMode
|
||||||
property color customColor: SettingsData.desktopClockCustomColor
|
property color customColor: isInstance ? (cfg.customColor ?? "#ffffff") : SettingsData.desktopClockCustomColor
|
||||||
property bool showDate: SettingsData.desktopClockShowDate
|
property bool showDate: isInstance ? (cfg.showDate ?? true) : SettingsData.desktopClockShowDate
|
||||||
property bool showAnalogNumbers: SettingsData.desktopClockShowAnalogNumbers
|
property bool showAnalogNumbers: isInstance ? (cfg.showAnalogNumbers ?? false) : SettingsData.desktopClockShowAnalogNumbers
|
||||||
|
|
||||||
readonly property real scaleFactor: Math.min(width, height) / 200
|
readonly property real scaleFactor: Math.min(width, height) / 200
|
||||||
|
|
||||||
@@ -78,7 +83,8 @@ Item {
|
|||||||
readonly property color subtleTextColor: Theme.onSurfaceVariant
|
readonly property color subtleTextColor: Theme.onSurfaceVariant
|
||||||
readonly property color backgroundColor: Theme.withAlpha(Theme.surface, root.transparency)
|
readonly property color backgroundColor: Theme.withAlpha(Theme.surface, root.transparency)
|
||||||
|
|
||||||
readonly property bool needsSeconds: clockStyle === "analog" ? SettingsData.desktopClockShowAnalogSeconds : SettingsData.showSeconds
|
readonly property bool showAnalogSeconds: isInstance ? (cfg.showAnalogSeconds ?? true) : SettingsData.desktopClockShowAnalogSeconds
|
||||||
|
readonly property bool needsSeconds: clockStyle === "analog" ? showAnalogSeconds : SettingsData.showSeconds
|
||||||
|
|
||||||
SystemClock {
|
SystemClock {
|
||||||
id: systemClock
|
id: systemClock
|
||||||
@@ -194,7 +200,7 @@ Item {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: secondDot
|
id: secondDot
|
||||||
visible: SettingsData.desktopClockShowAnalogSeconds
|
visible: root.showAnalogSeconds
|
||||||
|
|
||||||
property real angle: analogRoot.seconds * 6 * Math.PI / 180
|
property real angle: analogRoot.seconds * 6 * Math.PI / 180
|
||||||
property real orbitRadius: analogRoot.faceRadius * 0.92
|
property real orbitRadius: analogRoot.faceRadius * 0.92
|
||||||
|
|||||||
@@ -31,32 +31,32 @@ Item {
|
|||||||
return 180;
|
return 180;
|
||||||
}
|
}
|
||||||
|
|
||||||
property string variantId: ""
|
property string instanceId: ""
|
||||||
property var variantData: null
|
property var instanceData: null
|
||||||
|
|
||||||
readonly property var cfg: variantData?.config ?? null
|
readonly property var cfg: instanceData?.config ?? null
|
||||||
readonly property bool isVariant: variantId !== "" && cfg !== null
|
readonly property bool isInstance: instanceId !== "" && cfg !== null
|
||||||
|
|
||||||
property bool enabled: SettingsData.systemMonitorEnabled
|
property bool enabled: isInstance ? (instanceData?.enabled ?? true) : SettingsData.systemMonitorEnabled
|
||||||
property bool showHeader: isVariant ? (cfg.showHeader ?? true) : SettingsData.systemMonitorShowHeader
|
property bool showHeader: isInstance ? (cfg.showHeader ?? true) : SettingsData.systemMonitorShowHeader
|
||||||
property real transparency: isVariant ? (cfg.transparency ?? 0.8) : SettingsData.systemMonitorTransparency
|
property real transparency: isInstance ? (cfg.transparency ?? 0.8) : SettingsData.systemMonitorTransparency
|
||||||
property string colorMode: isVariant ? (cfg.colorMode ?? "primary") : SettingsData.systemMonitorColorMode
|
property string colorMode: isInstance ? (cfg.colorMode ?? "primary") : SettingsData.systemMonitorColorMode
|
||||||
property color customColor: isVariant ? (cfg.customColor ?? "#ffffff") : SettingsData.systemMonitorCustomColor
|
property color customColor: isInstance ? (cfg.customColor ?? "#ffffff") : SettingsData.systemMonitorCustomColor
|
||||||
property bool showCpu: isVariant ? (cfg.showCpu ?? true) : SettingsData.systemMonitorShowCpu
|
property bool showCpu: isInstance ? (cfg.showCpu ?? true) : SettingsData.systemMonitorShowCpu
|
||||||
property bool showCpuGraph: isVariant ? (cfg.showCpuGraph ?? true) : SettingsData.systemMonitorShowCpuGraph
|
property bool showCpuGraph: isInstance ? (cfg.showCpuGraph ?? true) : SettingsData.systemMonitorShowCpuGraph
|
||||||
property bool showCpuTemp: isVariant ? (cfg.showCpuTemp ?? true) : SettingsData.systemMonitorShowCpuTemp
|
property bool showCpuTemp: isInstance ? (cfg.showCpuTemp ?? true) : SettingsData.systemMonitorShowCpuTemp
|
||||||
property bool showGpuTemp: isVariant ? (cfg.showGpuTemp ?? false) : SettingsData.systemMonitorShowGpuTemp
|
property bool showGpuTemp: isInstance ? (cfg.showGpuTemp ?? false) : SettingsData.systemMonitorShowGpuTemp
|
||||||
property string selectedGpuPciId: isVariant ? (cfg.gpuPciId ?? "") : SettingsData.systemMonitorGpuPciId
|
property string selectedGpuPciId: isInstance ? (cfg.gpuPciId ?? "") : SettingsData.systemMonitorGpuPciId
|
||||||
property bool showMemory: isVariant ? (cfg.showMemory ?? true) : SettingsData.systemMonitorShowMemory
|
property bool showMemory: isInstance ? (cfg.showMemory ?? true) : SettingsData.systemMonitorShowMemory
|
||||||
property bool showMemoryGraph: isVariant ? (cfg.showMemoryGraph ?? true) : SettingsData.systemMonitorShowMemoryGraph
|
property bool showMemoryGraph: isInstance ? (cfg.showMemoryGraph ?? true) : SettingsData.systemMonitorShowMemoryGraph
|
||||||
property bool showNetwork: isVariant ? (cfg.showNetwork ?? true) : SettingsData.systemMonitorShowNetwork
|
property bool showNetwork: isInstance ? (cfg.showNetwork ?? true) : SettingsData.systemMonitorShowNetwork
|
||||||
property bool showNetworkGraph: isVariant ? (cfg.showNetworkGraph ?? true) : SettingsData.systemMonitorShowNetworkGraph
|
property bool showNetworkGraph: isInstance ? (cfg.showNetworkGraph ?? true) : SettingsData.systemMonitorShowNetworkGraph
|
||||||
property bool showDisk: isVariant ? (cfg.showDisk ?? true) : SettingsData.systemMonitorShowDisk
|
property bool showDisk: isInstance ? (cfg.showDisk ?? true) : SettingsData.systemMonitorShowDisk
|
||||||
property bool showTopProcesses: isVariant ? (cfg.showTopProcesses ?? false) : SettingsData.systemMonitorShowTopProcesses
|
property bool showTopProcesses: isInstance ? (cfg.showTopProcesses ?? false) : SettingsData.systemMonitorShowTopProcesses
|
||||||
property int topProcessCount: isVariant ? (cfg.topProcessCount ?? 3) : SettingsData.systemMonitorTopProcessCount
|
property int topProcessCount: isInstance ? (cfg.topProcessCount ?? 3) : SettingsData.systemMonitorTopProcessCount
|
||||||
property string topProcessSortBy: isVariant ? (cfg.topProcessSortBy ?? "cpu") : SettingsData.systemMonitorTopProcessSortBy
|
property string topProcessSortBy: isInstance ? (cfg.topProcessSortBy ?? "cpu") : SettingsData.systemMonitorTopProcessSortBy
|
||||||
property string layoutMode: isVariant ? (cfg.layoutMode ?? "auto") : SettingsData.systemMonitorLayoutMode
|
property string layoutMode: isInstance ? (cfg.layoutMode ?? "auto") : SettingsData.systemMonitorLayoutMode
|
||||||
property int graphInterval: isVariant ? (cfg.graphInterval ?? 60) : SettingsData.systemMonitorGraphInterval
|
property int graphInterval: isInstance ? (cfg.graphInterval ?? 60) : SettingsData.systemMonitorGraphInterval
|
||||||
|
|
||||||
readonly property color accentColor: {
|
readonly property color accentColor: {
|
||||||
switch (colorMode) {
|
switch (colorMode) {
|
||||||
|
|||||||
@@ -9,110 +9,101 @@ Variants {
|
|||||||
id: root
|
id: root
|
||||||
model: Quickshell.screens
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
Component.onCompleted: Qt.callLater(autoEnablePluginsForInstances)
|
||||||
|
|
||||||
|
function autoEnablePluginsForInstances() {
|
||||||
|
const instances = SettingsData.desktopWidgetInstances || [];
|
||||||
|
const pluginTypes = new Set();
|
||||||
|
|
||||||
|
for (const inst of instances) {
|
||||||
|
if (!inst.enabled)
|
||||||
|
continue;
|
||||||
|
if (inst.widgetType === "desktopClock" || inst.widgetType === "systemMonitor")
|
||||||
|
continue;
|
||||||
|
pluginTypes.add(inst.widgetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const pluginId of pluginTypes) {
|
||||||
|
if (PluginService.isPluginLoaded(pluginId))
|
||||||
|
continue;
|
||||||
|
if (!PluginService.availablePlugins[pluginId])
|
||||||
|
continue;
|
||||||
|
PluginService.enablePlugin(pluginId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: PluginService
|
||||||
|
function onPluginListUpdated() {
|
||||||
|
Qt.callLater(root.autoEnablePluginsForInstances);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: screenDelegate
|
id: screenDelegate
|
||||||
|
|
||||||
required property var modelData
|
required property var modelData
|
||||||
|
|
||||||
readonly property var screen: modelData
|
readonly property var screen: modelData
|
||||||
|
readonly property string screenKey: SettingsData.getScreenDisplayName(screen)
|
||||||
|
|
||||||
function shouldShowOnScreen(prefs) {
|
function shouldShowOnScreen(prefs) {
|
||||||
if (!Array.isArray(prefs) || prefs.length === 0 || prefs.includes("all"))
|
if (!Array.isArray(prefs) || prefs.length === 0 || prefs.includes("all"))
|
||||||
return true;
|
return true;
|
||||||
return prefs.some(p => p.name === modelData.name);
|
return prefs.some(p => {
|
||||||
}
|
if (typeof p === "string")
|
||||||
|
return p === screenKey || p === modelData.name;
|
||||||
readonly property bool showBuiltinClock: SettingsData.desktopClockEnabled && shouldShowOnScreen(SettingsData.desktopClockDisplayPreferences)
|
return p?.name === modelData.name || p === screenKey;
|
||||||
|
|
||||||
readonly property bool showSystemMonitor: SettingsData.systemMonitorEnabled && shouldShowOnScreen(SettingsData.systemMonitorDisplayPreferences)
|
|
||||||
|
|
||||||
readonly property var visibleSystemMonitorVariants: {
|
|
||||||
if (!SettingsData.systemMonitorEnabled)
|
|
||||||
return [];
|
|
||||||
const variants = SettingsData.systemMonitorVariants || [];
|
|
||||||
return variants.filter(v => shouldShowOnScreen(v.config?.displayPreferences));
|
|
||||||
}
|
|
||||||
|
|
||||||
property var _pluginComponents: PluginService.pluginDesktopComponents
|
|
||||||
property var _pluginTrigger: 0
|
|
||||||
|
|
||||||
readonly property var visiblePlugins: {
|
|
||||||
void _pluginTrigger;
|
|
||||||
return Object.keys(_pluginComponents).filter(id => {
|
|
||||||
const prefs = PluginService.loadPluginData(id, "displayPreferences", ["all"]);
|
|
||||||
return shouldShowOnScreen(prefs);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
property var pluginServiceConnections: Connections {
|
|
||||||
target: PluginService
|
|
||||||
function onPluginDataChanged(pluginId) {
|
|
||||||
screenDelegate._pluginTrigger++;
|
|
||||||
}
|
|
||||||
function onPluginLoaded(pluginId) {
|
|
||||||
const plugin = PluginService.availablePlugins[pluginId];
|
|
||||||
if (plugin?.type === "desktop")
|
|
||||||
screenDelegate._pluginTrigger++;
|
|
||||||
}
|
|
||||||
function onPluginUnloaded(pluginId) {
|
|
||||||
screenDelegate._pluginTrigger++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property Loader clockLoader: Loader {
|
|
||||||
active: screenDelegate.showBuiltinClock
|
|
||||||
sourceComponent: Component {
|
|
||||||
DesktopPluginWrapper {
|
|
||||||
pluginId: "desktopClock"
|
|
||||||
pluginComponent: clockComponent
|
|
||||||
screen: screenDelegate.screen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property Component clockComponent: Component {
|
property Component clockComponent: Component {
|
||||||
DesktopClockWidget {}
|
DesktopClockWidget {}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Loader systemMonitorLoader: Loader {
|
|
||||||
active: screenDelegate.showSystemMonitor
|
|
||||||
sourceComponent: Component {
|
|
||||||
DesktopPluginWrapper {
|
|
||||||
pluginId: "systemMonitor"
|
|
||||||
pluginComponent: systemMonitorComponent
|
|
||||||
screen: screenDelegate.screen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property Component systemMonitorComponent: Component {
|
property Component systemMonitorComponent: Component {
|
||||||
SystemMonitorWidget {}
|
SystemMonitorWidget {}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Instantiator sysMonVariantInstantiator: Instantiator {
|
property Instantiator widgetInstantiator: Instantiator {
|
||||||
model: screenDelegate.visibleSystemMonitorVariants
|
model: ScriptModel {
|
||||||
|
objectProp: "id"
|
||||||
|
values: SettingsData.desktopWidgetInstances
|
||||||
|
}
|
||||||
|
|
||||||
DesktopPluginWrapper {
|
DesktopPluginWrapper {
|
||||||
required property var modelData
|
required property var modelData
|
||||||
|
required property int index
|
||||||
|
|
||||||
pluginId: "systemMonitor"
|
readonly property string instanceIdRef: modelData.id
|
||||||
variantId: modelData.id
|
readonly property var liveInstanceData: {
|
||||||
variantData: modelData
|
const instances = SettingsData.desktopWidgetInstances || [];
|
||||||
pluginComponent: screenDelegate.systemMonitorComponent
|
return instances.find(inst => inst.id === instanceIdRef) ?? modelData;
|
||||||
screen: screenDelegate.screen
|
}
|
||||||
}
|
|
||||||
}
|
readonly property bool shouldBeVisible: {
|
||||||
|
if (!liveInstanceData.enabled)
|
||||||
property Instantiator pluginInstantiator: Instantiator {
|
return false;
|
||||||
model: screenDelegate.visiblePlugins
|
const prefs = liveInstanceData.config?.displayPreferences ?? ["all"];
|
||||||
|
return screenDelegate.shouldShowOnScreen(prefs);
|
||||||
DesktopPluginWrapper {
|
}
|
||||||
required property string modelData
|
|
||||||
|
pluginId: liveInstanceData.widgetType
|
||||||
pluginId: modelData
|
instanceId: instanceIdRef
|
||||||
pluginComponent: PluginService.pluginDesktopComponents[modelData]
|
instanceData: liveInstanceData
|
||||||
pluginService: PluginService
|
builtinComponent: {
|
||||||
|
switch (liveInstanceData.widgetType) {
|
||||||
|
case "desktopClock":
|
||||||
|
return screenDelegate.clockComponent;
|
||||||
|
case "systemMonitor":
|
||||||
|
return screenDelegate.systemMonitorComponent;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pluginService: (liveInstanceData.widgetType !== "desktopClock" && liveInstanceData.widgetType !== "systemMonitor") ? PluginService : null
|
||||||
screen: screenDelegate.screen
|
screen: screenDelegate.screen
|
||||||
|
visible: shouldBeVisible
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,20 +6,34 @@ Item {
|
|||||||
|
|
||||||
property var pluginService: null
|
property var pluginService: null
|
||||||
property string pluginId: ""
|
property string pluginId: ""
|
||||||
|
property string instanceId: ""
|
||||||
|
property var instanceData: null
|
||||||
|
|
||||||
property real widgetWidth: 200
|
property real widgetWidth: 200
|
||||||
property real widgetHeight: 200
|
property real widgetHeight: 200
|
||||||
property real minWidth: 100
|
property real minWidth: 100
|
||||||
property real minHeight: 100
|
property real minHeight: 100
|
||||||
|
|
||||||
property var pluginData: ({})
|
readonly property bool isInstance: instanceId !== "" && instanceData !== null
|
||||||
|
readonly property var instanceConfig: instanceData?.config ?? {}
|
||||||
|
|
||||||
|
property var pluginData: isInstance ? instanceConfig : _globalPluginData
|
||||||
|
property var _globalPluginData: ({})
|
||||||
|
|
||||||
Component.onCompleted: loadPluginData()
|
Component.onCompleted: loadPluginData()
|
||||||
onPluginServiceChanged: loadPluginData()
|
onPluginServiceChanged: loadPluginData()
|
||||||
onPluginIdChanged: loadPluginData()
|
onPluginIdChanged: loadPluginData()
|
||||||
|
onInstanceDataChanged: {
|
||||||
|
if (isInstance)
|
||||||
|
Qt.callLater(() => {
|
||||||
|
pluginData = instanceConfig;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: pluginService
|
target: pluginService
|
||||||
|
enabled: pluginService !== null
|
||||||
|
|
||||||
function onPluginDataChanged(changedPluginId) {
|
function onPluginDataChanged(changedPluginId) {
|
||||||
if (changedPluginId !== pluginId)
|
if (changedPluginId !== pluginId)
|
||||||
return;
|
return;
|
||||||
@@ -29,10 +43,14 @@ Item {
|
|||||||
|
|
||||||
function loadPluginData() {
|
function loadPluginData() {
|
||||||
if (!pluginService || !pluginId) {
|
if (!pluginService || !pluginId) {
|
||||||
pluginData = {};
|
_globalPluginData = {};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pluginData = SettingsData.getPluginSettingsForPlugin(pluginId);
|
if (isInstance) {
|
||||||
|
pluginData = instanceConfig;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_globalPluginData = SettingsData.getPluginSettingsForPlugin(pluginId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getData(key, defaultValue) {
|
function getData(key, defaultValue) {
|
||||||
|
|||||||
@@ -11,16 +11,71 @@ Item {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property string pluginId
|
required property string pluginId
|
||||||
required property var pluginComponent
|
|
||||||
required property var screen
|
required property var screen
|
||||||
|
|
||||||
|
property var builtinComponent: null
|
||||||
property var pluginService: null
|
property var pluginService: null
|
||||||
property string variantId: ""
|
property string instanceId: ""
|
||||||
property var variantData: null
|
property var instanceData: null
|
||||||
|
|
||||||
readonly property string settingsKey: variantId ? variantId : pluginId
|
readonly property bool isBuiltin: pluginId === "desktopClock" || pluginId === "systemMonitor"
|
||||||
readonly property bool isVariant: variantId !== "" && variantData !== null
|
readonly property var activeComponent: isBuiltin ? builtinComponent : PluginService.pluginDesktopComponents[pluginId] ?? null
|
||||||
readonly property bool usePluginService: pluginService !== null && !isVariant
|
|
||||||
|
Connections {
|
||||||
|
target: PluginService
|
||||||
|
enabled: !root.isBuiltin
|
||||||
|
|
||||||
|
function onPluginLoaded(loadedPluginId) {
|
||||||
|
if (loadedPluginId === root.pluginId)
|
||||||
|
contentLoader.reloadComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPluginUnloaded(unloadedPluginId) {
|
||||||
|
if (unloadedPluginId === root.pluginId)
|
||||||
|
contentLoader.reloadComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property string settingsKey: instanceId ? instanceId : pluginId
|
||||||
|
readonly property bool isInstance: instanceId !== "" && instanceData !== null
|
||||||
|
readonly property bool usePluginService: pluginService !== null && !isInstance
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: instanceScopedPluginService
|
||||||
|
|
||||||
|
readonly property var availablePlugins: PluginService.availablePlugins
|
||||||
|
readonly property var loadedPlugins: PluginService.loadedPlugins
|
||||||
|
readonly property var pluginDesktopComponents: PluginService.pluginDesktopComponents
|
||||||
|
|
||||||
|
signal pluginDataChanged(string pluginId)
|
||||||
|
signal pluginLoaded(string pluginId)
|
||||||
|
signal pluginUnloaded(string pluginId)
|
||||||
|
|
||||||
|
function loadPluginData(pluginId, key, defaultValue) {
|
||||||
|
const cfg = root.instanceData?.config;
|
||||||
|
if (cfg && key in cfg)
|
||||||
|
return cfg[key];
|
||||||
|
return SettingsData.getPluginSetting(pluginId, key, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
function savePluginData(pluginId, key, value) {
|
||||||
|
if (!root.instanceId)
|
||||||
|
return false;
|
||||||
|
var updates = {};
|
||||||
|
updates[key] = value;
|
||||||
|
SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, updates);
|
||||||
|
Qt.callLater(() => pluginDataChanged(pluginId));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPluginVariants(pluginId) {
|
||||||
|
return PluginService.getPluginVariants(pluginId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPluginLoaded(pluginId) {
|
||||||
|
return PluginService.isPluginLoaded(pluginId);
|
||||||
|
}
|
||||||
|
}
|
||||||
readonly property string screenKey: SettingsData.getScreenDisplayName(screen)
|
readonly property string screenKey: SettingsData.getScreenDisplayName(screen)
|
||||||
|
|
||||||
readonly property int screenWidth: screen?.width ?? 1920
|
readonly property int screenWidth: screen?.width ?? 1920
|
||||||
@@ -34,45 +89,45 @@ Item {
|
|||||||
property real previewHeight: widgetHeight
|
property real previewHeight: widgetHeight
|
||||||
|
|
||||||
readonly property bool hasSavedPosition: {
|
readonly property bool hasSavedPosition: {
|
||||||
if (isVariant)
|
if (isInstance)
|
||||||
return variantData?.positions?.[screenKey]?.x !== undefined;
|
return instanceData?.positions?.[screenKey]?.x !== undefined;
|
||||||
if (usePluginService)
|
if (usePluginService)
|
||||||
return pluginService.loadPluginData(pluginId, "desktopX_" + screenKey, null) !== null;
|
return pluginService.loadPluginData(pluginId, "desktopX_" + screenKey, null) !== null;
|
||||||
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "x", null) !== null;
|
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "x", null) !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool hasSavedSize: {
|
readonly property bool hasSavedSize: {
|
||||||
if (isVariant)
|
if (isInstance)
|
||||||
return variantData?.positions?.[screenKey]?.width !== undefined;
|
return instanceData?.positions?.[screenKey]?.width !== undefined;
|
||||||
if (usePluginService)
|
if (usePluginService)
|
||||||
return pluginService.loadPluginData(pluginId, "desktopWidth_" + screenKey, null) !== null;
|
return pluginService.loadPluginData(pluginId, "desktopWidth_" + screenKey, null) !== null;
|
||||||
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "width", null) !== null;
|
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "width", null) !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
property real savedX: {
|
property real savedX: {
|
||||||
if (isVariant)
|
if (isInstance)
|
||||||
return variantData?.positions?.[screenKey]?.x ?? (screenWidth / 2 - savedWidth / 2);
|
return instanceData?.positions?.[screenKey]?.x ?? (screenWidth / 2 - savedWidth / 2);
|
||||||
if (usePluginService)
|
if (usePluginService)
|
||||||
return pluginService.loadPluginData(pluginId, "desktopX_" + screenKey, screenWidth / 2 - savedWidth / 2);
|
return pluginService.loadPluginData(pluginId, "desktopX_" + screenKey, screenWidth / 2 - savedWidth / 2);
|
||||||
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "x", screenWidth / 2 - savedWidth / 2);
|
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "x", screenWidth / 2 - savedWidth / 2);
|
||||||
}
|
}
|
||||||
property real savedY: {
|
property real savedY: {
|
||||||
if (isVariant)
|
if (isInstance)
|
||||||
return variantData?.positions?.[screenKey]?.y ?? (screenHeight / 2 - savedHeight / 2);
|
return instanceData?.positions?.[screenKey]?.y ?? (screenHeight / 2 - savedHeight / 2);
|
||||||
if (usePluginService)
|
if (usePluginService)
|
||||||
return pluginService.loadPluginData(pluginId, "desktopY_" + screenKey, screenHeight / 2 - savedHeight / 2);
|
return pluginService.loadPluginData(pluginId, "desktopY_" + screenKey, screenHeight / 2 - savedHeight / 2);
|
||||||
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "y", screenHeight / 2 - savedHeight / 2);
|
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "y", screenHeight / 2 - savedHeight / 2);
|
||||||
}
|
}
|
||||||
property real savedWidth: {
|
property real savedWidth: {
|
||||||
if (isVariant)
|
if (isInstance)
|
||||||
return variantData?.positions?.[screenKey]?.width ?? 280;
|
return instanceData?.positions?.[screenKey]?.width ?? 280;
|
||||||
if (usePluginService)
|
if (usePluginService)
|
||||||
return pluginService.loadPluginData(pluginId, "desktopWidth_" + screenKey, 200);
|
return pluginService.loadPluginData(pluginId, "desktopWidth_" + screenKey, 200);
|
||||||
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "width", 280);
|
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "width", 280);
|
||||||
}
|
}
|
||||||
property real savedHeight: {
|
property real savedHeight: {
|
||||||
if (isVariant)
|
if (isInstance)
|
||||||
return variantData?.positions?.[screenKey]?.height ?? 180;
|
return instanceData?.positions?.[screenKey]?.height ?? 180;
|
||||||
if (usePluginService)
|
if (usePluginService)
|
||||||
return pluginService.loadPluginData(pluginId, "desktopHeight_" + screenKey, 200);
|
return pluginService.loadPluginData(pluginId, "desktopHeight_" + screenKey, 200);
|
||||||
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "height", 180);
|
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "height", 180);
|
||||||
@@ -102,17 +157,9 @@ Item {
|
|||||||
return Math.round(value / gridSize) * gridSize;
|
return Math.round(value / gridSize) * gridSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateVariantPositions(updates) {
|
|
||||||
const positions = JSON.parse(JSON.stringify(variantData?.positions || {}));
|
|
||||||
positions[screenKey] = Object.assign({}, positions[screenKey] || {}, updates);
|
|
||||||
SettingsData.updateSystemMonitorVariant(variantId, {
|
|
||||||
positions: positions
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function savePosition() {
|
function savePosition() {
|
||||||
if (isVariant && variantData) {
|
if (isInstance && instanceData) {
|
||||||
updateVariantPositions({
|
SettingsData.updateDesktopWidgetInstancePosition(instanceId, screenKey, {
|
||||||
x: root.widgetX,
|
x: root.widgetX,
|
||||||
y: root.widgetY
|
y: root.widgetY
|
||||||
});
|
});
|
||||||
@@ -130,8 +177,8 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function saveSize() {
|
function saveSize() {
|
||||||
if (isVariant && variantData) {
|
if (isInstance && instanceData) {
|
||||||
updateVariantPositions({
|
SettingsData.updateDesktopWidgetInstancePosition(instanceId, screenKey, {
|
||||||
width: root.widgetWidth,
|
width: root.widgetWidth,
|
||||||
height: root.widgetHeight
|
height: root.widgetHeight
|
||||||
});
|
});
|
||||||
@@ -151,10 +198,10 @@ Item {
|
|||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: widgetWindow
|
id: widgetWindow
|
||||||
screen: root.screen
|
screen: root.screen
|
||||||
visible: root.visible
|
visible: root.visible && root.activeComponent !== null
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
WlrLayershell.namespace: "quickshell:desktop-widget:" + root.pluginId + (root.variantId ? ":" + root.variantId : "")
|
WlrLayershell.namespace: "quickshell:desktop-widget:" + root.pluginId + (root.instanceId ? ":" + root.instanceId : "")
|
||||||
WlrLayershell.layer: WlrLayer.Bottom
|
WlrLayershell.layer: WlrLayer.Bottom
|
||||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||||
WlrLayershell.keyboardFocus: {
|
WlrLayershell.keyboardFocus: {
|
||||||
@@ -210,19 +257,41 @@ Item {
|
|||||||
Loader {
|
Loader {
|
||||||
id: contentLoader
|
id: contentLoader
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
sourceComponent: root.pluginComponent
|
sourceComponent: root.activeComponent
|
||||||
|
|
||||||
|
function reloadComponent() {
|
||||||
|
active = false;
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateInstanceData() {
|
||||||
|
if (!item || item.instanceData === undefined)
|
||||||
|
return;
|
||||||
|
item.instanceData = root.instanceData;
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
enabled: contentLoader.item !== null
|
||||||
|
|
||||||
|
function onInstanceDataChanged() {
|
||||||
|
contentLoader.updateInstanceData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
if (!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
if (root.usePluginService) {
|
|
||||||
item.pluginService = root.pluginService;
|
if (item.pluginService !== undefined) {
|
||||||
item.pluginId = root.pluginId;
|
item.pluginService = root.isInstance ? instanceScopedPluginService : root.pluginService;
|
||||||
}
|
}
|
||||||
if (item.variantId !== undefined)
|
if (item.pluginId !== undefined)
|
||||||
item.variantId = root.variantId;
|
item.pluginId = root.pluginId;
|
||||||
if (item.variantData !== undefined)
|
if (item.instanceId !== undefined)
|
||||||
item.variantData = Qt.binding(() => root.variantData);
|
item.instanceId = root.instanceId;
|
||||||
|
if (item.instanceData !== undefined)
|
||||||
|
item.instanceData = root.instanceData;
|
||||||
if (!root.hasSavedSize) {
|
if (!root.hasSavedSize) {
|
||||||
const defW = item.defaultWidth ?? item.widgetWidth ?? 280;
|
const defW = item.defaultWidth ?? item.widgetWidth ?? 280;
|
||||||
const defH = item.defaultHeight ?? item.widgetHeight ?? 180;
|
const defH = item.defaultHeight ?? item.widgetHeight ?? 180;
|
||||||
|
|||||||
@@ -19,17 +19,16 @@ Item {
|
|||||||
height: implicitHeight
|
height: implicitHeight
|
||||||
|
|
||||||
readonly property bool isDesktopPlugin: {
|
readonly property bool isDesktopPlugin: {
|
||||||
if (!pluginService || !pluginId)
|
if (!pluginService?.availablePlugins || !pluginId)
|
||||||
return false;
|
return false;
|
||||||
const plugin = pluginService.availablePlugins[pluginId];
|
const plugin = pluginService.availablePlugins[pluginId];
|
||||||
return plugin?.type === "desktop";
|
return plugin?.type === "desktop";
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool hasPermission: {
|
readonly property bool hasPermission: {
|
||||||
if (!pluginService || !pluginId)
|
if (!pluginService?.availablePlugins || !pluginId)
|
||||||
return true;
|
return true;
|
||||||
const allPlugins = pluginService.availablePlugins;
|
const plugin = pluginService.availablePlugins[pluginId];
|
||||||
const plugin = allPlugins[pluginId];
|
|
||||||
if (!plugin)
|
if (!plugin)
|
||||||
return true;
|
return true;
|
||||||
const permissions = Array.isArray(plugin.permissions) ? plugin.permissions : [];
|
const permissions = Array.isArray(plugin.permissions) ? plugin.permissions : [];
|
||||||
@@ -63,15 +62,27 @@ Item {
|
|||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: pluginService
|
target: pluginService
|
||||||
|
enabled: pluginService !== null
|
||||||
|
|
||||||
function onPluginDataChanged(changedPluginId) {
|
function onPluginDataChanged(changedPluginId) {
|
||||||
if (changedPluginId === pluginId) {
|
if (changedPluginId === pluginId) {
|
||||||
loadVariants();
|
loadVariants();
|
||||||
|
reloadChildValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadChildValues() {
|
||||||
|
for (let i = 0; i < content.length; i++) {
|
||||||
|
const child = content[i];
|
||||||
|
if (child.loadValue) {
|
||||||
|
child.loadValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadVariants() {
|
function loadVariants() {
|
||||||
if (!pluginService || !pluginId) {
|
if (!pluginService?.getPluginVariants || !pluginId) {
|
||||||
variants = [];
|
variants = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -95,21 +106,21 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createVariant(variantName, variantConfig) {
|
function createVariant(variantName, variantConfig) {
|
||||||
if (!pluginService || !pluginId) {
|
if (!pluginService?.createPluginVariant || !pluginId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return pluginService.createPluginVariant(pluginId, variantName, variantConfig);
|
return pluginService.createPluginVariant(pluginId, variantName, variantConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeVariant(variantId) {
|
function removeVariant(variantId) {
|
||||||
if (!pluginService || !pluginId) {
|
if (!pluginService?.removePluginVariant || !pluginId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pluginService.removePluginVariant(pluginId, variantId);
|
pluginService.removePluginVariant(pluginId, variantId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateVariant(variantId, variantConfig) {
|
function updateVariant(variantId, variantConfig) {
|
||||||
if (!pluginService || !pluginId) {
|
if (!pluginService?.updatePluginVariant || !pluginId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pluginService.updatePluginVariant(pluginId, variantId, variantConfig);
|
pluginService.updatePluginVariant(pluginId, variantId, variantConfig);
|
||||||
|
|||||||
417
quickshell/Modules/Settings/DesktopWidgetBrowser.qml
Normal file
417
quickshell/Modules/Settings/DesktopWidgetBrowser.qml
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
FloatingWindow {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string searchQuery: ""
|
||||||
|
property var filteredWidgets: []
|
||||||
|
property int selectedIndex: -1
|
||||||
|
property bool keyboardNavigationActive: false
|
||||||
|
property var parentModal: null
|
||||||
|
|
||||||
|
signal closed
|
||||||
|
signal widgetAdded(string widgetType)
|
||||||
|
|
||||||
|
function updateFilteredWidgets() {
|
||||||
|
const allWidgets = DesktopWidgetRegistry.registeredWidgetsList || [];
|
||||||
|
if (!searchQuery || searchQuery.length === 0) {
|
||||||
|
filteredWidgets = allWidgets.slice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var filtered = [];
|
||||||
|
var query = searchQuery.toLowerCase();
|
||||||
|
|
||||||
|
for (var i = 0; i < allWidgets.length; i++) {
|
||||||
|
var widget = allWidgets[i];
|
||||||
|
var name = widget.name ? widget.name.toLowerCase() : "";
|
||||||
|
var description = widget.description ? widget.description.toLowerCase() : "";
|
||||||
|
var id = widget.id ? widget.id.toLowerCase() : "";
|
||||||
|
|
||||||
|
if (name.indexOf(query) !== -1 || description.indexOf(query) !== -1 || id.indexOf(query) !== -1)
|
||||||
|
filtered.push(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredWidgets = filtered;
|
||||||
|
selectedIndex = -1;
|
||||||
|
keyboardNavigationActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectNext() {
|
||||||
|
if (filteredWidgets.length === 0)
|
||||||
|
return;
|
||||||
|
keyboardNavigationActive = true;
|
||||||
|
selectedIndex = Math.min(selectedIndex + 1, filteredWidgets.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPrevious() {
|
||||||
|
if (filteredWidgets.length === 0)
|
||||||
|
return;
|
||||||
|
keyboardNavigationActive = true;
|
||||||
|
selectedIndex = Math.max(selectedIndex - 1, -1);
|
||||||
|
if (selectedIndex === -1)
|
||||||
|
keyboardNavigationActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectWidget() {
|
||||||
|
if (selectedIndex < 0 || selectedIndex >= filteredWidgets.length)
|
||||||
|
return;
|
||||||
|
var widget = filteredWidgets[selectedIndex];
|
||||||
|
addWidget(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addWidget(widget) {
|
||||||
|
const widgetType = widget.id;
|
||||||
|
const defaultConfig = DesktopWidgetRegistry.getDefaultConfig(widgetType);
|
||||||
|
const name = widget.name || widgetType;
|
||||||
|
SettingsData.createDesktopWidgetInstance(widgetType, name, defaultConfig);
|
||||||
|
root.widgetAdded(widgetType);
|
||||||
|
root.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
updateFilteredWidgets();
|
||||||
|
if (parentModal)
|
||||||
|
parentModal.shouldHaveFocus = false;
|
||||||
|
visible = true;
|
||||||
|
Qt.callLater(() => {
|
||||||
|
searchField.forceActiveFocus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
visible = false;
|
||||||
|
root.closed();
|
||||||
|
if (!parentModal)
|
||||||
|
return;
|
||||||
|
parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible);
|
||||||
|
Qt.callLater(() => {
|
||||||
|
if (parentModal && parentModal.modalFocusScope)
|
||||||
|
parentModal.modalFocusScope.forceActiveFocus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
objectName: "desktopWidgetBrowser"
|
||||||
|
title: I18n.tr("Add Desktop Widget")
|
||||||
|
minimumSize: Qt.size(400, 350)
|
||||||
|
implicitWidth: 500
|
||||||
|
implicitHeight: 550
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
onVisibleChanged: {
|
||||||
|
if (visible) {
|
||||||
|
updateFilteredWidgets();
|
||||||
|
Qt.callLater(() => {
|
||||||
|
searchField.forceActiveFocus();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
searchQuery = "";
|
||||||
|
filteredWidgets = [];
|
||||||
|
selectedIndex = -1;
|
||||||
|
keyboardNavigationActive = false;
|
||||||
|
if (!parentModal)
|
||||||
|
return;
|
||||||
|
parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible);
|
||||||
|
Qt.callLater(() => {
|
||||||
|
if (parentModal && parentModal.modalFocusScope)
|
||||||
|
parentModal.modalFocusScope.forceActiveFocus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: DesktopWidgetRegistry
|
||||||
|
function onRegistryChanged() {
|
||||||
|
if (root.visible)
|
||||||
|
root.updateFilteredWidgets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FocusScope {
|
||||||
|
id: widgetKeyHandler
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
focus: true
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
switch (event.key) {
|
||||||
|
case Qt.Key_Escape:
|
||||||
|
root.hide();
|
||||||
|
event.accepted = true;
|
||||||
|
return;
|
||||||
|
case Qt.Key_Down:
|
||||||
|
root.selectNext();
|
||||||
|
event.accepted = true;
|
||||||
|
return;
|
||||||
|
case Qt.Key_Up:
|
||||||
|
root.selectPrevious();
|
||||||
|
event.accepted = true;
|
||||||
|
return;
|
||||||
|
case Qt.Key_Return:
|
||||||
|
case Qt.Key_Enter:
|
||||||
|
if (root.keyboardNavigationActive) {
|
||||||
|
root.selectWidget();
|
||||||
|
} else if (root.filteredWidgets.length > 0) {
|
||||||
|
root.addWidget(root.filteredWidgets[0]);
|
||||||
|
}
|
||||||
|
event.accepted = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.modifiers & Qt.ControlModifier) {
|
||||||
|
switch (event.key) {
|
||||||
|
case Qt.Key_N:
|
||||||
|
case Qt.Key_J:
|
||||||
|
root.selectNext();
|
||||||
|
event.accepted = true;
|
||||||
|
return;
|
||||||
|
case Qt.Key_P:
|
||||||
|
case Qt.Key_K:
|
||||||
|
root.selectPrevious();
|
||||||
|
event.accepted = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: titleBar
|
||||||
|
width: parent.width
|
||||||
|
height: 48
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Theme.withAlpha(Theme.surfaceContainer, 0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Theme.spacingL
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "add_circle"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Add Desktop Widget")
|
||||||
|
font.pixelSize: Theme.fontSizeXLarge
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
circular: false
|
||||||
|
iconName: "close"
|
||||||
|
iconSize: Theme.iconSize - 4
|
||||||
|
iconColor: Theme.surfaceText
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onClicked: root.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height - titleBar.height
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: contentColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingL
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Select a widget to add to your desktop. Each widget is a separate instance with its own settings.")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.outline
|
||||||
|
width: parent.width
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
id: searchField
|
||||||
|
width: parent.width
|
||||||
|
height: 48
|
||||||
|
cornerRadius: Theme.cornerRadius
|
||||||
|
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||||
|
normalBorderColor: Theme.outlineMedium
|
||||||
|
focusedBorderColor: Theme.primary
|
||||||
|
leftIconName: "search"
|
||||||
|
leftIconSize: Theme.iconSize
|
||||||
|
leftIconColor: Theme.surfaceVariantText
|
||||||
|
leftIconFocusedColor: Theme.primary
|
||||||
|
showClearButton: true
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
placeholderText: I18n.tr("Search widgets...")
|
||||||
|
text: root.searchQuery
|
||||||
|
focus: true
|
||||||
|
ignoreLeftRightKeys: true
|
||||||
|
keyForwardTargets: [widgetKeyHandler]
|
||||||
|
onTextEdited: {
|
||||||
|
root.searchQuery = text;
|
||||||
|
root.updateFilteredWidgets();
|
||||||
|
}
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Escape) {
|
||||||
|
root.hide();
|
||||||
|
event.accepted = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0))
|
||||||
|
event.accepted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankListView {
|
||||||
|
id: widgetList
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height - y
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
model: root.filteredWidgets
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: delegateRoot
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
width: widgetList.width
|
||||||
|
height: 72
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex
|
||||||
|
color: isSelected ? Theme.primarySelected : widgetArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.surfaceVariant, 0.3)
|
||||||
|
border.color: isSelected ? Theme.primary : Theme.withAlpha(Theme.outline, 0.2)
|
||||||
|
border.width: isSelected ? 2 : 1
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingM
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 44
|
||||||
|
height: 44
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.primarySelected
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: delegateRoot.modelData.icon || "widgets"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: 2
|
||||||
|
width: parent.width - 44 - Theme.iconSize - Theme.spacingM * 3
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: delegateRoot.modelData.name || delegateRoot.modelData.id
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
visible: delegateRoot.modelData.type === "plugin"
|
||||||
|
width: pluginLabel.implicitWidth + Theme.spacingXS * 2
|
||||||
|
height: 18
|
||||||
|
radius: 9
|
||||||
|
color: Theme.withAlpha(Theme.secondary, 0.15)
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: pluginLabel
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: I18n.tr("Plugin")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall - 2
|
||||||
|
color: Theme.secondary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: delegateRoot.modelData.description || ""
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.outline
|
||||||
|
elide: Text.ElideRight
|
||||||
|
width: parent.width
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
maximumLineCount: 2
|
||||||
|
visible: text !== ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "add"
|
||||||
|
size: Theme.iconSize - 4
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: widgetArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: root.addWidget(delegateRoot.modelData)
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: Item {
|
||||||
|
width: widgetList.width
|
||||||
|
height: emptyText.visible ? 60 : 0
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: emptyText
|
||||||
|
visible: root.filteredWidgets.length === 0
|
||||||
|
text: root.searchQuery.length > 0 ? I18n.tr("No widgets match your search") : I18n.tr("No widgets available")
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
width: parent.width
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
158
quickshell/Modules/Settings/DesktopWidgetInstanceCard.qml
Normal file
158
quickshell/Modules/Settings/DesktopWidgetInstanceCard.qml
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
import qs.Modules.Settings.Widgets
|
||||||
|
import qs.Modules.Settings.DesktopWidgetSettings as DWS
|
||||||
|
|
||||||
|
SettingsCard {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var instanceData
|
||||||
|
property bool isExpanded: false
|
||||||
|
|
||||||
|
readonly property string instanceId: instanceData?.id ?? ""
|
||||||
|
readonly property string widgetType: instanceData?.widgetType ?? ""
|
||||||
|
readonly property var widgetDef: DesktopWidgetRegistry.getWidget(widgetType)
|
||||||
|
readonly property string widgetName: instanceData?.name ?? widgetDef?.name ?? widgetType
|
||||||
|
|
||||||
|
signal deleteRequested
|
||||||
|
|
||||||
|
property Component clockSettingsComponent: Component {
|
||||||
|
DWS.ClockSettings {}
|
||||||
|
}
|
||||||
|
|
||||||
|
property Component systemMonitorSettingsComponent: Component {
|
||||||
|
DWS.SystemMonitorSettings {}
|
||||||
|
}
|
||||||
|
|
||||||
|
property Component pluginSettingsComponent: Component {
|
||||||
|
DWS.PluginDesktopWidgetSettings {
|
||||||
|
instanceId: root.instanceId
|
||||||
|
instanceData: root.instanceData
|
||||||
|
widgetType: root.widgetType
|
||||||
|
widgetDef: root.widgetDef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
width: parent?.width ?? 400
|
||||||
|
iconName: widgetDef?.icon ?? "widgets"
|
||||||
|
title: widgetName
|
||||||
|
collapsible: true
|
||||||
|
expanded: isExpanded
|
||||||
|
|
||||||
|
onExpandedChanged: isExpanded = expanded
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width - toggleRow.width - deleteBtn.width - Theme.spacingS * 2
|
||||||
|
height: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: toggleRow
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: (instanceData?.enabled ?? true) ? I18n.tr("Enabled") : I18n.tr("Disabled")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
DankToggle {
|
||||||
|
checked: instanceData?.enabled ?? true
|
||||||
|
onToggled: isChecked => {
|
||||||
|
if (!root.instanceId) return;
|
||||||
|
SettingsData.updateDesktopWidgetInstance(root.instanceId, { enabled: isChecked });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
id: deleteBtn
|
||||||
|
iconName: "delete"
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
textColor: Theme.error
|
||||||
|
buttonHeight: 32
|
||||||
|
horizontalPadding: 4
|
||||||
|
onClicked: root.deleteRequested()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 0
|
||||||
|
visible: root.isExpanded
|
||||||
|
opacity: visible ? 1 : 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.mediumDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: nameRow.height + Theme.spacingM * 2
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: nameRow
|
||||||
|
x: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
width: parent.width - Theme.spacingM * 2
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Name")
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: 80
|
||||||
|
}
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
width: parent.width - 80 - Theme.spacingM
|
||||||
|
text: root.widgetName
|
||||||
|
onEditingFinished: {
|
||||||
|
if (!root.instanceId) return;
|
||||||
|
SettingsData.updateDesktopWidgetInstance(root.instanceId, { name: text });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: settingsLoader
|
||||||
|
width: parent.width
|
||||||
|
active: root.isExpanded && root.widgetType !== ""
|
||||||
|
|
||||||
|
sourceComponent: {
|
||||||
|
switch (root.widgetType) {
|
||||||
|
case "desktopClock":
|
||||||
|
return clockSettingsComponent;
|
||||||
|
case "systemMonitor":
|
||||||
|
return systemMonitorSettingsComponent;
|
||||||
|
default:
|
||||||
|
return pluginSettingsComponent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoaded: {
|
||||||
|
if (!item) return;
|
||||||
|
item.instanceId = root.instanceId;
|
||||||
|
item.instanceData = Qt.binding(() => root.instanceData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Widgets
|
||||||
|
import qs.Modules.Settings.Widgets
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string instanceId: ""
|
||||||
|
property var instanceData: null
|
||||||
|
|
||||||
|
readonly property var cfg: instanceData?.config ?? {}
|
||||||
|
|
||||||
|
function updateConfig(key, value) {
|
||||||
|
if (!instanceId)
|
||||||
|
return;
|
||||||
|
var updates = {};
|
||||||
|
updates[key] = value;
|
||||||
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, updates);
|
||||||
|
}
|
||||||
|
|
||||||
|
width: parent?.width ?? 400
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
SettingsDropdownRow {
|
||||||
|
text: I18n.tr("Clock Style")
|
||||||
|
options: [I18n.tr("Digital"), I18n.tr("Analog"), I18n.tr("Stacked")]
|
||||||
|
currentValue: {
|
||||||
|
switch (cfg.style) {
|
||||||
|
case "analog":
|
||||||
|
return I18n.tr("Analog");
|
||||||
|
case "stacked":
|
||||||
|
return I18n.tr("Stacked");
|
||||||
|
default:
|
||||||
|
return I18n.tr("Digital");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onValueChanged: value => {
|
||||||
|
switch (value) {
|
||||||
|
case I18n.tr("Analog"):
|
||||||
|
root.updateConfig("style", "analog");
|
||||||
|
return;
|
||||||
|
case I18n.tr("Stacked"):
|
||||||
|
root.updateConfig("style", "stacked");
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
root.updateConfig("style", "digital");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {
|
||||||
|
visible: cfg.style === "analog"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
visible: cfg.style === "analog"
|
||||||
|
text: I18n.tr("Show Hour Numbers")
|
||||||
|
checked: cfg.showAnalogNumbers ?? false
|
||||||
|
onToggled: checked => root.updateConfig("showAnalogNumbers", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {
|
||||||
|
visible: cfg.style === "analog"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
visible: cfg.style === "analog"
|
||||||
|
text: I18n.tr("Show Seconds")
|
||||||
|
checked: cfg.showAnalogSeconds ?? true
|
||||||
|
onToggled: checked => root.updateConfig("showAnalogSeconds", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Show Date")
|
||||||
|
checked: cfg.showDate ?? true
|
||||||
|
onToggled: checked => root.updateConfig("showDate", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsSliderRow {
|
||||||
|
text: I18n.tr("Transparency")
|
||||||
|
minimum: 0
|
||||||
|
maximum: 100
|
||||||
|
value: Math.round((cfg.transparency ?? 0.8) * 100)
|
||||||
|
unit: "%"
|
||||||
|
onSliderValueChanged: newValue => root.updateConfig("transparency", newValue / 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsColorPicker {
|
||||||
|
colorMode: cfg.colorMode ?? "primary"
|
||||||
|
customColor: cfg.customColor ?? "#ffffff"
|
||||||
|
onColorModeSelected: mode => root.updateConfig("colorMode", mode)
|
||||||
|
onCustomColorSelected: selectedColor => root.updateConfig("customColor", selectedColor.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsDisplayPicker {
|
||||||
|
displayPreferences: cfg.displayPreferences ?? ["all"]
|
||||||
|
onPreferencesChanged: prefs => root.updateConfig("displayPreferences", prefs)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: resetRow.height + Theme.spacingM * 2
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: resetRow
|
||||||
|
x: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: I18n.tr("Reset Position")
|
||||||
|
backgroundColor: Theme.surfaceHover
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
buttonHeight: 36
|
||||||
|
onClicked: {
|
||||||
|
if (!root.instanceId)
|
||||||
|
return;
|
||||||
|
SettingsData.updateDesktopWidgetInstance(root.instanceId, {
|
||||||
|
positions: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: I18n.tr("Reset Size")
|
||||||
|
backgroundColor: Theme.surfaceHover
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
buttonHeight: 36
|
||||||
|
onClicked: {
|
||||||
|
if (!root.instanceId)
|
||||||
|
return;
|
||||||
|
SettingsData.updateDesktopWidgetInstance(root.instanceId, {
|
||||||
|
positions: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
import qs.Modules.Settings.Widgets
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string instanceId: ""
|
||||||
|
property var instanceData: null
|
||||||
|
property string widgetType: ""
|
||||||
|
property var widgetDef: null
|
||||||
|
|
||||||
|
readonly property var cfg: instanceData?.config ?? {}
|
||||||
|
readonly property string settingsPath: widgetDef?.settingsComponent ?? ""
|
||||||
|
|
||||||
|
function updateConfig(key, value) {
|
||||||
|
if (!instanceId)
|
||||||
|
return;
|
||||||
|
var updates = {};
|
||||||
|
updates[key] = value;
|
||||||
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, updates);
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: instanceScopedPluginService
|
||||||
|
|
||||||
|
readonly property var availablePlugins: PluginService.availablePlugins
|
||||||
|
readonly property var loadedPlugins: PluginService.loadedPlugins
|
||||||
|
readonly property var pluginDesktopComponents: PluginService.pluginDesktopComponents
|
||||||
|
|
||||||
|
signal pluginDataChanged(string pluginId)
|
||||||
|
signal pluginLoaded(string pluginId)
|
||||||
|
signal pluginUnloaded(string pluginId)
|
||||||
|
|
||||||
|
function loadPluginData(pluginId, key, defaultValue) {
|
||||||
|
const cfg = root.instanceData?.config;
|
||||||
|
if (cfg && key in cfg)
|
||||||
|
return cfg[key];
|
||||||
|
return SettingsData.getPluginSetting(root.widgetType, key, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
function savePluginData(pluginId, key, value) {
|
||||||
|
root.updateConfig(key, value);
|
||||||
|
Qt.callLater(() => pluginDataChanged(root.widgetType));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPluginVariants(pluginId) {
|
||||||
|
return PluginService.getPluginVariants(pluginId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPluginLoaded(pluginId) {
|
||||||
|
return PluginService.isPluginLoaded(pluginId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
width: parent?.width ?? 400
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: pluginSettingsLoader
|
||||||
|
width: parent.width
|
||||||
|
active: root.settingsPath !== ""
|
||||||
|
|
||||||
|
source: root.settingsPath
|
||||||
|
|
||||||
|
onLoaded: {
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
if (item.instanceId !== undefined)
|
||||||
|
item.instanceId = root.instanceId;
|
||||||
|
if (item.instanceData !== undefined)
|
||||||
|
item.instanceData = Qt.binding(() => root.instanceData);
|
||||||
|
if (item.pluginService !== undefined)
|
||||||
|
item.pluginService = instanceScopedPluginService;
|
||||||
|
if (item.reloadChildValues)
|
||||||
|
Qt.callLater(item.reloadChildValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 0
|
||||||
|
visible: root.settingsPath === ""
|
||||||
|
|
||||||
|
SettingsDisplayPicker {
|
||||||
|
displayPreferences: cfg.displayPreferences ?? ["all"]
|
||||||
|
onPreferencesChanged: prefs => root.updateConfig("displayPreferences", prefs)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: resetRow.height + Theme.spacingM * 2
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: resetRow
|
||||||
|
x: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: I18n.tr("Reset Position")
|
||||||
|
backgroundColor: Theme.surfaceHover
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
buttonHeight: 36
|
||||||
|
onClicked: {
|
||||||
|
if (!root.instanceId)
|
||||||
|
return;
|
||||||
|
SettingsData.updateDesktopWidgetInstance(root.instanceId, {
|
||||||
|
positions: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: I18n.tr("Reset Size")
|
||||||
|
backgroundColor: Theme.surfaceHover
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
buttonHeight: 36
|
||||||
|
onClicked: {
|
||||||
|
if (!root.instanceId)
|
||||||
|
return;
|
||||||
|
SettingsData.updateDesktopWidgetInstance(root.instanceId, {
|
||||||
|
positions: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,444 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
import qs.Modules.Settings.Widgets
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string instanceId: ""
|
||||||
|
property var instanceData: null
|
||||||
|
|
||||||
|
readonly property var cfg: instanceData?.config ?? {}
|
||||||
|
|
||||||
|
function updateConfig(key, value) {
|
||||||
|
if (!instanceId)
|
||||||
|
return;
|
||||||
|
var updates = {};
|
||||||
|
updates[key] = value;
|
||||||
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, updates);
|
||||||
|
}
|
||||||
|
|
||||||
|
width: parent?.width ?? 400
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Show Header")
|
||||||
|
checked: cfg.showHeader ?? true
|
||||||
|
onToggled: checked => root.updateConfig("showHeader", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: graphIntervalColumn.height + Theme.spacingM * 2
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: graphIntervalColumn
|
||||||
|
width: parent.width - Theme.spacingM * 2
|
||||||
|
x: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Graph Time Range")
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButtonGroup {
|
||||||
|
model: ["1m", "5m", "10m", "30m"]
|
||||||
|
currentIndex: {
|
||||||
|
switch (cfg.graphInterval ?? 60) {
|
||||||
|
case 60:
|
||||||
|
return 0;
|
||||||
|
case 300:
|
||||||
|
return 1;
|
||||||
|
case 600:
|
||||||
|
return 2;
|
||||||
|
case 1800:
|
||||||
|
return 3;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buttonHeight: 32
|
||||||
|
minButtonWidth: 48
|
||||||
|
textSize: Theme.fontSizeSmall
|
||||||
|
checkEnabled: false
|
||||||
|
onSelectionChanged: (index, selected) => {
|
||||||
|
if (!selected)
|
||||||
|
return;
|
||||||
|
const values = [60, 300, 600, 1800];
|
||||||
|
root.updateConfig("graphInterval", values[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("CPU")
|
||||||
|
checked: cfg.showCpu ?? true
|
||||||
|
onToggled: checked => root.updateConfig("showCpu", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {
|
||||||
|
visible: cfg.showCpu ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
visible: cfg.showCpu ?? true
|
||||||
|
text: I18n.tr("CPU Graph")
|
||||||
|
checked: cfg.showCpuGraph ?? true
|
||||||
|
onToggled: checked => root.updateConfig("showCpuGraph", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {
|
||||||
|
visible: cfg.showCpu ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
visible: cfg.showCpu ?? true
|
||||||
|
text: I18n.tr("CPU Temperature")
|
||||||
|
checked: cfg.showCpuTemp ?? true
|
||||||
|
onToggled: checked => root.updateConfig("showCpuTemp", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("GPU Temperature")
|
||||||
|
checked: cfg.showGpuTemp ?? false
|
||||||
|
onToggled: checked => root.updateConfig("showGpuTemp", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {
|
||||||
|
visible: (cfg.showGpuTemp ?? false) && DgopService.availableGpus.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: gpuSelectColumn.height + Theme.spacingM * 2
|
||||||
|
visible: (cfg.showGpuTemp ?? false) && DgopService.availableGpus.length > 0
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: gpuSelectColumn
|
||||||
|
width: parent.width - Theme.spacingM * 2
|
||||||
|
x: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("GPU")
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: DgopService.availableGpus
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
readonly property bool isSelected: (cfg.gpuPciId ?? "") === modelData.pciId
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: 44
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: isSelected ? Theme.primarySelected : Theme.surfaceHover
|
||||||
|
border.color: isSelected ? Theme.primary : "transparent"
|
||||||
|
border.width: 2
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "videocam"
|
||||||
|
size: Theme.iconSizeSmall
|
||||||
|
color: isSelected ? Theme.primary : Theme.surfaceVariantText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width - Theme.iconSizeSmall - Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: modelData.displayName || "Unknown GPU"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
width: parent.width
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: modelData.driver || ""
|
||||||
|
font.pixelSize: Theme.fontSizeSmall - 2
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
visible: text !== ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: root.updateConfig("gpuPciId", modelData.pciId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Memory")
|
||||||
|
checked: cfg.showMemory ?? true
|
||||||
|
onToggled: checked => root.updateConfig("showMemory", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {
|
||||||
|
visible: cfg.showMemory ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
visible: cfg.showMemory ?? true
|
||||||
|
text: I18n.tr("Memory Graph")
|
||||||
|
checked: cfg.showMemoryGraph ?? true
|
||||||
|
onToggled: checked => root.updateConfig("showMemoryGraph", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Network")
|
||||||
|
checked: cfg.showNetwork ?? true
|
||||||
|
onToggled: checked => root.updateConfig("showNetwork", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {
|
||||||
|
visible: cfg.showNetwork ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
visible: cfg.showNetwork ?? true
|
||||||
|
text: I18n.tr("Network Graph")
|
||||||
|
checked: cfg.showNetworkGraph ?? true
|
||||||
|
onToggled: checked => root.updateConfig("showNetworkGraph", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Disk")
|
||||||
|
checked: cfg.showDisk ?? true
|
||||||
|
onToggled: checked => root.updateConfig("showDisk", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Top Processes")
|
||||||
|
checked: cfg.showTopProcesses ?? false
|
||||||
|
onToggled: checked => root.updateConfig("showTopProcesses", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {
|
||||||
|
visible: cfg.showTopProcesses ?? false
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: topProcessesColumn.height + Theme.spacingM * 2
|
||||||
|
visible: cfg.showTopProcesses ?? false
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: topProcessesColumn
|
||||||
|
width: parent.width - Theme.spacingM * 2
|
||||||
|
x: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
width: parent.width - processCountButtons.width - Theme.spacingM
|
||||||
|
text: I18n.tr("Process Count")
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButtonGroup {
|
||||||
|
id: processCountButtons
|
||||||
|
model: ["3", "5", "10"]
|
||||||
|
currentIndex: {
|
||||||
|
switch (cfg.topProcessCount ?? 3) {
|
||||||
|
case 3:
|
||||||
|
return 0;
|
||||||
|
case 5:
|
||||||
|
return 1;
|
||||||
|
case 10:
|
||||||
|
return 2;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buttonHeight: 32
|
||||||
|
minButtonWidth: 36
|
||||||
|
textSize: Theme.fontSizeSmall
|
||||||
|
checkEnabled: false
|
||||||
|
onSelectionChanged: (index, selected) => {
|
||||||
|
if (!selected)
|
||||||
|
return;
|
||||||
|
const values = [3, 5, 10];
|
||||||
|
root.updateConfig("topProcessCount", values[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
width: parent.width - sortByButtons.width - Theme.spacingM
|
||||||
|
text: I18n.tr("Sort By")
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButtonGroup {
|
||||||
|
id: sortByButtons
|
||||||
|
model: ["CPU", "MEM"]
|
||||||
|
currentIndex: (cfg.topProcessSortBy ?? "cpu") === "cpu" ? 0 : 1
|
||||||
|
buttonHeight: 32
|
||||||
|
minButtonWidth: 48
|
||||||
|
textSize: Theme.fontSizeSmall
|
||||||
|
checkEnabled: false
|
||||||
|
onSelectionChanged: (index, selected) => {
|
||||||
|
if (!selected)
|
||||||
|
return;
|
||||||
|
root.updateConfig("topProcessSortBy", index === 0 ? "cpu" : "memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsDropdownRow {
|
||||||
|
text: I18n.tr("Layout")
|
||||||
|
options: [I18n.tr("Auto"), I18n.tr("Grid"), I18n.tr("List")]
|
||||||
|
currentValue: {
|
||||||
|
switch (cfg.layoutMode ?? "auto") {
|
||||||
|
case "grid":
|
||||||
|
return I18n.tr("Grid");
|
||||||
|
case "list":
|
||||||
|
return I18n.tr("List");
|
||||||
|
default:
|
||||||
|
return I18n.tr("Auto");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onValueChanged: value => {
|
||||||
|
switch (value) {
|
||||||
|
case I18n.tr("Grid"):
|
||||||
|
root.updateConfig("layoutMode", "grid");
|
||||||
|
return;
|
||||||
|
case I18n.tr("List"):
|
||||||
|
root.updateConfig("layoutMode", "list");
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
root.updateConfig("layoutMode", "auto");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsSliderRow {
|
||||||
|
text: I18n.tr("Transparency")
|
||||||
|
minimum: 0
|
||||||
|
maximum: 100
|
||||||
|
value: Math.round((cfg.transparency ?? 0.8) * 100)
|
||||||
|
unit: "%"
|
||||||
|
onSliderValueChanged: newValue => root.updateConfig("transparency", newValue / 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsColorPicker {
|
||||||
|
colorMode: cfg.colorMode ?? "primary"
|
||||||
|
customColor: cfg.customColor ?? "#ffffff"
|
||||||
|
onColorModeSelected: mode => root.updateConfig("colorMode", mode)
|
||||||
|
onCustomColorSelected: selectedColor => root.updateConfig("customColor", selectedColor.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsDisplayPicker {
|
||||||
|
displayPreferences: cfg.displayPreferences ?? ["all"]
|
||||||
|
onPreferencesChanged: prefs => root.updateConfig("displayPreferences", prefs)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: resetRow.height + Theme.spacingM * 2
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: resetRow
|
||||||
|
x: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: I18n.tr("Reset Position")
|
||||||
|
backgroundColor: Theme.surfaceHover
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
buttonHeight: 36
|
||||||
|
onClicked: {
|
||||||
|
if (!root.instanceId)
|
||||||
|
return;
|
||||||
|
SettingsData.updateDesktopWidgetInstance(root.instanceId, {
|
||||||
|
positions: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: I18n.tr("Reset Size")
|
||||||
|
backgroundColor: Theme.surfaceHover
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
buttonHeight: 36
|
||||||
|
onClicked: {
|
||||||
|
if (!root.instanceId)
|
||||||
|
return;
|
||||||
|
SettingsData.updateDesktopWidgetInstance(root.instanceId, {
|
||||||
|
positions: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
@@ -9,6 +10,23 @@ import qs.Modules.Settings.Widgets
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property var expandedStates: ({})
|
||||||
|
property var parentModal: null
|
||||||
|
|
||||||
|
DesktopWidgetBrowser {
|
||||||
|
id: widgetBrowser
|
||||||
|
parentModal: root.parentModal
|
||||||
|
onWidgetAdded: widgetType => {
|
||||||
|
ToastService.showInfo(I18n.tr("Widget added"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginBrowser {
|
||||||
|
id: desktopPluginBrowser
|
||||||
|
parentModal: root.parentModal
|
||||||
|
typeFilter: "desktop-widget"
|
||||||
|
}
|
||||||
|
|
||||||
DankFlickable {
|
DankFlickable {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
clip: true
|
clip: true
|
||||||
@@ -23,686 +41,94 @@ Item {
|
|||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "schedule"
|
iconName: "widgets"
|
||||||
title: I18n.tr("Desktop Clock")
|
title: I18n.tr("Desktop Widgets")
|
||||||
collapsible: true
|
|
||||||
expanded: false
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
text: I18n.tr("Enable Desktop Clock")
|
|
||||||
checked: SettingsData.desktopClockEnabled
|
|
||||||
onToggled: checked => SettingsData.set("desktopClockEnabled", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
width: parent.width
|
width: parent.width - Theme.spacingM * 2
|
||||||
spacing: 0
|
x: Theme.spacingM
|
||||||
visible: SettingsData.desktopClockEnabled
|
spacing: Theme.spacingM
|
||||||
opacity: visible ? 1 : 0
|
|
||||||
|
|
||||||
Behavior on opacity {
|
StyledText {
|
||||||
NumberAnimation {
|
|
||||||
duration: Theme.mediumDuration
|
|
||||||
easing.type: Theme.emphasizedEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsDropdownRow {
|
|
||||||
text: I18n.tr("Clock Style")
|
|
||||||
options: [I18n.tr("Digital"), I18n.tr("Analog"), I18n.tr("Stacked")]
|
|
||||||
currentValue: {
|
|
||||||
switch (SettingsData.desktopClockStyle) {
|
|
||||||
case "analog":
|
|
||||||
return I18n.tr("Analog");
|
|
||||||
case "stacked":
|
|
||||||
return I18n.tr("Stacked");
|
|
||||||
default:
|
|
||||||
return I18n.tr("Digital");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onValueChanged: value => {
|
|
||||||
switch (value) {
|
|
||||||
case I18n.tr("Analog"):
|
|
||||||
SettingsData.set("desktopClockStyle", "analog");
|
|
||||||
return;
|
|
||||||
case I18n.tr("Stacked"):
|
|
||||||
SettingsData.set("desktopClockStyle", "stacked");
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
SettingsData.set("desktopClockStyle", "digital");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {
|
|
||||||
visible: SettingsData.desktopClockStyle === "analog"
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
visible: SettingsData.desktopClockStyle === "analog"
|
|
||||||
text: I18n.tr("Show Hour Numbers")
|
|
||||||
checked: SettingsData.desktopClockShowAnalogNumbers
|
|
||||||
onToggled: checked => SettingsData.set("desktopClockShowAnalogNumbers", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {
|
|
||||||
visible: SettingsData.desktopClockStyle === "analog"
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
visible: SettingsData.desktopClockStyle === "analog"
|
|
||||||
text: I18n.tr("Show Seconds")
|
|
||||||
checked: SettingsData.desktopClockShowAnalogSeconds
|
|
||||||
onToggled: checked => SettingsData.set("desktopClockShowAnalogSeconds", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
text: I18n.tr("Show Date")
|
|
||||||
checked: SettingsData.desktopClockShowDate
|
|
||||||
onToggled: checked => SettingsData.set("desktopClockShowDate", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsSliderRow {
|
|
||||||
text: I18n.tr("Transparency")
|
|
||||||
minimum: 0
|
|
||||||
maximum: 100
|
|
||||||
value: Math.round(SettingsData.desktopClockTransparency * 100)
|
|
||||||
unit: "%"
|
|
||||||
onSliderValueChanged: newValue => SettingsData.set("desktopClockTransparency", newValue / 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsColorPicker {
|
|
||||||
colorMode: SettingsData.desktopClockColorMode
|
|
||||||
customColor: SettingsData.desktopClockCustomColor
|
|
||||||
onColorModeSelected: mode => SettingsData.set("desktopClockColorMode", mode)
|
|
||||||
onCustomColorSelected: selectedColor => SettingsData.set("desktopClockCustomColor", selectedColor.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsDisplayPicker {
|
|
||||||
displayPreferences: SettingsData.desktopClockDisplayPreferences
|
|
||||||
onPreferencesChanged: prefs => SettingsData.set("desktopClockDisplayPreferences", prefs)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: clockResetRow.height + Theme.spacingM * 2
|
text: I18n.tr("Add and configure widgets that appear on your desktop")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: clockResetRow
|
spacing: Theme.spacingM
|
||||||
x: Theme.spacingM
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
DankButton {
|
DankButton {
|
||||||
text: I18n.tr("Reset Position")
|
text: I18n.tr("Add Widget")
|
||||||
backgroundColor: Theme.surfaceHover
|
iconName: "add"
|
||||||
textColor: Theme.surfaceText
|
onClicked: widgetBrowser.show()
|
||||||
buttonHeight: 36
|
}
|
||||||
onClicked: {
|
|
||||||
SettingsData.set("desktopClockX", -1);
|
|
||||||
SettingsData.set("desktopClockY", -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DankButton {
|
DankButton {
|
||||||
text: I18n.tr("Reset Size")
|
text: I18n.tr("Browse Plugins")
|
||||||
backgroundColor: Theme.surfaceHover
|
iconName: "store"
|
||||||
textColor: Theme.surfaceText
|
onClicked: desktopPluginBrowser.show()
|
||||||
buttonHeight: 36
|
|
||||||
onClicked: {
|
|
||||||
SettingsData.set("desktopClockWidth", 280);
|
|
||||||
SettingsData.set("desktopClockHeight", 180);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsCard {
|
Column {
|
||||||
|
id: instancesColumn
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "monitoring"
|
spacing: Theme.spacingM
|
||||||
title: I18n.tr("System Monitor")
|
visible: SettingsData.desktopWidgetInstances.length > 0
|
||||||
collapsible: true
|
|
||||||
expanded: false
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
Repeater {
|
||||||
text: I18n.tr("Enable System Monitor")
|
id: instanceRepeater
|
||||||
checked: SettingsData.systemMonitorEnabled
|
model: ScriptModel {
|
||||||
onToggled: checked => SettingsData.set("systemMonitorEnabled", checked)
|
id: instancesModel
|
||||||
}
|
objectProp: "id"
|
||||||
|
values: SettingsData.desktopWidgetInstances
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
DesktopWidgetInstanceCard {
|
||||||
width: parent.width
|
required property var modelData
|
||||||
spacing: 0
|
required property int index
|
||||||
visible: SettingsData.systemMonitorEnabled
|
|
||||||
opacity: visible ? 1 : 0
|
|
||||||
|
|
||||||
Behavior on opacity {
|
readonly property string instanceIdRef: modelData.id
|
||||||
NumberAnimation {
|
readonly property var liveInstanceData: {
|
||||||
duration: Theme.mediumDuration
|
const instances = SettingsData.desktopWidgetInstances || [];
|
||||||
easing.type: Theme.emphasizedEasing
|
return instances.find(inst => inst.id === instanceIdRef) ?? modelData;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
width: instancesColumn.width
|
||||||
|
instanceData: liveInstanceData
|
||||||
|
isExpanded: root.expandedStates[instanceIdRef] ?? false
|
||||||
|
|
||||||
SettingsToggleRow {
|
onExpandedChanged: {
|
||||||
text: I18n.tr("Show Header")
|
if (expanded === (root.expandedStates[instanceIdRef] ?? false))
|
||||||
checked: SettingsData.systemMonitorShowHeader
|
|
||||||
onToggled: checked => SettingsData.set("systemMonitorShowHeader", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: graphIntervalColumn.height + Theme.spacingM * 2
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: graphIntervalColumn
|
|
||||||
width: parent.width - Theme.spacingM * 2
|
|
||||||
x: Theme.spacingM
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: I18n.tr("Graph Time Range")
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
}
|
|
||||||
|
|
||||||
DankButtonGroup {
|
|
||||||
model: ["1m", "5m", "10m", "30m"]
|
|
||||||
currentIndex: {
|
|
||||||
switch (SettingsData.systemMonitorGraphInterval) {
|
|
||||||
case 60:
|
|
||||||
return 0;
|
|
||||||
case 300:
|
|
||||||
return 1;
|
|
||||||
case 600:
|
|
||||||
return 2;
|
|
||||||
case 1800:
|
|
||||||
return 3;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buttonHeight: 32
|
|
||||||
minButtonWidth: 48
|
|
||||||
textSize: Theme.fontSizeSmall
|
|
||||||
checkEnabled: false
|
|
||||||
onSelectionChanged: (index, selected) => {
|
|
||||||
if (!selected)
|
|
||||||
return;
|
|
||||||
const values = [60, 300, 600, 1800];
|
|
||||||
SettingsData.set("systemMonitorGraphInterval", values[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
text: I18n.tr("CPU")
|
|
||||||
checked: SettingsData.systemMonitorShowCpu
|
|
||||||
onToggled: checked => SettingsData.set("systemMonitorShowCpu", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {
|
|
||||||
visible: SettingsData.systemMonitorShowCpu
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
visible: SettingsData.systemMonitorShowCpu
|
|
||||||
text: I18n.tr("CPU Graph")
|
|
||||||
checked: SettingsData.systemMonitorShowCpuGraph
|
|
||||||
onToggled: checked => SettingsData.set("systemMonitorShowCpuGraph", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {
|
|
||||||
visible: SettingsData.systemMonitorShowCpu
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
visible: SettingsData.systemMonitorShowCpu
|
|
||||||
text: I18n.tr("CPU Temperature")
|
|
||||||
checked: SettingsData.systemMonitorShowCpuTemp
|
|
||||||
onToggled: checked => SettingsData.set("systemMonitorShowCpuTemp", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
text: I18n.tr("GPU Temperature")
|
|
||||||
checked: SettingsData.systemMonitorShowGpuTemp
|
|
||||||
onToggled: checked => SettingsData.set("systemMonitorShowGpuTemp", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {
|
|
||||||
visible: SettingsData.systemMonitorShowGpuTemp && DgopService.availableGpus.length > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: gpuSelectColumn.height + Theme.spacingM * 2
|
|
||||||
visible: SettingsData.systemMonitorShowGpuTemp && DgopService.availableGpus.length > 0
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: gpuSelectColumn
|
|
||||||
width: parent.width - Theme.spacingM * 2
|
|
||||||
x: Theme.spacingM
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: I18n.tr("GPU")
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: DgopService.availableGpus
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
required property var modelData
|
|
||||||
|
|
||||||
width: parent.width
|
|
||||||
height: 44
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: SettingsData.systemMonitorGpuPciId === modelData.pciId ? Theme.primarySelected : Theme.surfaceHover
|
|
||||||
border.color: SettingsData.systemMonitorGpuPciId === modelData.pciId ? Theme.primary : "transparent"
|
|
||||||
border.width: 2
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingS
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
name: "videocam"
|
|
||||||
size: Theme.iconSizeSmall
|
|
||||||
color: SettingsData.systemMonitorGpuPciId === modelData.pciId ? Theme.primary : Theme.surfaceVariantText
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width - Theme.iconSizeSmall - Theme.spacingS
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: modelData.displayName || "Unknown GPU"
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
width: parent.width
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: modelData.driver || ""
|
|
||||||
font.pixelSize: Theme.fontSizeSmall - 2
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
visible: text !== ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: SettingsData.set("systemMonitorGpuPciId", modelData.pciId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
text: I18n.tr("Memory")
|
|
||||||
checked: SettingsData.systemMonitorShowMemory
|
|
||||||
onToggled: checked => SettingsData.set("systemMonitorShowMemory", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {
|
|
||||||
visible: SettingsData.systemMonitorShowMemory
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
visible: SettingsData.systemMonitorShowMemory
|
|
||||||
text: I18n.tr("Memory Graph")
|
|
||||||
checked: SettingsData.systemMonitorShowMemoryGraph
|
|
||||||
onToggled: checked => SettingsData.set("systemMonitorShowMemoryGraph", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
text: I18n.tr("Network")
|
|
||||||
checked: SettingsData.systemMonitorShowNetwork
|
|
||||||
onToggled: checked => SettingsData.set("systemMonitorShowNetwork", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {
|
|
||||||
visible: SettingsData.systemMonitorShowNetwork
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
visible: SettingsData.systemMonitorShowNetwork
|
|
||||||
text: I18n.tr("Network Graph")
|
|
||||||
checked: SettingsData.systemMonitorShowNetworkGraph
|
|
||||||
onToggled: checked => SettingsData.set("systemMonitorShowNetworkGraph", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
text: I18n.tr("Disk")
|
|
||||||
checked: SettingsData.systemMonitorShowDisk
|
|
||||||
onToggled: checked => SettingsData.set("systemMonitorShowDisk", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsToggleRow {
|
|
||||||
text: I18n.tr("Top Processes")
|
|
||||||
checked: SettingsData.systemMonitorShowTopProcesses
|
|
||||||
onToggled: checked => SettingsData.set("systemMonitorShowTopProcesses", checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {
|
|
||||||
visible: SettingsData.systemMonitorShowTopProcesses
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: topProcessesColumn.height + Theme.spacingM * 2
|
|
||||||
visible: SettingsData.systemMonitorShowTopProcesses
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: topProcessesColumn
|
|
||||||
width: parent.width - Theme.spacingM * 2
|
|
||||||
x: Theme.spacingM
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
width: parent.width - processCountButtons.width - Theme.spacingM
|
|
||||||
text: I18n.tr("Process Count")
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
DankButtonGroup {
|
|
||||||
id: processCountButtons
|
|
||||||
model: ["3", "5", "10"]
|
|
||||||
currentIndex: {
|
|
||||||
switch (SettingsData.systemMonitorTopProcessCount) {
|
|
||||||
case 3:
|
|
||||||
return 0;
|
|
||||||
case 5:
|
|
||||||
return 1;
|
|
||||||
case 10:
|
|
||||||
return 2;
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buttonHeight: 32
|
|
||||||
minButtonWidth: 36
|
|
||||||
textSize: Theme.fontSizeSmall
|
|
||||||
checkEnabled: false
|
|
||||||
onSelectionChanged: (index, selected) => {
|
|
||||||
if (!selected)
|
|
||||||
return;
|
|
||||||
const values = [3, 5, 10];
|
|
||||||
SettingsData.set("systemMonitorTopProcessCount", values[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
width: parent.width - sortByButtons.width - Theme.spacingM
|
|
||||||
text: I18n.tr("Sort By")
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
DankButtonGroup {
|
|
||||||
id: sortByButtons
|
|
||||||
model: ["CPU", "MEM"]
|
|
||||||
currentIndex: SettingsData.systemMonitorTopProcessSortBy === "cpu" ? 0 : 1
|
|
||||||
buttonHeight: 32
|
|
||||||
minButtonWidth: 48
|
|
||||||
textSize: Theme.fontSizeSmall
|
|
||||||
checkEnabled: false
|
|
||||||
onSelectionChanged: (index, selected) => {
|
|
||||||
if (!selected)
|
|
||||||
return;
|
|
||||||
SettingsData.set("systemMonitorTopProcessSortBy", index === 0 ? "cpu" : "memory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsDropdownRow {
|
|
||||||
text: I18n.tr("Layout")
|
|
||||||
options: [I18n.tr("Auto"), I18n.tr("Grid"), I18n.tr("List")]
|
|
||||||
currentValue: {
|
|
||||||
switch (SettingsData.systemMonitorLayoutMode) {
|
|
||||||
case "grid":
|
|
||||||
return I18n.tr("Grid");
|
|
||||||
case "list":
|
|
||||||
return I18n.tr("List");
|
|
||||||
default:
|
|
||||||
return I18n.tr("Auto");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onValueChanged: value => {
|
|
||||||
switch (value) {
|
|
||||||
case I18n.tr("Grid"):
|
|
||||||
SettingsData.set("systemMonitorLayoutMode", "grid");
|
|
||||||
return;
|
return;
|
||||||
case I18n.tr("List"):
|
var states = Object.assign({}, root.expandedStates);
|
||||||
SettingsData.set("systemMonitorLayoutMode", "list");
|
states[instanceIdRef] = expanded;
|
||||||
return;
|
root.expandedStates = states;
|
||||||
default:
|
|
||||||
SettingsData.set("systemMonitorLayoutMode", "auto");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
onDeleteRequested: {
|
||||||
|
SettingsData.removeDesktopWidgetInstance(instanceIdRef);
|
||||||
SettingsSliderRow {
|
ToastService.showInfo(I18n.tr("Widget removed"));
|
||||||
text: I18n.tr("Transparency")
|
|
||||||
minimum: 0
|
|
||||||
maximum: 100
|
|
||||||
value: Math.round(SettingsData.systemMonitorTransparency * 100)
|
|
||||||
unit: "%"
|
|
||||||
onSliderValueChanged: newValue => SettingsData.set("systemMonitorTransparency", newValue / 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsColorPicker {
|
|
||||||
colorMode: SettingsData.systemMonitorColorMode
|
|
||||||
customColor: SettingsData.systemMonitorCustomColor
|
|
||||||
onColorModeSelected: mode => SettingsData.set("systemMonitorColorMode", mode)
|
|
||||||
onCustomColorSelected: selectedColor => SettingsData.set("systemMonitorCustomColor", selectedColor.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
SettingsDisplayPicker {
|
|
||||||
displayPreferences: SettingsData.systemMonitorDisplayPreferences
|
|
||||||
onPreferencesChanged: prefs => SettingsData.set("systemMonitorDisplayPreferences", prefs)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: sysMonResetRow.height + Theme.spacingM * 2
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: sysMonResetRow
|
|
||||||
x: Theme.spacingM
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
DankButton {
|
|
||||||
text: I18n.tr("Reset Position")
|
|
||||||
backgroundColor: Theme.surfaceHover
|
|
||||||
textColor: Theme.surfaceText
|
|
||||||
buttonHeight: 36
|
|
||||||
onClicked: {
|
|
||||||
SettingsData.set("systemMonitorX", -1);
|
|
||||||
SettingsData.set("systemMonitorY", -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DankButton {
|
|
||||||
text: I18n.tr("Reset Size")
|
|
||||||
backgroundColor: Theme.surfaceHover
|
|
||||||
textColor: Theme.surfaceText
|
|
||||||
buttonHeight: 36
|
|
||||||
onClicked: {
|
|
||||||
SettingsData.set("systemMonitorWidth", 320);
|
|
||||||
SettingsData.set("systemMonitorHeight", 480);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDivider {}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: variantsColumn.height + Theme.spacingM * 2
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: variantsColumn
|
|
||||||
width: parent.width - Theme.spacingM * 2
|
|
||||||
x: Theme.spacingM
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
width: parent.width - addVariantBtn.width - Theme.spacingM
|
|
||||||
text: I18n.tr("Widget Variants")
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
DankButton {
|
|
||||||
id: addVariantBtn
|
|
||||||
text: I18n.tr("Add")
|
|
||||||
iconName: "add"
|
|
||||||
onClicked: {
|
|
||||||
const variant = SettingsData.createSystemMonitorVariant("Monitor " + (SettingsData.systemMonitorVariants.length + 1), SettingsData.getDefaultSystemMonitorConfig());
|
|
||||||
if (variant)
|
|
||||||
ToastService.showInfo(I18n.tr("Variant created - expand to configure"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: variantsListColumn
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
visible: SettingsData.systemMonitorVariants.length > 0
|
|
||||||
|
|
||||||
property var expandedStates: ({})
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: SettingsData.systemMonitorVariants
|
|
||||||
|
|
||||||
SystemMonitorVariantCard {
|
|
||||||
required property var modelData
|
|
||||||
required property int index
|
|
||||||
|
|
||||||
width: parent.width
|
|
||||||
variant: modelData
|
|
||||||
expanded: variantsListColumn.expandedStates[modelData.id] || false
|
|
||||||
|
|
||||||
onExpandToggled: isExpanded => {
|
|
||||||
var states = JSON.parse(JSON.stringify(variantsListColumn.expandedStates));
|
|
||||||
states[modelData.id] = isExpanded;
|
|
||||||
variantsListColumn.expandedStates = states;
|
|
||||||
}
|
|
||||||
|
|
||||||
onDeleteRequested: {
|
|
||||||
SettingsData.removeSystemMonitorVariant(modelData.id);
|
|
||||||
ToastService.showInfo(I18n.tr("Variant removed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
onNameChanged: newName => {
|
|
||||||
SettingsData.updateSystemMonitorVariant(modelData.id, {
|
|
||||||
name: newName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onConfigChanged: (key, value) => {
|
|
||||||
var update = {};
|
|
||||||
update[key] = value;
|
|
||||||
SettingsData.updateSystemMonitorVariant(modelData.id, update);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
visible: SettingsData.systemMonitorVariants.length === 0
|
|
||||||
text: I18n.tr("No variants created. Click Add to create a new monitor widget.")
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
width: parent.width
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
visible: SettingsData.desktopWidgetInstances.length === 0
|
||||||
|
text: I18n.tr("No widgets added. Click \"Add Widget\" to get started.")
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
width: parent.width
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "info"
|
iconName: "info"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ FloatingWindow {
|
|||||||
property bool isLoading: false
|
property bool isLoading: false
|
||||||
property var parentModal: null
|
property var parentModal: null
|
||||||
property bool pendingInstallHandled: false
|
property bool pendingInstallHandled: false
|
||||||
|
property string typeFilter: ""
|
||||||
|
|
||||||
function updateFilteredPlugins() {
|
function updateFilteredPlugins() {
|
||||||
var filtered = [];
|
var filtered = [];
|
||||||
@@ -29,6 +30,12 @@ FloatingWindow {
|
|||||||
if (!SessionData.showThirdPartyPlugins && !isFirstParty)
|
if (!SessionData.showThirdPartyPlugins && !isFirstParty)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (typeFilter !== "") {
|
||||||
|
var hasCapability = plugin.capabilities && plugin.capabilities.includes(typeFilter);
|
||||||
|
if (!hasCapability)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (query.length === 0) {
|
if (query.length === 0) {
|
||||||
filtered.push(plugin);
|
filtered.push(plugin);
|
||||||
continue;
|
continue;
|
||||||
@@ -76,6 +83,11 @@ FloatingWindow {
|
|||||||
if (enableAfterInstall) {
|
if (enableAfterInstall) {
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
PluginService.enablePlugin(pluginName);
|
PluginService.enablePlugin(pluginName);
|
||||||
|
const plugin = PluginService.availablePlugins[pluginName];
|
||||||
|
if (plugin?.type === "desktop") {
|
||||||
|
const defaultConfig = DesktopWidgetRegistry.getDefaultConfig(pluginName);
|
||||||
|
SettingsData.createDesktopWidgetInstance(pluginName, plugin.name || pluginName, defaultConfig);
|
||||||
|
}
|
||||||
hide();
|
hide();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -149,6 +161,33 @@ FloatingWindow {
|
|||||||
isLoading = false;
|
isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: DMSService
|
||||||
|
|
||||||
|
function onPluginsListReceived(plugins) {
|
||||||
|
root.isLoading = false;
|
||||||
|
root.allPlugins = plugins;
|
||||||
|
root.updateFilteredPlugins();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onInstalledPluginsReceived(plugins) {
|
||||||
|
var pluginMap = {};
|
||||||
|
for (var i = 0; i < plugins.length; i++) {
|
||||||
|
var plugin = plugins[i];
|
||||||
|
if (plugin.id)
|
||||||
|
pluginMap[plugin.id] = true;
|
||||||
|
if (plugin.name)
|
||||||
|
pluginMap[plugin.name] = true;
|
||||||
|
}
|
||||||
|
var updated = root.allPlugins.map(p => {
|
||||||
|
var isInstalled = pluginMap[p.name] || pluginMap[p.id] || false;
|
||||||
|
return Object.assign({}, p, { installed: isInstalled });
|
||||||
|
});
|
||||||
|
root.allPlugins = updated;
|
||||||
|
root.updateFilteredPlugins();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ConfirmModal {
|
ConfirmModal {
|
||||||
id: urlInstallConfirm
|
id: urlInstallConfirm
|
||||||
}
|
}
|
||||||
@@ -355,8 +394,8 @@ FloatingWindow {
|
|||||||
property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex
|
property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex
|
||||||
property bool isInstalled: modelData.installed || false
|
property bool isInstalled: modelData.installed || false
|
||||||
property bool isFirstParty: modelData.firstParty || false
|
property bool isFirstParty: modelData.firstParty || false
|
||||||
color: isSelected ? Theme.primarySelected : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
color: isSelected ? Theme.primarySelected : Theme.withAlpha(Theme.surfaceVariant, 0.3)
|
||||||
border.color: isSelected ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
border.color: isSelected ? Theme.primary : Theme.withAlpha(Theme.outline, 0.2)
|
||||||
border.width: isSelected ? 2 : 1
|
border.width: isSelected ? 2 : 1
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
@@ -396,8 +435,8 @@ FloatingWindow {
|
|||||||
height: 16
|
height: 16
|
||||||
width: firstPartyText.implicitWidth + Theme.spacingXS * 2
|
width: firstPartyText.implicitWidth + Theme.spacingXS * 2
|
||||||
radius: 8
|
radius: 8
|
||||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15)
|
color: Theme.withAlpha(Theme.primary, 0.15)
|
||||||
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.4)
|
border.color: Theme.withAlpha(Theme.primary, 0.4)
|
||||||
border.width: 1
|
border.width: 1
|
||||||
visible: isFirstParty
|
visible: isFirstParty
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -416,8 +455,8 @@ FloatingWindow {
|
|||||||
height: 16
|
height: 16
|
||||||
width: thirdPartyText.implicitWidth + Theme.spacingXS * 2
|
width: thirdPartyText.implicitWidth + Theme.spacingXS * 2
|
||||||
radius: 8
|
radius: 8
|
||||||
color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.15)
|
color: Theme.withAlpha(Theme.warning, 0.15)
|
||||||
border.color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.4)
|
border.color: Theme.withAlpha(Theme.warning, 0.4)
|
||||||
border.width: 1
|
border.width: 1
|
||||||
visible: !isFirstParty
|
visible: !isFirstParty
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -501,8 +540,10 @@ FloatingWindow {
|
|||||||
cursorShape: isInstalled ? Qt.ArrowCursor : Qt.PointingHandCursor
|
cursorShape: isInstalled ? Qt.ArrowCursor : Qt.PointingHandCursor
|
||||||
enabled: !isInstalled
|
enabled: !isInstalled
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!isInstalled)
|
if (isInstalled)
|
||||||
root.installPlugin(modelData.name, false);
|
return;
|
||||||
|
const isDesktop = modelData.type === "desktop";
|
||||||
|
root.installPlugin(modelData.name, isDesktop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -529,8 +570,8 @@ FloatingWindow {
|
|||||||
height: 18
|
height: 18
|
||||||
width: capabilityText.implicitWidth + Theme.spacingXS * 2
|
width: capabilityText.implicitWidth + Theme.spacingXS * 2
|
||||||
radius: 9
|
radius: 9
|
||||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
color: Theme.withAlpha(Theme.primary, 0.1)
|
||||||
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3)
|
border.color: Theme.withAlpha(Theme.primary, 0.3)
|
||||||
border.width: 1
|
border.width: 1
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ StyledRect {
|
|||||||
property string pluginSettingsPath: pluginData ? (pluginData.settingsPath || "") : ""
|
property string pluginSettingsPath: pluginData ? (pluginData.settingsPath || "") : ""
|
||||||
property var pluginPermissions: pluginData ? (pluginData.permissions || []) : []
|
property var pluginPermissions: pluginData ? (pluginData.permissions || []) : []
|
||||||
property bool hasSettings: pluginData && pluginData.settings !== undefined && pluginData.settings !== ""
|
property bool hasSettings: pluginData && pluginData.settings !== undefined && pluginData.settings !== ""
|
||||||
|
property bool isDesktopPlugin: pluginData ? (pluginData.type === "desktop") : false
|
||||||
|
property bool showSettings: hasSettings && !isDesktopPlugin
|
||||||
property bool isSystemPlugin: pluginData ? (pluginData.source === "system") : false
|
property bool isSystemPlugin: pluginData ? (pluginData.source === "system") : false
|
||||||
property string requiresDms: pluginData ? (pluginData.requires_dms || "") : ""
|
property string requiresDms: pluginData ? (pluginData.requires_dms || "") : ""
|
||||||
property bool meetsRequirements: requiresDms ? PluginService.checkPluginCompatibility(requiresDms) : true
|
property bool meetsRequirements: requiresDms ? PluginService.checkPluginCompatibility(requiresDms) : true
|
||||||
@@ -55,8 +57,8 @@ StyledRect {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.bottomMargin: root.isExpanded ? settingsContainer.height : 0
|
anchors.bottomMargin: root.isExpanded ? settingsContainer.height : 0
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: root.hasSettings ? Qt.PointingHandCursor : Qt.ArrowCursor
|
cursorShape: root.showSettings ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
enabled: root.hasSettings
|
enabled: root.showSettings
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.expandedPluginId = root.expandedPluginId === root.pluginId ? "" : root.pluginId;
|
root.expandedPluginId = root.expandedPluginId === root.pluginId ? "" : root.pluginId;
|
||||||
}
|
}
|
||||||
@@ -103,7 +105,7 @@ StyledRect {
|
|||||||
width: incompatIcon.width + Theme.spacingXS * 2
|
width: incompatIcon.width + Theme.spacingXS * 2
|
||||||
height: 18
|
height: 18
|
||||||
radius: 9
|
radius: 9
|
||||||
color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.15)
|
color: Theme.withAlpha(Theme.error, 0.15)
|
||||||
visible: !root.meetsRequirements
|
visible: !root.meetsRequirements
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
@@ -135,11 +137,28 @@ StyledRect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: root.hasSettings ? (root.isExpanded ? "expand_less" : "expand_more") : ""
|
name: root.showSettings ? (root.isExpanded ? "expand_less" : "expand_more") : ""
|
||||||
size: 16
|
size: 16
|
||||||
color: root.hasSettings ? Theme.primary : "transparent"
|
color: root.showSettings ? Theme.primary : "transparent"
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: root.hasSettings
|
visible: root.showSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: desktopLabel.implicitWidth + Theme.spacingXS * 2
|
||||||
|
height: 18
|
||||||
|
radius: 9
|
||||||
|
color: Theme.withAlpha(Theme.secondary, 0.15)
|
||||||
|
visible: root.isDesktopPlugin
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: desktopLabel
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: I18n.tr("Desktop Widget")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall - 2
|
||||||
|
color: Theme.secondary
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,8 +352,8 @@ StyledRect {
|
|||||||
height: 20
|
height: 20
|
||||||
width: permissionText.implicitWidth + Theme.spacingXS * 2
|
width: permissionText.implicitWidth + Theme.spacingXS * 2
|
||||||
radius: 10
|
radius: 10
|
||||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
color: Theme.withAlpha(Theme.primary, 0.1)
|
||||||
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3)
|
border.color: Theme.withAlpha(Theme.primary, 0.3)
|
||||||
border.width: 1
|
border.width: 1
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -354,9 +373,9 @@ StyledRect {
|
|||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
height: root.isExpanded && root.hasSettings ? (settingsLoader.item ? settingsLoader.item.implicitHeight + Theme.spacingL * 2 : 0) : 0
|
height: root.isExpanded && root.showSettings ? (settingsLoader.item ? settingsLoader.item.implicitHeight + Theme.spacingL * 2 : 0) : 0
|
||||||
clip: true
|
clip: true
|
||||||
focus: root.isExpanded && root.hasSettings
|
focus: root.isExpanded && root.showSettings
|
||||||
|
|
||||||
Keys.onPressed: event => {
|
Keys.onPressed: event => {
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
@@ -374,7 +393,7 @@ StyledRect {
|
|||||||
id: settingsLoader
|
id: settingsLoader
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Theme.spacingL
|
anchors.margins: Theme.spacingL
|
||||||
active: root.isExpanded && root.hasSettings && root.isLoaded
|
active: root.isExpanded && root.showSettings && root.isLoaded
|
||||||
asynchronous: false
|
asynchronous: false
|
||||||
|
|
||||||
source: {
|
source: {
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ FocusScope {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
height: dmsWarningColumn.implicitHeight + Theme.spacingM * 2
|
height: dmsWarningColumn.implicitHeight + Theme.spacingM * 2
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.1)
|
color: Theme.withAlpha(Theme.warning, 0.1)
|
||||||
border.color: Theme.warning
|
border.color: Theme.warning
|
||||||
border.width: 1
|
border.width: 1
|
||||||
visible: !DMSService.dmsAvailable
|
visible: !DMSService.dmsAvailable
|
||||||
@@ -126,7 +126,7 @@ FocusScope {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
height: incompatWarningColumn.implicitHeight + Theme.spacingM * 2
|
height: incompatWarningColumn.implicitHeight + Theme.spacingM * 2
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.1)
|
color: Theme.withAlpha(Theme.error, 0.1)
|
||||||
border.color: Theme.error
|
border.color: Theme.error
|
||||||
border.width: 1
|
border.width: 1
|
||||||
visible: incompatPlugins.length > 0
|
visible: incompatPlugins.length > 0
|
||||||
|
|||||||
@@ -12,10 +12,14 @@ Item {
|
|||||||
|
|
||||||
signal preferencesChanged(var preferences)
|
signal preferencesChanged(var preferences)
|
||||||
|
|
||||||
readonly property bool allDisplaysEnabled: {
|
property bool localAllDisplays: true
|
||||||
if (!Array.isArray(displayPreferences) || displayPreferences.length === 0)
|
|
||||||
return true;
|
onDisplayPreferencesChanged: {
|
||||||
return displayPreferences.includes("all");
|
if (!Array.isArray(displayPreferences) || displayPreferences.length === 0) {
|
||||||
|
localAllDisplays = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
localAllDisplays = displayPreferences.includes("all");
|
||||||
}
|
}
|
||||||
|
|
||||||
width: parent?.width ?? 0
|
width: parent?.width ?? 0
|
||||||
@@ -37,8 +41,9 @@ Item {
|
|||||||
DankToggle {
|
DankToggle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: I18n.tr("All displays")
|
text: I18n.tr("All displays")
|
||||||
checked: root.allDisplaysEnabled
|
checked: root.localAllDisplays
|
||||||
onToggled: isChecked => {
|
onToggled: isChecked => {
|
||||||
|
root.localAllDisplays = isChecked;
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
root.preferencesChanged(["all"]);
|
root.preferencesChanged(["all"]);
|
||||||
return;
|
return;
|
||||||
@@ -58,7 +63,7 @@ Item {
|
|||||||
Column {
|
Column {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
visible: !root.allDisplaysEnabled
|
visible: !root.localAllDisplays
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: Quickshell.screens
|
model: Quickshell.screens
|
||||||
@@ -66,17 +71,20 @@ Item {
|
|||||||
DankToggle {
|
DankToggle {
|
||||||
required property var modelData
|
required property var modelData
|
||||||
|
|
||||||
|
property bool localChecked: {
|
||||||
|
const prefs = root.displayPreferences;
|
||||||
|
if (!Array.isArray(prefs) || prefs.includes("all"))
|
||||||
|
return true;
|
||||||
|
return prefs.some(p => p.name === modelData.name);
|
||||||
|
}
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: SettingsData.getScreenDisplayName(modelData)
|
text: SettingsData.getScreenDisplayName(modelData)
|
||||||
description: modelData.width + "×" + modelData.height
|
description: modelData.width + "×" + modelData.height
|
||||||
checked: {
|
checked: localChecked
|
||||||
const prefs = root.displayPreferences;
|
|
||||||
if (!Array.isArray(prefs) || prefs.includes("all"))
|
|
||||||
return false;
|
|
||||||
return prefs.some(p => p.name === modelData.name);
|
|
||||||
}
|
|
||||||
onToggled: isChecked => {
|
onToggled: isChecked => {
|
||||||
var prefs = root.displayPreferences;
|
localChecked = isChecked;
|
||||||
|
var prefs = JSON.parse(JSON.stringify(root.displayPreferences));
|
||||||
if (!Array.isArray(prefs) || prefs.includes("all"))
|
if (!Array.isArray(prefs) || prefs.includes("all"))
|
||||||
prefs = [];
|
prefs = [];
|
||||||
prefs = prefs.filter(p => p.name !== modelData.name);
|
prefs = prefs.filter(p => p.name !== modelData.name);
|
||||||
|
|||||||
232
quickshell/Services/DesktopWidgetRegistry.qml
Normal file
232
quickshell/Services/DesktopWidgetRegistry.qml
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var registeredWidgets: ({})
|
||||||
|
property var registeredWidgetsList: []
|
||||||
|
|
||||||
|
signal registryChanged
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
registerBuiltins();
|
||||||
|
Qt.callLater(syncPluginWidgets);
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: PluginService
|
||||||
|
function onPluginLoaded(pluginId) {
|
||||||
|
const plugin = PluginService.availablePlugins[pluginId];
|
||||||
|
if (plugin?.type === "desktop")
|
||||||
|
syncPluginWidgets();
|
||||||
|
}
|
||||||
|
function onPluginUnloaded(pluginId) {
|
||||||
|
syncPluginWidgets();
|
||||||
|
}
|
||||||
|
function onPluginListUpdated() {
|
||||||
|
syncPluginWidgets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerBuiltins() {
|
||||||
|
registerWidget({
|
||||||
|
id: "desktopClock",
|
||||||
|
name: I18n.tr("Desktop Clock", "Desktop clock widget name"),
|
||||||
|
icon: "schedule",
|
||||||
|
description: I18n.tr("Analog, digital, or stacked clock display", "Desktop clock widget description"),
|
||||||
|
type: "builtin",
|
||||||
|
component: "qs.Modules.BuiltinDesktopPlugins.DesktopClockWidget",
|
||||||
|
settingsComponent: "qs.Modules.Settings.DesktopWidgetSettings.ClockSettings",
|
||||||
|
defaultConfig: getDefaultClockConfig(),
|
||||||
|
defaultSize: {
|
||||||
|
width: 280,
|
||||||
|
height: 180
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
registerWidget({
|
||||||
|
id: "systemMonitor",
|
||||||
|
name: I18n.tr("System Monitor", "System monitor widget name"),
|
||||||
|
icon: "monitoring",
|
||||||
|
description: I18n.tr("CPU, memory, network, and disk monitoring", "System monitor widget description"),
|
||||||
|
type: "builtin",
|
||||||
|
component: "qs.Modules.BuiltinDesktopPlugins.SystemMonitorWidget",
|
||||||
|
settingsComponent: "qs.Modules.Settings.DesktopWidgetSettings.SystemMonitorSettings",
|
||||||
|
defaultConfig: getDefaultSystemMonitorConfig(),
|
||||||
|
defaultSize: {
|
||||||
|
width: 320,
|
||||||
|
height: 480
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultClockConfig() {
|
||||||
|
return {
|
||||||
|
style: "analog",
|
||||||
|
transparency: 0.8,
|
||||||
|
colorMode: "primary",
|
||||||
|
customColor: "#ffffff",
|
||||||
|
showDate: true,
|
||||||
|
showAnalogNumbers: false,
|
||||||
|
showAnalogSeconds: true,
|
||||||
|
displayPreferences: ["all"]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultSystemMonitorConfig() {
|
||||||
|
return {
|
||||||
|
showHeader: true,
|
||||||
|
transparency: 0.8,
|
||||||
|
colorMode: "primary",
|
||||||
|
customColor: "#ffffff",
|
||||||
|
showCpu: true,
|
||||||
|
showCpuGraph: true,
|
||||||
|
showCpuTemp: true,
|
||||||
|
showGpuTemp: false,
|
||||||
|
gpuPciId: "",
|
||||||
|
showMemory: true,
|
||||||
|
showMemoryGraph: true,
|
||||||
|
showNetwork: true,
|
||||||
|
showNetworkGraph: true,
|
||||||
|
showDisk: true,
|
||||||
|
showTopProcesses: false,
|
||||||
|
topProcessCount: 3,
|
||||||
|
topProcessSortBy: "cpu",
|
||||||
|
layoutMode: "auto",
|
||||||
|
graphInterval: 60,
|
||||||
|
displayPreferences: ["all"]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerWidget(widgetDef) {
|
||||||
|
if (!widgetDef?.id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const newMap = Object.assign({}, registeredWidgets);
|
||||||
|
newMap[widgetDef.id] = widgetDef;
|
||||||
|
registeredWidgets = newMap;
|
||||||
|
_updateWidgetsList();
|
||||||
|
registryChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
function unregisterWidget(widgetId) {
|
||||||
|
if (!registeredWidgets[widgetId])
|
||||||
|
return;
|
||||||
|
|
||||||
|
const newMap = Object.assign({}, registeredWidgets);
|
||||||
|
delete newMap[widgetId];
|
||||||
|
registeredWidgets = newMap;
|
||||||
|
_updateWidgetsList();
|
||||||
|
registryChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWidget(widgetType) {
|
||||||
|
return registeredWidgets[widgetType] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultConfig(widgetType) {
|
||||||
|
const widget = getWidget(widgetType);
|
||||||
|
if (!widget)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (widget.type === "builtin") {
|
||||||
|
switch (widgetType) {
|
||||||
|
case "desktopClock":
|
||||||
|
return getDefaultClockConfig();
|
||||||
|
case "systemMonitor":
|
||||||
|
return getDefaultSystemMonitorConfig();
|
||||||
|
default:
|
||||||
|
return widget.defaultConfig ?? {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return widget.defaultConfig ?? {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultSize(widgetType) {
|
||||||
|
const widget = getWidget(widgetType);
|
||||||
|
return widget?.defaultSize ?? {
|
||||||
|
width: 200,
|
||||||
|
height: 200
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncPluginWidgets() {
|
||||||
|
const desktopPlugins = PluginService.pluginDesktopComponents;
|
||||||
|
const availablePlugins = PluginService.availablePlugins;
|
||||||
|
const currentPluginIds = [];
|
||||||
|
|
||||||
|
for (const pluginId in desktopPlugins) {
|
||||||
|
currentPluginIds.push(pluginId);
|
||||||
|
const plugin = availablePlugins[pluginId];
|
||||||
|
if (!plugin)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (registeredWidgets[pluginId]?.type === "plugin")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
registerWidget({
|
||||||
|
id: pluginId,
|
||||||
|
name: plugin.name || pluginId,
|
||||||
|
icon: plugin.icon || "extension",
|
||||||
|
description: plugin.description || "",
|
||||||
|
type: "plugin",
|
||||||
|
component: null,
|
||||||
|
settingsComponent: plugin.settingsPath || null,
|
||||||
|
defaultConfig: {
|
||||||
|
displayPreferences: ["all"]
|
||||||
|
},
|
||||||
|
defaultSize: {
|
||||||
|
width: 200,
|
||||||
|
height: 200
|
||||||
|
},
|
||||||
|
pluginInfo: plugin
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const toRemove = [];
|
||||||
|
for (const widgetId in registeredWidgets) {
|
||||||
|
const widget = registeredWidgets[widgetId];
|
||||||
|
if (widget.type !== "plugin")
|
||||||
|
continue;
|
||||||
|
if (!currentPluginIds.includes(widgetId))
|
||||||
|
toRemove.push(widgetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const widgetId of toRemove) {
|
||||||
|
unregisterWidget(widgetId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _updateWidgetsList() {
|
||||||
|
const result = [];
|
||||||
|
for (const key in registeredWidgets) {
|
||||||
|
result.push(registeredWidgets[key]);
|
||||||
|
}
|
||||||
|
result.sort((a, b) => {
|
||||||
|
if (a.type === "builtin" && b.type !== "builtin")
|
||||||
|
return -1;
|
||||||
|
if (a.type !== "builtin" && b.type === "builtin")
|
||||||
|
return 1;
|
||||||
|
return (a.name || "").localeCompare(b.name || "");
|
||||||
|
});
|
||||||
|
registeredWidgetsList = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBuiltinWidgets() {
|
||||||
|
return registeredWidgetsList.filter(w => w.type === "builtin");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPluginWidgets() {
|
||||||
|
return registeredWidgetsList.filter(w => w.type === "plugin");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAllWidgets() {
|
||||||
|
return registeredWidgetsList;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user