summaryrefslogtreecommitdiff
path: root/.config
diff options
context:
space:
mode:
Diffstat (limited to '.config')
-rw-r--r--.config/noctalia/colors.json18
-rw-r--r--.config/noctalia/plugins.json16
-rw-r--r--.config/noctalia/plugins/timer/BarWidget.qml179
-rw-r--r--.config/noctalia/plugins/timer/ControlCenterWidget.qml45
-rw-r--r--.config/noctalia/plugins/timer/Main.qml239
-rw-r--r--.config/noctalia/plugins/timer/Panel.qml593
-rw-r--r--.config/noctalia/plugins/timer/README.md52
-rw-r--r--.config/noctalia/plugins/timer/Settings.qml65
-rw-r--r--.config/noctalia/plugins/timer/i18n/de.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/en.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/es.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/fr.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/hu.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/it.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/ja.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/ku.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/nl.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/pl.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/pt.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/ru.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/tr.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/uk-UA.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/zh-CN.json20
-rw-r--r--.config/noctalia/plugins/timer/i18n/zh-TW.json20
-rw-r--r--.config/noctalia/plugins/timer/manifest.json33
-rw-r--r--.config/noctalia/plugins/timer/preview.pngbin0 -> 29832 bytes
-rw-r--r--.config/noctalia/plugins/timer/settings.json5
-rw-r--r--.config/noctalia/settings.json672
28 files changed, 2237 insertions, 0 deletions
diff --git a/.config/noctalia/colors.json b/.config/noctalia/colors.json
new file mode 100644
index 0000000..2c13fcf
--- /dev/null
+++ b/.config/noctalia/colors.json
@@ -0,0 +1,18 @@
+{
+ "mError": "#bf616a",
+ "mHover": "#6fa9a8",
+ "mOnError": "#eceff4",
+ "mOnHover": "#eceff4",
+ "mOnPrimary": "#eceff4",
+ "mOnSecondary": "#eceff4",
+ "mOnSurface": "#2e3440",
+ "mOnSurfaceVariant": "#4c566a",
+ "mOnTertiary": "#eceff4",
+ "mOutline": "#c5cedd",
+ "mPrimary": "#5e81ac",
+ "mSecondary": "#64adc2",
+ "mShadow": "#d8dee9",
+ "mSurface": "#eceff4",
+ "mSurfaceVariant": "#e5e9f0",
+ "mTertiary": "#6fa9a8"
+}
diff --git a/.config/noctalia/plugins.json b/.config/noctalia/plugins.json
new file mode 100644
index 0000000..735522c
--- /dev/null
+++ b/.config/noctalia/plugins.json
@@ -0,0 +1,16 @@
+{
+ "sources": [
+ {
+ "enabled": true,
+ "name": "Noctalia Plugins",
+ "url": "https://github.com/noctalia-dev/noctalia-plugins"
+ }
+ ],
+ "states": {
+ "timer": {
+ "enabled": true,
+ "sourceUrl": "https://github.com/noctalia-dev/noctalia-plugins"
+ }
+ },
+ "version": 2
+}
diff --git a/.config/noctalia/plugins/timer/BarWidget.qml b/.config/noctalia/plugins/timer/BarWidget.qml
new file mode 100644
index 0000000..81d2cb9
--- /dev/null
+++ b/.config/noctalia/plugins/timer/BarWidget.qml
@@ -0,0 +1,179 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import qs.Commons
+import qs.Widgets
+import qs.Services.UI
+import qs.Services.System
+
+Item {
+ id: root
+
+ property var pluginApi: null
+ property ShellScreen screen
+ property string widgetId: ""
+ property string section: ""
+ property int sectionWidgetIndex: -1
+ property int sectionWidgetsCount: 0
+
+ readonly property bool pillDirection: BarService.getPillDirection(root)
+
+ readonly property var mainInstance: pluginApi?.mainInstance
+ readonly property bool isActive: mainInstance && (mainInstance.cdRunning || mainInstance.swRunning || mainInstance.swElapsedSeconds > 0 || mainInstance.cdRemainingSeconds > 0 || mainInstance.cdSoundPlaying)
+
+ property var cfg: pluginApi?.pluginSettings || ({})
+ property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
+
+ readonly property string iconColorKey: cfg.iconColor ?? defaults.iconColor ?? "none"
+ readonly property color iconColor: Color.resolveColorKey(iconColorKey)
+
+ readonly property string textColorKey: cfg.textColor ?? defaults.textColor ?? "none"
+ readonly property color textColor: Color.resolveColorKey(textColorKey)
+
+ // Bar positioning properties
+ readonly property string screenName: screen ? screen.name : ""
+ readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
+ readonly property bool isVertical: barPosition === "left" || barPosition === "right"
+ readonly property real barHeight: Style.getBarHeightForScreen(screenName)
+ readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
+ readonly property real barFontSize: Style.getBarFontSizeForScreen(screenName)
+
+ readonly property real contentWidth: {
+ if (isVertical) return root.capsuleHeight
+ if (isActive) return contentRow.implicitWidth + Style.marginM * 2
+ return root.capsuleHeight
+ }
+ readonly property real contentHeight: root.capsuleHeight
+
+ implicitWidth: contentWidth
+ implicitHeight: contentHeight
+
+ function formatTime(seconds) {
+ const hours = Math.floor(seconds / 3600);
+ const minutes = Math.floor((seconds % 3600) / 60);
+ const secs = seconds % 60;
+
+ if (hours > 0) {
+ return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
+ }
+ return `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
+ }
+
+ Rectangle {
+ id: visualCapsule
+ x: Style.pixelAlignCenter(parent.width, width)
+ y: Style.pixelAlignCenter(parent.height, height)
+ width: root.contentWidth
+ height: root.contentHeight
+ color: mouseArea.containsMouse ? Color.mHover : Style.capsuleColor
+ radius: Style.radiusL
+ border.color: Style.capsuleBorderColor
+ border.width: Style.capsuleBorderWidth
+
+ RowLayout {
+ id: contentRow
+ anchors.centerIn: parent
+ spacing: Style.marginS
+ layoutDirection: pillDirection ? Qt.LeftToRight : Qt.RightToLeft
+
+ NIcon {
+ icon: {
+ if (mainInstance && mainInstance.timerSoundPlaying) return "bell-ringing"
+ if (mainInstance && mainInstance.timerStopwatchMode) return "stopwatch"
+ return "hourglass"
+ }
+ applyUiScale: false
+ color: mouseArea.containsMouse ? Color.mOnHover : root.iconColor
+ }
+
+ NText {
+ visible: !isVertical && mainInstance && (mainInstance.cdRunning || mainInstance.swRunning || mainInstance.swElapsedSeconds > 0 || mainInstance.cdRemainingSeconds > 0 || mainInstance.cdSoundPlaying)
+ family: Settings.data.ui.fontFixed
+ pointSize: root.barFontSize
+ font.weight: Style.fontWeightBold
+ color: mouseArea.containsMouse ? Color.mOnHover : root.textColor
+ text: {
+ if (!mainInstance) return ""
+ if (mainInstance.timerStopwatchMode) {
+ return formatTime(mainInstance.timerElapsedSeconds)
+ }
+ return formatTime(mainInstance.timerRemainingSeconds)
+ }
+ }
+ }
+ }
+
+ NPopupContextMenu {
+ id: contextMenu
+
+ model: {
+ var items = [];
+
+ if (mainInstance) {
+ // Pause / Resume & Reset
+ const modeActive = mainInstance.timerStopwatchMode
+ ? (mainInstance.swRunning || mainInstance.swElapsedSeconds > 0)
+ : (mainInstance.cdRunning || mainInstance.cdRemainingSeconds > 0 || mainInstance.cdSoundPlaying);
+ if (modeActive) {
+ items.push({
+ "label": mainInstance.timerRunning ? pluginApi.tr("panel.pause") : pluginApi.tr("panel.resume"),
+ "action": "toggle",
+ "icon": mainInstance.timerRunning ? "media-pause" : "media-play"
+ });
+
+ items.push({
+ "label": pluginApi.tr("panel.reset"),
+ "action": "reset",
+ "icon": "refresh"
+ });
+ }
+ }
+
+ // Settings
+ items.push({
+ "label": pluginApi.tr("panel.settings"),
+ "action": "widget-settings",
+ "icon": "settings"
+ });
+
+ return items;
+ }
+
+ onTriggered: action => {
+ contextMenu.close();
+ PanelService.closeContextMenu(screen);
+
+ if (action === "widget-settings") {
+ BarService.openPluginSettings(screen, pluginApi.manifest);
+ } else if (mainInstance) {
+ if (action === "toggle") {
+ if (mainInstance.timerRunning) {
+ mainInstance.timerPause();
+ } else {
+ mainInstance.timerStart();
+ }
+ } else if (action === "reset") {
+ mainInstance.timerReset();
+ }
+ }
+ }
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+
+ onClicked: (mouse) => {
+ if (mouse.button === Qt.LeftButton) {
+ if (pluginApi) {
+ pluginApi.openPanel(root.screen, root)
+ }
+ } else if (mouse.button === Qt.RightButton) {
+ PanelService.showContextMenu(contextMenu, root, screen);
+ }
+ }
+ }
+}
diff --git a/.config/noctalia/plugins/timer/ControlCenterWidget.qml b/.config/noctalia/plugins/timer/ControlCenterWidget.qml
new file mode 100644
index 0000000..528ee04
--- /dev/null
+++ b/.config/noctalia/plugins/timer/ControlCenterWidget.qml
@@ -0,0 +1,45 @@
+import QtQuick
+import Quickshell
+import qs.Widgets
+import qs.Commons
+
+NIconButton {
+ property ShellScreen screen
+ property var pluginApi: null
+ readonly property var mainInstance: pluginApi?.mainInstance
+
+ icon: {
+ if (mainInstance && mainInstance.timerSoundPlaying) return "bell-ringing"
+ if (mainInstance && mainInstance.timerStopwatchMode) return "stopwatch"
+ return "hourglass"
+ }
+
+ tooltipText: {
+ if (!mainInstance) return "Timer"
+ if (mainInstance.timerSoundPlaying) return "Timer Finished!"
+ if (mainInstance.timerStopwatchMode) {
+ return mainInstance.timerRunning ? "Stopwatch Running" : "Stopwatch"
+ }
+ return mainInstance.timerRunning ? "Timer Running" : "Timer"
+ }
+
+ colorFg: {
+ if (mainInstance && (mainInstance.cdRunning || mainInstance.swRunning || mainInstance.cdSoundPlaying)) {
+ return Color.mOnPrimary
+ }
+ return Color.mPrimary
+ }
+
+ colorBg: {
+ if (mainInstance && (mainInstance.cdRunning || mainInstance.swRunning || mainInstance.cdSoundPlaying)) {
+ return Color.mPrimary
+ }
+ return Style.capsuleColor
+ }
+
+ onClicked: {
+ if (pluginApi) {
+ pluginApi.togglePanel(screen);
+ }
+ }
+}
diff --git a/.config/noctalia/plugins/timer/Main.qml b/.config/noctalia/plugins/timer/Main.qml
new file mode 100644
index 0000000..db2193d
--- /dev/null
+++ b/.config/noctalia/plugins/timer/Main.qml
@@ -0,0 +1,239 @@
+import QtQuick
+import Quickshell
+import qs.Commons
+import qs.Services.System
+import qs.Services.UI
+import Quickshell.Io
+
+Item {
+ id: root
+
+ property var pluginApi: null
+
+ IpcHandler {
+ target: "plugin:timer"
+
+ function toggle() {
+ if (pluginApi) {
+ pluginApi.withCurrentScreen(screen => {
+ pluginApi.togglePanel(screen);
+ });
+ }
+ }
+
+ function start(duration_str: string) {
+ if (duration_str && duration_str === "stopwatch") {
+ root.stopwatchReset();
+ root.timerStopwatchMode = true;
+ root.stopwatchStart();
+ } else if (duration_str && duration_str !== "") {
+ const seconds = root.parseDuration(duration_str);
+ if (seconds > 0) {
+ root.countdownReset();
+ root.cdRemainingSeconds = seconds;
+ root.timerStopwatchMode = false;
+ root.countdownStart();
+ }
+ } else {
+ root.timerStart();
+ }
+ }
+
+ function pause() {
+ root.timerPause();
+ }
+
+ function reset() {
+ root.timerReset();
+ }
+ }
+
+ // View mode (which tab is active in the panel)
+ property bool timerStopwatchMode: false
+
+ // Countdown state
+ property bool cdRunning: false
+ property int cdRemainingSeconds: 0
+ property int cdTotalSeconds: 0
+ property int cdStartTimestamp: 0
+ property int cdPausedAt: 0
+ property bool cdSoundPlaying: false
+
+ // Stopwatch state
+ property bool swRunning: false
+ property int swElapsedSeconds: 0
+ property int swStartTimestamp: 0
+ property int swPausedAt: 0
+
+ // Backward-compatible computed properties (used by bar/CC widgets)
+ readonly property bool timerRunning: timerStopwatchMode ? swRunning : cdRunning
+ readonly property int timerRemainingSeconds: cdRemainingSeconds
+ readonly property int timerTotalSeconds: cdTotalSeconds
+ readonly property int timerElapsedSeconds: swElapsedSeconds
+ readonly property bool timerSoundPlaying: cdSoundPlaying
+
+ // Current timestamp
+ property int timestamp: Math.floor(Date.now() / 1000)
+
+ // Main timer loop
+ Timer {
+ id: updateTimer
+ interval: 1000
+ repeat: true
+ running: true
+ triggeredOnStart: false
+ onTriggered: {
+ var now = new Date();
+ root.timestamp = Math.floor(now.getTime() / 1000);
+
+ // Update countdown if running
+ if (root.cdRunning && root.cdStartTimestamp > 0) {
+ const elapsed = root.timestamp - root.cdStartTimestamp;
+ root.cdRemainingSeconds = root.cdTotalSeconds - elapsed;
+ if (root.cdRemainingSeconds <= 0) {
+ root.countdownOnFinished();
+ }
+ }
+
+ // Update stopwatch if running
+ if (root.swRunning && root.swStartTimestamp > 0) {
+ const elapsed = root.timestamp - root.swStartTimestamp;
+ root.swElapsedSeconds = root.swPausedAt + elapsed;
+ }
+
+ // Sync to next second
+ var msIntoSecond = now.getMilliseconds();
+ if (msIntoSecond > 100) {
+ updateTimer.interval = 1000 - msIntoSecond + 10;
+ updateTimer.restart();
+ } else {
+ updateTimer.interval = 1000;
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ // Sync start
+ var now = new Date();
+ var msUntilNextSecond = 1000 - now.getMilliseconds();
+ updateTimer.interval = msUntilNextSecond + 10;
+ updateTimer.restart();
+ }
+
+ // Countdown logic
+ function countdownStart() {
+ if (root.cdRemainingSeconds <= 0) return;
+ root.cdTotalSeconds = root.cdRemainingSeconds;
+ root.cdStartTimestamp = root.timestamp;
+ root.cdPausedAt = 0;
+ root.cdRunning = true;
+ }
+
+ function countdownPause() {
+ if (root.cdRunning) {
+ const currentTimestamp = Math.floor(Date.now() / 1000);
+ const elapsed = currentTimestamp - root.cdStartTimestamp;
+ const remaining = root.cdTotalSeconds - elapsed;
+ root.cdPausedAt = Math.max(0, remaining);
+ root.cdRemainingSeconds = root.cdPausedAt;
+ }
+ root.cdRunning = false;
+ root.cdStartTimestamp = 0;
+ SoundService.stopSound("alarm-beep.wav");
+ root.cdSoundPlaying = false;
+ }
+
+ function countdownReset() {
+ root.cdRunning = false;
+ root.cdStartTimestamp = 0;
+ root.cdRemainingSeconds = 0;
+ root.cdTotalSeconds = 0;
+ root.cdPausedAt = 0;
+ SoundService.stopSound("alarm-beep.wav");
+ root.cdSoundPlaying = false;
+ }
+
+ // Stopwatch logic
+ function stopwatchStart() {
+ root.swStartTimestamp = root.timestamp;
+ root.swPausedAt = root.swElapsedSeconds;
+ root.swRunning = true;
+ }
+
+ function stopwatchPause() {
+ if (root.swRunning) {
+ root.swPausedAt = root.swElapsedSeconds;
+ }
+ root.swRunning = false;
+ root.swStartTimestamp = 0;
+ }
+
+ function stopwatchReset() {
+ root.swRunning = false;
+ root.swStartTimestamp = 0;
+ root.swElapsedSeconds = 0;
+ root.swPausedAt = 0;
+ }
+
+ // Convenience: operate on current mode
+ function timerStart() {
+ if (root.timerStopwatchMode) stopwatchStart();
+ else countdownStart();
+ }
+
+ function timerPause() {
+ if (root.timerStopwatchMode) stopwatchPause();
+ else countdownPause();
+ }
+
+ function timerReset() {
+ if (root.timerStopwatchMode) stopwatchReset();
+ else countdownReset();
+ }
+
+ function parseDuration(duration_str) {
+ if (!duration_str) return 0;
+
+ // Default to minutes if just a number
+ if (/^\d+$/.test(duration_str)) {
+ return parseInt(duration_str) * 60;
+ }
+
+ var totalSeconds = 0;
+ var regex = /(\d+)([hms])/g;
+ var match;
+
+ while ((match = regex.exec(duration_str)) !== null) {
+ var value = parseInt(match[1]);
+ var unit = match[2];
+
+ if (unit === 'h') totalSeconds += value * 3600;
+ else if (unit === 'm') totalSeconds += value * 60;
+ else if (unit === 's') totalSeconds += value;
+ }
+
+ return totalSeconds;
+ }
+
+ function countdownOnFinished() {
+ root.cdRunning = false;
+ root.cdRemainingSeconds = 0;
+ root.cdSoundPlaying = true;
+ SoundService.playSound("alarm-beep.wav", {
+ repeat: true,
+ volume: 0.3
+ });
+ ToastService.showNotice(
+ pluginApi?.tr("toast.title") || "Timer",
+ pluginApi?.tr("toast.finished") || "Timer finished!",
+ "hourglass",
+ {
+ onDismissed: () => {
+ if (root.cdSoundPlaying) {
+ root.countdownPause();
+ }
+ }
+ }
+ );
+ }
+}
diff --git a/.config/noctalia/plugins/timer/Panel.qml b/.config/noctalia/plugins/timer/Panel.qml
new file mode 100644
index 0000000..b79389e
--- /dev/null
+++ b/.config/noctalia/plugins/timer/Panel.qml
@@ -0,0 +1,593 @@
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import qs.Commons
+import qs.Services.System
+import qs.Widgets
+
+Item {
+ id: root
+
+ property var pluginApi: null
+ readonly property var geometryPlaceholder: panelContainer
+ property real contentPreferredWidth: (compactMode ? 340 : 380) * Style.uiScaleRatio
+ property real contentPreferredHeight: (compactMode ? 230 : 350) * Style.uiScaleRatio
+ readonly property bool allowAttach: true
+
+
+
+ readonly property bool compactMode:
+ pluginApi?.pluginSettings?.compactMode ??
+ pluginApi?.manifest?.metadata?.defaultSettings?.compactMode ??
+ false
+
+
+
+ anchors.fill: parent
+
+ readonly property var mainInstance: pluginApi?.mainInstance
+
+ readonly property bool isRunning: mainInstance ? mainInstance.timerRunning : false
+ property bool isStopwatchMode: mainInstance ? mainInstance.timerStopwatchMode : false
+ readonly property int remainingSeconds: mainInstance ? mainInstance.timerRemainingSeconds : 0
+ readonly property int totalSeconds: mainInstance ? mainInstance.timerTotalSeconds : 0
+ readonly property int elapsedSeconds: mainInstance ? mainInstance.timerElapsedSeconds : 0
+ readonly property bool soundPlaying: mainInstance ? mainInstance.timerSoundPlaying : false
+
+ function startTimer() { if (mainInstance) mainInstance.timerStart(); }
+ function pauseTimer() { if (mainInstance) mainInstance.timerPause(); }
+ function resetTimer() {
+ if (mainInstance) {
+ mainInstance.timerReset();
+ // Do not apply default duration here. User wants 00:00:00 on reset.
+ }
+ }
+
+ function setTimerStopwatchMode(mode) {
+ if (mainInstance) {
+ mainInstance.timerStopwatchMode = mode;
+ }
+ }
+
+ function setTimerRemainingSeconds(seconds) {
+ if (mainInstance) mainInstance.cdRemainingSeconds = seconds;
+ }
+
+ function formatTime(seconds, totalTimeSeconds) {
+ const hours = Math.floor(seconds / 3600);
+ const minutes = Math.floor((seconds % 3600) / 60);
+ const secs = seconds % 60;
+
+ if (seconds === 0 && totalTimeSeconds > 0) {
+ return `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
+ }
+
+ if (!totalTimeSeconds || totalTimeSeconds === 0) {
+ return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
+ }
+
+ if (totalTimeSeconds < 3600) {
+ return `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
+ }
+ return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
+ }
+
+ function formatTimeFromDigits(digits) {
+ const len = digits.length;
+ let seconds = 0;
+ let minutes = 0;
+ let hours = 0;
+
+ if (len > 0) {
+ seconds = parseInt(digits.substring(Math.max(0, len - 2))) || 0;
+ }
+ if (len > 2) {
+ minutes = parseInt(digits.substring(Math.max(0, len - 4), len - 2)) || 0;
+ }
+ if (len > 4) {
+ hours = parseInt(digits.substring(0, len - 4)) || 0;
+ }
+
+ seconds = Math.min(59, seconds);
+ minutes = Math.min(59, minutes);
+ hours = Math.min(99, hours);
+
+ return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
+ }
+
+ function parseDigitsToTime(digits) {
+ const len = digits.length;
+ let seconds = 0;
+ let minutes = 0;
+ let hours = 0;
+
+ if (len > 0) {
+ seconds = parseInt(digits.substring(Math.max(0, len - 2))) || 0;
+ }
+ if (len > 2) {
+ minutes = parseInt(digits.substring(Math.max(0, len - 4), len - 2)) || 0;
+ }
+ if (len > 4) {
+ hours = parseInt(digits.substring(0, len - 4)) || 0;
+ }
+
+ seconds = Math.min(59, seconds);
+ minutes = Math.min(59, minutes);
+ hours = Math.min(99, hours);
+
+ setTimerRemainingSeconds((hours * 3600) + (minutes * 60) + seconds);
+ }
+
+ Component.onCompleted: {
+ // Do not auto-set default duration on load
+ }
+
+ function applyTimeFromBuffer() {
+ if (timerDisplayItem.inputBuffer !== "") {
+ parseDigitsToTime(timerDisplayItem.inputBuffer);
+ timerDisplayItem.inputBuffer = "";
+ }
+ }
+
+ onVisibleChanged: {
+ if (visible) {
+ if (!isRunning && !isStopwatchMode && totalSeconds === 0) {
+ timerInput.forceActiveFocus();
+ }
+ }
+ }
+
+ Rectangle {
+ id: panelContainer
+ anchors.fill: parent
+ color: "transparent"
+
+ ColumnLayout {
+ anchors {
+ fill: parent
+ margins: Style.marginM
+ }
+ spacing: Style.marginL
+
+ NBox {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ ColumnLayout {
+ id: content
+ anchors.fill: parent
+ anchors.margins: Style.marginM
+ spacing: Style.marginM
+ clip: true
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: Style.marginS
+
+ NIcon {
+ icon: isStopwatchMode ? "clock" : "hourglass"
+ pointSize: Style.fontSizeL
+ color: Color.mPrimary
+ }
+
+ NText {
+ text: pluginApi?.tr("panel.title") || "Timer"
+ pointSize: Style.fontSizeL
+ font.weight: Style.fontWeightBold
+ color: Color.mOnSurface
+ Layout.fillWidth: true
+ }
+ }
+
+ Item {
+ id: timerDisplayItem
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.alignment: Qt.AlignHCenter
+
+ property string inputBuffer: ""
+ property bool isEditing: false
+
+ WheelHandler {
+ target: timerDisplayItem
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
+ enabled: !isRunning && !isStopwatchMode && totalSeconds === 0
+ onWheel: function (event) {
+ if (!enabled || !mainInstance) {
+ return;
+ }
+ const step = 5;
+ if (event.angleDelta.y > 0) {
+ mainInstance.cdRemainingSeconds = Math.max(0, mainInstance.cdRemainingSeconds + step);
+ event.accepted = true;
+ } else if (event.angleDelta.y < 0) {
+ mainInstance.cdRemainingSeconds = Math.max(0, mainInstance.cdRemainingSeconds - step);
+ event.accepted = true;
+ }
+ }
+ }
+
+ Rectangle {
+ id: textboxBorder
+ anchors.centerIn: parent
+ width: Math.max(timerInput.implicitWidth + Style.marginM * 2, parent.width * 0.8)
+ height: timerInput.implicitHeight + Style.marginM * 2
+ radius: Style.iRadiusM
+ color: Color.mSurfaceVariant
+ border.color: (timerInput.activeFocus || timerDisplayItem.isEditing) ? Color.mPrimary : Color.mOutline
+ border.width: Style.borderS
+ visible: !isRunning && !isStopwatchMode && totalSeconds === 0
+ z: 0
+
+ Behavior on border.color {
+ ColorAnimation {
+ duration: Style.animationFast
+ }
+ }
+ }
+
+ Canvas {
+ id: progressRing
+ anchors.centerIn: parent
+ width: Math.min(parent.width, parent.height) * 1.0
+ height: width
+ visible: !isStopwatchMode && totalSeconds > 0 && !compactMode && (isRunning || elapsedSeconds > 0)
+ z: -1
+
+ property real progressRatio: {
+ if (totalSeconds <= 0)
+ return 0;
+ const ratio = remainingSeconds / totalSeconds;
+ return Math.max(0, Math.min(1, ratio));
+ }
+
+ onProgressRatioChanged: requestPaint()
+
+ onPaint: {
+ var ctx = getContext("2d");
+ if (width <= 0 || height <= 0) {
+ return;
+ }
+
+ var centerX = width / 2;
+ var centerY = height / 2;
+ var radius = Math.min(width, height) / 2 - 5;
+
+ if (radius <= 0) {
+ return;
+ }
+
+ ctx.reset();
+
+ ctx.beginPath();
+ ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
+ ctx.lineWidth = 10;
+ ctx.strokeStyle = Qt.alpha(Color.mOnSurface, 0.1);
+ ctx.stroke();
+
+ if (progressRatio > 0) {
+ ctx.beginPath();
+ ctx.arc(centerX, centerY, radius, -Math.PI / 2, -Math.PI / 2 + progressRatio * 2 * Math.PI);
+ ctx.lineWidth = 10;
+ ctx.strokeStyle = Color.mPrimary;
+ ctx.lineCap = "round";
+ ctx.stroke();
+ }
+ }
+ }
+
+ Item {
+ id: timerContainer
+ anchors.centerIn: parent
+ width: timerInput.implicitWidth
+ height: timerInput.implicitHeight + 8
+
+ TextInput {
+ id: timerInput
+ anchors.centerIn: parent
+ width: Math.max(implicitWidth, timerDisplayItem.width * 0.8)
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ selectByMouse: false
+ cursorVisible: false
+ cursorDelegate: Item {}
+ readOnly: isStopwatchMode || isRunning || totalSeconds > 0
+ enabled: !isRunning && !isStopwatchMode && totalSeconds === 0
+ font.family: Settings.data.ui.fontFixed
+
+ readonly property bool showingHours: {
+ if (isStopwatchMode) {
+ return elapsedSeconds >= 3600;
+ }
+ if (timerDisplayItem.isEditing) {
+ return true;
+ }
+ return totalSeconds >= 3600;
+ }
+
+ font.pointSize: {
+ const scale = compactMode ? 0.8 : 1.0;
+ if (totalSeconds === 0) {
+ return Style.fontSizeXXXL * 1.5 * scale;
+ }
+ return (showingHours ? Style.fontSizeXXL * 1.3 : (Style.fontSizeXXL * 1.8)) * scale;
+ }
+
+ font.weight: Style.fontWeightBold
+ color: {
+ if (totalSeconds > 0) {
+ return Color.mPrimary;
+ }
+ if (timerDisplayItem.isEditing) {
+ return Color.mPrimary;
+ }
+ return Color.mOnSurface;
+ }
+
+ property string _cachedText: ""
+ property int _textUpdateCounter: 0
+
+ function updateText() {
+ if (isStopwatchMode) {
+ _cachedText = formatTime(elapsedSeconds, elapsedSeconds);
+ } else if (timerDisplayItem.isEditing && totalSeconds === 0 && timerDisplayItem.inputBuffer !== "") {
+ _cachedText = formatTimeFromDigits(timerDisplayItem.inputBuffer);
+ } else if (timerDisplayItem.isEditing && totalSeconds === 0) {
+ _cachedText = formatTime(0, 0);
+ } else {
+ _cachedText = formatTime(remainingSeconds, totalSeconds);
+ }
+ _textUpdateCounter = _textUpdateCounter + 1;
+ }
+
+ text: {
+ const counter = _textUpdateCounter;
+ return _cachedText;
+ }
+
+ Connections {
+ target: root
+ function onRemainingSecondsChanged() { timerInput.updateText(); }
+ function onTotalSecondsChanged() { timerInput.updateText(); }
+ function onIsRunningChanged() { timerInput.updateText(); Qt.callLater(() => { timerInput.updateText(); }); }
+ function onElapsedSecondsChanged() { timerInput.updateText(); }
+ function onIsStopwatchModeChanged() { timerInput.updateText(); }
+ }
+
+ Connections {
+ target: timerDisplayItem
+ function onIsEditingChanged() {
+ timerInput.updateText();
+ }
+ }
+
+ Component.onCompleted: updateText()
+
+ Keys.onPressed: event => {
+ if (isRunning || isStopwatchMode || totalSeconds > 0) {
+ if (event.key === Qt.Key_Space) {
+ if (isRunning) mainInstance.timerPause();
+ else mainInstance.timerStart();
+ event.accepted = true;
+ return;
+ }
+ event.accepted = true;
+ return;
+ }
+
+ const keyText = event.text.toLowerCase();
+
+ if (event.key === Qt.Key_Backspace) {
+ if (timerDisplayItem.isEditing && timerDisplayItem.inputBuffer.length > 0) {
+ timerDisplayItem.inputBuffer = timerDisplayItem.inputBuffer.slice(0, -1);
+ if (timerDisplayItem.inputBuffer !== "") {
+ parseDigitsToTime(timerDisplayItem.inputBuffer);
+ } else {
+ setTimerRemainingSeconds(0);
+ }
+ }
+ event.accepted = true;
+ return;
+ }
+
+ if (event.key === Qt.Key_Delete) {
+ if (timerDisplayItem.isEditing) {
+ timerDisplayItem.inputBuffer = "";
+ setTimerRemainingSeconds(0);
+ }
+ event.accepted = true;
+ return;
+ }
+
+ if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_Space) {
+ applyTimeFromBuffer();
+ timerDisplayItem.isEditing = false;
+ timerInput.focus = false;
+ if (remainingSeconds > 0) {
+ mainInstance.timerStart();
+ }
+ event.accepted = true;
+ return;
+ }
+
+ if (event.key === Qt.Key_Escape) {
+ timerDisplayItem.inputBuffer = "";
+ setTimerRemainingSeconds(0);
+ timerDisplayItem.isEditing = false;
+ timerInput.focus = false;
+ event.accepted = true;
+ return;
+ }
+
+ if (keyText === 'h' || keyText === 'm' || keyText === 's') {
+ if (timerDisplayItem.inputBuffer.length > 0) {
+ let val = parseInt(timerDisplayItem.inputBuffer) || 0;
+ let secs = 0;
+ if (keyText === 'h') secs = val * 3600;
+ else if (keyText === 'm') secs = val * 60;
+ else if (keyText === 's') secs = val;
+
+ setTimerRemainingSeconds(Math.min(99 * 3600 + 59 * 60 + 59, secs));
+ timerDisplayItem.inputBuffer = "";
+ timerDisplayItem.isEditing = false;
+ timerInput.focus = false;
+ }
+ event.accepted = true;
+ return;
+ }
+
+ const isDigitKey = event.key >= Qt.Key_0 && event.key <= Qt.Key_9;
+ const isDigitText = keyText.length === 1 && keyText >= '0' && keyText <= '9';
+
+ if (isDigitKey && isDigitText) {
+ if (timerDisplayItem.inputBuffer.length >= 6) {
+ event.accepted = true;
+ return;
+ }
+ timerDisplayItem.inputBuffer += keyText;
+ parseDigitsToTime(timerDisplayItem.inputBuffer);
+ event.accepted = true;
+ } else {
+ event.accepted = true;
+ }
+ }
+
+ onActiveFocusChanged: {
+ if (activeFocus) {
+ timerDisplayItem.isEditing = true;
+ timerDisplayItem.inputBuffer = "";
+ } else {
+ applyTimeFromBuffer();
+ timerDisplayItem.isEditing = false;
+ timerDisplayItem.inputBuffer = "";
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ enabled: !isRunning && !isStopwatchMode && totalSeconds === 0
+ cursorShape: enabled ? Qt.IBeamCursor : Qt.ArrowCursor
+ preventStealing: true
+ onPressed: (mouse) => {
+ if (!isRunning && !isStopwatchMode && totalSeconds === 0) {
+ timerInput.forceActiveFocus();
+ mouse.accepted = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ RowLayout {
+ id: buttonRow
+ Layout.fillWidth: true
+ spacing: Style.marginS
+
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.preferredWidth: 0
+ implicitHeight: startButton.implicitHeight
+ color: "transparent"
+
+ NButton {
+ id: startButton
+ anchors.fill: parent
+ text: {
+ if (isRunning) return pluginApi?.tr("panel.pause") || "Pause";
+ if (isStopwatchMode && elapsedSeconds > 0) return pluginApi?.tr("panel.resume") || "Resume";
+ if (!isStopwatchMode && totalSeconds > 0) return pluginApi?.tr("panel.resume") || "Resume";
+ return pluginApi?.tr("panel.start") || "Start";
+ }
+ icon: isRunning ? "player-pause" : "player-play"
+ enabled: isStopwatchMode || remainingSeconds > 0
+ onClicked: {
+ if (isRunning) {
+ pauseTimer();
+ } else {
+ startTimer();
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.preferredWidth: 0
+ implicitHeight: resetButton.implicitHeight
+ color: "transparent"
+
+ NButton {
+ id: resetButton
+ anchors.fill: parent
+ text: pluginApi?.tr("panel.reset") || "Reset"
+ icon: "refresh"
+ enabled: (isStopwatchMode && (elapsedSeconds > 0 || isRunning)) || (!isStopwatchMode && (remainingSeconds > 0 || isRunning || soundPlaying))
+ onClicked: {
+ resetTimer();
+ }
+ }
+ }
+ }
+
+ NTabBar {
+ id: modeTabBar
+ Layout.fillWidth: true
+ Layout.preferredHeight: Style.baseWidgetSize
+ currentIndex: isStopwatchMode ? 1 : 0
+ margins: 0
+ distributeEvenly: true
+ onCurrentIndexChanged: {
+ const newMode = currentIndex === 1;
+ if (newMode !== isStopwatchMode) {
+ timerInput.focus = false;
+ setTimerStopwatchMode(newMode);
+ }
+ }
+ spacing: Style.marginS
+
+
+ Component.onCompleted: {
+ Qt.callLater(() => {
+ if (modeTabBar.children && modeTabBar.children.length > 0) {
+ for (var i = 0; i < modeTabBar.children.length; i++) {
+ var child = modeTabBar.children[i];
+ if (child && typeof child.spacing !== 'undefined' && child.anchors) {
+ child.anchors.margins = 0;
+ break;
+ }
+ }
+ }
+ });
+ }
+
+ NTabButton {
+ text: pluginApi?.tr("panel.countdown") || "Timer"
+ tabIndex: 0
+ checked: !isStopwatchMode
+ radius: Style.iRadiusS
+ }
+
+ NTabButton {
+ text: pluginApi?.tr("panel.stopwatch") || "Stopwatch"
+ tabIndex: 1
+ checked: isStopwatchMode
+ radius: Style.iRadiusS
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Shortcut {
+ sequence: "Space"
+ onActivated: {
+ if (!timerInput.activeFocus) {
+ if (isRunning) mainInstance.timerPause();
+ else if (isStopwatchMode || remainingSeconds > 0) mainInstance.timerStart();
+ }
+ }
+ }
+}
+
diff --git a/.config/noctalia/plugins/timer/README.md b/.config/noctalia/plugins/timer/README.md
new file mode 100644
index 0000000..ae04689
--- /dev/null
+++ b/.config/noctalia/plugins/timer/README.md
@@ -0,0 +1,52 @@
+# Timer Plugin
+
+A simple and elegant timer and stopwatch plugin for Noctalia.
+
+## Features
+
+- **Countdown Timer**: Set a duration and get notified when it finishes.
+- **Stopwatch**: Measure elapsed time.
+- **Bar Widget**: Shows status and remaining/elapsed time.
+- **Control Center Widget**: Quick access from the control center.
+- **Notifications**: Sound and toast notification when timer finishes.
+- **Multi-language**: Support for 14 languages.
+
+## IPC Commands
+
+You can control the timer plugin via the command line using the Noctalia IPC interface.
+
+### General Usage
+```bash
+qs -c noctalia-shell ipc call plugin:timer <command>
+```
+
+### Available Commands
+
+| Command | Arguments | Description | Example |
+|---|---|---|---|
+| `toggle` | | Opens or closes the timer panel on the current screen | `qs -c noctalia-shell ipc call plugin:timer toggle` |
+| `start` | `[duration]` or `stopwatch` (optional) | Starts/resumes timer or switches to stopwatch mode. | `qs -c noctalia-shell ipc call plugin:timer start 10m` |
+| `pause` | | Pauses the running timer/stopwatch | `qs -c noctalia-shell ipc call plugin:timer pause` |
+| `reset` | | Resets the timer/stopwatch to initial state | `qs -c noctalia-shell ipc call plugin:timer reset` |
+
+### Duration Format
+
+The `start` command accepts duration strings in the following formats:
+- `30` (defaults to minutes)
+- `10s` (seconds)
+- `5m` (minutes)
+- `2h` (hours)
+- `1h30m` (combined)
+- `stopwatch` (keyword to start stopwatch)
+
+### Examples
+
+**Start a 25-minute timer (Pomodoro):**
+```bash
+qs -c noctalia-shell ipc call plugin:timer start 25m
+```
+
+**Start the stopwatch:**
+```bash
+qs -c noctalia-shell ipc call plugin:timer start stopwatch
+```
diff --git a/.config/noctalia/plugins/timer/Settings.qml b/.config/noctalia/plugins/timer/Settings.qml
new file mode 100644
index 0000000..fc963d8
--- /dev/null
+++ b/.config/noctalia/plugins/timer/Settings.qml
@@ -0,0 +1,65 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import qs.Commons
+import qs.Widgets
+import qs.Services.UI
+
+ColumnLayout {
+ id: root
+ spacing: Style.marginL
+
+ property var pluginApi: null
+
+ property bool editCompactMode:
+ pluginApi?.pluginSettings?.compactMode ??
+ pluginApi?.manifest?.metadata?.defaultSettings?.compactMode ??
+ false
+
+ property string editIconColor:
+ pluginApi?.pluginSettings?.iconColor ??
+ pluginApi?.manifest?.metadata?.defaultSettings?.iconColor ??
+ "none"
+
+ property string editTextColor:
+ pluginApi?.pluginSettings?.textColor ??
+ pluginApi?.manifest?.metadata?.defaultSettings?.textColor ??
+ "none"
+
+ function saveSettings() {
+ if (!pluginApi) {
+ Logger.e("Timer", "Cannot save: pluginApi is null")
+ return
+ }
+
+ pluginApi.pluginSettings.compactMode = root.editCompactMode
+ pluginApi.pluginSettings.iconColor = root.editIconColor
+ pluginApi.pluginSettings.textColor = root.editTextColor
+
+ pluginApi.saveSettings()
+ Logger.i("Timer", "Settings saved successfully")
+ }
+
+ // Icon Color
+ NColorChoice {
+ label: I18n.tr("common.select-icon-color")
+ description: I18n.tr("common.select-color-description")
+ currentKey: root.editIconColor
+ onSelected: key => root.editIconColor = key
+ }
+
+ // Text Color
+ NColorChoice {
+ currentKey: root.editTextColor
+ onSelected: key => root.editTextColor = key
+ }
+
+ // Compact Mode
+ NToggle {
+ label: pluginApi?.tr("settings.compact-mode") || "Compact Mode"
+ description: pluginApi?.tr("settings.compact-mode-desc") || "Hide the circular progress bar for a cleaner look"
+ checked: root.editCompactMode
+ onToggled: checked => root.editCompactMode = checked
+ defaultValue: pluginApi?.manifest?.metadata?.defaultSettings?.compactMode ?? false
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/de.json b/.config/noctalia/plugins/timer/i18n/de.json
new file mode 100644
index 0000000..41f35c8
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/de.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Countdown",
+ "pause": "Pause",
+ "reset": "Zurücksetzen",
+ "resume": "Fortsetzen",
+ "settings": "Widget-Einstellungen",
+ "start": "Start",
+ "stopwatch": "Stoppuhr",
+ "title": "Timer"
+ },
+ "settings": {
+ "compact-mode": "Kompaktmodus",
+ "compact-mode-desc": "Kreisförmigen Fortschrittsbalken für ein saubereres Aussehen ausblenden"
+ },
+ "toast": {
+ "finished": "Timer abgelaufen!",
+ "title": "Timer"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/en.json b/.config/noctalia/plugins/timer/i18n/en.json
new file mode 100644
index 0000000..bdfa722
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/en.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Countdown",
+ "pause": "Pause",
+ "reset": "Reset",
+ "resume": "Resume",
+ "settings": "Widget Settings",
+ "start": "Start",
+ "stopwatch": "Stopwatch",
+ "title": "Timer"
+ },
+ "settings": {
+ "compact-mode": "Compact Mode",
+ "compact-mode-desc": "Hide the circular progress bar for a cleaner look"
+ },
+ "toast": {
+ "finished": "Timer finished!",
+ "title": "Timer"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/es.json b/.config/noctalia/plugins/timer/i18n/es.json
new file mode 100644
index 0000000..4a0be12
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/es.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Cuenta atrás",
+ "pause": "Pausa",
+ "reset": "Reiniciar",
+ "resume": "Reanudar",
+ "settings": "Configuración del Widget",
+ "start": "Iniciar",
+ "stopwatch": "Cronómetro",
+ "title": "Temporizador"
+ },
+ "settings": {
+ "compact-mode": "Modo compacto",
+ "compact-mode-desc": "Ocultar la barra de progreso circular para una apariencia más limpia"
+ },
+ "toast": {
+ "finished": "¡Temporizador terminado!",
+ "title": "Temporizador"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/fr.json b/.config/noctalia/plugins/timer/i18n/fr.json
new file mode 100644
index 0000000..d11c630
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/fr.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Compte à rebours",
+ "pause": "Pause",
+ "reset": "Réinitialiser",
+ "resume": "Reprendre",
+ "settings": "Paramètres du Widget",
+ "start": "Démarrer",
+ "stopwatch": "Chronomètre",
+ "title": "Minuteur"
+ },
+ "settings": {
+ "compact-mode": "Mode compact",
+ "compact-mode-desc": "Masquer la barre de progression circulaire pour un aspect plus épuré"
+ },
+ "toast": {
+ "finished": "Minuteur terminé !",
+ "title": "Minuteur"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/hu.json b/.config/noctalia/plugins/timer/i18n/hu.json
new file mode 100644
index 0000000..be49bb5
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/hu.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Visszaszámlálás",
+ "pause": "Szünet",
+ "reset": "Visszaállítás",
+ "resume": "Folytatás",
+ "settings": "Widget beállítások",
+ "start": "Indítás",
+ "stopwatch": "Stopper",
+ "title": "Időzítő"
+ },
+ "settings": {
+ "compact-mode": "Kompakt mód",
+ "compact-mode-desc": "A körkörös folyamatjelző elrejtése a tisztább megjelenés érdekében"
+ },
+ "toast": {
+ "finished": "Időzítő lejárt!",
+ "title": "Időzítő"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/it.json b/.config/noctalia/plugins/timer/i18n/it.json
new file mode 100644
index 0000000..40517c8
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/it.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Countdown",
+ "pause": "Pausa",
+ "reset": "Reimposta",
+ "resume": "Riprendi",
+ "settings": "Impostazioni",
+ "start": "Avvia",
+ "stopwatch": "Cronometro",
+ "title": "Timer"
+ },
+ "settings": {
+ "compact-mode": "Modalità compatta",
+ "compact-mode-desc": "Nascondi la barra di avanzamento circolare per un aspetto più pulito"
+ },
+ "toast": {
+ "finished": "Timer terminato",
+ "title": "Timer"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/ja.json b/.config/noctalia/plugins/timer/i18n/ja.json
new file mode 100644
index 0000000..948109b
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/ja.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "カウントダウン",
+ "pause": "一時停止",
+ "reset": "リセット",
+ "resume": "再開",
+ "settings": "ウィジェット設定",
+ "start": "開始",
+ "stopwatch": "ストップウォッチ",
+ "title": "タイマー"
+ },
+ "settings": {
+ "compact-mode": "コンパクトモード",
+ "compact-mode-desc": "円形の進行状況バーを非表示にして、すっきりとした見た目にする"
+ },
+ "toast": {
+ "finished": "タイマー終了!",
+ "title": "タイマー"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/ku.json b/.config/noctalia/plugins/timer/i18n/ku.json
new file mode 100644
index 0000000..abff80f
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/ku.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Jimartina Paşve",
+ "pause": "Rawestandin",
+ "reset": "Nûkirin",
+ "resume": "Berdewamkirin",
+ "settings": "Mîhengên Widget",
+ "start": "Destpêkirin",
+ "stopwatch": "Demgir",
+ "title": "Demjimêr"
+ },
+ "settings": {
+ "compact-mode": "Moda Kompakt",
+ "compact-mode-desc": "Barê pêşveçûnê yê dorûber veşêre ji bo dîmenek paqijtir"
+ },
+ "toast": {
+ "finished": "Demjimêr qediya!",
+ "title": "Demjimêr"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/nl.json b/.config/noctalia/plugins/timer/i18n/nl.json
new file mode 100644
index 0000000..8098f3c
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/nl.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Aftellen",
+ "pause": "Pauze",
+ "reset": "Resetten",
+ "resume": "Hervatten",
+ "settings": "Widget-instellingen",
+ "start": "Start",
+ "stopwatch": "Stopwatch",
+ "title": "Timer"
+ },
+ "settings": {
+ "compact-mode": "Compacte modus",
+ "compact-mode-desc": "Verberg de circulaire voortgangsbalk voor een schoner uiterlijk"
+ },
+ "toast": {
+ "finished": "Timer afgelopen!",
+ "title": "Timer"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/pl.json b/.config/noctalia/plugins/timer/i18n/pl.json
new file mode 100644
index 0000000..8aa6cf2
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/pl.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Odliczanie",
+ "pause": "Pauza",
+ "reset": "Resetuj",
+ "resume": "Wznów",
+ "settings": "Ustawienia widżetu",
+ "start": "Start",
+ "stopwatch": "Stoper",
+ "title": "Czasomierz"
+ },
+ "settings": {
+ "compact-mode": "Tryb kompaktowy",
+ "compact-mode-desc": "Ukryj okrągły pasek postępu dla czystszego wyglądu"
+ },
+ "toast": {
+ "finished": "Czasomierz zakończony!",
+ "title": "Czasomierz"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/pt.json b/.config/noctalia/plugins/timer/i18n/pt.json
new file mode 100644
index 0000000..50c490d
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/pt.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Contagem regressiva",
+ "pause": "Pausar",
+ "reset": "Reiniciar",
+ "resume": "Retomar",
+ "settings": "Configurações do Widget",
+ "start": "Iniciar",
+ "stopwatch": "Cronômetro",
+ "title": "Temporizador"
+ },
+ "settings": {
+ "compact-mode": "Modo compacto",
+ "compact-mode-desc": "Ocultar a barra de progresso circular para um visual mais limpo"
+ },
+ "toast": {
+ "finished": "Temporizador finalizado!",
+ "title": "Temporizador"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/ru.json b/.config/noctalia/plugins/timer/i18n/ru.json
new file mode 100644
index 0000000..0269aa7
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/ru.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Обратный отсчет",
+ "pause": "Пауза",
+ "reset": "Сброс",
+ "resume": "Продолжить",
+ "settings": "Настройки виджета",
+ "start": "Старт",
+ "stopwatch": "Секундомер",
+ "title": "Таймер"
+ },
+ "settings": {
+ "compact-mode": "Компактный режим",
+ "compact-mode-desc": "Скрыть круговой индикатор прогресса для более чистого вида"
+ },
+ "toast": {
+ "finished": "Таймер завершён!",
+ "title": "Таймер"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/tr.json b/.config/noctalia/plugins/timer/i18n/tr.json
new file mode 100644
index 0000000..c3d8f8f
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/tr.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Geri Sayım",
+ "pause": "Duraklat",
+ "reset": "Sıfırla",
+ "resume": "Devam Et",
+ "settings": "Widget Ayarları",
+ "start": "Başlat",
+ "stopwatch": "Kronometre",
+ "title": "Zamanlayıcı"
+ },
+ "settings": {
+ "compact-mode": "Kompakt Mod",
+ "compact-mode-desc": "Daha temiz bir görünüm için dairesel ilerleme çubuğunu gizle"
+ },
+ "toast": {
+ "finished": "Zamanlayıcı bitti!",
+ "title": "Zamanlayıcı"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/uk-UA.json b/.config/noctalia/plugins/timer/i18n/uk-UA.json
new file mode 100644
index 0000000..a4326cc
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/uk-UA.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "Зворотний відлік",
+ "pause": "Пауза",
+ "reset": "Скинути",
+ "resume": "Продовжити",
+ "settings": "Налаштування віджета",
+ "start": "Старт",
+ "stopwatch": "Секундомір",
+ "title": "Таймер"
+ },
+ "settings": {
+ "compact-mode": "Компактний режим",
+ "compact-mode-desc": "Приховати круговий індикатор прогресу для чистішого вигляду"
+ },
+ "toast": {
+ "finished": "Таймер завершено!",
+ "title": "Таймер"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/zh-CN.json b/.config/noctalia/plugins/timer/i18n/zh-CN.json
new file mode 100644
index 0000000..72bb0e1
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/zh-CN.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "倒计时",
+ "pause": "暂停",
+ "reset": "重置",
+ "resume": "继续",
+ "settings": "小部件设置",
+ "start": "开始",
+ "stopwatch": "秒表",
+ "title": "计时器"
+ },
+ "settings": {
+ "compact-mode": "紧凑模式",
+ "compact-mode-desc": "隐藏圆形进度条以获得更整洁的外观"
+ },
+ "toast": {
+ "finished": "计时器结束!",
+ "title": "计时器"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/i18n/zh-TW.json b/.config/noctalia/plugins/timer/i18n/zh-TW.json
new file mode 100644
index 0000000..e9b89bd
--- /dev/null
+++ b/.config/noctalia/plugins/timer/i18n/zh-TW.json
@@ -0,0 +1,20 @@
+{
+ "panel": {
+ "countdown": "倒數",
+ "pause": "暫停",
+ "reset": "重置",
+ "resume": "繼續",
+ "settings": "小工具設定",
+ "start": "開始",
+ "stopwatch": "碼表",
+ "title": "計時器"
+ },
+ "settings": {
+ "compact-mode": "緊湊模式",
+ "compact-mode-desc": "隱藏進度圓環以得到更精簡的外觀"
+ },
+ "toast": {
+ "finished": "時間到了!",
+ "title": "計時器"
+ }
+}
diff --git a/.config/noctalia/plugins/timer/manifest.json b/.config/noctalia/plugins/timer/manifest.json
new file mode 100644
index 0000000..766392a
--- /dev/null
+++ b/.config/noctalia/plugins/timer/manifest.json
@@ -0,0 +1,33 @@
+{
+ "id": "timer",
+ "name": "Timer",
+ "version": "1.1.2",
+ "minNoctaliaVersion": "4.4.4",
+ "author": "Noctalia Team",
+ "official": true,
+ "license": "MIT",
+ "repository": "https://github.com/noctalia-dev/noctalia-plugins",
+ "description": "A timer and stopwatch plugin for the bar & control center.",
+ "tags": [
+ "Bar",
+ "Utility"
+ ],
+ "entryPoints": {
+ "main": "Main.qml",
+ "barWidget": "BarWidget.qml",
+ "panel": "Panel.qml",
+ "controlCenterWidget": "ControlCenterWidget.qml",
+ "settings": "Settings.qml"
+ },
+ "dependencies": {
+ "plugins": []
+ },
+ "metadata": {
+ "defaultSettings": {
+ "defaultDuration": 0,
+ "compactMode": false,
+ "iconColor": "none",
+ "textColor": "none"
+ }
+ }
+} \ No newline at end of file
diff --git a/.config/noctalia/plugins/timer/preview.png b/.config/noctalia/plugins/timer/preview.png
new file mode 100644
index 0000000..bead8e2
--- /dev/null
+++ b/.config/noctalia/plugins/timer/preview.png
Binary files differ
diff --git a/.config/noctalia/plugins/timer/settings.json b/.config/noctalia/plugins/timer/settings.json
new file mode 100644
index 0000000..3979fb2
--- /dev/null
+++ b/.config/noctalia/plugins/timer/settings.json
@@ -0,0 +1,5 @@
+{
+ "compactMode": true,
+ "iconColor": "none",
+ "textColor": "none"
+}
diff --git a/.config/noctalia/settings.json b/.config/noctalia/settings.json
new file mode 100644
index 0000000..a8139a1
--- /dev/null
+++ b/.config/noctalia/settings.json
@@ -0,0 +1,672 @@
+{
+ "appLauncher": {
+ "autoPasteClipboard": false,
+ "clipboardWatchImageCommand": "wl-paste --type image --watch cliphist store",
+ "clipboardWatchTextCommand": "wl-paste --type text --watch cliphist store",
+ "clipboardWrapText": true,
+ "customLaunchPrefix": "",
+ "customLaunchPrefixEnabled": false,
+ "density": "default",
+ "enableClipPreview": true,
+ "enableClipboardHistory": false,
+ "enableSessionSearch": true,
+ "enableSettingsSearch": true,
+ "enableWindowsSearch": true,
+ "iconMode": "tabler",
+ "ignoreMouseInput": false,
+ "overviewLayer": false,
+ "pinnedApps": [
+ ],
+ "position": "center",
+ "screenshotAnnotationTool": "",
+ "showCategories": true,
+ "showIconBackground": false,
+ "sortByMostUsed": true,
+ "terminalCommand": "foot -e",
+ "useApp2Unit": false,
+ "viewMode": "list"
+ },
+ "audio": {
+ "mprisBlacklist": [
+ ],
+ "preferredPlayer": "mpv",
+ "spectrumFrameRate": 30,
+ "visualizerType": "linear",
+ "volumeFeedback": false,
+ "volumeFeedbackSoundFile": "",
+ "volumeOverdrive": false,
+ "volumeStep": 5
+ },
+ "bar": {
+ "autoHideDelay": 500,
+ "autoShowDelay": 150,
+ "backgroundOpacity": 0.8,
+ "barType": "simple",
+ "capsuleColorKey": "none",
+ "capsuleOpacity": 1,
+ "contentPadding": 3,
+ "density": "comfortable",
+ "displayMode": "always_visible",
+ "floating": false,
+ "fontScale": 1,
+ "frameRadius": 8,
+ "frameThickness": 4,
+ "hideOnOverview": true,
+ "marginHorizontal": 4,
+ "marginVertical": 4,
+ "middleClickAction": "none",
+ "middleClickCommand": "",
+ "middleClickFollowMouse": false,
+ "monitors": [
+ ],
+ "mouseWheelAction": "none",
+ "mouseWheelWrap": true,
+ "outerCorners": false,
+ "position": "top",
+ "reverseScroll": false,
+ "rightClickAction": "controlCenter",
+ "rightClickCommand": "",
+ "rightClickFollowMouse": true,
+ "screenOverrides": [
+ ],
+ "showCapsule": true,
+ "showOnWorkspaceSwitch": true,
+ "showOutline": true,
+ "useSeparateOpacity": true,
+ "widgetSpacing": 6,
+ "widgets": {
+ "center": [
+ {
+ "clockColor": "none",
+ "customFont": "",
+ "formatHorizontal": "HH:mm:ss t – dddd, d MMMM yyyy",
+ "formatVertical": "HH mm - dd MM",
+ "id": "Clock",
+ "tooltipFormat": "HH:mm ddd, MMM dd",
+ "useCustomFont": false
+ }
+ ],
+ "left": [
+ {
+ "characterCount": 2,
+ "colorizeIcons": false,
+ "emptyColor": "secondary",
+ "enableScrollWheel": true,
+ "focusedColor": "primary",
+ "followFocusedScreen": false,
+ "fontWeight": "bold",
+ "groupedBorderOpacity": 1,
+ "hideUnoccupied": false,
+ "iconScale": 0.8,
+ "id": "Workspace",
+ "labelMode": "index",
+ "occupiedColor": "secondary",
+ "pillSize": 0.6,
+ "showApplications": false,
+ "showBadge": true,
+ "showLabelsOnlyWhenOccupied": true,
+ "unfocusedIconsOpacity": 1
+ },
+ {
+ "colorizeIcons": false,
+ "hideMode": "hidden",
+ "id": "ActiveWindow",
+ "maxWidth": 1000,
+ "scrollingMode": "always",
+ "showIcon": false,
+ "textColor": "none",
+ "useFixedWidth": false
+ }
+ ],
+ "right": [
+ {
+ "compactMode": false,
+ "hideMode": "hidden",
+ "hideWhenIdle": false,
+ "id": "MediaMini",
+ "maxWidth": 1000,
+ "panelShowAlbumArt": true,
+ "scrollingMode": "hover",
+ "showAlbumArt": true,
+ "showArtistFirst": true,
+ "showProgressRing": true,
+ "showVisualizer": true,
+ "textColor": "none",
+ "useFixedWidth": false,
+ "visualizerType": "linear"
+ },
+ {
+ "id": "Spacer",
+ "width": 20
+ },
+ {
+ "blacklist": [
+ ],
+ "chevronColor": "none",
+ "colorizeIcons": false,
+ "drawerEnabled": true,
+ "hidePassive": false,
+ "id": "Tray",
+ "pinned": [
+ ]
+ },
+ {
+ "compactMode": true,
+ "diskPath": "/",
+ "iconColor": "none",
+ "id": "SystemMonitor",
+ "showCpuCores": false,
+ "showCpuFreq": false,
+ "showCpuTemp": true,
+ "showCpuUsage": true,
+ "showDiskAvailable": false,
+ "showDiskUsage": false,
+ "showDiskUsageAsPercent": false,
+ "showGpuTemp": false,
+ "showLoadAverage": false,
+ "showMemoryAsPercent": false,
+ "showMemoryUsage": true,
+ "showNetworkStats": false,
+ "showSwapUsage": false,
+ "textColor": "none",
+ "useMonospaceFont": true,
+ "usePadding": false
+ },
+ {
+ "hideWhenZero": false,
+ "hideWhenZeroUnread": false,
+ "iconColor": "none",
+ "id": "NotificationHistory",
+ "showUnreadBadge": true,
+ "unreadBadgeColor": "primary"
+ },
+ {
+ "displayMode": "onhover",
+ "iconColor": "none",
+ "id": "Volume",
+ "middleClickCommand": "pwvucontrol || pavucontrol",
+ "textColor": "none"
+ },
+ {
+ "displayMode": "onhover",
+ "iconColor": "none",
+ "id": "Network",
+ "textColor": "none"
+ },
+ {
+ "displayMode": "onhover",
+ "iconColor": "none",
+ "id": "Bluetooth",
+ "textColor": "none"
+ },
+ {
+ "displayMode": "forceOpen",
+ "iconColor": "none",
+ "id": "KeyboardLayout",
+ "showIcon": false,
+ "textColor": "none"
+ },
+ {
+ "iconColor": "none",
+ "id": "SessionMenu"
+ },
+ {
+ "capsLockIcon": "letter-c",
+ "hideWhenOff": true,
+ "id": "LockKeys",
+ "numLockIcon": "letter-n",
+ "scrollLockIcon": "letter-s",
+ "showCapsLock": true,
+ "showNumLock": false,
+ "showScrollLock": true
+ }
+ ]
+ }
+ },
+ "brightness": {
+ "backlightDeviceMappings": [
+ ],
+ "brightnessStep": 5,
+ "enableDdcSupport": true,
+ "enforceMinimum": false
+ },
+ "calendar": {
+ "cards": [
+ {
+ "enabled": true,
+ "id": "calendar-header-card"
+ },
+ {
+ "enabled": true,
+ "id": "calendar-month-card"
+ },
+ {
+ "enabled": true,
+ "id": "weather-card"
+ }
+ ]
+ },
+ "colorSchemes": {
+ "darkMode": false,
+ "generationMethod": "tonal-spot",
+ "manualSunrise": "06:30",
+ "manualSunset": "18:30",
+ "monitorForColors": "",
+ "predefinedScheme": "Nord",
+ "schedulingMode": "location",
+ "useWallpaperColors": false
+ },
+ "controlCenter": {
+ "cards": [
+ {
+ "enabled": true,
+ "id": "profile-card"
+ },
+ {
+ "enabled": true,
+ "id": "shortcuts-card"
+ },
+ {
+ "enabled": true,
+ "id": "audio-card"
+ },
+ {
+ "enabled": false,
+ "id": "brightness-card"
+ },
+ {
+ "enabled": true,
+ "id": "weather-card"
+ },
+ {
+ "enabled": true,
+ "id": "media-sysmon-card"
+ }
+ ],
+ "diskPath": "/",
+ "position": "close_to_bar_button",
+ "shortcuts": {
+ "left": [
+ {
+ "id": "WallpaperSelector"
+ }
+ ],
+ "right": [
+ {
+ "id": "NightLight"
+ },
+ {
+ "id": "DarkMode"
+ }
+ ]
+ }
+ },
+ "desktopWidgets": {
+ "enabled": false,
+ "gridSnap": false,
+ "monitorWidgets": [
+ {
+ "name": "DP-1",
+ "widgets": [
+ ]
+ }
+ ],
+ "overviewEnabled": false
+ },
+ "dock": {
+ "animationSpeed": 1,
+ "backgroundOpacity": 1,
+ "colorizeIcons": true,
+ "deadOpacity": 0.6,
+ "displayMode": "always_visible",
+ "dockType": "floating",
+ "enabled": false,
+ "floatingRatio": 1,
+ "groupApps": true,
+ "groupClickAction": "cycle",
+ "groupContextMenuMode": "extended",
+ "groupIndicatorStyle": "dots",
+ "inactiveIndicators": true,
+ "indicatorColor": "primary",
+ "indicatorOpacity": 0.6,
+ "indicatorThickness": 3,
+ "launcherIconColor": "none",
+ "launcherPosition": "end",
+ "monitors": [
+ ],
+ "onlySameOutput": true,
+ "pinnedApps": [
+ ],
+ "pinnedStatic": true,
+ "position": "bottom",
+ "showDockIndicator": false,
+ "showLauncherIcon": true,
+ "sitOnFrame": false,
+ "size": 1
+ },
+ "general": {
+ "allowPanelsOnScreenWithoutBar": true,
+ "allowPasswordWithFprintd": false,
+ "animationDisabled": false,
+ "animationSpeed": 1,
+ "autoStartAuth": false,
+ "avatarImage": "/home/thomas/.face",
+ "boxRadiusRatio": 1,
+ "clockFormat": "hh\\nmm",
+ "clockStyle": "custom",
+ "compactLockScreen": false,
+ "dimmerOpacity": 0,
+ "enableBlurBehind": true,
+ "enableLockScreenCountdown": true,
+ "enableLockScreenMediaControls": false,
+ "enableShadows": true,
+ "forceBlackScreenCorners": false,
+ "iRadiusRatio": 1,
+ "keybinds": {
+ "keyDown": [
+ "Down"
+ ],
+ "keyEnter": [
+ "Return",
+ "Enter"
+ ],
+ "keyEscape": [
+ "Esc"
+ ],
+ "keyLeft": [
+ "Left"
+ ],
+ "keyRemove": [
+ "Del"
+ ],
+ "keyRight": [
+ "Right"
+ ],
+ "keyUp": [
+ "Up"
+ ]
+ },
+ "language": "",
+ "lockOnSuspend": true,
+ "lockScreenAnimations": false,
+ "lockScreenBlur": 0,
+ "lockScreenCountdownDuration": 10000,
+ "lockScreenMonitors": [
+ ],
+ "lockScreenTint": 0,
+ "passwordChars": false,
+ "radiusRatio": 1,
+ "reverseScroll": false,
+ "scaleRatio": 1,
+ "screenRadiusRatio": 1,
+ "shadowDirection": "bottom_right",
+ "shadowOffsetX": 2,
+ "shadowOffsetY": 3,
+ "showChangelogOnStartup": true,
+ "showHibernateOnLockScreen": false,
+ "showScreenCorners": false,
+ "showSessionButtonsOnLockScreen": true,
+ "telemetryEnabled": false
+ },
+ "hooks": {
+ "darkModeChange": "",
+ "enabled": false,
+ "performanceModeDisabled": "",
+ "performanceModeEnabled": "",
+ "screenLock": "",
+ "screenUnlock": "",
+ "session": "",
+ "startup": "",
+ "wallpaperChange": ""
+ },
+ "idle": {
+ "customCommands": "[]",
+ "enabled": false,
+ "fadeDuration": 5,
+ "lockCommand": "",
+ "lockTimeout": 660,
+ "resumeLockCommand": "",
+ "resumeScreenOffCommand": "",
+ "resumeSuspendCommand": "",
+ "screenOffCommand": "",
+ "screenOffTimeout": 600,
+ "suspendCommand": "",
+ "suspendTimeout": 1800
+ },
+ "location": {
+ "analogClockInCalendar": false,
+ "firstDayOfWeek": -1,
+ "hideWeatherCityName": false,
+ "hideWeatherTimezone": false,
+ "name": "Växjö",
+ "showCalendarEvents": true,
+ "showCalendarWeather": true,
+ "showWeekNumberInCalendar": true,
+ "use12hourFormat": false,
+ "useFahrenheit": false,
+ "weatherEnabled": true,
+ "weatherShowEffects": true
+ },
+ "network": {
+ "airplaneModeEnabled": false,
+ "bluetoothAutoConnect": true,
+ "bluetoothDetailsViewMode": "grid",
+ "bluetoothHideUnnamedDevices": false,
+ "bluetoothRssiPollIntervalMs": 60000,
+ "bluetoothRssiPollingEnabled": false,
+ "disableDiscoverability": false,
+ "networkPanelView": "wifi",
+ "wifiDetailsViewMode": "grid",
+ "wifiEnabled": false
+ },
+ "nightLight": {
+ "autoSchedule": true,
+ "dayTemp": "6500",
+ "enabled": true,
+ "forced": false,
+ "manualSunrise": "06:30",
+ "manualSunset": "18:30",
+ "nightTemp": "4002"
+ },
+ "noctaliaPerformance": {
+ "disableDesktopWidgets": true,
+ "disableWallpaper": true
+ },
+ "notifications": {
+ "backgroundOpacity": 0.7000000000000001,
+ "clearDismissed": true,
+ "criticalUrgencyDuration": 15,
+ "density": "default",
+ "enableBatteryToast": true,
+ "enableKeyboardLayoutToast": true,
+ "enableMarkdown": false,
+ "enableMediaToast": true,
+ "enabled": true,
+ "location": "top_right",
+ "lowUrgencyDuration": 3,
+ "monitors": [
+ ],
+ "normalUrgencyDuration": 8,
+ "overlayLayer": true,
+ "respectExpireTimeout": false,
+ "saveToHistory": {
+ "critical": true,
+ "low": true,
+ "normal": true
+ },
+ "sounds": {
+ "criticalSoundFile": "",
+ "enabled": false,
+ "excludedApps": "discord,firefox,chrome,chromium,edge",
+ "lowSoundFile": "",
+ "normalSoundFile": "",
+ "separateSounds": false,
+ "volume": 0.5
+ }
+ },
+ "osd": {
+ "autoHideMs": 2000,
+ "backgroundOpacity": 1,
+ "enabled": true,
+ "enabledTypes": [
+ 0,
+ 1,
+ 2
+ ],
+ "location": "top_right",
+ "monitors": [
+ ],
+ "overlayLayer": true
+ },
+ "plugins": {
+ "autoUpdate": true
+ },
+ "sessionMenu": {
+ "countdownDuration": 10000,
+ "enableCountdown": true,
+ "largeButtonsLayout": "single-row",
+ "largeButtonsStyle": true,
+ "position": "center",
+ "powerOptions": [
+ {
+ "action": "lock",
+ "command": "",
+ "countdownEnabled": true,
+ "enabled": true,
+ "keybind": "1"
+ },
+ {
+ "action": "suspend",
+ "command": "",
+ "countdownEnabled": true,
+ "enabled": true,
+ "keybind": "2"
+ },
+ {
+ "action": "hibernate",
+ "command": "",
+ "countdownEnabled": true,
+ "enabled": true,
+ "keybind": "3"
+ },
+ {
+ "action": "reboot",
+ "command": "",
+ "countdownEnabled": true,
+ "enabled": true,
+ "keybind": "4"
+ },
+ {
+ "action": "logout",
+ "command": "",
+ "countdownEnabled": true,
+ "enabled": true,
+ "keybind": "5"
+ },
+ {
+ "action": "shutdown",
+ "command": "",
+ "countdownEnabled": true,
+ "enabled": true,
+ "keybind": "6"
+ },
+ {
+ "action": "rebootToUefi",
+ "command": "",
+ "countdownEnabled": true,
+ "enabled": true,
+ "keybind": "7"
+ },
+ {
+ "action": "userspaceReboot",
+ "command": "",
+ "countdownEnabled": true,
+ "enabled": false,
+ "keybind": ""
+ }
+ ],
+ "showHeader": true,
+ "showKeybinds": true
+ },
+ "settingsVersion": 57,
+ "systemMonitor": {
+ "batteryCriticalThreshold": 5,
+ "batteryWarningThreshold": 20,
+ "cpuCriticalThreshold": 90,
+ "cpuWarningThreshold": 80,
+ "criticalColor": "#bf616a",
+ "diskAvailCriticalThreshold": 10,
+ "diskAvailWarningThreshold": 20,
+ "diskCriticalThreshold": 90,
+ "diskWarningThreshold": 80,
+ "enableDgpuMonitoring": false,
+ "externalMonitor": "resources || missioncenter || jdsystemmonitor || corestats || system-monitoring-center || gnome-system-monitor || plasma-systemmonitor || mate-system-monitor || ukui-system-monitor || deepin-system-monitor || pantheon-system-monitor",
+ "gpuCriticalThreshold": 90,
+ "gpuWarningThreshold": 80,
+ "memCriticalThreshold": 90,
+ "memWarningThreshold": 80,
+ "swapCriticalThreshold": 90,
+ "swapWarningThreshold": 80,
+ "tempCriticalThreshold": 90,
+ "tempWarningThreshold": 80,
+ "useCustomColors": false,
+ "warningColor": "#6fa9a8"
+ },
+ "templates": {
+ "activeTemplates": [
+ ],
+ "enableUserTheming": false
+ },
+ "ui": {
+ "boxBorderEnabled": false,
+ "fontDefault": "Sans Serif",
+ "fontDefaultScale": 1,
+ "fontFixed": "monospace",
+ "fontFixedScale": 1,
+ "panelBackgroundOpacity": 1,
+ "panelsAttachedToBar": true,
+ "settingsPanelMode": "attached",
+ "settingsPanelSideBarCardStyle": false,
+ "tooltipsEnabled": true
+ },
+ "wallpaper": {
+ "automationEnabled": false,
+ "directory": "/home/thomas/media/img/wall",
+ "enableMultiMonitorDirectories": false,
+ "enabled": true,
+ "favorites": [
+ ],
+ "fillColor": "#000000",
+ "fillMode": "crop",
+ "hideWallpaperFilenames": true,
+ "monitorDirectories": [
+ ],
+ "overviewBlur": 0.4,
+ "overviewEnabled": true,
+ "overviewTint": 0.6,
+ "panelPosition": "follow_bar",
+ "randomIntervalSec": 3600,
+ "setWallpaperOnAllMonitors": true,
+ "showHiddenFiles": false,
+ "skipStartupTransition": false,
+ "solidColor": "#1a1a2e",
+ "sortOrder": "name",
+ "transitionDuration": 1500,
+ "transitionEdgeSmoothness": 0.05,
+ "transitionType": "random",
+ "useSolidColor": false,
+ "useWallhaven": false,
+ "viewMode": "single",
+ "wallhavenApiKey": "",
+ "wallhavenCategories": "111",
+ "wallhavenOrder": "desc",
+ "wallhavenPurity": "100",
+ "wallhavenQuery": "",
+ "wallhavenRatios": "",
+ "wallhavenResolutionHeight": "",
+ "wallhavenResolutionMode": "atleast",
+ "wallhavenResolutionWidth": "",
+ "wallhavenSorting": "relevance",
+ "wallpaperChangeMode": "random"
+ }
+}