Watch
1
0
Fork
You've already forked souveraine
0
souveraine/surfaces/quickshell/modules/ii/sidebarRight/pomodoro/PomodoroTimer.qml
Fimeg b8e76c4e9e shell: own the right sidebar, move garden into the drawer
Garden was welded onto the notification list in CenterWidgetGroup —
always on, unrelated, stealing space from notifications that said
"Nothing". Moved it into the BottomWidgetGroup drawer as a fifth tab
alongside Calendar, To Do, Pomodoro, and Stopwatch.

CenterWidgetGroup is now just the notification list. Lens events
(note_created, synced) emit through notify-send so they land in the
notification system properly.

Forked calendar, todo, pomodoro, notifications out of ii-base into
our tree — the right sidebar no longer borrows any widget files from
ii. Toggle dialogs (bluetooth, wifi, nightLight) still symlinked as
infrastructure.
2026-08-21 15:42:37 -04:00

187 lines
7.3 KiB
QML

import qs.services
import qs.modules.common
import qs.modules.common.widgets
import Qt5Compat.GraphicalEffects
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
Item {
id: root
implicitHeight: contentColumn.implicitHeight
implicitWidth: contentColumn.implicitWidth
readonly property color stateColor: TimerService.pomodoroBreak ? Appearance.colors.colTertiaryContainer : Appearance.colors.colSecondaryContainer
readonly property color stateTextColor: TimerService.pomodoroBreak ? Appearance.colors.colOnTertiaryContainer : Appearance.colors.colOnSecondaryContainer
readonly property string stateLabel: TimerService.pomodoroLongBreak ? Translation.tr("Long break") : TimerService.pomodoroBreak ? Translation.tr("Break") : Translation.tr("Focus")
readonly property int cyclePosition: TimerService.pomodoroCycle + 1
ColumnLayout {
id: contentColumn
anchors.fill: parent
spacing: 10
// The Pomodoro timer circle
CircularProgress {
Layout.alignment: Qt.AlignHCenter
lineWidth: 10
value: {
return TimerService.pomodoroSecondsLeft / TimerService.pomodoroLapDuration;
}
implicitSize: 200
colPrimary: root.stateTextColor
colSecondary: root.stateColor
enableAnimation: true
ColumnLayout {
anchors.centerIn: parent
spacing: 2
StyledText {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: 150
horizontalAlignment: Text.AlignHCenter
text: {
let minutes = Math.floor(TimerService.pomodoroSecondsLeft / 60).toString().padStart(2, '0');
let seconds = Math.floor(TimerService.pomodoroSecondsLeft % 60).toString().padStart(2, '0');
return `${minutes}:${seconds}`;
}
font.family: Appearance.font.family.monospace
font.pixelSize: 40
font.weight: Font.DemiBold
color: Appearance.m3colors.m3onSurface
}
StyledText {
Layout.alignment: Qt.AlignHCenter
text: root.stateLabel
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colSubtext
}
}
Rectangle {
radius: Appearance.rounding.full
color: root.stateColor
anchors {
right: parent.right
bottom: parent.bottom
}
implicitWidth: 58
implicitHeight: 36
RowLayout {
anchors.centerIn: parent
spacing: 3
MaterialSymbol {
text: "repeat"
iconSize: 14
color: root.stateTextColor
}
StyledText {
id: cycleText
font.family: Appearance.font.family.monospace
font.weight: Font.DemiBold
color: root.stateTextColor
text: `${root.cyclePosition}/${TimerService.cyclesBeforeLongBreak}`
}
}
}
}
Rectangle {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: 210
Layout.preferredHeight: 30
radius: Appearance.rounding.full
color: Appearance.colors.colLayer2
RowLayout {
anchors.centerIn: parent
spacing: 6
MaterialSymbol {
text: TimerService.pomodoroBreak ? "coffee" : "search_activity"
iconSize: Appearance.font.pixelSize.larger
color: root.stateTextColor
}
StyledText {
text: root.stateLabel
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colOnLayer2
}
}
}
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 5
Repeater {
model: TimerService.cyclesBeforeLongBreak
Rectangle {
required property int index
implicitWidth: index === TimerService.pomodoroCycle ? 18 : 8
implicitHeight: 8
radius: Appearance.rounding.full
color: index <= TimerService.pomodoroCycle ? root.stateTextColor : Appearance.colors.colLayer2
Behavior on implicitWidth {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
}
}
}
// The Start/Stop and Reset buttons
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 10
RippleButton {
buttonRadius: Appearance.rounding.full
contentItem: StyledText {
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
text: TimerService.pomodoroRunning ? Translation.tr("Pause") : (TimerService.pomodoroSecondsLeft === TimerService.focusTime) ? Translation.tr("Start") : Translation.tr("Resume")
color: TimerService.pomodoroRunning ? Appearance.colors.colOnSecondaryContainer : Appearance.colors.colOnPrimary
}
implicitHeight: 38
implicitWidth: 96
font.pixelSize: Appearance.font.pixelSize.larger
onClicked: TimerService.togglePomodoro()
colBackground: TimerService.pomodoroRunning ? Appearance.colors.colSecondaryContainer : Appearance.colors.colPrimary
colBackgroundHover: TimerService.pomodoroRunning ? Appearance.colors.colSecondaryContainer : Appearance.colors.colPrimary
}
RippleButton {
buttonRadius: Appearance.rounding.full
implicitHeight: 38
implicitWidth: 96
onClicked: TimerService.resetPomodoro()
enabled: (TimerService.pomodoroSecondsLeft < TimerService.pomodoroLapDuration) || TimerService.pomodoroCycle > 0 || TimerService.pomodoroBreak
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
}
}
}
}
}