Merge release/v2.11.0 into feat/agenda-range-limit
Integrate #3/#5/#6 (week-start, time-format, hour-lines) into the agenda range branch. SettingsViewModel folds all five view prefs into one combine; WidgetData keeps the range-based window and adds the resolved is24Hour. Also, in the same Appearance section: - regroup the rows into four titled-by-spacing groups (theme & colour / calendar layout / timeline display / agenda) instead of one long card. - add an explanatory description line under the title of each agenda-range picker (PickerDescription). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,7 @@ class SettingsPrefsTest {
|
||||
val prefs = SettingsPrefs(newDataStore(tempDir))
|
||||
assertThat(prefs.themeMode.first()).isEqualTo(ThemeMode.SYSTEM)
|
||||
assertThat(prefs.dynamicColor.first()).isTrue()
|
||||
assertThat(prefs.weekStart.first()).isEqualTo(WeekStartPref.AUTO)
|
||||
assertThat(prefs.weekStart.first()).isEqualTo(WeekStartPref.Auto)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -44,10 +44,50 @@ class SettingsPrefsTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `week start round-trips`(@TempDir tempDir: Path) = runTest {
|
||||
fun `week start round-trips any day`(@TempDir tempDir: Path) = runTest {
|
||||
val prefs = SettingsPrefs(newDataStore(tempDir))
|
||||
prefs.setWeekStart(WeekStartPref.SUNDAY)
|
||||
assertThat(prefs.weekStart.first()).isEqualTo(WeekStartPref.SUNDAY)
|
||||
prefs.setWeekStart(WeekStartPref.Day(DayOfWeek.SATURDAY))
|
||||
assertThat(prefs.weekStart.first()).isEqualTo(WeekStartPref.Day(DayOfWeek.SATURDAY))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `legacy MONDAY week-start value migrates to Day`(@TempDir tempDir: Path) = runTest {
|
||||
val store = newDataStore(tempDir)
|
||||
val prefs = SettingsPrefs(store)
|
||||
store.updateData { p ->
|
||||
val m = p.toMutablePreferences()
|
||||
m[SettingsPrefs.WEEK_START_KEY] = "MONDAY"
|
||||
m
|
||||
}
|
||||
assertThat(prefs.weekStart.first()).isEqualTo(WeekStartPref.Day(DayOfWeek.MONDAY))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `garbage week-start value falls back to Auto`(@TempDir tempDir: Path) = runTest {
|
||||
val store = newDataStore(tempDir)
|
||||
val prefs = SettingsPrefs(store)
|
||||
store.updateData { p ->
|
||||
val m = p.toMutablePreferences()
|
||||
m[SettingsPrefs.WEEK_START_KEY] = "FUNDAY"
|
||||
m
|
||||
}
|
||||
assertThat(prefs.weekStart.first()).isEqualTo(WeekStartPref.Auto)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `time format defaults to auto and round-trips`(@TempDir tempDir: Path) = runTest {
|
||||
val prefs = SettingsPrefs(newDataStore(tempDir))
|
||||
assertThat(prefs.timeFormat.first()).isEqualTo(TimeFormatPref.AUTO)
|
||||
prefs.setTimeFormat(TimeFormatPref.TWELVE_HOUR)
|
||||
assertThat(prefs.timeFormat.first()).isEqualTo(TimeFormatPref.TWELVE_HOUR)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hour lines default off and round-trips`(@TempDir tempDir: Path) = runTest {
|
||||
val prefs = SettingsPrefs(newDataStore(tempDir))
|
||||
assertThat(prefs.showHourLines.first()).isFalse()
|
||||
prefs.setShowHourLines(true)
|
||||
assertThat(prefs.showHourLines.first()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -265,13 +305,15 @@ class SettingsPrefsTest {
|
||||
|
||||
@Test
|
||||
fun `explicit week-start prefs resolve regardless of locale`() {
|
||||
assertThat(WeekStartPref.MONDAY.resolveFirstDay(Locale.US)).isEqualTo(DayOfWeek.MONDAY)
|
||||
assertThat(WeekStartPref.SUNDAY.resolveFirstDay(Locale.GERMANY)).isEqualTo(DayOfWeek.SUNDAY)
|
||||
assertThat(WeekStartPref.Day(DayOfWeek.MONDAY).resolveFirstDay(Locale.US))
|
||||
.isEqualTo(DayOfWeek.MONDAY)
|
||||
assertThat(WeekStartPref.Day(DayOfWeek.SATURDAY).resolveFirstDay(Locale.GERMANY))
|
||||
.isEqualTo(DayOfWeek.SATURDAY)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `auto week start follows the locale convention`() {
|
||||
assertThat(WeekStartPref.AUTO.resolveFirstDay(Locale.GERMANY)).isEqualTo(DayOfWeek.MONDAY)
|
||||
assertThat(WeekStartPref.AUTO.resolveFirstDay(Locale.US)).isEqualTo(DayOfWeek.SUNDAY)
|
||||
assertThat(WeekStartPref.Auto.resolveFirstDay(Locale.GERMANY)).isEqualTo(DayOfWeek.MONDAY)
|
||||
assertThat(WeekStartPref.Auto.resolveFirstDay(Locale.US)).isEqualTo(DayOfWeek.SUNDAY)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,24 @@ class ReminderTimeTextTest {
|
||||
isAllDay = false,
|
||||
zone = berlin,
|
||||
locale = Locale.GERMANY,
|
||||
is24Hour = true,
|
||||
)
|
||||
assertThat(text).isEqualTo("09:30 – 10:00")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `12-hour preference renders an am-pm time range`() {
|
||||
val text = reminderTimeText(
|
||||
beginMillis = millisAt(LocalDateTime.of(2026, 6, 11, 14, 0), berlin),
|
||||
endMillis = millisAt(LocalDateTime.of(2026, 6, 11, 15, 0), berlin),
|
||||
isAllDay = false,
|
||||
zone = berlin,
|
||||
locale = Locale.US,
|
||||
is24Hour = false,
|
||||
)
|
||||
assertThat(text).isEqualTo("2:00 PM – 3:00 PM")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `timed event crossing midnight includes both dates`() {
|
||||
val text = reminderTimeText(
|
||||
@@ -38,6 +52,7 @@ class ReminderTimeTextTest {
|
||||
isAllDay = false,
|
||||
zone = berlin,
|
||||
locale = Locale.GERMANY,
|
||||
is24Hour = true,
|
||||
)
|
||||
assertThat(text).contains("11.06.2026")
|
||||
assertThat(text).contains("12.06.2026")
|
||||
@@ -54,6 +69,7 @@ class ReminderTimeTextTest {
|
||||
// 02:00 in Berlin — naive local reading would shift the day.
|
||||
zone = berlin,
|
||||
locale = Locale.GERMANY,
|
||||
is24Hour = true,
|
||||
)
|
||||
assertThat(text).isEqualTo("11.06.2026")
|
||||
}
|
||||
@@ -66,6 +82,7 @@ class ReminderTimeTextTest {
|
||||
isAllDay = true,
|
||||
zone = berlin,
|
||||
locale = Locale.GERMANY,
|
||||
is24Hour = true,
|
||||
)
|
||||
assertThat(text).isEqualTo("11.06.2026 – 12.06.2026")
|
||||
}
|
||||
@@ -79,6 +96,7 @@ class ReminderTimeTextTest {
|
||||
isAllDay = true,
|
||||
zone = berlin,
|
||||
locale = Locale.GERMANY,
|
||||
is24Hour = true,
|
||||
)
|
||||
assertThat(text).isEqualTo("11.06.2026")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package de.jeanlucmakiola.calendula.ui.common
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.util.Locale
|
||||
|
||||
class TimeFormatTest {
|
||||
|
||||
@Test
|
||||
fun `24-hour format is zero-padded HH mm`() {
|
||||
assertThat(formatTimeOfDay(9, 5, is24Hour = true, Locale.US)).isEqualTo("09:05")
|
||||
assertThat(formatTimeOfDay(14, 0, is24Hour = true, Locale.US)).isEqualTo("14:00")
|
||||
assertThat(formatTimeOfDay(0, 0, is24Hour = true, Locale.US)).isEqualTo("00:00")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `12-hour format adds a localised am-pm marker`() {
|
||||
assertThat(formatTimeOfDay(14, 0, is24Hour = false, Locale.US)).isEqualTo("2:00 PM")
|
||||
assertThat(formatTimeOfDay(0, 30, is24Hour = false, Locale.US)).isEqualTo("12:30 AM")
|
||||
assertThat(formatTimeOfDay(12, 0, is24Hour = false, Locale.US)).isEqualTo("12:00 PM")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `minute-of-day end-of-day renders 24 00 in 24h and midnight in 12h`() {
|
||||
assertThat(formatMinuteOfDay(1_440, is24Hour = true, Locale.US)).isEqualTo("24:00")
|
||||
assertThat(formatMinuteOfDay(1_440, is24Hour = false, Locale.US)).isEqualTo("12:00 AM")
|
||||
assertThat(formatMinuteOfDay(13 * 60 + 15, is24Hour = true, Locale.US)).isEqualTo("13:15")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hour label is zero-padded in 24h and compact am-pm in 12h`() {
|
||||
assertThat(formatHourLabel(13, is24Hour = true, Locale.US)).isEqualTo("13")
|
||||
assertThat(formatHourLabel(13, is24Hour = false, Locale.US)).isEqualTo("1 PM")
|
||||
assertThat(formatHourLabel(1, is24Hour = false, Locale.US)).isEqualTo("1 AM")
|
||||
assertThat(formatHourLabel(0, is24Hour = false, Locale.US)).isEqualTo("12 AM")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user