Remove .config/DankMaterialShell/firefox.css

Remove .config/DankMaterialShell/plugin_settings.json
Remove .config/DankMaterialShell/plugins/calculator/CalculatorLauncher.qml
Remove .config/DankMaterialShell/plugins/calculator/CalculatorSettings.qml
Remove .config/DankMaterialShell/plugins/calculator/README.md
Remove .config/DankMaterialShell/plugins/calculator/calculator.js
Remove .config/DankMaterialShell/plugins/calculator/.git/HEAD
Remove .config/DankMaterialShell/plugins/calculator/.git/config
Remove .config/DankMaterialShell/plugins/calculator/.git/index
Remove .config/DankMaterialShell/plugins/calculator/.git/objects/info/.keep
Remove .config/DankMaterialShell/plugins/calculator/.git/objects/pack/pack-67f644835e660794f65c9273e46788b0c3da57cf.idx
Remove .config/DankMaterialShell/plugins/calculator/.git/objects/pack/pack-67f644835e660794f65c9273e46788b0c3da57cf.rev
Remove .config/DankMaterialShell/plugins/calculator/.git/objects/pack/pack-67f644835e660794f65c9273e46788b0c3da57cf.pack
Remove .config/DankMaterialShell/plugins/calculator/.git/refs/heads/main
Remove .config/DankMaterialShell/plugins/calculator/.git/refs/remotes/origin/main
Remove .config/DankMaterialShell/plugins/calculator/.git/refs/remotes/origin/qalc
Remove .config/DankMaterialShell/plugins/calculator/.git/refs/tags/.keep
Remove .config/DankMaterialShell/plugins/calculator/plugin.json
Remove .config/DankMaterialShell/plugins/calculator/screenshot.png
Remove .config/DankMaterialShell/plugins/calculator/test_precision.js
Remove .config/DankMaterialShell/plugins/calculator/test_single.js
Remove .config/DankMaterialShell/plugins/commandRunner/CommandRunner.qml
Remove .config/DankMaterialShell/plugins/commandRunner/CommandRunnerSettings.qml
Remove .config/DankMaterialShell/plugins/commandRunner/LICENSE
Remove .config/DankMaterialShell/plugins/commandRunner/README.md
Remove .config/DankMaterialShell/plugins/commandRunner/.git/HEAD
Remove .config/DankMaterialShell/plugins/commandRunner/.git/config
Remove .config/DankMaterialShell/plugins/commandRunner/.git/index
Remove .config/DankMaterialShell/plugins/commandRunner/.git/objects/info/.keep
Remove .config/DankMaterialShell/plugins/commandRunner/.git/objects/pack/pack-5a720f795fd2994ef506cd867d86ca7df8a25a31.idx
Remove .config/DankMaterialShell/plugins/commandRunner/.git/objects/pack/pack-5a720f795fd2994ef506cd867d86ca7df8a25a31.rev
Remove .config/DankMaterialShell/plugins/commandRunner/.git/objects/pack/pack-5a720f795fd2994ef506cd867d86ca7df8a25a31.pack
Remove .config/DankMaterialShell/plugins/commandRunner/.git/refs/heads/main
Remove .config/DankMaterialShell/plugins/commandRunner/.git/refs/remotes/origin/main
Remove .config/DankMaterialShell/plugins/commandRunner/.git/refs/tags/.keep
Remove .config/DankMaterialShell/plugins/commandRunner/plugin.json
Remove .config/DankMaterialShell/plugins/commandRunner/screenshot.png
Remove .config/DankMaterialShell/plugins/dankActions.meta
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankActions/DankActionsSettings.qml
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankActions/DankActionsWidget.qml
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankActions/plugin.json
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankBatteryAlerts/DankBatteryAlerts.qml
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankBatteryAlerts/DankBatteryAlertsSettings.qml
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankBatteryAlerts/plugin.json
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankHooks/DankHooks.qml
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankHooks/DankHooksSettings.qml
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankHooks/README.md
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankHooks/plugin.json
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankPomodoroTimer/DankPomodoroSettings.qml
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankPomodoroTimer/DankPomodoroWidget.qml
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankPomodoroTimer/plugin.json
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/LICENSE
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/README.md
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/HEAD
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/config
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/index
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/info/.keep
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/pack/pack-3221a15c022ef4a7bb6bf2c47e40068b66b3588b.idx
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/pack/pack-3221a15c022ef4a7bb6bf2c47e40068b66b3588b.rev
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/pack/pack-3221a15c022ef4a7bb6bf2c47e40068b66b3588b.pack
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/refs/heads/master
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/refs/remotes/origin/master
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/refs/tags/.keep
Remove .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.gitignore
Remove .config/DankMaterialShell/plugins/emojiLauncher/EmojiLauncher.qml
Remove .config/DankMaterialShell/plugins/emojiLauncher/EmojiLauncherSettings.qml
Remove .config/DankMaterialShell/plugins/emojiLauncher/LICENSE
Remove .config/DankMaterialShell/plugins/emojiLauncher/README.md
Remove .config/DankMaterialShell/plugins/emojiLauncher/catalog.js
Remove .config/DankMaterialShell/plugins/emojiLauncher/data/emojis.txt
Remove .config/DankMaterialShell/plugins/emojiLauncher/data/math.txt
Remove .config/DankMaterialShell/plugins/emojiLauncher/data/nerdfont.txt
Remove .config/DankMaterialShell/plugins/emojiLauncher/.git/HEAD
Remove .config/DankMaterialShell/plugins/emojiLauncher/.git/config
Remove .config/DankMaterialShell/plugins/emojiLauncher/.git/index
Remove .config/DankMaterialShell/plugins/emojiLauncher/.git/objects/info/.keep
Remove .config/DankMaterialShell/plugins/emojiLauncher/.git/objects/pack/pack-e04a5b1ea381dc3a792b8bf08cf70e735b195c0d.idx
Remove .config/DankMaterialShell/plugins/emojiLauncher/.git/objects/pack/pack-e04a5b1ea381dc3a792b8bf08cf70e735b195c0d.rev
Remove .config/DankMaterialShell/plugins/emojiLauncher/.git/objects/pack/pack-e04a5b1ea381dc3a792b8bf08cf70e735b195c0d.pack
Remove .config/DankMaterialShell/plugins/emojiLauncher/.git/refs/heads/main
Remove .config/DankMaterialShell/plugins/emojiLauncher/.git/refs/remotes/origin/main
Remove .config/DankMaterialShell/plugins/emojiLauncher/.git/refs/tags/.keep
Remove .config/DankMaterialShell/plugins/emojiLauncher/plugin.json
Remove .config/DankMaterialShell/plugins/emojiLauncher/screenshot.png
Remove .config/DankMaterialShell/plugins/emojiLauncher/scripts/generate_catalog.py
Remove .config/DankMaterialShell/plugins/dankActions
Remove .config/DankMaterialShell/plugins/webSearch/LICENSE
Remove .config/DankMaterialShell/plugins/webSearch/README.md
Remove .config/DankMaterialShell/plugins/webSearch/WebSearch.qml
Remove .config/DankMaterialShell/plugins/webSearch/WebSearchSettings.qml
Remove .config/DankMaterialShell/plugins/webSearch/.git/HEAD
Remove .config/DankMaterialShell/plugins/webSearch/.git/config
Remove .config/DankMaterialShell/plugins/webSearch/.git/index
Remove .config/DankMaterialShell/plugins/webSearch/.git/objects/info/.keep
Remove .config/DankMaterialShell/plugins/webSearch/.git/objects/pack/pack-6a60c736f418e5b4b1f0505f66c1e2a371d46fed.idx
Remove .config/DankMaterialShell/plugins/webSearch/.git/objects/pack/pack-6a60c736f418e5b4b1f0505f66c1e2a371d46fed.rev
Remove .config/DankMaterialShell/plugins/webSearch/.git/objects/pack/pack-6a60c736f418e5b4b1f0505f66c1e2a371d46fed.pack
Remove .config/DankMaterialShell/plugins/webSearch/.git/refs/heads/main
Remove .config/DankMaterialShell/plugins/webSearch/.git/refs/remotes/origin/main
Remove .config/DankMaterialShell/plugins/webSearch/.git/refs/tags/.keep
Remove .config/DankMaterialShell/plugins/webSearch/plugin.json
Remove .config/DankMaterialShell/plugins/webSearch/screenshot.png
Remove .config/DankMaterialShell/settings.json
This commit is contained in:
Lewis Wynne 2026-01-07 15:08:40 +00:00
parent e08bb9229f
commit 917b479a94
103 changed files with 0 additions and 24611 deletions

View file

@ -1,644 +0,0 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Services
import qs.Widgets
import qs.Modules.Plugins
PluginSettings {
id: root
pluginId: "dankActions"
property string editingVariantId: ""
function loadVariantForEditing(variantData) {
editingVariantId = variantData.id || ""
nameField.text = variantData.name || ""
iconField.text = variantData.icon || ""
displayTextField.text = variantData.displayText || ""
displayCommandField.text = variantData.displayCommand || ""
clickCommandField.text = variantData.clickCommand || ""
middleClickCommandField.text = variantData.middleClickCommand || ""
rightClickCommandField.text = variantData.rightClickCommand || ""
updateIntervalField.text = (variantData.updateInterval || 0).toString()
showIconToggle.checked = variantData.showIcon !== undefined ? variantData.showIcon : true
showTextToggle.checked = variantData.showText !== undefined ? variantData.showText : true
}
function clearForm() {
editingVariantId = ""
nameField.text = ""
iconField.text = ""
displayTextField.text = ""
displayCommandField.text = ""
clickCommandField.text = ""
middleClickCommandField.text = ""
rightClickCommandField.text = ""
updateIntervalField.text = "0"
showIconToggle.checked = true
showTextToggle.checked = true
}
StyledText {
width: parent.width
text: "Custom Action Manager"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Bold
color: Theme.surfaceText
}
StyledText {
width: parent.width
text: "Create custom widgets that execute commands and display dynamic output"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
}
StyledRect {
width: parent.width
height: addActionColumn.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
Column {
id: addActionColumn
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
StyledText {
text: root.editingVariantId ? "Edit Action" : "Create New Action"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
DankButton {
text: "Cancel"
iconName: "close"
visible: root.editingVariantId !== ""
onClicked: root.clearForm()
}
}
Row {
width: parent.width
spacing: Theme.spacingM
Column {
width: (parent.width - Theme.spacingM) / 2
spacing: Theme.spacingXS
StyledText {
text: "Variant Name *"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: nameField
width: parent.width
placeholderText: "e.g., Power Profile"
keyNavigationTab: iconField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(nameField)
}
}
}
Column {
width: (parent.width - Theme.spacingM) / 2
spacing: Theme.spacingXS
StyledText {
text: "Icon Name"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: iconField
width: parent.width
placeholderText: "e.g., power_settings_new"
keyNavigationBacktab: nameField
keyNavigationTab: displayTextField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(iconField)
}
}
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Static Display Text (optional)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: displayTextField
width: parent.width
placeholderText: "Text to show (or leave empty if using command output)"
keyNavigationBacktab: iconField
keyNavigationTab: displayCommandField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(displayTextField)
}
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Display Command (optional)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: displayCommandField
width: parent.width
placeholderText: 'e.g., echo "Hello World" or powerprofilesctl get'
keyNavigationBacktab: displayTextField
keyNavigationTab: clickCommandField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(displayCommandField)
}
}
StyledText {
text: "Command output will replace static text. Runs on widget load."
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Left Click Command (optional)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: clickCommandField
width: parent.width
placeholderText: "e.g., notify-send 'Clicked!' or cycle-power-profile.sh"
keyNavigationBacktab: displayCommandField
keyNavigationTab: middleClickCommandField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(clickCommandField)
}
}
StyledText {
text: "Command to run on left click. After completion, display command refreshes."
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Middle Click Command (optional)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: middleClickCommandField
width: parent.width
placeholderText: "e.g., notify-send 'Middle clicked!'"
keyNavigationBacktab: clickCommandField
keyNavigationTab: rightClickCommandField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(middleClickCommandField)
}
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Right Click Command (optional)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: rightClickCommandField
width: parent.width
placeholderText: "e.g., notify-send 'Right clicked!'"
keyNavigationBacktab: middleClickCommandField
keyNavigationTab: updateIntervalField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(rightClickCommandField)
}
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Update Interval (seconds, 0 = disabled)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: updateIntervalField
width: parent.width
placeholderText: "0"
text: "0"
keyNavigationBacktab: rightClickCommandField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(updateIntervalField)
}
}
StyledText {
text: "Automatically re-run display command every N seconds. Set to 0 to disable."
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
Row {
width: parent.width
spacing: Theme.spacingL
Column {
spacing: Theme.spacingXS
StyledText {
text: "Show Icon"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankToggle {
id: showIconToggle
checked: true
onToggled: isChecked => {
checked = isChecked
}
}
}
Column {
spacing: Theme.spacingXS
StyledText {
text: "Show Text"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankToggle {
id: showTextToggle
checked: true
onToggled: isChecked => {
checked = isChecked
}
}
}
}
DankButton {
text: root.editingVariantId ? "Update Action" : "Create Action"
iconName: root.editingVariantId ? "check" : "add"
onClicked: {
if (!nameField.text) {
ToastService.showError("Please enter a variant name")
return
}
var interval = parseInt(updateIntervalField.text) || 0
if (interval < 0) {
ToastService.showError("Update interval must be 0 or greater")
return
}
var variantConfig = {
icon: iconField.text || "terminal",
displayText: displayTextField.text || "",
displayCommand: displayCommandField.text || "",
clickCommand: clickCommandField.text || "",
middleClickCommand: middleClickCommandField.text || "",
rightClickCommand: rightClickCommandField.text || "",
updateInterval: interval,
showIcon: showIconToggle.checked,
showText: showTextToggle.checked
}
if (root.editingVariantId) {
variantConfig.name = nameField.text
updateVariant(root.editingVariantId, variantConfig)
} else {
createVariant(nameField.text, variantConfig)
}
root.clearForm()
}
}
}
}
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 Actions"
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: root.variantsModel
delegate: StyledRect {
required property var model
width: ListView.view.width
height: variantColumn.implicitHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
color: variantMouseArea.containsMouse ? Theme.surfaceContainerHighest : Theme.surfaceContainer
Column {
id: variantColumn
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingXS
Row {
width: parent.width
spacing: Theme.spacingM
Item {
width: Theme.iconSize
height: Theme.iconSize
anchors.verticalCenter: parent.verticalCenter
DankIcon {
anchors.centerIn: parent
name: model.icon || "terminal"
size: Theme.iconSize
color: Theme.surfaceText
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 2
width: parent.width - Theme.iconSize - (editButton.width + deleteButton.width + Theme.spacingXS) - Theme.spacingM * 3
StyledText {
text: model.name || "Unnamed"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
width: parent.width
elide: Text.ElideRight
}
StyledText {
text: {
var parts = []
if (model.displayText) parts.push("Text: " + model.displayText)
if (model.displayCommand) parts.push("Cmd: " + model.displayCommand)
if (model.updateInterval && model.updateInterval > 0) parts.push("Update: " + model.updateInterval + "s")
return parts.join(" | ") || "No display config"
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
elide: Text.ElideRight
}
StyledText {
text: {
var actions = []
if (model.clickCommand) actions.push("L: " + model.clickCommand)
if (model.middleClickCommand) actions.push("M: " + model.middleClickCommand)
if (model.rightClickCommand) actions.push("R: " + model.rightClickCommand)
return actions.join(" | ") || "No click actions"
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
elide: Text.ElideRight
}
}
Row {
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
Rectangle {
id: editButton
width: 32
height: 32
radius: 16
color: editArea.containsMouse ? Theme.primary : "transparent"
DankIcon {
anchors.centerIn: parent
name: "edit"
size: 16
color: editArea.containsMouse ? Theme.onPrimary : Theme.surfaceVariantText
}
MouseArea {
id: editArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.loadVariantForEditing(model)
}
}
}
Rectangle {
id: deleteButton
width: 32
height: 32
radius: 16
color: deleteArea.containsMouse ? Theme.error : "transparent"
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)
}
}
}
}
}
}
MouseArea {
id: variantMouseArea
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
}
}
StyledText {
anchors.centerIn: parent
text: "No actions created yet"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
visible: variantsModel.count === 0
}
}
}
}
StyledRect {
width: parent.width
height: examplesColumn.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surface
Column {
id: examplesColumn
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
spacing: Theme.spacingM
DankIcon {
name: "lightbulb"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Usage Examples"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "• Power Profile Cycler"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Display: powerprofilesctl get\nClick: powerprofilesctl set $(powerprofilesctl list | grep -v \"$(powerprofilesctl get)\" | head -1)"
font.pixelSize: Theme.fontSizeSmall
font.family: "monospace"
color: Theme.surfaceVariantText
wrapMode: Text.Wrap
width: parent.width
leftPadding: Theme.spacingM
}
StyledText {
text: "• System Uptime"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Display: uptime -p | sed 's/up //'\nClick: notify-send \"Uptime\" \"$(uptime -p)\""
font.pixelSize: Theme.fontSizeSmall
font.family: "monospace"
color: Theme.surfaceVariantText
wrapMode: Text.Wrap
width: parent.width
leftPadding: Theme.spacingM
}
StyledText {
text: "• Custom Greeting"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Display: echo \"Hello $(whoami)!\"\nClick: notify-send \"Hi!\" \"Welcome back!\""
font.pixelSize: Theme.fontSizeSmall
font.family: "monospace"
color: Theme.surfaceVariantText
wrapMode: Text.Wrap
width: parent.width
leftPadding: Theme.spacingM
}
}
StyledText {
text: "After creating actions, add them to your bar from Bar Settings → Add Widget"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
}
}

View file

@ -1,263 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Io
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 displayIcon: "terminal"
property string displayText: ""
property string displayCommand: ""
property string clickCommand: ""
property string middleClickCommand: ""
property string rightClickCommand: ""
property int updateInterval: 0
property bool showIcon: true
property bool showText: true
property string currentOutput: ""
property bool isLoading: false
onVariantDataChanged: {
updatePropertiesFromVariantData()
}
Connections {
target: PluginService
function onPluginDataChanged(changedPluginId) {
if (changedPluginId === "dankActions" && variantId) {
const newData = PluginService.getPluginVariantData("dankActions", variantId)
if (newData) {
variantData = newData
}
}
}
}
function updatePropertiesFromVariantData() {
if (!variantData) {
displayIcon = "terminal"
displayText = ""
displayCommand = ""
clickCommand = ""
middleClickCommand = ""
rightClickCommand = ""
updateInterval = 0
showIcon = true
showText = true
currentOutput = ""
return
}
displayIcon = variantData.icon || "terminal"
displayText = variantData.displayText || ""
displayCommand = variantData.displayCommand || ""
clickCommand = variantData.clickCommand || ""
middleClickCommand = variantData.middleClickCommand || ""
rightClickCommand = variantData.rightClickCommand || ""
updateInterval = variantData.updateInterval || 0
showIcon = variantData.showIcon !== undefined ? variantData.showIcon : true
showText = variantData.showText !== undefined ? variantData.showText : true
if (displayCommand) {
Qt.callLater(refreshOutput)
} else {
currentOutput = displayText
}
if (updateInterval > 0) {
updateTimer.restart()
}
}
onDisplayCommandChanged: {
if (displayCommand) {
Qt.callLater(refreshOutput)
} else {
currentOutput = displayText
}
}
onDisplayTextChanged: {
if (!displayCommand) {
currentOutput = displayText
}
}
onUpdateIntervalChanged: {
if (updateInterval > 0) {
updateTimer.restart()
} else {
updateTimer.stop()
}
}
Component.onCompleted: {
if (displayCommand) {
Qt.callLater(refreshOutput)
} else {
currentOutput = displayText
}
if (updateInterval > 0) {
updateTimer.start()
}
}
Timer {
id: updateTimer
interval: root.updateInterval * 1000
repeat: true
running: false
onTriggered: {
if (root.displayCommand) {
root.refreshOutput()
}
}
}
function refreshOutput() {
if (!displayCommand) {
currentOutput = displayText
return
}
isLoading = true
displayProcess.running = true
}
function executeCommand(command) {
if (!command) return
isLoading = true
actionProcess.command = ["sh", "-c", command]
actionProcess.running = true
}
Process {
id: displayProcess
command: ["sh", "-c", root.displayCommand]
running: false
stdout: SplitParser {
onRead: data => {
root.currentOutput = data.trim()
}
}
onExited: (exitCode, exitStatus) => {
root.isLoading = false
if (exitCode !== 0) {
console.warn("CustomActions: Display command failed with code", exitCode)
}
}
}
Process {
id: actionProcess
command: ["sh", "-c", ""]
running: false
onExited: (exitCode, exitStatus) => {
root.isLoading = false
if (exitCode === 0) {
if (root.displayCommand) {
root.refreshOutput()
}
} else {
console.warn("CustomActions: Action command failed with code", exitCode)
}
}
}
pillClickAction: () => {
if (root.clickCommand) {
root.executeCommand(root.clickCommand)
}
}
horizontalBarPill: Component {
MouseArea {
implicitWidth: contentRow.implicitWidth
implicitHeight: contentRow.implicitHeight
acceptedButtons: Qt.MiddleButton | Qt.RightButton
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: (mouse) => {
if (mouse.button === Qt.MiddleButton && root.middleClickCommand) {
root.executeCommand(root.middleClickCommand)
} else if (mouse.button === Qt.RightButton && root.rightClickCommand) {
root.executeCommand(root.rightClickCommand)
}
}
Row {
id: contentRow
spacing: Theme.spacingXS
DankIcon {
name: root.displayIcon
size: Theme.iconSize - 6
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
visible: root.showIcon
}
StyledText {
text: root.currentOutput || ""
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
visible: root.showText && root.currentOutput
}
}
}
}
verticalBarPill: Component {
MouseArea {
implicitWidth: contentColumn.implicitWidth
implicitHeight: contentColumn.implicitHeight
acceptedButtons: Qt.MiddleButton | Qt.RightButton
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: (mouse) => {
if (mouse.button === Qt.MiddleButton && root.middleClickCommand) {
root.executeCommand(root.middleClickCommand)
} else if (mouse.button === Qt.RightButton && root.rightClickCommand) {
root.executeCommand(root.rightClickCommand)
}
}
Column {
id: contentColumn
spacing: Theme.spacingXS
DankIcon {
name: root.displayIcon
size: Theme.iconSize - 6
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showIcon
}
StyledText {
text: root.currentOutput || ""
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showText && root.currentOutput
}
}
}
}
}

View file

@ -1,16 +0,0 @@
{
"id": "dankActions",
"name": "Dank Actions",
"description": "Execute custom commands with dynamic output display and configurable icons",
"version": "1.0.4",
"license": "MIT",
"author": "Avenge Media",
"icon": "terminal",
"firstParty": true,
"component": "./DankActionsWidget.qml",
"settings": "./DankActionsSettings.qml",
"permissions": [
"settings_read",
"settings_write"
]
}

View file

@ -1,110 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
import qs.Services
import qs.Modules.Plugins
PluginComponent {
id: root
Item {}
property bool enableCriticalAlert: pluginData.enableCriticalAlert ?? true
property int criticalThreshold: pluginData.criticalThreshold ?? 10
property string criticalTitle: pluginData.criticalTitle || "Critical Battery Level"
property string criticalMessage: pluginData.criticalMessage || "Battery at ${level}% - Connect charger immediately!"
property bool enableWarningAlert: pluginData.enableWarningAlert ?? true
property int warningThreshold: pluginData.warningThreshold ?? 20
property string warningTitle: pluginData.warningTitle || "Low Battery"
property string warningMessage: pluginData.warningMessage || "Battery at ${level}% - Consider charging soon"
property bool criticalAlertSent: false
property bool warningAlertSent: false
Component.onCompleted: {
console.log("DankBatteryAlerts: Started monitoring battery level")
console.log("DankBatteryAlerts: Critical alerts:", enableCriticalAlert, "at", criticalThreshold + "%")
console.log("DankBatteryAlerts: Warning alerts:", enableWarningAlert, "at", warningThreshold + "%")
}
Connections {
target: BatteryService.batteryAvailable ? BatteryService : null
function onBatteryLevelChanged() {
const level = BatteryService.batteryLevel
const isCharging = BatteryService.isCharging
if (isCharging) {
criticalAlertSent = false
warningAlertSent = false
return
}
if (enableCriticalAlert && level <= criticalThreshold && !criticalAlertSent) {
sendNotification(
criticalTitle,
criticalMessage.replace("${level}", level),
"critical",
"battery_alert"
)
criticalAlertSent = true
} else if (enableWarningAlert && level <= warningThreshold && !warningAlertSent && !criticalAlertSent) {
sendNotification(
warningTitle,
warningMessage.replace("${level}", level),
"normal",
"battery_std"
)
warningAlertSent = true
}
if (level > warningThreshold) {
warningAlertSent = false
}
if (level > criticalThreshold) {
criticalAlertSent = false
}
}
}
function sendNotification(title, message, urgency, icon) {
const process = notifyProcessComponent.createObject(root, {
notifyTitle: title,
notifyMessage: message,
notifyUrgency: urgency,
notifyIcon: icon
})
process.running = true
}
Component {
id: notifyProcessComponent
Process {
property string notifyTitle: ""
property string notifyMessage: ""
property string notifyUrgency: "normal"
property string notifyIcon: "battery_alert"
command: [
"notify-send",
"-a", "DankMaterialShell",
"-i", notifyIcon,
"-u", notifyUrgency,
notifyTitle,
notifyMessage
]
onExited: (exitCode) => {
if (exitCode !== 0) {
console.error("DankBatteryAlerts: notify-send failed with code:", exitCode)
}
destroy()
}
}
}
Component.onDestruction: {
console.log("DankBatteryAlerts: Stopped monitoring battery level")
}
}

View file

@ -1,139 +0,0 @@
import QtQuick
import qs.Common
import qs.Widgets
import qs.Modules.Plugins
PluginSettings {
id: root
pluginId: "dankBatteryAlerts"
StyledText {
text: "Battery Alerts"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Bold
color: Theme.surfaceText
}
StyledText {
text: "Get notified when battery reaches critical or warning levels while on battery power"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
StyledRect {
width: parent.width
height: 1
color: Theme.surfaceVariant
}
StyledText {
text: "Critical Alert"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.DemiBold
color: Theme.surfaceText
}
ToggleSetting {
settingKey: "enableCriticalAlert"
label: "Enable Critical Alert"
description: "Show urgent notification when battery reaches critical level"
defaultValue: true
}
SliderSetting {
settingKey: "criticalThreshold"
label: "Critical Threshold"
description: "Battery percentage to trigger critical alert"
defaultValue: 10
minimum: 1
maximum: 30
unit: "%"
rightIcon: "battery_alert"
}
StringSetting {
settingKey: "criticalTitle"
label: "Critical Title"
description: "Notification title for critical alerts"
placeholder: "Critical Battery Level"
defaultValue: "Critical Battery Level"
}
StringSetting {
settingKey: "criticalMessage"
label: "Critical Message"
description: "Use ${level} for battery percentage"
placeholder: "Battery at ${level}% - Connect charger immediately!"
defaultValue: "Battery at ${level}% - Connect charger immediately!"
}
StyledRect {
width: parent.width
height: 1
color: Theme.surfaceVariant
}
StyledText {
text: "Warning Alert"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.DemiBold
color: Theme.surfaceText
}
ToggleSetting {
settingKey: "enableWarningAlert"
label: "Enable Warning Alert"
description: "Show notification when battery reaches warning level"
defaultValue: true
}
SliderSetting {
settingKey: "warningThreshold"
label: "Warning Threshold"
description: "Battery percentage to trigger warning alert"
defaultValue: 20
minimum: 5
maximum: 50
unit: "%"
rightIcon: "battery_std"
}
StringSetting {
settingKey: "warningTitle"
label: "Warning Title"
description: "Notification title for warning alerts"
placeholder: "Low Battery"
defaultValue: "Low Battery"
}
StringSetting {
settingKey: "warningMessage"
label: "Warning Message"
description: "Use ${level} for battery percentage"
placeholder: "Battery at ${level}% - Consider charging soon"
defaultValue: "Battery at ${level}% - Consider charging soon"
}
StyledRect {
width: parent.width
height: 1
color: Theme.surfaceVariant
}
StyledText {
text: "Alert Behavior"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.DemiBold
color: Theme.surfaceText
}
StyledText {
text: "• Critical alerts use urgent priority and persist longer\n• Alerts reset when battery is charging or rises above threshold\n• Only one alert per threshold per battery discharge cycle"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
}

View file

@ -1,13 +0,0 @@
{
"id": "dankBatteryAlerts",
"name": "Dank Battery Alerts",
"description": "Receive notifications when battery level reaches critical or warning thresholds",
"version": "1.1.1",
"license": "MIT",
"author": "Avenge Media",
"icon": "battery_alert",
"type": "daemon",
"component": "./DankBatteryAlerts.qml",
"settings": "./DankBatteryAlertsSettings.qml",
"permissions": ["settings_read", "settings_write"]
}

View file

@ -1,277 +0,0 @@
import QtQuick
import Quickshell.Io
import qs.Common
import qs.Services
import qs.Modules.Plugins
PluginComponent {
id: root
property bool preparingForSleep: false
property string hookWallpaperPath: pluginData.wallpaperPath || ""
property string hookLightMode: pluginData.lightMode || ""
property string hookTheme: pluginData.theme || ""
property string hookMatugenCompleted: pluginData.matugenCompleted || ""
property string hookBatteryLevel: pluginData.batteryLevel || ""
property string hookBatteryCharging: pluginData.batteryCharging || ""
property string hookBatteryPluggedIn: pluginData.batteryPluggedIn || ""
property string hookPowerRequestLock: pluginData.hookPowerRequestLock || ""
property string hookPowerMonitorOff: pluginData.hookPowerMonitorOff || ""
property string hookPowerMonitorOn: pluginData.hookPowerMonitorOn || ""
property string hookPowerSuspend: pluginData.hookPowerSuspend || ""
property string hookResumeFromSleep: pluginData.hookResumeFromSleep || ""
property string hookWifiConnected: pluginData.wifiConnected || ""
property string hookWifiSSID: pluginData.wifiSSID || ""
property string hookEthernetConnected: pluginData.ethernetConnected || ""
property string hookAudioVolume: pluginData.audioVolume || ""
property string hookAudioMute: pluginData.audioMute || ""
property string hookMicMute: pluginData.micMute || ""
property string hookBrightness: pluginData.brightness || ""
property string hookNightMode: pluginData.nightMode || ""
property string hookDoNotDisturb: pluginData.doNotDisturb || ""
property string hookMediaPlaying: pluginData.mediaPlaying || ""
property string hookIdleStateActive: pluginData.idleStateActive || ""
property string hookMonitorWallpaper: pluginData.monitorWallpaper || ""
Connections {
target: SessionData
function onWallpaperPathChanged() {
if (hookWallpaperPath) {
executeHook(hookWallpaperPath, "onWallpaperChanged", SessionData.wallpaperPath);
}
}
function onMonitorWallpapersChanged() {
if (hookMonitorWallpaper) {
const wallpapersJson = JSON.stringify(SessionData.monitorWallpapers);
executeHook(hookMonitorWallpaper, "onMonitorWallpapersChanged", wallpapersJson);
}
}
function onIsLightModeChanged() {
if (hookLightMode) {
executeHook(hookLightMode, "onLightModeChanged", SessionData.isLightMode ? "light" : "dark");
}
}
function onNightModeEnabledChanged() {
if (hookNightMode) {
executeHook(hookNightMode, "onNightModeChanged", SessionData.nightModeEnabled ? "enabled" : "disabled");
}
}
function onDoNotDisturbChanged() {
if (hookDoNotDisturb) {
executeHook(hookDoNotDisturb, "onDoNotDisturbChanged", SessionData.doNotDisturb ? "enabled" : "disabled");
}
}
}
Connections {
target: typeof Theme !== "undefined" ? Theme : null
function onCurrentThemeChanged() {
if (!hookTheme)
return;
executeHook(hookTheme, "onThemeChanged", Theme.currentTheme);
}
function onMatugenCompleted(mode, result) {
if (!hookMatugenCompleted)
return;
executeHook(hookMatugenCompleted, "onMatugenCompleted", mode + ":" + result);
}
}
Connections {
target: BatteryService.batteryAvailable ? BatteryService : null
function onBatteryLevelChanged() {
if (hookBatteryLevel) {
executeHook(hookBatteryLevel, "onBatteryLevelChanged", String(BatteryService.batteryLevel));
}
}
function onIsChargingChanged() {
if (hookBatteryCharging) {
executeHook(hookBatteryCharging, "onBatteryChargingChanged", BatteryService.isCharging ? "charging" : "not-charging");
}
}
function onIsPluggedInChanged() {
if (hookBatteryPluggedIn) {
executeHook(hookBatteryPluggedIn, "onBatteryPluggedInChanged", BatteryService.isPluggedIn ? "plugged-in" : "on-battery");
}
}
}
Connections {
target: IdleService
function onLockRequested() {
if (hookPowerRequestLock) {
executeHook(hookPowerRequestLock, "onLockRequested", "");
}
}
function onRequestMonitorOff() {
if (hookPowerMonitorOff) {
executeHook(hookPowerMonitorOff, "onRequestMonitorOff", "");
}
}
function onRequestMonitorOn() {
if (hookPowerMonitorOn) {
executeHook(hookPowerMonitorOn, "onRequestMonitorOn", "");
}
}
function onRequestSuspend() {
if (hookPowerSuspend) {
executeHook(hookPowerSuspend, "onRequestSuspend", "");
}
}
}
Connections {
target: DMSService
function onLoginctlStateUpdate(data) {
var lastState = root.preparingForSleep;
root.preparingForSleep = data.preparingForSleep;
if (lastState && !root.preparingForSleep) {
executeHook(hookResumeFromSleep, "onResumeFromSleep", "");
}
}
}
Connections {
target: NetworkService
function onWifiConnectedChanged() {
if (hookWifiConnected) {
executeHook(hookWifiConnected, "onWifiConnectedChanged", NetworkService.wifiConnected ? "connected" : "disconnected");
}
}
function onCurrentWifiSSIDChanged() {
if (hookWifiSSID) {
executeHook(hookWifiSSID, "onWifiSSIDChanged", NetworkService.currentWifiSSID || "none");
}
}
function onEthernetConnectedChanged() {
if (hookEthernetConnected) {
executeHook(hookEthernetConnected, "onEthernetConnectedChanged", NetworkService.ethernetConnected ? "connected" : "disconnected");
}
}
}
Connections {
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
function onVolumeChanged() {
if (hookAudioVolume && AudioService.sink && AudioService.sink.audio) {
executeHook(hookAudioVolume, "onAudioVolumeChanged", String(Math.round(AudioService.sink.audio.volume * 100)));
}
}
function onMutedChanged() {
if (hookAudioMute && AudioService.sink && AudioService.sink.audio) {
executeHook(hookAudioMute, "onAudioMuteChanged", AudioService.sink.audio.muted ? "muted" : "unmuted");
}
}
}
Connections {
target: AudioService.source && AudioService.source.audio ? AudioService.source.audio : null
function onMutedChanged() {
if (hookMicMute && AudioService.source && AudioService.source.audio) {
executeHook(hookMicMute, "onMicMuteChanged", AudioService.source.audio.muted ? "muted" : "unmuted");
}
}
}
Connections {
target: DisplayService
function onBrightnessLevelChanged() {
if (hookBrightness && DisplayService.brightnessAvailable) {
executeHook(hookBrightness, "onBrightnessChanged", String(DisplayService.brightnessLevel));
}
}
}
Connections {
target: MprisController.activePlayer
function onIsPlayingChanged() {
if (hookMediaPlaying && MprisController.activePlayer) {
executeHook(hookMediaPlaying, "onMediaPlayingChanged", MprisController.activePlayer.isPlaying ? "playing" : "paused");
}
}
}
function executeHook(scriptPath, hookName, hookValue) {
if (!scriptPath || scriptPath.trim() === "") {
return;
}
const process = hookProcessComponent.createObject(root, {
hookScript: scriptPath,
hookName: hookName,
hookValue: hookValue
});
if (!process) {
console.error("DankHooks: Failed to create process object");
return;
}
process.running = true;
}
Component {
id: hookProcessComponent
Process {
property string hookScript: ""
property string hookName: ""
property string hookValue: ""
command: ["sh", "-c", "$HOOK_SCRIPT \"$HOOK_NAME\" \"$HOOK_VALUE\""]
environment: {
"HOOK_SCRIPT": hookScript,
"HOOK_NAME": hookName,
"HOOK_VALUE": hookValue
}
stdout: StdioCollector {
onStreamFinished: {
if (text.trim()) {
console.log("DankHooks output:", text.trim());
}
}
}
stderr: StdioCollector {
onStreamFinished: {
if (text.trim()) {
ToastService.showError("Hook Script Error", text.trim());
}
}
}
onExited: exitCode => {
if (exitCode !== 0) {
ToastService.showError("Hook Script Error", `Script '${hookScript}' exited with code: ${exitCode}`);
}
destroy();
}
}
}
Component.onDestruction: {
console.log("DankHooks: Stopped monitoring system events");
}
}

View file

@ -1,332 +0,0 @@
import QtQuick
import qs.Common
import qs.Widgets
import qs.Modules.Plugins
PluginSettings {
id: root
pluginId: "dankHooks"
StyledText {
text: "System Event Hooks"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Bold
color: Theme.surfaceText
}
StyledText {
text: "Execute custom scripts when system events occur. Scripts receive two arguments: hook name (e.g., 'onBatteryLevelChanged') and event value."
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
StyledRect {
width: parent.width
height: 1
color: Theme.surfaceVariant
}
StyledText {
text: "Appearance & Theme"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.DemiBold
color: Theme.surfaceText
}
StringSetting {
settingKey: "wallpaperPath"
label: "Wallpaper Changed"
description: "Hook: onWallpaperChanged | Value: wallpaper file path"
placeholder: "/path/to/wallpaper-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "monitorWallpaper"
label: "Per-Monitor Wallpapers Changed"
description: "Hook: onMonitorWallpapersChanged | Value: JSON object with all monitors (e.g., '{\"eDP-1\":\"/path1.jpg\",\"DP-2\":\"/path2.jpg\"}')"
placeholder: "/path/to/monitor-wallpaper-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "lightMode"
label: "Light/Dark Mode Changed"
description: "Hook: onLightModeChanged | Value: 'light' or 'dark'"
placeholder: "/path/to/mode-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "theme"
label: "Theme Changed"
description: "Hook: onThemeChanged | Value: theme name (e.g., 'blue', 'red', 'dynamic')"
placeholder: "/path/to/theme-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "matugenCompleted"
label: "Matugen Generation Completed"
description: "Hook: onMatugenCompleted | Value: '<mode>:<result>' (e.g., 'dark:success', 'light:no-changes')"
placeholder: "/path/to/matugen-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "nightMode"
label: "Night Mode Changed"
description: "Hook: onNightModeChanged | Value: 'enabled' or 'disabled'"
placeholder: "/path/to/nightmode-hook.sh"
defaultValue: ""
}
StyledRect {
width: parent.width
height: 1
color: Theme.surfaceVariant
}
StyledText {
text: "Power & Battery"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.DemiBold
color: Theme.surfaceText
}
StringSetting {
settingKey: "batteryLevel"
label: "Battery Level Changed"
description: "Hook: onBatteryLevelChanged | Value: percentage (0-100)"
placeholder: "/path/to/battery-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "batteryCharging"
label: "Battery Charging State Changed"
description: "Hook: onBatteryChargingChanged | Value: 'charging' or 'not-charging'"
placeholder: "/path/to/charging-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "batteryPluggedIn"
label: "Power Adapter Changed"
description: "Hook: onBatteryPluggedInChanged | Value: 'plugged-in' or 'on-battery'"
placeholder: "/path/to/power-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "hookPowerRequestLock"
label: "Lock Screen Event Triggered"
description: "Hook: onLockRequested | Value: empty"
placeholder: "/path/to/sessionlock-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "hookPowerMonitorOff"
label: "Monitor Off Event Triggered"
description: "Hook: onRequestMonitorOff | Value: empty"
placeholder: "/path/to/monitoroff-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "hookPowerMonitorOn"
label: "Monitor On Event Triggered"
description: "Hook: onRequestMonitorOn | Value: empty"
placeholder: "/path/to/monitoron-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "hookPowerSuspend"
label: "Suspend Event Triggered"
description: "Hook: onRequestSuspend | Value: empty"
placeholder: "/path/to/suspend-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "hookResumeFromSleep"
label: "Resume From Sleep Event Triggered"
description: "Hook: onResumeFromSleep | Value: empty"
placeholder: "/path/to/resumeFromSleep-hook.sh"
defaultValue: ""
}
StyledRect {
width: parent.width
height: 1
color: Theme.surfaceVariant
}
StyledText {
text: "Network"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.DemiBold
color: Theme.surfaceText
}
StringSetting {
settingKey: "wifiConnected"
label: "WiFi Connection Changed"
description: "Hook: onWifiConnectedChanged | Value: 'connected' or 'disconnected'"
placeholder: "/path/to/wifi-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "wifiSSID"
label: "WiFi Network Changed"
description: "Hook: onWifiSSIDChanged | Value: SSID name or 'none'"
placeholder: "/path/to/ssid-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "ethernetConnected"
label: "Ethernet Connection Changed"
description: "Hook: onEthernetConnectedChanged | Value: 'connected' or 'disconnected'"
placeholder: "/path/to/ethernet-hook.sh"
defaultValue: ""
}
StyledRect {
width: parent.width
height: 1
color: Theme.surfaceVariant
}
StyledText {
text: "Audio"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.DemiBold
color: Theme.surfaceText
}
StringSetting {
settingKey: "audioVolume"
label: "Audio Volume Changed"
description: "Hook: onAudioVolumeChanged | Value: percentage (0-100)"
placeholder: "/path/to/volume-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "audioMute"
label: "Audio Mute Changed"
description: "Hook: onAudioMuteChanged | Value: 'muted' or 'unmuted'"
placeholder: "/path/to/mute-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "micMute"
label: "Microphone Mute Changed"
description: "Hook: onMicMuteChanged | Value: 'muted' or 'unmuted'"
placeholder: "/path/to/mic-hook.sh"
defaultValue: ""
}
StyledRect {
width: parent.width
height: 1
color: Theme.surfaceVariant
}
StyledText {
text: "Display & Media"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.DemiBold
color: Theme.surfaceText
}
StringSetting {
settingKey: "brightness"
label: "Brightness Changed"
description: "Hook: onBrightnessChanged | Value: percentage (0-100)"
placeholder: "/path/to/brightness-hook.sh"
defaultValue: ""
}
StringSetting {
settingKey: "mediaPlaying"
label: "Media Playback Changed"
description: "Hook: onMediaPlayingChanged | Value: 'playing' or 'paused'"
placeholder: "/path/to/media-hook.sh"
defaultValue: ""
}
StyledRect {
width: parent.width
height: 1
color: Theme.surfaceVariant
}
StyledText {
text: "System"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.DemiBold
color: Theme.surfaceText
}
StringSetting {
settingKey: "doNotDisturb"
label: "Do Not Disturb Changed"
description: "Hook: onDoNotDisturbChanged | Value: 'enabled' or 'disabled'"
placeholder: "/path/to/dnd-hook.sh"
defaultValue: ""
}
StyledRect {
width: parent.width
height: 1
color: Theme.surfaceVariant
}
StyledText {
text: "Hook Script Examples"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.DemiBold
color: Theme.surfaceText
}
StyledText {
text: "Example hook script:"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledRect {
width: parent.width
height: exampleCode.height + 16
color: Theme.surface
radius: Theme.cornerRadius
StyledText {
id: exampleCode
anchors.centerIn: parent
anchors.margins: 8
width: parent.width - 16
text: '#!/bin/bash\n# Save as ~/.config/scripts/hook.sh\n# Make executable: chmod +x ~/.config/scripts/hook.sh\n\nHOOK_NAME="$1" # e.g., "onWallpaperChanged"\nHOOK_VALUE="$2" # e.g., "/path/to/wallpaper.jpg"\n\necho "Hook: $HOOK_NAME, Value: $HOOK_VALUE"\nnotify-send "$HOOK_NAME" "$HOOK_VALUE"'
font.pixelSize: Theme.fontSizeSmall
font.family: "monospace"
color: Theme.surfaceText
wrapMode: Text.WordWrap
}
}
StyledText {
text: "All hooks pass two arguments: $1 = hook name (e.g., 'onBatteryLevelChanged'), $2 = event value. See descriptions above for each hook's values."
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
}

View file

@ -1,50 +0,0 @@
# Dank Hooks Plugin
## Available Hooks
### Appearance & Theme
| Hook | Trigger | Hook Name | Value |
|------|---------|-----------|-------|
| **Wallpaper Changed** | When wallpaper changes | `onWallpaperChanged` | Wallpaper file path |
| **Light/Dark Mode Changed** | When switching between modes | `onLightModeChanged` | `light` or `dark` |
| **Theme Changed** | When color theme changes | `onThemeChanged` | Theme name (e.g., `blue`, `red`, `dynamic`) |
| **Matugen Completed** | When matugen finishes generating colors | `onMatugenCompleted` | `<mode>:<result>` (e.g., `dark:success`, `light:no-changes`, `dark:error`) |
| **Night Mode Changed** | When night mode toggles | `onNightModeChanged` | `enabled` or `disabled` |
### Power & Battery
| Hook | Trigger | Hook Name | Value |
|------|---------|-----------|-------|
| **Battery Level Changed** | When battery percentage changes | `onBatteryLevelChanged` | Battery percentage (0-100) |
| **Battery Charging State Changed** | When charging state changes | `onBatteryChargingChanged` | `charging` or `not-charging` |
| **Power Adapter Changed** | When power adapter connects/disconnects | `onBatteryPluggedInChanged` | `plugged-in` or `on-battery` |
### Network
| Hook | Trigger | Hook Name | Value |
|------|---------|-----------|-------|
| **WiFi Connection Changed** | When WiFi connects/disconnects | `onWifiConnectedChanged` | `connected` or `disconnected` |
| **WiFi Network Changed** | When connected WiFi network changes | `onWifiSSIDChanged` | SSID name or `none` |
| **Ethernet Connection Changed** | When Ethernet connects/disconnects | `onEthernetConnectedChanged` | `connected` or `disconnected` |
### Audio
| Hook | Trigger | Hook Name | Value |
|------|---------|-----------|-------|
| **Audio Volume Changed** | When speaker volume changes | `onAudioVolumeChanged` | Volume percentage (0-100) |
| **Audio Mute Changed** | When speakers mute/unmute | `onAudioMuteChanged` | `muted` or `unmuted` |
| **Microphone Mute Changed** | When microphone mutes/unmutes | `onMicMuteChanged` | `muted` or `unmuted` |
### Display & Media
| Hook | Trigger | Hook Name | Value |
|------|---------|-----------|-------|
| **Brightness Changed** | When screen brightness changes | `onBrightnessChanged` | Brightness percentage (0-100) |
| **Media Playback Changed** | When media starts/stops playing | `onMediaPlayingChanged` | `playing` or `paused` |
### System
| Hook | Trigger | Hook Name | Value |
|------|---------|-----------|-------|
| **Do Not Disturb Changed** | When DND mode toggles | `onDoNotDisturbChanged` | `enabled` or `disabled` |

View file

@ -1,16 +0,0 @@
{
"id": "dankHooks",
"name": "Dank Hooks",
"description": "Execute custom scripts on system events like wallpaper changes, theme updates, battery level changes, and more",
"version": "1.0.7",
"license": "MIT",
"author": "Avenge Media",
"icon": "webhook",
"type": "daemon",
"component": "./DankHooks.qml",
"settings": "./DankHooksSettings.qml",
"permissions": [
"settings_read",
"settings_write"
]
}

View file

@ -1,156 +0,0 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Services
import qs.Widgets
import qs.Modules.Plugins
PluginSettings {
id: root
pluginId: "dankPomodoroTimer"
StyledText {
width: parent.width
text: "Pomodoro Settings"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Bold
color: Theme.surfaceText
}
StyledText {
width: parent.width
text: "Configure timer durations and behavior"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
}
StyledRect {
width: parent.width
height: durationsColumn.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
Column {
id: durationsColumn
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
StyledText {
text: "Durations"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
}
StringSetting {
settingKey: "workDuration"
label: "Work Duration (minutes)"
description: "Length of each focus session"
placeholder: "25"
defaultValue: "25"
}
StringSetting {
settingKey: "shortBreakDuration"
label: "Short Break (minutes)"
description: "Break after each pomodoro"
placeholder: "5"
defaultValue: "5"
}
StringSetting {
settingKey: "longBreakDuration"
label: "Long Break (minutes)"
description: "Break after 4 pomodoros"
placeholder: "15"
defaultValue: "15"
}
}
}
StyledRect {
width: parent.width
height: behaviorColumn.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
Column {
id: behaviorColumn
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
StyledText {
text: "Behavior"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
}
ToggleSetting {
settingKey: "autoStartBreaks"
label: "Auto-start Breaks"
description: "Automatically start break timers after work sessions"
defaultValue: false
}
ToggleSetting {
settingKey: "autoStartPomodoros"
label: "Auto-start Pomodoros"
description: "Automatically start work sessions after breaks"
defaultValue: false
}
ToggleSetting {
settingKey: "autoSetDND"
label: "Do Not Disturb Work"
description: "Automatically enable Do Not Disturb mode during work sessions"
defaultValue: false
}
}
}
StyledRect {
width: parent.width
height: infoColumn.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surface
Column {
id: infoColumn
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: "About Pomodoro Technique"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
StyledText {
text: "The Pomodoro Technique uses 25-minute focused work sessions followed by short breaks. After 4 pomodoros, take a longer break to recharge.\n\n• Work: 25 minutes of focused work\n• Short Break: 5 minute rest\n• Long Break: 15 minutes after 4 pomodoros\n\nNotifications will alert you when each session completes."
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
lineHeight: 1.4
}
}
}
}

View file

@ -1,497 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
import qs.Services
import qs.Widgets
import qs.Modules.Plugins
PluginComponent {
id: root
property int workDuration: pluginData.workDuration || 25
property int shortBreakDuration: pluginData.shortBreakDuration || 5
property int longBreakDuration: pluginData.longBreakDuration || 15
property bool autoStartBreaks: pluginData.autoStartBreaks ?? false
property bool autoStartPomodoros: pluginData.autoStartPomodoros ?? false
property bool autoSetDND: pluginData.autoSetDND ?? false
onWorkDurationChanged: {
if (globalTimerState.value === "work" && globalTotalSeconds.value > 0) {
const newTotal = workDuration * 60
const elapsed = globalTotalSeconds.value - globalRemainingSeconds.value
globalTotalSeconds.set(newTotal)
globalRemainingSeconds.set(Math.max(1, newTotal - elapsed))
}
}
onShortBreakDurationChanged: {
if (globalTimerState.value === "shortBreak" && globalTotalSeconds.value > 0) {
const newTotal = shortBreakDuration * 60
const elapsed = globalTotalSeconds.value - globalRemainingSeconds.value
globalTotalSeconds.set(newTotal)
globalRemainingSeconds.set(Math.max(1, newTotal - elapsed))
}
}
onLongBreakDurationChanged: {
if (globalTimerState.value === "longBreak" && globalTotalSeconds.value > 0) {
const newTotal = longBreakDuration * 60
const elapsed = globalTotalSeconds.value - globalRemainingSeconds.value
globalTotalSeconds.set(newTotal)
globalRemainingSeconds.set(Math.max(1, newTotal - elapsed))
}
}
PluginGlobalVar {
id: globalRemainingSeconds
varName: "remainingSeconds"
defaultValue: 0
}
PluginGlobalVar {
id: globalTotalSeconds
varName: "totalSeconds"
defaultValue: 0
}
PluginGlobalVar {
id: globalIsRunning
varName: "isRunning"
defaultValue: false
}
PluginGlobalVar {
id: globalTimerState
varName: "timerState"
defaultValue: "work"
}
PluginGlobalVar {
id: globalCompletedPomodoros
varName: "completedPomodoros"
defaultValue: 0
}
PluginGlobalVar {
id: globalTimerOwnerId
varName: "timerOwnerId"
defaultValue: ""
}
property string instanceId: Math.random().toString(36).substring(2)
Timer {
id: pomodoroTimer
interval: 1000
repeat: true
running: globalIsRunning.value && globalTimerOwnerId.value === root.instanceId
onTriggered: {
if (globalRemainingSeconds.value > 0) {
globalRemainingSeconds.set(globalRemainingSeconds.value - 1)
} else {
root.timerComplete()
}
}
}
function timerComplete() {
globalIsRunning.set(false)
if (globalTimerState.value === "work") {
globalCompletedPomodoros.set(globalCompletedPomodoros.value + 1)
const isLongBreak = globalCompletedPomodoros.value % 4 === 0
Quickshell.execDetached(["sh", "-c", "notify-send 'Pomodoro Complete' 'Time for a " + (isLongBreak ? "long" : "short") + " break!' -u normal"])
if (root.autoSetDND) {
SessionData.setDoNotDisturb(false)
}
if (isLongBreak) {
root.startLongBreak(root.autoStartBreaks)
} else {
root.startShortBreak(root.autoStartBreaks)
}
} else {
Quickshell.execDetached(["sh", "-c", "notify-send 'Break Complete' 'Ready for another pomodoro?' -u normal"])
root.startWork(root.autoStartPomodoros)
}
}
function startWork(autoStart) {
globalTimerState.set("work")
globalTotalSeconds.set(root.workDuration * 60)
globalRemainingSeconds.set(globalTotalSeconds.value)
if (autoStart) {
globalTimerOwnerId.set(root.instanceId)
if (root.autoSetDND) {
SessionData.setDoNotDisturb(true)
}
}
globalIsRunning.set(autoStart ?? false)
}
function startShortBreak(autoStart) {
if(globalTimerState.value === "work" && root.autoSetDND) {
SessionData.setDoNotDisturb(false)
}
globalTimerState.set("shortBreak")
globalTotalSeconds.set(root.shortBreakDuration * 60)
globalRemainingSeconds.set(globalTotalSeconds.value)
if (autoStart) {
globalTimerOwnerId.set(root.instanceId)
}
globalIsRunning.set(autoStart ?? false)
}
function startLongBreak(autoStart) {
if(globalTimerState.value === "work" && root.autoSetDND) {
SessionData.setDoNotDisturb(false)
}
globalTimerState.set("longBreak")
globalTotalSeconds.set(root.longBreakDuration * 60)
globalRemainingSeconds.set(globalTotalSeconds.value)
if (autoStart) {
globalTimerOwnerId.set(root.instanceId)
}
globalIsRunning.set(autoStart ?? false)
}
function toggleTimer() {
if (!globalIsRunning.value) {
globalTimerOwnerId.set(root.instanceId)
}
globalIsRunning.set(!globalIsRunning.value)
if (root.autoSetDND && globalTimerState.value === "work") {
SessionData.setDoNotDisturb(globalIsRunning.value)
}
}
function resetTimer() {
globalIsRunning.set(false)
if (root.autoSetDND && globalTimerState.value === "work") {
SessionData.setDoNotDisturb(false)
}
globalRemainingSeconds.set(globalTotalSeconds.value)
}
function formatTime(seconds, isVertical = false) {
const mins = Math.floor(seconds / 60)
const secs = seconds % 60
return isVertical ? mins + "\n" + (secs < 10 ? "0" : "") + secs : mins + " " + (secs < 10 ? "0" : "") + secs
}
function getStateColor() {
if (globalTimerState.value === "work") return Theme.primary
if (globalTimerState.value === "shortBreak") return Theme.success
return Theme.warning
}
function getStateIcon() {
if (globalTimerState.value === "work") return "work"
return "coffee"
}
IpcHandler {
function resetTimer(): string {
root.resetTimer()
return "POMDORO_TIME_RESET_SUCCESS"
}
function toggleTimer(): string {
root.toggleTimer()
return globalIsRunning.value ? "Timer is running" : "Timer is paused"
}
function startWork(): string {
root.startWork(true)
return "POMODORO_WORK_STARTED"
}
function startShortBreak(): string {
root.startShortBreak(true)
return "POMODORO_SHORT_BREAK_STARTED"
}
function startLongBreak(): string {
root.startLongBreak(true)
return "POMODORO_LONG_BREAK_STARTED"
}
target: "pomodoroTimer"
}
Timer {
id: initTimer
interval: 100
repeat: false
running: true
onTriggered: {
if (globalRemainingSeconds.value === 0 && globalTotalSeconds.value === 0) {
root.startWork(false)
}
}
}
horizontalBarPill: Component {
Row {
spacing: Theme.spacingXS
DankIcon {
name: root.getStateIcon()
size: Theme.iconSize - 6
color: root.getStateColor()
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: root.formatTime(globalRemainingSeconds.value)
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
}
}
verticalBarPill: Component {
Column {
spacing: Theme.spacingXS
DankIcon {
name: root.getStateIcon()
size: Theme.iconSize - 6
color: root.getStateColor()
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: root.formatTime(globalRemainingSeconds.value, true)
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceVariantText
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
popoutContent: Component {
PopoutComponent {
id: popout
headerText: "Pomodoro Timer"
detailsText: {
if (globalTimerState.value === "work") return "Focus session • " + globalCompletedPomodoros.value + " completed"
if (globalTimerState.value === "shortBreak") return "Short break"
return "Long break"
}
showCloseButton: true
Column {
id: popoutContentColumn
width: parent.width
spacing: Theme.spacingM
Item {
width: parent.width
height: 180
Rectangle {
width: 180
height: 180
radius: 90
anchors.centerIn: parent
color: "transparent"
border.width: 8
border.color: Qt.rgba(root.getStateColor().r, root.getStateColor().g, root.getStateColor().b, 0.2)
Canvas {
id: progressCanvas
width: parent.width - 16
height: parent.height - 16
anchors.centerIn: parent
onPaint: {
var ctx = getContext("2d")
ctx.clearRect(0, 0, width, height)
ctx.lineWidth = 8
ctx.strokeStyle = root.getStateColor()
ctx.beginPath()
const centerX = width / 2
const centerY = height / 2
const radius = (width - 8) / 2
const progress = globalRemainingSeconds.value / globalTotalSeconds.value
const startAngle = -Math.PI / 2
const endAngle = startAngle + (2 * Math.PI * progress)
ctx.arc(centerX, centerY, radius, startAngle, endAngle, false)
ctx.stroke()
}
Connections {
target: globalRemainingSeconds
function onValueChanged() {
progressCanvas.requestPaint()
}
}
}
Column {
anchors.centerIn: parent
spacing: Theme.spacingXS
StyledText {
text: root.formatTime(globalRemainingSeconds.value)
font.pixelSize: 36
font.weight: Font.Bold
color: root.getStateColor()
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
width: 120
}
StyledText {
text: {
if (globalTimerState.value === "work") return "Work"
if (globalTimerState.value === "shortBreak") return "Short Break"
return "Long Break"
}
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingM
Rectangle {
width: 64
height: 64
radius: 32
color: playArea.containsMouse ? Qt.rgba(root.getStateColor().r, root.getStateColor().g, root.getStateColor().b, 0.2) : "transparent"
DankIcon {
anchors.centerIn: parent
name: globalIsRunning.value ? "pause" : "play_arrow"
size: 32
color: root.getStateColor()
}
MouseArea {
id: playArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.toggleTimer()
}
}
Rectangle {
width: 64
height: 64
radius: 32
color: resetArea.containsMouse ? Theme.surfaceContainerHighest : "transparent"
DankIcon {
anchors.centerIn: parent
name: "refresh"
size: 24
color: Theme.surfaceText
}
MouseArea {
id: resetArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.resetTimer()
}
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Quick Actions"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
Row {
id: quickActionsRow
width: parent.width
spacing: Theme.spacingS
property real buttonWidth: (width - spacing * 2) / 3
DankButton {
text: "Work"
iconName: "work"
width: quickActionsRow.buttonWidth
onClicked: root.startWork(false)
}
DankButton {
text: "Short Break"
iconName: "coffee"
width: quickActionsRow.buttonWidth
onClicked: root.startShortBreak(false)
}
DankButton {
text: "Long Break"
iconName: "weekend"
width: quickActionsRow.buttonWidth
onClicked: root.startLongBreak(false)
}
}
}
StyledRect {
width: parent.width
height: statsColumn.implicitHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
Column {
id: statsColumn
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingXS
Row {
spacing: Theme.spacingM
DankIcon {
name: "check_circle"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: globalCompletedPomodoros.value + " pomodoros completed"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
StyledText {
text: "Next long break after " + (4 - (globalCompletedPomodoros.value % 4)) + " more"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
leftPadding: Theme.iconSize + Theme.spacingM
}
}
}
}
}
}
}

View file

@ -1,16 +0,0 @@
{
"id": "dankPomodoroTimer",
"name": "Dank Pomodoro Timer",
"description": "Productivity timer with 25-minute work sessions and breaks",
"version": "1.1.5",
"license": "MIT",
"author": "Avenge Media",
"icon": "timer",
"firstParty": true,
"component": "./DankPomodoroWidget.qml",
"settings": "./DankPomodoroSettings.qml",
"permissions": [
"settings_read",
"settings_write"
]
}

View file

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2025 Avenge Media LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,31 +0,0 @@
# DankMaterialShell plugins
A collection of first-party, officially maintained plugins for [DankMaterialShell](https://github.com/AvengeMedia/DankMaterialShell)
## Plugins
### [Dank Actions](./DankActions)
Scriptable, custom actions that can be added to the DankBar.
Allows for creating multiple widgets that execute custom script actions on click, or periodically.
<img width="488" height="638" alt="image" src="https://github.com/user-attachments/assets/36b44c32-69b5-49c9-97d2-87f530e4b7fd" />
### [Dank Pomodoro Timer](./DankPomodoroTimer)
A timer that is intended to improve productivity using the [Pomodoro technique](https://en.wikipedia.org/wiki/Pomodoro_Technique).
<img width="442" height="545" alt="image" src="https://github.com/user-attachments/assets/b51b5f78-5215-403c-850f-c7e137097438" />
### [Dank Hooks](./DankHooks)
Trigger scripts based on various system events, such as `onWallpaperChanged`, `onVolumeChanged`, etc.
<img width="472" height="593" alt="image" src="https://github.com/user-attachments/assets/83e89b5b-0636-4b8e-ba29-1fa4d12169a0" />
### [Dank Battery Alerts](./DankBatteryAlerts)
Trigger notifications when battery reaches low charge levels.
<img width="497" height="710" alt="image" src="https://github.com/user-attachments/assets/4302d886-eb87-41d4-a9a4-1eeaadd787c6" />

View file

@ -1,9 +0,0 @@
[core]
bare = false
filemode = true
[remote "origin"]
url = https://github.com/AvengeMedia/dms-plugins
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master

View file

@ -1 +0,0 @@
87870d8b70758f08aa8fd5401a0e4eec3941ed48

View file

@ -1,54 +0,0 @@
# C++ objects and libs
*.slo
*.lo
*.o
*.a
*.la
*.lai
*.so
*.so.*
*.dll
*.dylib
# Qt-es
object_script.*.Release
object_script.*.Debug
*_plugin_import.cpp
/.qmake.cache
/.qmake.stash
*.pro.user
*.pro.user.*
*.qbs.user
*.qbs.user.*
*.moc
moc_*.cpp
moc_*.h
qrc_*.cpp
ui_*.h
*.qmlc
*.jsc
Makefile*
*build-*
*.qm
*.prl
# Qt unit tests
target_wrapper.*
# QtCreator
*.autosave
# QtCreator Qml
*.qmlproject.user
*.qmlproject.user.*
# QtCreator CMake
CMakeLists.txt.user*
# QtCreator 4.8< compilation database
compile_commands.json
# QtCreator local machine specific files for imported projects
*creator.user*
*_qmlcache.qrc