diff --git a/modules/bar/popouts/Calendar.qml b/modules/bar/popouts/Calendar.qml index 87fc229..beae51c 100644 --- a/modules/bar/popouts/Calendar.qml +++ b/modules/bar/popouts/Calendar.qml @@ -13,6 +13,38 @@ Column { property bool isCurrentMonth: true property string currentTime: Qt.formatDateTime(new Date(), "HH:mm:ss") property int currentYear: new Date().getFullYear() + property date selectedStartDate: new Date() + property date selectedEndDate: new Date() + property bool isSelectingRange: false + property string dateCalculation: "" + property bool hasSelection: false + + function calculateDays() { + if (root.selectedStartDate && root.selectedEndDate) { + const diffTime = Math.abs(root.selectedEndDate - root.selectedStartDate) + const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + root.dateCalculation = diffDays + " days" + } else if (root.selectedStartDate) { + const today = new Date() + const diffTime = Math.abs(root.selectedStartDate - today) + const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + root.dateCalculation = diffDays + " days" + } + } + + function calculateDaysFromReference(referenceDate, targetDate) { + const diffTime = Math.abs(targetDate - referenceDate) + const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + root.dateCalculation = diffDays + " days" + } + + function resetSelection() { + root.selectedStartDate = new Date() + root.selectedEndDate = new Date() + root.isSelectingRange = false + root.dateCalculation = "" + root.hasSelection = false + } // Update time every second Timer { @@ -24,6 +56,29 @@ Column { } } + // Date calculation display + Row { + visible: root.hasSelection + anchors.horizontalCenter: parent.horizontalCenter + spacing: Appearance.spacing.small + + StyledText { + text: root.dateCalculation + font.pointSize: Appearance.font.size.small + font.family: Appearance.font.family.mono + color: Colours.palette.m3onSurfaceVariant + } + + MaterialIcon { + text: "close" + color: Colours.palette.m3onSurfaceVariant + MouseArea { + anchors.fill: parent + onClicked: root.resetSelection() + } + } + } + // Time and Date header Column { anchors.horizontalCenter: parent.horizontalCenter @@ -131,6 +186,30 @@ Column { highlightResizeDuration: Appearance.anim.durations.normal highlightResizeVelocity: -1 + // Add mouse wheel scrolling + MouseArea { + anchors.fill: parent + onWheel: { + if (wheel.angleDelta.y > 0) { + // Going to previous month + if (monthView.currentIndex === 0) { + root.currentYear-- + monthView.currentIndex = 11 + } else { + monthView.decrementCurrentIndex() + } + } else { + // Going to next month + if (monthView.currentIndex === 11) { + root.currentYear++ + monthView.currentIndex = 0 + } else { + monthView.incrementCurrentIndex() + } + } + } + } + model: 12 // Show all months currentIndex: new Date().getMonth() @@ -166,14 +245,17 @@ Column { // Add previous month's days const prevMonthLastDay = new Date(root.currentYear, monthView.currentIndex, 0).getDate(); for (let i = firstDayOfWeek - 1; i > 0; i--) { + const date = new Date(root.currentYear, monthView.currentIndex - 1, prevMonthLastDay - i + 1); days.push({ day: prevMonthLastDay - i + 1, isCurrentMonth: false, - isNextMonth: false + isNextMonth: false, + date: date }); } // Add days of the current month for (let i = 1; i <= daysInMonth; i++) { + const date = new Date(root.currentYear, monthView.currentIndex, i); const isToday = i === today.getDate() && monthView.currentIndex === today.getMonth() && root.currentYear === today.getFullYear(); @@ -181,16 +263,19 @@ Column { day: i, isCurrentMonth: true, isToday: isToday, - isNextMonth: false + isNextMonth: false, + date: date }); } // Add next month's days const remainingCells = Math.ceil((firstDayOfWeek - 1 + daysInMonth) / 7) * 7 - days.length; for (let i = 1; i <= remainingCells; i++) { + const date = new Date(root.currentYear, monthView.currentIndex + 1, i); days.push({ day: i, isCurrentMonth: false, - isNextMonth: true + isNextMonth: true, + date: date }); } return days; @@ -200,20 +285,58 @@ Column { width: 30 height: 30 radius: Appearance.rounding.full - color: modelData.isToday ? Colours.palette.m3primary : "transparent" + color: { + if (modelData.date.getTime() === root.selectedStartDate.getTime()) { + return Colours.palette.m3primary + } else if (modelData.date.getTime() === root.selectedEndDate.getTime()) { + return Colours.palette.m3secondary + } else if (modelData.isToday) { + return Colours.palette.m3tertiary + } + return "transparent" + } + + border.width: modelData.isToday ? 2 : 0 + border.color: Colours.palette.m3outline + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onClicked: function(mouse) { + if (mouse.button === Qt.RightButton) { + root.selectedStartDate = modelData.date + root.hasSelection = true + root.calculateDays() + } else if (mouse.button === Qt.LeftButton) { + if (root.selectedStartDate) { + root.selectedEndDate = modelData.date + root.hasSelection = true + root.calculateDaysFromReference(root.selectedStartDate, modelData.date) + } + } + } + } StyledText { anchors.centerIn: parent text: modelData.day font.pointSize: Appearance.font.size.small font.family: Appearance.font.family.mono - color: modelData.isToday ? - Colours.palette.m3onPrimary : - modelData.isCurrentMonth ? - Colours.palette.m3onSurface : - modelData.isNextMonth ? - "#404040" : - "#505050" + color: { + if (modelData.date.getTime() === root.selectedStartDate.getTime() || + modelData.date.getTime() === root.selectedEndDate.getTime()) { + return Colours.palette.m3onPrimary + } else if (modelData.isToday) { + return Colours.palette.m3onTertiary + } else if (modelData.isCurrentMonth) { + return Colours.palette.m3onSurface + } else if (modelData.isNextMonth) { + return "#404040" + } else { + return "#505050" + } + } } } } @@ -226,6 +349,31 @@ Column { } } + // Usage instructions + Column { + width: 280 + anchors.horizontalCenter: parent.horizontalCenter + spacing: Appearance.spacing.small + + StyledText { + text: " Usage:" + font.pointSize: Appearance.font.size.smaller + color: "#505050" + } + + StyledText { + text: " • Scroll to navigate" + font.pointSize: Appearance.font.size.smaller + color: "#505050" + } + + StyledText { + text: " • Right-click = days from/till today" + font.pointSize: Appearance.font.size.smaller + color: "#505050" + } + } + // Reset to current month when popout closes Connections { target: root.parent @@ -235,6 +383,7 @@ Column { root.currentYear = new Date().getFullYear() root.currentDate = new Date() root.isCurrentMonth = true + root.resetSelection() } } }