1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-26 14:32:52 -05:00

switch hto monorepo structure

This commit is contained in:
bbedward
2025-11-12 17:18:45 -05:00
parent 6013c994a6
commit 24e800501a
768 changed files with 76284 additions and 221 deletions

View File

@@ -0,0 +1,140 @@
import QtQuick
import Quickshell
import qs.Services
Item {
id: root
// Plugin properties
property var pluginService: null
property string trigger: "#"
// Plugin interface signals
signal itemsChanged()
Component.onCompleted: {
console.info("LauncherExample: Plugin loaded")
// Load custom trigger from settings
if (pluginService) {
trigger = pluginService.loadPluginData("launcherExample", "trigger", "#")
}
}
// Required function: Get items for launcher
function getItems(query) {
const baseItems = [
{
name: "Test Item 1",
icon: "material:lightbulb",
comment: "This is a test item that shows a toast notification",
action: "toast:Test Item 1 executed!",
categories: ["LauncherExample"]
},
{
name: "Test Item 2",
icon: "material:star",
comment: "Another test item with different action",
action: "toast:Test Item 2 clicked!",
categories: ["LauncherExample"]
},
{
name: "Test Item 3",
icon: "material:favorite",
comment: "Third test item for demonstration",
action: "toast:Test Item 3 activated!",
categories: ["LauncherExample"]
},
{
name: "Unicode Icon Example",
icon: "unicode:🚀",
comment: "Demonstrates unicode/emoji icon support",
action: "toast:Unicode icons work great!",
categories: ["LauncherExample"]
},
{
name: "Example Copy Action",
icon: "material:content_copy",
comment: "Demonstrates copying text to clipboard",
action: "copy:This text was copied by the launcher plugin!",
categories: ["LauncherExample"]
},
{
name: "Example Script Action",
icon: "material:terminal",
comment: "Demonstrates running a simple command",
action: "script:echo 'Hello from launcher plugin!'",
categories: ["LauncherExample"]
}
]
if (!query || query.length === 0) {
return baseItems
}
// Filter items based on query
const lowerQuery = query.toLowerCase()
return baseItems.filter(item => {
return item.name.toLowerCase().includes(lowerQuery) ||
item.comment.toLowerCase().includes(lowerQuery)
})
}
// Required function: Execute item action
function executeItem(item) {
if (!item || !item.action) {
console.warn("LauncherExample: Invalid item or action")
return
}
console.log("LauncherExample: Executing item:", item.name, "with action:", item.action)
const actionParts = item.action.split(":")
const actionType = actionParts[0]
const actionData = actionParts.slice(1).join(":")
switch (actionType) {
case "toast":
showToast(actionData)
break
case "copy":
copyToClipboard(actionData)
break
case "script":
runScript(actionData)
break
default:
console.warn("LauncherExample: Unknown action type:", actionType)
showToast("Unknown action: " + actionType)
}
}
// Helper functions for different action types
function showToast(message) {
if (typeof ToastService !== "undefined") {
ToastService.showInfo("LauncherExample", message)
} else {
console.log("LauncherExample Toast:", message)
}
}
function copyToClipboard(text) {
Quickshell.execDetached(["sh", "-c", "echo -n '" + text + "' | wl-copy"])
showToast("Copied to clipboard: " + text)
}
function runScript(command) {
console.log("LauncherExample: Would run script:", command)
showToast("Script executed: " + command)
// In a real plugin, you might create a Process component here
// For demo purposes, we just show what would happen
}
// Watch for trigger changes
onTriggerChanged: {
if (pluginService) {
pluginService.savePluginData("launcherExample", "trigger", trigger)
}
}
}

View File

@@ -0,0 +1,244 @@
import QtQuick
import QtQuick.Controls
import qs.Widgets
FocusScope {
id: root
property var pluginService: null
implicitHeight: settingsColumn.implicitHeight
height: implicitHeight
Column {
id: settingsColumn
anchors.fill: parent
anchors.margins: 16
spacing: 16
Text {
text: "Launcher Example Plugin Settings"
font.pixelSize: 18
font.weight: Font.Bold
color: "#FFFFFF"
}
Text {
text: "This plugin demonstrates the launcher plugin system with example items and actions."
font.pixelSize: 14
color: "#CCFFFFFF"
wrapMode: Text.WordWrap
width: parent.width - 32
}
Rectangle {
width: parent.width - 32
height: 1
color: "#30FFFFFF"
}
Column {
spacing: 12
width: parent.width - 32
Text {
text: "Trigger Configuration"
font.pixelSize: 16
font.weight: Font.Medium
color: "#FFFFFF"
}
Text {
text: noTriggerToggle.checked ? "Items will always show in the launcher (no trigger needed)." : "Set the trigger text to activate this plugin. Type the trigger in the launcher to filter to this plugin's items."
font.pixelSize: 12
color: "#CCFFFFFF"
wrapMode: Text.WordWrap
width: parent.width
}
Row {
spacing: 12
CheckBox {
id: noTriggerToggle
text: "No trigger (always show)"
checked: loadSettings("noTrigger", false)
contentItem: Text {
text: noTriggerToggle.text
font.pixelSize: 14
color: "#FFFFFF"
leftPadding: noTriggerToggle.indicator.width + 8
verticalAlignment: Text.AlignVCenter
}
indicator: Rectangle {
implicitWidth: 20
implicitHeight: 20
radius: 4
border.color: noTriggerToggle.checked ? "#4CAF50" : "#60FFFFFF"
border.width: 2
color: noTriggerToggle.checked ? "#4CAF50" : "transparent"
Rectangle {
width: 12
height: 12
anchors.centerIn: parent
radius: 2
color: "#FFFFFF"
visible: noTriggerToggle.checked
}
}
onCheckedChanged: {
saveSettings("noTrigger", checked)
if (checked) {
saveSettings("trigger", "")
} else {
saveSettings("trigger", triggerField.text || "#")
}
}
}
}
Row {
spacing: 12
anchors.left: parent.left
anchors.right: parent.right
visible: !noTriggerToggle.checked
Text {
text: "Trigger:"
font.pixelSize: 14
color: "#FFFFFF"
anchors.verticalCenter: parent.verticalCenter
}
DankTextField {
id: triggerField
width: 100
height: 40
text: loadSettings("trigger", "#")
placeholderText: "#"
backgroundColor: "#30FFFFFF"
textColor: "#FFFFFF"
onTextEdited: {
const newTrigger = text.trim()
saveSettings("trigger", newTrigger || "#")
saveSettings("noTrigger", newTrigger === "")
}
}
Text {
text: "Examples: #, !, @, !ex, etc."
font.pixelSize: 12
color: "#AAFFFFFF"
anchors.verticalCenter: parent.verticalCenter
}
}
}
Rectangle {
width: parent.width - 32
height: 1
color: "#30FFFFFF"
}
Column {
spacing: 8
width: parent.width - 32
Text {
text: "Example Items:"
font.pixelSize: 14
font.weight: Font.Medium
color: "#FFFFFF"
}
Column {
spacing: 4
leftPadding: 16
Text {
text: "• Test Item 1, 2, 3 - Show toast notifications"
font.pixelSize: 12
color: "#CCFFFFFF"
}
Text {
text: "• Example Copy Action - Copy text to clipboard"
font.pixelSize: 12
color: "#CCFFFFFF"
}
Text {
text: "• Example Script Action - Demonstrate script execution"
font.pixelSize: 12
color: "#CCFFFFFF"
}
}
}
Rectangle {
width: parent.width - 32
height: 1
color: "#30FFFFFF"
}
Column {
spacing: 8
width: parent.width - 32
Text {
text: "Usage:"
font.pixelSize: 14
font.weight: Font.Medium
color: "#FFFFFF"
}
Column {
spacing: 4
leftPadding: 16
bottomPadding: 24
Text {
text: "1. Open Launcher (Ctrl+Space or click launcher button)"
font.pixelSize: 12
color: "#CCFFFFFF"
}
Text {
text: noTriggerToggle.checked ? "2. Items are always visible in the launcher" : "2. Type your trigger (default: #) to filter to this plugin"
font.pixelSize: 12
color: "#CCFFFFFF"
}
Text {
text: noTriggerToggle.checked ? "3. Search works normally with plugin items included" : "3. Optionally add search terms: '# test' to find test items"
font.pixelSize: 12
color: "#CCFFFFFF"
}
Text {
text: "4. Select an item and press Enter to execute its action"
font.pixelSize: 12
color: "#CCFFFFFF"
}
}
}
}
function saveSettings(key, value) {
if (pluginService) {
pluginService.savePluginData("launcherExample", key, value)
}
}
function loadSettings(key, defaultValue) {
if (pluginService) {
return pluginService.loadPluginData("launcherExample", key, defaultValue)
}
return defaultValue
}
}

View File

@@ -0,0 +1,240 @@
# LauncherExample Plugin
A demonstration plugin that showcases the DMS launcher plugin system capabilities.
## Purpose
This plugin serves as a comprehensive example for developers creating launcher plugins for DMS. It demonstrates:
- **Plugin Structure**: Proper manifest, launcher, and settings components
- **Trigger System**: Customizable trigger strings for plugin activation (including empty triggers)
- **Item Management**: Providing searchable items to the launcher
- **Action Execution**: Handling different types of actions (toast, copy, script)
- **Settings Integration**: Configurable plugin settings with persistence
## Features
### Example Items
- **Test Items 1-3**: Demonstrate toast notifications
- **Copy Action**: Shows clipboard integration
- **Script Action**: Demonstrates command execution
### Trigger System
- **Default Trigger**: `#` (configurable in settings)
- **Empty Trigger Option**: Items can always be visible without needing a trigger
- **Usage**: Type `#` in launcher to filter to this plugin (when trigger is set)
- **Search**: Type `# test` to search within plugin items
### Action Types
- `toast:message` - Shows toast notification
- `copy:text` - Copies text to clipboard
- `script:command` - Executes shell command (demo only)
## File Structure
```
PLUGINS/LauncherExample/
├── plugin.json # Plugin manifest
├── LauncherExampleLauncher.qml # Main launcher component
├── LauncherExampleSettings.qml # Settings interface
└── README.md # This documentation
```
## Installation
1. **Plugin Directory**: Copy to `~/.config/DankMaterialShell/plugins/LauncherExample`
2. **Enable Plugin**: Settings → Plugins → Enable "LauncherExample"
3. **Configure**: Set custom trigger in plugin settings if desired
## Usage
### With Trigger (Default)
1. Open launcher (Ctrl+Space or launcher button)
2. Type `#` to activate plugin trigger
3. Browse available items or add search terms
4. Press Enter to execute selected item
### Without Trigger (Empty Trigger Mode)
1. Enable "No trigger (always show)" in plugin settings
2. Open launcher - plugin items are always visible
3. Search works normally with plugin items included
4. Press Enter to execute selected item
### Search Examples
- `#` - Show all plugin items (with trigger enabled)
- `# test` - Show items matching "test"
- `# copy` - Show items matching "copy"
- `test` - Show all items matching "test" (with empty trigger enabled)
## Developer Guide
### Plugin Contract
**Launcher Component Requirements**:
```qml
// Required properties
property var pluginService: null
property string trigger: "#"
// Required signals
signal itemsChanged()
// Required functions
function getItems(query): array
function executeItem(item): void
```
**Item Structure**:
```javascript
{
name: "Item Name", // Display name
icon: "icon_name", // Icon (optional, see Icon Types below)
comment: "Description", // Subtitle text
action: "type:data", // Action to execute
categories: ["PluginName"] // Category array
}
```
**Icon Types**:
The `icon` field supports four formats:
1. **Material Design Icons** - Use `material:` prefix:
```javascript
icon: "material:lightbulb" // Material Symbols Rounded font
```
Examples: `material:star`, `material:favorite`, `material:settings`
2. **Unicode/Emoji Icons** - Use `unicode:` prefix:
```javascript
icon: "unicode:🚀" // Unicode character or emoji
```
Display any Unicode character or emoji as the icon. Examples: `unicode:😀`, `unicode:⚡`, `unicode:🎨`
3. **Desktop Theme Icons** - Use icon name directly:
```javascript
icon: "firefox" // Uses system icon theme
```
Examples: `firefox`, `chrome`, `folder`, `text-editor`
4. **No Icon** - Omit the `icon` field entirely:
```javascript
{
name: "😀 Grinning Face",
// No icon field
comment: "Copy emoji",
action: "copy:😀",
categories: ["MyPlugin"]
}
```
When icon is omitted, the launcher hides the icon area and displays only text
**Action Format**: `type:data` where:
- `type` - Action handler (toast, copy, script, etc.)
- `data` - Action-specific data
### Settings Integration
```qml
// Save setting
pluginService.savePluginData("pluginId", "key", value)
// Load setting
pluginService.loadPluginData("pluginId", "key", defaultValue)
```
### Trigger Configuration
The trigger can be configured in two ways:
1. **Empty Trigger** (No Trigger Mode):
- Check "No trigger (always show)" in settings
- Saves `trigger: ""` and `noTrigger: true`
- Items always appear in launcher alongside regular apps
2. **Custom Trigger**:
- Enter any string (e.g., `#`, `!`, `@`, `!ex`)
- Uncheck "No trigger" checkbox
- Items only appear when trigger is typed
### Manifest Structure
```json
{
"id": "launcherExample",
"name": "LauncherExample",
"type": "launcher",
"capabilities": ["launcher"],
"component": "./LauncherExampleLauncher.qml",
"settings": "./LauncherExampleSettings.qml",
"permissions": ["settings_read", "settings_write"]
}
```
Note: The `trigger` field in the manifest is optional and serves as the default trigger value.
## Extending This Plugin
### Adding New Items
```qml
function getItems(query) {
return [
{
name: "My Item",
icon: "custom_icon",
comment: "Does something cool",
action: "custom:action_data",
categories: ["LauncherExample"]
}
]
}
```
### Adding New Actions
```qml
function executeItem(item) {
const actionParts = item.action.split(":")
const actionType = actionParts[0]
const actionData = actionParts.slice(1).join(":")
switch (actionType) {
case "custom":
handleCustomAction(actionData)
break
}
}
```
### Custom Trigger Logic
```qml
Component.onCompleted: {
if (pluginService) {
trigger = pluginService.loadPluginData("launcherExample", "trigger", "#")
}
}
onTriggerChanged: {
if (pluginService) {
pluginService.savePluginData("launcherExample", "trigger", trigger)
}
}
```
## Best Practices
1. **Unique Triggers**: Choose triggers that don't conflict with other plugins
2. **Clear Descriptions**: Write helpful item comments
3. **Error Handling**: Gracefully handle action failures
4. **Performance**: Return results quickly in getItems()
5. **Cleanup**: Destroy temporary objects in executeItem()
6. **Empty Trigger Support**: Consider if your plugin should support empty trigger mode
## Testing
Test the plugin by:
1. Installing and enabling in DMS
2. Testing with trigger enabled
3. Testing with empty trigger (no trigger mode)
4. Trying each action type
5. Testing search functionality
6. Verifying settings persistence
This plugin provides a solid foundation for building more sophisticated launcher plugins with custom functionality!

View File

@@ -0,0 +1,17 @@
{
"id": "launcherExample",
"name": "LauncherExample",
"description": "Example launcher plugin demonstrating the launcher plugin system",
"version": "1.0.0",
"author": "DMS Team",
"icon": "extension",
"type": "launcher",
"capabilities": ["clipboard", "command-execution"],
"component": "./LauncherExampleLauncher.qml",
"settings": "./LauncherExampleSettings.qml",
"trigger": "#",
"permissions": [
"settings_read",
"settings_write"
]
}