Reset the back preview when an overlay reopens (#184)

This commit is contained in:
2026-09-27 12:06:45 +02:00
parent dc841a91e0
commit df33eca5f2
16 changed files with 52 additions and 13 deletions
@@ -470,6 +470,7 @@ fun CalendarHost(
SearchScreen(
onBack = { showSearch = false },
onEventClick = onEventClick,
visible = showSearch,
)
}
@@ -498,6 +499,7 @@ fun CalendarHost(
importForm = form
detailKey = null
},
visible = detailKey != null,
)
}
}
@@ -515,6 +517,7 @@ fun CalendarHost(
onClose = { createDateIso = null },
onSaved = { createDateIso = null },
onManageCalendars = { showCalendars = true },
visible = createDateIso != null,
)
}
}
@@ -535,6 +538,7 @@ fun CalendarHost(
detailKey = null
},
onManageCalendars = { showCalendars = true },
visible = editKey != null,
)
}
}
@@ -549,6 +553,7 @@ fun CalendarHost(
onBack = { showSettings = false },
onManageCalendars = { showCalendars = true },
onOpenBackup = { showBackup = true },
visible = showSettings,
)
}
@@ -605,6 +610,7 @@ fun CalendarHost(
CalendarsScreen(
onBack = { showCalendars = false },
onOpenBackup = { showBackup = true },
visible = showCalendars,
)
}
@@ -639,6 +645,7 @@ fun CalendarHost(
showBackup = false
showCalendars = false
},
visible = showBackup,
)
}
}
@@ -82,6 +82,7 @@ private val RESTORE_MIME_TYPES = arrayOf(
fun BackupScreen(
onBack: () -> Unit,
onImport: (Uri) -> Unit,
visible: Boolean = true,
viewModel: CalendarsViewModel = hiltViewModel(),
) {
val state by viewModel.backupState.collectAsStateWithLifecycle()
@@ -137,6 +138,7 @@ fun BackupScreen(
scrollable = state is BackupUiState.Ready,
snackbarHost = { SnackbarHost(snackbarHostState) },
predictiveBack = true,
visible = visible,
) {
when (val s = state) {
BackupUiState.Loading -> BackupLoading()
@@ -133,6 +133,7 @@ private const val NEW_CALENDAR_ID = Long.MIN_VALUE
fun CalendarsScreen(
onBack: () -> Unit,
onOpenBackup: () -> Unit,
visible: Boolean = true,
viewModel: CalendarsViewModel = hiltViewModel(),
) {
val calendars by viewModel.calendars.collectAsStateWithLifecycle()
@@ -177,6 +178,7 @@ fun CalendarsScreen(
onConsumeError = viewModel::consumeError,
onOpenBackup = onOpenBackup,
onBack = onBack,
visible = visible,
onAdd = { editorSession++; editorId = NEW_CALENDAR_ID },
onEdit = { calendar -> editorSession++; editorId = calendar.id },
onSetVisible = viewModel::setCalendarVisible,
@@ -193,6 +195,7 @@ private fun CalendarsList(
onConsumeError: () -> Unit,
onOpenBackup: () -> Unit,
onBack: () -> Unit,
visible: Boolean,
onAdd: () -> Unit,
onEdit: (CalendarSource) -> Unit,
onSetVisible: (Long, Boolean) -> Unit,
@@ -218,6 +221,7 @@ private fun CalendarsList(
onBack = onBack,
snackbarHost = { SnackbarHost(snackbarHostState) },
predictiveBack = true,
visible = visible,
) {
// What the per-calendar / per-account switches below actually do.
HintText(stringResource(R.string.calendars_visibility_hint))
@@ -140,6 +140,7 @@ fun EventDetailScreen(
onBack: () -> Unit,
onEdit: () -> Unit,
onDuplicate: (EventForm) -> Unit,
visible: Boolean = true,
viewModel: EventDetailViewModel = hiltViewModel(),
) {
LaunchedEffect(eventId, beginMillis, endMillis) {
@@ -227,7 +228,7 @@ fun EventDetailScreen(
}
Scaffold(
modifier = Modifier.predictiveBack(onBack = onBack),
modifier = Modifier.predictiveBack(onBack = onBack, visible = visible),
snackbarHost = { SnackbarHost(snackbarHostState) },
topBar = {
TopAppBar(
@@ -203,6 +203,7 @@ fun EventEditScreen(
initialForm: EventForm? = null,
initialFormSource: ImportSource = ImportSource.File,
onManageCalendars: (() -> Unit)? = null,
visible: Boolean = true,
viewModel: EventEditViewModel = hiltViewModel(),
) {
LaunchedEffect(initialDateIso, editKey, initialForm) {
@@ -285,7 +286,7 @@ fun EventEditScreen(
}
Scaffold(
modifier = Modifier.predictiveBack(onBack = close),
modifier = Modifier.predictiveBack(onBack = close, visible = visible),
snackbarHost = { SnackbarHost(snackbarHostState) },
topBar = {
TopAppBar(
@@ -78,6 +78,7 @@ fun ImportScreen(
onOpenSingle: (EventForm) -> Unit,
forceMany: Boolean = false,
onManageCalendars: (() -> Unit)? = null,
visible: Boolean = true,
viewModel: ImportViewModel = hiltViewModel(),
) {
// hiltViewModel() resolves to the Activity's store and is retained across
@@ -103,7 +104,7 @@ fun ImportScreen(
Scaffold(
modifier = Modifier
.predictiveBack(onBack = onClose)
.predictiveBack(onBack = onClose, visible = visible)
.fillMaxSize(),
topBar = {
TopAppBar(
@@ -23,13 +23,14 @@ import de.jeanlucmakiola.floret.components.positionOf
* what the *recipient of the binary* is told. Each row opens the project's source.
*/
@Composable
internal fun LicencesScreen(onBack: () -> Unit) {
internal fun LicencesScreen(onBack: () -> Unit, visible: Boolean = true) {
val uriHandler = LocalUriHandler.current
CollapsingScaffold(
title = stringResource(R.string.licences_title),
onBack = onBack,
predictiveBack = true,
visible = visible,
) {
Text(
stringResource(R.string.licences_intro),
@@ -126,6 +126,7 @@ fun SearchScreen(
onBack: () -> Unit,
onEventClick: (EventInstance) -> Unit,
modifier: Modifier = Modifier,
visible: Boolean = true,
viewModel: SearchViewModel = hiltViewModel(),
) {
val query by viewModel.query.collectAsStateWithLifecycle()
@@ -184,7 +185,7 @@ fun SearchScreen(
BackHandler(enabled = inSelection) { viewModel.clearSelection() }
Scaffold(
modifier = modifier.predictiveBack(onBack = onBack, enabled = !inSelection),
modifier = modifier.predictiveBack(onBack = onBack, enabled = !inSelection, visible = visible),
containerColor = MaterialTheme.colorScheme.surface,
topBar = {
SearchTopBar(
@@ -76,6 +76,7 @@ internal fun AppearanceScreen(
state: SettingsUiState,
viewModel: SettingsViewModel,
onBack: () -> Unit,
visible: Boolean = true,
) {
var showTheme by remember { mutableStateOf(false) }
var showBrandFont by remember { mutableStateOf(false) }
@@ -96,6 +97,7 @@ internal fun AppearanceScreen(
title = stringResource(R.string.settings_section_appearance),
onBack = onBack,
predictiveBack = true,
visible = visible,
) {
// Theme & colour
GroupedRow(
@@ -41,6 +41,7 @@ internal fun EventFormScreen(
state: SettingsUiState,
viewModel: SettingsViewModel,
onBack: () -> Unit,
visible: Boolean = true,
) {
var showDefaultDuration by remember { mutableStateOf(false) }
// The calendar whose duration-override picker is open, if any.
@@ -53,6 +54,7 @@ internal fun EventFormScreen(
title = stringResource(R.string.settings_section_event_form),
onBack = onBack,
predictiveBack = true,
visible = visible,
) {
SettingsHint(stringResource(R.string.settings_form_fields_hint))
Spacer(Modifier.height(8.dp))
@@ -63,6 +63,7 @@ internal fun NotificationsScreen(
viewModel: SettingsViewModel,
onBack: () -> Unit,
onOpenSpecialDates: () -> Unit,
visible: Boolean = true,
) {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(
@@ -92,6 +93,7 @@ internal fun NotificationsScreen(
title = stringResource(R.string.settings_section_notifications),
onBack = onBack,
predictiveBack = true,
visible = visible,
) {
GroupedRow(
title = stringResource(R.string.settings_reminders),
@@ -84,6 +84,7 @@ fun SettingsScreen(
onManageCalendars: () -> Unit,
onOpenBackup: () -> Unit,
modifier: Modifier = Modifier,
visible: Boolean = true,
viewModel: SettingsViewModel = hiltViewModel(),
) {
val state by viewModel.state.collectAsStateWithLifecycle()
@@ -102,6 +103,7 @@ fun SettingsScreen(
onOpenSection = { section = it },
onManageCalendars = onManageCalendars,
onOpenBackup = onOpenBackup,
visible = visible,
)
AnimatedVisibility(
@@ -109,21 +111,21 @@ fun SettingsScreen(
enter = slideInHorizontally(slideSpec) { it } + fadeIn(),
exit = overlayExit,
) {
AppearanceScreen(state = state, viewModel = viewModel, onBack = { section = null })
AppearanceScreen(state = state, viewModel = viewModel, onBack = { section = null }, visible = section == SettingsSection.Appearance)
}
AnimatedVisibility(
visible = section == SettingsSection.Views,
enter = slideInHorizontally(slideSpec) { it } + fadeIn(),
exit = overlayExit,
) {
ViewsScreen(state = state, viewModel = viewModel, onBack = { section = null })
ViewsScreen(state = state, viewModel = viewModel, onBack = { section = null }, visible = section == SettingsSection.Views)
}
AnimatedVisibility(
visible = section == SettingsSection.EventForm,
enter = slideInHorizontally(slideSpec) { it } + fadeIn(),
exit = overlayExit,
) {
EventFormScreen(state = state, viewModel = viewModel, onBack = { section = null })
EventFormScreen(state = state, viewModel = viewModel, onBack = { section = null }, visible = section == SettingsSection.EventForm)
}
AnimatedVisibility(
visible = section == SettingsSection.Notifications,
@@ -135,6 +137,7 @@ fun SettingsScreen(
viewModel = viewModel,
onBack = { section = null },
onOpenSpecialDates = { section = SettingsSection.SpecialDates },
visible = section == SettingsSection.Notifications,
)
}
AnimatedVisibility(
@@ -142,21 +145,21 @@ fun SettingsScreen(
enter = slideInHorizontally(slideSpec) { it } + fadeIn(),
exit = overlayExit,
) {
SpecialDatesScreen(viewModel = viewModel, onBack = { section = null })
SpecialDatesScreen(viewModel = viewModel, onBack = { section = null }, visible = section == SettingsSection.SpecialDates)
}
AnimatedVisibility(
visible = section == SettingsSection.Widgets,
enter = slideInHorizontally(slideSpec) { it } + fadeIn(),
exit = overlayExit,
) {
WidgetsScreen(state = state, viewModel = viewModel, onBack = { section = null })
WidgetsScreen(state = state, viewModel = viewModel, onBack = { section = null }, visible = section == SettingsSection.Widgets)
}
AnimatedVisibility(
visible = section == SettingsSection.Licences,
enter = slideInHorizontally(slideSpec) { it } + fadeIn(),
exit = overlayExit,
) {
LicencesScreen(onBack = { section = null })
LicencesScreen(onBack = { section = null }, visible = section == SettingsSection.Licences)
}
}
}
@@ -171,8 +174,14 @@ private fun SettingsHub(
onOpenSection: (SettingsSection) -> Unit,
onManageCalendars: () -> Unit,
onOpenBackup: () -> Unit,
visible: Boolean,
) {
CollapsingScaffold(title = stringResource(R.string.settings_title), onBack = onBack, predictiveBack = true) {
CollapsingScaffold(
title = stringResource(R.string.settings_title),
onBack = onBack,
predictiveBack = true,
visible = visible,
) {
// Card and support row are one grouped block, so the call to action
// continues the container instead of sitting inside it as a button.
Box(Modifier.padding(horizontal = GroupedListInset)) { AboutCard() }
@@ -46,6 +46,7 @@ import de.jeanlucmakiola.floret.reminders.ReminderOverride
internal fun SpecialDatesScreen(
viewModel: SettingsViewModel,
onBack: () -> Unit,
visible: Boolean = true,
) {
val state by viewModel.specialDatesState.collectAsStateWithLifecycle()
val settings by viewModel.state.collectAsStateWithLifecycle()
@@ -76,6 +77,7 @@ internal fun SpecialDatesScreen(
title = stringResource(R.string.settings_section_special_dates),
onBack = onBack,
predictiveBack = true,
visible = visible,
) {
// Paused banner: the permission was revoked after enabling.
if (state.enabled && state.stalledPermission) {
@@ -65,6 +65,7 @@ internal fun ViewsScreen(
state: SettingsUiState,
viewModel: SettingsViewModel,
onBack: () -> Unit,
visible: Boolean = true,
) {
var showMonthStyle by remember { mutableStateOf(false) }
var showDefaultView by remember { mutableStateOf(false) }
@@ -79,6 +80,7 @@ internal fun ViewsScreen(
title = stringResource(R.string.settings_section_views),
onBack = onBack,
predictiveBack = true,
visible = visible,
) {
val config = state.quickSwitchConfig
@@ -42,6 +42,7 @@ internal fun WidgetsScreen(
state: SettingsUiState,
viewModel: SettingsViewModel,
onBack: () -> Unit,
visible: Boolean = true,
) {
var showAgendaWidgetRange by remember { mutableStateOf(false) }
var showWidgetSize by remember { mutableStateOf(false) }
@@ -50,6 +51,7 @@ internal fun WidgetsScreen(
title = stringResource(R.string.settings_section_widgets),
onBack = onBack,
predictiveBack = true,
visible = visible,
) {
SettingsHint(stringResource(R.string.settings_widgets_hint))
Spacer(Modifier.height(8.dp))