diff --git a/dots/.config/quickshell/ii/modules/common/Appearance.qml b/dots/.config/quickshell/ii/modules/common/Appearance.qml index fbe362075..1d3890487 100644 --- a/dots/.config/quickshell/ii/modules/common/Appearance.qml +++ b/dots/.config/quickshell/ii/modules/common/Appearance.qml @@ -375,7 +375,7 @@ Singleton { property QtObject scroll: QtObject { property int duration: 200 property int type: Easing.BezierSpline - property list bezierCurve: animationCurves.standardDecel + property list bezierCurve: root.animationCurves.standardDecel } property QtObject menuDecel: QtObject { diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index 659c3eb22..fb0817ed4 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -301,6 +301,9 @@ Singleton { property JsonObject calendar: JsonObject { property string locale: "en-GB" + property bool force2CharDayOfWeek: true + property bool animate: false // Disabled by default cuz laggy + property bool weekScrollPrecision: false // One scroll advances 1 week instead of 1 month } property JsonObject cheatsheet: JsonObject { diff --git a/dots/.config/quickshell/ii/modules/common/config/WaffleConfig.qml b/dots/.config/quickshell/ii/modules/common/config/WaffleConfig.qml index 9509ff166..d7936bb56 100644 --- a/dots/.config/quickshell/ii/modules/common/config/WaffleConfig.qml +++ b/dots/.config/quickshell/ii/modules/common/config/WaffleConfig.qml @@ -18,7 +18,4 @@ JsonObject { property JsonObject actionCenter: JsonObject { property list toggles: [ "network", "bluetooth", "easyEffects", "powerProfile", "idleInhibitor", "nightLight", "darkMode", "antiFlashbang", "cloudflareWarp", "mic", "musicRecognition", "notifications", "onScreenKeyboard", "gameMode", "screenSnip", "colorPicker" ] } - property JsonObject calendar: JsonObject { - property bool force2CharDayOfWeek: true - } } diff --git a/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml b/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml index 0e1bd13fc..25b70818c 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml @@ -1,15 +1,10 @@ pragma ComponentBehavior: Bound import QtQml import QtQuick -import QtQuick.Controls import QtQuick.Layouts -import Quickshell -import qs -import qs.services import qs.modules.common import qs.modules.common.widgets import qs.modules.common.functions -import qs.modules.waffle.looks Item { id: root @@ -36,15 +31,23 @@ Item { const diffWeeks = Math.round(diffMillis / root.millisPerWeek); root.targetWeekDiff += diffWeeks; } + function scrollToToday() { + root.targetWeekDiff = 0; + } property int weeksPerScroll: 1 property real targetWeekDiff: 0 property real weekDiff: targetWeekDiff property int contentWeekDiff: weekDiff // whole part of weekDiff property bool scrolling: false + property Animation scrollAnimation: NumberAnimation { + duration: Config.options.calendar.animate ? Appearance.animation.scroll.duration : 0 + easing.type: Appearance.animation.scroll.type + easing.bezierCurve: Appearance.animation.scroll.bezierCurve + } Behavior on weekDiff { id: weekScrollBehavior - animation: Looks.transition.scroll.createObject(this) + animation: root.scrollAnimation } Timer { id: scrollAnimationCheckTimer @@ -56,12 +59,20 @@ Item { scrollAnimationCheckTimer.restart(); } - MouseArea { - anchors.fill: parent - onWheel: wheel => { - root.targetWeekDiff += wheel.angleDelta.y / 120 * -root.weeksPerScroll; // Reverse cuz scrolling down should advance + property var wheelAction: (wheel) => { + // Reverse cuz scrolling down should advance + const sign = wheel.angleDelta.y / 120 * -1; + if (Config.options.calendar.weekScrollPrecision) { + root.targetWeekDiff += sign * root.weeksPerScroll; + } else { + scrollMonthsAndSnap(sign); } } + MouseArea { + id: mouseArea + anchors.fill: parent + onWheel: (wheel) => root.wheelAction(wheel) + } // Date calculations readonly property int millisPerWeek: 7 * 24 * 60 * 60 * 1000 @@ -82,14 +93,16 @@ Item { return DateUtils.getIthDayDateOfSameWeek(dateInTargetWeek, root.focusDayOfWeekIndex - root.locale.firstDayOfWeek, root.locale.firstdayOfWeek); // 4 = Thursday } property int focusedMonth: focusedDate.getMonth() + 1 // 0-indexed -> 1-indexed + property string title: locale.toString(focusedDate, "MMMM yyyy") // Sizes property real verticalPadding: 0 + property real horizontalPadding: 0 property real buttonSize: 40 property real buttonSpacing: 2 property real buttonVerticalSpacing: buttonSpacing implicitHeight: (6 * buttonSize) + (5 * buttonVerticalSpacing) + (2 * verticalPadding) - implicitWidth: weeksColumn.implicitWidth + implicitWidth: weeksColumn.implicitWidth + (2 * horizontalPadding) clip: true ColumnLayout { @@ -97,6 +110,8 @@ Item { anchors { left: parent.left right: parent.right + leftMargin: root.horizontalPadding + rightMargin: root.horizontalPadding } y: { const spacePerExtraRow = root.buttonSize + root.buttonVerticalSpacing; diff --git a/dots/.config/quickshell/ii/modules/common/widgets/ChoreographerGrid.qml b/dots/.config/quickshell/ii/modules/common/widgets/ChoreographerGridLayout.qml similarity index 93% rename from dots/.config/quickshell/ii/modules/common/widgets/ChoreographerGrid.qml rename to dots/.config/quickshell/ii/modules/common/widgets/ChoreographerGridLayout.qml index 7223458d1..97223d904 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/ChoreographerGrid.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/ChoreographerGridLayout.qml @@ -10,7 +10,7 @@ GridLayout { property real totalDuration: 250 property real interval: totalDuration / count - default property list choreographableChildren + default property list choreographableChildren readonly property int count: choreographableChildren.length children: choreographableChildren diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledButton.qml new file mode 100644 index 000000000..970e212bf --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledButton.qml @@ -0,0 +1,72 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Controls +import ".." +import "../functions" + +Button { + id: root + + property alias radius: bg.radius + property alias contentLayer: bg.contentLayer + + property color colFocusRing: Appearance.colors.colOnSecondaryContainer + property color colBackground: checked ? colBackgroundChecked : colBackgroundUnchecked + property color colForeground: checked ? colForegroundChecked : colForegroundUnchecked + + property color colBackgroundUnchecked: ColorUtils.transparentize(Appearance.colors.colLayer4Base, 1) + property color colBackgroundChecked: Appearance.colors.colPrimary + property color colForegroundUnchecked: Appearance.colors.colOnLayer4 + property color colForegroundChecked: Appearance.colors.colOnPrimary + + hoverEnabled: true + opacity: root.enabled ? 1 : 0.5 + + HoverHandler { + cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor + } + + background: StyledRectangle { + id: bg + implicitHeight: root.contentItem.implicitHeight + implicitWidth: root.contentItem.implicitWidth + + radius: Math.min(width, height) / 2 + color: root.colBackground + + StateOverlay { + anchors.fill: parent + hover: root.hovered && root.enabled + press: root.pressed && root.enabled + focus: false // We use a ring instead + radius: bg.radius + } + + Rectangle { + id: focusRing + radius: bg.radius - anchors.margins + visible: root.visualFocus + color: "transparent" + anchors { + fill: parent + margins: -4 + } + border { + color: root.colFocusRing + width: 2 + } + } + } + + contentItem: Item { + implicitWidth: buttonText.implicitWidth + implicitHeight: buttonText.implicitHeight + VisuallyCenteredStyledText { + id: buttonText + anchors.centerIn: parent + text: root.text + color: root.colForeground + } + } + +} diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledIconButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledIconButton.qml new file mode 100644 index 000000000..66387c410 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledIconButton.qml @@ -0,0 +1,19 @@ +pragma ComponentBehavior: Bound +import QtQuick + +StyledButton { + id: root + + property alias implicitSize: root.implicitHeight + implicitWidth: implicitHeight + property alias iconSize: icon.iconSize + + contentItem: Item { + MaterialSymbol { + id: icon + anchors.centerIn: parent + color: root.colForeground + text: root.text + } + } +} diff --git a/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/HTime.qml b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/HTime.qml index 6e917652a..36bbd1d11 100644 --- a/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/HTime.qml +++ b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/HTime.qml @@ -1,5 +1,6 @@ pragma ComponentBehavior: Bound import QtQuick +import QtQuick.Controls import QtQuick.Layouts import qs.modules.common as C @@ -70,38 +71,8 @@ HBarWidgetContainer { anchors.fill: parent shown: !contentRoot.vertical - sourceComponent: Item { + sourceComponent: HorizontalClock { anchors.fill: parent - implicitWidth: contentLayout.implicitWidth - implicitHeight: contentLayout.implicitHeight - - RowLayout { - id: contentLayout - anchors.fill: parent - - W.VisuallyCenteredStyledText { - Layout.leftMargin: contentRoot.layoutParentTopLeftRadius * contentRoot.parentRadiusToPaddingRatio - Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - Layout.fillHeight: true - font.pixelSize: C.Appearance.font.pixelSize.large - color: C.Appearance.colors.colOnLayer1 - text: S.DateTime.time - } - - W.VisuallyCenteredStyledText { - Layout.alignment: Qt.AlignVCenter - font.pixelSize: C.Appearance.font.pixelSize.small - color: C.Appearance.colors.colOnLayer1 - text: "•" - } - - W.VisuallyCenteredStyledText { - Layout.alignment: Qt.AlignVCenter - font.pixelSize: C.Appearance.font.pixelSize.small - color: C.Appearance.colors.colOnLayer1 - text: S.DateTime.longDate - } - } } } @@ -111,45 +82,13 @@ HBarWidgetContainer { anchors.fill: parent shown: contentRoot.vertical - sourceComponent: Item { + sourceComponent: VerticalClock { anchors.fill: parent - implicitWidth: contentLayoutVertical.implicitWidth - implicitHeight: contentLayoutVertical.implicitHeight - - ColumnLayout { - id: contentLayoutVertical - anchors.fill: parent - spacing: -6 - - W.StyledText { - Layout.alignment: Qt.AlignHCenter - font.pixelSize: C.Appearance.font.pixelSize.large - color: C.Appearance.colors.colOnLayer1 - text: { - var hrs = S.DateTime.clock.hours; - if (root.is12h) hrs %= 12; - return hrs.toString().padStart(2, '0') - } - } - W.StyledText { - Layout.alignment: Qt.AlignHCenter - font.pixelSize: C.Appearance.font.pixelSize.large - color: C.Appearance.colors.colOnLayer1 - text: S.DateTime.clock.minutes.toString().padStart(2, '0') - } - W.StyledText { - visible: root.hasAmPm - Layout.alignment: Qt.AlignHCenter - font.pixelSize: C.Appearance.font.pixelSize.smaller - color: C.Appearance.colors.colOnLayer1 - text: Qt.locale().toString(S.DateTime.clock.date, root.capitalizedAmPm ? "AP" : "ap") - } - } } } // Popup content - W.ChoreographerGrid { + PopupContent { id: popupContent anchors { top: root.vertical ? verticalContent.top : horizontalContent.top @@ -159,21 +98,211 @@ HBarWidgetContainer { } shown: root.showPopup + } + } + + component HorizontalClock: Item { + implicitWidth: contentLayout.implicitWidth + implicitHeight: contentLayout.implicitHeight + + RowLayout { + id: contentLayout + anchors.fill: parent + + W.VisuallyCenteredStyledText { + Layout.leftMargin: contentRoot.layoutParentTopLeftRadius * contentRoot.parentRadiusToPaddingRatio + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + Layout.fillHeight: true + font.pixelSize: C.Appearance.font.pixelSize.large + color: C.Appearance.colors.colOnLayer1 + text: S.DateTime.time + } + + W.VisuallyCenteredStyledText { + Layout.alignment: Qt.AlignVCenter + font.pixelSize: C.Appearance.font.pixelSize.small + color: C.Appearance.colors.colOnLayer1 + text: "•" + } + + W.VisuallyCenteredStyledText { + Layout.alignment: Qt.AlignVCenter + font.pixelSize: C.Appearance.font.pixelSize.small + color: C.Appearance.colors.colOnLayer1 + text: S.DateTime.longDate + } + } + } + + component VerticalClock: Item { + implicitWidth: contentLayoutVertical.implicitWidth + implicitHeight: contentLayoutVertical.implicitHeight + + ColumnLayout { + id: contentLayoutVertical + anchors.fill: parent + spacing: amPmText.visible ? -2 : -4 + + ColumnLayout { + id: verticalTime + Layout.alignment: Qt.AlignHCenter + spacing: -4 - W.FlyFadeEnterChoreographable { W.StyledText { - text: "Kalender" - font.pixelSize: 25 + Layout.alignment: Qt.AlignHCenter + font.pixelSize: C.Appearance.font.pixelSize.large + color: C.Appearance.colors.colOnLayer1 + text: { + var hrs = S.DateTime.clock.hours; + if (root.is12h && hrs != 12) + hrs %= 12; + return hrs.toString().padStart(2, '0'); + } + } + W.StyledText { + Layout.alignment: Qt.AlignHCenter + font.pixelSize: C.Appearance.font.pixelSize.large + color: C.Appearance.colors.colOnLayer1 + text: S.DateTime.clock.minutes.toString().padStart(2, '0') + } + W.StyledText { + id: amPmText + visible: root.hasAmPm + Layout.topMargin: -2 + Layout.alignment: Qt.AlignHCenter + font.pixelSize: C.Appearance.font.pixelSize.smaller + color: C.Appearance.colors.colOnLayer1 + text: Qt.locale().toString(S.DateTime.clock.date, root.capitalizedAmPm ? "AP" : "ap") } } - W.FlyFadeEnterChoreographable { + + W.StyledText { + Layout.alignment: Qt.AlignHCenter + font.pixelSize: C.Appearance.font.pixelSize.smallest + color: C.Appearance.colors.colOnLayer1 + text: S.DateTime.shortDate + } + } + } + + component PopupContent: W.ChoreographerGridLayout { + id: popupRoot + + property real buttonSize: C.Appearance.rounding.normal * 2 + property real buttonSpacing: 4 + + rowSpacing: 0 + + W.FlyFadeEnterChoreographable { + Layout.fillWidth: true + + RowLayout { + width: parent.width + spacing: 0 + W.StyledText { - text: "Lorem ipsum okakumalum tung\ntung tung tung" + Layout.leftMargin: 6 + Layout.alignment: Qt.AlignVCenter + Layout.fillWidth: true + text: calendarView.title + font.pixelSize: C.Appearance.font.pixelSize.larger + elide: Text.ElideRight + color: C.Appearance.colors.colSecondary + } + W.StyledIconButton { + implicitSize: 30 + text: "chevron_left" + iconSize: 20 + onClicked: calendarView.scrollMonthsAndSnap(-1) + colForeground: C.Appearance.colors.colPrimary + } + W.StyledIconButton { + implicitSize: 30 + text: "chevron_right" + iconSize: 20 + onClicked: calendarView.scrollMonthsAndSnap(1) + colForeground: C.Appearance.colors.colPrimary + } + W.StyledIconButton { + implicitSize: 30 + text: "rotate_left" + iconSize: 20 + onClicked: calendarView.scrollToToday() + colForeground: C.Appearance.colors.colPrimary + enabled: calendarView.targetWeekDiff != 0 } } - W.FlyFadeEnterChoreographable { - W.StyledText { - text: "BAJLANDO\nUUOOOUUUOOOUUOOUOU" + } + W.FlyFadeEnterChoreographable { + Layout.fillWidth: true + + DayOfWeekRow { + id: dayOfWeekRow + width: parent.width + locale: calendarView.locale + spacing: popupRoot.buttonSpacing + delegate: Item { + id: dayOfWeekItem + required property var model + implicitHeight: popupRoot.buttonSize + implicitWidth: popupRoot.buttonSize + + W.VisuallyCenteredStyledText { + anchors.centerIn: parent + text: { + var result = dayOfWeekItem.model.shortName; + if (C.Config.options.calendar.force2CharDayOfWeek) + result = result.substring(0, 2); + return result; + } + } + } + } + } + W.FlyFadeEnterChoreographable { + Item { + implicitWidth: calendarView.implicitWidth - calendarView.horizontalPadding * 2 + implicitHeight: calendarView.implicitHeight - calendarView.verticalPadding * 2 + W.CalendarView { + id: calendarView + anchors.centerIn: parent + locale: Qt.locale(C.Config.options.calendar.locale) + verticalPadding: 4 + horizontalPadding: 4 + buttonSize: popupRoot.buttonSize + buttonSpacing: popupRoot.buttonSpacing + buttonVerticalSpacing: popupRoot.buttonSpacing + Layout.fillWidth: true + + delegate: W.StyledButton { + id: dayButton + required property var model + + focus: model.today + checked: model.today + enabled: model.month === calendarView.focusedMonth + implicitWidth: popupRoot.buttonSize + implicitHeight: popupRoot.buttonSize + width: implicitWidth + height: implicitHeight + text: model.day + + Connections { + target: popupRoot + enabled: dayButton.model.today + function onShownChanged() { + if (popupRoot.shown) dayButton.forceActiveFocus(); + } + } + + contentItem: Item { + W.VisuallyCenteredStyledText { + anchors.centerIn: parent + text: dayButton.text + color: dayButton.colForeground + } + } + } } } } diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml index 16dc831e1..8255dba4e 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml @@ -54,7 +54,7 @@ BodyRectangle { anchors.centerIn: parent text: { var result = dayOfWeekItem.model.shortName; - if (Config.options.waffles.calendar.force2CharDayOfWeek) result = result.substring(0,2); + if (Config.options.calendar.force2CharDayOfWeek) result = result.substring(0,2); return result; } color: Looks.colors.fg @@ -70,6 +70,7 @@ BodyRectangle { buttonSpacing: 6 buttonVerticalSpacing: 1 Layout.fillWidth: true + scrollAnimation: Looks.transition.scroll.createObject(this) delegate: DayButton {} } }