Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make claim-flow navigation bar a shared element #2350

Merged
merged 1 commit into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions app/app/src/main/kotlin/com/hedvig/android/app/ui/HedvigApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ package com.hedvig.android.app.ui

import android.graphics.Color
import androidx.activity.SystemBarStyle
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.lifecycle.Lifecycle
Expand All @@ -22,6 +26,7 @@ import com.hedvig.android.app.urihandler.DeepLinkFirstUriHandler
import com.hedvig.android.app.urihandler.SafeAndroidUriHandler
import com.hedvig.android.auth.AuthStatus
import com.hedvig.android.auth.AuthTokenService
import com.hedvig.android.compose.ui.LocalSharedTransitionScope
import com.hedvig.android.core.appreview.WaitUntilAppReviewDialogShouldBeOpenedUseCase
import com.hedvig.android.core.buildconstants.HedvigBuildConstants
import com.hedvig.android.core.demomode.DemoManager
Expand Down Expand Up @@ -49,6 +54,7 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow

@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
internal fun HedvigApp(
navHostController: NavHostController,
Expand Down Expand Up @@ -99,19 +105,24 @@ internal fun HedvigApp(
navController = hedvigAppState.navController,
delegate = SafeAndroidUriHandler(LocalContext.current),
)
CompositionLocalProvider(LocalUriHandler provides deepLinkFirstUriHandler) {
HedvigAppUi(
hedvigAppState = hedvigAppState,
hedvigDeepLinkContainer = hedvigDeepLinkContainer,
externalNavigator = externalNavigator,
shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale,
openUrl = deepLinkFirstUriHandler::openUri,
finishApp = finishApp,
market = marketManager.market.collectAsStateWithLifecycle().value,
imageLoader = imageLoader,
languageService = languageService,
hedvigBuildConstants = hedvigBuildConstants,
)
SharedTransitionLayout(Modifier.fillMaxSize()) {
CompositionLocalProvider(
LocalUriHandler provides deepLinkFirstUriHandler,
LocalSharedTransitionScope provides this,
) {
HedvigAppUi(
hedvigAppState = hedvigAppState,
hedvigDeepLinkContainer = hedvigDeepLinkContainer,
externalNavigator = externalNavigator,
shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale,
openUrl = deepLinkFirstUriHandler::openUri,
finishApp = finishApp,
market = marketManager.market.collectAsStateWithLifecycle().value,
imageLoader = imageLoader,
languageService = languageService,
hedvigBuildConstants = hedvigBuildConstants,
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package com.hedvig.android.compose.ui

import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.animation.BoundsTransform
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.SharedTransitionScope
import androidx.compose.animation.SharedTransitionScope.OverlayClip
import androidx.compose.animation.SharedTransitionScope.PlaceHolderSize
import androidx.compose.animation.SharedTransitionScope.PlaceHolderSize.Companion.contentSize
import androidx.compose.animation.SharedTransitionScope.ResizeMode
import androidx.compose.animation.SharedTransitionScope.ResizeMode.Companion.ScaleToBounds
import androidx.compose.animation.SharedTransitionScope.SharedContentState
import androidx.compose.animation.core.Spring.StiffnessMediumLow
import androidx.compose.animation.core.SpringSpec
import androidx.compose.animation.core.VisibilityThreshold
import androidx.compose.animation.core.spring
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.Alignment.Companion.Center
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection

/**
* A local which contains the SharedTransitionScope wrapping the entire app. This is always taking up the entire
* screen's size and must be provided by the app's main activity
*/
val LocalSharedTransitionScope: ProvidableCompositionLocal<SharedTransitionScope> = compositionLocalOf {
error("The app must provide a SharedTransitionScope to the entire compose hierarchy")
}

@Composable
fun rememberGlobalSharedContentState(key: Any): SharedContentState =
LocalSharedTransitionScope.current.rememberSharedContentState(key)

fun Modifier.globalSharedElement(
sharedTransitionScope: SharedTransitionScope,
animatedVisibilityScope: AnimatedVisibilityScope,
state: SharedContentState,
boundsTransform: BoundsTransform = DefaultBoundsTransform,
placeHolderSize: PlaceHolderSize = contentSize,
renderInOverlayDuringTransition: Boolean = true,
zIndexInOverlay: Float = 0f,
clipInOverlayDuringTransition: OverlayClip = ParentClip,
): Modifier = with(sharedTransitionScope) {
[email protected](
state = state,
animatedVisibilityScope = animatedVisibilityScope,
boundsTransform = boundsTransform,
placeHolderSize = placeHolderSize,
renderInOverlayDuringTransition = renderInOverlayDuringTransition,
zIndexInOverlay = zIndexInOverlay,
clipInOverlayDuringTransition = clipInOverlayDuringTransition,
)
}

fun Modifier.globalSharedBounds(
sharedTransitionScope: SharedTransitionScope,
animatedVisibilityScope: AnimatedVisibilityScope,
state: SharedContentState,
enter: EnterTransition = fadeIn(),
exit: ExitTransition = fadeOut(),
boundsTransform: BoundsTransform = DefaultBoundsTransform,
resizeMode: ResizeMode = ScaleToBounds(ContentScale.FillWidth, Center),
placeHolderSize: PlaceHolderSize = contentSize,
renderInOverlayDuringTransition: Boolean = true,
zIndexInOverlay: Float = 0f,
clipInOverlayDuringTransition: OverlayClip = ParentClip,
): Modifier = with(sharedTransitionScope) {
[email protected](
sharedContentState = state,
animatedVisibilityScope = animatedVisibilityScope,
enter = enter,
exit = exit,
boundsTransform = boundsTransform,
resizeMode = resizeMode,
placeHolderSize = placeHolderSize,
renderInOverlayDuringTransition = renderInOverlayDuringTransition,
zIndexInOverlay = zIndexInOverlay,
clipInOverlayDuringTransition = clipInOverlayDuringTransition,
)
}

private val DefaultBoundsTransform: BoundsTransform = BoundsTransform { _, _ -> DefaultSpring }

private val DefaultSpring: SpringSpec<Rect> = spring(
stiffness = StiffnessMediumLow,
visibilityThreshold = Rect.VisibilityThreshold,
)

private val ParentClip: OverlayClip = object : OverlayClip {
override fun getClipPath(
state: SharedContentState,
bounds: Rect,
layoutDirection: LayoutDirection,
density: Density,
): Path? = state.parentSharedContentState?.clipPathInOverlay
}
2 changes: 2 additions & 0 deletions app/ui/ui-claim-flow/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ dependencies {
implementation(libs.androidx.compose.foundationLayout)
implementation(libs.androidx.compose.runtime)
implementation(libs.androidx.compose.uiCore)
implementation(projects.composeUi)
implementation(projects.coreResources)
implementation(projects.designSystemHedvig)
implementation(projects.navigationCompose)
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.hedvig.android.compose.ui.LocalSharedTransitionScope
import com.hedvig.android.compose.ui.globalSharedElement
import com.hedvig.android.compose.ui.rememberGlobalSharedContentState
import com.hedvig.android.design.system.hedvig.ErrorSnackbar
import com.hedvig.android.design.system.hedvig.ErrorSnackbarState
import com.hedvig.android.design.system.hedvig.HedvigAlertDialog
Expand All @@ -37,6 +40,7 @@ import com.hedvig.android.design.system.hedvig.TopAppBar
import com.hedvig.android.design.system.hedvig.TopAppBarActionType.BACK
import com.hedvig.android.design.system.hedvig.icon.Close
import com.hedvig.android.design.system.hedvig.icon.HedvigIcons
import com.hedvig.android.navigation.compose.LocalNavAnimatedVisibilityScope
import hedvig.resources.R

/**
Expand Down Expand Up @@ -74,7 +78,6 @@ fun ClaimFlowScaffold(
title = topAppBarText ?: "",
actionType = BACK,
onActionClick = navigateUp,
modifier = Modifier.fillMaxWidth(),
topAppBarActions = {
IconButton(
modifier = Modifier.size(24.dp),
Expand All @@ -87,6 +90,13 @@ fun ClaimFlowScaffold(
},
)
},
modifier = Modifier
.fillMaxWidth()
.globalSharedElement(
LocalSharedTransitionScope.current,
LocalNavAnimatedVisibilityScope.current,
rememberGlobalSharedContentState("com.hedvig.android.ui.claimflow.ClaimFlowScaffold"),
),
)
Column(
horizontalAlignment = itemsColumnHorizontalAlignment,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ private fun commonFreeCompilerArgs(): List<String> {
addAll(
listOf(
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
"-opt-in=androidx.compose.animation.ExperimentalSharedTransitionApi",
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
"-opt-in=androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi",
Expand Down
Loading