Skip to content

Commit

Permalink
Show risky address alert in Send
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelekol committed Feb 18, 2025
1 parent b877ac5 commit ba79b94
Show file tree
Hide file tree
Showing 12 changed files with 465 additions and 133 deletions.
Original file line number Diff line number Diff line change
@@ -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
)
}
}
}
)
}
Original file line number Diff line number Diff line change
@@ -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<Input>()?.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)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
)
}
}
Expand All @@ -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
)
}
}
Expand All @@ -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
)
}
}
Expand All @@ -128,12 +132,13 @@ class SendFragment : BaseFragment() {
val sendSolanaViewModel by navGraphViewModels<SendSolanaViewModel>(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
)
}
}
Expand All @@ -148,7 +153,8 @@ class SendFragment : BaseFragment() {
sendTonViewModel,
amountInputModeViewModel,
sendEntryPointDestId,
amount
amount,
riskyAddress = riskyAddress
)
}
}
Expand All @@ -158,12 +164,13 @@ class SendFragment : BaseFragment() {
val sendTronViewModel by navGraphViewModels<SendTronViewModel>(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
)
}
}
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
)
)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
)
)
}
}
Expand Down Expand Up @@ -378,7 +387,12 @@ fun CheckLocked() {
}

@Composable
fun AddressSuggestions(recent: String?, recentContact: SContact?, contacts: List<SContact>, onClick: (String) -> Unit) {
fun AddressSuggestions(
recent: String?,
recentContact: SContact?,
contacts: List<SContact>,
onClick: (String) -> Unit
) {
if (recentContact != null) {
Column(
modifier = Modifier
Expand Down
Loading

0 comments on commit ba79b94

Please sign in to comment.