From bc93964e05f9c261bff491534dc8d441d8e920df Mon Sep 17 00:00:00 2001 From: Guido Schmit Date: Sun, 31 May 2026 15:17:01 +0200 Subject: [PATCH] fix: single branded splash (invisible system icon), December title, first-open lag - System splash now uses a transparent icon, so there is no system icon that shrinks into the in-app splash: just black, then the branded screen (icon + Calendarr name + copyright), held until data is loaded - Month/quarter title uses TextStyle.FULL (format style) with a hard fallback; FULL_STANDALONE had the same desugar bug as the LLLL pattern (December showed only the year) - First open: load the full +/- cacheMonths window behind the splash and only then reveal, so the app no longer enters mid-load and stutters Co-Authored-By: Claude Opus 4.8 --- .../ui/calendar/CalendarFormatting.kt | 23 +++++++++---- .../ui/calendar/CalendarViewModel.kt | 34 +++++++++++-------- .../main/res/drawable/splash_transparent.xml | 7 ++++ app/src/main/res/values-v31/themes.xml | 3 -- app/src/main/res/values/themes.xml | 5 +-- 5 files changed, 45 insertions(+), 27 deletions(-) create mode 100644 app/src/main/res/drawable/splash_transparent.xml diff --git a/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarFormatting.kt b/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarFormatting.kt index bbdd129..81f17d9 100644 --- a/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarFormatting.kt +++ b/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarFormatting.kt @@ -12,21 +12,30 @@ import java.time.format.TextStyle private val zone: ZoneId = ZoneId.systemDefault() +/** Localized month name with a hard fallback (guards against empty/numeric results). */ +private fun monthName(date: LocalDate, style: TextStyle, loc: java.util.Locale): String { + val name = date.month.getDisplayName(style, loc) + val safe = if (name.isBlank() || name.all { it.isDigit() }) { + date.month.getDisplayName(TextStyle.FULL, java.util.Locale.ENGLISH) + } else { + name + } + return safe.replaceFirstChar { it.uppercase(loc) } +} + fun titleForView(viewType: CalViewType, date: LocalDate, lang: String): String { val loc = L10n.locale(lang) return when (viewType) { CalViewType.MONTH -> { - // Use Month.getDisplayName (robust) instead of the "LLLL" pattern, - // which could drop the month name under desugared java.time. - val month = date.month.getDisplayName(TextStyle.FULL_STANDALONE, loc) - .replaceFirstChar { it.uppercase(loc) } + // Use the FORMAT month style (TextStyle.FULL). The standalone style + // (FULL_STANDALONE / the "LLLL" pattern) drops the name for some + // months under desugared java.time (e.g. December showed only "2026"). + val month = monthName(date, TextStyle.FULL, loc) "$month ${date.year}" } CalViewType.QUARTER -> { val endM = date.plusMonths(2) - val m1 = date.month.getDisplayName(TextStyle.SHORT_STANDALONE, loc).replaceFirstChar { it.uppercase(loc) } - val m2 = endM.month.getDisplayName(TextStyle.SHORT_STANDALONE, loc).replaceFirstChar { it.uppercase(loc) } - "$m1 ${date.year} – $m2 ${endM.year}" + "${monthName(date, TextStyle.SHORT, loc)} ${date.year} – ${monthName(endM, TextStyle.SHORT, loc)} ${endM.year}" } CalViewType.WEEK -> { val start = date diff --git a/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarViewModel.kt b/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarViewModel.kt index 7c62517..b669a69 100644 --- a/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarViewModel.kt +++ b/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarViewModel.kt @@ -64,9 +64,24 @@ class CalendarViewModel @Inject constructor( private var allCachedEvents: List = emptyList() init { - loadVisible() loadWritableCalendars() - prefetchBackground() + initialLoad() + } + + /** + * Load the full ±cacheMonths window once, behind the splash, and only then + * mark ready. Entering the app fully-loaded avoids the first-open jank of + * loading a big batch while the user is already scrolling. + */ + private fun initialLoad() { + val months = settingsStore.cacheMonths.toLong() + val today = LocalDate.now().withDayOfMonth(1) + val start = instant(today.minusMonths(months)) + val end = instant(today.plusMonths(months + 1)) + viewModelScope.launch { + loadRange(start, end, background = false) + markReady() + } } private fun initialState(): CalendarUiState { @@ -188,15 +203,6 @@ class CalendarViewModel @Inject constructor( _ready.value = true } - private fun prefetchBackground() { - val months = settingsStore.cacheMonths - val today = LocalDate.now().withDayOfMonth(1) - val start = instant(today.minusMonths(months.toLong())) - val end = instant(today.plusMonths((months + 1).toLong())) - if (isCached(start, end)) return - viewModelScope.launch { loadRange(start, end, background = true) } - } - private fun isCached(start: Instant, end: Instant): Boolean { val cs = cachedStart ?: return false val ce = cachedEnd ?: return false @@ -231,8 +237,7 @@ class CalendarViewModel @Inject constructor( fun syncWithServer() { invalidateCache() - loadVisible(force = true) - prefetchBackground() + initialLoad() } fun clearError() = _state.update { it.copy(error = null) } @@ -280,8 +285,7 @@ class CalendarViewModel @Inject constructor( private fun afterMutation() { invalidateCache() - loadVisible(force = true) - prefetchBackground() + initialLoad() } fun saveEvent( diff --git a/app/src/main/res/drawable/splash_transparent.xml b/app/src/main/res/drawable/splash_transparent.xml new file mode 100644 index 0000000..73ad064 --- /dev/null +++ b/app/src/main/res/drawable/splash_transparent.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/src/main/res/values-v31/themes.xml b/app/src/main/res/values-v31/themes.xml index e46e021..a5de45d 100644 --- a/app/src/main/res/values-v31/themes.xml +++ b/app/src/main/res/values-v31/themes.xml @@ -4,8 +4,5 @@ @android:color/black @android:color/black false - - @android:color/black - @drawable/splash_icon diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 45c14a3..938a0b2 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -9,10 +9,11 @@ false - +