1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-12 23:32:50 -04:00

add dms-plugin-dev agent skill for plugin development (#2394)

This commit is contained in:
Bruno Rocha
2026-05-12 14:26:38 +01:00
committed by GitHub
parent c878ffb7f9
commit 9b68fc8213
25 changed files with 3491 additions and 0 deletions
@@ -0,0 +1,176 @@
# Data Persistence Guide
DMS plugins have three tiers of data persistence, each suited for different use cases.
## Tier 1: Plugin Data (Settings)
Persisted to `settings.json`. Use for user preferences and configuration.
### Saving
```qml
pluginService.savePluginData(pluginId, "key", value)
```
### Loading
```qml
var value = pluginService.loadPluginData(pluginId, "key", defaultValue)
```
### Reactive Access via pluginData
`PluginComponent` has a reactive `pluginData` property that auto-loads from settings:
```qml
PluginComponent {
property string displayText: pluginData?.text || "Default"
property bool showIcon: pluginData?.showIcon !== undefined ? pluginData.showIcon : true
}
```
### Reacting to Settings Changes
When settings are changed (e.g., from the settings UI), react with `Connections`:
```qml
Connections {
target: pluginService
function onPluginDataChanged(changedId) {
if (changedId !== pluginId) return
displayText = pluginService.loadPluginData(pluginId, "text", "Default")
showIcon = pluginService.loadPluginData(pluginId, "showIcon", true)
}
}
```
## Tier 2: Plugin State
Persisted to a separate state file. Use for runtime state that should survive restarts but is not user-configurable (history, cache, counters).
### Saving
```qml
pluginService.savePluginState(pluginId, "key", value)
```
### Loading
```qml
var state = pluginService.loadPluginState(pluginId, "key", defaultValue)
```
### Additional Methods
```qml
pluginService.clearPluginState(pluginId)
pluginService.removePluginStateKey(pluginId, "key")
```
### Example: Persistent History
```qml
Item {
property var history: []
Component.onCompleted: {
history = pluginService?.loadPluginState(pluginId, "history", []) || []
}
function addToHistory(entry) {
history.unshift({
text: entry,
timestamp: Date.now()
})
if (history.length > 100) history = history.slice(0, 100)
pluginService?.savePluginState(pluginId, "history", history)
}
function clearHistory() {
history = []
pluginService?.removePluginStateKey(pluginId, "history")
}
}
```
## Tier 3: Global Variables (Runtime Only)
NOT persisted. Shared across all instances of a plugin. Use for cross-instance state synchronization (multi-monitor consistency, multi-instance widgets).
### Using PluginGlobalVar Component
```qml
import qs.Modules.Plugins
PluginComponent {
PluginGlobalVar {
id: globalCounter
varName: "counter"
defaultValue: 0
}
horizontalBarPill: Component {
StyledRect {
// ...
StyledText {
text: "Count: " + globalCounter.value
}
MouseArea {
onClicked: globalCounter.set(globalCounter.value + 1)
}
}
}
}
```
**PluginGlobalVar properties:**
| Property | Type | Description |
|----------|------|-------------|
| `varName` | string | Required: name of the global variable |
| `defaultValue` | any | Optional: default if not set |
| `value` | any | Readonly: current value |
**Methods:**
- `set(newValue)` - update the value (triggers reactivity across all instances)
### Using PluginService API Directly
```qml
import qs.Services
property int counter: PluginService.getGlobalVar("myPlugin", "counter", 0)
Connections {
target: PluginService
function onGlobalVarChanged(pluginId, varName) {
if (pluginId === "myPlugin" && varName === "counter") {
counter = PluginService.getGlobalVar("myPlugin", "counter", 0)
}
}
}
function increment() {
var current = PluginService.getGlobalVar("myPlugin", "counter", 0)
PluginService.setGlobalVar("myPlugin", "counter", current + 1)
}
```
## Decision Matrix
| Need | API | Persisted | Scope |
|------|-----|-----------|-------|
| User preferences (API keys, themes, intervals) | `savePluginData` / `loadPluginData` | Yes (settings.json) | Per plugin |
| Runtime state (history, cache, counters) | `savePluginState` / `loadPluginState` | Yes (state file) | Per plugin |
| Cross-instance sync (multi-monitor data) | `PluginGlobalVar` or `getGlobalVar`/`setGlobalVar` | No (runtime only) | All instances |
| Quick reactive reads from settings | `pluginData` property | N/A (read-only) | Per instance |
## Important Notes
1. **pluginData is reactive** - bindings update automatically when data changes
2. **Global vars are NOT persistent** - they reset when the shell restarts
3. **State vs Data** - data is for user-facing settings, state is for internal runtime data
4. **Null safety** - always check `pluginService` is not null before calling methods
5. **Signal namespacing** - global var signals include `pluginId` to filter for your plugin
6. **Performance** - global vars are efficient for frequent updates; settings writes are batched