forked from Shinonome/dots-hyprland
pomodoro: add cycle indicator, make long break work, fix reset button
This commit is contained in:
@@ -11,18 +11,35 @@ Singleton {
|
|||||||
property string fileName: "states.json"
|
property string fileName: "states.json"
|
||||||
property string filePath: `${root.fileDir}/${root.fileName}`
|
property string filePath: `${root.fileDir}/${root.fileName}`
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: fileReloadTimer
|
||||||
|
interval: 100
|
||||||
|
repeat: false
|
||||||
|
onTriggered: {
|
||||||
|
persistentStatesFileView.reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: fileWriteTimer
|
||||||
|
interval: 100
|
||||||
|
repeat: false
|
||||||
|
onTriggered: {
|
||||||
|
persistentStatesFileView.writeAdapter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
|
id: persistentStatesFileView
|
||||||
path: root.filePath
|
path: root.filePath
|
||||||
|
|
||||||
watchChanges: true
|
watchChanges: true
|
||||||
onFileChanged: reload()
|
onFileChanged: fileReloadTimer.restart()
|
||||||
onAdapterUpdated: {
|
onAdapterUpdated: fileWriteTimer.restart()
|
||||||
writeAdapter()
|
|
||||||
}
|
|
||||||
onLoadFailed: error => {
|
onLoadFailed: error => {
|
||||||
console.log("Failed to load persistent states file:", error);
|
console.log("Failed to load persistent states file:", error);
|
||||||
if (error == FileViewError.FileNotFound) {
|
if (error == FileViewError.FileNotFound) {
|
||||||
writeAdapter();
|
fileWriteTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +67,7 @@ Singleton {
|
|||||||
property bool running: false
|
property bool running: false
|
||||||
property int start: 0
|
property int start: 0
|
||||||
property bool isBreak: false
|
property bool isBreak: false
|
||||||
|
property bool isLongBreak: false
|
||||||
property int cycle: 0
|
property int cycle: 0
|
||||||
}
|
}
|
||||||
property JsonObject stopwatch: JsonObject {
|
property JsonObject stopwatch: JsonObject {
|
||||||
|
|||||||
@@ -23,14 +23,10 @@ Item {
|
|||||||
CircularProgress {
|
CircularProgress {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
lineWidth: 8
|
lineWidth: 8
|
||||||
gapAngle: Math.PI / 14
|
|
||||||
value: {
|
value: {
|
||||||
let pomodoroTotalTime = Pomodoro.isBreak ? Pomodoro.breakTime : Pomodoro.focusTime;
|
return Pomodoro.pomodoroSecondsLeft / Pomodoro.pomodoroLapDuration;
|
||||||
return Pomodoro.pomodoroSecondsLeft / pomodoroTotalTime;
|
|
||||||
}
|
}
|
||||||
size: 200
|
size: 200
|
||||||
primaryColor: Appearance.m3colors.m3onSecondaryContainer
|
|
||||||
secondaryColor: Appearance.colors.colSecondaryContainer
|
|
||||||
enableAnimation: true
|
enableAnimation: true
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
@@ -49,11 +45,30 @@ Item {
|
|||||||
}
|
}
|
||||||
StyledText {
|
StyledText {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
text: Pomodoro.isBreak ? Translation.tr("Break") : Translation.tr("Focus")
|
text: Pomodoro.isLongBreak ? Translation.tr("Long break") : Pomodoro.isBreak ? Translation.tr("Break") : Translation.tr("Focus")
|
||||||
font.pixelSize: Appearance.font.pixelSize.normal
|
font.pixelSize: Appearance.font.pixelSize.normal
|
||||||
color: Appearance.colors.colSubtext
|
color: Appearance.colors.colSubtext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
color: Appearance.colors.colLayer2
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
implicitWidth: 36
|
||||||
|
implicitHeight: implicitWidth
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: cycleText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: Appearance.colors.colOnLayer2
|
||||||
|
text: Pomodoro.pomodoroCycle + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Start/Stop and Reset buttons
|
// The Start/Stop and Reset buttons
|
||||||
@@ -81,7 +96,7 @@ Item {
|
|||||||
implicitWidth: 90
|
implicitWidth: 90
|
||||||
|
|
||||||
onClicked: Pomodoro.resetPomodoro()
|
onClicked: Pomodoro.resetPomodoro()
|
||||||
enabled: (Pomodoro.pomodoroSecondsLeft < (Pomodoro.isBreak ? Pomodoro.breakTime : Pomodoro.focusTime))
|
enabled: (Pomodoro.pomodoroSecondsLeft < Pomodoro.pomodoroLapDuration) || Pomodoro.pomodoroCycle > 0 || Pomodoro.isBreak
|
||||||
|
|
||||||
font.pixelSize: Appearance.font.pixelSize.larger
|
font.pixelSize: Appearance.font.pixelSize.larger
|
||||||
colBackground: Appearance.colors.colErrorContainer
|
colBackground: Appearance.colors.colErrorContainer
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ Singleton {
|
|||||||
|
|
||||||
property bool isPomodoroRunning: Persistent.states.timer.pomodoro.running
|
property bool isPomodoroRunning: Persistent.states.timer.pomodoro.running
|
||||||
property bool isBreak: Persistent.states.timer.pomodoro.isBreak
|
property bool isBreak: Persistent.states.timer.pomodoro.isBreak
|
||||||
property bool isPomodoroReset: !isPomodoroRunning
|
property bool isLongBreak: Persistent.states.timer.pomodoro.isLongBreak
|
||||||
property int timeLeft: focusTime
|
property bool isPomodoroLongBreak: Persistent.states.timer.pomodoro.isLongBreak
|
||||||
|
property int pomodoroLapDuration: isBreak ? (isLongBreak ? longBreakTime : breakTime) : focusTime
|
||||||
property int pomodoroSecondsLeft: focusTime
|
property int pomodoroSecondsLeft: focusTime
|
||||||
property int pomodoroStart: Persistent.states.timer.pomodoro.start
|
property int pomodoroCycle: Persistent.states.timer.pomodoro.cycle
|
||||||
property int pomodoroCycle: 1
|
|
||||||
|
|
||||||
property bool isStopwatchRunning: Persistent.states.timer.stopwatch.running
|
property bool isStopwatchRunning: Persistent.states.timer.stopwatch.running
|
||||||
property int stopwatchTime: 0
|
property int stopwatchTime: 0
|
||||||
@@ -49,30 +49,34 @@ Singleton {
|
|||||||
// Pomodoro
|
// Pomodoro
|
||||||
function refreshPomodoro() {
|
function refreshPomodoro() {
|
||||||
// Work <-> break ?
|
// Work <-> break ?
|
||||||
if (getCurrentTimeInSeconds() >= pomodoroStart + timeLeft) {
|
if (getCurrentTimeInSeconds() >= Persistent.states.timer.pomodoro.start + pomodoroLapDuration) {
|
||||||
Persistent.states.timer.pomodoro.isBreak = !isBreak
|
// Reset counts
|
||||||
Persistent.states.timer.pomodoro.start += timeLeft
|
const currentTimeInSeconds = getCurrentTimeInSeconds()
|
||||||
timeLeft = isBreak ? breakTime : focusTime
|
Persistent.states.timer.pomodoro.isBreak = !Persistent.states.timer.pomodoro.isBreak
|
||||||
|
Persistent.states.timer.pomodoro.isLongBreak = Persistent.states.timer.pomodoro.isBreak && (pomodoroCycle + 1 == cyclesBeforeLongBreak)
|
||||||
|
Persistent.states.timer.pomodoro.start = currentTimeInSeconds
|
||||||
|
|
||||||
|
// Send notification
|
||||||
let notificationTitle, notificationMessage
|
let notificationTitle, notificationMessage
|
||||||
|
if (Persistent.states.timer.pomodoro.isBreak && pomodoroCycle % cyclesBeforeLongBreak === 0) { // isPomodoroLongBreak
|
||||||
if (isBreak && pomodoroCycle % cyclesBeforeLongBreak === 0) { // isPomodoroLongBreak
|
|
||||||
notificationMessage = Translation.tr(`Relax for %1 minutes`).arg(Math.floor(longBreakTime / 60))
|
notificationMessage = Translation.tr(`Relax for %1 minutes`).arg(Math.floor(longBreakTime / 60))
|
||||||
} else if (isBreak) {
|
} else if (Persistent.states.timer.pomodoro.isBreak) {
|
||||||
notificationMessage = Translation.tr(`Relax for %1 minutes`).arg(Math.floor(breakTime / 60))
|
notificationMessage = Translation.tr(`Relax for %1 minutes`).arg(Math.floor(breakTime / 60))
|
||||||
} else {
|
} else {
|
||||||
notificationMessage = Translation.tr(`Focus for %1 minutes`).arg(Math.floor(focusTime / 60))
|
notificationMessage = Translation.tr(`Focus for %1 minutes`).arg(Math.floor(focusTime / 60))
|
||||||
pomodoroCycle += 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Quickshell.execDetached(["notify-send", "Pomodoro", notificationMessage, "-a", "Shell"])
|
Quickshell.execDetached(["notify-send", "Pomodoro", notificationMessage, "-a", "Shell"])
|
||||||
if (alertSound) { // Play sound only if alertSound is explicitly specified
|
if (alertSound) { // Play sound only if alertSound is explicitly specified
|
||||||
Quickshell.execDetached(["ffplay", "-nodisp", "-autoexit", alertSound])
|
Quickshell.execDetached(["ffplay", "-nodisp", "-autoexit", alertSound])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isBreak) {
|
||||||
|
Persistent.states.timer.pomodoro.cycle = (Persistent.states.timer.pomodoro.cycle + 1) % root.cyclesBeforeLongBreak;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A nice abstraction for resume logic by updating the TimeStarted
|
pomodoroSecondsLeft = pomodoroLapDuration - (getCurrentTimeInSeconds() - Persistent.states.timer.pomodoro.start)
|
||||||
pomodoroSecondsLeft = (pomodoroStart + timeLeft) - getCurrentTimeInSeconds()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
@@ -84,21 +88,17 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function togglePomodoro() {
|
function togglePomodoro() {
|
||||||
isPomodoroReset = false
|
|
||||||
Persistent.states.timer.pomodoro.running = !isPomodoroRunning
|
Persistent.states.timer.pomodoro.running = !isPomodoroRunning
|
||||||
if (Persistent.states.timer.pomodoro.running) { // Start/Resume
|
if (Persistent.states.timer.pomodoro.running) { // Start/Resume
|
||||||
Persistent.states.timer.pomodoro.start = getCurrentTimeInSeconds() + pomodoroSecondsLeft - (isBreak ? breakTime : focusTime)
|
Persistent.states.timer.pomodoro.start = getCurrentTimeInSeconds() + pomodoroSecondsLeft - pomodoroLapDuration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetPomodoro() {
|
function resetPomodoro() {
|
||||||
Persistent.states.timer.pomodoro.running = false
|
Persistent.states.timer.pomodoro.running = false
|
||||||
Persistent.states.timer.pomodoro.isBreak = false
|
Persistent.states.timer.pomodoro.isBreak = false
|
||||||
isPomodoroReset = true
|
|
||||||
timeLeft = focusTime
|
|
||||||
Persistent.states.timer.pomodoro.start = getCurrentTimeInSeconds()
|
Persistent.states.timer.pomodoro.start = getCurrentTimeInSeconds()
|
||||||
pomodoroSecondsLeft = 0
|
Persistent.states.timer.pomodoro.cycle = 0
|
||||||
Persistent.states.timer.pomodoro.cycle = 1
|
|
||||||
refreshPomodoro()
|
refreshPomodoro()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user