diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/address/HSAddressCell.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/address/HSAddressCell.kt index 1adaf6b432..a2fccea230 100644 --- a/app/src/main/java/io/horizontalsystems/bankwallet/modules/address/HSAddressCell.kt +++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/address/HSAddressCell.kt @@ -1,39 +1,70 @@ package io.horizontalsystems.bankwallet.modules.address +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import io.horizontalsystems.bankwallet.R import io.horizontalsystems.bankwallet.ui.compose.ComposeAppTheme import io.horizontalsystems.bankwallet.ui.compose.components.HSpacer import io.horizontalsystems.bankwallet.ui.compose.components.cell.CellUniversal -import io.horizontalsystems.bankwallet.ui.compose.components.cell.SectionUniversalLawrence import io.horizontalsystems.bankwallet.ui.compose.components.subhead1_leah import io.horizontalsystems.bankwallet.ui.compose.components.subhead2_grey @Composable -fun HSAddressCell(title: String, value: String, onClick: () -> Unit) { - SectionUniversalLawrence { - CellUniversal( - borderTop = false, - onClick = onClick - ) { - subhead2_grey(text = title) +fun HSAddressCell( + title: String, + value: String, + riskyAddress: Boolean, + onClick: () -> Unit +) { + val borderColor = if (riskyAddress) { + ComposeAppTheme.colors.red50 + } else { + ComposeAppTheme.colors.transparent + } + + Column( + modifier = Modifier + .padding(horizontal = 16.dp) + .clip(RoundedCornerShape(12.dp)) + .border(1.dp, borderColor, RoundedCornerShape(12.dp)) + .background(ComposeAppTheme.colors.lawrence), + content = { + CellUniversal( + borderTop = false, + onClick = onClick + ) { + subhead2_grey(text = title) - HSpacer(16.dp) - subhead1_leah( - modifier = Modifier.weight(1f), - text = value - ) + HSpacer(16.dp) + subhead1_leah( + modifier = Modifier.weight(1f), + text = value + ) + if (riskyAddress) { + HSpacer(16.dp) + Icon( + painter = painterResource(id = R.drawable.ic_attention_20), + contentDescription = null, + tint = ComposeAppTheme.colors.lucian + ) + } - HSpacer(16.dp) - Icon( - painter = painterResource(id = R.drawable.ic_down_arrow_20), - contentDescription = null, - tint = ComposeAppTheme.colors.grey - ) + HSpacer(16.dp) + Icon( + painter = painterResource(id = R.drawable.ic_down_arrow_20), + contentDescription = null, + tint = ComposeAppTheme.colors.grey + ) + } } - } + ) } \ No newline at end of file diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/AddressRiskyBottomSheetAlert.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/AddressRiskyBottomSheetAlert.kt new file mode 100644 index 0000000000..5b4074b762 --- /dev/null +++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/AddressRiskyBottomSheetAlert.kt @@ -0,0 +1,105 @@ +package io.horizontalsystems.bankwallet.modules.send + +import android.os.Bundle +import android.os.Parcelable +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import io.horizontalsystems.bankwallet.R +import io.horizontalsystems.bankwallet.core.getInput +import io.horizontalsystems.bankwallet.core.setNavigationResultX +import io.horizontalsystems.bankwallet.ui.compose.ComposeAppTheme +import io.horizontalsystems.bankwallet.ui.compose.components.ButtonPrimaryRed +import io.horizontalsystems.bankwallet.ui.compose.components.ButtonPrimaryTransparent +import io.horizontalsystems.bankwallet.ui.compose.components.TextImportantError +import io.horizontalsystems.bankwallet.ui.compose.components.VSpacer +import io.horizontalsystems.bankwallet.ui.extensions.BaseComposableBottomSheetFragment +import io.horizontalsystems.bankwallet.ui.extensions.BottomSheetHeader +import io.horizontalsystems.core.findNavController +import kotlinx.parcelize.Parcelize + +class AddressRiskyBottomSheetAlert : BaseComposableBottomSheetFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + return ComposeView(requireContext()).apply { + setViewCompositionStrategy( + ViewCompositionStrategy.DisposeOnLifecycleDestroyed(viewLifecycleOwner) + ) + setContent { + val navController = findNavController() + navController.getInput()?.let { input -> + RiskyAddressAlertView( + alertText = input.alertText, + onCloseClick = { + navController.popBackStack() + }, + onContinueClick = { + navController.setNavigationResultX(Result(true)) + } + ) + } + } + } + } + + @Parcelize + data class Input(val alertText: String) : Parcelable + + @Parcelize + data class Result(val canContinue: Boolean) : Parcelable +} + +@Composable +private fun RiskyAddressAlertView( + alertText: String, + onCloseClick: () -> Unit, + onContinueClick: () -> Unit, +) { + ComposeAppTheme { + BottomSheetHeader( + iconPainter = painterResource(R.drawable.ic_attention_24), + iconTint = ColorFilter.tint(ComposeAppTheme.colors.lucian), + title = stringResource(R.string.Send_RiskyAddress), + onCloseClick = onCloseClick + ) { + VSpacer(12.dp) + TextImportantError( + modifier = Modifier.padding(horizontal = 16.dp), + text = alertText + ) + VSpacer(32.dp) + ButtonPrimaryRed( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp), + title = stringResource(R.string.Button_ContinueAnyway), + onClick = { + onContinueClick() + } + ) + VSpacer(12.dp) + ButtonPrimaryTransparent( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp), + title = stringResource(R.string.Button_Cancel), + onClick = onCloseClick + ) + VSpacer(32.dp) + } + } +} diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/SendFragment.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/SendFragment.kt index cb2178fcf6..a70f120a89 100644 --- a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/SendFragment.kt +++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/SendFragment.kt @@ -54,6 +54,7 @@ class SendFragment : BaseFragment() { val title = input.title val sendEntryPointDestId = input.sendEntryPointDestId val address = input.address + val riskyAddress = input.riskyAddress val hideAddress = input.hideAddress val amount = input.amount @@ -73,12 +74,13 @@ class SendFragment : BaseFragment() { } setContent { SendBitcoinNavHost( - title, - findNavController(), - sendBitcoinViewModel, - amountInputModeViewModel, - sendEntryPointDestId, - amount + title = title, + fragmentNavController = findNavController(), + viewModel = sendBitcoinViewModel, + amountInputModeViewModel = amountInputModeViewModel, + sendEntryPointDestId = sendEntryPointDestId, + amount = amount, + riskyAddress = riskyAddress ) } } @@ -90,12 +92,13 @@ class SendFragment : BaseFragment() { } setContent { SendZCashScreen( - title, - findNavController(), - sendZCashViewModel, - amountInputModeViewModel, - sendEntryPointDestId, - amount + title = title, + navController = findNavController(), + viewModel = sendZCashViewModel, + amountInputModeViewModel = amountInputModeViewModel, + sendEntryPointDestId = sendEntryPointDestId, + amount = amount, + riskyAddress = riskyAddress ) } } @@ -111,14 +114,15 @@ class SendFragment : BaseFragment() { BlockchainType.ArbitrumOne -> { setContent { SendEvmScreen( - title, - findNavController(), - amountInputModeViewModel, - address, - wallet, - amount, - hideAddress, - sendEntryPointDestId + title = title, + navController = findNavController(), + amountInputModeViewModel = amountInputModeViewModel, + address = address, + wallet = wallet, + amount = amount, + hideAddress = hideAddress, + riskyAddress = riskyAddress, + sendEntryPointDestId = sendEntryPointDestId ) } } @@ -128,12 +132,13 @@ class SendFragment : BaseFragment() { val sendSolanaViewModel by navGraphViewModels(R.id.sendXFragment) { factory } setContent { SendSolanaScreen( - title, - findNavController(), - sendSolanaViewModel, - amountInputModeViewModel, - sendEntryPointDestId, - amount + title = title, + navController = findNavController(), + viewModel = sendSolanaViewModel, + amountInputModeViewModel = amountInputModeViewModel, + sendEntryPointDestId = sendEntryPointDestId, + amount = amount, + riskyAddress = riskyAddress ) } } @@ -148,7 +153,8 @@ class SendFragment : BaseFragment() { sendTonViewModel, amountInputModeViewModel, sendEntryPointDestId, - amount + amount, + riskyAddress = riskyAddress ) } } @@ -158,12 +164,13 @@ class SendFragment : BaseFragment() { val sendTronViewModel by navGraphViewModels(R.id.sendXFragment) { factory } setContent { SendTronScreen( - title, - findNavController(), - sendTronViewModel, - amountInputModeViewModel, - sendEntryPointDestId, - amount + title = title, + navController = findNavController(), + viewModel = sendTronViewModel, + amountInputModeViewModel = amountInputModeViewModel, + sendEntryPointDestId = sendEntryPointDestId, + amount = amount, + riskyAddress = riskyAddress ) } } @@ -182,6 +189,7 @@ class SendFragment : BaseFragment() { val title: String, val sendEntryPointDestId: Int, val address: Address, + val riskyAddress: Boolean = false, val amount: BigDecimal? = null, val hideAddress: Boolean = false ) : Parcelable diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/address/EnterAddressFragment.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/address/EnterAddressFragment.kt index cdceda1910..0e9ebd4c32 100644 --- a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/address/EnterAddressFragment.kt +++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/address/EnterAddressFragment.kt @@ -132,7 +132,11 @@ fun EnterAddressScreen(navController: NavController, input: EnterAddressFragment } if (uiState.value.isBlank()) { - AddressSuggestions(uiState.recentAddress, uiState.recentContact, uiState.contacts) { + AddressSuggestions( + uiState.recentAddress, + uiState.recentContact, + uiState.contacts + ) { viewModel.onEnterAddress(it) } } else { @@ -163,6 +167,7 @@ fun EnterAddressScreen(navController: NavController, input: EnterAddressFragment sendEntryPointDestId = input.sendEntryPointDestId ?: R.id.enterAddressFragment, title = input.title, address = it, + riskyAddress = uiState.checkResults.any { result -> result.value.checkResult == AddressCheckResult.Detected }, amount = uiState.amount ) ) @@ -226,7 +231,8 @@ private fun Errors( modifier = Modifier.padding(horizontal = 16.dp), icon = R.drawable.ic_attention_20, title = stringResource(R.string.SwapSettings_Error_InvalidAddress), - text = addressValidationError.message ?: stringResource(R.string.SwapSettings_Error_InvalidAddress) + text = addressValidationError.message + ?: stringResource(R.string.SwapSettings_Error_InvalidAddress) ) VSpacer(32.dp) } else { @@ -262,7 +268,10 @@ private fun CheckCell( { navController.slideFromBottom( R.id.feeSettingsInfoDialog, - FeeSettingsInfoDialog.Input(Translator.getString(checkType.clearInfoTitle), Translator.getString(checkType.clearInfoDescription)) + FeeSettingsInfoDialog.Input( + Translator.getString(checkType.clearInfoTitle), + Translator.getString(checkType.clearInfoDescription) + ) ) } } @@ -378,7 +387,12 @@ fun CheckLocked() { } @Composable -fun AddressSuggestions(recent: String?, recentContact: SContact?, contacts: List, onClick: (String) -> Unit) { +fun AddressSuggestions( + recent: String?, + recentContact: SContact?, + contacts: List, + onClick: (String) -> Unit +) { if (recentContact != null) { Column( modifier = Modifier diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/bitcoin/SendBitcoinScreen.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/bitcoin/SendBitcoinScreen.kt index dc63682ef2..70222649be 100644 --- a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/bitcoin/SendBitcoinScreen.kt +++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/bitcoin/SendBitcoinScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp @@ -24,6 +25,8 @@ import androidx.navigation.compose.rememberNavController import io.horizontalsystems.bankwallet.R import io.horizontalsystems.bankwallet.core.composablePage import io.horizontalsystems.bankwallet.core.composablePopup +import io.horizontalsystems.bankwallet.core.providers.Translator +import io.horizontalsystems.bankwallet.core.slideFromBottomForResult import io.horizontalsystems.bankwallet.core.slideFromRight import io.horizontalsystems.bankwallet.modules.address.AddressParserModule import io.horizontalsystems.bankwallet.modules.address.AddressParserViewModel @@ -33,6 +36,7 @@ import io.horizontalsystems.bankwallet.modules.amount.HSAmountInput import io.horizontalsystems.bankwallet.modules.availablebalance.AvailableBalance import io.horizontalsystems.bankwallet.modules.fee.HSFeeRaw import io.horizontalsystems.bankwallet.modules.memo.HSMemoInput +import io.horizontalsystems.bankwallet.modules.send.AddressRiskyBottomSheetAlert import io.horizontalsystems.bankwallet.modules.send.SendConfirmationFragment import io.horizontalsystems.bankwallet.modules.send.bitcoin.advanced.BtcTransactionInputSortInfoScreen import io.horizontalsystems.bankwallet.modules.send.bitcoin.advanced.FeeRateCaution @@ -66,6 +70,7 @@ fun SendBitcoinNavHost( amountInputModeViewModel: AmountInputModeViewModel, sendEntryPointDestId: Int, amount: BigDecimal?, + riskyAddress: Boolean ) { val navController = rememberNavController() NavHost( @@ -80,7 +85,8 @@ fun SendBitcoinNavHost( viewModel, amountInputModeViewModel, sendEntryPointDestId, - amount + amount, + riskyAddress ) } composablePage(SendBtcAdvancedSettingsPage) { @@ -117,6 +123,7 @@ fun SendBitcoinScreen( amountInputModeViewModel: AmountInputModeViewModel, sendEntryPointDestId: Int, amount: BigDecimal?, + riskyAddress: Boolean, ) { val wallet = viewModel.wallet val uiState = viewModel.uiState @@ -128,6 +135,7 @@ fun SendBitcoinScreen( val proceedEnabled = uiState.canBeSend val amountInputType = amountInputModeViewModel.inputType val feeRateCaution = uiState.feeRateCaution + val keyboardController = LocalSoftwareKeyboardController.current val rate = viewModel.coinRate @@ -163,7 +171,8 @@ fun SendBitcoinScreen( if (uiState.showAddressInput) { HSAddressCell( title = stringResource(R.string.Send_Confirmation_To), - value = uiState.address.hex + value = uiState.address.hex, + riskyAddress = riskyAddress ) { fragmentNavController.popBackStack() } @@ -241,12 +250,21 @@ fun SendBitcoinScreen( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 16.dp), - title = stringResource(R.string.Send_DialogProceed), + title = stringResource(R.string.Button_Check), onClick = { - fragmentNavController.slideFromRight( - R.id.sendConfirmation, - SendConfirmationFragment.Input(SendConfirmationFragment.Type.Bitcoin, sendEntryPointDestId) - ) + if (riskyAddress) { + keyboardController?.hide() + fragmentNavController.slideFromBottomForResult( + R.id.addressRiskyBottomSheetAlert, + AddressRiskyBottomSheetAlert.Input( + alertText = Translator.getString(R.string.Send_RiskyAddress_AlertText) + ) + ) { + openConfirm(fragmentNavController, sendEntryPointDestId) + } + } else { + openConfirm(fragmentNavController, sendEntryPointDestId) + } }, enabled = proceedEnabled ) @@ -255,6 +273,19 @@ fun SendBitcoinScreen( } } +private fun openConfirm( + fragmentNavController: NavController, + sendEntryPointDestId: Int +) { + fragmentNavController.slideFromRight( + R.id.sendConfirmation, + SendConfirmationFragment.Input( + SendConfirmationFragment.Type.Bitcoin, + sendEntryPointDestId + ) + ) +} + @Composable fun UtxoCell( utxoData: SendBitcoinModule.UtxoData, diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/evm/SendEvmScreen.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/evm/SendEvmScreen.kt index 339d25a949..abeb6c9eca 100644 --- a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/evm/SendEvmScreen.kt +++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/evm/SendEvmScreen.kt @@ -7,12 +7,15 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import io.horizontalsystems.bankwallet.R +import io.horizontalsystems.bankwallet.core.providers.Translator +import io.horizontalsystems.bankwallet.core.slideFromBottomForResult import io.horizontalsystems.bankwallet.core.slideFromRight import io.horizontalsystems.bankwallet.entities.Address import io.horizontalsystems.bankwallet.entities.Wallet @@ -22,12 +25,14 @@ import io.horizontalsystems.bankwallet.modules.address.HSAddressCell import io.horizontalsystems.bankwallet.modules.amount.AmountInputModeViewModel import io.horizontalsystems.bankwallet.modules.amount.HSAmountInput import io.horizontalsystems.bankwallet.modules.availablebalance.AvailableBalance +import io.horizontalsystems.bankwallet.modules.send.AddressRiskyBottomSheetAlert import io.horizontalsystems.bankwallet.modules.send.SendScreen import io.horizontalsystems.bankwallet.modules.send.evm.confirmation.SendEvmConfirmationFragment import io.horizontalsystems.bankwallet.ui.compose.ComposeAppTheme import io.horizontalsystems.bankwallet.ui.compose.components.ButtonPrimaryYellow import io.horizontalsystems.bankwallet.ui.compose.components.VSpacer import io.horizontalsystems.core.helpers.HudHelper +import io.horizontalsystems.marketkit.models.BlockchainType import java.math.BigDecimal @Composable @@ -39,6 +44,7 @@ fun SendEvmScreen( wallet: Wallet, amount: BigDecimal?, hideAddress: Boolean, + riskyAddress: Boolean, sendEntryPointDestId: Int, ) { val viewModel = viewModel( @@ -56,6 +62,7 @@ fun SendEvmScreen( ) val amountUnique = paymentAddressViewModel.amountUnique val view = LocalView.current + val keyboardController = LocalSoftwareKeyboardController.current ComposeAppTheme { val focusRequester = remember { FocusRequester() } @@ -71,7 +78,8 @@ fun SendEvmScreen( if (uiState.showAddressInput) { HSAddressCell( title = stringResource(R.string.Send_Confirmation_To), - value = uiState.address.hex + value = uiState.address.hex, + riskyAddress = riskyAddress, ) { navController.popBackStack() } @@ -111,22 +119,33 @@ fun SendEvmScreen( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 16.dp), - title = stringResource(R.string.Send_DialogProceed), + title = stringResource(R.string.Button_Check), onClick = { - if (viewModel.hasConnection()) { - viewModel.getSendData()?.let { - navController.slideFromRight( - R.id.sendEvmConfirmationFragment, - SendEvmConfirmationFragment. - Input( - sendData = it, - blockchainType = viewModel.wallet.token.blockchainType, - sendEntryPointDestId = sendEntryPointDestId - ) + val sendData = viewModel.getSendData() ?: return@ButtonPrimaryYellow + if (!viewModel.hasConnection()) { + HudHelper.showErrorMessage(view, R.string.Hud_Text_NoInternet) + } else if (riskyAddress) { + keyboardController?.hide() + navController.slideFromBottomForResult( + R.id.addressRiskyBottomSheetAlert, + AddressRiskyBottomSheetAlert.Input( + alertText = Translator.getString(R.string.Send_RiskyAddress_AlertText) + ) + ) { + openSendConfirm( + sendData, + viewModel.wallet.token.blockchainType, + navController, + sendEntryPointDestId ) } } else { - HudHelper.showErrorMessage(view, R.string.Hud_Text_NoInternet) + openSendConfirm( + sendData, + viewModel.wallet.token.blockchainType, + navController, + sendEntryPointDestId + ) } }, enabled = proceedEnabled @@ -134,3 +153,19 @@ fun SendEvmScreen( } } } + +private fun openSendConfirm( + sendEvmData: SendEvmData, + blockchainType: BlockchainType, + navController: NavController, + sendEntryPointDestId: Int +) { + navController.slideFromRight( + R.id.sendEvmConfirmationFragment, + SendEvmConfirmationFragment.Input( + sendData = sendEvmData, + blockchainType = blockchainType, + sendEntryPointDestId = sendEntryPointDestId + ) + ) +} diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/solana/SendSolanaScreen.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/solana/SendSolanaScreen.kt index 98c09a51c2..fd4a5c8873 100644 --- a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/solana/SendSolanaScreen.kt +++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/solana/SendSolanaScreen.kt @@ -7,12 +7,15 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import io.horizontalsystems.bankwallet.R +import io.horizontalsystems.bankwallet.core.providers.Translator +import io.horizontalsystems.bankwallet.core.slideFromBottomForResult import io.horizontalsystems.bankwallet.core.slideFromRight import io.horizontalsystems.bankwallet.modules.address.AddressParserModule import io.horizontalsystems.bankwallet.modules.address.AddressParserViewModel @@ -20,6 +23,7 @@ import io.horizontalsystems.bankwallet.modules.address.HSAddressCell import io.horizontalsystems.bankwallet.modules.amount.AmountInputModeViewModel import io.horizontalsystems.bankwallet.modules.amount.HSAmountInput import io.horizontalsystems.bankwallet.modules.availablebalance.AvailableBalance +import io.horizontalsystems.bankwallet.modules.send.AddressRiskyBottomSheetAlert import io.horizontalsystems.bankwallet.modules.send.SendConfirmationFragment import io.horizontalsystems.bankwallet.modules.send.SendScreen import io.horizontalsystems.bankwallet.ui.compose.ComposeAppTheme @@ -36,6 +40,7 @@ fun SendSolanaScreen( amountInputModeViewModel: AmountInputModeViewModel, sendEntryPointDestId: Int, amount: BigDecimal?, + riskyAddress: Boolean ) { val view = LocalView.current val wallet = viewModel.wallet @@ -45,6 +50,7 @@ fun SendSolanaScreen( val amountCaution = uiState.amountCaution val proceedEnabled = uiState.canBeSend val amountInputType = amountInputModeViewModel.inputType + val keyboardController = LocalSoftwareKeyboardController.current val paymentAddressViewModel = viewModel( factory = AddressParserModule.Factory(wallet.token, amount) @@ -65,7 +71,8 @@ fun SendSolanaScreen( if (uiState.showAddressInput) { HSAddressCell( title = stringResource(R.string.Send_Confirmation_To), - value = uiState.address.hex + value = uiState.address.hex, + riskyAddress = riskyAddress ) { navController.popBackStack() } @@ -73,22 +80,22 @@ fun SendSolanaScreen( } HSAmountInput( - modifier = Modifier.padding(horizontal = 16.dp), - focusRequester = focusRequester, - availableBalance = availableBalance, - caution = amountCaution, - coinCode = wallet.coin.code, - coinDecimal = viewModel.coinMaxAllowedDecimals, - fiatDecimal = viewModel.fiatMaxAllowedDecimals, - onClickHint = { - amountInputModeViewModel.onToggleInputType() - }, - onValueChange = { - viewModel.onEnterAmount(it) - }, - inputType = amountInputType, - rate = viewModel.coinRate, - amountUnique = amountUnique + modifier = Modifier.padding(horizontal = 16.dp), + focusRequester = focusRequester, + availableBalance = availableBalance, + caution = amountCaution, + coinCode = wallet.coin.code, + coinDecimal = viewModel.coinMaxAllowedDecimals, + fiatDecimal = viewModel.fiatMaxAllowedDecimals, + onClickHint = { + amountInputModeViewModel.onToggleInputType() + }, + onValueChange = { + viewModel.onEnterAmount(it) + }, + inputType = amountInputType, + rate = viewModel.coinRate, + amountUnique = amountUnique ) VSpacer(8.dp) @@ -105,18 +112,22 @@ fun SendSolanaScreen( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 16.dp), - title = stringResource(R.string.Send_DialogProceed), + title = stringResource(R.string.Button_Check), onClick = { - if (viewModel.hasConnection()) { - navController.slideFromRight( - R.id.sendConfirmation, - SendConfirmationFragment.Input( - SendConfirmationFragment.Type.Solana, - sendEntryPointDestId + if (!viewModel.hasConnection()) { + HudHelper.showErrorMessage(view, R.string.Hud_Text_NoInternet) + } else if (riskyAddress) { + keyboardController?.hide() + navController.slideFromBottomForResult( + R.id.addressRiskyBottomSheetAlert, + AddressRiskyBottomSheetAlert.Input( + alertText = Translator.getString(R.string.Send_RiskyAddress_AlertText) ) - ) + ) { + openConfirm(navController, sendEntryPointDestId) + } } else { - HudHelper.showErrorMessage(view, R.string.Hud_Text_NoInternet) + openConfirm(navController, sendEntryPointDestId) } }, enabled = proceedEnabled @@ -125,3 +136,16 @@ fun SendSolanaScreen( } } + +private fun openConfirm( + navController: NavController, + sendEntryPointDestId: Int +) { + navController.slideFromRight( + R.id.sendConfirmation, + SendConfirmationFragment.Input( + SendConfirmationFragment.Type.Solana, + sendEntryPointDestId + ) + ) +} diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/ton/SendTonScreen.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/ton/SendTonScreen.kt index 1547fbb051..00ca97e06d 100644 --- a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/ton/SendTonScreen.kt +++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/ton/SendTonScreen.kt @@ -7,11 +7,14 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import io.horizontalsystems.bankwallet.R +import io.horizontalsystems.bankwallet.core.providers.Translator +import io.horizontalsystems.bankwallet.core.slideFromBottomForResult import io.horizontalsystems.bankwallet.core.slideFromRight import io.horizontalsystems.bankwallet.entities.ViewState import io.horizontalsystems.bankwallet.modules.address.AddressParserModule @@ -22,6 +25,7 @@ import io.horizontalsystems.bankwallet.modules.amount.HSAmountInput import io.horizontalsystems.bankwallet.modules.availablebalance.AvailableBalance import io.horizontalsystems.bankwallet.modules.fee.HSFee import io.horizontalsystems.bankwallet.modules.memo.HSMemoInput +import io.horizontalsystems.bankwallet.modules.send.AddressRiskyBottomSheetAlert import io.horizontalsystems.bankwallet.modules.send.SendConfirmationFragment import io.horizontalsystems.bankwallet.modules.send.SendScreen import io.horizontalsystems.bankwallet.ui.compose.ComposeAppTheme @@ -37,6 +41,7 @@ fun SendTonScreen( amountInputModeViewModel: AmountInputModeViewModel, sendEntryPointDestId: Int, amount: BigDecimal?, + riskyAddress: Boolean ) { val wallet = viewModel.wallet val uiState = viewModel.uiState @@ -47,6 +52,7 @@ fun SendTonScreen( val fee = uiState.fee val feeInProgress = uiState.feeInProgress val amountInputType = amountInputModeViewModel.inputType + val keyboardController = LocalSoftwareKeyboardController.current val paymentAddressViewModel = viewModel( factory = AddressParserModule.Factory(wallet.token, amount) @@ -68,7 +74,8 @@ fun SendTonScreen( if (uiState.showAddressInput) { HSAddressCell( title = stringResource(R.string.Send_Confirmation_To), - value = uiState.address.hex + value = uiState.address.hex, + riskyAddress = riskyAddress ) { navController.popBackStack() } @@ -124,19 +131,37 @@ fun SendTonScreen( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 16.dp), - title = stringResource(R.string.Send_DialogProceed), + title = stringResource(R.string.Button_Check), onClick = { - navController.slideFromRight( - R.id.sendConfirmation, - SendConfirmationFragment.Input( - SendConfirmationFragment.Type.Ton, - sendEntryPointDestId - ) - ) + if (riskyAddress) { + keyboardController?.hide() + navController.slideFromBottomForResult( + R.id.addressRiskyBottomSheetAlert, + AddressRiskyBottomSheetAlert.Input( + alertText = Translator.getString(R.string.Send_RiskyAddress_AlertText) + ) + ) { + openConfirm(navController, sendEntryPointDestId) + } + } else { + openConfirm(navController, sendEntryPointDestId) + } }, enabled = proceedEnabled ) } } +} +private fun openConfirm( + navController: NavController, + sendEntryPointDestId: Int +) { + navController.slideFromRight( + R.id.sendConfirmation, + SendConfirmationFragment.Input( + SendConfirmationFragment.Type.Ton, + sendEntryPointDestId + ) + ) } diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/tron/SendTronScreen.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/tron/SendTronScreen.kt index eb3eda1a08..4d64b7cfc9 100644 --- a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/tron/SendTronScreen.kt +++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/tron/SendTronScreen.kt @@ -7,12 +7,15 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import io.horizontalsystems.bankwallet.R +import io.horizontalsystems.bankwallet.core.providers.Translator +import io.horizontalsystems.bankwallet.core.slideFromBottomForResult import io.horizontalsystems.bankwallet.core.slideFromRight import io.horizontalsystems.bankwallet.modules.address.AddressParserModule import io.horizontalsystems.bankwallet.modules.address.AddressParserViewModel @@ -20,6 +23,7 @@ import io.horizontalsystems.bankwallet.modules.address.HSAddressCell import io.horizontalsystems.bankwallet.modules.amount.AmountInputModeViewModel import io.horizontalsystems.bankwallet.modules.amount.HSAmountInput import io.horizontalsystems.bankwallet.modules.availablebalance.AvailableBalance +import io.horizontalsystems.bankwallet.modules.send.AddressRiskyBottomSheetAlert import io.horizontalsystems.bankwallet.modules.send.SendConfirmationFragment import io.horizontalsystems.bankwallet.modules.send.SendScreen import io.horizontalsystems.bankwallet.ui.compose.ComposeAppTheme @@ -36,6 +40,7 @@ fun SendTronScreen( amountInputModeViewModel: AmountInputModeViewModel, sendEntryPointDestId: Int, amount: BigDecimal?, + riskyAddress: Boolean ) { val view = LocalView.current val wallet = viewModel.wallet @@ -45,6 +50,7 @@ fun SendTronScreen( val amountCaution = uiState.amountCaution val proceedEnabled = uiState.proceedEnabled val amountInputType = amountInputModeViewModel.inputType + val keyboardController = LocalSoftwareKeyboardController.current val paymentAddressViewModel = viewModel( factory = AddressParserModule.Factory(wallet.token, amount) @@ -66,7 +72,8 @@ fun SendTronScreen( if (uiState.showAddressInput) { HSAddressCell( title = stringResource(R.string.Send_Confirmation_To), - value = uiState.address.hex + value = uiState.address.hex, + riskyAddress = riskyAddress ) { navController.popBackStack() } @@ -106,20 +113,22 @@ fun SendTronScreen( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 16.dp), - title = stringResource(R.string.Send_DialogProceed), + title = stringResource(R.string.Button_Check), onClick = { - if (viewModel.hasConnection()) { - viewModel.onNavigateToConfirmation() - - navController.slideFromRight( - R.id.sendConfirmation, - SendConfirmationFragment.Input( - SendConfirmationFragment.Type.Tron, - sendEntryPointDestId + if (!viewModel.hasConnection()) { + HudHelper.showErrorMessage(view, R.string.Hud_Text_NoInternet) + } else if (riskyAddress) { + keyboardController?.hide() + navController.slideFromBottomForResult( + R.id.addressRiskyBottomSheetAlert, + AddressRiskyBottomSheetAlert.Input( + alertText = Translator.getString(R.string.Send_RiskyAddress_AlertText) ) - ) + ) { + openConfirm(viewModel, navController, sendEntryPointDestId) + } } else { - HudHelper.showErrorMessage(view, R.string.Hud_Text_NoInternet) + openConfirm(viewModel, navController, sendEntryPointDestId) } }, enabled = proceedEnabled @@ -128,3 +137,19 @@ fun SendTronScreen( } } + +private fun openConfirm( + viewModel: SendTronViewModel, + navController: NavController, + sendEntryPointDestId: Int +) { + viewModel.onNavigateToConfirmation() + + navController.slideFromRight( + R.id.sendConfirmation, + SendConfirmationFragment.Input( + SendConfirmationFragment.Type.Tron, + sendEntryPointDestId + ) + ) +} diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/zcash/SendZCashScreen.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/zcash/SendZCashScreen.kt index 807420db86..72219b9ddf 100644 --- a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/zcash/SendZCashScreen.kt +++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/zcash/SendZCashScreen.kt @@ -7,11 +7,14 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import io.horizontalsystems.bankwallet.R +import io.horizontalsystems.bankwallet.core.providers.Translator +import io.horizontalsystems.bankwallet.core.slideFromBottomForResult import io.horizontalsystems.bankwallet.core.slideFromRight import io.horizontalsystems.bankwallet.modules.address.AddressParserModule import io.horizontalsystems.bankwallet.modules.address.AddressParserViewModel @@ -21,6 +24,7 @@ import io.horizontalsystems.bankwallet.modules.amount.HSAmountInput import io.horizontalsystems.bankwallet.modules.availablebalance.AvailableBalance import io.horizontalsystems.bankwallet.modules.fee.HSFee import io.horizontalsystems.bankwallet.modules.memo.HSMemoInput +import io.horizontalsystems.bankwallet.modules.send.AddressRiskyBottomSheetAlert import io.horizontalsystems.bankwallet.modules.send.SendConfirmationFragment import io.horizontalsystems.bankwallet.modules.send.SendScreen import io.horizontalsystems.bankwallet.ui.compose.ComposeAppTheme @@ -36,6 +40,7 @@ fun SendZCashScreen( amountInputModeViewModel: AmountInputModeViewModel, sendEntryPointDestId: Int, amount: BigDecimal?, + riskyAddress: Boolean ) { val wallet = viewModel.wallet val uiState = viewModel.uiState @@ -46,6 +51,7 @@ fun SendZCashScreen( val proceedEnabled = uiState.canBeSend val memoIsAllowed = uiState.memoIsAllowed val amountInputType = amountInputModeViewModel.inputType + val keyboardController = LocalSoftwareKeyboardController.current val paymentAddressViewModel = viewModel( factory = AddressParserModule.Factory(wallet.token, amount) @@ -66,7 +72,8 @@ fun SendZCashScreen( if (uiState.showAddressInput) { HSAddressCell( title = stringResource(R.string.Send_Confirmation_To), - value = uiState.address.hex + value = uiState.address.hex, + riskyAddress = riskyAddress ) { navController.popBackStack() } @@ -125,18 +132,37 @@ fun SendZCashScreen( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 16.dp), - title = stringResource(R.string.Send_DialogProceed), + title = stringResource(R.string.Button_Check), onClick = { - navController.slideFromRight( - R.id.sendConfirmation, - SendConfirmationFragment.Input( - SendConfirmationFragment.Type.ZCash, - sendEntryPointDestId - ) - ) + if (riskyAddress) { + keyboardController?.hide() + navController.slideFromBottomForResult( + R.id.addressRiskyBottomSheetAlert, + AddressRiskyBottomSheetAlert.Input( + alertText = Translator.getString(R.string.Send_RiskyAddress_AlertText) + ) + ) { + openConfirm(navController, sendEntryPointDestId) + } + } else { + openConfirm(navController, sendEntryPointDestId) + } }, enabled = proceedEnabled ) } } } + +private fun openConfirm( + navController: NavController, + sendEntryPointDestId: Int +) { + navController.slideFromRight( + R.id.sendConfirmation, + SendConfirmationFragment.Input( + SendConfirmationFragment.Type.ZCash, + sendEntryPointDestId + ) + ) +} diff --git a/app/src/main/res/navigation/main_graph.xml b/app/src/main/res/navigation/main_graph.xml index 1c5c878022..b65e2b1a5f 100644 --- a/app/src/main/res/navigation/main_graph.xml +++ b/app/src/main/res/navigation/main_graph.xml @@ -371,6 +371,9 @@ + Share Apply Set Amount + Continue Anyway + Check Can\'t be less than %1$s or more than %2$s Wrong integer number @@ -464,6 +466,9 @@ The address you entered is flagged as blacklisted. Transactions to this address could lead to loss or other risks. Please verify the recipient\'s details before proceeding. The address you entered is marked as being under sanctions. Transactions to this address could lead to loss or other risks. Please verify the recipient\'s details before proceeding. + Risky Address! + You are about to send funds to a high-risk address. Proceeding may result in loss or other security risks. By continuing, you accept the potential dangers. Are you sure you want to proceed? + \u2713 Sent Camera permission