Updated on 2026-08-14

This commit is contained in:
Tangem 2024-05-17 17:10:50 +08:00
parent f04fdd1406
commit 70c989be4e

View file

@ -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)
},
)
}