Compare commits
4 Commits
v2.15.0
...
release/v2
| Author | SHA1 | Date | |
|---|---|---|---|
| 60938af9f0 | |||
| accf0ac142 | |||
| f90badfcd5 | |||
| 249606a358 |
23
CHANGELOG.md
23
CHANGELOG.md
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2.16.0] — 2026-07-17
|
||||
|
||||
### Changed
|
||||
- Dates in the Month, Week and Day title bars now follow your language and
|
||||
region instead of one hardcoded layout. Every date was rendered in a fixed
|
||||
German-style order with a trailing dot on the day number, whatever your
|
||||
settings: US English showed "Fri, 17. Jul 2026" where it should read
|
||||
"Fri, Jul 17". The Agenda view already formatted correctly, so the two
|
||||
disagreed about the same date. All four views now share one formatter, and the
|
||||
day/month order, the separators and the ordinal all come from your locale —
|
||||
so English-in-Germany reads "Fri, 17 Jul" and English-in-the-US "Fri, Jul 17",
|
||||
each correct for where you are ([#60]).
|
||||
- The title bar drops the year while you're in the current one — "July" rather
|
||||
than "July 2026". The year reappears the moment you page out of the current
|
||||
year, which is when it tells you something you didn't already know.
|
||||
- The Week view's title now names the month instead of spelling out the day range.
|
||||
"24. Jun – 31. Jun" restated the day numbers already printed in the column
|
||||
headers right below it, in the widest string in the bar. A week that straddles
|
||||
two months keeps the outgoing month until it is fully gone ([#60]).
|
||||
|
||||
## [2.15.0] — 2026-07-15
|
||||
|
||||
### Added
|
||||
@@ -997,3 +1019,4 @@ automatically, with zero telemetry and no internet permission.
|
||||
[#48]: https://codeberg.org/jlmakiola/calendula/issues/48
|
||||
[#49]: https://codeberg.org/jlmakiola/calendula/issues/49
|
||||
[#52]: https://codeberg.org/jlmakiola/calendula/issues/52
|
||||
[#60]: https://codeberg.org/jlmakiola/calendula/issues/60
|
||||
|
||||
@@ -28,8 +28,8 @@ android {
|
||||
// which builds this version and then creates the matching vX.Y.Z tag +
|
||||
// release itself (versionCode is pinned to MAJOR*10000 + MINOR*100 +
|
||||
// PATCH from versionName, e.g. 2.7.2 -> 20702). See docs/RELEASING.md.
|
||||
versionCode = 21500
|
||||
versionName = "2.15.0"
|
||||
versionCode = 21600
|
||||
versionName = "2.16.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package de.jeanlucmakiola.calendula.ui.agenda
|
||||
|
||||
import de.jeanlucmakiola.calendula.ui.common.localizedDateFormatter
|
||||
import de.jeanlucmakiola.floret.locale.localizedDateFormatter
|
||||
import kotlinx.datetime.DayOfWeek
|
||||
import kotlinx.datetime.LocalDate
|
||||
import java.time.YearMonth
|
||||
|
||||
@@ -68,7 +68,7 @@ import de.jeanlucmakiola.calendula.ui.common.CalendarFabColumn
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFailure
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
||||
import de.jeanlucmakiola.calendula.ui.common.IMPLEMENTED_VIEWS
|
||||
import de.jeanlucmakiola.calendula.ui.common.localizedDateFormatter
|
||||
import de.jeanlucmakiola.floret.locale.localizedDateFormatter
|
||||
import de.jeanlucmakiola.calendula.ui.common.EventDimAlpha
|
||||
import de.jeanlucmakiola.floret.components.GroupedRow
|
||||
import de.jeanlucmakiola.floret.components.Position
|
||||
@@ -76,7 +76,7 @@ import de.jeanlucmakiola.calendula.ui.common.ViewSwitcherPill
|
||||
import de.jeanlucmakiola.calendula.ui.common.next
|
||||
import de.jeanlucmakiola.floret.components.positionOf
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberCurrentMinute
|
||||
import de.jeanlucmakiola.calendula.ui.common.currentLocale
|
||||
import de.jeanlucmakiola.floret.locale.currentLocale
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalUse24HourFormat
|
||||
import de.jeanlucmakiola.calendula.ui.common.formatTimeOfDay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package de.jeanlucmakiola.calendula.ui.common
|
||||
|
||||
import de.jeanlucmakiola.floret.locale.localizedDateFormatter
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Formats a calendar title (top bar or widget header): [skeleton]'s fields laid
|
||||
* out in [locale]'s own order, with the year shown only when [date] falls outside
|
||||
* [currentYear].
|
||||
*
|
||||
* Pass [skeleton] *without* a year field — "LLLL" for a month, "EEEdMMM" for a
|
||||
* day. A skeleton is a field list, so wanting the year is just asking for one
|
||||
* more field; the locale still decides where it lands ("July 2026" vs "2026年7月").
|
||||
*
|
||||
* Dropping the year in the current year is the one bit of policy here: the title
|
||||
* sits directly above a grid that already says which year it is, and the year's
|
||||
* *absence* is itself the signal that you're in the current one — it appears the
|
||||
* moment you page out of it, which is when it starts carrying information.
|
||||
*/
|
||||
fun formatCalendarTitle(
|
||||
date: java.time.LocalDate,
|
||||
locale: Locale,
|
||||
currentYear: Int,
|
||||
skeleton: String,
|
||||
): String {
|
||||
val fields = if (date.year == currentYear) skeleton else skeleton + "y"
|
||||
return localizedDateFormatter(locale, fields).format(date)
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package de.jeanlucmakiola.calendula.ui.common
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.core.os.ConfigurationCompat
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Current display [Locale], read observably from [LocalConfiguration] so the UI
|
||||
* recomposes after a locale change (lint: NonObservableLocale). Used for
|
||||
* weekday/month name formatting.
|
||||
*/
|
||||
@Composable
|
||||
fun currentLocale(): Locale {
|
||||
val configuration = LocalConfiguration.current
|
||||
return remember(configuration) {
|
||||
ConfigurationCompat.getLocales(configuration).get(0) ?: Locale.getDefault()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A [DateTimeFormatter] for [skeleton]'s fields laid out in [locale]'s own order
|
||||
* (via Android's best-pattern matching), so dates read naturally per locale
|
||||
* instead of a hardcoded day-month-year order. [skeleton] lists the wanted
|
||||
* fields, e.g. "dMMMy" (day, abbreviated month, year) or "EEEdMMM" (weekday too).
|
||||
*/
|
||||
fun localizedDateFormatter(locale: Locale, skeleton: String): DateTimeFormatter =
|
||||
DateTimeFormatter.ofPattern(
|
||||
android.text.format.DateFormat.getBestDateTimePattern(locale, skeleton),
|
||||
locale,
|
||||
)
|
||||
@@ -68,6 +68,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import de.jeanlucmakiola.calendula.R
|
||||
import de.jeanlucmakiola.calendula.domain.EventInstance
|
||||
import de.jeanlucmakiola.calendula.ui.common.formatCalendarTitle
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarDrawer
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFabColumn
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFailure
|
||||
@@ -83,7 +84,7 @@ import de.jeanlucmakiola.calendula.ui.common.LocalSoftenColors
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventFill
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventInk
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberCalendarSlideSpec
|
||||
import de.jeanlucmakiola.calendula.ui.common.currentLocale
|
||||
import de.jeanlucmakiola.floret.locale.currentLocale
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalUse24HourFormat
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalShowHourLines
|
||||
import de.jeanlucmakiola.calendula.ui.common.formatHourLabel
|
||||
@@ -93,7 +94,9 @@ import de.jeanlucmakiola.calendula.ui.week.TimedBlock
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.datetime.LocalDate
|
||||
import java.time.format.TextStyle as JavaTextStyle
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import kotlin.time.Clock
|
||||
import java.util.Locale
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@@ -157,6 +160,13 @@ fun DayScreen(
|
||||
else -> true
|
||||
}
|
||||
|
||||
// Drives whether the title carries the year. Falls back to the clock only
|
||||
// while the first load is in flight, when there is no state to read today from.
|
||||
val currentYear = when (val s = state) {
|
||||
is DayUiState.Success -> s.today.year
|
||||
else -> Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date.year
|
||||
}
|
||||
|
||||
// Slide direction for the day transition: +1 = next, -1 = prev, 0 = jump.
|
||||
var slideDir by remember { mutableIntStateOf(0) }
|
||||
val goNext = { slideDir = 1; viewModel.goToNext() }
|
||||
@@ -205,6 +215,7 @@ fun DayScreen(
|
||||
topBar = {
|
||||
DayTopBar(
|
||||
date = date,
|
||||
currentYear = currentYear,
|
||||
selectedView = selectedView,
|
||||
onCycleView = { onSelectView(selectedView.next(quickSwitchViews)) },
|
||||
onOpenDrawer = { scope.launch { drawerState.open() } },
|
||||
@@ -360,16 +371,18 @@ private fun DaySuccess(
|
||||
@Composable
|
||||
private fun DayTopBar(
|
||||
date: LocalDate,
|
||||
currentYear: Int,
|
||||
selectedView: CalendarView,
|
||||
onCycleView: () -> Unit,
|
||||
onOpenDrawer: () -> Unit,
|
||||
onOpenSearch: () -> Unit,
|
||||
scrollBehavior: androidx.compose.material3.TopAppBarScrollBehavior,
|
||||
) {
|
||||
val locale = currentLocale()
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
text = formatDayTitle(date),
|
||||
text = formatDayTitle(date, locale, currentYear),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
)
|
||||
},
|
||||
@@ -669,10 +682,10 @@ private fun DayLoading() {
|
||||
private fun minToHm(min: Int, is24Hour: Boolean, locale: Locale): String =
|
||||
formatMinuteOfDay(min, is24Hour, locale)
|
||||
|
||||
private fun formatDayTitle(date: LocalDate): String {
|
||||
val locale = Locale.getDefault()
|
||||
val java = java.time.LocalDate.of(date.year, date.month.ordinal + 1, date.day)
|
||||
val weekday = java.dayOfWeek.getDisplayName(JavaTextStyle.SHORT, locale)
|
||||
val monthName = java.month.getDisplayName(JavaTextStyle.SHORT, locale)
|
||||
return "$weekday, ${date.day}. $monthName ${date.year}"
|
||||
}
|
||||
private fun formatDayTitle(date: LocalDate, locale: Locale, currentYear: Int): String =
|
||||
formatCalendarTitle(
|
||||
date = java.time.LocalDate.of(date.year, date.month.ordinal + 1, date.day),
|
||||
locale = locale,
|
||||
currentYear = currentYear,
|
||||
skeleton = "EEEdMMM",
|
||||
)
|
||||
|
||||
@@ -98,7 +98,7 @@ import de.jeanlucmakiola.calendula.ui.common.CalendarFailure
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalSoftenColors
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventFill
|
||||
import de.jeanlucmakiola.floret.components.OptionCard
|
||||
import de.jeanlucmakiola.calendula.ui.common.currentLocale
|
||||
import de.jeanlucmakiola.floret.locale.currentLocale
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalUse24HourFormat
|
||||
import de.jeanlucmakiola.calendula.ui.common.timeOfDayFormatter
|
||||
import de.jeanlucmakiola.calendula.ui.common.recurrenceText
|
||||
|
||||
@@ -143,7 +143,7 @@ import de.jeanlucmakiola.floret.components.positionOf
|
||||
import de.jeanlucmakiola.calendula.ui.common.REMINDER_PRESETS
|
||||
import de.jeanlucmakiola.calendula.ui.common.TimePickerAlert
|
||||
import de.jeanlucmakiola.floret.reminders.ReminderUnit
|
||||
import de.jeanlucmakiola.calendula.ui.common.currentLocale
|
||||
import de.jeanlucmakiola.floret.locale.currentLocale
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalUse24HourFormat
|
||||
import de.jeanlucmakiola.calendula.ui.common.timeOfDayFormatter
|
||||
import de.jeanlucmakiola.calendula.ui.common.reminderLeadTimeLabel
|
||||
|
||||
@@ -64,6 +64,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import de.jeanlucmakiola.calendula.R
|
||||
import de.jeanlucmakiola.calendula.domain.hasEnded
|
||||
import de.jeanlucmakiola.calendula.ui.common.formatCalendarTitle
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarDrawer
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFabColumn
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFailure
|
||||
@@ -79,7 +80,7 @@ import de.jeanlucmakiola.calendula.ui.common.ViewSwitcherPill
|
||||
import de.jeanlucmakiola.calendula.ui.common.calendarSlideTransition
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberCalendarFadeSpec
|
||||
import de.jeanlucmakiola.floret.identity.rememberReduceMotion
|
||||
import de.jeanlucmakiola.calendula.ui.common.currentLocale
|
||||
import de.jeanlucmakiola.floret.locale.currentLocale
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberCalendarSlideSpec
|
||||
import de.jeanlucmakiola.calendula.ui.common.next
|
||||
import de.jeanlucmakiola.floret.time.isoWeekNumber
|
||||
@@ -130,6 +131,13 @@ fun MonthScreen(
|
||||
else -> true
|
||||
}
|
||||
|
||||
// Drives whether the title carries the year. Falls back to the clock only
|
||||
// while the first load is in flight, when there is no state to read today from.
|
||||
val currentYear = when (val s = state) {
|
||||
is MonthUiState.Success -> s.today.year
|
||||
else -> Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date.year
|
||||
}
|
||||
|
||||
// Slide direction for the grid transition: +1 = next, -1 = prev, 0 = jump (no slide).
|
||||
var slideDir by remember { mutableIntStateOf(0) }
|
||||
|
||||
@@ -186,6 +194,7 @@ fun MonthScreen(
|
||||
topBar = {
|
||||
MonthTopBar(
|
||||
month = month,
|
||||
currentYear = currentYear,
|
||||
selectedView = selectedView,
|
||||
onCycleView = { onSelectView(selectedView.next(quickSwitchViews)) },
|
||||
onOpenDrawer = { scope.launch { drawerState.open() } },
|
||||
@@ -294,16 +303,18 @@ private fun MonthContent(
|
||||
@Composable
|
||||
private fun MonthTopBar(
|
||||
month: YearMonth,
|
||||
currentYear: Int,
|
||||
selectedView: CalendarView,
|
||||
onCycleView: () -> Unit,
|
||||
onOpenDrawer: () -> Unit,
|
||||
onOpenSearch: () -> Unit,
|
||||
scrollBehavior: androidx.compose.material3.TopAppBarScrollBehavior,
|
||||
) {
|
||||
val locale = currentLocale()
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
text = formatMonthYear(month),
|
||||
text = formatMonthTitle(month, locale, currentYear),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
)
|
||||
},
|
||||
@@ -732,9 +743,10 @@ private fun MonthGridLoading() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatMonthYear(ym: YearMonth): String {
|
||||
val locale = Locale.getDefault()
|
||||
val name = java.time.Month.of(ym.month.ordinal + 1)
|
||||
.getDisplayName(JavaTextStyle.FULL, locale)
|
||||
return "$name ${ym.year}"
|
||||
}
|
||||
private fun formatMonthTitle(ym: YearMonth, locale: Locale, currentYear: Int): String =
|
||||
formatCalendarTitle(
|
||||
date = java.time.LocalDate.of(ym.year, ym.month.ordinal + 1, 1),
|
||||
locale = locale,
|
||||
currentYear = currentYear,
|
||||
skeleton = "LLLL",
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ import de.jeanlucmakiola.floret.identity.predictiveBack
|
||||
import de.jeanlucmakiola.floret.components.GroupedRow
|
||||
import de.jeanlucmakiola.floret.components.InlineTextField
|
||||
import de.jeanlucmakiola.floret.components.Position
|
||||
import de.jeanlucmakiola.calendula.ui.common.currentLocale
|
||||
import de.jeanlucmakiola.floret.locale.currentLocale
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalSoftenColors
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventFill
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalUse24HourFormat
|
||||
|
||||
@@ -135,7 +135,7 @@ import de.jeanlucmakiola.floret.components.positionOf
|
||||
import de.jeanlucmakiola.calendula.ui.common.reminderLeadTimeLabel
|
||||
import de.jeanlucmakiola.calendula.ui.common.SnoozeDurationPicker
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberCalendarSlideSpec
|
||||
import de.jeanlucmakiola.calendula.ui.common.currentLocale
|
||||
import de.jeanlucmakiola.floret.locale.currentLocale
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventFormFieldIcon
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventFormFieldLabel
|
||||
import de.jeanlucmakiola.calendula.ui.theme.BundledFont
|
||||
|
||||
@@ -77,6 +77,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import de.jeanlucmakiola.calendula.R
|
||||
import de.jeanlucmakiola.calendula.domain.EventInstance
|
||||
import de.jeanlucmakiola.calendula.domain.hasEnded
|
||||
import de.jeanlucmakiola.calendula.ui.common.formatCalendarTitle
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarDrawer
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFabColumn
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFailure
|
||||
@@ -93,7 +94,7 @@ import de.jeanlucmakiola.calendula.ui.common.ViewSwitcherPill
|
||||
import de.jeanlucmakiola.calendula.ui.common.calendarSlideTransition
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberCalendarFadeSpec
|
||||
import de.jeanlucmakiola.floret.identity.rememberReduceMotion
|
||||
import de.jeanlucmakiola.calendula.ui.common.currentLocale
|
||||
import de.jeanlucmakiola.floret.locale.currentLocale
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalUse24HourFormat
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalShowHourLines
|
||||
import de.jeanlucmakiola.calendula.ui.common.formatHourLabel
|
||||
@@ -180,6 +181,13 @@ fun WeekScreen(
|
||||
else -> true
|
||||
}
|
||||
|
||||
// Drives whether the title carries the year. Falls back to the clock only
|
||||
// while the first load is in flight, when there is no state to read today from.
|
||||
val currentYear = when (val s = state) {
|
||||
is WeekUiState.Success -> s.today.year
|
||||
else -> Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date.year
|
||||
}
|
||||
|
||||
// Slide direction for the week transition: +1 = next, -1 = prev, 0 = jump.
|
||||
var slideDir by remember { mutableIntStateOf(0) }
|
||||
val goNext = { slideDir = 1; viewModel.goToNext() }
|
||||
@@ -228,6 +236,7 @@ fun WeekScreen(
|
||||
topBar = {
|
||||
WeekTopBar(
|
||||
weekStart = weekStart,
|
||||
currentYear = currentYear,
|
||||
selectedView = selectedView,
|
||||
onCycleView = { onSelectView(selectedView.next(quickSwitchViews)) },
|
||||
onOpenDrawer = { scope.launch { drawerState.open() } },
|
||||
@@ -395,16 +404,18 @@ private fun WeekSuccess(
|
||||
@Composable
|
||||
private fun WeekTopBar(
|
||||
weekStart: LocalDate,
|
||||
currentYear: Int,
|
||||
selectedView: CalendarView,
|
||||
onCycleView: () -> Unit,
|
||||
onOpenDrawer: () -> Unit,
|
||||
onOpenSearch: () -> Unit,
|
||||
scrollBehavior: androidx.compose.material3.TopAppBarScrollBehavior,
|
||||
) {
|
||||
val locale = currentLocale()
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
text = formatWeekRange(weekStart),
|
||||
text = formatWeekTitle(weekStart, locale, currentYear),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
)
|
||||
},
|
||||
@@ -854,18 +865,21 @@ private fun WeekLoading() {
|
||||
private fun minToHm(min: Int, is24Hour: Boolean, locale: java.util.Locale): String =
|
||||
formatMinuteOfDay(min, is24Hour, locale)
|
||||
|
||||
private fun formatWeekRange(weekStart: LocalDate): String {
|
||||
val locale = Locale.getDefault()
|
||||
val end = weekStart.plus(6, kotlinx.datetime.DateTimeUnit.DAY)
|
||||
val monthName = { d: LocalDate ->
|
||||
java.time.Month.of(d.month.ordinal + 1).getDisplayName(JavaTextStyle.SHORT, locale)
|
||||
}
|
||||
return if (weekStart.month == end.month && weekStart.year == end.year) {
|
||||
"${weekStart.day}.–${end.day}. ${monthName(weekStart)} ${weekStart.year}"
|
||||
} else if (weekStart.year == end.year) {
|
||||
"${weekStart.day}. ${monthName(weekStart)} – ${end.day}. ${monthName(end)} ${end.year}"
|
||||
} else {
|
||||
"${weekStart.day}. ${monthName(weekStart)} ${weekStart.year} – " +
|
||||
"${end.day}. ${monthName(end)} ${end.year}"
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The week's title: just the month [weekStart] falls in.
|
||||
*
|
||||
* The day numbers are already in the column headers directly below, so spelling
|
||||
* out "13.–19. Jul" restates them in the widest string in the bar. Naming the
|
||||
* month of [weekStart] means a week straddling a boundary keeps the outgoing
|
||||
* month until it is fully gone — a week is seven contiguous days, so the earlier
|
||||
* month has a day in it exactly while [weekStart] is still inside it. That also
|
||||
* makes the title depend on nothing but [weekStart], so it cannot drift with the
|
||||
* direction you paged in from.
|
||||
*/
|
||||
private fun formatWeekTitle(weekStart: LocalDate, locale: Locale, currentYear: Int): String =
|
||||
formatCalendarTitle(
|
||||
date = java.time.LocalDate.of(weekStart.year, weekStart.month.ordinal + 1, 1),
|
||||
locale = locale,
|
||||
currentYear = currentYear,
|
||||
skeleton = "LLLL",
|
||||
)
|
||||
|
||||
@@ -55,7 +55,7 @@ import de.jeanlucmakiola.calendula.ui.agenda.parseAgendaRange
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
||||
import de.jeanlucmakiola.calendula.ui.common.EventDimAlpha
|
||||
import de.jeanlucmakiola.calendula.ui.common.formatTimeOfDay
|
||||
import de.jeanlucmakiola.calendula.ui.common.localizedDateFormatter
|
||||
import de.jeanlucmakiola.floret.locale.localizedDateFormatter
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventFill
|
||||
import de.jeanlucmakiola.calendula.widget.AgendaWidgetData
|
||||
import de.jeanlucmakiola.calendula.widget.CalendulaGlanceTheme
|
||||
|
||||
@@ -49,6 +49,7 @@ import de.jeanlucmakiola.calendula.MainActivity
|
||||
import de.jeanlucmakiola.calendula.R
|
||||
import de.jeanlucmakiola.calendula.domain.EventInstance
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
||||
import de.jeanlucmakiola.calendula.ui.common.formatCalendarTitle
|
||||
import de.jeanlucmakiola.calendula.ui.month.MonthWeek
|
||||
import de.jeanlucmakiola.calendula.ui.month.layoutMonthWeeks
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventFill
|
||||
@@ -162,7 +163,7 @@ private fun MonthWidgetBody(source: MonthWidgetSource, dark: Boolean, soften: Bo
|
||||
val colW = (LocalSize.current.width - GRID_HPADDING * 2) / 7
|
||||
val weeks = layoutMonthWeeks(ym, source.weekStart, source.instances, zone)
|
||||
|
||||
MonthHeader(label = monthLabel(ym))
|
||||
MonthHeader(label = monthLabel(ym, source.today.year))
|
||||
Spacer(GlanceModifier.height(2.dp))
|
||||
WeekdayHeader(weekStart = source.weekStart, colW = colW)
|
||||
weeks.forEach { week ->
|
||||
@@ -480,9 +481,13 @@ private fun PermissionMessage() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun monthLabel(month: YearMonth): String {
|
||||
val locale = Locale.getDefault()
|
||||
val name = java.time.Month.of(month.month.ordinal + 1)
|
||||
.getDisplayName(JavaTextStyle.FULL, locale)
|
||||
return "$name ${month.year}"
|
||||
}
|
||||
// Locale.getDefault() rather than currentLocale(): Glance has no
|
||||
// LocalConfiguration, and the widget is re-rendered on a configuration change
|
||||
// anyway (same convention as AgendaWidget).
|
||||
private fun monthLabel(month: YearMonth, currentYear: Int): String =
|
||||
formatCalendarTitle(
|
||||
date = java.time.LocalDate.of(month.year, month.month.ordinal + 1, 1),
|
||||
locale = Locale.getDefault(),
|
||||
currentYear = currentYear,
|
||||
skeleton = "LLLL",
|
||||
)
|
||||
|
||||
18
fastlane/metadata/android/en-US/changelogs/21600.txt
Normal file
18
fastlane/metadata/android/en-US/changelogs/21600.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
### Changed
|
||||
- Dates in the Month, Week and Day title bars now follow your language and
|
||||
region instead of one hardcoded layout. Every date was rendered in a fixed
|
||||
German-style order with a trailing dot on the day number, whatever your
|
||||
settings: US English showed "Fri, 17. Jul 2026" where it should read
|
||||
"Fri, Jul 17". The Agenda view already formatted correctly, so the two
|
||||
disagreed about the same date. All four views now share one formatter, and the
|
||||
day/month order, the separators and the ordinal all come from your locale —
|
||||
so English-in-Germany reads "Fri, 17 Jul" and English-in-the-US "Fri, Jul 17",
|
||||
each correct for where you are ([#60]).
|
||||
- The title bar drops the year while you're in the current one — "July" rather
|
||||
than "July 2026". The year reappears the moment you page out of the current
|
||||
year, which is when it tells you something you didn't already know.
|
||||
- The Week view's title now names the month instead of spelling out the day range.
|
||||
"24. Jun – 31. Jun" restated the day numbers already printed in the column
|
||||
headers right below it, in the widest string in the bar. A week that straddles
|
||||
two months keeps the outgoing month until it is fully gone ([#60]).
|
||||
|
||||
Submodule floret-kit updated: 2124227a7f...a50878a7ac
Reference in New Issue
Block a user