From 70c989be4e628ebc29725d9fb7a1ce6e3aa8ece2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 17 May 2024 17:10:50 +0800 Subject: [PATCH] Updated on 2026-08-14 --- .../tokenreceive/TokenReceiveBottomSheet.kt | 255 +++++++++++------- 1 file changed, 159 insertions(+), 96 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/tokenreceive/TokenReceiveBottomSheet.kt b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/tokenreceive/TokenReceiveBottomSheet.kt index 1057a43847..46317b571e 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/tokenreceive/TokenReceiveBottomSheet.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/tokenreceive/TokenReceiveBottomSheet.kt @@ -1,6 +1,5 @@ package com.tangem.core.ui.components.bottomsheets.tokenreceive -import android.widget.Toast import androidx.compose.animation.animateColorAsState import androidx.compose.foundation.* import androidx.compose.foundation.layout.* @@ -9,10 +8,12 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalClipboardManager @@ -26,9 +27,11 @@ import com.tangem.core.ui.components.SecondaryButtonIconStart import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.rememberQrPainters +import com.tangem.core.ui.components.snackbar.CopiedTextSnackbarHost import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.shareText import com.tangem.core.ui.res.TangemTheme +import kotlinx.coroutines.launch @Composable fun TokenReceiveBottomSheet(config: TangemBottomSheetConfig) { @@ -40,117 +43,88 @@ fun TokenReceiveBottomSheet(config: TangemBottomSheetConfig) { @Composable private fun TokenReceiveBottomSheetContent(content: TokenReceiveBottomSheetConfig) { var selectedAddress by remember { mutableStateOf(content.addresses.first()) } - Column( - modifier = Modifier - .verticalScroll(state = rememberScrollState()) - .padding( - start = TangemTheme.dimens.spacing24, - top = TangemTheme.dimens.spacing24, - end = TangemTheme.dimens.spacing24, - bottom = TangemTheme.dimens.spacing16, - ), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing24), - ) { - QrCodeContent( - content = content, - onAddressChange = { selectedAddress = it }, - ) - Text( - text = stringResource(R.string.receive_bottom_sheet_warning_message_full, content.name), - color = TangemTheme.colors.text.secondary, - textAlign = TextAlign.Center, - style = TangemTheme.typography.caption2, - ) - Row( - horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16), + + val snackbarHostState = remember(::SnackbarHostState) + + ContainerWithSnackbarHost(snackbarHostState = snackbarHostState) { + Column( + modifier = Modifier + .verticalScroll(state = rememberScrollState()) + .padding( + start = TangemTheme.dimens.spacing24, + top = TangemTheme.dimens.spacing24, + end = TangemTheme.dimens.spacing24, + bottom = TangemTheme.dimens.spacing16, + ), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing24), ) { - val clipboardManager = LocalClipboardManager.current - val hapticFeedback = LocalHapticFeedback.current - val context = LocalContext.current - SecondaryButtonIconStart( - modifier = Modifier.weight(1f), - text = stringResource(id = R.string.common_copy), - iconResId = R.drawable.ic_copy_24, - onClick = { - content.onCopyClick.invoke() - hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) - clipboardManager.setText(AnnotatedString(selectedAddress.value)) - Toast.makeText(context, R.string.wallet_notification_address_copied, Toast.LENGTH_SHORT).show() - }, - ) - SecondaryButtonIconStart( - modifier = Modifier.weight(1f), - text = stringResource(id = R.string.common_share), - iconResId = R.drawable.ic_share_24, - onClick = { - content.onShareClick.invoke() - hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) - context.shareText(selectedAddress.value) - }, - ) + QrCodeContent(content = content, onAddressChange = { selectedAddress = it }) + + DisclaimerText(text = content.name) + + Row(horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16)) { + CopyButton( + address = selectedAddress.value, + snackbarHostState = snackbarHostState, + onClick = content.onCopyClick, + modifier = Modifier.weight(1f), + ) + + ShareButton( + address = selectedAddress.value, + onClick = content.onShareClick, + modifier = Modifier.weight(1f), + ) + } } } } -@Suppress("LongMethod") +@Composable +private fun ContainerWithSnackbarHost(snackbarHostState: SnackbarHostState, content: @Composable () -> Unit) { + Box { + content() + + CopiedTextSnackbarHost( + hostState = snackbarHostState, + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(bottom = TangemTheme.dimens.spacing80), + ) + } +} + @OptIn(ExperimentalFoundationApi::class) @Composable private fun QrCodeContent(content: TokenReceiveBottomSheetConfig, onAddressChange: (AddressModel) -> Unit) { val qrCodes = rememberQrPainters(content.addresses.map(AddressModel::value)) + val pagerState = rememberPagerState( initialPage = 0, initialPageOffsetFraction = 0f, - ) { - content.addresses.count() - } + pageCount = content.addresses::count, + ) LaunchedEffect(key1 = pagerState.currentPage) { onAddressChange.invoke(content.addresses[pagerState.currentPage]) } - HorizontalPager( - state = pagerState, - ) { currentPage -> - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing24), - ) { - Text( - text = stringResource( - R.string.receive_bottom_sheet_warning_message, - getName(content = content, index = pagerState.currentPage), - content.symbol, - content.network, - ), - color = TangemTheme.colors.text.primary1, - textAlign = TextAlign.Center, - style = TangemTheme.typography.h3, - ) - Image( - painter = qrCodes[currentPage], - contentDescription = null, - contentScale = ContentScale.Fit, - modifier = Modifier - .size(TangemTheme.dimens.size248), - ) - Text( - text = content.addresses[currentPage].value, - color = TangemTheme.colors.text.primary1, - textAlign = TextAlign.Center, - style = TangemTheme.typography.subtitle1, - ) - } + HorizontalPager(state = pagerState) { currentPage -> + QrCodePage( + content = content, + qrCodePainter = qrCodes[currentPage], + currentIndex = currentPage, + ) } if (pagerState.pageCount > 1) { val indicatorState = rememberLazyListState() val selectedColor = TangemTheme.colors.icon.primary1 val unselectedColor = TangemTheme.colors.icon.informative + LazyRow( - modifier = Modifier - .height(TangemTheme.dimens.size20), + modifier = Modifier.height(TangemTheme.dimens.size20), state = indicatorState, horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically, @@ -158,17 +132,14 @@ private fun QrCodeContent(content: TokenReceiveBottomSheetConfig, onAddressChang repeat(pagerState.pageCount) { iteration -> item(key = iteration) { val color by animateColorAsState( - if (pagerState.currentPage == iteration) selectedColor else unselectedColor, + targetValue = if (pagerState.currentPage == iteration) selectedColor else unselectedColor, + label = "", ) + Box( modifier = Modifier - .padding( - start = TangemTheme.dimens.spacing4, - top = TangemTheme.dimens.spacing6, - end = TangemTheme.dimens.spacing4, - bottom = TangemTheme.dimens.spacing6, - ) - .background(color, CircleShape) + .padding(horizontal = TangemTheme.dimens.spacing4, vertical = TangemTheme.dimens.spacing6) + .background(color = color, shape = CircleShape) .size(TangemTheme.dimens.size7), ) } @@ -177,6 +148,41 @@ private fun QrCodeContent(content: TokenReceiveBottomSheetConfig, onAddressChang } } +@Composable +private fun QrCodePage(content: TokenReceiveBottomSheetConfig, qrCodePainter: Painter, currentIndex: Int) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing24), + ) { + Text( + text = stringResource( + R.string.receive_bottom_sheet_warning_message, + getName(content = content, index = currentIndex), + content.symbol, + content.network, + ), + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.Center, + style = TangemTheme.typography.h3, + ) + + Image( + painter = qrCodePainter, + contentDescription = null, + contentScale = ContentScale.Fit, + modifier = Modifier.size(TangemTheme.dimens.size248), + ) + + Text( + text = content.addresses[currentIndex].value, + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.Center, + style = TangemTheme.typography.subtitle1, + ) + } +} + @Composable private fun getName(content: TokenReceiveBottomSheetConfig, index: Int): String { return if (content.addresses.size < 2) { @@ -184,4 +190,61 @@ private fun getName(content: TokenReceiveBottomSheetConfig, index: Int): String } else { "${content.addresses[index].displayName.resolveReference()} ${content.name}" } +} + +@Composable +private fun DisclaimerText(text: String) { + Text( + text = stringResource(R.string.receive_bottom_sheet_warning_message_full, text), + color = TangemTheme.colors.text.secondary, + textAlign = TextAlign.Center, + style = TangemTheme.typography.caption2, + ) +} + +@Composable +private fun CopyButton( + address: String, + snackbarHostState: SnackbarHostState, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + val hapticFeedback = LocalHapticFeedback.current + val clipboardManager = LocalClipboardManager.current + val coroutineScope = rememberCoroutineScope() + val resources = LocalContext.current.resources + + SecondaryButtonIconStart( + modifier = modifier, + text = stringResource(id = R.string.common_copy), + iconResId = R.drawable.ic_copy_24, + onClick = { + onClick() + hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) + clipboardManager.setText(AnnotatedString(address)) + + coroutineScope.launch { + snackbarHostState.showSnackbar( + message = resources.getString(R.string.wallet_notification_address_copied), + ) + } + }, + ) +} + +@Composable +private fun ShareButton(address: String, onClick: () -> Unit, modifier: Modifier = Modifier) { + val hapticFeedback = LocalHapticFeedback.current + val context = LocalContext.current + + SecondaryButtonIconStart( + modifier = modifier, + text = stringResource(id = R.string.common_share), + iconResId = R.drawable.ic_share_24, + onClick = { + onClick() + hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) + context.shareText(address) + }, + ) } \ No newline at end of file