Skip to content

Commit

Permalink
Revert AnimatedScreen work on it later
Browse files Browse the repository at this point in the history
  • Loading branch information
stagg committed Nov 19, 2024
1 parent 62e3297 commit 918ca4e
Show file tree
Hide file tree
Showing 6 changed files with 11 additions and 218 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,9 @@ public object NavigatorDefaults {
// The states are available as `targetState` and `initialState`.
val diff = targetState.args.size - initialState.args.size
val sameRoot = targetState.args.lastOrNull() == initialState.args.lastOrNull()
val targetScreen = targetState.args.firstOrNull()?.screen
val initialScreen = initialState.args.firstOrNull()?.screen
when {
sameRoot && diff > 0 -> contentTransform(targetScreen, initialScreen, forward)
sameRoot && diff < 0 -> contentTransform(initialScreen, targetScreen, backward)
sameRoot && diff > 0 -> forward
sameRoot && diff < 0 -> backward
else -> fadeIn() togetherWith fadeOut()
}.using(
// Disable clipping since the faded slide-in/out should
Expand All @@ -361,16 +359,6 @@ public object NavigatorDefaults {
)
}

private fun contentTransform(
targetScreen: Screen?,
initialScreen: Screen?,
fallback: ContentTransform,
): ContentTransform {
return ((targetScreen as? AnimatedScreen)?.enterTransition()
?: fallback.targetContentEnter) togetherWith
((initialScreen as? AnimatedScreen)?.exitTransition() ?: fallback.initialContentExit)
}

@Composable
public override fun AnimatedContentScope.AnimatedNavContent(
targetState: DefaultAnimatedState<T>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,17 @@ package com.slack.circuit.foundation
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.core.Transition
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.Modifier
import com.slack.circuit.backstack.NavArgument
import com.slack.circuit.backstack.NavDecoration
import com.slack.circuit.retained.rememberRetained
import com.slack.circuit.runtime.screen.Screen
import com.slack.circuit.sharedelements.ProvideAnimatedTransitionScope
import com.slack.circuit.sharedelements.SharedElementTransitionScope.AnimatedScope.Navigation
Expand All @@ -49,22 +39,9 @@ public abstract class AnimatedNavDecoration(
}
with(decorator) {
Content(args, backStackDepth, modifier) { modifier ->
val backStackEntryState = sharedElementBackStack()
AnimatedContent(modifier = modifier, transitionSpec = transitionSpec()) { targetState ->
val animatedContentScope = this@AnimatedContent
ProvideAnimatedTransitionScope(Navigation, animatedContentScope) {
sharedElementTransitionScope ->
val entry = backStackEntryState.value
Box(
modifier =
Modifier.overrideAnimations(
animatedVisibilityScope = animatedContentScope,
screen = targetState.screen,
sharedElementTransition = sharedElementTransitionScope != null && entry != null,
)
) {
AnimatedNavContent(targetState) { content(it) }
}
ProvideAnimatedTransitionScope(Navigation, this) {
AnimatedNavContent(targetState) { content(it) }
}
}
}
Expand Down Expand Up @@ -110,148 +87,5 @@ public interface AnimatedNavState {
public val backStackDepth: Int
}

/** A [Screen] that supports custom Enter/Exit transitions. */
// TODO Remove AnimatedScreen and replace it with a mechanism to support custom transitions between
// any two given screens
public interface AnimatedNavigationOverride {
// todo Should this indicate if it's a backward navigation or forward navigation?
public fun transitionSpec(source: Screen, target: Screen, direction: Direction): ContentTransform?

// todo If we don't need the sharedBounds we don't need this. It might be nice to have this check
// so we default override any shared transition away from the normal animations?
public fun expectsSharedElementTransition(source: Screen, target: Screen): Boolean

public enum class Direction {
Forward,
Backward,
}
}

public interface AnimatedScreen : Screen {
/**
* A [EnterTransition] to use when showing this screen. If null is returned the screen is animated
* by the [NavDecoration].
*
* @param sharedElementTransition Whether this screen has a shared element transition.
*/
public fun enterTransition(sharedElementTransition: Boolean = false): EnterTransition? = null

/**
* A [EnterTransition] to use when hiding this screen. If null is returned the screen is animated
* by the [NavDecoration].
*
* @param sharedElementTransition Whether this screen has a shared element transition.
*/
public fun exitTransition(sharedElementTransition: Boolean = false): ExitTransition? = null

/**
* A key for use when a shared element transition is expected when navigating to this screen. If
* no shared element transition is expected, return `null`.
*/
public fun sharedElementTransitionKey(): Any? = null
}

/** Create or retrieve a [SharedElementBackStackEntry] for the current back stack. */
@Composable
private fun Transition<AnimatedNavState>.sharedElementBackStack():
State<SharedElementBackStackEntry?> {
val current = targetState.asNavArgBackStackState()
val previous = currentState.asNavArgBackStackState()

val sharedKeys = rememberRetained {
mutableStateMapOf<NavArgBackStackState, SharedElementBackStackEntry>()
}

var lastCurrent by rememberRetained { mutableStateOf(current) }
var lastPrevious by rememberRetained { mutableStateOf(previous) }

val lastCurrentValue = lastCurrent
val lastPreviousValue = lastPrevious

return produceState<SharedElementBackStackEntry?>(null, current, previous) {
// Ignore a settled state
if (current == previous) {
value = null
return@produceState
}
value =
when {
// Forward
lastCurrentValue == previous &&
(lastCurrentValue.backStackDepth + 1) == current.backStackDepth -> {
forwardSharedElementBackStackEntry(current.screen, previous.screen)?.also {
sharedKeys[current] = it
}
}
// Backward
lastPreviousValue == current &&
lastPreviousValue.backStackDepth == current.backStackDepth -> {
backwardSharedElementBackStackEntry(lastCurrentValue, current.screen, sharedKeys).also {
sharedKeys.remove(lastCurrentValue)
}
}
// Unknown
else -> null
}
lastCurrent = current
lastPrevious = previous
}
}

/** If navigating forward, with a key, we're expecting a shared element transition. */
private fun forwardSharedElementBackStackEntry(
current: Screen,
previous: Screen,
): SharedElementBackStackEntry? {
val currentScreen = current as? AnimatedScreen
val key = currentScreen?.sharedElementTransitionKey() ?: return null
return SharedElementBackStackEntry(key, currentScreen, previous)
}

/**
* If navigating backward, with a shared key, and screens already seen; We are expecting a shared
* element transition.
*/
private fun backwardSharedElementBackStackEntry(
lastCurrentArg: NavArgBackStackState,
current: Screen,
sharedKeys: SnapshotStateMap<NavArgBackStackState, SharedElementBackStackEntry>,
): SharedElementBackStackEntry? {
val previousScreen = lastCurrentArg.screen as? AnimatedScreen
val key = previousScreen?.sharedElementTransitionKey() ?: return null
val entry = sharedKeys[lastCurrentArg] ?: return null
return if (
key == entry.key && previousScreen == entry.currentScreen && current == entry.previousScreen
) {
entry
} else {
null
}
}

private fun Modifier.overrideAnimations(
animatedVisibilityScope: AnimatedVisibilityScope,
screen: Screen,
sharedElementTransition: Boolean,
): Modifier {
val animatedScreen = screen as? AnimatedScreen
val enter = animatedScreen?.enterTransition(sharedElementTransition)
val exit = animatedScreen?.exitTransition(sharedElementTransition)
if (enter == null || exit == null) return this
return with(animatedVisibilityScope) { animateEnterExit(enter = enter, exit = exit) }
}

private fun AnimatedNavState.asNavArgBackStackState(): NavArgBackStackState {
return NavArgBackStackState(screen, backStackDepth)
}

private data class NavArgBackStackState(val screen: Screen, val backStackDepth: Int)

private data class SharedElementBackStackEntry(
val key: Any,
val currentScreen: AnimatedScreen,
val previousScreen: Screen,
)

public class DefaultAnimatedNavDecoration(decoratorFactory: AnimatedNavDecorator.Factory) :
AnimatedNavDecoration(decoratorFactory)
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ datastore = "1.1.1"
detekt = "1.23.7"
dokka = "1.9.20"
eithernet = "2.0.0-alpha01"
jdk = "22"
jdk = "23"
jvmTarget = "11"
publishedJvmTarget = "1.8"
kct = "0.5.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ package com.slack.circuit.star.home
import androidx.compose.animation.EnterExitState
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.core.EaseInOutCubic
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
Expand All @@ -29,14 +27,14 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.unit.IntOffset
import com.slack.circuit.codegen.annotations.CircuitInject
import com.slack.circuit.foundation.AnimatedScreen
import com.slack.circuit.foundation.CircuitContent
import com.slack.circuit.foundation.NavEvent
import com.slack.circuit.foundation.onNavEvent
import com.slack.circuit.retained.rememberRetained
import com.slack.circuit.runtime.CircuitUiEvent
import com.slack.circuit.runtime.CircuitUiState
import com.slack.circuit.runtime.Navigator
import com.slack.circuit.runtime.screen.Screen
import com.slack.circuit.sharedelements.SharedElementTransitionScope
import com.slack.circuit.sharedelements.SharedElementTransitionScope.AnimatedScope.Navigation
import com.slack.circuit.sharedelements.progress
Expand All @@ -51,13 +49,7 @@ import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf

@CommonParcelize
data object HomeScreen : AnimatedScreen {

override fun enterTransition(sharedElementTransition: Boolean) =
if (sharedElementTransition) fadeIn() else null

override fun exitTransition(sharedElementTransition: Boolean) =
if (sharedElementTransition) fadeOut() else null
data object HomeScreen : Screen {

data class State(
val navItems: ImmutableList<BottomNavItem> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
package com.slack.circuit.star.petdetail

import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.ExperimentalLayoutApi
Expand Down Expand Up @@ -38,14 +36,14 @@ import androidx.compose.ui.text.capitalize
import androidx.compose.ui.text.intl.LocaleList
import androidx.compose.ui.unit.dp
import com.slack.circuit.codegen.annotations.CircuitInject
import com.slack.circuit.foundation.AnimatedScreen
import com.slack.circuit.foundation.CircuitContent
import com.slack.circuit.foundation.thenIf
import com.slack.circuit.foundation.thenIfNotNull
import com.slack.circuit.runtime.CircuitUiEvent
import com.slack.circuit.runtime.CircuitUiState
import com.slack.circuit.runtime.Navigator
import com.slack.circuit.runtime.presenter.Presenter
import com.slack.circuit.runtime.screen.Screen
import com.slack.circuit.sharedelements.DelicateCircuitSharedElementsApi
import com.slack.circuit.sharedelements.SharedElementTransitionScope
import com.slack.circuit.sharedelements.SharedElementTransitionScope.AnimatedScope.Navigation
Expand Down Expand Up @@ -87,17 +85,7 @@ data class PetDetailScreen(
val petId: Long,
val photoUrlMemoryCacheKey: String? = null,
val animal: PartialAnimal? = null,
) : AnimatedScreen {

override fun enterTransition(sharedElementTransition: Boolean) =
if (sharedElementTransition) fadeIn() else null

override fun exitTransition(sharedElementTransition: Boolean) =
if (sharedElementTransition) fadeOut() else null

override fun sharedElementTransitionKey(): Any? {
return if (animal != null && photoUrlMemoryCacheKey != null) petId else null
}
) : Screen {

@CommonParcelize
data class PartialAnimal(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@
// SPDX-License-Identifier: Apache-2.0
package com.slack.circuit.star.petlist

import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionScope.PlaceHolderSize.Companion.animatedSize
import androidx.compose.animation.SharedTransitionScope.ResizeMode.Companion.ScaleToBounds
import androidx.compose.animation.core.AnimationConstants
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
Expand Down Expand Up @@ -92,7 +89,6 @@ import coil3.compose.LocalPlatformContext
import coil3.request.ImageRequest.Builder
import coil3.request.crossfade
import com.slack.circuit.codegen.annotations.CircuitInject
import com.slack.circuit.foundation.AnimatedScreen
import com.slack.circuit.foundation.rememberAnsweringNavigator
import com.slack.circuit.overlay.OverlayEffect
import com.slack.circuit.retained.collectAsRetainedState
Expand All @@ -101,6 +97,7 @@ import com.slack.circuit.runtime.CircuitUiEvent
import com.slack.circuit.runtime.CircuitUiState
import com.slack.circuit.runtime.Navigator
import com.slack.circuit.runtime.presenter.Presenter
import com.slack.circuit.runtime.screen.Screen
import com.slack.circuit.sharedelements.SharedElementTransitionScope
import com.slack.circuit.sharedelements.SharedElementTransitionScope.AnimatedScope.Navigation
import com.slack.circuit.sharedelements.progress
Expand Down Expand Up @@ -145,13 +142,7 @@ import kotlinx.collections.immutable.toImmutableSet
import kotlinx.coroutines.flow.map

@CommonParcelize
data object PetListScreen : AnimatedScreen {

override fun enterTransition(sharedElementTransition: Boolean) =
if (sharedElementTransition) EnterTransition.None else null

override fun exitTransition(sharedElementTransition: Boolean) =
if (sharedElementTransition) ExitTransition.None else fadeOut()
data object PetListScreen : Screen {

sealed interface State : CircuitUiState {
val isRefreshing: Boolean
Expand Down

0 comments on commit 918ca4e

Please sign in to comment.