Updated on 2026-08-14
This commit is contained in:
parent
12fc61bbdc
commit
9334609daf
19 changed files with 297 additions and 206 deletions
|
|
@ -43,6 +43,7 @@
|
|||
android:resizeableActivity="@bool/resizeable_activity"
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:supportsRtl="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
tools:ignore="GoogleAppIndexingWarning"
|
||||
tools:replace="android:allowBackup, android:fullBackupContent, android:label">
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.tap.features.details.ui.common
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.selection.selectable
|
||||
|
|
@ -29,8 +28,6 @@ internal fun SettingsScreensScaffold(
|
|||
) {
|
||||
val backgroundColor = TangemTheme.colors.background.secondary
|
||||
|
||||
BackHandler(onBack = onBackClick)
|
||||
|
||||
Scaffold(
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
topBar = {
|
||||
|
|
|
|||
|
|
@ -2,14 +2,18 @@ package com.tangem.tap.features.home
|
|||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.arkivanov.essenty.lifecycle.subscribe
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.SystemBarsIconsDisposable
|
||||
import com.tangem.core.ui.res.LocalRootBackgroundColor
|
||||
import com.tangem.core.ui.utils.findActivity
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.home.api.HomeComponent
|
||||
|
|
@ -61,6 +65,17 @@ internal class DefaultHomeComponent @AssistedInject constructor(
|
|||
onShopButtonClick = model::onShopClick,
|
||||
onSearchTokensClick = model::onSearchClick,
|
||||
)
|
||||
|
||||
val rootBackgroundColor = LocalRootBackgroundColor.current
|
||||
val previousColor = remember { rootBackgroundColor.value }
|
||||
val storiesBackgroundColor = Color(color = 0xFF010101)
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
rootBackgroundColor.value = storiesBackgroundColor
|
||||
onDispose {
|
||||
rootBackgroundColor.value = previousColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun newState(state: HomeState) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.routing
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
|
|
@ -8,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -17,25 +17,31 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.core.content.ContextCompat.startActivity
|
||||
import com.arkivanov.decompose.ExperimentalDecomposeApi
|
||||
import com.arkivanov.decompose.extensions.compose.stack.Children
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.fade
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.StackAnimation
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.predictiveback.androidPredictiveBackAnimatable
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.predictiveback.predictiveBackAnimation
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
|
||||
import com.arkivanov.decompose.router.stack.ChildStack
|
||||
import com.arkivanov.decompose.value.Value
|
||||
import com.arkivanov.essenty.backhandler.BackHandler
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.components.snackbar.TangemSnackbarHost
|
||||
import com.tangem.core.ui.message.EventMessageEffect
|
||||
import com.tangem.core.ui.res.LocalIsNavigationRefactoringEnabled
|
||||
import com.tangem.core.ui.res.LocalRootBackgroundColor
|
||||
import com.tangem.core.ui.res.LocalSnackbarHostState
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.tap.routing.component.RoutingComponent
|
||||
import com.tangem.tap.routing.transitions.RoutingTransitionAnimationFactory
|
||||
|
||||
@OptIn(ExperimentalDecomposeApi::class)
|
||||
@Composable
|
||||
internal fun RootContent(
|
||||
stack: Value<ChildStack<AppRoute, RoutingComponent.Child>>,
|
||||
wcContent: @Composable (modifier: Modifier) -> Unit,
|
||||
backHandler: BackHandler,
|
||||
uiDependencies: UiDependencies,
|
||||
wcContent: @Composable (modifier: Modifier) -> Unit,
|
||||
onBack: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
|
@ -44,45 +50,62 @@ internal fun RootContent(
|
|||
activity = context as Activity,
|
||||
uiDependencies = uiDependencies,
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalIsNavigationRefactoringEnabled provides true,
|
||||
) {
|
||||
val snackbarHostState = LocalSnackbarHostState.current
|
||||
val snackbarHostState = LocalSnackbarHostState.current
|
||||
|
||||
Box(Modifier.background(TangemTheme.colors.background.primary)) {
|
||||
Children(
|
||||
modifier = modifier,
|
||||
animation = stackAnimation(fade()),
|
||||
stack = stack,
|
||||
) { child ->
|
||||
when (val instance = child.instance) {
|
||||
is RoutingComponent.Child.Initial -> Unit
|
||||
is RoutingComponent.Child.ComposableComponent -> {
|
||||
instance.component.Content(Modifier.fillMaxSize())
|
||||
Box(Modifier.background(LocalRootBackgroundColor.current.value)) {
|
||||
Children(
|
||||
modifier = modifier,
|
||||
animation = childrenAnimation(backHandler = backHandler, onBack = onBack),
|
||||
stack = stack,
|
||||
) { child ->
|
||||
when (val instance = child.instance) {
|
||||
is RoutingComponent.Child.Initial -> Unit
|
||||
is RoutingComponent.Child.ComposableComponent -> {
|
||||
instance.component.Content(Modifier.fillMaxSize())
|
||||
}
|
||||
is RoutingComponent.Child.LegacyIntent -> {
|
||||
// TODO: Remove and use it's own router: [REDACTED_JIRA]
|
||||
LaunchedEffect(instance) {
|
||||
startActivity(context, instance.intent, Bundle.EMPTY)
|
||||
}
|
||||
is RoutingComponent.Child.LegacyIntent -> {
|
||||
// TODO: Remove and use it's own router: [REDACTED_JIRA]
|
||||
LaunchedEffect(instance) {
|
||||
startActivity(context, instance.intent, Bundle.EMPTY)
|
||||
}
|
||||
}
|
||||
is RoutingComponent.Child.LegacyFragment,
|
||||
-> error("Unsupported child: $instance")
|
||||
}
|
||||
}
|
||||
|
||||
wcContent(Modifier.fillMaxSize())
|
||||
|
||||
TangemSnackbarHost(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.navigationBarsPadding()
|
||||
.padding(all = 16.dp),
|
||||
hostState = snackbarHostState,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
EventMessageEffect()
|
||||
wcContent(Modifier.fillMaxSize())
|
||||
|
||||
TangemSnackbarHost(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.navigationBarsPadding()
|
||||
.padding(all = 16.dp),
|
||||
hostState = snackbarHostState,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
EventMessageEffect()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalDecomposeApi::class)
|
||||
private fun childrenAnimation(
|
||||
backHandler: BackHandler,
|
||||
onBack: () -> Unit,
|
||||
): StackAnimation<AppRoute, RoutingComponent.Child> {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
predictiveBackAnimation(
|
||||
backHandler = backHandler,
|
||||
onBack = onBack,
|
||||
selector = { backEvent, _, _ ->
|
||||
androidPredictiveBackAnimatable(backEvent)
|
||||
},
|
||||
fallbackAnimation = stackAnimation {
|
||||
RoutingTransitionAnimationFactory.create(it.configuration)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
stackAnimation {
|
||||
RoutingTransitionAnimationFactory.create(it.configuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,9 @@ package com.tangem.tap.routing.component
|
|||
|
||||
import android.content.Intent
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.utils.Provider
|
||||
|
||||
internal interface RoutingComponent : ComposableContentComponent {
|
||||
|
||||
|
|
@ -16,11 +14,6 @@ internal interface RoutingComponent : ComposableContentComponent {
|
|||
// TODO: Remove and find initial intent in RoutingComponent: [REDACTED_JIRA]
|
||||
data object Initial : Child()
|
||||
|
||||
data class LegacyFragment(
|
||||
val name: String,
|
||||
val fragmentProvider: Provider<Fragment>,
|
||||
) : Child()
|
||||
|
||||
data class LegacyIntent(val intent: Intent) : Child()
|
||||
|
||||
data class ComposableComponent(
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
stack = stack,
|
||||
uiDependencies = uiDependencies,
|
||||
wcContent = { wcRoutingComponent.Content(it) },
|
||||
backHandler = backHandler,
|
||||
onBack = router::pop,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
package com.tangem.tap.routing.transitions
|
||||
|
||||
import androidx.compose.animation.core.CubicBezierEasing
|
||||
import androidx.compose.animation.core.FiniteAnimationSpec
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.layout.layout
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.*
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import kotlin.compareTo
|
||||
import kotlin.times
|
||||
|
||||
object RoutingTransitionAnimationFactory {
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
fun create(appRoute: AppRoute): StackAnimator {
|
||||
return when (appRoute) {
|
||||
is AppRoute.Onboarding,
|
||||
is AppRoute.Welcome,
|
||||
is AppRoute.Home,
|
||||
-> fade(tween(400)).plus(scale(tween(400)))
|
||||
is AppRoute.Wallet,
|
||||
-> slideAndFade(directions = setOf(Direction.ENTER_BACK, Direction.EXIT_BACK))
|
||||
.plus(
|
||||
scaleWithDirection(
|
||||
directions = setOf(Direction.ENTER_FRONT, Direction.EXIT_FRONT),
|
||||
animationSpec = tween(400),
|
||||
),
|
||||
)
|
||||
else -> slideAndFade()
|
||||
}
|
||||
}
|
||||
|
||||
private fun scaleWithDirection(
|
||||
directions: Set<Direction>,
|
||||
animationSpec: FiniteAnimationSpec<Float> = tween(),
|
||||
frontFactor: Float = 1.15F,
|
||||
backFactor: Float = 0.95F,
|
||||
): StackAnimator = stackAnimator(animationSpec = animationSpec) { factor, direction, content ->
|
||||
content(
|
||||
Modifier.graphicsLayer {
|
||||
val scaleFactor = if (directions.contains(direction)) {
|
||||
if (factor >= 0F) {
|
||||
factor * (frontFactor - 1F) + 1F
|
||||
} else {
|
||||
factor * (1F - backFactor) + 1F
|
||||
}
|
||||
} else {
|
||||
1f
|
||||
}
|
||||
scaleX = scaleFactor
|
||||
scaleY = scaleFactor
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
private fun slideAndFade(directions: Set<Direction>? = null): StackAnimator {
|
||||
val easing = CubicBezierEasing(0.55f, 0.0f, 0.0f, 1f)
|
||||
|
||||
return stackAnimator(
|
||||
animationSpec = tween(durationMillis = 400, easing = easing),
|
||||
) { factor, direction, content ->
|
||||
content(
|
||||
if (directions == null || directions.contains(direction)) {
|
||||
Modifier.offsetXFactor(factor)
|
||||
} else {
|
||||
Modifier
|
||||
},
|
||||
)
|
||||
}.plus(
|
||||
fade(
|
||||
animationSpec = tween(
|
||||
delayMillis = 50,
|
||||
durationMillis = 300,
|
||||
easing = easing,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
private fun Modifier.offsetXFactor(factor: Float): Modifier = layout { measurable, constraints ->
|
||||
val placeable = measurable.measure(constraints)
|
||||
|
||||
layout(placeable.width, placeable.height) {
|
||||
placeable.placeRelative(x = (placeable.width.toFloat() * factor * 0.15f).toInt(), y = 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -87,6 +87,8 @@ fun TangemTheme(
|
|||
DefaultHapticManager(view = view, vibratorHapticManager = vibratorHapticManager)
|
||||
}
|
||||
|
||||
val rootBackgroundColor = rememberedColors.background.secondary
|
||||
|
||||
MaterialTheme(
|
||||
colors = materialThemeColors(colors = themeColors, isDark = isDark),
|
||||
) {
|
||||
|
|
@ -105,6 +107,7 @@ fun TangemTheme(
|
|||
CompositionLocalProvider(
|
||||
LocalTangemShimmer provides TangemShimmer,
|
||||
LocalMainBottomSheetColor provides remember { mutableStateOf(Color.Unspecified) },
|
||||
LocalRootBackgroundColor provides remember { mutableStateOf(rootBackgroundColor) },
|
||||
LocalTextSelectionColors provides TangemTextSelectionColors,
|
||||
) {
|
||||
ProvideTextStyle(
|
||||
|
|
@ -308,13 +311,12 @@ val LocalMainBottomSheetColor = staticCompositionLocalOf<MutableState<Color>> {
|
|||
error("No MainBottomSheetColor provided")
|
||||
}
|
||||
|
||||
val LocalBladeAnimation = staticCompositionLocalOf<BladeAnimation> {
|
||||
val LocalRootBackgroundColor = staticCompositionLocalOf<MutableState<Color>> {
|
||||
error("No MainBottomSheetColor provided")
|
||||
}
|
||||
|
||||
// TODO remove this after migration to new navigation
|
||||
val LocalIsNavigationRefactoringEnabled = staticCompositionLocalOf<Boolean> {
|
||||
false
|
||||
val LocalBladeAnimation = staticCompositionLocalOf<BladeAnimation> {
|
||||
error("No MainBottomSheetColor provided")
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.features.details.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.gestures.scrollable
|
||||
|
|
@ -41,8 +40,6 @@ internal fun DetailsScreen(
|
|||
) {
|
||||
val backgroundColor = TangemTheme.colors.background.secondary
|
||||
|
||||
BackHandler(onBack = state.popBack)
|
||||
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
containerColor = backgroundColor,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.features.disclaimer.impl.component.impl
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -24,8 +23,6 @@ internal class DefaultDisclaimerComponent @AssistedInject constructor(
|
|||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
|
||||
BackHandler(onBack = state.popBack)
|
||||
DisclaimerScreen(state = state)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.features.managetokens.component.impl
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -42,8 +41,6 @@ internal class DefaultManageTokensComponent @AssistedInject constructor(
|
|||
val state by model.state.collectAsStateWithLifecycle()
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
|
||||
BackHandler(onBack = state.popBack)
|
||||
|
||||
ManageTokensScreen(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
|
|
|
|||
|
|
@ -124,10 +124,6 @@ internal class DefaultMarketsTokenDetailsComponent @AssistedInject constructor(
|
|||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
BackHandler {
|
||||
navigateBack()
|
||||
}
|
||||
|
||||
LifecycleStartEffect(Unit) {
|
||||
model.isVisibleOnScreen.value = true
|
||||
onStopOrDispose {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ internal class DefaultMarketsEntryComponent @AssistedInject constructor(
|
|||
source = stackNavigation,
|
||||
serializer = Child.serializer(),
|
||||
initialConfiguration = Child.TokenList,
|
||||
handleBackButton = true,
|
||||
handleBackButton = false,
|
||||
childFactory = { configuration, factoryContext ->
|
||||
marketsEntryChildFactory.createChild(
|
||||
child = configuration,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.tangem.feature.referral.ui
|
|||
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
|
|
@ -52,8 +51,6 @@ import kotlinx.coroutines.launch
|
|||
internal fun ReferralScreen(stateHolder: ReferralStateHolder) {
|
||||
val snackbarHostState = remember(::SnackbarHostState)
|
||||
|
||||
BackHandler(onBack = stateHolder.headerState.onBackClicked)
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
AppBarWithBackButton(
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
package com.tangem.feature.stories.impl
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.ui.swapStoriesScreen.SwapStoriesScreen
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.res.LocalRootBackgroundColor
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.feature.stories.api.StoriesComponent
|
||||
import com.tangem.feature.stories.impl.model.StoriesModel
|
||||
import dagger.assisted.Assisted
|
||||
|
|
@ -25,6 +29,16 @@ internal class DefaultStoriesComponent @AssistedInject constructor(
|
|||
override fun Content(modifier: Modifier) {
|
||||
val state = model.state.collectAsStateWithLifecycle()
|
||||
SwapStoriesScreen(state.value)
|
||||
|
||||
val rootBackgroundColor = LocalRootBackgroundColor.current
|
||||
val previousColor = remember { rootBackgroundColor.value }
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
rootBackgroundColor.value = TangemColorPalette.Black
|
||||
onDispose {
|
||||
rootBackgroundColor.value = previousColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.*
|
||||
import androidx.compose.material3.Scaffold
|
||||
|
|
@ -53,7 +52,6 @@ internal fun TokenDetailsScreen(
|
|||
tokenMarketBlockComponent: TokenMarketBlockComponent?,
|
||||
txHistoryComponent: TxHistoryComponent?,
|
||||
) {
|
||||
BackHandler(onBack = state.topAppBarConfig.onBackClick)
|
||||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
|
||||
Scaffold(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.feature.walletsettings.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
|
|
@ -37,8 +36,6 @@ internal fun WalletSettingsScreen(
|
|||
) {
|
||||
val backgroundColor = TangemTheme.colors.background.secondary
|
||||
|
||||
BackHandler(onBack = state.popBack)
|
||||
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
containerColor = backgroundColor,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
package com.tangem.feature.wallet.child.wallet
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
|
|
@ -16,7 +14,6 @@ import com.tangem.core.decompose.model.getOrCreateModel
|
|||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.decompose.ComposableDialogComponent
|
||||
import com.tangem.core.ui.utils.findActivity
|
||||
import com.tangem.feature.wallet.child.wallet.model.WalletModel
|
||||
import com.tangem.feature.wallet.navigation.WalletRoute
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig
|
||||
|
|
@ -77,9 +74,6 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val activity = LocalContext.current.findActivity()
|
||||
BackHandler { activity.finish() }
|
||||
|
||||
val dialog by dialog.subscribeAsState()
|
||||
|
||||
WalletScreen(
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import androidx.compose.animation.fadeIn
|
|||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideIn
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.*
|
||||
|
|
@ -24,7 +25,6 @@ import androidx.compose.ui.focus.onFocusChanged
|
|||
import androidx.compose.ui.geometry.*
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Path
|
||||
import androidx.compose.ui.graphics.luminance
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
|
|
@ -40,7 +40,6 @@ import androidx.compose.ui.unit.DpSize
|
|||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheet
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.expressTransactionsItems
|
||||
|
|
@ -59,7 +58,6 @@ import com.tangem.core.ui.components.snackbar.TangemSnackbar
|
|||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalIsNavigationRefactoringEnabled
|
||||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.LocalWindowSize
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -336,108 +334,121 @@ private inline fun BaseScaffoldWithMarkets(
|
|||
) {
|
||||
val backgroundColor = LocalMainBottomSheetColor.current
|
||||
var isSearchFieldFocused by remember { mutableStateOf(false) }
|
||||
val isNavBarVisible = remember { mutableStateOf(true) }
|
||||
|
||||
BottomSheetStateEffects(
|
||||
bottomSheetState = bottomSheetState,
|
||||
alertConfig = alertConfig,
|
||||
onBottomSheetStateChange = onBottomSheetStateChange,
|
||||
navigationBarVisible = isNavBarVisible,
|
||||
isSearchFieldFocused = isSearchFieldFocused,
|
||||
)
|
||||
|
||||
TangemBottomSheetScaffold(
|
||||
snackbarHost = {
|
||||
WalletSnackbarHost(
|
||||
snackbarHostState = it,
|
||||
event = state.event,
|
||||
modifier = Modifier
|
||||
.padding(bottom = TangemTheme.dimens.spacing4)
|
||||
.navigationBarsPadding(),
|
||||
)
|
||||
},
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
sheetContainerColor = backgroundColor.value,
|
||||
scaffoldState = scaffoldState,
|
||||
sheetPeekHeight = peekHeight,
|
||||
sheetShape = TangemTheme.shapes.bottomSheetLarge,
|
||||
sheetContent = {
|
||||
// hide bottom sheet when back pressed
|
||||
BackHandler(
|
||||
isKeyboardVisible.not() &&
|
||||
bottomSheetState.currentValue == TangemSheetValue.Expanded,
|
||||
) {
|
||||
coroutineScope.launch { bottomSheetState.partialExpand() }
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.sizeIn(maxHeight = maxHeight - statusBarHeight),
|
||||
) {
|
||||
Hand(Modifier.drawBehind { drawRect(backgroundColor.value) })
|
||||
|
||||
Box(
|
||||
Box {
|
||||
TangemBottomSheetScaffold(
|
||||
snackbarHost = {
|
||||
WalletSnackbarHost(
|
||||
snackbarHostState = it,
|
||||
event = state.event,
|
||||
modifier = Modifier
|
||||
// expand bottom sheet when clicked on the header
|
||||
.clickable(
|
||||
enabled = bottomSheetState.currentValue == TangemSheetValue.PartiallyExpanded,
|
||||
indication = null,
|
||||
interactionSource = null,
|
||||
) {
|
||||
coroutineScope.launch { bottomSheetState.expand() }
|
||||
}
|
||||
.onFocusChanged {
|
||||
isSearchFieldFocused = it.isFocused
|
||||
},
|
||||
) {
|
||||
bottomSheetContent()
|
||||
}
|
||||
}
|
||||
},
|
||||
content = { paddingValues ->
|
||||
Box {
|
||||
MarketsHint(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(bottom = peekHeight + 12.dp)
|
||||
.fillMaxWidth(fraction = .4f),
|
||||
isVisible = showMarketsHint,
|
||||
.padding(bottom = TangemTheme.dimens.spacing4)
|
||||
.navigationBarsPadding(),
|
||||
)
|
||||
},
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
sheetContainerColor = backgroundColor.value,
|
||||
scaffoldState = scaffoldState,
|
||||
sheetPeekHeight = peekHeight,
|
||||
sheetShape = TangemTheme.shapes.bottomSheetLarge,
|
||||
sheetContent = {
|
||||
// hide bottom sheet when back pressed
|
||||
BackHandler(
|
||||
isKeyboardVisible.not() &&
|
||||
bottomSheetState.currentValue == TangemSheetValue.Expanded,
|
||||
) {
|
||||
coroutineScope.launch { bottomSheetState.partialExpand() }
|
||||
}
|
||||
|
||||
Column {
|
||||
WalletTopBar(config = state.topBarConfig)
|
||||
TangemPullToRefreshContainer(config = selectedWallet.pullToRefreshConfig) {
|
||||
content(paddingValues)
|
||||
Column(
|
||||
modifier = Modifier.sizeIn(maxHeight = maxHeight - statusBarHeight),
|
||||
) {
|
||||
Hand(Modifier.drawBehind { drawRect(backgroundColor.value) })
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
// expand bottom sheet when clicked on the header
|
||||
.clickable(
|
||||
enabled = bottomSheetState.currentValue == TangemSheetValue.PartiallyExpanded,
|
||||
indication = null,
|
||||
interactionSource = null,
|
||||
) {
|
||||
coroutineScope.launch { bottomSheetState.expand() }
|
||||
}
|
||||
.onFocusChanged {
|
||||
isSearchFieldFocused = it.isFocused
|
||||
},
|
||||
) {
|
||||
bottomSheetContent()
|
||||
}
|
||||
}
|
||||
},
|
||||
content = { paddingValues ->
|
||||
Box {
|
||||
MarketsHint(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(bottom = peekHeight + 12.dp)
|
||||
.fillMaxWidth(fraction = .4f),
|
||||
isVisible = showMarketsHint,
|
||||
)
|
||||
|
||||
BottomSheetScrim(
|
||||
color = if (state.showMarketsOnboarding) {
|
||||
Color.Black.copy(alpha = .65f)
|
||||
} else {
|
||||
BottomSheetDefaults.ScrimColor
|
||||
},
|
||||
visible = bottomSheetState.targetValue == TangemSheetValue.Expanded ||
|
||||
state.showMarketsOnboarding,
|
||||
onDismissRequest = {
|
||||
coroutineScope.launch { bottomSheetState.partialExpand() }
|
||||
state.onDismissMarketsOnboarding()
|
||||
},
|
||||
)
|
||||
Column {
|
||||
WalletTopBar(config = state.topBarConfig)
|
||||
TangemPullToRefreshContainer(config = selectedWallet.pullToRefreshConfig) {
|
||||
content(paddingValues)
|
||||
}
|
||||
}
|
||||
|
||||
MarketsTooltip(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(bottom = 24.dp)
|
||||
.fillMaxWidth(fraction = 0.7f),
|
||||
isVisible = state.showMarketsOnboarding,
|
||||
availableHeight = if (LocalIsNavigationRefactoringEnabled.current) {
|
||||
maxHeight
|
||||
} else {
|
||||
maxHeight - statusBarHeight - bottomBarHeight
|
||||
},
|
||||
bottomSheetState = bottomSheetState,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
BottomSheetScrim(
|
||||
color = if (state.showMarketsOnboarding) {
|
||||
Color.Black.copy(alpha = .65f)
|
||||
} else {
|
||||
BottomSheetDefaults.ScrimColor
|
||||
},
|
||||
visible = bottomSheetState.targetValue == TangemSheetValue.Expanded ||
|
||||
state.showMarketsOnboarding,
|
||||
onDismissRequest = {
|
||||
coroutineScope.launch { bottomSheetState.partialExpand() }
|
||||
state.onDismissMarketsOnboarding()
|
||||
},
|
||||
)
|
||||
|
||||
MarketsTooltip(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(bottom = 24.dp)
|
||||
.fillMaxWidth(fraction = 0.7f),
|
||||
isVisible = state.showMarketsOnboarding,
|
||||
availableHeight = maxHeight,
|
||||
bottomSheetState = bottomSheetState,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
modifier = Modifier.align(Alignment.BottomCenter),
|
||||
visible = isNavBarVisible.value,
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.background(backgroundColor.value)
|
||||
.height(bottomBarHeight)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(state.showMarketsOnboarding, bottomSheetState.targetValue) {
|
||||
if (state.showMarketsOnboarding && bottomSheetState.targetValue == TangemSheetValue.Expanded) {
|
||||
|
|
@ -599,49 +610,17 @@ private fun BottomSheetScrim(color: Color, visible: Boolean, onDismissRequest: (
|
|||
private fun BottomSheetStateEffects(
|
||||
bottomSheetState: TangemSheetState,
|
||||
alertConfig: WalletAlertState?,
|
||||
navigationBarVisible: MutableState<Boolean>,
|
||||
onBottomSheetStateChange: (BottomSheetState) -> Unit,
|
||||
isSearchFieldFocused: Boolean,
|
||||
) {
|
||||
val systemUiController = rememberSystemUiController()
|
||||
val navigationBarColor = TangemTheme.colors.background.primary
|
||||
|
||||
LaunchedEffect(navigationBarColor) {
|
||||
delay(timeMillis = 100)
|
||||
when (bottomSheetState.currentValue) {
|
||||
TangemSheetValue.Hidden,
|
||||
TangemSheetValue.Expanded,
|
||||
-> systemUiController.setNavigationBarColor(
|
||||
color = Color.Transparent,
|
||||
darkIcons = navigationBarColor.luminance() > 0.5f,
|
||||
navigationBarContrastEnforced = true,
|
||||
)
|
||||
TangemSheetValue.PartiallyExpanded,
|
||||
-> systemUiController.setNavigationBarColor(navigationBarColor)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(bottomSheetState.targetValue, navigationBarColor) {
|
||||
LaunchedEffect(bottomSheetState.targetValue) {
|
||||
when (bottomSheetState.targetValue) {
|
||||
TangemSheetValue.Hidden,
|
||||
TangemSheetValue.Expanded,
|
||||
-> systemUiController.setNavigationBarColor(
|
||||
color = Color.Transparent,
|
||||
darkIcons = navigationBarColor.luminance() > 0.5f,
|
||||
navigationBarContrastEnforced = true,
|
||||
)
|
||||
-> navigationBarVisible.value = false
|
||||
TangemSheetValue.PartiallyExpanded,
|
||||
-> systemUiController.setNavigationBarColor(navigationBarColor)
|
||||
}
|
||||
}
|
||||
|
||||
// make navigation bar transparent when leaving the screen
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
systemUiController.setNavigationBarColor(
|
||||
color = Color.Transparent,
|
||||
darkIcons = navigationBarColor.luminance() > 0.5f,
|
||||
navigationBarContrastEnforced = false,
|
||||
)
|
||||
-> navigationBarVisible.value = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue