From 498fe2409321a127e946570afab7781131c5fd6b Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Mon, 3 Nov 2025 16:53:10 -0500 Subject: [PATCH] Time: more accurate time update to fix janky seconds needle. --- Commons/Time.qml | 29 ++++++++++++++++-- Modules/Bar/Calendar/CalendarPanel.qml | 20 ++++++------- Modules/Bar/Widgets/Clock.qml | 2 +- Modules/LockScreen/LockScreen.qml | 6 ++-- .../Bar/WidgetSettings/ClockSettings.qml | 2 +- Widgets/NClock.qml | 30 ++++++++----------- 6 files changed, 54 insertions(+), 35 deletions(-) diff --git a/Commons/Time.qml b/Commons/Time.qml index 16dbfdca..c346d1e0 100644 --- a/Commons/Time.qml +++ b/Commons/Time.qml @@ -9,18 +9,41 @@ Singleton { id: root // Current date - property var date: new Date() + property var now: new Date() // Returns a Unix Timestamp (in seconds) readonly property int timestamp: { - return Math.floor(date / 1000) + return Math.floor(root.now / 1000) } Timer { + id: updateTimer interval: 1000 repeat: true running: true - onTriggered: root.date = new Date() + triggeredOnStart: false + onTriggered: { + var newTime = new Date() + root.now = newTime + + // Adjust next interval to sync with the start of the next second + var msIntoSecond = newTime.getMilliseconds() + if (msIntoSecond > 100) { + // If we're more than 100ms into the second, adjust for next time + updateTimer.interval = 1000 - msIntoSecond + 10 // +10ms buffer + updateTimer.restart() + } else { + updateTimer.interval = 1000 + } + } + } + + Component.onCompleted: { + // Start by syncing to the next second boundary + var now = new Date() + var msUntilNextSecond = 1000 - now.getMilliseconds() + updateTimer.interval = msUntilNextSecond + 10 // +10ms buffer + updateTimer.restart() } // Formats a Date object into a YYYYMMDD-HHMMSS string. diff --git a/Modules/Bar/Calendar/CalendarPanel.qml b/Modules/Bar/Calendar/CalendarPanel.qml index 307300ba..ba0bbf8e 100644 --- a/Modules/Bar/Calendar/CalendarPanel.qml +++ b/Modules/Bar/Calendar/CalendarPanel.qml @@ -12,10 +12,10 @@ NPanel { id: root property ShellScreen screen - readonly property var now: Time.date + readonly property var now: Time.now - preferredWidth: 500 - preferredHeight: 700 + preferredWidth: 500 * Style.uiScaleRatio + preferredHeight: 700 * Style.uiScaleRatio // Helper function to calculate ISO week number function getISOWeekNumber(date) { @@ -60,7 +60,7 @@ NPanel { readonly property bool weatherReady: Settings.data.location.weatherEnabled && (LocationService.data.weather !== null) function checkIsCurrentMonth() { - return (Time.date.getMonth() === grid.month) && (Time.date.getFullYear() === grid.year) + return (now.getMonth() === grid.month) && (now.getFullYear() === grid.year) } Component.onCompleted: { @@ -69,7 +69,7 @@ NPanel { Connections { target: Time - function onDateChanged() { + function onNowChanged() { content.isCurrentMonth = content.checkIsCurrentMonth() } } @@ -118,7 +118,7 @@ NPanel { clip: true Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - text: Time.date.getDate() + text: now.getDate() pointSize: Style.fontSizeXXXL * 1.5 font.weight: Style.fontWeightBold color: Color.mOnPrimary @@ -266,8 +266,8 @@ NPanel { NIconButton { icon: "calendar" onClicked: { - grid.month = Time.date.getMonth() - grid.year = Time.date.getFullYear() + grid.month = now.getMonth() + grid.year = now.getFullYear() content.isCurrentMonth = true CalendarService.loadEvents() } @@ -473,8 +473,8 @@ NPanel { columnSpacing: Style.marginXXS rowSpacing: Style.marginXXS - property int month: Time.date.getMonth() - property int year: Time.date.getFullYear() + property int month: now.getMonth() + property int year: now.getFullYear() Behavior on Layout.preferredHeight { NumberAnimation { diff --git a/Modules/Bar/Widgets/Clock.qml b/Modules/Bar/Widgets/Clock.qml index 3b7a2208..8a31bdc3 100644 --- a/Modules/Bar/Widgets/Clock.qml +++ b/Modules/Bar/Widgets/Clock.qml @@ -32,7 +32,7 @@ Rectangle { readonly property bool isBarVertical: barPosition === "left" || barPosition === "right" readonly property bool density: Settings.data.bar.density - readonly property var now: Time.date + readonly property var now: Time.now // Resolve settings: try user settings or defaults from BarWidgetRegistry readonly property bool usePrimaryColor: widgetSettings.usePrimaryColor !== undefined ? widgetSettings.usePrimaryColor : widgetMetadata.usePrimaryColor diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml index 59bac6b3..cd3a5393 100644 --- a/Modules/LockScreen/LockScreen.qml +++ b/Modules/LockScreen/LockScreen.qml @@ -57,7 +57,7 @@ Loader { locked: lockScreen.active WlSessionLockSurface { - readonly property var now: Time.date + readonly property var now: Time.now Item { id: batteryIndicator @@ -350,7 +350,7 @@ Loader { "pt": "dddd, d 'de' MMMM", "zh": "yyyy年M月d日 dddd" } - return I18n.locale.toString(Time.date, formats[lang] || "dddd, MMMM d") + return I18n.locale.toString(Time.now, formats[lang] || "dddd, MMMM d") } pointSize: Style.fontSizeXL font.weight: Font.Medium @@ -366,7 +366,7 @@ Loader { // Clock NClock { - now: Time.date + now: Time.now clockStyle: Settings.data.location.analogClockInCalendar ? "analog" : "digital" Layout.preferredWidth: 70 Layout.preferredHeight: 70 diff --git a/Modules/Settings/Bar/WidgetSettings/ClockSettings.qml b/Modules/Settings/Bar/WidgetSettings/ClockSettings.qml index 024592f1..a214f508 100644 --- a/Modules/Settings/Bar/WidgetSettings/ClockSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/ClockSettings.qml @@ -25,7 +25,7 @@ ColumnLayout { property var focusedInput: null property int focusedLineIndex: -1 - readonly property var now: Time.date + readonly property var now: Time.now function saveSettings() { var settings = Object.assign({}, widgetData || {}) diff --git a/Widgets/NClock.qml b/Widgets/NClock.qml index c77774e9..fccc6c0c 100644 --- a/Widgets/NClock.qml +++ b/Widgets/NClock.qml @@ -9,7 +9,7 @@ import "../Helpers/ColorsConvert.js" as ColorsConvert Item { id: root - property var now: Time.date + property var now: Time.now // Style: "analog" or "digital" property string clockStyle: "analog" @@ -94,11 +94,19 @@ Item { id: clockCanvas anchors.fill: parent - property int hours: now.getHours() - property int minutes: now.getMinutes() - property int seconds: now.getSeconds() + Connections { + target: Time + function onNowChanged() { + clockCanvas.requestPaint() + } + } onPaint: { + var currentTime = Time.now + var hours = currentTime.getHours() + var minutes = currentTime.getMinutes() + var seconds = currentTime.getSeconds() + const markAlpha = 0.7 var ctx = getContext("2d") ctx.reset() @@ -170,18 +178,6 @@ Item { ctx.fill() } - Timer { - interval: 1000 - running: true - repeat: true - onTriggered: { - clockCanvas.hours = now.getHours() - clockCanvas.minutes = now.getMinutes() - clockCanvas.seconds = now.getSeconds() - clockCanvas.requestPaint() - } - } - Component.onCompleted: requestPaint() } } @@ -203,7 +199,7 @@ Item { onProgressChanged: requestPaint() Connections { target: Time - function onDateChanged() { + function onNowChanged() { const total = now.getSeconds() * 1000 + now.getMilliseconds() secondsProgress.progress = total / 60000 }