diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index a3318920..807f4fb4 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -631,6 +631,14 @@ "week-numbers": { "label": "Wochennummern anzeigen", "description": "Zeigt die Woche des Jahres (z.B. Woche 38) im Kalender an." + }, + "first-day-of-week": { + "label": "Erster Tag der Woche", + "description": "Wählen Sie, welcher Tag die Kalenderwoche beginnt.", + "auto": "Systemstandard", + "monday": "Montag", + "saturday": "Samstag", + "sunday": "Sonntag" } } }, diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index cbad3dd8..765201aa 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -631,6 +631,14 @@ "week-numbers": { "label": "Show week numbers", "description": "Displays the week of the year (e.g., Week 38) in the calendar." + }, + "first-day-of-week": { + "label": "First day of week", + "description": "Choose which day starts the calendar week.", + "auto": "System default", + "monday": "Monday", + "saturday": "Saturday", + "sunday": "Sunday" } } }, diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index 2db6da8f..0a4f77f4 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -624,6 +624,14 @@ "week-numbers": { "label": "Mostrar números de semana", "description": "Muestra la semana del año (ej., Semana 38) en el calendario." + }, + "first-day-of-week": { + "label": "Primer día de la semana", + "description": "Elige qué día comienza la semana del calendario.", + "auto": "Predeterminado del sistema", + "monday": "Lunes", + "saturday": "Sábado", + "sunday": "Domingo" } } }, diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index 8131592a..eb401542 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -624,6 +624,14 @@ "week-numbers": { "label": "Afficher les numéros de semaine", "description": "Affiche la semaine de l'année (ex: Semaine 38) dans le calendrier." + }, + "first-day-of-week": { + "label": "Premier jour de la semaine", + "description": "Choisissez quel jour commence la semaine du calendrier.", + "auto": "Par défaut du système", + "monday": "Lundi", + "saturday": "Samedi", + "sunday": "Dimanche" } } }, diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index dd3fe7f0..cdd14da2 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -586,6 +586,14 @@ "week-numbers": { "label": "Mostrar números da semana", "description": "Exibe a semana do ano (ex., Semana 38) no calendário." + }, + "first-day-of-week": { + "label": "Primeiro dia da semana", + "description": "Escolha qual dia inicia a semana do calendário.", + "auto": "Padrão do sistema", + "monday": "Segunda-feira", + "saturday": "Sábado", + "sunday": "Domingo" } } }, diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index 4738030b..427e7c41 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -624,6 +624,14 @@ "week-numbers": { "label": "显示周数", "description": "在日历中显示一年中的第几周(例如:第 38 周)。" + }, + "first-day-of-week": { + "label": "每周第一天", + "description": "选择日历每周的起始日。", + "auto": "系统默认", + "monday": "星期一", + "saturday": "星期六", + "sunday": "星期日" } } }, diff --git a/Assets/settings-default.json b/Assets/settings-default.json index 57033237..6e1b77a2 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -74,7 +74,8 @@ "weatherEnabled": true, "useFahrenheit": false, "use12hourFormat": false, - "showWeekNumberInCalendar": false + "showWeekNumberInCalendar": false, + "firstDayOfWeek": "auto" }, "screenRecorder": { "directory": "", diff --git a/Commons/I18n.qml b/Commons/I18n.qml index 4ec5e86f..59eeb922 100644 --- a/Commons/I18n.qml +++ b/Commons/I18n.qml @@ -8,7 +8,6 @@ import qs.Commons Singleton { id: root - property bool isLoaded: false property string langCode: "" property string systemDetectedLangCode: "" diff --git a/Commons/Settings.qml b/Commons/Settings.qml index f98e3e3e..236277b1 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -202,6 +202,7 @@ Singleton { property bool useFahrenheit: false property bool use12hourFormat: false property bool showWeekNumberInCalendar: false + property string firstDayOfWeek: "auto" // "auto", "monday", "saturday", "sunday" } // screen recorder diff --git a/Modules/Bar/Calendar/CalendarPanel.qml b/Modules/Bar/Calendar/CalendarPanel.qml index b882324d..3b8bdd45 100644 --- a/Modules/Bar/Calendar/CalendarPanel.qml +++ b/Modules/Bar/Calendar/CalendarPanel.qml @@ -22,7 +22,24 @@ NPanel { anchors.margins: Style.marginL spacing: Style.marginM - readonly property int firstDayOfWeek: Qt.locale().firstDayOfWeek + readonly property int firstDayOfWeek: { + var setting = Settings.data.location.firstDayOfWeek + if (!setting) + return Qt.Monday + + switch (setting) { + case "auto": + return Qt.locale().firstDayOfWeek + case "monday": + return Qt.Monday + case "saturday": + return 6 // Qt.Saturday + case "sunday": + return Qt.Sunday + default: + return Qt.Monday + } + } property bool isCurrentMonth: checkIsCurrentMonth() readonly property bool weatherReady: Settings.data.location.weatherEnabled && (LocationService.data.weather !== null) @@ -278,7 +295,7 @@ NPanel { } } - // ... (rest of the file is unchanged) ... + // Weather forecast RowLayout { visible: weatherReady Layout.fillWidth: true @@ -446,38 +463,88 @@ NPanel { } } } - MonthGrid { + GridLayout { id: grid Layout.fillWidth: true Layout.fillHeight: true - spacing: Style.marginXXS - month: Time.date.getMonth() - year: Time.date.getFullYear() - locale: Qt.locale() - delegate: Item { - Rectangle { - width: Style.baseWidgetSize * 0.9 - height: Style.baseWidgetSize * 0.9 - anchors.centerIn: parent - radius: Style.radiusM - color: model.today ? Color.mSecondary : Color.transparent - NText { - anchors.centerIn: parent - text: model.day - color: { - if (model.today) - return Color.mOnSecondary - if (model.month === grid.month) - return Color.mOnSurface - return Color.mOnSurfaceVariant - } - opacity: model.month === grid.month ? 1.0 : 0.4 - pointSize: Style.fontSizeM - font.weight: model.today ? Style.fontWeightBold : Style.fontWeightMedium + columns: 7 + rowSpacing: Style.marginXXS + columnSpacing: Style.marginXXS + + property int month: Time.date.getMonth() + property int year: Time.date.getFullYear() + + Repeater { + model: 42 // 6 rows × 7 days + delegate: Item { + id: cellItem + Layout.fillWidth: true + Layout.fillHeight: true + + required property int index + + property int cellDay: { + let firstOfMonth = new Date(grid.year, grid.month, 1) + let firstDayOfWeek = content.firstDayOfWeek + let firstOfMonthDayOfWeek = firstOfMonth.getDay() + let daysBeforeFirst = (firstOfMonthDayOfWeek - firstDayOfWeek + 7) % 7 + let startDate = new Date(grid.year, grid.month, 1 - daysBeforeFirst) + let currentDate = new Date(startDate) + currentDate.setDate(startDate.getDate() + cellItem.index) + return currentDate.getDate() } - Behavior on color { - ColorAnimation { - duration: Style.animationFast + + property int cellMonth: { + let firstOfMonth = new Date(grid.year, grid.month, 1) + let firstDayOfWeek = content.firstDayOfWeek + let firstOfMonthDayOfWeek = firstOfMonth.getDay() + let daysBeforeFirst = (firstOfMonthDayOfWeek - firstDayOfWeek + 7) % 7 + let startDate = new Date(grid.year, grid.month, 1 - daysBeforeFirst) + let currentDate = new Date(startDate) + currentDate.setDate(startDate.getDate() + cellItem.index) + return currentDate.getMonth() + } + + property int cellYear: { + let firstOfMonth = new Date(grid.year, grid.month, 1) + let firstDayOfWeek = content.firstDayOfWeek + let firstOfMonthDayOfWeek = firstOfMonth.getDay() + let daysBeforeFirst = (firstOfMonthDayOfWeek - firstDayOfWeek + 7) % 7 + let startDate = new Date(grid.year, grid.month, 1 - daysBeforeFirst) + let currentDate = new Date(startDate) + currentDate.setDate(startDate.getDate() + cellItem.index) + return currentDate.getFullYear() + } + + property bool isToday: cellDay === Time.date.getDate() && cellMonth === Time.date.getMonth() && cellYear === Time.date.getFullYear() + property bool isCurrentMonth: cellMonth === grid.month + + Rectangle { + width: Style.baseWidgetSize * 0.9 + height: Style.baseWidgetSize * 0.9 + anchors.centerIn: parent + radius: Style.radiusM + color: parent.isToday ? Color.mSecondary : Color.transparent + + NText { + anchors.centerIn: parent + text: cellItem.cellDay + color: { + if (cellItem.isToday) + return Color.mOnSecondary + if (cellItem.isCurrentMonth) + return Color.mOnSurface + return Color.mOnSurfaceVariant + } + opacity: cellItem.isCurrentMonth ? 1.0 : 0.5 + pointSize: Style.fontSizeM + font.weight: cellItem.isToday ? Style.fontWeightBold : Style.fontWeightSemiBold + } + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + } } } } diff --git a/Modules/Settings/Tabs/GeneralTab.qml b/Modules/Settings/Tabs/GeneralTab.qml index 40b5276d..4f084445 100644 --- a/Modules/Settings/Tabs/GeneralTab.qml +++ b/Modules/Settings/Tabs/GeneralTab.qml @@ -204,20 +204,24 @@ ColumnLayout { Layout.fillWidth: true label: I18n.tr("settings.general.language.select.label") description: I18n.tr("settings.general.language.select.description") - model: [ - { "key": "", "name": I18n.tr("settings.general.language.select.auto-detect") + " (" + I18n.systemDetectedLangCode + ")" } - ].concat(I18n.availableLanguages.map(function(langCode) { - return { "key": langCode, "name": langCode } - })) + model: [{ + "key": "", + "name": I18n.tr("settings.general.language.select.auto-detect") + " (" + I18n.systemDetectedLangCode + ")" + }].concat(I18n.availableLanguages.map(function (langCode) { + return { + "key": langCode, + "name": langCode + } + })) currentKey: Settings.data.general.language onSelected: key => { - Settings.data.general.language = key - if (key === "") { - I18n.detectLanguage() // Re-detect system language if "Automatic" is selected - } else { - I18n.setLanguage(key) // Set specific language - } - } + Settings.data.general.language = key + if (key === "") { + I18n.detectLanguage() // Re-detect system language if "Automatic" is selected + } else { + I18n.setLanguage(key) // Set specific language + } + } } } diff --git a/Modules/Settings/Tabs/LocationTab.qml b/Modules/Settings/Tabs/LocationTab.qml index 7b6c340b..0fb7f8a2 100644 --- a/Modules/Settings/Tabs/LocationTab.qml +++ b/Modules/Settings/Tabs/LocationTab.qml @@ -117,6 +117,27 @@ ColumnLayout { checked: Settings.data.location.showWeekNumberInCalendar onToggled: checked => Settings.data.location.showWeekNumberInCalendar = checked } + + NComboBox { + label: I18n.tr("settings.location.date-time.first-day-of-week.label") + description: I18n.tr("settings.location.date-time.first-day-of-week.description") + minimumWidth: 220 * Style.uiScaleRatio + model: [{ + "key": "auto", + "name": I18n.tr("settings.location.date-time.first-day-of-week.auto") + }, { + "key": "monday", + "name": I18n.tr("settings.location.date-time.first-day-of-week.monday") + }, { + "key": "saturday", + "name": I18n.tr("settings.location.date-time.first-day-of-week.saturday") + }, { + "key": "sunday", + "name": I18n.tr("settings.location.date-time.first-day-of-week.sunday") + }] + currentKey: Settings.data.location.firstDayOfWeek + onSelected: key => Settings.data.location.firstDayOfWeek = key + } } NDivider {