Calendar: add timer

LocationTab: rework calendar settings
SoundService: add simple service to play & loop sounds
This commit is contained in:
Ly-sec
2025-11-26 19:18:30 +01:00
parent f611e3a2c0
commit 309648d6d6
19 changed files with 1127 additions and 164 deletions
+22
View File
@@ -252,6 +252,28 @@ Singleton {
property int firstDayOfWeek: -1 // -1 = auto (use locale), 0 = Sunday, 1 = Monday, 6 = Saturday
}
// calendar
property JsonObject calendar: JsonObject {
property list<var> cards: [
{
"id": "banner-card",
"enabled": true
},
{
"id": "calendar-card",
"enabled": true
},
{
"id": "timer-card",
"enabled": true
},
{
"id": "weather-card",
"enabled": true
}
]
}
// screen recorder
property JsonObject screenRecorder: JsonObject {
property string directory: ""
+84
View File
@@ -3,6 +3,7 @@ import QtQuick
import Quickshell
import qs.Commons
import qs.Services.System
Singleton {
id: root
@@ -15,6 +16,16 @@ Singleton {
return Math.floor(root.now / 1000);
}
// Timer state (for countdown/stopwatch)
property bool timerRunning: false
property bool timerStopwatchMode: false
property int timerRemainingSeconds: 0
property int timerTotalSeconds: 0
property int timerElapsedSeconds: 0
property bool timerSoundPlaying: false
property int timerStartTimestamp: 0 // Unix timestamp when timer was started
property int timerPausedAt: 0 // Value when paused (for resuming)
Timer {
id: updateTimer
interval: 1000
@@ -25,6 +36,20 @@ Singleton {
var newTime = new Date();
root.now = newTime;
// Update timer if running
if (root.timerRunning && root.timerStartTimestamp > 0) {
const elapsedSinceStart = root.timestamp - root.timerStartTimestamp;
if (root.timerStopwatchMode) {
root.timerElapsedSeconds = root.timerPausedAt + elapsedSinceStart;
} else {
root.timerRemainingSeconds = root.timerTotalSeconds - elapsedSinceStart;
if (root.timerRemainingSeconds <= 0) {
root.timerOnFinished();
}
}
}
// Adjust next interval to sync with the start of the next second
var msIntoSecond = newTime.getMilliseconds();
if (msIntoSecond > 100) {
@@ -119,4 +144,63 @@ Singleton {
"diff": Math.floor(diff / 86400000)
});
}
// Timer functions
function timerStart() {
if (root.timerStopwatchMode) {
root.timerRunning = true;
root.timerStartTimestamp = root.timestamp;
root.timerPausedAt = root.timerElapsedSeconds;
} else {
if (root.timerRemainingSeconds <= 0) {
return;
}
root.timerRunning = true;
root.timerTotalSeconds = root.timerRemainingSeconds;
root.timerStartTimestamp = root.timestamp;
root.timerPausedAt = 0;
}
}
function timerPause() {
if (root.timerRunning) {
// Save current state
if (root.timerStopwatchMode) {
root.timerPausedAt = root.timerElapsedSeconds;
} else {
root.timerPausedAt = root.timerRemainingSeconds;
}
}
root.timerRunning = false;
root.timerStartTimestamp = 0;
// Stop any repeating notification sound when pausing
SoundService.stopSound("alarm-beep.wav");
root.timerSoundPlaying = false;
}
function timerReset() {
root.timerRunning = false;
root.timerStartTimestamp = 0;
if (root.timerStopwatchMode) {
root.timerElapsedSeconds = 0;
root.timerPausedAt = 0;
} else {
root.timerRemainingSeconds = 0;
root.timerTotalSeconds = 0;
root.timerPausedAt = 0;
}
// Stop any repeating notification sound
SoundService.stopSound("alarm-beep.wav");
root.timerSoundPlaying = false;
}
function timerOnFinished() {
root.timerRunning = false;
root.timerRemainingSeconds = 0;
// Play notification sound with repeat
root.timerSoundPlaying = true;
SoundService.playSound("alarm-beep.wav", {
repeat: true
});
}
}