1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-07 22:15:38 -05:00

plugins: support for multiple widgets per-plugin (variants)

This commit is contained in:
bbedward
2025-10-06 12:33:58 -04:00
parent 11a1af89f4
commit 89793d2d62
10 changed files with 676 additions and 14 deletions

View 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

View 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
}
}
}
}

View 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
}
}
}
}

View 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"
]
}