From 67e50aaa14004bfb56a55e8673cf7148c6ff3e4d Mon Sep 17 00:00:00 2001 From: Benjamin Palko Date: Tue, 26 Aug 2025 23:22:25 -0400 Subject: [PATCH] pomodoroooooo --- constants/Icons.qml | 3 + modules/Shell.qml | 2 + modules/Shortcuts.qml | 6 ++ modules/pomodoro/Pomodoro.qml | 119 ++++++++++++++++++++++++++++++++++ services/Pomodoro.qml | 62 ++++++++++++++++++ services/Visibility.qml | 1 + widgets/Circle.qml | 51 +++++++++++++++ 7 files changed, 244 insertions(+) create mode 100644 modules/pomodoro/Pomodoro.qml create mode 100644 services/Pomodoro.qml create mode 100644 widgets/Circle.qml diff --git a/constants/Icons.qml b/constants/Icons.qml index 2fee3c8..3311396 100644 --- a/constants/Icons.qml +++ b/constants/Icons.qml @@ -17,7 +17,10 @@ Singleton { property string gpu: "\u{E66f}" property string hardDrive: "\u{E0f1}" property string memoryStick: "\u{E44a}" + property string play: "\u{E140}" property string search: "\u{E155}" + property string stop: "\u{E132}" + property string square: "\u{E16B}" property string wifiOff: "\u{E1af}" property string wifiLow: "\u{E5fd}" property string wifiHigh: "\u{E5fc}" diff --git a/modules/Shell.qml b/modules/Shell.qml index 875a431..d38c685 100644 --- a/modules/Shell.qml +++ b/modules/Shell.qml @@ -1,5 +1,6 @@ import "bar" import "launcher" +import "pomodoro" import "powermenu" import Quickshell import Quickshell.Wayland @@ -16,6 +17,7 @@ Variants { Bar {} Launcher {} + Pomodoro {} PowerMenu {} } } diff --git a/modules/Shortcuts.qml b/modules/Shortcuts.qml index 430f3ea..2c47882 100644 --- a/modules/Shortcuts.qml +++ b/modules/Shortcuts.qml @@ -11,6 +11,12 @@ Scope { onPressed: Visibility.launcher = !Visibility.launcher } + LuxShortcut { + name: 'pomodoro' + description: 'Open the Pomodoro' + onPressed: Visibility.pomodoro = !Visibility.pomodoro + } + LuxShortcut { name: 'power-menu' description: 'Open the Power Menu' diff --git a/modules/pomodoro/Pomodoro.qml b/modules/pomodoro/Pomodoro.qml new file mode 100644 index 0000000..0a46cb1 --- /dev/null +++ b/modules/pomodoro/Pomodoro.qml @@ -0,0 +1,119 @@ +pragma ComponentBehavior: Bound + +import qs.config +import qs.constants +import qs.services +import qs.widgets +import Quickshell.Hyprland +import Quickshell.Wayland +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +StyledWindow { + id: root + name: "pomodoro" + + visible: Visibility.pomodoro + implicitWidth: rect.width + implicitHeight: rect.height + + WlrLayershell.layer: WlrLayer.Top + WlrLayershell.keyboardFocus: root.visible ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None + + WrapperRectangle { + id: rect + + color: Theme.palette.base300 + leftMargin: 48 + rightMargin: 48 + topMargin: 24 + bottomMargin: 24 + radius: 8 + + HyprlandFocusGrab { + active: Visibility.pomodoro + windows: [root] + onCleared: { + Visibility.pomodoro = false; + } + } + + ColumnLayout { + + spacing: 22 + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: "Pomodoro" + font.pixelSize: 22 + } + + Circle { + id: circle + radius: 150 + color: Pomodoro.state == "timer" ? Theme.palette.primary : Theme.palette.warning + percentage: (Pomodoro.state == "timer" ? (Pomodoro.initialTime - Pomodoro.remainingTime) : Pomodoro.remainingTime) / Pomodoro.initialTime % 1 + + WrapperRectangle { + color: "transparent" + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + ColumnLayout { + spacing: 18 + StyledButton { + + Layout.alignment: Qt.AlignHCenter + + focus: root.visible + + content: LucideIcon { + text: Pomodoro.running ? Icons.square : Icons.play + font.pixelSize: 20 + } + + onClicked: { + Pomodoro.toggle(); + } + + Keys.onSpacePressed: event => { + event.accepted = true; + Pomodoro.toggle(); + } + Keys.onEscapePressed: event => { + event.accepted = true; + Visibility.pomodoro = false; + } + Keys.onBackPressed: event => { + event.accepted = true; + Pomodoro.reset(); + } + } + StyledText { + Layout.alignment: Qt.AlignHCenter + text: { + const date = new Date(Pomodoro.remainingTime); + return `${date.getMinutes().toString().padStart(2, "0")}:${(date.getSeconds() % 3600).toString().padStart(2, "0")}`; + } + font.pixelSize: 16 + } + } + } + } + + StyledButton { + + Layout.alignment: Qt.AlignHCenter + + content: StyledText { + text: "Reset" + font.pixelSize: 14 + } + + onClicked: { + Pomodoro.reset(); + } + } + } + } +} diff --git a/services/Pomodoro.qml b/services/Pomodoro.qml new file mode 100644 index 0000000..03c3655 --- /dev/null +++ b/services/Pomodoro.qml @@ -0,0 +1,62 @@ +pragma Singleton + +import QtQuick +import Quickshell + +Singleton { + id: root + + readonly property alias running: properties.running + readonly property alias initialTime: properties.initialTime + readonly property alias remainingTime: properties.remainingTime + readonly property alias state: properties.state + + function toggle() { + properties.running = !properties.running; + } + + function reset() { + properties.running = false; + properties.setTimer(); + } + + Timer { + id: timer + + interval: 10 + repeat: true + running: properties.running + onTriggered: { + if (properties.remainingTime <= 0) { + properties.state == "timer" ? properties.setRest() : properties.setTimer(); + + } + properties.remainingTime -= interval; + } + } + + PersistentProperties { + id: properties + reloadableId: "Pomodoro" + + readonly property int timerAmount: 25 * 60 * 1000 + readonly property int restAmount: 10 * 60 * 1000 + + property bool running: false + property string state: "timer" + property int initialTime: 0 + property int remainingTime: 0 + + function setTimer() { + properties.state = "timer"; + properties.initialTime = timerAmount; + properties.remainingTime = timerAmount; + } + + function setRest() { + properties.state = "rest"; + properties.initialTime = restAmount; + properties.remainingTime = restAmount; + } + } +} diff --git a/services/Visibility.qml b/services/Visibility.qml index c65d00a..b4895b4 100644 --- a/services/Visibility.qml +++ b/services/Visibility.qml @@ -5,6 +5,7 @@ import Quickshell Singleton { property bool launcher + property bool pomodoro property bool powermenu property StyledPopupWindow activePopup diff --git a/widgets/Circle.qml b/widgets/Circle.qml new file mode 100644 index 0000000..18cbc59 --- /dev/null +++ b/widgets/Circle.qml @@ -0,0 +1,51 @@ +import qs.config +import QtQuick +import QtQuick.Shapes + +Item { + id: root + + property int radius: 0 + property double percentage: 0 + property alias color: path.strokeColor + + implicitWidth: radius * 2 + implicitHeight: radius * 2 + + Shape { + + preferredRendererType: Shape.CurveRenderer + + ShapePath { + fillColor: Theme.palette.base100 + strokeColor: Theme.palette.base200 + strokeWidth: 8 + + PathAngleArc { + centerX: root.radius + centerY: root.radius + radiusX: root.radius + radiusY: root.radius + sweepAngle: 360 + } + } + + ShapePath { + id: path + + fillColor: "transparent" + strokeWidth: 8 + strokeColor: "white" + capStyle: ShapePath.RoundCap + + PathAngleArc { + centerX: root.radius + centerY: root.radius + radiusX: root.radius + radiusY: root.radius + startAngle: -90 + sweepAngle: 360 * root.percentage + } + } + } +}