Preview the previous view on a back gesture (#185)
This commit is contained in:
@@ -1,10 +1,13 @@
|
|||||||
package de.jeanlucmakiola.calendula.ui
|
package de.jeanlucmakiola.calendula.ui
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.activity.compose.PredictiveBackHandler
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
||||||
import androidx.compose.animation.SharedTransitionLayout
|
import androidx.compose.animation.SharedTransitionLayout
|
||||||
|
import androidx.compose.animation.core.SeekableTransitionState
|
||||||
|
import androidx.compose.animation.core.rememberTransition
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.slideInHorizontally
|
import androidx.compose.animation.slideInHorizontally
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
@@ -56,6 +59,7 @@ import de.jeanlucmakiola.calendula.ui.week.WeekScreen
|
|||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
import kotlinx.datetime.TimeZone
|
import kotlinx.datetime.TimeZone
|
||||||
import kotlinx.datetime.toLocalDateTime
|
import kotlinx.datetime.toLocalDateTime
|
||||||
|
import kotlin.coroutines.cancellation.CancellationException
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -358,8 +362,26 @@ fun CalendarHost(
|
|||||||
val anyOverlayVisible = showSearch || detailKey != null || createDateIso != null ||
|
val anyOverlayVisible = showSearch || detailKey != null || createDateIso != null ||
|
||||||
editKey != null || showSettings || showCalendars || showBackup ||
|
editKey != null || showSettings || showCalendars || showBackup ||
|
||||||
importUri != null || importForm != null
|
importUri != null || importForm != null
|
||||||
BackHandler(enabled = !anyOverlayVisible && viewStack.size > 1) {
|
// The view switch runs on a seekable transition, so a back gesture can scrub
|
||||||
viewStack = viewStack.dropLast(1)
|
// it (#185): the previous view morphs in under the finger, releasing finishes
|
||||||
|
// the pop and cancelling springs back. Reduced motion keeps a plain back.
|
||||||
|
val viewTransition = remember { SeekableTransitionState(view) }
|
||||||
|
LaunchedEffect(view) { viewTransition.animateTo(view) }
|
||||||
|
val reduceMotion = rememberReduceMotion()
|
||||||
|
val viewBackEnabled = !anyOverlayVisible && viewStack.size > 1
|
||||||
|
if (reduceMotion) {
|
||||||
|
BackHandler(enabled = viewBackEnabled) { viewStack = viewStack.dropLast(1) }
|
||||||
|
} else {
|
||||||
|
PredictiveBackHandler(enabled = viewBackEnabled) { events ->
|
||||||
|
val previous = viewStack[viewStack.size - 2]
|
||||||
|
try {
|
||||||
|
events.collect { viewTransition.seekTo(it.progress, targetState = previous) }
|
||||||
|
viewStack = viewStack.dropLast(1)
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
viewTransition.animateTo(viewTransition.currentState)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(modifier = modifier.fillMaxSize()) {
|
Box(modifier = modifier.fillMaxSize()) {
|
||||||
@@ -368,7 +390,6 @@ fun CalendarHost(
|
|||||||
// view keeps the directional slide. What both views show morphs across
|
// view keeps the directional slide. What both views show morphs across
|
||||||
// (#184): see [ViewMorphKey]. Reduced motion keeps the plain fade.
|
// (#184): see [ViewMorphKey]. Reduced motion keeps the plain fade.
|
||||||
val viewSwitch = fadeThrough()
|
val viewSwitch = fadeThrough()
|
||||||
val reduceMotion = rememberReduceMotion()
|
|
||||||
val morphBounds = rememberViewMorphBoundsTransform()
|
val morphBounds = rememberViewMorphBoundsTransform()
|
||||||
val morphFade = rememberCalendarFadeSpec()
|
val morphFade = rememberCalendarFadeSpec()
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
@@ -378,10 +399,8 @@ fun CalendarHost(
|
|||||||
LocalManageCalendars provides { showCalendars = true },
|
LocalManageCalendars provides { showCalendars = true },
|
||||||
) {
|
) {
|
||||||
SharedTransitionLayout(Modifier.fillMaxSize()) {
|
SharedTransitionLayout(Modifier.fillMaxSize()) {
|
||||||
AnimatedContent(
|
rememberTransition(viewTransition, label = "view-switch").AnimatedContent(
|
||||||
targetState = view,
|
|
||||||
transitionSpec = { viewSwitch },
|
transitionSpec = { viewSwitch },
|
||||||
label = "view-switch",
|
|
||||||
) { currentView ->
|
) { currentView ->
|
||||||
val sharedScope = this@SharedTransitionLayout
|
val sharedScope = this@SharedTransitionLayout
|
||||||
val visibilityScope = this@AnimatedContent
|
val visibilityScope = this@AnimatedContent
|
||||||
|
|||||||
Reference in New Issue
Block a user