Localise the untitled-event placeholder (#321)
The instance and search mappers substituted a hardcoded German "(Ohne Titel)" for an empty title, so EventInstance.title was never blank and every ifBlank fallback in the views was dead code. Leave the title blank and let the UI supply the translated string. This also restores the drag identity guards in MonthDrag/TimelineDrag, which check isNotBlank so two untitled events are not taken for the same event (#253) — the injected literal made that check always pass.
This commit is contained in:
@@ -21,8 +21,9 @@ internal fun ColumnReader.toEventInstance(): EventInstance? {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val rawTitle = getString(InstanceProjection.IDX_TITLE)
|
// Left blank when the event has no title: the placeholder is a display
|
||||||
val title = if (rawTitle.isNullOrEmpty()) Fallbacks.UNTITLED_EVENT else rawTitle
|
// 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)) {
|
val color = if (isNull(InstanceProjection.IDX_EVENT_COLOR)) {
|
||||||
getInt(InstanceProjection.IDX_CALENDAR_COLOR)
|
getInt(InstanceProjection.IDX_CALENDAR_COLOR)
|
||||||
|
|||||||
@@ -315,5 +315,4 @@ internal object ReminderProjection {
|
|||||||
|
|
||||||
internal object Fallbacks {
|
internal object Fallbacks {
|
||||||
const val UNNAMED_CALENDAR = "(Unbenannter Kalender)"
|
const val UNNAMED_CALENDAR = "(Unbenannter Kalender)"
|
||||||
const val UNTITLED_EVENT = "(Ohne Titel)"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ internal fun ColumnReader.toSearchResult(): EventInstance? {
|
|||||||
else -> dtStart + parseRfc2445DurationMillis(getString(SearchProjection.IDX_DURATION))
|
else -> dtStart + parseRfc2445DurationMillis(getString(SearchProjection.IDX_DURATION))
|
||||||
}.coerceAtLeast(dtStart)
|
}.coerceAtLeast(dtStart)
|
||||||
|
|
||||||
val rawTitle = getString(SearchProjection.IDX_TITLE)
|
val title = getString(SearchProjection.IDX_TITLE).orEmpty()
|
||||||
val title = if (rawTitle.isNullOrEmpty()) Fallbacks.UNTITLED_EVENT else rawTitle
|
|
||||||
val color = if (isNull(SearchProjection.IDX_EVENT_COLOR)) {
|
val color = if (isNull(SearchProjection.IDX_EVENT_COLOR)) {
|
||||||
getInt(SearchProjection.IDX_CALENDAR_COLOR)
|
getInt(SearchProjection.IDX_CALENDAR_COLOR)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -509,6 +509,9 @@ private fun SearchResultRow(
|
|||||||
onLongClick: (() -> Unit)? = null,
|
onLongClick: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
val event = hit.event
|
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 dark = isSystemInDarkTheme()
|
||||||
val soften = LocalSoftenColors.current
|
val soften = LocalSoftenColors.current
|
||||||
// On a picked row the headline is already recoloured for the secondary
|
// 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
|
// Faded like a past event anywhere else in the app — search reaches back
|
||||||
// through the whole history.
|
// through the whole history.
|
||||||
modifier = if (hit.isPast) modifier.alpha(EventDimAlpha) else modifier,
|
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),
|
summary = searchSummary(hit, highlight),
|
||||||
position = position,
|
position = position,
|
||||||
minHeight = 64.dp,
|
minHeight = 64.dp,
|
||||||
|
|||||||
@@ -61,15 +61,15 @@ class InstanceMapperTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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()
|
val inst = reader(title = null).toEventInstance()
|
||||||
assertThat(inst!!.title).isEqualTo(Fallbacks.UNTITLED_EVENT)
|
assertThat(inst!!.title).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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()
|
val inst = reader(title = "").toEventInstance()
|
||||||
assertThat(inst!!.title).isEqualTo(Fallbacks.UNTITLED_EVENT)
|
assertThat(inst!!.title).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -242,8 +242,8 @@ class EventSearchTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `an untitled event's placeholder is not something the query can match`() {
|
fun `an untitled event's blank title is not something the query can match`() {
|
||||||
val untitled = candidate("(Ohne Titel)", description = "Titel folgt noch").copy(title = null)
|
val untitled = candidate("", description = "Titel folgt noch").copy(title = null)
|
||||||
|
|
||||||
val results = search(untitled, query = "titel")
|
val results = search(untitled, query = "titel")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user