diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/InstanceMapper.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/InstanceMapper.kt index 1fc7645..a1a9a18 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/InstanceMapper.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/InstanceMapper.kt @@ -21,8 +21,9 @@ internal fun ColumnReader.toEventInstance(): EventInstance? { return null } - val rawTitle = getString(InstanceProjection.IDX_TITLE) - val title = if (rawTitle.isNullOrEmpty()) Fallbacks.UNTITLED_EVENT else rawTitle + // Left blank when the event has no title: the placeholder is a display + // string, so it belongs to the UI layer where it can be localised (#321). + val title = getString(InstanceProjection.IDX_TITLE).orEmpty() val color = if (isNull(InstanceProjection.IDX_EVENT_COLOR)) { getInt(InstanceProjection.IDX_CALENDAR_COLOR) diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/Projections.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/Projections.kt index b535aee..c107d8f 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/Projections.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/Projections.kt @@ -315,5 +315,4 @@ internal object ReminderProjection { internal object Fallbacks { const val UNNAMED_CALENDAR = "(Unbenannter Kalender)" - const val UNTITLED_EVENT = "(Ohne Titel)" } diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/SearchMapper.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/SearchMapper.kt index 23ee661..441f8c1 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/SearchMapper.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/SearchMapper.kt @@ -21,8 +21,7 @@ internal fun ColumnReader.toSearchResult(): EventInstance? { else -> dtStart + parseRfc2445DurationMillis(getString(SearchProjection.IDX_DURATION)) }.coerceAtLeast(dtStart) - val rawTitle = getString(SearchProjection.IDX_TITLE) - val title = if (rawTitle.isNullOrEmpty()) Fallbacks.UNTITLED_EVENT else rawTitle + val title = getString(SearchProjection.IDX_TITLE).orEmpty() val color = if (isNull(SearchProjection.IDX_EVENT_COLOR)) { getInt(SearchProjection.IDX_CALENDAR_COLOR) } else { diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/search/SearchScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/search/SearchScreen.kt index e3333c8..2dde1ab 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/search/SearchScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/search/SearchScreen.kt @@ -509,6 +509,9 @@ private fun SearchResultRow( onLongClick: (() -> Unit)? = null, ) { val event = hit.event + // Spans are empty for a blank title — the query never matches the + // placeholder — so marking the substitute is safe. + val title = event.title.ifBlank { stringResource(R.string.event_untitled) } val dark = isSystemInDarkTheme() val soften = LocalSoftenColors.current // On a picked row the headline is already recoloured for the secondary @@ -521,7 +524,7 @@ private fun SearchResultRow( // Faded like a past event anywhere else in the app — search reaches back // through the whole history. modifier = if (hit.isPast) modifier.alpha(EventDimAlpha) else modifier, - title = declinedTitle(marked(event.title, hit.titleSpans, highlight), event.isDeclined), + title = declinedTitle(marked(title, hit.titleSpans, highlight), event.isDeclined), summary = searchSummary(hit, highlight), position = position, minHeight = 64.dp, diff --git a/app/src/test/java/de/jeanlucmakiola/calendula/data/calendar/InstanceMapperTest.kt b/app/src/test/java/de/jeanlucmakiola/calendula/data/calendar/InstanceMapperTest.kt index e52f384..2c58954 100644 --- a/app/src/test/java/de/jeanlucmakiola/calendula/data/calendar/InstanceMapperTest.kt +++ b/app/src/test/java/de/jeanlucmakiola/calendula/data/calendar/InstanceMapperTest.kt @@ -61,15 +61,15 @@ class InstanceMapperTest { } @Test - fun `null title falls back to placeholder`() { + fun `null title is left blank for the UI to fill in`() { val inst = reader(title = null).toEventInstance() - assertThat(inst!!.title).isEqualTo(Fallbacks.UNTITLED_EVENT) + assertThat(inst!!.title).isEmpty() } @Test - fun `empty title falls back to placeholder`() { + fun `empty title is left blank for the UI to fill in`() { val inst = reader(title = "").toEventInstance() - assertThat(inst!!.title).isEqualTo(Fallbacks.UNTITLED_EVENT) + assertThat(inst!!.title).isEmpty() } @Test diff --git a/app/src/test/java/de/jeanlucmakiola/calendula/domain/EventSearchTest.kt b/app/src/test/java/de/jeanlucmakiola/calendula/domain/EventSearchTest.kt index 710bab7..0ebae1f 100644 --- a/app/src/test/java/de/jeanlucmakiola/calendula/domain/EventSearchTest.kt +++ b/app/src/test/java/de/jeanlucmakiola/calendula/domain/EventSearchTest.kt @@ -242,8 +242,8 @@ class EventSearchTest { } @Test - fun `an untitled event's placeholder is not something the query can match`() { - val untitled = candidate("(Ohne Titel)", description = "Titel folgt noch").copy(title = null) + fun `an untitled event's blank title is not something the query can match`() { + val untitled = candidate("", description = "Titel folgt noch").copy(title = null) val results = search(untitled, query = "titel")