From 6948168b9c5138e603932305a30f859b0cd856e3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 19 Feb 2024 17:42:35 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../ui/AddCustomTokenBottomSheet.kt | 90 ++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/AddCustomTokenBottomSheet.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/AddCustomTokenBottomSheet.kt index 499c2e6cb4..69fe567327 100644 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/AddCustomTokenBottomSheet.kt +++ b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/AddCustomTokenBottomSheet.kt @@ -1,13 +1,22 @@ package com.tangem.managetokens.presentation.addcustomtoken.ui import android.annotation.SuppressLint +import androidx.activity.compose.BackHandler +import androidx.activity.compose.LocalOnBackPressedDispatcherOwner +import androidx.compose.foundation.focusable +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.systemBars +import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.ModalBottomSheetDefaults +import androidx.compose.material3.ModalBottomSheetProperties +import androidx.compose.material3.SheetState +import androidx.compose.material3.SheetValue import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -15,8 +24,18 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.KeyEventType +import androidx.compose.ui.input.key.key +import androidx.compose.ui.input.key.onPreviewKeyEvent +import androidx.compose.ui.input.key.type import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable @@ -29,6 +48,7 @@ import com.tangem.managetokens.presentation.addcustomtoken.router.AddCustomToken import com.tangem.managetokens.presentation.addcustomtoken.router.AddCustomTokenRouter import com.tangem.managetokens.presentation.addcustomtoken.viewmodels.AddCustomTokenViewModel import com.tangem.managetokens.presentation.common.state.ChooseWalletState +import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -46,14 +66,14 @@ fun AddCustomTokenBottomSheet(config: TangemBottomSheetConfig) { onDispose { viewModel.onDispose() } } - // FIXME: handle back presses after updating material3 to 1.2.0 - ModalBottomSheet( + ModalBottomSheetWithBackHandling( onDismissRequest = config.onDismissRequest, sheetState = sheetState, containerColor = TangemTheme.colors.background.tertiary, shape = TangemTheme.shapes.bottomSheetLarge, windowInsets = WindowInsets.systemBars.only(WindowInsetsSides.Top), dragHandle = { TangemBottomSheetDraggableHeader(color = TangemTheme.colors.background.tertiary) }, + properties = ModalBottomSheetDefaults.properties(shouldDismissOnBackPress = false), ) { Content(onDismissRequest = config.onDismissRequest, viewModel = viewModel) } @@ -68,6 +88,68 @@ fun AddCustomTokenBottomSheet(config: TangemBottomSheetConfig) { } } +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun ModalBottomSheetWithBackHandling( + onDismissRequest: () -> Unit, + modifier: Modifier = Modifier, + containerColor: Color = BottomSheetDefaults.ContainerColor, + shape: Shape = BottomSheetDefaults.ExpandedShape, + windowInsets: WindowInsets = BottomSheetDefaults.windowInsets, + dragHandle: @Composable (() -> Unit)? = { BottomSheetDefaults.DragHandle() }, + sheetState: SheetState = rememberModalBottomSheetState(), + properties: ModalBottomSheetProperties = ModalBottomSheetDefaults.properties(), + content: @Composable ColumnScope.() -> Unit, +) { + val scope = rememberCoroutineScope() + + BackHandler(enabled = sheetState.targetValue != SheetValue.Hidden) { + // Always catch back here, but only let it dismiss if shouldDismissOnBackPress. + // If not, it will have no effect. + if (properties.shouldDismissOnBackPress) { + scope.launch { sheetState.hide() }.invokeOnCompletion { + if (!sheetState.isVisible) { + onDismissRequest() + } + } + } + } + + val requester = remember { FocusRequester() } + val backPressedDispatcherOwner = LocalOnBackPressedDispatcherOwner.current + + ModalBottomSheet( + onDismissRequest = onDismissRequest, + containerColor = containerColor, + shape = shape, + windowInsets = windowInsets, + dragHandle = dragHandle, + sheetState = sheetState, + modifier = modifier + .focusRequester(requester) + .focusable() + .onPreviewKeyEvent { + if (it.key == Key.Back && it.type == KeyEventType.KeyUp && !it.nativeKeyEvent.isCanceled) { + backPressedDispatcherOwner?.onBackPressedDispatcher?.onBackPressed() + return@onPreviewKeyEvent true + } + return@onPreviewKeyEvent false + }, + properties = ModalBottomSheetDefaults.properties( + securePolicy = properties.securePolicy, + isFocusable = properties.isFocusable, + // Set false otherwise the onPreviewKeyEvent doesn't work at all. + // The functionality of shouldDismissOnBackPress is achieved by the BackHandler. + shouldDismissOnBackPress = false, + ), + content = content, + ) + + LaunchedEffect(Unit) { + requester.requestFocus() + } +} + @SuppressLint("RestrictedApi") @Composable private fun Content(viewModel: AddCustomTokenViewModel, onDismissRequest: () -> Unit) { @@ -82,6 +164,10 @@ private fun Content(viewModel: AddCustomTokenViewModel, onDismissRequest: () -> } } + BackHandler(true) { + navController.popBackStack() + } + val router = remember(navController) { AddCustomTokenRouter(navController) } viewModel.router = router