Updated on 2026-08-14

This commit is contained in:
Tangem 2024-04-24 15:08:37 +03:00
parent c5c28eca82
commit ddb167daf7
5 changed files with 88 additions and 102 deletions

View file

@ -4,27 +4,18 @@ import android.os.Bundle
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import arrow.core.getOrElse
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.ui.components.SystemBarsEffect
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.screen.ComposeFragment
import com.tangem.core.ui.theme.AppThemeModeHolder
import com.tangem.domain.qrscanning.models.SourceType
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
import com.tangem.features.send.api.navigation.SendRouter
import com.tangem.features.send.impl.navigation.InnerSendRouter
import com.tangem.features.send.impl.presentation.state.StateRouter
import com.tangem.features.send.impl.presentation.ui.SendScreen
import com.tangem.features.send.impl.presentation.viewmodel.SendViewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.launch
import java.lang.ref.WeakReference
import javax.inject.Inject
@ -40,9 +31,6 @@ internal class SendFragment : ComposeFragment() {
@Inject
lateinit var router: SendRouter
@Inject
lateinit var listenToQrScanningUseCase: ListenToQrScanningUseCase
@Inject
lateinit var analyticsEventsHandler: AnalyticsEventHandler
@ -65,7 +53,6 @@ internal class SendFragment : ComposeFragment() {
analyticsEventsHandler = analyticsEventsHandler,
),
)
listenToQrCode()
}
@Composable
@ -83,25 +70,7 @@ internal class SendFragment : ComposeFragment() {
super.onDestroy()
}
private fun listenToQrCode() {
lifecycleScope.launch {
listenToQrScanningUseCase(SourceType.SEND)
.getOrElse { emptyFlow() }
.flowWithLifecycle(this@SendFragment.lifecycle, minActiveState = Lifecycle.State.CREATED)
.collect {
delay(QR_SCAN_DELAY)
// Delayed launch is needed in order for the UI to be drawn and to process the sent events.
// If do not use the delay, then error field is not displayed when
// inserting an incorrect amount by shareUri
viewModel.onQrCodeScanned(it)
}
}
}
companion object {
private const val QR_SCAN_DELAY = 200L
/** Create send fragment instance */
fun create(): SendFragment = SendFragment()
}

View file

@ -15,6 +15,8 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.qrscanning.models.SourceType
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
import com.tangem.domain.qrscanning.usecases.ParseQrCodeUseCase
import com.tangem.domain.redux.LegacyAction
import com.tangem.domain.redux.ReduxStateHolder
@ -92,6 +94,7 @@ internal class SendViewModel @Inject constructor(
private val isSendTapHelpEnabledUseCase: IsSendTapHelpEnabledUseCase,
private val neverShowTapHelpUseCase: NeverShowTapHelpUseCase,
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
private val listenToQrScanningUseCase: ListenToQrScanningUseCase,
currencyChecksRepository: CurrencyChecksRepository,
isFeeApproximateUseCase: IsFeeApproximateUseCase,
validateWalletMemoUseCase: ValidateWalletMemoUseCase,
@ -189,11 +192,11 @@ internal class SendViewModel @Inject constructor(
private var memoValidationJobHolder = JobHolder()
private var sendNotificationsJobHolder = JobHolder()
private var feeNotificationsJobHolder = JobHolder()
private var qrScannerJobHolder = JobHolder()
private var sendIdleTimer = 0L
init {
subscribeOnQRScannerResult()
subscribeOnCurrencyStatusUpdates()
subscribeOnBalanceHidden()
getTapHelpPreviewAvailability()
@ -215,6 +218,13 @@ internal class SendViewModel @Inject constructor(
this.stateRouter = stateRouter
}
private fun subscribeOnQRScannerResult() {
listenToQrScanningUseCase(SourceType.SEND)
.getOrElse { emptyFlow() }
.onEach(::onQrCodeScanned)
.launchIn(viewModelScope)
}
private fun subscribeOnCurrencyStatusUpdates() {
viewModelScope.launch(dispatchers.main) {
getUserWalletUseCase(userWalletId).fold(
@ -536,6 +546,23 @@ internal class SendViewModel @Inject constructor(
feeJobHolder.cancel()
}
}
private fun onQrCodeScanned(address: String) {
parseQrCodeUseCase(address, cryptoCurrency).fold(
ifRight = { parsedCode ->
onRecipientAddressValueChange(parsedCode.address, EnterAddressSource.QRCode)
parsedCode.amount?.let {
onAmountValueChange(it.parseBigDecimal(decimals = cryptoCurrency.decimals))
}
parsedCode.memo?.let { onRecipientMemoValueChange(it) }
},
ifLeft = {
onRecipientAddressValueChange(address, EnterAddressSource.QRCode)
Timber.w(it)
},
)
}
// endregion
// region amount state clicks
@ -555,26 +582,9 @@ internal class SendViewModel @Inject constructor(
override fun onAmountPasteTriggerDismiss() {
uiState = amountStateFactory.getOnAmountPastedTriggerDismiss()
}
// endregion
// endregion
// region recipient state clicks
fun onQrCodeScanned(address: String) {
viewModelScope.launch(dispatchers.main) {
parseQrCodeUseCase(address, cryptoCurrency).fold(
ifRight = { parsedCode ->
onRecipientAddressValueChange(parsedCode.address, EnterAddressSource.QRCode)
parsedCode.amount?.let {
onAmountValueChange(it.parseBigDecimal(decimals = cryptoCurrency.decimals))
}
parsedCode.memo?.let { onRecipientMemoValueChange(it) }
},
ifLeft = {
onRecipientAddressValueChange(address, EnterAddressSource.QRCode)
Timber.w(it)
},
)
}.saveIn(qrScannerJobHolder)
}
// region recipient state clicks
override fun onRecipientAddressValueChange(value: String, type: EnterAddressSource?) {
viewModelScope.launch {
@ -633,7 +643,7 @@ internal class SendViewModel @Inject constructor(
val isRecent = type == EnterAddressSource.RecentAddress
if (isRecent && isValidAddress) onNextClick()
}
// endregion
// endregion
// region fee
override fun feeReload() = loadFee()
@ -709,7 +719,7 @@ internal class SendViewModel @Inject constructor(
cryptoCurrency = cryptoCurrency,
)
}
// endregion
// endregion
// region send state clicks
override fun onSendClick() {
@ -894,7 +904,7 @@ internal class SendViewModel @Inject constructor(
}
uiState = stateFactory.getHiddenTapHelpState()
}
// endregion
// endregion
private companion object {
const val CHECK_FEE_UPDATE_DELAY = 60_000L