mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-29 16:02:51 -05:00
plugins: support for multiple widgets per-plugin (variants)
This commit is contained in:
@@ -87,8 +87,18 @@ Loader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (item.pluginService !== undefined) {
|
if (item.pluginService !== undefined) {
|
||||||
|
var parts = widgetId.split(":")
|
||||||
|
var pluginId = parts[0]
|
||||||
|
var variantId = parts.length > 1 ? parts[1] : null
|
||||||
|
|
||||||
if (item.pluginId !== undefined) {
|
if (item.pluginId !== undefined) {
|
||||||
item.pluginId = widgetId
|
item.pluginId = pluginId
|
||||||
|
}
|
||||||
|
if (item.variantId !== undefined) {
|
||||||
|
item.variantId = variantId
|
||||||
|
}
|
||||||
|
if (item.variantData !== undefined && variantId) {
|
||||||
|
item.variantData = PluginService.getPluginVariantData(pluginId, variantId)
|
||||||
}
|
}
|
||||||
item.pluginService = PluginService
|
item.pluginService = PluginService
|
||||||
}
|
}
|
||||||
@@ -134,8 +144,11 @@ Loader {
|
|||||||
return componentMap[widgetId]
|
return componentMap[widgetId]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var parts = widgetId.split(":")
|
||||||
|
var pluginId = parts[0]
|
||||||
|
|
||||||
let pluginMap = PluginService.getWidgetComponents()
|
let pluginMap = PluginService.getWidgetComponents()
|
||||||
return pluginMap[widgetId] || null
|
return pluginMap[pluginId] || null
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWidgetVisible(widgetId, dgopAvailable) {
|
function getWidgetVisible(widgetId, dgopAvailable) {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ Item {
|
|||||||
signal ccWidgetExpanded()
|
signal ccWidgetExpanded()
|
||||||
|
|
||||||
property var pluginData: ({})
|
property var pluginData: ({})
|
||||||
|
property var variants: []
|
||||||
|
|
||||||
readonly property bool isVertical: axis?.isVertical ?? false
|
readonly property bool isVertical: axis?.isVertical ?? false
|
||||||
readonly property bool hasHorizontalPill: horizontalBarPill !== null
|
readonly property bool hasHorizontalPill: horizontalBarPill !== null
|
||||||
@@ -64,9 +65,32 @@ Item {
|
|||||||
function loadPluginData() {
|
function loadPluginData() {
|
||||||
if (!pluginService || !pluginId) {
|
if (!pluginService || !pluginId) {
|
||||||
pluginData = {}
|
pluginData = {}
|
||||||
|
variants = []
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pluginData = SettingsData.getPluginSettingsForPlugin(pluginId)
|
pluginData = SettingsData.getPluginSettingsForPlugin(pluginId)
|
||||||
|
variants = pluginService.getPluginVariants(pluginId)
|
||||||
|
}
|
||||||
|
|
||||||
|
function createVariant(variantName, variantConfig) {
|
||||||
|
if (!pluginService || !pluginId) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return pluginService.createPluginVariant(pluginId, variantName, variantConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeVariant(variantId) {
|
||||||
|
if (!pluginService || !pluginId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pluginService.removePluginVariant(pluginId, variantId)
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateVariant(variantId, variantConfig) {
|
||||||
|
if (!pluginService || !pluginId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pluginService.updatePluginVariant(pluginId, variantId, variantConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
width: isVertical ? (hasVerticalPill ? verticalPill.width : 0) : (hasHorizontalPill ? horizontalPill.width : 0)
|
width: isVertical ? (hasVerticalPill ? verticalPill.width : 0) : (hasHorizontalPill ? horizontalPill.width : 0)
|
||||||
|
|||||||
@@ -12,13 +12,20 @@ Item {
|
|||||||
|
|
||||||
signal settingChanged()
|
signal settingChanged()
|
||||||
|
|
||||||
|
property var variants: []
|
||||||
|
|
||||||
implicitHeight: hasPermission ? settingsColumn.implicitHeight : errorText.implicitHeight
|
implicitHeight: hasPermission ? settingsColumn.implicitHeight : errorText.implicitHeight
|
||||||
height: implicitHeight
|
height: implicitHeight
|
||||||
|
|
||||||
readonly property bool hasPermission: pluginService && pluginService.hasPermission ? pluginService.hasPermission(pluginId, "settings_write") : true
|
readonly property bool hasPermission: pluginService && pluginService.hasPermission ? pluginService.hasPermission(pluginId, "settings_write") : true
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
loadVariants()
|
||||||
|
}
|
||||||
|
|
||||||
onPluginServiceChanged: {
|
onPluginServiceChanged: {
|
||||||
if (pluginService) {
|
if (pluginService) {
|
||||||
|
loadVariants()
|
||||||
for (let i = 0; i < settingsColumn.children.length; i++) {
|
for (let i = 0; i < settingsColumn.children.length; i++) {
|
||||||
const child = settingsColumn.children[i]
|
const child = settingsColumn.children[i]
|
||||||
if (child.loadValue) {
|
if (child.loadValue) {
|
||||||
@@ -28,6 +35,44 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: pluginService
|
||||||
|
function onPluginDataChanged(changedPluginId) {
|
||||||
|
if (changedPluginId === pluginId) {
|
||||||
|
loadVariants()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadVariants() {
|
||||||
|
if (!pluginService || !pluginId) {
|
||||||
|
variants = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
variants = pluginService.getPluginVariants(pluginId)
|
||||||
|
}
|
||||||
|
|
||||||
|
function createVariant(variantName, variantConfig) {
|
||||||
|
if (!pluginService || !pluginId) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return pluginService.createPluginVariant(pluginId, variantName, variantConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeVariant(variantId) {
|
||||||
|
if (!pluginService || !pluginId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pluginService.removePluginVariant(pluginId, variantId)
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateVariant(variantId, variantConfig) {
|
||||||
|
if (!pluginService || !pluginId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pluginService.updatePluginVariant(pluginId, variantId, variantConfig)
|
||||||
|
}
|
||||||
|
|
||||||
function saveValue(key, value) {
|
function saveValue(key, value) {
|
||||||
if (!pluginService) {
|
if (!pluginService) {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -190,18 +190,16 @@ Item {
|
|||||||
"enabled": SystemUpdateService.distributionSupported
|
"enabled": SystemUpdateService.distributionSupported
|
||||||
}]
|
}]
|
||||||
|
|
||||||
// Add all available plugins (loaded and unloaded)
|
var allPluginVariants = PluginService.getAllPluginVariants()
|
||||||
var allPlugins = PluginService.getAvailablePlugins()
|
for (var i = 0; i < allPluginVariants.length; i++) {
|
||||||
for (var i = 0; i < allPlugins.length; i++) {
|
var variant = allPluginVariants[i]
|
||||||
var plugin = allPlugins[i]
|
|
||||||
var isLoaded = PluginService.isPluginLoaded(plugin.id)
|
|
||||||
coreWidgets.push({
|
coreWidgets.push({
|
||||||
"id": plugin.id,
|
"id": variant.fullId,
|
||||||
"text": plugin.name,
|
"text": variant.name,
|
||||||
"description": plugin.description || "Plugin widget",
|
"description": variant.description,
|
||||||
"icon": plugin.icon || "extension",
|
"icon": variant.icon,
|
||||||
"enabled": isLoaded,
|
"enabled": variant.loaded,
|
||||||
"warning": !isLoaded ? "Plugin is disabled - enable in Plugins settings to use" : undefined
|
"warning": !variant.loaded ? "Plugin is disabled - enable in Plugins settings to use" : undefined
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -378,6 +378,7 @@ Item {
|
|||||||
anchors.margins: Theme.spacingL
|
anchors.margins: Theme.spacingL
|
||||||
active: pluginDelegate.isExpanded && pluginDelegate.hasSettings && PluginService.isPluginLoaded(pluginDelegate.pluginId)
|
active: pluginDelegate.isExpanded && pluginDelegate.hasSettings && PluginService.isPluginLoaded(pluginDelegate.pluginId)
|
||||||
asynchronous: false
|
asynchronous: false
|
||||||
|
focus: true
|
||||||
|
|
||||||
source: {
|
source: {
|
||||||
if (active && pluginDelegate.pluginSettingsPath) {
|
if (active && pluginDelegate.pluginSettingsPath) {
|
||||||
@@ -394,9 +395,13 @@ Item {
|
|||||||
if (item && typeof PluginService !== "undefined") {
|
if (item && typeof PluginService !== "undefined") {
|
||||||
item.pluginService = PluginService
|
item.pluginService = PluginService
|
||||||
}
|
}
|
||||||
if (item && typeof PopoutService !== "undefined") {
|
if (item && typeof PopoutService !== "undefined" && "popoutService" in item) {
|
||||||
item.popoutService = PopoutService
|
item.popoutService = PopoutService
|
||||||
}
|
}
|
||||||
|
if (item) {
|
||||||
|
item.focus = true
|
||||||
|
item.forceActiveFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
116
PLUGINS/ExampleWithVariants/README.md
Normal file
116
PLUGINS/ExampleWithVariants/README.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# Example with Variants Plugin
|
||||||
|
|
||||||
|
This plugin demonstrates the dynamic variant system for DankMaterialShell plugins.
|
||||||
|
|
||||||
|
## What are Variants?
|
||||||
|
|
||||||
|
Variants allow a single plugin to create multiple widget instances with different configurations. Each variant appears as a separate widget option in the Bar Settings "Add Widget" menu.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
### Plugin Architecture
|
||||||
|
|
||||||
|
1. **Single Component**: The plugin defines one widget component (`VariantWidget.qml`)
|
||||||
|
2. **Variant Data**: Each variant stores its configuration in plugin settings
|
||||||
|
3. **Dynamic Creation**: Variants are created through the plugin's settings UI
|
||||||
|
4. **Widget ID Format**: Variants use the format `pluginId:variantId` (e.g., `exampleVariants:variant_1234567890`)
|
||||||
|
|
||||||
|
### Widget Properties
|
||||||
|
|
||||||
|
Each variant widget receives:
|
||||||
|
- `pluginService`: Reference to PluginService
|
||||||
|
- `pluginId`: The base plugin ID (e.g., "exampleVariants")
|
||||||
|
- `variantId`: The specific variant ID (e.g., "variant_1234567890")
|
||||||
|
- `variantData`: The variant's configuration object
|
||||||
|
|
||||||
|
### Variant Configuration
|
||||||
|
|
||||||
|
This example stores:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
id: "variant_1234567890",
|
||||||
|
name: "My Variant",
|
||||||
|
text: "Display Text",
|
||||||
|
icon: "star",
|
||||||
|
color: "#FF5722"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating Your Own Variant Plugin
|
||||||
|
|
||||||
|
### 1. Widget Component
|
||||||
|
|
||||||
|
Create a widget that accepts variant data:
|
||||||
|
|
||||||
|
```qml
|
||||||
|
Rectangle {
|
||||||
|
property var pluginService: null
|
||||||
|
property string pluginId: ""
|
||||||
|
property string variantId: ""
|
||||||
|
property var variantData: null
|
||||||
|
|
||||||
|
// Use variantData for configuration
|
||||||
|
property string displayText: variantData?.text || "Default"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Settings Component
|
||||||
|
|
||||||
|
Provide UI to manage variants:
|
||||||
|
|
||||||
|
```qml
|
||||||
|
FocusScope {
|
||||||
|
property var pluginService: null
|
||||||
|
|
||||||
|
// Create variant
|
||||||
|
pluginService.createPluginVariant(pluginId, variantName, variantConfig)
|
||||||
|
|
||||||
|
// Remove variant
|
||||||
|
pluginService.removePluginVariant(pluginId, variantId)
|
||||||
|
|
||||||
|
// Update variant
|
||||||
|
pluginService.updatePluginVariant(pluginId, variantId, variantConfig)
|
||||||
|
|
||||||
|
// Get all variants
|
||||||
|
var variants = pluginService.getPluginVariants(pluginId)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Plugin Manifest
|
||||||
|
|
||||||
|
Standard plugin manifest - no special configuration needed:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "yourPlugin",
|
||||||
|
"name": "Your Plugin",
|
||||||
|
"component": "./Widget.qml",
|
||||||
|
"settings": "./Settings.qml"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
- **Script Runner**: Multiple variants running different scripts
|
||||||
|
- **System Monitors**: Different monitoring targets (CPU, GPU, Network)
|
||||||
|
- **Quick Launchers**: Different apps or commands per variant
|
||||||
|
- **Custom Indicators**: Different data sources or APIs
|
||||||
|
- **Time Zones**: Multiple clocks for different time zones
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
### PluginService Functions
|
||||||
|
|
||||||
|
- `getPluginVariants(pluginId)`: Get all variants for a plugin
|
||||||
|
- `getAllPluginVariants()`: Get all variants across all plugins
|
||||||
|
- `createPluginVariant(pluginId, name, config)`: Create new variant
|
||||||
|
- `removePluginVariant(pluginId, variantId)`: Delete variant
|
||||||
|
- `updatePluginVariant(pluginId, variantId, config)`: Update variant
|
||||||
|
- `getPluginVariantData(pluginId, variantId)`: Get specific variant data
|
||||||
|
|
||||||
|
### Widget Properties
|
||||||
|
|
||||||
|
- `pluginId`: Base plugin identifier
|
||||||
|
- `variantId`: Variant identifier (null if no variant)
|
||||||
|
- `variantData`: Variant configuration object
|
||||||
|
- `pluginService`: PluginService reference
|
||||||
303
PLUGINS/ExampleWithVariants/VariantSettings.qml
Normal file
303
PLUGINS/ExampleWithVariants/VariantSettings.qml
Normal file
@@ -0,0 +1,303 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
import qs.Modules.Plugins
|
||||||
|
|
||||||
|
PluginSettings {
|
||||||
|
id: root
|
||||||
|
pluginId: "exampleVariants"
|
||||||
|
|
||||||
|
onVariantsChanged: {
|
||||||
|
variantsModel.clear()
|
||||||
|
for (var i = 0; i < variants.length; i++) {
|
||||||
|
variantsModel.append(variants[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
width: parent.width
|
||||||
|
text: "Variant Manager"
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
width: parent.width
|
||||||
|
text: "Create multiple widget variants with different text, icons, and colors"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
width: parent.width
|
||||||
|
height: addVariantColumn.implicitHeight + Theme.spacingL * 2
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surfaceContainerHigh
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: addVariantColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingL
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Add New Variant"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: (parent.width - Theme.spacingM * 2) / 3
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Name"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
id: nameField
|
||||||
|
width: parent.width
|
||||||
|
placeholderText: "Variant Name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: (parent.width - Theme.spacingM * 2) / 3
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Icon"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
id: iconField
|
||||||
|
width: parent.width
|
||||||
|
placeholderText: "star"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: (parent.width - Theme.spacingM * 2) / 3
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Text"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
id: textField
|
||||||
|
width: parent.width
|
||||||
|
placeholderText: "Display Text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: "Create Variant"
|
||||||
|
iconName: "add"
|
||||||
|
onClicked: {
|
||||||
|
if (!nameField.text) {
|
||||||
|
ToastService.showError("Please enter a variant name")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var variantConfig = {
|
||||||
|
text: textField.text || nameField.text,
|
||||||
|
icon: iconField.text || "widgets"
|
||||||
|
}
|
||||||
|
|
||||||
|
createVariant(nameField.text, variantConfig)
|
||||||
|
ToastService.showInfo("Variant created: " + nameField.text)
|
||||||
|
|
||||||
|
nameField.text = ""
|
||||||
|
iconField.text = ""
|
||||||
|
textField.text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
width: parent.width
|
||||||
|
height: Math.max(200, variantsColumn.implicitHeight + Theme.spacingL * 2)
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surfaceContainerHigh
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: variantsColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingL
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Existing Variants"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
width: parent.width
|
||||||
|
height: Math.max(100, contentHeight)
|
||||||
|
clip: true
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
model: ListModel {
|
||||||
|
id: variantsModel
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: StyledRect {
|
||||||
|
required property var model
|
||||||
|
width: ListView.view.width
|
||||||
|
height: variantRow.implicitHeight + Theme.spacingM * 2
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: variantMouseArea.containsMouse ? Theme.surfaceContainerHighest : Theme.surfaceContainer
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: variantRow
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingM
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: Theme.iconSize
|
||||||
|
height: Theme.iconSize
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: model.icon || "widgets"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.surfaceText
|
||||||
|
width: Theme.iconSize
|
||||||
|
height: Theme.iconSize
|
||||||
|
clip: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
width: parent.width - Theme.iconSize - deleteButton.width - Theme.spacingM * 4
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: model.name || "Unnamed"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
width: parent.width
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Text: " + (model.text || "") + " | Icon: " + (model.icon || "")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
width: parent.width
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: deleteButton
|
||||||
|
width: 32
|
||||||
|
height: 32
|
||||||
|
radius: 16
|
||||||
|
color: deleteArea.containsMouse ? Theme.error : "transparent"
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: "delete"
|
||||||
|
size: 16
|
||||||
|
color: deleteArea.containsMouse ? Theme.onError : Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: deleteArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
removeVariant(model.id)
|
||||||
|
ToastService.showInfo("Variant removed: " + model.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: variantMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
propagateComposedEvents: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "No variants created yet"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
visible: variantsModel.count === 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
width: parent.width
|
||||||
|
height: instructionsColumn.implicitHeight + Theme.spacingL * 2
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surface
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: instructionsColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingL
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "info"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "How to Use Variants"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "1. Create variants with different names, icons, and text\n2. Go to Bar Settings and click 'Add Widget'\n3. Each variant will appear as a separate widget option\n4. Add variants to your bar just like any other widget"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: parent.width
|
||||||
|
lineHeight: 1.4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
PLUGINS/ExampleWithVariants/VariantWidget.qml
Normal file
57
PLUGINS/ExampleWithVariants/VariantWidget.qml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
import qs.Modules.Plugins
|
||||||
|
|
||||||
|
PluginComponent {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string variantId: ""
|
||||||
|
property var variantData: null
|
||||||
|
|
||||||
|
property string displayText: variantData?.text || "Default Text"
|
||||||
|
property string displayIcon: variantData?.icon || "widgets"
|
||||||
|
|
||||||
|
horizontalBarPill: Component {
|
||||||
|
Row {
|
||||||
|
spacing: 3
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: root.displayIcon
|
||||||
|
size: Theme.iconSize - 8
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: root.displayText
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verticalBarPill: Component {
|
||||||
|
Column {
|
||||||
|
spacing: 1
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: root.displayIcon
|
||||||
|
size: Theme.iconSize - 8
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: root.displayText
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
PLUGINS/ExampleWithVariants/plugin.json
Normal file
14
PLUGINS/ExampleWithVariants/plugin.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"id": "exampleVariants",
|
||||||
|
"name": "Example with Variants",
|
||||||
|
"description": "Demonstrates dynamic variant creation for plugins",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": "DMS",
|
||||||
|
"icon": "widgets",
|
||||||
|
"component": "./VariantWidget.qml",
|
||||||
|
"settings": "./VariantSettings.qml",
|
||||||
|
"permissions": [
|
||||||
|
"settings_read",
|
||||||
|
"settings_write"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -333,6 +333,93 @@ Singleton {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPluginVariants(pluginId) {
|
||||||
|
var plugin = availablePlugins[pluginId]
|
||||||
|
if (!plugin) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
var variants = SettingsData.getPluginSetting(pluginId, "variants", [])
|
||||||
|
return variants
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAllPluginVariants() {
|
||||||
|
var result = []
|
||||||
|
for (var pluginId in availablePlugins) {
|
||||||
|
var plugin = availablePlugins[pluginId]
|
||||||
|
if (plugin.type !== "widget") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var variants = getPluginVariants(pluginId)
|
||||||
|
if (variants.length === 0) {
|
||||||
|
result.push({
|
||||||
|
pluginId: pluginId,
|
||||||
|
variantId: null,
|
||||||
|
fullId: pluginId,
|
||||||
|
name: plugin.name,
|
||||||
|
icon: plugin.icon || "extension",
|
||||||
|
description: plugin.description || "Plugin widget",
|
||||||
|
loaded: plugin.loaded
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < variants.length; i++) {
|
||||||
|
var variant = variants[i]
|
||||||
|
result.push({
|
||||||
|
pluginId: pluginId,
|
||||||
|
variantId: variant.id,
|
||||||
|
fullId: pluginId + ":" + variant.id,
|
||||||
|
name: plugin.name + " - " + variant.name,
|
||||||
|
icon: variant.icon || plugin.icon || "extension",
|
||||||
|
description: variant.description || plugin.description || "Plugin widget variant",
|
||||||
|
loaded: plugin.loaded
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPluginVariant(pluginId, variantName, variantConfig) {
|
||||||
|
var variants = getPluginVariants(pluginId)
|
||||||
|
var variantId = "variant_" + Date.now()
|
||||||
|
var newVariant = Object.assign({}, variantConfig, {
|
||||||
|
id: variantId,
|
||||||
|
name: variantName
|
||||||
|
})
|
||||||
|
variants.push(newVariant)
|
||||||
|
SettingsData.setPluginSetting(pluginId, "variants", variants)
|
||||||
|
pluginDataChanged(pluginId)
|
||||||
|
return variantId
|
||||||
|
}
|
||||||
|
|
||||||
|
function removePluginVariant(pluginId, variantId) {
|
||||||
|
var variants = getPluginVariants(pluginId)
|
||||||
|
var newVariants = variants.filter(function(v) { return v.id !== variantId })
|
||||||
|
SettingsData.setPluginSetting(pluginId, "variants", newVariants)
|
||||||
|
pluginDataChanged(pluginId)
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePluginVariant(pluginId, variantId, variantConfig) {
|
||||||
|
var variants = getPluginVariants(pluginId)
|
||||||
|
for (var i = 0; i < variants.length; i++) {
|
||||||
|
if (variants[i].id === variantId) {
|
||||||
|
variants[i] = Object.assign({}, variants[i], variantConfig)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SettingsData.setPluginSetting(pluginId, "variants", variants)
|
||||||
|
pluginDataChanged(pluginId)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPluginVariantData(pluginId, variantId) {
|
||||||
|
var variants = getPluginVariants(pluginId)
|
||||||
|
for (var i = 0; i < variants.length; i++) {
|
||||||
|
if (variants[i].id === variantId) {
|
||||||
|
return variants[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
function getLoadedPlugins() {
|
function getLoadedPlugins() {
|
||||||
var result = []
|
var result = []
|
||||||
for (var key in loadedPlugins) {
|
for (var key in loadedPlugins) {
|
||||||
|
|||||||
Reference in New Issue
Block a user