Merge back preview (#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
|
||||||
@@ -29,7 +32,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import de.jeanlucmakiola.calendula.ui.common.screen
|
import de.jeanlucmakiola.calendula.ui.common.screen
|
||||||
import de.jeanlucmakiola.calendula.ui.common.ViewScreen
|
import de.jeanlucmakiola.calendula.ui.common.ViewScreen
|
||||||
import androidx.compose.runtime.SideEffect
|
|
||||||
import androidx.compose.ui.layout.onGloballyPositioned
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
import androidx.compose.ui.layout.positionInWindow
|
import androidx.compose.ui.layout.positionInWindow
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
@@ -80,10 +82,13 @@ import de.jeanlucmakiola.calendula.ui.month.MonthScreen
|
|||||||
import de.jeanlucmakiola.calendula.ui.search.SearchScreen
|
import de.jeanlucmakiola.calendula.ui.search.SearchScreen
|
||||||
import de.jeanlucmakiola.calendula.ui.settings.SettingsScreen
|
import de.jeanlucmakiola.calendula.ui.settings.SettingsScreen
|
||||||
import de.jeanlucmakiola.calendula.ui.week.TimelineScreen
|
import de.jeanlucmakiola.calendula.ui.week.TimelineScreen
|
||||||
|
import kotlinx.coroutines.NonCancellable
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,14 +146,6 @@ fun CalendarHost(
|
|||||||
}
|
}
|
||||||
var navigationVersion by remember { mutableIntStateOf(0) }
|
var navigationVersion by remember { mutableIntStateOf(0) }
|
||||||
val view = viewStack.last()
|
val view = viewStack.last()
|
||||||
// The timeline view last shown, so the timeline leaving for another screen
|
|
||||||
// keeps drawing the view it was on while it goes.
|
|
||||||
var heldTimeline by rememberSaveable {
|
|
||||||
mutableStateOf(if (view.screen == ViewScreen.Timeline) view else CalendarView.Week)
|
|
||||||
}
|
|
||||||
val timelineView = if (view.screen == ViewScreen.Timeline) view else heldTimeline
|
|
||||||
SideEffect { heldTimeline = timelineView }
|
|
||||||
|
|
||||||
// The date every view opens on and carries along (#184); tapping a day
|
// The date every view opens on and carries along (#184); tapping a day
|
||||||
// anywhere focuses it and opens the day view there.
|
// anywhere focuses it and opens the day view there.
|
||||||
val focus = rememberSaveable(saver = ViewFocusSaver) { ViewFocus(localToday()) }
|
val focus = rememberSaveable(saver = ViewFocusSaver) { ViewFocus(localToday()) }
|
||||||
@@ -407,9 +404,30 @@ 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
|
||||||
navigationVersion++
|
// it (#185): the previous view morphs in under the finger, releasing finishes
|
||||||
viewStack = viewStack.dropLast(1)
|
// 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) {
|
||||||
|
navigationVersion++
|
||||||
|
viewStack = viewStack.dropLast(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PredictiveBackHandler(enabled = viewBackEnabled) { events ->
|
||||||
|
val previous = viewStack[viewStack.size - 2]
|
||||||
|
try {
|
||||||
|
events.collect { viewTransition.seekTo(it.progress, targetState = previous) }
|
||||||
|
navigationVersion++
|
||||||
|
viewStack = viewStack.dropLast(1)
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
withContext(NonCancellable) { viewTransition.animateTo(viewTransition.currentState) }
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(modifier = modifier.fillMaxSize()) {
|
Box(modifier = modifier.fillMaxSize()) {
|
||||||
@@ -418,7 +436,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()
|
||||||
val morphClip = remember { BelowTopBarClip() }
|
val morphClip = remember { BelowTopBarClip() }
|
||||||
@@ -493,11 +510,11 @@ fun CalendarHost(
|
|||||||
// Keyed on the screen, not the view: the day, multi-day and week views
|
// Keyed on the screen, not the view: the day, multi-day and week views
|
||||||
// are one timeline that resizes between them itself (#184), so switching
|
// are one timeline that resizes between them itself (#184), so switching
|
||||||
// among them must not replay this transition.
|
// among them must not replay this transition.
|
||||||
AnimatedContent(
|
rememberTransition(viewTransition, label = "view-switch").AnimatedContent(
|
||||||
targetState = view.screen,
|
|
||||||
transitionSpec = { viewSwitch },
|
transitionSpec = { viewSwitch },
|
||||||
label = "view-switch",
|
contentKey = { it.screen },
|
||||||
) { screen ->
|
) { currentView ->
|
||||||
|
val screen = currentView.screen
|
||||||
val sharedScope = this@SharedTransitionLayout
|
val sharedScope = this@SharedTransitionLayout
|
||||||
val visibilityScope = this@AnimatedContent
|
val visibilityScope = this@AnimatedContent
|
||||||
val viewMorph = remember(reduceMotion, sharedScope, visibilityScope, morphBounds, morphFade, morphClip, stayingPut) {
|
val viewMorph = remember(reduceMotion, sharedScope, visibilityScope, morphBounds, morphFade, morphClip, stayingPut) {
|
||||||
@@ -509,7 +526,7 @@ fun CalendarHost(
|
|||||||
) {
|
) {
|
||||||
when (screen) {
|
when (screen) {
|
||||||
ViewScreen.Timeline -> TimelineScreen(
|
ViewScreen.Timeline -> TimelineScreen(
|
||||||
view = timelineView,
|
view = currentView,
|
||||||
onOpenDay = onOpenDay,
|
onOpenDay = onOpenDay,
|
||||||
onEventClick = onEventClick,
|
onEventClick = onEventClick,
|
||||||
onCreateEvent = onCreateEvent,
|
onCreateEvent = onCreateEvent,
|
||||||
|
|||||||
Reference in New Issue
Block a user