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:
parent
e08bb9229f
commit
917b479a94
103 changed files with 0 additions and 24611 deletions
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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"]
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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` |
|
||||
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
@ -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" />
|
||||
|
|
@ -1 +0,0 @@
|
|||
ref: refs/heads/master
|
||||
|
|
@ -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
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
87870d8b70758f08aa8fd5401a0e4eec3941ed48
|
||||
|
|
@ -1 +0,0 @@
|
|||
87870d8b70758f08aa8fd5401a0e4eec3941ed48
|
||||
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue