pomodoro: make pause/resume less weird

This commit is contained in:
end-4
2025-08-09 21:36:28 +07:00
parent 5bf80dae4e
commit 4ca15a1fc3
4 changed files with 80 additions and 175 deletions
@@ -256,9 +256,9 @@ Singleton {
property JsonObject pomodoro: JsonObject { property JsonObject pomodoro: JsonObject {
property string alertSound: "" property string alertSound: ""
property int breakTime: 300 property int breakTime: 300
property int cycle: 4 property int cyclesBeforeLongBreak: 4
property int focus: 1500 property int focus: 1500
property int longBreak: 1200 property int longBreak: 900
} }
} }
@@ -50,6 +50,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 int cycle: 0
} }
property JsonObject stopwatch: JsonObject { property JsonObject stopwatch: JsonObject {
property bool running: false property bool running: false
@@ -9,187 +9,92 @@ import QtQuick.Layouts
import Quickshell import Quickshell
Item { Item {
id: root
implicitHeight: contentColumn.implicitHeight
implicitWidth: contentColumn.implicitWidth
ColumnLayout { ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter id: contentColumn
spacing: 20 anchors.fill: parent
spacing: 0
RowLayout { // The Pomodoro timer circle
spacing: 40 CircularProgress {
// The Pomodoro timer circle Layout.alignment: Qt.AlignHCenter
CircularProgress { lineWidth: 8
Layout.alignment: Qt.AlignHCenter gapAngle: Math.PI / 14
lineWidth: 7 value: {
gapAngle: Math.PI / 14 let pomodoroTotalTime = Pomodoro.isBreak ? Pomodoro.breakTime : Pomodoro.focusTime;
value: { return Pomodoro.pomodoroSecondsLeft / pomodoroTotalTime;
let pomodoroTotalTime = Pomodoro.isBreak ? Pomodoro.breakTime : Pomodoro.focusTime
return Pomodoro.pomodoroSecondsLeft / pomodoroTotalTime
}
size: 125
primaryColor: Appearance.m3colors.m3onSecondaryContainer
secondaryColor: Appearance.colors.colSecondaryContainer
enableAnimation: true
ColumnLayout {
anchors.centerIn: parent
spacing: 0
StyledText {
Layout.alignment: Qt.AlignHCenter
text: {
let minutes = Math.floor(Pomodoro.pomodoroSecondsLeft / 60).toString().padStart(2, '0')
let seconds = Math.floor(Pomodoro.pomodoroSecondsLeft % 60).toString().padStart(2, '0')
return `${minutes}:${seconds}`
}
font.pixelSize: Appearance.font.pixelSize.hugeass + 4
color: Appearance.m3colors.m3onSurface
}
StyledText {
Layout.alignment: Qt.AlignHCenter
text: Pomodoro.isBreak ? Translation.tr("Break") : Translation.tr("Focus")
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.m3colors.m3onSurface
}
}
} }
size: 200
primaryColor: Appearance.m3colors.m3onSecondaryContainer
secondaryColor: Appearance.colors.colSecondaryContainer
enableAnimation: true
// The Start/Stop and Reset buttons
ColumnLayout { ColumnLayout {
Layout.alignment: Qt.AlignHCenter anchors.centerIn: parent
spacing: 10 spacing: 0
RippleButton { StyledText {
contentItem: StyledText { Layout.alignment: Qt.AlignHCenter
anchors.centerIn: parent text: {
horizontalAlignment: Text.AlignHCenter let minutes = Math.floor(Pomodoro.pomodoroSecondsLeft / 60).toString().padStart(2, '0');
text: Pomodoro.isPomodoroRunning ? Translation.tr("Pause") : (Pomodoro.pomodoroSecondsLeft === Pomodoro.focusTime) ? Translation.tr("Start") : Translation.tr("Resume") let seconds = Math.floor(Pomodoro.pomodoroSecondsLeft % 60).toString().padStart(2, '0');
color: Pomodoro.isPomodoroRunning ? Appearance.colors.colOnSecondaryContainer : Appearance.colors.colOnPrimary return `${minutes}:${seconds}`;
} }
implicitHeight: 35 font.pixelSize: 40
implicitWidth: 90 color: Appearance.m3colors.m3onSurface
font.pixelSize: Appearance.font.pixelSize.larger
onClicked: Pomodoro.togglePomodoro()
colBackground: Pomodoro.isPomodoroRunning ? Appearance.colors.colSecondaryContainer : Appearance.colors.colPrimary
colBackgroundHover: Pomodoro.isPomodoroRunning ? Appearance.colors.colSecondaryContainer : Appearance.colors.colPrimary
} }
StyledText {
RippleButton { Layout.alignment: Qt.AlignHCenter
implicitHeight: 35 text: Pomodoro.isBreak ? Translation.tr("Break") : Translation.tr("Focus")
implicitWidth: 90 font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colSubtext
onClicked: Pomodoro.resetPomodoro()
enabled: (Pomodoro.pomodoroSecondsLeft < Pomodoro.focusTime)
font.pixelSize: Appearance.font.pixelSize.larger
colBackground: Appearance.colors.colErrorContainer
colBackgroundHover: Appearance.colors.colErrorContainerHover
colRipple: Appearance.colors.colErrorContainerActive
contentItem: StyledText {
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
text: Translation.tr("Reset")
color: Appearance.colors.colOnErrorContainer
}
} }
} }
} }
// The SpinBoxes for adjusting duration // The Start/Stop and Reset buttons
// GridLayout { RowLayout {
// Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
// columns: 2 spacing: 10
// uniformCellWidths: true
// columnSpacing: 20
// rowSpacing: 4
// StyledText { RippleButton {
// Layout.alignment: Qt.AlignHCenter contentItem: StyledText {
// text: Translation.tr("Focus") anchors.centerIn: parent
// } horizontalAlignment: Text.AlignHCenter
text: Pomodoro.isPomodoroRunning ? Translation.tr("Pause") : (Pomodoro.pomodoroSecondsLeft === Pomodoro.focusTime) ? Translation.tr("Start") : Translation.tr("Resume")
color: Pomodoro.isPomodoroRunning ? Appearance.colors.colOnSecondaryContainer : Appearance.colors.colOnPrimary
}
implicitHeight: 35
implicitWidth: 90
font.pixelSize: Appearance.font.pixelSize.larger
onClicked: Pomodoro.togglePomodoro()
colBackground: Pomodoro.isPomodoroRunning ? Appearance.colors.colSecondaryContainer : Appearance.colors.colPrimary
colBackgroundHover: Pomodoro.isPomodoroRunning ? Appearance.colors.colSecondaryContainer : Appearance.colors.colPrimary
}
// StyledText { RippleButton {
// Layout.alignment: Qt.AlignHCenter implicitHeight: 35
// text: Translation.tr("Break") implicitWidth: 90
// }
// ConfigSpinBox { onClicked: Pomodoro.resetPomodoro()
// id: focusSpinBox enabled: (Pomodoro.pomodoroSecondsLeft < (Pomodoro.isBreak ? Pomodoro.breakTime : Pomodoro.focusTime))
// spacing: 0
// Layout.leftMargin: 0
// Layout.rightMargin: 0
// from: 0
// to: 120
// Connections {
// target: Config
// function onReadyChanged() {
// focusSpinBox.valueChanged()
// }
// }
// value: {
// console.log("New focus time: " + (Config.options.time.pomodoro.focus / 60))
// return Config.options.time.pomodoro.focus / 60
// }
// onValueChanged: {
// console.log("New focus time is " + value + " minutes, Config is ready:", Config.ready)
// if (!Config.ready) return;
// console.log("Setting focus time to " + value + " minutes")
// Config.options.time.pomodoro.focus = value * 60
// if (Pomodoro.isPomodoroReset) { // Special case for Pomodoro in Reset state
// Pomodoro.pomodoroSecondsLeft = Pomodoro.focusTime
// Pomodoro.timeLeft = Pomodoro.focusTime
// }
// }
// }
// ConfigSpinBox { font.pixelSize: Appearance.font.pixelSize.larger
// id: breakSpinBox colBackground: Appearance.colors.colErrorContainer
// value: Config.options.time.pomodoro.breakTime / 60 colBackgroundHover: Appearance.colors.colErrorContainerHover
// spacing: 0 colRipple: Appearance.colors.colErrorContainerActive
// from: 0
// to: 120
// Layout.leftMargin: 0
// Layout.rightMargin: 0
// onValueChanged: {
// Config.options.time.pomodoro.breakTime = value * 60
// }
// }
// StyledText { contentItem: StyledText {
// Layout.topMargin: 6 anchors.centerIn: parent
// Layout.alignment: Qt.AlignHCenter horizontalAlignment: Text.AlignHCenter
// text: Translation.tr("Cycle") text: Translation.tr("Reset")
// } color: Appearance.colors.colOnErrorContainer
// StyledText { }
// Layout.topMargin: 6 }
// Layout.alignment: Qt.AlignHCenter }
// text: Translation.tr("Long break")
// }
// ConfigSpinBox {
// id: cycleSpinBox
// value: Config.options.time.pomodoro.cycle
// spacing: 0
// from: 1
// to: 20
// Layout.leftMargin: 0
// Layout.rightMargin: 0
// onValueChanged: {
// Config.options.time.pomodoro.cycle = value
// }
// }
// ConfigSpinBox {
// id: longBreakSpinBox
// spacing: 0
// Layout.leftMargin: 0
// Layout.rightMargin: 0
// value: Config.options.time.pomodoro.longBreak / 60
// from: 0
// to: 120
// onValueChanged: {
// Config.options.time.pomodoro.longBreak = value * 60
// }
// }
// }
} }
} }
+6 -7
View File
@@ -17,7 +17,7 @@ Singleton {
property int focusTime: Config.options.time.pomodoro.focus property int focusTime: Config.options.time.pomodoro.focus
property int breakTime: Config.options.time.pomodoro.breakTime property int breakTime: Config.options.time.pomodoro.breakTime
property int longBreakTime: Config.options.time.pomodoro.longBreak property int longBreakTime: Config.options.time.pomodoro.longBreak
property int longBreakCycle: Config.options.time.pomodoro.cycle property int cyclesBeforeLongBreak: Config.options.time.pomodoro.cyclesBeforeLongBreak
property string alertSound: Config.options.time.pomodoro.alertSound property string alertSound: Config.options.time.pomodoro.alertSound
property bool isPomodoroRunning: Persistent.states.timer.pomodoro.running property bool isPomodoroRunning: Persistent.states.timer.pomodoro.running
@@ -56,7 +56,7 @@ Singleton {
let notificationTitle, notificationMessage let notificationTitle, notificationMessage
if (isBreak && pomodoroCycle % longBreakCycle === 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 (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))
@@ -86,10 +86,8 @@ Singleton {
function togglePomodoro() { function togglePomodoro() {
isPomodoroReset = false isPomodoroReset = false
Persistent.states.timer.pomodoro.running = !isPomodoroRunning Persistent.states.timer.pomodoro.running = !isPomodoroRunning
if (isPomodoroRunning) { // Pressed Start button if (Persistent.states.timer.pomodoro.running) { // Start/Resume
Persistent.states.timer.pomodoro.start = getCurrentTimeInSeconds() Persistent.states.timer.pomodoro.start = getCurrentTimeInSeconds() + pomodoroSecondsLeft - (isBreak ? breakTime : focusTime)
} else { // Pressed Stop button
timeLeft -= (getCurrentTimeInSeconds() - pomodoroStart)
} }
} }
@@ -99,7 +97,8 @@ Singleton {
isPomodoroReset = true isPomodoroReset = true
timeLeft = focusTime timeLeft = focusTime
Persistent.states.timer.pomodoro.start = getCurrentTimeInSeconds() Persistent.states.timer.pomodoro.start = getCurrentTimeInSeconds()
pomodoroCycle = 1 pomodoroSecondsLeft = 0
Persistent.states.timer.pomodoro.cycle = 1
refreshPomodoro() refreshPomodoro()
} }