pragma ComponentBehavior: Bound import qs import qs.services import qs.modules.common import qs.modules.common.widgets import qs.modules.common.functions import QtQuick import QtQuick.Layouts import Quickshell import Qt5Compat.GraphicalEffects Item { id: root readonly property string clockStyle: Config.options.background.clock.style readonly property bool showQuote: Config.options.background.showQuote && Config.options.background.quote.length > 0 && !GlobalStates.screenLocked property real implicitSize: 230 property real hourHandLength: 72 property real hourHandWidth: 20 property real minuteHandLength: 95 property real minuteHandWidth: Config.options.background.clock.cookie.minuteHandStyle === "bold" ? hourHandWidth : Config.options.background.clock.cookie.minuteHandStyle === "medium" ? 12 : 5 property real centerDotSize: 10 property real hourDotSize: 12 property real centerGlowSize: 135 property real secondDotSize: 20 property real secondsHandWidth: 2 property real secondsHandLength: 100 property real hourLineSize: 5 property real minuteLineSize: 2 property real hourNumberSize: 36 property real dateSquareSize: 64 property color colShadow: Appearance.colors.colShadow property color colBackground: Appearance.colors.colSecondaryContainer property color colOnBackground: ColorUtils.mix(Appearance.colors.colPrimary, Appearance.colors.colSecondaryContainer, 0.5) property color colMinuteHand: Appearance.colors.colPrimary property color colHourHand: Appearance.colors.colSecondaryActive property color colOnHourHand: Appearance.colors.colOnPrimary property color colTimeIndicators: Appearance.colors.colSecondaryContainerHover property color colSeconds: Appearance.colors.colTertiary readonly property list clockNumbers: DateTime.time.split(/[: ]/) readonly property int clockHour: parseInt(clockNumbers[0]) % 12 readonly property int clockMinute: parseInt(clockNumbers[1]) property int clockSecond: 0 // Loader to set root.clockSecond Loader{ active: Config.option.background.clock.cookie.secondDot sourceComponent: Timer { interval: 1000 running: true;repeat: true onTriggered: { var now = new Date() clockSecond = now.getSeconds() } } } implicitWidth: implicitSize implicitHeight: implicitSize DropShadow { source: cookie anchors.fill: source horizontalOffset: 0 verticalOffset: 2 radius: 12 samples: radius * 2 + 1 color: root.colShadow transparentBorder: true } DropShadow { source: quoteBox anchors.fill: source horizontalOffset: 0 verticalOffset: 2 radius: 12 samples: radius * 2 + 1 color: root.colShadow transparentBorder: true } MaterialCookie { id: cookie z: 0 implicitSize: root.implicitSize amplitude: implicitSize / 70 sides: Config.options.background.clock.clockSides color: root.colBackground constantlyRotate: Config.options.background.clock.cookie.constantlyRotate } // Hour dots dial style Repeater { model: 12 Item { required property int index opacity: Config.options.background.clock.cookie.dialNumberStyle === "dots" ? 1.0 : 0 rotation: 360 / 12 * index anchors.fill: parent Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } Rectangle { anchors{ left: parent.left verticalCenter: parent.verticalCenter leftMargin: Config.options.background.clock.cookie.dialNumberStyle === "dots" ? 10 : 50 } Behavior on anchors.leftMargin{ animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } implicitWidth: root.hourDotSize implicitHeight: implicitWidth radius: implicitWidth / 2 color: root.colOnBackground opacity: 0.5 } } } // Center glow lines Rectangle { id: glowLines z: 1 anchors.centerIn: cookie Repeater { model: 12 Item { required property int index opacity: Config.options.background.clock.cookie.centerGlow ? 1.0 : 0 rotation: 360 / 12 * index anchors.fill: parent Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } Rectangle { anchors { left: parent.left verticalCenter: parent.verticalCenter leftMargin: Config.options.background.clock.cookie.centerGlow ? 50 : 75 } implicitWidth: root.hourDotSize implicitHeight: implicitWidth / 2 radius: implicitWidth / 2 color: root.colOnBackground opacity: Config.options.background.clock.cookie.centerGlow ? 0.5 : 0 Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } Behavior on anchors.leftMargin{ animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } } } } } // Numbers column Column { id: timeIndicators z: 1 anchors.centerIn: cookie spacing: -16 Repeater { model: root.clockNumbers delegate: StyledText { required property string modelData opacity: Config.options.background.clock.cookie.timeIndicators ? 1.0 : 0 // Not using visible to allow smooth transition anchors.horizontalCenter: parent?.horizontalCenter color: root.colOnBackground text: modelData.padStart(2, "0") font { property real numberSizeWithoutGlow: modelData.match(/am|pm/i) ? 26 : 68 property real numberSizeWithGlow: modelData.match(/am|pm/i) ? 10 : 40 pixelSize: !Config.options.background.clock.cookie.timeIndicators ? 100 : // open/close animation Config.options.background.clock.cookie.centerGlow ? numberSizeWithGlow : numberSizeWithoutGlow // changing size according to center glow Behavior on pixelSize { animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } family: Appearance.font.family.main weight: Font.Bold } Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } } } } // Hour hand Item { opacity: Config.options.background.clock.cookie.hourHandStyle === "hide" ? 0.0 : 1.0 anchors.fill: parent z: Config.options.background.clock.cookie.hourHandStyle === "fill" ? 3 : 1 rotation: -90 + (360 / 12) * (root.clockHour + root.clockMinute / 60) Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } Rectangle { opacity: Config.options.background.clock.cookie.hourHandStyle !== "hide" ? 1.0 : 0 anchors.verticalCenter: parent.verticalCenter x: Config.options.background.clock.cookie.hourHandStyle === "classic" ? (parent.width / 2 - minuteHandWidth / 2) - 15 : parent.width / 2 - minuteHandWidth / 2 width: hourHandLength height: Config.options.background.clock.cookie.hourHandStyle === "classic" ? 8 : hourHandWidth radius: Config.options.background.clock.cookie.hourHandStyle === "classic" ? 2 : hourHandWidth / 2 color : Config.options.background.clock.cookie.hourHandStyle === "stroke" ? "transparent" : root.colHourHand border.color: root.colHourHand border.width: 4 Behavior on opacity { animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } Behavior on x{ animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } } } // Minute hand Item { opacity: Config.options.background.clock.cookie.minuteHandStyle === "hide" ? 0.0 : 1.0 anchors.fill: parent z: Config.options.background.clock.cookie.minuteHandStyle === "thin" ? 1 : 3 rotation: -90 + (360 / 60) * root.clockMinute Behavior on rotation{ animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } Behavior on opacity { animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } Rectangle { anchors.verticalCenter: parent.verticalCenter x: Config.options.background.clock.cookie.minuteHandStyle === "classic" ? (parent.width / 2 - minuteHandWidth / 2) - 15 : parent.width / 2 - minuteHandWidth / 2 width: minuteHandLength height: minuteHandWidth radius: Config.options.background.clock.cookie.minuteHandStyle === "classic" ? 2 : minuteHandWidth / 2 color: root.colMinuteHand Behavior on height { animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } Behavior on x{ animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } } } // Center dot Rectangle { visible: Config.options.background.clock.cookie.minuteHandStyle === "hide" && Config.options.background.clock.cookie.hourHandStyle === "hide" ? false : true z: 4 opacity: Config.options.background.clock.cookie.minuteHandStyle !== "bold" ? 1.0 : 0 color: Config.options.background.clock.cookie.minuteHandStyle === "medium" ? root.colBackground : root.colMinuteHand anchors.centerIn: parent implicitWidth: centerDotSize implicitHeight: implicitWidth radius: implicitWidth / 2 Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } } // Center glow Rectangle { opacity: Config.options.background.clock.cookie.centerGlow ? 1.0 : 0 z: 0 color: root.colTimeIndicators anchors.centerIn: parent implicitWidth: Config.options.background.clock.cookie.centerGlow ? centerGlowSize : centerGlowSize * 1.75 implicitHeight: Config.options.background.clock.cookie.centerGlow ? centerGlowSize : centerGlowSize * 1.75 // Not using implicitHeight to allow smooth transition radius: implicitWidth / 2 Behavior on opacity { animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } Behavior on implicitWidth { animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } Behavior on implicitHeight { animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } } // Second hand/dot Item { id: secondHand z: Config.options.background.clock.cookie.secondHandStyle === "line" ? 2 : 3 opacity: Config.options.background.clock.cookie.secondHandStyle !== "hide" ? 1.0 : 0 rotation: (360 / 60 * clockSecond) + 90 // +90 degrees to align with minute hand anchors.fill: parent Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } Behavior on rotation{ animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } Rectangle { implicitWidth: Config.options.background.clock.cookie.secondHandStyle === "dot" ? root.secondDotSize : root.secondsHandLength implicitHeight: Config.options.background.clock.cookie.secondHandStyle === "dot" ? root.secondDotSize : root.secondsHandWidth radius: Config.options.background.clock.cookie.secondHandStyle === "dot" ? implicitWidth / 2 : root.secondsHandWidth / 2 color: colSeconds Behavior on implicitHeight { animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } Behavior on implicitWidth { animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } anchors { left: parent.left verticalCenter: parent.verticalCenter leftMargin: 10 } } Rectangle{ // Dot on the classic style opacity: Config.options.background.clock.cookie.secondHandStyle === "classic" ? 1.0 : 0.0 implicitHeight: 14 implicitWidth: 14 color: root.colSeconds radius: Appearance.rounding.small anchors { left: parent.left verticalCenter: parent.verticalCenter leftMargin: 40 } Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } } } // Date (the rotating one with the second hand) Canvas { z: 0 width: cookie.width height: cookie.height rotation: secondHand.rotation + 45 // +45 degrees to align with minute hand opacity: Config.options.background.clock.cookie.dateStyle === "rotating" ? 1.0 : 0 Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } onPaint: { var ctx = getContext("2d"); ctx.clearRect(0,0,width,height); ctx.font = "700 30px gabarito"; var text = DateTime.date.substring(0,3) + " " + DateTime.date.substring(4,7); var radius = 78; var angleStep = Math.PI / 2.35 / text.length; for (var i=0; i= 3) ctx.fillStyle = root.colOnBackground; else ctx.fillStyle = Appearance.colors.colSecondaryHover; ctx.fillText(text[i], 0, 0); ctx.restore(); } } } // Date(only today's number) in right side of the clock Rectangle{ z: 1 implicitWidth: 45 implicitHeight: Config.options.background.clock.cookie.dateStyle === "square" ? 30 : 0 color: root.colOnBackground radius: Appearance.rounding.small anchors{ verticalCenter: cookie.verticalCenter right: cookie.right rightMargin: 10 } Behavior on implicitHeight{ animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } StyledText{ opacity: Config.options.background.clock.cookie.dateStyle === "square" ? 1.0 : 0 Behavior on opacity{ animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } anchors.centerIn: parent color: Appearance.colors.colSecondaryHover text: DateTime.date.substring(5,7) font { family: Appearance.font.family.expressive pixelSize: 20 weight: 1000 } } } // Date bubble style left side Rectangle{ z: 5 implicitWidth: Config.options.background.clock.cookie.dateStyle === "bubble" ? dateSquareSize : 0 implicitHeight: Config.options.background.clock.cookie.dateStyle === "bubble" ? dateSquareSize : 0 color: Appearance.colors.colPrimaryContainerHover radius: Appearance.rounding.large anchors{ left: cookie.left bottom: cookie.bottom bottomMargin: 5 } Behavior on implicitWidth{ animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } Behavior on implicitHeight{ animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } StyledText{ anchors.centerIn: parent text: DateTime.date.substring(5,7) color: Appearance.colors.colPrimary opacity: Config.options.background.clock.cookie.dateStyle === "bubble" ? 1.0 : 0 font { family: Appearance.font.family.reading pixelSize: 30 weight: 1000 } Behavior on opacity{ animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } } } // Date bubble style right side Rectangle{ z: 5 implicitWidth: Config.options.background.clock.cookie.dateStyle === "bubble" ? dateSquareSize : 0 implicitHeight: Config.options.background.clock.cookie.dateStyle === "bubble" ? dateSquareSize : 0 color: Appearance.colors.colTertiaryContainer radius: Appearance.rounding.verylarge anchors{ right: cookie.right top: cookie.top topMargin: 5 } Behavior on implicitWidth{ animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } Behavior on implicitHeight{ animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } StyledText{ anchors.centerIn: parent text: DateTime.date.substring(8,10) color: Appearance.colors.colTertiary opacity: Config.options.background.clock.cookie.dateStyle === "bubble" ? 1.0 : 0 font { family: Appearance.font.family.reading pixelSize: 30 weight: 1000 } Behavior on opacity{ animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } } } // Hour Indicator numbers (3-6-9-12) Repeater { model: 4 Item { required property int index opacity: Config.options.background.clock.cookie.dialNumberStyle === "numbers" ? 1.0 : 0 rotation: 360 / 4 * index anchors.fill: parent Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } Rectangle { color: "transparent" implicitWidth: root.hourNumberSize implicitHeight: implicitWidth anchors { left: parent.left verticalCenter: parent.verticalCenter leftMargin: Config.options.background.clock.cookie.dialNumberStyle === "numbers" ? 32 : 96 } Behavior on anchors.leftMargin{ animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } StyledText{ color: root.colOnBackground anchors.centerIn: parent text: index === 0 ? "9" : index === 1 ? "12" : index === 2 ? "3" : "6" rotation: index % 2 === 0 ? index * 90 : -index * 90 //A better way can be found to show texts on right angle font { family: Appearance.font.family.reading pixelSize: 80 weight: 1000 } } } } } // Full dial style hour lines Repeater { model: 12 Item { required property int index rotation: 360 / 12 * index anchors.fill: parent opacity: Config.options.background.clock.cookie.dialNumberStyle === "full" ? 1.0 : 0 Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } Rectangle { implicitWidth: root.hourLineSize * 3.5 implicitHeight: root.hourLineSize radius: implicitWidth / 2 color: root.colOnBackground anchors { left: parent.left verticalCenter: parent.verticalCenter leftMargin: Config.options.background.clock.cookie.dialNumberStyle === "full" ? 10 : 50 } Behavior on anchors.leftMargin{ animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } } } } // Full dial style minute lines Repeater { model: 60 Item { required property int index rotation: 360 / 60 * index anchors.fill: parent opacity: Config.options.background.clock.cookie.dialNumberStyle === "full" ? 1.0 : 0 Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } Rectangle { implicitWidth: root.minuteLineSize * 3.5 implicitHeight: root.minuteLineSize radius: implicitWidth / 2 color: root.colOnBackground opacity: 0.5 anchors { left: parent.left verticalCenter: parent.verticalCenter leftMargin: Config.options.background.clock.cookie.dialNumberStyle === "full" ? 10 : 50 } Behavior on anchors.leftMargin{ animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } } } } // Quote Rectangle{ id: quoteBox anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.bottom anchors.topMargin: 24 implicitWidth: quoteText.width + quoteIcon.width + 16 // for spacing on both sides implicitHeight: showQuote ? quoteText.height + 8 : 0 radius: Appearance.rounding.small color: Appearance.colors.colSecondaryContainer Behavior on implicitHeight { animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } Behavior on implicitWidth { animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } RowLayout{ anchors.centerIn: parent spacing: 4 MaterialSymbol{ id: quoteIcon visible: showQuote > 0 iconSize: Appearance.font.pixelSize.huge text: "comic_bubble" } StyledText{ id: quoteText visible : showQuote > 0 Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter text: Config.options.background.quote font { family: Appearance.font.family.main pixelSize: Appearance.font.pixelSize.large weight: Font.Normal italic: true } } } } }