mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-03 20:32:07 -04:00
feat(calendar): add show week number option (#1990)
* increase DankDashPopout width to accommodate week number column * add getWeekNumber function * add week number column * add showWeekNumber SettingsData * add showWeekNumber SettingsSpec * make dash popout width changes reponsively to showWeekNumber option * complete and cleanup * fix typo * fix typo
This commit is contained in:
@@ -12,7 +12,7 @@ DankPopout {
|
||||
property var triggerScreen: null
|
||||
property int currentTabIndex: 0
|
||||
|
||||
popupWidth: 700
|
||||
popupWidth: SettingsData.showWeekNumber ? 736 : 700
|
||||
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 500
|
||||
triggerWidth: 80
|
||||
screen: triggerScreen
|
||||
@@ -168,6 +168,7 @@ DankPopout {
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
implicitWidth: Math.max(700, pages.implicitWidth + (Theme.spacingM * 2))
|
||||
implicitHeight: contentColumn.height + Theme.spacingM * 2
|
||||
color: "transparent"
|
||||
focus: true
|
||||
@@ -316,6 +317,7 @@ DankPopout {
|
||||
id: pages
|
||||
width: parent.width
|
||||
height: implicitHeight
|
||||
implicitWidth: currentItem && currentItem.implicitWidth > 0 ? currentItem.implicitWidth : (700 - Theme.spacingM * 2)
|
||||
implicitHeight: {
|
||||
if (root.currentTabIndex === 0)
|
||||
return overviewLoader.item?.implicitHeight ?? 410;
|
||||
|
||||
@@ -105,7 +105,7 @@ Item {
|
||||
return Math.max(0, Math.min(1, calculatedRatio));
|
||||
}
|
||||
|
||||
implicitWidth: 700
|
||||
implicitWidth: SettingsData.showWeekNumber ? 736 : 700
|
||||
implicitHeight: playerContent.height + playerContent.anchors.topMargin * 2
|
||||
|
||||
Connections {
|
||||
|
||||
@@ -7,6 +7,8 @@ import qs.Widgets
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
implicitWidth: SettingsData.showWeekNumber ? 736 : 700
|
||||
|
||||
property bool showEventDetails: false
|
||||
property date selectedDate: systemClock.date
|
||||
property var selectedDateEvents: []
|
||||
@@ -41,6 +43,40 @@ Rectangle {
|
||||
return d;
|
||||
}
|
||||
|
||||
function getWeekNumber(dateObj) {
|
||||
// Set time to noon to avoid potential Daylight Saving Time related bugs
|
||||
const weekStartDay = startOfWeek(dateObj);
|
||||
weekStartDay.setHours(12, 0, 0, 0);
|
||||
|
||||
let week1Start;
|
||||
|
||||
if (weekStartJs() === 1) {
|
||||
// ISO 8601 Standard, week start on Monday
|
||||
// A week belongs to the year its Thursday falls in
|
||||
// So we have to get the yearTarget from weekStartDay instead of dateObj
|
||||
let yearTarget = weekStartDay;
|
||||
yearTarget.setDate(yearTarget.getDate() + 3); // Monday + 3 = Thursday
|
||||
|
||||
// Week 1 is the week containing Jan 4th
|
||||
const jan4 = new Date(yearTarget.getFullYear(), 0, 4);
|
||||
week1Start = startOfWeek(jan4);
|
||||
} else {
|
||||
// Traditional / US Standard, week start on Sunday
|
||||
// A week belongs to the year its Sunday falls in
|
||||
let yearTarget = weekStartDay;
|
||||
yearTarget.setDate(yearTarget.getDate() + 6); // Monday + 6 = Sunday
|
||||
|
||||
// Week 1 is the week containing Jan 1st
|
||||
const jan1 = new Date(yearTarget.getFullYear(), 0, 1);
|
||||
week1Start = startOfWeek(jan1);
|
||||
}
|
||||
|
||||
week1Start.setHours(12, 0, 0, 0);
|
||||
|
||||
const diffDays = Math.round((weekStartDay.getTime() - week1Start.getTime()) / 86400000); // Number of miliseconds in a day
|
||||
return Math.floor(diffDays / 7) + 1;
|
||||
}
|
||||
|
||||
function updateSelectedDateEvents() {
|
||||
if (CalendarService && CalendarService.khalAvailable) {
|
||||
const events = CalendarService.getEventsForDate(selectedDate);
|
||||
@@ -151,6 +187,7 @@ Rectangle {
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 28
|
||||
@@ -224,120 +261,172 @@ Rectangle {
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 18
|
||||
height: parent.height - 28 - Theme.spacingS
|
||||
visible: !showEventDetails
|
||||
spacing: SettingsData.showWeekNumber ? Theme.spacingS : 0
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
const days = [];
|
||||
const qtFirst = weekStartQt();
|
||||
for (let i = 0; i < 7; ++i) {
|
||||
const qtDay = ((qtFirst - 1 + i) % 7) + 1;
|
||||
days.push(I18n.locale().dayName(qtDay, Locale.ShortFormat));
|
||||
}
|
||||
return days;
|
||||
}
|
||||
Column {
|
||||
id: weekNumberColumn
|
||||
visible: SettingsData.showWeekNumber
|
||||
width: SettingsData.showWeekNumber ? 28 : 0
|
||||
height: parent.height
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
width: parent.width / 7
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 18
|
||||
color: "transparent"
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: modelData
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
font.weight: Font.Medium
|
||||
Grid {
|
||||
width: parent.width
|
||||
height: parent.height - 18 - Theme.spacingS
|
||||
columns: 1
|
||||
rows: 6
|
||||
|
||||
Repeater {
|
||||
model: 6
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: parent.height / 6
|
||||
color: "transparent"
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: {
|
||||
const rowDate = new Date(calendarGrid.firstDay);
|
||||
rowDate.setDate(rowDate.getDate() + index * 7);
|
||||
return root.getWeekNumber(rowDate);
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Grid {
|
||||
id: calendarGrid
|
||||
visible: !showEventDetails
|
||||
Column {
|
||||
width: SettingsData.showWeekNumber ? (parent.width - weekNumberColumn.width - parent.spacing) : parent.width
|
||||
height: parent.height
|
||||
spacing: Theme.spacingS
|
||||
|
||||
property date displayDate: systemClock.date
|
||||
property date selectedDate: systemClock.date
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 18
|
||||
|
||||
readonly property date firstDay: {
|
||||
const firstOfMonth = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1);
|
||||
return startOfWeek(firstOfMonth);
|
||||
}
|
||||
|
||||
width: parent.width
|
||||
height: parent.height - 28 - 18 - Theme.spacingS * 2
|
||||
columns: 7
|
||||
rows: 6
|
||||
|
||||
Repeater {
|
||||
model: 42
|
||||
|
||||
Rectangle {
|
||||
readonly property date dayDate: {
|
||||
const date = new Date(parent.firstDay);
|
||||
date.setDate(date.getDate() + index);
|
||||
return date;
|
||||
}
|
||||
readonly property bool isCurrentMonth: dayDate.getMonth() === calendarGrid.displayDate.getMonth()
|
||||
readonly property bool isToday: dayDate.toDateString() === new Date().toDateString()
|
||||
readonly property bool isSelected: dayDate.toDateString() === calendarGrid.selectedDate.toDateString()
|
||||
|
||||
width: parent.width / 7
|
||||
height: parent.height / 6
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: Math.min(parent.width - 4, parent.height - 4, 32)
|
||||
height: width
|
||||
color: isToday ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : dayArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: dayDate.getDate()
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: isToday ? Theme.primary : isCurrentMonth ? Theme.surfaceText : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4)
|
||||
font.weight: isToday ? Font.Medium : Font.Normal
|
||||
Repeater {
|
||||
model: {
|
||||
const days = [];
|
||||
const qtFirst = weekStartQt();
|
||||
for (let i = 0; i < 7; ++i) {
|
||||
const qtDay = ((qtFirst - 1 + i) % 7) + 1;
|
||||
days.push(I18n.locale().dayName(qtDay, Locale.ShortFormat));
|
||||
}
|
||||
return days;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottomMargin: 4
|
||||
width: 12
|
||||
height: 2
|
||||
radius: Theme.cornerRadius
|
||||
visible: CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate)
|
||||
color: isToday ? Qt.lighter(Theme.primary, 1.3) : Theme.primary
|
||||
opacity: isToday ? 0.9 : 0.7
|
||||
width: parent.width / 7
|
||||
height: 18
|
||||
color: "transparent"
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: modelData
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Grid {
|
||||
id: calendarGrid
|
||||
width: parent.width
|
||||
height: parent.height - 18 - Theme.spacingS
|
||||
columns: 7
|
||||
rows: 6
|
||||
|
||||
property date displayDate: systemClock.date
|
||||
property date selectedDate: systemClock.date
|
||||
|
||||
readonly property date firstDay: {
|
||||
const firstOfMonth = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1);
|
||||
return startOfWeek(firstOfMonth);
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: 42
|
||||
|
||||
Rectangle {
|
||||
readonly property date dayDate: {
|
||||
const date = new Date(parent.firstDay);
|
||||
date.setDate(date.getDate() + index);
|
||||
return date;
|
||||
}
|
||||
readonly property bool isCurrentMonth: dayDate.getMonth() === calendarGrid.displayDate.getMonth()
|
||||
readonly property bool isToday: dayDate.toDateString() === new Date().toDateString()
|
||||
readonly property bool isSelected: dayDate.toDateString() === calendarGrid.selectedDate.toDateString()
|
||||
|
||||
width: parent.width / 7
|
||||
height: parent.height / 6
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: Math.min(parent.width - 4, parent.height - 4, 32)
|
||||
height: width
|
||||
color: isToday ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : dayArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: dayDate.getDate()
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: isToday ? Theme.primary : isCurrentMonth ? Theme.surfaceText : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4)
|
||||
font.weight: isToday ? Font.Medium : Font.Normal
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottomMargin: 4
|
||||
width: 12
|
||||
height: 2
|
||||
radius: Theme.cornerRadius
|
||||
visible: CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate)
|
||||
color: isToday ? Qt.lighter(Theme.primary, 1.3) : Theme.primary
|
||||
opacity: isToday ? 0.9 : 0.7
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: dayArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate)) {
|
||||
root.selectedDate = dayDate;
|
||||
root.showEventDetails = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: dayArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate)) {
|
||||
root.selectedDate = dayDate;
|
||||
root.showEventDetails = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankListView {
|
||||
width: parent.width - Theme.spacingS * 2
|
||||
height: parent.height - (showEventDetails ? 40 : 28 + 18) - Theme.spacingS
|
||||
|
||||
@@ -8,7 +8,7 @@ Item {
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
implicitWidth: 700
|
||||
implicitWidth: SettingsData.showWeekNumber ? 736 : 700
|
||||
implicitHeight: 410
|
||||
|
||||
signal switchToWeatherTab
|
||||
|
||||
@@ -12,7 +12,7 @@ Item {
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
implicitWidth: 700
|
||||
implicitWidth: SettingsData.showWeekNumber ? 736 : 700
|
||||
implicitHeight: 410
|
||||
|
||||
property string wallpaperDir: ""
|
||||
|
||||
@@ -11,7 +11,7 @@ Item {
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
implicitWidth: 700
|
||||
implicitWidth: SettingsData.showWeekNumber ? 736 : 700
|
||||
implicitHeight: 410
|
||||
property bool syncing: false
|
||||
property bool showHourly: false
|
||||
|
||||
@@ -85,6 +85,16 @@ Item {
|
||||
settingKey: "dateFormat"
|
||||
iconName: "calendar_today"
|
||||
|
||||
SettingsToggleRow {
|
||||
tab: "time"
|
||||
tags: ["show", "week"]
|
||||
settingKey: "showWeekNumber"
|
||||
text: I18n.tr("Show Week Number")
|
||||
description: I18n.tr("Show week number in the calendar")
|
||||
checked: SettingsData.showWeekNumber
|
||||
onToggled: checked => SettingsData.set("showWeekNumber", checked)
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
tab: "time"
|
||||
tags: ["first", "day", "week"]
|
||||
|
||||
Reference in New Issue
Block a user