Compare commits
5 Commits
v2.19.1
...
7e8119be02
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e8119be02 | ||
|
|
7e843aa740 | ||
| 9775e0a652 | |||
| 2cf7d590bd | |||
|
|
8c76cbdf5e |
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
- Month-view event titles no longer end in an ellipsis. The "…" took the width
|
||||
of a couple of characters and told you nothing you couldn't already see, so
|
||||
the title now simply runs to the edge of its chip — a few more letters per
|
||||
cell, which is often the difference between two events you can tell apart and
|
||||
two you can't ([#164]).
|
||||
|
||||
## [2.19.1] — 2026-08-11
|
||||
|
||||
### Added
|
||||
@@ -1414,3 +1421,4 @@ automatically, with zero telemetry and no internet permission.
|
||||
[#123]: https://codeberg.org/jlmakiola/calendula/issues/123
|
||||
[#163]: https://codeberg.org/jlmakiola/calendula/issues/163
|
||||
[#173]: https://codeberg.org/jlmakiola/calendula/issues/173
|
||||
[#164]: https://codeberg.org/jlmakiola/calendula/issues/164
|
||||
|
||||
@@ -135,6 +135,7 @@ fun AgendaScreen(
|
||||
AgendaTopBar(
|
||||
selectedView = selectedView,
|
||||
onCycleView = { onSelectView(selectedView.next(quickSwitchViews)) },
|
||||
quickSwitchViews = quickSwitchViews,
|
||||
onOpenDrawer = { scope.launch { drawerState.open() } },
|
||||
onOpenSearch = onOpenSearch,
|
||||
showTodayButton = todayInToolbar,
|
||||
@@ -409,6 +410,7 @@ private fun AgendaEmpty(modifier: Modifier = Modifier) {
|
||||
private fun AgendaTopBar(
|
||||
selectedView: CalendarView,
|
||||
onCycleView: () -> Unit,
|
||||
quickSwitchViews: List<CalendarView>,
|
||||
onOpenDrawer: () -> Unit,
|
||||
onOpenSearch: () -> Unit,
|
||||
showTodayButton: Boolean,
|
||||
@@ -440,6 +442,7 @@ private fun AgendaTopBar(
|
||||
}
|
||||
ViewSwitcherPill(
|
||||
current = selectedView,
|
||||
cycle = quickSwitchViews,
|
||||
onCycle = onCycleView,
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
)
|
||||
|
||||
@@ -57,7 +57,8 @@ fun CalendarView.next(available: List<CalendarView> = IMPLEMENTED_VIEWS): Calend
|
||||
* implemented view — the settings screen reorders the whole set — while [cycle]
|
||||
* is the subset the pill actually steps through, in [order]. The navigation
|
||||
* drawer keeps its own separate order and always lists every view, so a view
|
||||
* disabled here stays reachable there.
|
||||
* disabled here stays reachable there — including when [cycle] is emptied and
|
||||
* the pill disappears altogether.
|
||||
*/
|
||||
data class QuickSwitchConfig(
|
||||
val order: List<CalendarView>,
|
||||
@@ -67,14 +68,15 @@ data class QuickSwitchConfig(
|
||||
val cycle: List<CalendarView> get() = order.filter { it in enabled }
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Fewest views that keep the switch meaningful. A single target is not a
|
||||
* switch, so below this the pill is hidden rather than special-cased (#150);
|
||||
* the drawer still reaches every view.
|
||||
*/
|
||||
const val MIN_CYCLE = 2
|
||||
|
||||
/** All views, in default order, all enabled. */
|
||||
val Default = QuickSwitchConfig(IMPLEMENTED_VIEWS, IMPLEMENTED_VIEWS.toSet())
|
||||
|
||||
/**
|
||||
* Fewest views that keep the switch meaningful — a "switch" needs at
|
||||
* least two targets, so the settings screen blocks disabling below this.
|
||||
*/
|
||||
const val MIN_ENABLED = 2
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package de.jeanlucmakiola.calendula.ui.common
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
|
||||
/** How an event chip's title should overflow: what to pass to `Text`. */
|
||||
data class EventTitleOverflow(val overflow: TextOverflow, val softWrap: Boolean)
|
||||
|
||||
/**
|
||||
* Overflow for an event chip's title (#164). Chips are narrow enough that the
|
||||
* "…" costs a couple of readable characters, so the title runs to the chip's
|
||||
* edge and clips mid-glyph instead.
|
||||
*
|
||||
* Two cases keep the ellipsis:
|
||||
*
|
||||
* - **[rtl].** With `softWrap` off Compose lays the line out at its full
|
||||
* intrinsic width and clips to the node's left edge, which in RTL is the *end*
|
||||
* of the string — an Arabic title would lose its beginning. The ellipsis
|
||||
* truncates at the logical end in both directions.
|
||||
* - **More than one line** ([singleLine] false). Wrapping needs `softWrap` on,
|
||||
* and clipping with it on breaks the last line at the last whole word — less
|
||||
* title than the ellipsis showed, not more.
|
||||
*/
|
||||
fun eventTitleOverflowFor(rtl: Boolean, singleLine: Boolean): EventTitleOverflow =
|
||||
if (rtl || !singleLine) {
|
||||
EventTitleOverflow(TextOverflow.Ellipsis, softWrap = true)
|
||||
} else {
|
||||
EventTitleOverflow(TextOverflow.Clip, softWrap = false)
|
||||
}
|
||||
|
||||
/** [eventTitleOverflowFor] against the current layout direction. */
|
||||
@Composable
|
||||
fun eventTitleOverflow(singleLine: Boolean = true): EventTitleOverflow =
|
||||
eventTitleOverflowFor(
|
||||
rtl = LocalLayoutDirection.current == LayoutDirection.Rtl,
|
||||
singleLine = singleLine,
|
||||
)
|
||||
@@ -464,11 +464,13 @@ fun TimelineDragOverlay(controller: TimelineDragController, modifier: Modifier =
|
||||
.padding(horizontal = 4.dp, vertical = 2.dp),
|
||||
) {
|
||||
Column {
|
||||
val titleOverflow = eventTitleOverflow()
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
overflow = titleOverflow.overflow,
|
||||
softWrap = titleOverflow.softWrap,
|
||||
color = eventInk(fill, alpha = 0.85f),
|
||||
)
|
||||
Text(
|
||||
|
||||
@@ -10,13 +10,19 @@ import androidx.compose.ui.res.stringResource
|
||||
/**
|
||||
* Top-bar pill that shows the current view and cycles to the next one on tap
|
||||
* (spec M1: Month → Week → Day → Month, restricted to [IMPLEMENTED_VIEWS]).
|
||||
*
|
||||
* Renders nothing when [cycle] holds fewer than [QuickSwitchConfig.MIN_CYCLE]
|
||||
* views (#150), so it drops straight into an app bar's `actions` slot without a
|
||||
* wrapping condition — the same way [TodayAction] handles being turned off.
|
||||
*/
|
||||
@Composable
|
||||
fun ViewSwitcherPill(
|
||||
current: CalendarView,
|
||||
cycle: List<CalendarView>,
|
||||
onCycle: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (cycle.size < QuickSwitchConfig.MIN_CYCLE) return
|
||||
FilledTonalButton(
|
||||
onClick = onCycle,
|
||||
shape = MaterialTheme.shapes.large,
|
||||
|
||||
@@ -65,7 +65,6 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.customActions
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -94,6 +93,7 @@ import de.jeanlucmakiola.calendula.ui.common.TimelineDrop
|
||||
import de.jeanlucmakiola.calendula.ui.common.beginsOn
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventDragAllowed
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventMoveAction
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventTitleOverflow
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberEventDragSource
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberTimelineDragController
|
||||
import de.jeanlucmakiola.calendula.ui.common.startInstant
|
||||
@@ -243,6 +243,7 @@ fun DayScreen(
|
||||
currentYear = currentYear,
|
||||
selectedView = selectedView,
|
||||
onCycleView = { onSelectView(selectedView.next(quickSwitchViews)) },
|
||||
quickSwitchViews = quickSwitchViews,
|
||||
onOpenDrawer = { scope.launch { drawerState.open() } },
|
||||
onOpenSearch = onOpenSearch,
|
||||
onJumpToDate = jumpToDate,
|
||||
@@ -411,6 +412,7 @@ private fun DayTopBar(
|
||||
currentYear: Int,
|
||||
selectedView: CalendarView,
|
||||
onCycleView: () -> Unit,
|
||||
quickSwitchViews: List<CalendarView>,
|
||||
onOpenDrawer: () -> Unit,
|
||||
onOpenSearch: () -> Unit,
|
||||
onJumpToDate: (LocalDate) -> Unit,
|
||||
@@ -445,6 +447,7 @@ private fun DayTopBar(
|
||||
}
|
||||
ViewSwitcherPill(
|
||||
current = selectedView,
|
||||
cycle = quickSwitchViews,
|
||||
onCycle = onCycleView,
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
)
|
||||
@@ -519,11 +522,13 @@ private fun AllDayBar(
|
||||
.semantics { contentDescription = title },
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
) {
|
||||
val titleOverflow = eventTitleOverflow()
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
overflow = titleOverflow.overflow,
|
||||
softWrap = titleOverflow.softWrap,
|
||||
color = eventInk(fill),
|
||||
)
|
||||
}
|
||||
@@ -766,11 +771,13 @@ private fun EventBlock(
|
||||
) {
|
||||
Column {
|
||||
if (showTitle) {
|
||||
val titleOverflow = eventTitleOverflow(singleLine = showTime)
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
maxLines = if (showTime) 1 else 2,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
overflow = titleOverflow.overflow,
|
||||
softWrap = titleOverflow.softWrap,
|
||||
color = eventInk(fill, alpha = 0.85f),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ import androidx.compose.ui.geometry.Offset
|
||||
import kotlin.math.roundToInt
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberDragSurface
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventMoveAction
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventTitleOverflow
|
||||
import de.jeanlucmakiola.calendula.ui.common.MoveTarget
|
||||
import de.jeanlucmakiola.calendula.ui.common.MoveRequest
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalEventMove
|
||||
@@ -386,6 +387,7 @@ fun MonthScreen(
|
||||
titleDate = LocalDate(titleMonth.year, titleMonth.month, 1),
|
||||
selectedView = selectedView,
|
||||
onCycleView = { onSelectView(selectedView.next(quickSwitchViews)) },
|
||||
quickSwitchViews = quickSwitchViews,
|
||||
onOpenDrawer = { scope.launch { drawerState.open() } },
|
||||
onOpenSearch = onOpenSearch,
|
||||
onJumpToDate = jumpToDate,
|
||||
@@ -650,6 +652,7 @@ private fun MonthTopBar(
|
||||
titleDate: LocalDate,
|
||||
selectedView: CalendarView,
|
||||
onCycleView: () -> Unit,
|
||||
quickSwitchViews: List<CalendarView>,
|
||||
onOpenDrawer: () -> Unit,
|
||||
onOpenSearch: () -> Unit,
|
||||
onJumpToDate: (LocalDate) -> Unit,
|
||||
@@ -683,6 +686,7 @@ private fun MonthTopBar(
|
||||
}
|
||||
ViewSwitcherPill(
|
||||
current = selectedView,
|
||||
cycle = quickSwitchViews,
|
||||
onCycle = onCycleView,
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
)
|
||||
@@ -2352,11 +2356,13 @@ private fun MonthBar(
|
||||
},
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
) {
|
||||
val titleOverflow = eventTitleOverflow()
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
overflow = titleOverflow.overflow,
|
||||
softWrap = titleOverflow.softWrap,
|
||||
color = eventInk(fill),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -591,15 +591,15 @@ class SettingsViewModel @Inject constructor(
|
||||
|
||||
/**
|
||||
* Enable or disable [view] in the quick-switch cycle, via an atomic
|
||||
* read-modify-write so a concurrent reorder can't clobber it. The
|
||||
* MIN_ENABLED floor is re-checked inside the transform, because the screen's
|
||||
* own guard reads an async-echoed snapshot.
|
||||
* read-modify-write so a concurrent reorder can't clobber it. Any number of
|
||||
* views may be turned off; below two the pill hides itself (#150).
|
||||
*/
|
||||
fun setQuickSwitchViewEnabled(view: CalendarView, enabled: Boolean) {
|
||||
viewModelScope.launch {
|
||||
prefs.updateQuickSwitch { config ->
|
||||
val next = if (enabled) config.enabled + view else config.enabled - view
|
||||
if (next.size < QuickSwitchConfig.MIN_ENABLED) config else config.copy(enabled = next)
|
||||
config.copy(
|
||||
enabled = if (enabled) config.enabled + view else config.enabled - view,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import de.jeanlucmakiola.calendula.ui.common.AgendaRangePicker
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
||||
import de.jeanlucmakiola.calendula.ui.common.IMPLEMENTED_VIEWS
|
||||
import de.jeanlucmakiola.calendula.ui.common.PickerDescription
|
||||
import de.jeanlucmakiola.calendula.ui.common.QuickSwitchConfig
|
||||
import de.jeanlucmakiola.calendula.ui.common.TimelineScale
|
||||
import de.jeanlucmakiola.calendula.ui.common.agendaRangeLabel
|
||||
import de.jeanlucmakiola.calendula.ui.common.descriptionRes
|
||||
@@ -55,8 +54,8 @@ import java.time.format.TextStyle as JavaTextStyle
|
||||
* it belongs to, plus the two cross-view ordering lists (#24, #69).
|
||||
*
|
||||
* The quick-switch cycle and the drawer list are independent orders — a view
|
||||
* off in the cycle is still reachable from the drawer. The cycle needs at least
|
||||
* [QuickSwitchConfig.MIN_ENABLED] targets.
|
||||
* off in the cycle is still reachable from the drawer, including when the cycle
|
||||
* is emptied and the pill disappears (#150).
|
||||
*/
|
||||
@Composable
|
||||
internal fun ViewsScreen(
|
||||
@@ -221,8 +220,6 @@ internal fun ViewsScreen(
|
||||
SectionHeader(stringResource(R.string.settings_quick_switch_header))
|
||||
SettingsHint(stringResource(R.string.settings_quick_switch_hint))
|
||||
Spacer(Modifier.height(8.dp))
|
||||
// Turning a view off is blocked once only the minimum remain enabled.
|
||||
val canDisable = config.enabled.size > QuickSwitchConfig.MIN_ENABLED
|
||||
ReorderableColumn(
|
||||
items = config.order,
|
||||
keyOf = { it },
|
||||
@@ -238,8 +235,6 @@ internal fun ViewsScreen(
|
||||
trailing = {
|
||||
Switch(
|
||||
checked = checked,
|
||||
// Keep the last two on: with fewer, the pill can't switch.
|
||||
enabled = !checked || canDisable,
|
||||
onCheckedChange = { on -> viewModel.setQuickSwitchViewEnabled(view, on) },
|
||||
)
|
||||
},
|
||||
|
||||
@@ -72,7 +72,6 @@ import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.customActions
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -102,6 +101,7 @@ import de.jeanlucmakiola.calendula.ui.common.TimelineDrop
|
||||
import de.jeanlucmakiola.calendula.ui.common.beginsOn
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventDragAllowed
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventMoveAction
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventTitleOverflow
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberEventDragSource
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberTimelineDragController
|
||||
import de.jeanlucmakiola.calendula.ui.common.startInstant
|
||||
@@ -266,6 +266,7 @@ fun WeekScreen(
|
||||
currentYear = currentYear,
|
||||
selectedView = selectedView,
|
||||
onCycleView = { onSelectView(selectedView.next(quickSwitchViews)) },
|
||||
quickSwitchViews = quickSwitchViews,
|
||||
onOpenDrawer = { scope.launch { drawerState.open() } },
|
||||
onOpenSearch = onOpenSearch,
|
||||
onJumpToDate = jumpToDate,
|
||||
@@ -446,6 +447,7 @@ private fun WeekTopBar(
|
||||
currentYear: Int,
|
||||
selectedView: CalendarView,
|
||||
onCycleView: () -> Unit,
|
||||
quickSwitchViews: List<CalendarView>,
|
||||
onOpenDrawer: () -> Unit,
|
||||
onOpenSearch: () -> Unit,
|
||||
onJumpToDate: (LocalDate) -> Unit,
|
||||
@@ -480,6 +482,7 @@ private fun WeekTopBar(
|
||||
}
|
||||
ViewSwitcherPill(
|
||||
current = selectedView,
|
||||
cycle = quickSwitchViews,
|
||||
onCycle = onCycleView,
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
)
|
||||
@@ -656,11 +659,13 @@ private fun AllDayBar(
|
||||
.semantics { contentDescription = title },
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
) {
|
||||
val titleOverflow = eventTitleOverflow()
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
overflow = titleOverflow.overflow,
|
||||
softWrap = titleOverflow.softWrap,
|
||||
color = eventInk(fill),
|
||||
)
|
||||
}
|
||||
@@ -934,11 +939,13 @@ private fun EventBlock(
|
||||
) {
|
||||
Column {
|
||||
if (showTitle) {
|
||||
val titleOverflow = eventTitleOverflow(singleLine = titleMaxLines == 1)
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
maxLines = titleMaxLines,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
overflow = titleOverflow.overflow,
|
||||
softWrap = titleOverflow.softWrap,
|
||||
color = eventInk(fill, alpha = 0.85f),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -496,7 +496,7 @@
|
||||
<string name="month_split_expand">Show the whole month</string>
|
||||
<string name="month_split_collapse">Show the day\'s events</string>
|
||||
<string name="settings_quick_switch_header">Quick-switch button</string>
|
||||
<string name="settings_quick_switch_hint">Choose which views the top-right button cycles through, and drag to reorder them. Turned-off views stay reachable from the navigation menu.</string>
|
||||
<string name="settings_quick_switch_hint">Choose which views the top-right button cycles through, and drag to reorder them. With fewer than two views turned on the button is hidden. Turned-off views stay reachable from the navigation menu.</string>
|
||||
<string name="settings_drawer_order_header">Navigation menu</string>
|
||||
<string name="settings_drawer_order_hint">Drag to reorder the views listed in the navigation menu.</string>
|
||||
<string name="reorder_drag_handle">Drag to reorder</string>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package de.jeanlucmakiola.calendula.ui.common
|
||||
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class EventTitleOverflowTest {
|
||||
|
||||
@Test
|
||||
fun `a single LTR line clips, so the title runs to the chip's edge`() {
|
||||
val result = eventTitleOverflowFor(rtl = false, singleLine = true)
|
||||
assertThat(result.overflow).isEqualTo(TextOverflow.Clip)
|
||||
// Load-bearing: with softWrap on, a clipped line breaks at the last
|
||||
// whole word and shows less title than the ellipsis did (#164).
|
||||
assertThat(result.softWrap).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `RTL keeps the ellipsis, which truncates at the logical end`() {
|
||||
// Clipping with softWrap off cuts at the node's left edge, which in RTL
|
||||
// is the end of the string — the title would lose its beginning.
|
||||
val result = eventTitleOverflowFor(rtl = true, singleLine = true)
|
||||
assertThat(result.overflow).isEqualTo(TextOverflow.Ellipsis)
|
||||
assertThat(result.softWrap).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `a multi-line block keeps the ellipsis, since wrapping needs softWrap`() {
|
||||
val result = eventTitleOverflowFor(rtl = false, singleLine = false)
|
||||
assertThat(result.overflow).isEqualTo(TextOverflow.Ellipsis)
|
||||
assertThat(result.softWrap).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `multi-line in RTL keeps the ellipsis too`() {
|
||||
val result = eventTitleOverflowFor(rtl = true, singleLine = false)
|
||||
assertThat(result.overflow).isEqualTo(TextOverflow.Ellipsis)
|
||||
assertThat(result.softWrap).isTrue()
|
||||
}
|
||||
}
|
||||
@@ -120,4 +120,30 @@ class ViewBackStackTest {
|
||||
)
|
||||
assertThat(config.cycle).containsExactly(CalendarView.Agenda, CalendarView.Month).inOrder()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `a cycle can be emptied down to no views at all`() {
|
||||
// #150: the settings screen no longer holds a floor, so every view may go.
|
||||
val config = QuickSwitchConfig(order = IMPLEMENTED_VIEWS, enabled = emptySet())
|
||||
assertThat(config.cycle).isEmpty()
|
||||
assertThat(config.cycle.size).isLessThan(QuickSwitchConfig.MIN_CYCLE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `one enabled view is below the cycle minimum, so the pill hides`() {
|
||||
// A single target is not a switch — it hides rather than becoming a
|
||||
// jump-to-one-view button, which would be dead once you were there.
|
||||
val config = QuickSwitchConfig(order = IMPLEMENTED_VIEWS, enabled = setOf(CalendarView.Day))
|
||||
assertThat(config.cycle).containsExactly(CalendarView.Day)
|
||||
assertThat(config.cycle.size).isLessThan(QuickSwitchConfig.MIN_CYCLE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `two enabled views are enough to show the pill`() {
|
||||
val config = QuickSwitchConfig(
|
||||
order = IMPLEMENTED_VIEWS,
|
||||
enabled = setOf(CalendarView.Day, CalendarView.Month),
|
||||
)
|
||||
assertThat(config.cycle.size).isAtLeast(QuickSwitchConfig.MIN_CYCLE)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user