Updated on 2026-08-14
This commit is contained in:
parent
069605e151
commit
36516c900f
234 changed files with 902 additions and 1618 deletions
|
|
@ -59,8 +59,6 @@ class ForegroundActivityObserver : ActivityResultCaller {
|
|||
}
|
||||
}
|
||||
|
||||
fun ForegroundActivityObserver.withForegroundActivity(
|
||||
block: (Activity) -> Unit
|
||||
) {
|
||||
fun ForegroundActivityObserver.withForegroundActivity(block: (Activity) -> Unit) {
|
||||
foregroundActivity?.let { block(it) }
|
||||
}
|
||||
|
|
@ -11,12 +11,7 @@ import androidx.fragment.app.FragmentManager
|
|||
import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks
|
||||
|
||||
class NavBarInsetsFragmentLifecycleCallback : FragmentLifecycleCallbacks() {
|
||||
override fun onFragmentViewCreated(
|
||||
fm: FragmentManager,
|
||||
f: Fragment,
|
||||
v: View,
|
||||
savedInstanceState: Bundle?,
|
||||
) {
|
||||
override fun onFragmentViewCreated(fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle?) {
|
||||
if (v is ComposeView) return
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(v) { view, windowInsets ->
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import timber.log.Timber
|
|||
|
||||
class CompositionCounter(
|
||||
val id: String,
|
||||
count: Int = 0
|
||||
count: Int = 0,
|
||||
) {
|
||||
var count: Int = count
|
||||
private set
|
||||
|
|
@ -20,7 +20,7 @@ class CompositionCounter(
|
|||
class CompositionLogger(
|
||||
private val recomposeViewId: String,
|
||||
private val tag: String = recomposeViewId,
|
||||
private var turnOnForIds: List<String> = listOf(recomposeViewId)
|
||||
private var turnOnForIds: List<String> = listOf(recomposeViewId),
|
||||
) {
|
||||
val count: Int
|
||||
get() = compositionCounter.count
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import java.math.RoundingMode
|
|||
*/
|
||||
class CurrencyConverter(
|
||||
private val rateValue: BigDecimal,
|
||||
private val decimals: Int
|
||||
private val decimals: Int,
|
||||
) {
|
||||
private val roundingMode = RoundingMode.HALF_UP
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class CustomTabsManager {
|
|||
.setDefaultColorSchemeParams(
|
||||
CustomTabColorSchemeParams.Builder()
|
||||
.setNavigationBarColor(context.getColorCompat(R.color.toolbarColor))
|
||||
.build()
|
||||
.build(),
|
||||
)
|
||||
.build()
|
||||
customTabsIntent.launchUrl(context, Uri.parse(url))
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import timber.log.Timber
|
|||
*/
|
||||
class GlobalLayoutStateHandler<T : View>(
|
||||
private val view: T,
|
||||
attachImmediately: Boolean = true
|
||||
attachImmediately: Boolean = true,
|
||||
) : ViewTreeObserver.OnGlobalLayoutListener {
|
||||
|
||||
var onStateChanged: ((T) -> Unit)? = null
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@ object TangemSdkErrorMapper {
|
|||
is TangemSdkError.SerializeCommandError -> TangemSdkError.SerializeCommandError()
|
||||
is TangemSdkError.DeserializeApduFailed -> TangemSdkError.DeserializeApduFailed()
|
||||
is TangemSdkError.EncodingFailedTypeMismatch -> TangemSdkError.EncodingFailedTypeMismatch(
|
||||
error.customMessage
|
||||
error.customMessage,
|
||||
)
|
||||
is TangemSdkError.EncodingFailed -> TangemSdkError.EncodingFailed(error.customMessage)
|
||||
is TangemSdkError.DecodingFailedMissingTag -> TangemSdkError.DecodingFailedMissingTag(
|
||||
error.customMessage
|
||||
error.customMessage,
|
||||
)
|
||||
is TangemSdkError.DecodingFailedTypeMismatch -> TangemSdkError.DecodingFailedTypeMismatch(
|
||||
error.customMessage
|
||||
error.customMessage,
|
||||
)
|
||||
is TangemSdkError.DecodingFailed -> TangemSdkError.DecodingFailed(error.customMessage)
|
||||
is TangemSdkError.InvalidResponse -> TangemSdkError.InvalidResponse()
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ sealed class Token(
|
|||
|
||||
object ShowWalletAddress : Token(
|
||||
category = "Token",
|
||||
event = "Button - Show the Wallet Address"
|
||||
event = "Button - Show the Wallet Address",
|
||||
)
|
||||
|
||||
sealed class Receive(
|
||||
|
|
|
|||
|
|
@ -116,10 +116,7 @@ class TopUpController(
|
|||
}
|
||||
}
|
||||
|
||||
fun send(
|
||||
scanResponse: ScanResponse,
|
||||
cardBalanceState: AnalyticsParam.CardBalanceState,
|
||||
) {
|
||||
fun send(scanResponse: ScanResponse, cardBalanceState: AnalyticsParam.CardBalanceState) {
|
||||
UserWalletIdBuilder.scanResponse(scanResponse).build()?.let {
|
||||
send(it, cardBalanceState, scanResponse.cardTypesResolver)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ import androidx.compose.runtime.CompositionLocalProvider
|
|||
* Used for disable ripple if button is enable = false
|
||||
*/
|
||||
@Composable
|
||||
fun ToggledRippleTheme(
|
||||
isEnabled: Boolean,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
fun ToggledRippleTheme(isEnabled: Boolean, content: @Composable () -> Unit) {
|
||||
val theme = LocalRippleTheme provides if (isEnabled) LocalRippleTheme.current else NoRippleTheme()
|
||||
CompositionLocalProvider(theme) { content() }
|
||||
}
|
||||
|
|
@ -53,16 +53,22 @@ fun ComposeDialogManager() {
|
|||
|
||||
ShowTheDialog(dialogSate)
|
||||
|
||||
LaunchedEffect(key1 = Unit, block = {
|
||||
domainStore.subscribe(subscriber) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.globalState == newState.globalState
|
||||
}.select { it.globalState }
|
||||
}
|
||||
})
|
||||
DisposableEffect(key1 = Unit, effect = {
|
||||
onDispose { domainStore.unsubscribe(subscriber) }
|
||||
})
|
||||
LaunchedEffect(
|
||||
key1 = Unit,
|
||||
block = {
|
||||
domainStore.subscribe(subscriber) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.globalState == newState.globalState
|
||||
}.select { it.globalState }
|
||||
}
|
||||
},
|
||||
)
|
||||
DisposableEffect(
|
||||
key1 = Unit,
|
||||
effect = {
|
||||
onDispose { domainStore.unsubscribe(subscriber) }
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -77,7 +83,7 @@ private fun ShowTheDialog(dialogState: MutableState<DomainDialog?>) {
|
|||
is DomainDialog.DialogError -> ErrorDialog(
|
||||
title = stringResource(id = R.string.common_error),
|
||||
body = errorConverter.convert(dialog.error).message,
|
||||
onDismissRequest
|
||||
onDismissRequest,
|
||||
)
|
||||
is DomainDialog.SelectTokenDialog -> SelectTokenNetworkDialog(dialog, onDismissRequest)
|
||||
else -> {}
|
||||
|
|
@ -97,14 +103,14 @@ fun <T> SimpleDialog(
|
|||
) {
|
||||
Dialog(
|
||||
properties = DialogProperties(false, false),
|
||||
onDismissRequest = { }
|
||||
onDismissRequest = { },
|
||||
) {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = MaterialTheme.shapes.medium
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(22.dp)
|
||||
modifier = Modifier.padding(22.dp),
|
||||
) {
|
||||
DialogTitle(title = title)
|
||||
LazyColumn {
|
||||
|
|
@ -133,19 +139,15 @@ private fun DialogTitle(title: String) {
|
|||
style = LocalTextStyle.provides(
|
||||
TextStyle(
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 20.sp
|
||||
)
|
||||
).value
|
||||
fontSize = 20.sp,
|
||||
),
|
||||
).value,
|
||||
)
|
||||
SpacerH16()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ErrorDialog(
|
||||
title: String,
|
||||
body: String,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
fun ErrorDialog(title: String, body: String, onDismissRequest: () -> Unit) {
|
||||
AlertDialog(
|
||||
title = { DialogTitle(title) },
|
||||
text = { Text(body) },
|
||||
|
|
@ -154,6 +156,6 @@ fun ErrorDialog(
|
|||
Button(onClick = onDismissRequest) {
|
||||
Text(text = stringResource(id = R.string.common_ok))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -15,11 +15,7 @@ import androidx.compose.ui.unit.dp
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun ErrorView(
|
||||
text: String,
|
||||
modifier: Modifier = Modifier,
|
||||
style: TextStyle = LocalTextStyle.current,
|
||||
) {
|
||||
fun ErrorView(text: String, modifier: Modifier = Modifier, style: TextStyle = LocalTextStyle.current) {
|
||||
Text(
|
||||
text,
|
||||
color = MaterialTheme.colors.error,
|
||||
|
|
|
|||
|
|
@ -213,10 +213,7 @@ private fun OutlinedProgressTextField(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun AnimatedErrorView(
|
||||
errorConverter: ModuleMessageConverter,
|
||||
error: ModuleError? = null,
|
||||
) {
|
||||
private fun AnimatedErrorView(errorConverter: ModuleMessageConverter, error: ModuleError? = null) {
|
||||
AnimatedVisibility(
|
||||
visible = error != null,
|
||||
enter = fadeIn() + slideInVertically(),
|
||||
|
|
|
|||
|
|
@ -110,10 +110,7 @@ fun PinCodeWidget(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun PinElement(
|
||||
config: PinViewConfig,
|
||||
pinSymbol: String,
|
||||
) {
|
||||
private fun PinElement(config: PinViewConfig, pinSymbol: String) {
|
||||
Box(Modifier.padding(config.pinBoxPadding)) {
|
||||
Box(config.pinBoxModifier) {
|
||||
Text(
|
||||
|
|
|
|||
|
|
@ -128,11 +128,7 @@ internal data class TangemTextFieldColors(
|
|||
}
|
||||
|
||||
@Composable
|
||||
override fun labelColor(
|
||||
enabled: Boolean,
|
||||
error: Boolean,
|
||||
interactionSource: InteractionSource,
|
||||
): State<Color> {
|
||||
override fun labelColor(enabled: Boolean, error: Boolean, interactionSource: InteractionSource): State<Color> {
|
||||
val focused by interactionSource.collectIsFocusedAsState()
|
||||
|
||||
val targetValue = when {
|
||||
|
|
|
|||
|
|
@ -12,16 +12,13 @@ import androidx.compose.ui.unit.sp
|
|||
*/
|
||||
|
||||
@Composable
|
||||
fun TitleSubtitle(
|
||||
title: String,
|
||||
subtitle: String
|
||||
) {
|
||||
fun TitleSubtitle(title: String, subtitle: String) {
|
||||
Column {
|
||||
Text(text = title)
|
||||
Text(
|
||||
text = subtitle,
|
||||
fontSize = 12.sp,
|
||||
color = Color.Gray
|
||||
color = Color.Gray,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -21,11 +21,7 @@ import com.tangem.wallet.R
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun AddCustomTokenWarning(
|
||||
warning: ModuleMessage,
|
||||
converter: ModuleMessageConverter,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
fun AddCustomTokenWarning(warning: ModuleMessage, converter: ModuleMessageConverter, modifier: Modifier = Modifier) {
|
||||
Surface(
|
||||
modifier = modifier,
|
||||
shape = MaterialTheme.shapes.small,
|
||||
|
|
@ -39,14 +35,14 @@ fun AddCustomTokenWarning(
|
|||
text = stringResource(id = R.string.common_warning),
|
||||
color = colorResource(id = R.color.white),
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
SpacerH8()
|
||||
Text(
|
||||
text = converter.convert(warning).message,
|
||||
color = colorResource(id = R.color.white),
|
||||
fontSize = 13.sp,
|
||||
lineHeight = 18.sp
|
||||
lineHeight = 18.sp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
package com.tangem.tap.common.compose.extensions
|
||||
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.AnimationVector1D
|
||||
import androidx.compose.animation.core.Easing
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -41,8 +45,8 @@ fun animatable(
|
|||
targetValue = values.second,
|
||||
animationSpec = tween(
|
||||
durationMillis = duration,
|
||||
easing = easing
|
||||
)
|
||||
easing = easing,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.tangem.tap.features.wallet.redux.ProgressState
|
|||
open class Button(val enabled: Boolean)
|
||||
|
||||
open class IndeterminateProgressButton(
|
||||
val state: ButtonState
|
||||
val state: ButtonState,
|
||||
) : Button(state != ButtonState.DISABLED) {
|
||||
|
||||
val progressState: ProgressState
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ fun Activity.sendEmail(
|
|||
subject: String,
|
||||
message: String,
|
||||
file: File? = null,
|
||||
onFail: ((Exception) -> Unit)? = null
|
||||
onFail: ((Exception) -> Unit)? = null,
|
||||
) {
|
||||
fun createEmailShareIntent(recipient: String, subject: String, text: String, file: File? = null): Intent {
|
||||
val builder = ShareCompat.IntentBuilder.from(this)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ import android.net.Uri
|
|||
import androidx.annotation.AnyRes
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
fun Context.readFile(fileName: String): String =
|
||||
this.openFileInput(fileName).bufferedReader().readText()
|
||||
fun Context.readFile(fileName: String): String = this.openFileInput(fileName).bufferedReader().readText()
|
||||
|
||||
fun Context.rewriteFile(content: String, fileName: String) {
|
||||
this.openFileOutput(fileName, Context.MODE_PRIVATE).use {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
fun <K, V> Map<out K?, V?>.filterNotNull(): Map<K, V> =
|
||||
filter { it.key != null && it.value != null } as Map<K, V>
|
||||
fun <K, V> Map<out K?, V?>.filterNotNull(): Map<K, V> = filter { it.key != null && it.value != null } as Map<K, V>
|
||||
|
|
@ -46,9 +46,7 @@ fun BigDecimal.toFormattedCurrencyString(
|
|||
return "$formattedAmount $currency"
|
||||
}
|
||||
|
||||
fun BigDecimal.toFiatRateString(
|
||||
fiatCurrencyName: String,
|
||||
): String {
|
||||
fun BigDecimal.toFiatRateString(fiatCurrencyName: String): String {
|
||||
val value = this
|
||||
.setScale(2, RoundingMode.HALF_UP)
|
||||
.formatWithSpaces()
|
||||
|
|
@ -69,10 +67,7 @@ fun BigDecimal.toFiatValue(rateValue: BigDecimal): BigDecimal {
|
|||
return fiatValue.setScale(2, RoundingMode.HALF_UP)
|
||||
}
|
||||
|
||||
fun BigDecimal.toFormattedFiatValue(
|
||||
fiatCurrencyName: String,
|
||||
formatWithSpaces: Boolean = false,
|
||||
): String {
|
||||
fun BigDecimal.toFormattedFiatValue(fiatCurrencyName: String, formatWithSpaces: Boolean = false): String {
|
||||
val fiatValue = this.setScale(2, RoundingMode.HALF_UP)
|
||||
.let { if (formatWithSpaces) it.formatWithSpaces() else it }
|
||||
return " $fiatValue $fiatCurrencyName"
|
||||
|
|
|
|||
|
|
@ -25,12 +25,7 @@ fun String?.ellipsizeBeforeSpace(allowedSize: Int): String {
|
|||
newString.substring(startIndex until newString.length)
|
||||
}
|
||||
|
||||
fun String.colorSegment(
|
||||
context: Context,
|
||||
color: Int,
|
||||
startIndex: Int = 0,
|
||||
endIndex: Int = this.length,
|
||||
): Spannable {
|
||||
fun String.colorSegment(context: Context, color: Int, startIndex: Int = 0, endIndex: Int = this.length): Spannable {
|
||||
return this.toSpannable()
|
||||
.also { spannable ->
|
||||
spannable.setSpan(
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ inline fun Transition.addListener(
|
|||
crossinline onEnd: (animator: Transition) -> Unit = {},
|
||||
crossinline onCancel: (animator: Transition) -> Unit = {},
|
||||
crossinline onPause: (animator: Transition) -> Unit = {},
|
||||
crossinline onRepeat: (animator: Transition) -> Unit = {}
|
||||
crossinline onRepeat: (animator: Transition) -> Unit = {},
|
||||
): Transition.TransitionListener {
|
||||
val listener = object : Transition.TransitionListener {
|
||||
override fun onTransitionStart(transition: Transition) = onStart(transition)
|
||||
|
|
|
|||
|
|
@ -83,12 +83,11 @@ fun View.invisible(invisible: Boolean = true, invokeBeforeStateChanged: (() -> U
|
|||
}
|
||||
}
|
||||
|
||||
fun Context.dpToPixels(dp: Int): Int =
|
||||
TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
dp.toFloat(),
|
||||
this.resources.displayMetrics,
|
||||
).toInt()
|
||||
fun Context.dpToPixels(dp: Int): Int = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
dp.toFloat(),
|
||||
this.resources.displayMetrics,
|
||||
).toInt()
|
||||
|
||||
tailrec fun Context?.getActivity(): Activity? = this as? Activity
|
||||
?: (this as? ContextWrapper)?.baseContext?.getActivity()
|
||||
|
|
|
|||
|
|
@ -10,10 +10,7 @@ import timber.log.Timber
|
|||
|
||||
private const val COIL_LOG_TAG = "COIL"
|
||||
|
||||
fun createCoilImageLoader(
|
||||
context: Context,
|
||||
logEnabled: Boolean = false,
|
||||
): ImageLoader {
|
||||
fun createCoilImageLoader(context: Context, logEnabled: Boolean = false): ImageLoader {
|
||||
return ImageLoader.Builder(context)
|
||||
.apply {
|
||||
if (!logEnabled) return@apply
|
||||
|
|
@ -27,7 +24,7 @@ fun createCoilImageLoader(
|
|||
}
|
||||
.apply {
|
||||
level = HttpLoggingInterceptor.Level.BODY
|
||||
}
|
||||
},
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,9 @@ class ScanQrCodeActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
|
|||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val cameraPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
|
||||
cameraPermission == PackageManager.PERMISSION_GRANTED
|
||||
} else true
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestPermission() {
|
||||
|
|
|
|||
|
|
@ -12,17 +12,12 @@ class SpaceItemDecoration(
|
|||
|
||||
private lateinit var space: Space
|
||||
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect,
|
||||
view: View,
|
||||
parent: RecyclerView,
|
||||
state: RecyclerView.State
|
||||
) {
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
if (state.itemCount == 0) return
|
||||
if (!::space.isInitialized) {
|
||||
space = Space(
|
||||
view.dpToPx(horizontalSpaceDp).toInt(),
|
||||
view.dpToPx(verticalSpaceDp).toInt()
|
||||
view.dpToPx(verticalSpaceDp).toInt(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import android.content.Intent
|
|||
import com.google.android.gms.wallet.PaymentData
|
||||
import com.shopify.buy3.Storefront
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.datasource.config.models.ShopifyShop
|
||||
import com.tangem.tap.common.analytics.converters.ShopOrderToEventConverter
|
||||
import com.tangem.tap.common.extensions.filterNotNull
|
||||
import com.tangem.tap.common.shop.data.ProductType
|
||||
|
|
@ -12,7 +13,6 @@ import com.tangem.tap.common.shop.data.TangemProduct
|
|||
import com.tangem.tap.common.shop.data.TotalSum
|
||||
import com.tangem.tap.common.shop.googlepay.GooglePayService
|
||||
import com.tangem.tap.common.shop.shopify.ShopifyService
|
||||
import com.tangem.datasource.config.models.ShopifyShop
|
||||
import com.tangem.tap.common.shop.shopify.data.CheckoutItem
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
|
|
@ -106,11 +106,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
|
|||
// }
|
||||
// }
|
||||
|
||||
suspend fun handleGooglePayResult(
|
||||
resultCode: Int,
|
||||
data: Intent?,
|
||||
productType: ProductType,
|
||||
): Result<Unit> {
|
||||
suspend fun handleGooglePayResult(resultCode: Int, data: Intent?, productType: ProductType): Result<Unit> {
|
||||
val result = googlePayService.handleResponseFromGooglePay(resultCode, data)
|
||||
result.onSuccess {
|
||||
val finalizePaymentResult = completeTokenizedPayment(it, productType)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import com.tangem.tap.common.shop.TangemShopService
|
|||
|
||||
enum class ProductType(val sku: String) {
|
||||
WALLET_2_CARDS(TangemShopService.TANGEM_WALLET_2_CARDS_SKU),
|
||||
WALLET_3_CARDS(TangemShopService.TANGEM_WALLET_3_CARDS_SKU);
|
||||
WALLET_3_CARDS(TangemShopService.TANGEM_WALLET_3_CARDS_SKU),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun fromSku(sku: String): ProductType? {
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ package com.tangem.tap.common.shop.data
|
|||
data class TangemProduct(
|
||||
val type: ProductType,
|
||||
val totalSum: TotalSum? = null,
|
||||
val appliedDiscount: String? = null
|
||||
val appliedDiscount: String? = null,
|
||||
)
|
||||
|
|
@ -94,11 +94,7 @@ object GooglePayUtil {
|
|||
}
|
||||
}
|
||||
|
||||
private fun getTransactionInfo(
|
||||
price: String,
|
||||
countryCode: String,
|
||||
currencyCode: String,
|
||||
): JSONObject {
|
||||
private fun getTransactionInfo(price: String, countryCode: String, currencyCode: String): JSONObject {
|
||||
return JSONObject().apply {
|
||||
put("totalPrice", price)
|
||||
put("totalPriceStatus", "FINAL")
|
||||
|
|
|
|||
|
|
@ -106,10 +106,7 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun createCheckout(
|
||||
checkoutItems: List<CheckoutItem>,
|
||||
checkoutID: ID? = null,
|
||||
): Result<Checkout> {
|
||||
suspend fun createCheckout(checkoutItems: List<CheckoutItem>, checkoutID: ID? = null): Result<Checkout> {
|
||||
val storefrontLineItems: MutableList<CheckoutLineItemInput> = checkoutItems
|
||||
.map { CheckoutLineItemInput(it.quantity, it.id) }.toMutableList()
|
||||
|
||||
|
|
@ -197,10 +194,7 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
|
|||
return runCheckoutMutation(query)
|
||||
}
|
||||
|
||||
suspend fun completeWithTokenizedPayment(
|
||||
payment: TokenizedPaymentInputV3,
|
||||
checkoutID: ID,
|
||||
): Result<Checkout> {
|
||||
suspend fun completeWithTokenizedPayment(payment: TokenizedPaymentInputV3, checkoutID: ID): Result<Checkout> {
|
||||
val query = mutation { mutationQuery: MutationQuery ->
|
||||
mutationQuery
|
||||
.checkoutCompleteWithTokenizedPaymentV3(
|
||||
|
|
@ -247,25 +241,21 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
|
|||
private suspend fun queryAsync(
|
||||
query: QueryRootQuery,
|
||||
retryHandler: RetryHandler<QueryRoot>,
|
||||
): GraphCallResult<QueryRoot> =
|
||||
withContext(Dispatchers.IO) {
|
||||
suspendCoroutine { continuation ->
|
||||
client.queryGraph(query).enqueue(retryHandler = retryHandler) { result ->
|
||||
continuation.resume(result)
|
||||
}
|
||||
): GraphCallResult<QueryRoot> = withContext(Dispatchers.IO) {
|
||||
suspendCoroutine { continuation ->
|
||||
client.queryGraph(query).enqueue(retryHandler = retryHandler) { result ->
|
||||
continuation.resume(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun queryAsync(
|
||||
query: QueryRootQuery,
|
||||
): GraphCallResult<QueryRoot> =
|
||||
withContext(Dispatchers.IO) {
|
||||
suspendCoroutine { continuation ->
|
||||
client.queryGraph(query).enqueue { result ->
|
||||
continuation.resume(result)
|
||||
}
|
||||
private suspend fun queryAsync(query: QueryRootQuery): GraphCallResult<QueryRoot> = withContext(Dispatchers.IO) {
|
||||
suspendCoroutine { continuation ->
|
||||
client.queryGraph(query).enqueue { result ->
|
||||
continuation.resume(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun mutationQueryAsync(query: MutationQuery): GraphCallResult<Mutation> =
|
||||
withContext(Dispatchers.IO) {
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ import com.shopify.graphql.support.ID
|
|||
|
||||
data class CheckoutItem(
|
||||
val id: ID,
|
||||
val quantity: Int
|
||||
val quantity: Int,
|
||||
)
|
||||
|
|
@ -18,14 +18,14 @@ import com.tangem.wallet.R
|
|||
*/
|
||||
class MaxAmountSnackbar(
|
||||
parent: ViewGroup,
|
||||
content: MaxAmountSnackbarView
|
||||
content: MaxAmountSnackbarView,
|
||||
) : BaseTransientBottomBar<MaxAmountSnackbar>(parent, content, content) {
|
||||
|
||||
companion object {
|
||||
|
||||
fun make(view: View, onClick: () -> Unit): MaxAmountSnackbar {
|
||||
val parent = view.findSuitableParent() ?: throw IllegalArgumentException(
|
||||
"No suitable parent found from the given view. Please provide a valid view."
|
||||
"No suitable parent found from the given view. Please provide a valid view.",
|
||||
)
|
||||
val inflater = LayoutInflater.from(view.context)
|
||||
val customView = inflater.inflate(R.layout.view_snackbar_max_amount, parent, false) as MaxAmountSnackbarView
|
||||
|
|
@ -63,7 +63,7 @@ class MaxAmountSnackbar(
|
|||
class MaxAmountSnackbarView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
defStyleAttr: Int = 0,
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr), ContentViewCallback {
|
||||
|
||||
init {
|
||||
|
|
|
|||
|
|
@ -11,15 +11,13 @@ import java.util.*
|
|||
class PayIdManager {
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
suspend fun verifyPayId(
|
||||
payId: String,
|
||||
blockchain: Blockchain,
|
||||
): Result<VerifyPayIdResponse> = withContext(Dispatchers.IO) {
|
||||
val splitPayId = payId.split("\$")
|
||||
val user = splitPayId[0]
|
||||
val baseUrl = "https://${splitPayId[1]}/"
|
||||
return@withContext PayIdVerifyService(baseUrl).verifyAddress(user, blockchain.getPayIdNetwork())
|
||||
}
|
||||
suspend fun verifyPayId(payId: String, blockchain: Blockchain): Result<VerifyPayIdResponse> =
|
||||
withContext(Dispatchers.IO) {
|
||||
val splitPayId = payId.split("\$")
|
||||
val user = splitPayId[0]
|
||||
val baseUrl = "https://${splitPayId[1]}/"
|
||||
return@withContext PayIdVerifyService(baseUrl).verifyAddress(user, blockchain.getPayIdNetwork())
|
||||
}
|
||||
|
||||
private fun Blockchain.getPayIdNetwork(): String {
|
||||
return when (this) {
|
||||
|
|
@ -30,8 +28,10 @@ class PayIdManager {
|
|||
}
|
||||
|
||||
companion object {
|
||||
private val payIdRegExp = ("^[a-z0-9!#@%&*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#@%&*+/=?^_`{|}~-]+)*\\\$(?:(?:[a-z0-9]" +
|
||||
"(?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z-]*[a-z0-9])?|(?:[0-9]{1,3}\\.){3}[0-9]{1,3})\$").toRegex()
|
||||
private val payIdRegExp = (
|
||||
"^[a-z0-9!#@%&*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#@%&*+/=?^_`{|}~-]+)*\\\$(?:(?:[a-z0-9]" +
|
||||
"(?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z-]*[a-z0-9])?|(?:[0-9]{1,3}\\.){3}[0-9]{1,3})\$"
|
||||
).toRegex()
|
||||
|
||||
val payIdSupported: EnumSet<Blockchain> = EnumSet.of(
|
||||
Blockchain.XRP,
|
||||
|
|
|
|||
|
|
@ -82,9 +82,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
).also { sendScanResultsToAnalytics(it) }
|
||||
}
|
||||
|
||||
suspend fun createProductWallet(
|
||||
scanResponse: ScanResponse,
|
||||
): CompletionResult<CreateProductWalletTaskResponse> {
|
||||
suspend fun createProductWallet(scanResponse: ScanResponse): CompletionResult<CreateProductWalletTaskResponse> {
|
||||
return runTaskAsync(
|
||||
CreateProductWalletTask(scanResponse.cardTypesResolver),
|
||||
scanResponse.card.cardId,
|
||||
|
|
@ -92,9 +90,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
)
|
||||
}
|
||||
|
||||
private fun sendScanResultsToAnalytics(
|
||||
result: CompletionResult<ScanResponse>,
|
||||
) {
|
||||
private fun sendScanResultsToAnalytics(result: CompletionResult<ScanResponse>) {
|
||||
if (result is CompletionResult.Failure) {
|
||||
(result.error as? TangemSdkError)?.let { error ->
|
||||
Analytics.send(Basic.ScanError(error))
|
||||
|
|
@ -194,14 +190,13 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
cardId: String? = null,
|
||||
initialMessage: Message? = null,
|
||||
accessCode: String? = null,
|
||||
): CompletionResult<T> =
|
||||
withContext(Dispatchers.Main) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage, accessCode) { result ->
|
||||
if (continuation.isActive) continuation.resume(result)
|
||||
}
|
||||
): CompletionResult<T> = withContext(Dispatchers.Main) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage, accessCode) { result ->
|
||||
if (continuation.isActive) continuation.resume(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun <T : CommandResponse> runTaskAsyncReturnOnMain(
|
||||
runnable: CardSessionRunnable<T>,
|
||||
|
|
@ -226,9 +221,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
return context.getString(stringResId, *formatArgs)
|
||||
}
|
||||
|
||||
fun setAccessCodeRequestPolicy(
|
||||
useBiometricsForAccessCode: Boolean,
|
||||
) {
|
||||
fun setAccessCodeRequestPolicy(useBiometricsForAccessCode: Boolean) {
|
||||
tangemSdk.config.userCodeRequestPolicy = if (useBiometricsForAccessCode) {
|
||||
UserCodeRequestPolicy.AlwaysWithBiometrics(codeType = UserCodeType.AccessCode)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -53,10 +53,7 @@ class TangemSigner(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun sign(
|
||||
hash: ByteArray,
|
||||
publicKey: Wallet.PublicKey,
|
||||
): CompletionResult<ByteArray> {
|
||||
override suspend fun sign(hash: ByteArray, publicKey: Wallet.PublicKey): CompletionResult<ByteArray> {
|
||||
val result = sign(
|
||||
hashes = listOf(hash),
|
||||
publicKey = publicKey,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ data class WarningMessage(
|
|||
val origin: Origin = Origin.Remote,
|
||||
@StringRes val buttonTextId: Int? = null,
|
||||
val titleFormatArg: String? = null,
|
||||
val messageFormatArg: String? = null
|
||||
val messageFormatArg: String? = null,
|
||||
) {
|
||||
val blockchainList: List<Blockchain>? by lazy {
|
||||
blockchains?.map { Blockchain.fromId(it.uppercase()) }
|
||||
|
|
@ -35,7 +35,7 @@ data class WarningMessage(
|
|||
Warning,
|
||||
|
||||
@Json(name = "info")
|
||||
Info
|
||||
Info,
|
||||
}
|
||||
|
||||
enum class Type {
|
||||
|
|
@ -47,7 +47,7 @@ data class WarningMessage(
|
|||
|
||||
AppRating,
|
||||
|
||||
TestCard
|
||||
TestCard,
|
||||
}
|
||||
|
||||
enum class Location {
|
||||
|
|
@ -55,7 +55,7 @@ data class WarningMessage(
|
|||
MainScreen,
|
||||
|
||||
@Json(name = "send")
|
||||
SendScreen
|
||||
SendScreen,
|
||||
}
|
||||
|
||||
enum class Origin {
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ class WarningMessagesManager {
|
|||
messageResId = R.string.warning_signed_tx_previously,
|
||||
origin = WarningMessage.Origin.Local,
|
||||
buttonTextId = R.string.warning_button_learn_more,
|
||||
titleFormatArg = "\u26A0"
|
||||
titleFormatArg = "\u26A0",
|
||||
)
|
||||
|
||||
fun appRatingWarning(): WarningMessage = WarningMessage(
|
||||
|
|
|
|||
|
|
@ -92,10 +92,7 @@ private fun getDerivationParams(derivationPath: String?, card: CardDTO): Derivat
|
|||
}
|
||||
}
|
||||
|
||||
fun WalletManagerFactory.makeWalletManagerForApp(
|
||||
scanResponse: ScanResponse,
|
||||
currency: Currency,
|
||||
): WalletManager? {
|
||||
fun WalletManagerFactory.makeWalletManagerForApp(scanResponse: ScanResponse, currency: Currency): WalletManager? {
|
||||
return makeWalletManagerForApp(
|
||||
scanResponse,
|
||||
blockchain = currency.blockchain,
|
||||
|
|
@ -112,9 +109,7 @@ fun WalletManagerFactory.makeWalletManagersForApp(
|
|||
.mapNotNull { this.makeWalletManagerForApp(scanResponse, it) }
|
||||
}
|
||||
|
||||
fun WalletManagerFactory.makePrimaryWalletManager(
|
||||
scanResponse: ScanResponse,
|
||||
): WalletManager? {
|
||||
fun WalletManagerFactory.makePrimaryWalletManager(scanResponse: ScanResponse): WalletManager? {
|
||||
val blockchain = if (scanResponse.card.isTestCard) {
|
||||
scanResponse.cardTypesResolver.getBlockchain().getTestnetVersion() ?: return null
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ class UserWalletIdBuilder private constructor(
|
|||
} else {
|
||||
publicKey
|
||||
}
|
||||
} else null
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return seed?.let {
|
||||
UserWalletId(value = calculateUserWalletId(it))
|
||||
|
|
@ -34,7 +36,9 @@ class UserWalletIdBuilder private constructor(
|
|||
|
||||
return if (keyHash != null) {
|
||||
message.calculateHmacSha256(keyHash)
|
||||
} else null
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -34,10 +34,7 @@ interface WalletStoreBuilder {
|
|||
return BlockchainNetworkWalletStoreBuilderImpl(userWallet, blockchainNetwork)
|
||||
}
|
||||
|
||||
operator fun invoke(
|
||||
userWallet: UserWallet,
|
||||
walletManager: WalletManager,
|
||||
): WalletMangerWalletStoreBuilder {
|
||||
operator fun invoke(userWallet: UserWallet, walletManager: WalletManager): WalletMangerWalletStoreBuilder {
|
||||
return WalletMangerWalletStoreBuilderImpl(userWallet, walletManager)
|
||||
}
|
||||
}
|
||||
|
|
@ -161,10 +158,7 @@ private fun Blockchain.toBlockchainWalletData(walletManager: WalletManager): Wal
|
|||
)
|
||||
}
|
||||
|
||||
private fun Token.toTokenWalletData(
|
||||
walletManager: WalletManager,
|
||||
primaryToken: Token?,
|
||||
): WalletDataModel {
|
||||
private fun Token.toTokenWalletData(walletManager: WalletManager, primaryToken: Token?): WalletDataModel {
|
||||
val wallet = walletManager.wallet
|
||||
return WalletDataModel(
|
||||
currency = Currency.Token(
|
||||
|
|
|
|||
|
|
@ -99,10 +99,7 @@ object ScanCardProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
private fun sendAnalytics(
|
||||
analyticsEvent: AnalyticsEvent?,
|
||||
scanResponse: ScanResponse,
|
||||
) {
|
||||
private fun sendAnalytics(analyticsEvent: AnalyticsEvent?, scanResponse: ScanResponse) {
|
||||
analyticsEvent?.let {
|
||||
// this workaround needed to send CardWasScannedEvent without adding a context
|
||||
val interceptor = CardContextInterceptor(scanResponse)
|
||||
|
|
@ -257,10 +254,7 @@ object ScanCardProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
private suspend inline fun navigateTo(
|
||||
screen: AppScreen,
|
||||
onProgressStateChange: (showProgress: Boolean) -> Unit,
|
||||
) {
|
||||
private suspend inline fun navigateTo(screen: AppScreen, onProgressStateChange: (showProgress: Boolean) -> Unit) {
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(screen))
|
||||
onProgressStateChange(false)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class CreateWalletsTask(curves: List<EllipticCurve>? = null) : CardSessionRunnab
|
|||
private fun createWallet(
|
||||
curve: EllipticCurve,
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<Card>) -> Unit
|
||||
callback: (result: CompletionResult<Card>) -> Unit,
|
||||
) {
|
||||
CreateWalletTask(curve).run(session) { result ->
|
||||
when (result) {
|
||||
|
|
|
|||
|
|
@ -23,11 +23,15 @@ class SignHashTask(
|
|||
|
||||
when (response) {
|
||||
is CompletionResult.Success -> {
|
||||
callback(CompletionResult.Success(TangemSignHashResponse(
|
||||
response.data.signature,
|
||||
response.data.totalSignedHashes,
|
||||
session.environment.card?.wallet(publicKey.seedKey)?.remainingSignatures
|
||||
)))
|
||||
callback(
|
||||
CompletionResult.Success(
|
||||
TangemSignHashResponse(
|
||||
response.data.signature,
|
||||
response.data.totalSignedHashes,
|
||||
session.environment.card?.wallet(publicKey.seedKey)?.remainingSignatures,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
is CompletionResult.Failure ->
|
||||
callback(CompletionResult.Failure(response.error))
|
||||
|
|
|
|||
|
|
@ -22,11 +22,15 @@ class SignHashesTask(
|
|||
SignHashesCommand(hashes.toTypedArray(), publicKey.seedKey, publicKey.derivationPath).run(session) { response ->
|
||||
when (response) {
|
||||
is CompletionResult.Success -> {
|
||||
callback(CompletionResult.Success(TangemSignHashesResponse(
|
||||
response.data.signatures,
|
||||
response.data.totalSignedHashes,
|
||||
session.environment.card?.wallet(publicKey.seedKey)?.remainingSignatures
|
||||
)))
|
||||
callback(
|
||||
CompletionResult.Success(
|
||||
TangemSignHashesResponse(
|
||||
response.data.signatures,
|
||||
response.data.totalSignedHashes,
|
||||
session.environment.card?.wallet(publicKey.seedKey)?.remainingSignatures,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
is CompletionResult.Failure ->
|
||||
callback(CompletionResult.Failure(response.error))
|
||||
|
|
|
|||
|
|
@ -267,10 +267,7 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWa
|
|||
}
|
||||
}
|
||||
|
||||
private fun getBlockchains(
|
||||
cardId: String,
|
||||
card: CardDTO,
|
||||
): List<Blockchain> {
|
||||
private fun getBlockchains(cardId: String, card: CardDTO): List<Blockchain> {
|
||||
return when {
|
||||
DemoHelper.isDemoCardId(cardId) -> DemoHelper.config.demoBlockchains
|
||||
card.isTestCard -> listOf(Blockchain.BitcoinTestnet, Blockchain.EthereumTestnet)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import com.tangem.operations.wallet.CreateWalletTask
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class CreateWalletsResponse(
|
||||
val createWalletResponses: List<CreateWalletResponse>
|
||||
val createWalletResponses: List<CreateWalletResponse>,
|
||||
) : CommandResponse
|
||||
|
||||
class CreateWalletsTask(
|
||||
|
|
@ -35,7 +35,7 @@ class CreateWalletsTask(
|
|||
private fun createWallet(
|
||||
curve: EllipticCurve,
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<CreateWalletsResponse>) -> Unit
|
||||
callback: (result: CompletionResult<CreateWalletsResponse>) -> Unit,
|
||||
) {
|
||||
CreateWalletTask(curve).run(session) { result ->
|
||||
when (result) {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,5 @@ import com.tangem.domain.common.CardDTO
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface ProductCommandProcessor<T> {
|
||||
fun proceed(
|
||||
card: CardDTO,
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<T>) -> Unit,
|
||||
)
|
||||
fun proceed(card: CardDTO, session: CardSession, callback: (result: CompletionResult<T>) -> Unit)
|
||||
}
|
||||
|
|
@ -14,10 +14,7 @@ class ResetToFactorySettingsTask : CardSessionRunnable<Card> {
|
|||
deleteWallets(session, callback)
|
||||
}
|
||||
|
||||
private fun deleteWallets(
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<Card>) -> Unit,
|
||||
) {
|
||||
private fun deleteWallets(session: CardSession, callback: (result: CompletionResult<Card>) -> Unit) {
|
||||
val wallet = session.environment.card?.wallets?.lastOrNull().guard {
|
||||
resetBackup(session, callback)
|
||||
return
|
||||
|
|
@ -33,10 +30,7 @@ class ResetToFactorySettingsTask : CardSessionRunnable<Card> {
|
|||
}
|
||||
}
|
||||
|
||||
private fun resetBackup(
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<Card>) -> Unit,
|
||||
) {
|
||||
private fun resetBackup(session: CardSession, callback: (result: CompletionResult<Card>) -> Unit) {
|
||||
val backupStatus = session.environment.card?.backupStatus
|
||||
if (backupStatus == null || backupStatus == Card.BackupStatus.NoBackup) {
|
||||
callback(CompletionResult.Success(session.environment.card!!))
|
||||
|
|
|
|||
|
|
@ -52,10 +52,7 @@ class ScanProductTask(
|
|||
override val allowsRequestAccessCodeFromRepository: Boolean = false,
|
||||
) : CardSessionRunnable<ScanResponse> {
|
||||
|
||||
override fun run(
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<ScanResponse>) -> Unit,
|
||||
) {
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<ScanResponse>) -> Unit) {
|
||||
val card = this.card ?: session.environment.card.guard {
|
||||
callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead()))
|
||||
return
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@ import com.tangem.common.card.FirmwareVersion
|
|||
import com.tangem.domain.common.CardDTO
|
||||
|
||||
object CurrenciesRepository {
|
||||
fun getBlockchains(
|
||||
cardFirmware: CardDTO.FirmwareVersion,
|
||||
isTestNet: Boolean = false,
|
||||
): List<Blockchain> {
|
||||
fun getBlockchains(cardFirmware: CardDTO.FirmwareVersion, isTestNet: Boolean = false): List<Blockchain> {
|
||||
val blockchains = if (cardFirmware < FirmwareVersion.MultiWalletAvailable) {
|
||||
Blockchain.secp256k1Blockchains(isTestNet)
|
||||
} else {
|
||||
|
|
@ -23,7 +20,7 @@ object CurrenciesRepository {
|
|||
removeAll(
|
||||
listOf(
|
||||
// Any blockchain
|
||||
)
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,20 +10,20 @@ data class CurrencyFromJson(
|
|||
val id: String,
|
||||
val name: String,
|
||||
val symbol: String,
|
||||
val networks: List<ContractFromJson>? = null
|
||||
val networks: List<ContractFromJson>? = null,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class ContractFromJson(
|
||||
val networkId: String,
|
||||
val contractAddress: String?,
|
||||
val decimalCount: Int?
|
||||
val decimalCount: Int?,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CurrenciesFromJson(
|
||||
val imageHost: String?,
|
||||
val coins: List<CurrencyFromJson>
|
||||
val coins: List<CurrencyFromJson>,
|
||||
)
|
||||
|
||||
fun List<ContractFromJson>.toContracts(): List<Contract> {
|
||||
|
|
@ -35,7 +35,7 @@ data class Currency(
|
|||
val name: String,
|
||||
val symbol: String,
|
||||
val iconUrl: String,
|
||||
val contracts: List<Contract>
|
||||
val contracts: List<Contract>,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
|
@ -45,7 +45,7 @@ data class Currency(
|
|||
name = currency.name,
|
||||
symbol = currency.symbol,
|
||||
iconUrl = getIconUrl(currency.id, null),
|
||||
contracts = currency.networks?.toContracts() ?: emptyList()
|
||||
contracts = currency.networks?.toContracts() ?: emptyList(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ data class Currency(
|
|||
name = currency.name,
|
||||
symbol = currency.symbol,
|
||||
iconUrl = getIconUrl(currency.id, imageHost),
|
||||
contracts = currency.networks.mapNotNull { Contract.fromNetwork(it, imageHost) }
|
||||
contracts = currency.networks.mapNotNull { Contract.fromNetwork(it, imageHost) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -77,7 +77,7 @@ data class Contract(
|
|||
blockchain = blockchain,
|
||||
address = contract.contractAddress,
|
||||
decimalCount = contract.decimalCount,
|
||||
iconUrl = getIconUrl(contract.networkId, null)
|
||||
iconUrl = getIconUrl(contract.networkId, null),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ data class Contract(
|
|||
blockchain = blockchain,
|
||||
address = contract.contractAddress,
|
||||
decimalCount = contract.decimalCount?.toInt(),
|
||||
iconUrl = getIconUrl(contract.networkId, imageHost)
|
||||
iconUrl = getIconUrl(contract.networkId, imageHost),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ object CurrencyConverter : Converter<Currency, UserTokensResponse.Token> {
|
|||
name = value.currencyName,
|
||||
symbol = value.currencySymbol,
|
||||
decimals = value.decimals,
|
||||
contractAddress = if (value is Currency.Token) value.token.contractAddress else null
|
||||
contractAddress = if (value is Currency.Token) value.token.contractAddress else null,
|
||||
)
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ data class ObsoleteTokenDao(
|
|||
contractAddress = contractAddress,
|
||||
decimalCount = decimalCount,
|
||||
blockchainDao = BlockchainDao.fromBlockchain(blockchain),
|
||||
customIconUrl = customIconUrl
|
||||
customIconUrl = customIconUrl,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ data class TokenDao(
|
|||
@Json(name = "blockchain")
|
||||
val blockchainDao: BlockchainDao,
|
||||
val customIconUrl: String? = null,
|
||||
val type: String? = null
|
||||
val type: String? = null,
|
||||
) {
|
||||
fun toToken(): Token {
|
||||
return Token(
|
||||
|
|
|
|||
|
|
@ -13,10 +13,7 @@ class CreateFirstTwinWalletTask(private val firstCardId: String) : CardSessionRu
|
|||
|
||||
override val allowsRequestAccessCodeFromRepository: Boolean = false
|
||||
|
||||
override fun run(
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit,
|
||||
) {
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> Unit) {
|
||||
val card = session.environment.card
|
||||
val publicKey = card?.wallets?.firstOrNull()?.publicKey
|
||||
if (publicKey != null) {
|
||||
|
|
|
|||
|
|
@ -16,10 +16,7 @@ class FinalizeTwinTask(
|
|||
|
||||
override val allowsRequestAccessCodeFromRepository: Boolean = false
|
||||
|
||||
override fun run(
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<ScanResponse>) -> Unit,
|
||||
) {
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<ScanResponse>) -> Unit) {
|
||||
WriteProtectedIssuerDataTask(twinPublicKey, issuerKeys).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success ->
|
||||
|
|
|
|||
|
|
@ -19,10 +19,7 @@ class WriteProtectedIssuerDataTask(
|
|||
private val issuerKeys: KeyPair,
|
||||
) : CardSessionRunnable<SuccessResponse> {
|
||||
|
||||
override fun run(
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<SuccessResponse>) -> Unit,
|
||||
) {
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<SuccessResponse>) -> Unit) {
|
||||
SignHashCommand(
|
||||
twinPublicKey.calculateSha256(),
|
||||
session.environment.card!!.wallets.first().publicKey,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,6 @@ internal class DefaultSelectedUserWalletRepository(
|
|||
}
|
||||
|
||||
private enum class StorageKey {
|
||||
SelectedWalletId
|
||||
SelectedWalletId,
|
||||
}
|
||||
}
|
||||
|
|
@ -73,9 +73,7 @@ internal class DefaultUserWalletsPublicInformationRepository(
|
|||
}
|
||||
|
||||
@JvmName("saveWithPublicInformation")
|
||||
private suspend fun save(
|
||||
publicInformation: List<UserWalletPublicInformation>,
|
||||
): CompletionResult<Unit> = catching {
|
||||
private suspend fun save(publicInformation: List<UserWalletPublicInformation>): CompletionResult<Unit> = catching {
|
||||
withContext(Dispatchers.IO) {
|
||||
publicInformation
|
||||
.let(publicInformationAdapter::toJson)
|
||||
|
|
@ -85,6 +83,6 @@ internal class DefaultUserWalletsPublicInformationRepository(
|
|||
}
|
||||
|
||||
private enum class StorageKey {
|
||||
UserWalletPublicInformation
|
||||
UserWalletPublicInformation,
|
||||
}
|
||||
}
|
||||
|
|
@ -148,10 +148,7 @@ internal class DefaultUserWalletsSensitiveInformationRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun ByteArray.getIvAndDecrypt(
|
||||
userWalletId: String,
|
||||
encryptionKey: ByteArray,
|
||||
): ByteArray? {
|
||||
private suspend fun ByteArray.getIvAndDecrypt(userWalletId: String, encryptionKey: ByteArray): ByteArray? {
|
||||
return withContext(Dispatchers.Default) {
|
||||
val iv = secureStorage.get(StorageKey.SensitiveInformationIv(userWalletId).name)
|
||||
?: error("IV not found")
|
||||
|
|
|
|||
|
|
@ -50,7 +50,9 @@ internal fun UserWallet.updateWith(sensitiveInformation: UserWalletSensitiveInfo
|
|||
internal fun List<UserWallet>.updateWith(
|
||||
walletIdToSensitiveInformation: Map<UserWalletId, UserWalletSensitiveInformation>,
|
||||
): List<UserWallet> {
|
||||
return if (walletIdToSensitiveInformation.isEmpty()) this else {
|
||||
return if (walletIdToSensitiveInformation.isEmpty()) {
|
||||
this
|
||||
} else {
|
||||
this.map { wallet ->
|
||||
walletIdToSensitiveInformation[wallet.walletId]
|
||||
?.let(wallet::updateWith)
|
||||
|
|
|
|||
|
|
@ -9,19 +9,12 @@ import com.tangem.common.extensions.ByteArrayKey
|
|||
|
||||
internal class ByteArrayKeyAdapter {
|
||||
@ToJson
|
||||
fun toJson(
|
||||
writer: JsonWriter,
|
||||
src: ByteArrayKey,
|
||||
byteArrayAdapter: JsonAdapter<ByteArray>,
|
||||
) {
|
||||
fun toJson(writer: JsonWriter, src: ByteArrayKey, byteArrayAdapter: JsonAdapter<ByteArray>) {
|
||||
byteArrayAdapter.toJson(writer, src.bytes)
|
||||
}
|
||||
|
||||
@FromJson
|
||||
fun fromJson(
|
||||
reader: JsonReader,
|
||||
byteArrayAdapter: JsonAdapter<ByteArray>,
|
||||
): ByteArrayKey? {
|
||||
fun fromJson(reader: JsonReader, byteArrayAdapter: JsonAdapter<ByteArray>): ByteArrayKey? {
|
||||
return byteArrayAdapter.fromJson(reader)?.let {
|
||||
ByteArrayKey(bytes = it)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,7 @@ import com.tangem.domain.common.CardDTO
|
|||
|
||||
internal class CardBackupStatusAdapter {
|
||||
@ToJson
|
||||
fun toJson(
|
||||
writer: JsonWriter,
|
||||
src: CardDTO.BackupStatus?,
|
||||
mapAdapter: JsonAdapter<Map<String, String>>,
|
||||
) {
|
||||
fun toJson(writer: JsonWriter, src: CardDTO.BackupStatus?, mapAdapter: JsonAdapter<Map<String, String>>) {
|
||||
val jsonMap = mutableMapOf<String, String>()
|
||||
|
||||
when (src) {
|
||||
|
|
@ -37,10 +33,7 @@ internal class CardBackupStatusAdapter {
|
|||
}
|
||||
|
||||
@FromJson
|
||||
fun fromJson(
|
||||
reader: JsonReader,
|
||||
mapAdapter: JsonAdapter<Map<String, String>>,
|
||||
): CardDTO.BackupStatus? {
|
||||
fun fromJson(reader: JsonReader, mapAdapter: JsonAdapter<Map<String, String>>): CardDTO.BackupStatus? {
|
||||
val map = mapAdapter.fromJson(reader) ?: return null
|
||||
|
||||
return when (map["status"]) {
|
||||
|
|
|
|||
|
|
@ -16,10 +16,7 @@ interface WalletCurrenciesManager {
|
|||
*
|
||||
* @return [CompletionResult] of operation
|
||||
* */
|
||||
suspend fun update(
|
||||
userWallet: UserWallet,
|
||||
currency: Currency,
|
||||
): CompletionResult<Unit>
|
||||
suspend fun update(userWallet: UserWallet, currency: Currency): CompletionResult<Unit>
|
||||
|
||||
/**
|
||||
* Add list of [Currency] to [UserWallet].
|
||||
|
|
@ -32,10 +29,7 @@ interface WalletCurrenciesManager {
|
|||
*
|
||||
* @return [CompletionResult] of operation
|
||||
* */
|
||||
suspend fun addCurrencies(
|
||||
userWallet: UserWallet,
|
||||
currenciesToAdd: List<Currency>,
|
||||
): CompletionResult<Unit>
|
||||
suspend fun addCurrencies(userWallet: UserWallet, currenciesToAdd: List<Currency>): CompletionResult<Unit>
|
||||
|
||||
/**
|
||||
* Remove [Currency] from [UserWallet]
|
||||
|
|
@ -48,10 +42,7 @@ interface WalletCurrenciesManager {
|
|||
*
|
||||
* @return [CompletionResult] of operation
|
||||
* */
|
||||
suspend fun removeCurrency(
|
||||
userWallet: UserWallet,
|
||||
currencyToRemove: Currency,
|
||||
): CompletionResult<Unit>
|
||||
suspend fun removeCurrency(userWallet: UserWallet, currencyToRemove: Currency): CompletionResult<Unit>
|
||||
|
||||
/**
|
||||
* Remove list of [Currency] from [UserWallet]
|
||||
|
|
@ -64,10 +55,7 @@ interface WalletCurrenciesManager {
|
|||
*
|
||||
* @return [CompletionResult] of operation
|
||||
* */
|
||||
suspend fun removeCurrencies(
|
||||
userWallet: UserWallet,
|
||||
currenciesToRemove: List<Currency>,
|
||||
): CompletionResult<Unit>
|
||||
suspend fun removeCurrencies(userWallet: UserWallet, currenciesToRemove: List<Currency>): CompletionResult<Unit>
|
||||
|
||||
/**
|
||||
* Add a callback [Listener]
|
||||
|
|
|
|||
|
|
@ -33,29 +33,27 @@ internal class DefaultWalletCurrenciesManager(
|
|||
|
||||
private val listeners = mutableListOf<WalletCurrenciesManager.Listener>()
|
||||
|
||||
override suspend fun update(
|
||||
userWallet: UserWallet,
|
||||
currency: Currency,
|
||||
): CompletionResult<Unit> = withContext(Dispatchers.Default) {
|
||||
listeners.forEach { it.willUpdate(userWallet, currency) }
|
||||
val walletStore = walletStoresRepository.getSync(userWallet.walletId)
|
||||
.find {
|
||||
it.blockchain == currency.blockchain &&
|
||||
it.derivationPath?.rawPath == currency.derivationPath
|
||||
}
|
||||
override suspend fun update(userWallet: UserWallet, currency: Currency): CompletionResult<Unit> =
|
||||
withContext(Dispatchers.Default) {
|
||||
listeners.forEach { it.willUpdate(userWallet, currency) }
|
||||
val walletStore = walletStoresRepository.getSync(userWallet.walletId)
|
||||
.find {
|
||||
it.blockchain == currency.blockchain &&
|
||||
it.derivationPath?.rawPath == currency.derivationPath
|
||||
}
|
||||
|
||||
val updateResult = if (walletStore == null) {
|
||||
CompletionResult.Success(Unit)
|
||||
} else {
|
||||
walletAmountsRepository.updateAmountsForWalletStore(
|
||||
walletStore = walletStore,
|
||||
userWallet = userWallet,
|
||||
fiatCurrency = appCurrencyProvider(),
|
||||
)
|
||||
val updateResult = if (walletStore == null) {
|
||||
CompletionResult.Success(Unit)
|
||||
} else {
|
||||
walletAmountsRepository.updateAmountsForWalletStore(
|
||||
walletStore = walletStore,
|
||||
userWallet = userWallet,
|
||||
fiatCurrency = appCurrencyProvider(),
|
||||
)
|
||||
}
|
||||
listeners.forEach { it.didUpdate(userWallet, currency) }
|
||||
updateResult
|
||||
}
|
||||
listeners.forEach { it.didUpdate(userWallet, currency) }
|
||||
updateResult
|
||||
}
|
||||
|
||||
override suspend fun addCurrencies(
|
||||
userWallet: UserWallet,
|
||||
|
|
@ -110,10 +108,7 @@ internal class DefaultWalletCurrenciesManager(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun removeCurrency(
|
||||
userWallet: UserWallet,
|
||||
currencyToRemove: Currency,
|
||||
): CompletionResult<Unit> {
|
||||
override suspend fun removeCurrency(userWallet: UserWallet, currencyToRemove: Currency): CompletionResult<Unit> {
|
||||
listeners.forEach { it.willCurrencyRemove(userWallet, currencyToRemove) }
|
||||
return removeCurrencies(userWallet, listOf(currencyToRemove))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,10 +49,7 @@ interface WalletStoresManager {
|
|||
*
|
||||
* @return [CompletionResult] of operation
|
||||
* */
|
||||
suspend fun fetch(
|
||||
userWallet: UserWallet,
|
||||
refresh: Boolean = false,
|
||||
): CompletionResult<Unit>
|
||||
suspend fun fetch(userWallet: UserWallet, refresh: Boolean = false): CompletionResult<Unit>
|
||||
|
||||
/**
|
||||
* Fetch wallet stores associated with provided [UserWallet]s. Fetched [WalletStoreModel]s updates can be observed
|
||||
|
|
@ -63,10 +60,7 @@ interface WalletStoresManager {
|
|||
*
|
||||
* @return [CompletionResult] of operation
|
||||
* */
|
||||
suspend fun fetch(
|
||||
userWallets: List<UserWallet>,
|
||||
refresh: Boolean = false,
|
||||
): CompletionResult<Unit>
|
||||
suspend fun fetch(userWallets: List<UserWallet>, refresh: Boolean = false): CompletionResult<Unit>
|
||||
|
||||
/**
|
||||
* Update [WalletStoreModel]s amounts associated with provided [UserWallet]s
|
||||
|
|
@ -75,9 +69,7 @@ interface WalletStoresManager {
|
|||
*
|
||||
* @return [CompletionResult] of operation
|
||||
* */
|
||||
suspend fun updateAmounts(
|
||||
userWallets: List<UserWallet>,
|
||||
): CompletionResult<Unit>
|
||||
suspend fun updateAmounts(userWallets: List<UserWallet>): CompletionResult<Unit>
|
||||
|
||||
// For provider
|
||||
companion object
|
||||
|
|
|
|||
|
|
@ -58,38 +58,35 @@ internal class DefaultWalletStoresManager(
|
|||
return walletStoresRepository.clear()
|
||||
}
|
||||
|
||||
override suspend fun fetch(
|
||||
userWallets: List<UserWallet>,
|
||||
refresh: Boolean,
|
||||
): CompletionResult<Unit> = withContext(Dispatchers.Default) {
|
||||
val fiatCurrency = appCurrencyProvider.invoke()
|
||||
val isFiatCurrencyChanged = state.value.fiatCurrency != fiatCurrency
|
||||
override suspend fun fetch(userWallets: List<UserWallet>, refresh: Boolean): CompletionResult<Unit> =
|
||||
withContext(Dispatchers.Default) {
|
||||
val fiatCurrency = appCurrencyProvider.invoke()
|
||||
val isFiatCurrencyChanged = state.value.fiatCurrency != fiatCurrency
|
||||
|
||||
state.update { prevState ->
|
||||
prevState.copy(
|
||||
fiatCurrency = fiatCurrency,
|
||||
)
|
||||
state.update { prevState ->
|
||||
prevState.copy(
|
||||
fiatCurrency = fiatCurrency,
|
||||
)
|
||||
}
|
||||
|
||||
userWallets
|
||||
.mapNotNull { userWallet ->
|
||||
val hasNotWalletStoresForUserWallet = !walletStoresRepository.contains(userWallet.walletId)
|
||||
if (refresh || hasNotWalletStoresForUserWallet || isFiatCurrencyChanged) {
|
||||
fetchWalletsIfNeeded(userWallet)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
.fold(arrayListOf<UserWallet>()) { acc, data ->
|
||||
acc.apply { add(data) }
|
||||
}
|
||||
.flatMap {
|
||||
walletAmountsRepository.updateAmountsForUserWallets(it, fiatCurrency)
|
||||
}
|
||||
}
|
||||
|
||||
userWallets
|
||||
.mapNotNull { userWallet ->
|
||||
val hasNotWalletStoresForUserWallet = !walletStoresRepository.contains(userWallet.walletId)
|
||||
if (refresh || hasNotWalletStoresForUserWallet || isFiatCurrencyChanged) {
|
||||
fetchWalletsIfNeeded(userWallet)
|
||||
} else null
|
||||
}
|
||||
.fold(arrayListOf<UserWallet>()) { acc, data ->
|
||||
acc.apply { add(data) }
|
||||
}
|
||||
.flatMap {
|
||||
walletAmountsRepository.updateAmountsForUserWallets(it, fiatCurrency)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun fetch(
|
||||
userWallet: UserWallet,
|
||||
refresh: Boolean,
|
||||
): CompletionResult<Unit> {
|
||||
override suspend fun fetch(userWallet: UserWallet, refresh: Boolean): CompletionResult<Unit> {
|
||||
return fetch(listOf(userWallet), refresh)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,10 +24,7 @@ interface WalletAmountsRepository {
|
|||
* @param userWallet [UserWallet] which will be used to get the list of associated [WalletStoreModel]
|
||||
* @param fiatCurrency current app [FiatCurrency]
|
||||
* */
|
||||
suspend fun updateAmountsForUserWallet(
|
||||
userWallet: UserWallet,
|
||||
fiatCurrency: FiatCurrency,
|
||||
): CompletionResult<Unit>
|
||||
suspend fun updateAmountsForUserWallet(userWallet: UserWallet, fiatCurrency: FiatCurrency): CompletionResult<Unit>
|
||||
|
||||
suspend fun updateAmountsForWalletStores(
|
||||
walletStores: List<WalletStoreModel>,
|
||||
|
|
|
|||
|
|
@ -17,10 +17,7 @@ interface WalletManagersRepository {
|
|||
|
||||
suspend fun delete(userWalletIds: List<UserWalletId>): CompletionResult<Unit>
|
||||
|
||||
suspend fun delete(
|
||||
userWalletId: UserWalletId,
|
||||
blockchain: Blockchain,
|
||||
): CompletionResult<Unit>
|
||||
suspend fun delete(userWalletId: UserWalletId, blockchain: Blockchain): CompletionResult<Unit>
|
||||
|
||||
companion object
|
||||
}
|
||||
|
|
@ -22,10 +22,7 @@ interface WalletStoresRepository {
|
|||
|
||||
suspend fun clear(): CompletionResult<Unit>
|
||||
|
||||
suspend fun storeOrUpdate(
|
||||
userWalletId: UserWalletId,
|
||||
walletStore: WalletStoreModel,
|
||||
): CompletionResult<Unit>
|
||||
suspend fun storeOrUpdate(userWalletId: UserWalletId, walletStore: WalletStoreModel): CompletionResult<Unit>
|
||||
|
||||
companion object
|
||||
}
|
||||
|
|
@ -160,21 +160,19 @@ internal class DefaultWalletAmountsRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchAmountsForUserWallets(
|
||||
userWallets: List<UserWallet>,
|
||||
): CompletionResult<Unit> = withContext(Dispatchers.Default) {
|
||||
userWallets.map { async { fetchAmountsForUserWallet(it) } }.awaitAll().fold()
|
||||
}
|
||||
private suspend fun fetchAmountsForUserWallets(userWallets: List<UserWallet>): CompletionResult<Unit> =
|
||||
withContext(Dispatchers.Default) {
|
||||
userWallets.map { async { fetchAmountsForUserWallet(it) } }.awaitAll().fold()
|
||||
}
|
||||
|
||||
private suspend fun fetchAmountsForUserWallet(
|
||||
userWallet: UserWallet,
|
||||
): CompletionResult<Unit> = withContext(Dispatchers.Default) {
|
||||
val userWalletId = userWallet.walletId
|
||||
val scanResponse = userWallet.scanResponse
|
||||
val walletStores = getWalletStores(listOf(userWallet))
|
||||
private suspend fun fetchAmountsForUserWallet(userWallet: UserWallet): CompletionResult<Unit> =
|
||||
withContext(Dispatchers.Default) {
|
||||
val userWalletId = userWallet.walletId
|
||||
val scanResponse = userWallet.scanResponse
|
||||
val walletStores = getWalletStores(listOf(userWallet))
|
||||
|
||||
fetchAmountForWalletStores(userWalletId, scanResponse, walletStores)
|
||||
}
|
||||
fetchAmountForWalletStores(userWalletId, scanResponse, walletStores)
|
||||
}
|
||||
|
||||
private suspend fun fetchAmountForWalletStores(
|
||||
userWalletId: UserWalletId,
|
||||
|
|
@ -286,7 +284,9 @@ internal class DefaultWalletAmountsRepository(
|
|||
rent = rentProvider.rentAmount(),
|
||||
exemptionAmount = rentExempt,
|
||||
)
|
||||
} else null,
|
||||
} else {
|
||||
null
|
||||
},
|
||||
)
|
||||
}
|
||||
is Failure -> Unit
|
||||
|
|
@ -295,39 +295,36 @@ internal class DefaultWalletAmountsRepository(
|
|||
return CompletionResult.Success(Unit)
|
||||
}
|
||||
|
||||
private suspend fun updateWalletStoreWithError(
|
||||
walletStore: WalletStoreModel,
|
||||
wallet: Wallet,
|
||||
error: TangemError,
|
||||
) = withContext(Dispatchers.Default) {
|
||||
Timber.e(
|
||||
error,
|
||||
"""
|
||||
private suspend fun updateWalletStoreWithError(walletStore: WalletStoreModel, wallet: Wallet, error: TangemError) =
|
||||
withContext(Dispatchers.Default) {
|
||||
Timber.e(
|
||||
error,
|
||||
"""
|
||||
Unable to fetch amounts
|
||||
|- User wallet id: ${walletStore.userWalletId}
|
||||
|- Blockchain: ${walletStore.blockchain}
|
||||
|- Derivation path: ${walletStore.derivationPath?.rawPath}
|
||||
""".trimIndent(),
|
||||
)
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
if (error is BlockchainSdkError) {
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
it.updateWithError(
|
||||
wallet = wallet,
|
||||
error = error,
|
||||
)
|
||||
},
|
||||
)
|
||||
if (error is BlockchainSdkError) {
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
it.updateWithError(
|
||||
wallet = wallet,
|
||||
error = error,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
CompletionResult.Success(Unit)
|
||||
} else {
|
||||
CompletionResult.Failure(error)
|
||||
}
|
||||
|
||||
CompletionResult.Success(Unit)
|
||||
} else {
|
||||
CompletionResult.Failure(error)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateWalletStoreWithAmounts(
|
||||
walletStore: WalletStoreModel,
|
||||
|
|
@ -359,53 +356,51 @@ internal class DefaultWalletAmountsRepository(
|
|||
CompletionResult.Success(Unit)
|
||||
}
|
||||
|
||||
private suspend fun updateWalletStoreWithMissedDerivation(
|
||||
walletStore: WalletStoreModel,
|
||||
) = withContext(Dispatchers.Default) {
|
||||
Timber.e(
|
||||
"""
|
||||
private suspend fun updateWalletStoreWithMissedDerivation(walletStore: WalletStoreModel) =
|
||||
withContext(Dispatchers.Default) {
|
||||
Timber.e(
|
||||
"""
|
||||
Missed derivation
|
||||
|- User wallet id: ${walletStore.userWalletId}
|
||||
|- Blockchain: ${walletStore.blockchain}
|
||||
|- Derivation path: ${walletStore.derivationPath?.rawPath}
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
it.updateWithMissedDerivation()
|
||||
},
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
it.updateWithMissedDerivation()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
CompletionResult.Success(Unit)
|
||||
}
|
||||
|
||||
CompletionResult.Success(Unit)
|
||||
}
|
||||
|
||||
private suspend fun updateWalletStoreWithUnreachable(
|
||||
walletStore: WalletStoreModel,
|
||||
) = withContext(Dispatchers.Default) {
|
||||
Timber.e(
|
||||
"""
|
||||
private suspend fun updateWalletStoreWithUnreachable(walletStore: WalletStoreModel) =
|
||||
withContext(Dispatchers.Default) {
|
||||
Timber.e(
|
||||
"""
|
||||
Wallet manager is null
|
||||
|- User wallet id: ${walletStore.userWalletId}
|
||||
|- Blockchain: ${walletStore.blockchain}
|
||||
|- Derivation path: ${walletStore.derivationPath?.rawPath}
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
it.updateWithUnreachable()
|
||||
},
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
|
||||
CompletionResult.Success(Unit)
|
||||
}
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
it.updateWithUnreachable()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
CompletionResult.Success(Unit)
|
||||
}
|
||||
|
||||
private suspend fun updateWalletStoresWithFiatRates(
|
||||
walletStores: List<WalletStoreModel>,
|
||||
|
|
@ -428,48 +423,44 @@ internal class DefaultWalletAmountsRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun updateWalletStoreWithRent(
|
||||
walletStore: WalletStoreModel,
|
||||
rent: WalletStoreModel.WalletRent?,
|
||||
) = withContext(Dispatchers.Default) {
|
||||
Timber.d(
|
||||
"""
|
||||
private suspend fun updateWalletStoreWithRent(walletStore: WalletStoreModel, rent: WalletStoreModel.WalletRent?) =
|
||||
withContext(Dispatchers.Default) {
|
||||
Timber.d(
|
||||
"""
|
||||
Fetched wallet rent
|
||||
|- User wallet id: ${walletStore.userWalletId}
|
||||
|- Blockchain: ${walletStore.blockchain}
|
||||
|- Derivation path: ${walletStore.derivationPath?.rawPath}
|
||||
|- Rent: $rent
|
||||
""".trimIndent(),
|
||||
)
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
if (rent != walletStore.walletRent) {
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
it.updateWithRent(rent)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateWalletManagerInStorage(
|
||||
userWalletId: UserWalletId,
|
||||
walletManager: WalletManager,
|
||||
) = withContext(Dispatchers.Default) {
|
||||
WalletManagerStorage.update { prevManagers ->
|
||||
val newManagersForUserWallet = prevManagers[userWalletId].orEmpty().toMutableList().apply {
|
||||
replaceByOrAdd(walletManager) {
|
||||
it.wallet.blockchain == walletManager.wallet.blockchain
|
||||
if (rent != walletStore.walletRent) {
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
it.updateWithRent(rent)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prevManagers.apply {
|
||||
set(userWalletId, newManagersForUserWallet)
|
||||
private suspend fun updateWalletManagerInStorage(userWalletId: UserWalletId, walletManager: WalletManager) =
|
||||
withContext(Dispatchers.Default) {
|
||||
WalletManagerStorage.update { prevManagers ->
|
||||
val newManagersForUserWallet = prevManagers[userWalletId].orEmpty().toMutableList().apply {
|
||||
replaceByOrAdd(walletManager) {
|
||||
it.wallet.blockchain == walletManager.wallet.blockchain
|
||||
}
|
||||
}
|
||||
|
||||
prevManagers.apply {
|
||||
set(userWalletId, newManagersForUserWallet)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getWalletStores(userWallets: List<UserWallet>): List<WalletStoreModel> {
|
||||
return userWallets.map { it.walletId }.flatMap { userWalletId ->
|
||||
|
|
|
|||
|
|
@ -125,10 +125,7 @@ internal class DefaultWalletManagersRepository(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun delete(
|
||||
userWalletId: UserWalletId,
|
||||
blockchain: Blockchain,
|
||||
): CompletionResult<Unit> = catching {
|
||||
override suspend fun delete(userWalletId: UserWalletId, blockchain: Blockchain): CompletionResult<Unit> = catching {
|
||||
deleteInternal(userWalletId, blockchain)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,17 +14,13 @@ import com.tangem.tap.features.wallet.models.Currency
|
|||
import com.tangem.tap.features.wallet.models.getPendingTransactions
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal fun WalletDataModel.updateWithFiatRate(
|
||||
fiatRate: BigDecimal?,
|
||||
): WalletDataModel {
|
||||
internal fun WalletDataModel.updateWithFiatRate(fiatRate: BigDecimal?): WalletDataModel {
|
||||
return this.copy(
|
||||
fiatRate = fiatRate,
|
||||
)
|
||||
}
|
||||
|
||||
internal fun List<WalletDataModel>.updateWithFiatRates(
|
||||
fiatRates: Map<String, Double>,
|
||||
): List<WalletDataModel> {
|
||||
internal fun List<WalletDataModel>.updateWithFiatRates(fiatRates: Map<String, Double>): List<WalletDataModel> {
|
||||
return this.map { walletData ->
|
||||
val rate = fiatRates[walletData.currency.coinId]?.toBigDecimal()
|
||||
walletData.updateWithFiatRate(rate)
|
||||
|
|
@ -40,9 +36,7 @@ internal fun WalletDataModel.updateWithTxHistory(wallet: Wallet): WalletDataMode
|
|||
)
|
||||
}
|
||||
|
||||
internal fun List<WalletDataModel>.updateWithTxHistories(
|
||||
wallet: Wallet,
|
||||
): List<WalletDataModel> {
|
||||
internal fun List<WalletDataModel>.updateWithTxHistories(wallet: Wallet): List<WalletDataModel> {
|
||||
return this.map { walletData ->
|
||||
walletData.updateWithTxHistory(wallet)
|
||||
}
|
||||
|
|
@ -114,10 +108,7 @@ internal fun List<WalletDataModel>.updateWithDemoAmounts(wallet: Wallet): List<W
|
|||
}
|
||||
}
|
||||
|
||||
internal fun WalletDataModel.updateWithError(
|
||||
wallet: Wallet,
|
||||
error: TangemError,
|
||||
): WalletDataModel {
|
||||
internal fun WalletDataModel.updateWithError(wallet: Wallet, error: TangemError): WalletDataModel {
|
||||
return this.copy(
|
||||
status = when (error) {
|
||||
is BlockchainSdkError.AccountNotFound -> {
|
||||
|
|
@ -141,18 +132,13 @@ internal fun WalletDataModel.updateWithError(
|
|||
)
|
||||
}
|
||||
|
||||
internal fun List<WalletDataModel>.updateWithError(
|
||||
wallet: Wallet,
|
||||
error: TangemError,
|
||||
): List<WalletDataModel> {
|
||||
internal fun List<WalletDataModel>.updateWithError(wallet: Wallet, error: TangemError): List<WalletDataModel> {
|
||||
return this.map { walletData ->
|
||||
walletData.updateWithError(wallet, error)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun WalletDataModel.updateWithSelf(
|
||||
newWalletData: WalletDataModel,
|
||||
): WalletDataModel {
|
||||
internal fun WalletDataModel.updateWithSelf(newWalletData: WalletDataModel): WalletDataModel {
|
||||
val oldWalletData = this
|
||||
val oldStatus = oldWalletData.status
|
||||
return oldWalletData.copy(
|
||||
|
|
@ -191,9 +177,7 @@ internal fun List<WalletDataModel>.updateWithUnreachable(): List<WalletDataModel
|
|||
}
|
||||
}
|
||||
|
||||
internal fun List<WalletDataModel>.updateWithSelf(
|
||||
newWalletsData: List<WalletDataModel>,
|
||||
): List<WalletDataModel> {
|
||||
internal fun List<WalletDataModel>.updateWithSelf(newWalletsData: List<WalletDataModel>): List<WalletDataModel> {
|
||||
val oldWalletsData = this
|
||||
val updatedWalletsData = arrayListOf<WalletDataModel>()
|
||||
|
||||
|
|
|
|||
|
|
@ -29,10 +29,7 @@ internal inline fun HashMap<UserWalletId, List<WalletStoreModel>>.replaceWalletS
|
|||
}
|
||||
}
|
||||
|
||||
internal fun WalletStoreModel.updateWithError(
|
||||
wallet: Wallet,
|
||||
error: TangemError,
|
||||
): WalletStoreModel {
|
||||
internal fun WalletStoreModel.updateWithError(wallet: Wallet, error: TangemError): WalletStoreModel {
|
||||
return this.copy(
|
||||
walletsData = walletsData.updateWithError(
|
||||
wallet = wallet,
|
||||
|
|
@ -41,41 +38,31 @@ internal fun WalletStoreModel.updateWithError(
|
|||
)
|
||||
}
|
||||
|
||||
internal fun WalletStoreModel.updateWithTxHistories(
|
||||
wallet: Wallet,
|
||||
): WalletStoreModel {
|
||||
internal fun WalletStoreModel.updateWithTxHistories(wallet: Wallet): WalletStoreModel {
|
||||
return this.copy(
|
||||
walletsData = walletsData.updateWithTxHistories(wallet = wallet),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun WalletStoreModel.updateWithAmounts(
|
||||
wallet: Wallet,
|
||||
): WalletStoreModel {
|
||||
internal fun WalletStoreModel.updateWithAmounts(wallet: Wallet): WalletStoreModel {
|
||||
return this.copy(
|
||||
walletsData = walletsData.updateWithAmounts(wallet = wallet),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun WalletStoreModel.updateWithDemoAmounts(
|
||||
wallet: Wallet,
|
||||
): WalletStoreModel {
|
||||
internal fun WalletStoreModel.updateWithDemoAmounts(wallet: Wallet): WalletStoreModel {
|
||||
return this.copy(
|
||||
walletsData = walletsData.updateWithDemoAmounts(wallet = wallet),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun WalletStoreModel.updateWithFiatRates(
|
||||
rates: Map<String, Double>,
|
||||
): WalletStoreModel {
|
||||
internal fun WalletStoreModel.updateWithFiatRates(rates: Map<String, Double>): WalletStoreModel {
|
||||
return this.copy(
|
||||
walletsData = walletsData.updateWithFiatRates(rates),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun WalletStoreModel.updateWithSelf(
|
||||
newWalletStore: WalletStoreModel,
|
||||
): WalletStoreModel {
|
||||
internal fun WalletStoreModel.updateWithSelf(newWalletStore: WalletStoreModel): WalletStoreModel {
|
||||
val oldStore = this
|
||||
return oldStore.copy(
|
||||
derivationPath = newWalletStore.derivationPath,
|
||||
|
|
|
|||
|
|
@ -287,11 +287,7 @@ class WalletConnectManager {
|
|||
}
|
||||
}
|
||||
|
||||
fun signBnb(
|
||||
id: Long,
|
||||
data: ByteArray,
|
||||
sessionData: WCSession,
|
||||
) {
|
||||
fun signBnb(id: Long, data: ByteArray, sessionData: WCSession) {
|
||||
val activeData = sessions[sessionData] ?: return
|
||||
scope.launch {
|
||||
val hash = WalletConnectSdkHelper().signBnbTransaction(data, activeData, cardId).guard {
|
||||
|
|
@ -307,11 +303,7 @@ class WalletConnectManager {
|
|||
}
|
||||
}
|
||||
|
||||
fun handlePersonalSignRequest(
|
||||
message: WCEthereumSignMessage,
|
||||
session: WalletConnectSession,
|
||||
id: Long,
|
||||
) {
|
||||
fun handlePersonalSignRequest(message: WCEthereumSignMessage, session: WalletConnectSession, id: Long) {
|
||||
val activeData = sessions[session.session] ?: return
|
||||
scope.launch {
|
||||
val data = WalletConnectSdkHelper().prepareDataForPersonalSign(
|
||||
|
|
|
|||
|
|
@ -71,10 +71,13 @@ interface FragmentOnBackPressedHandler {
|
|||
|
||||
@SuppressLint("FragmentBackPressedCallback")
|
||||
fun Fragment.addBackPressHandler(handler: FragmentOnBackPressedHandler) {
|
||||
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
handler.handleOnBackPressed()
|
||||
}
|
||||
})
|
||||
activity?.onBackPressedDispatcher?.addCallback(
|
||||
this,
|
||||
object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
handler.handleOnBackPressed()
|
||||
}
|
||||
},
|
||||
)
|
||||
view?.findViewById<Toolbar>(R.id.toolbar)?.setNavigationOnClickListener { activity?.onBackPressed() }
|
||||
}
|
||||
|
|
@ -275,10 +275,7 @@ class DetailsMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun toggleSaveWallets(
|
||||
scanResponse: ScanResponse?,
|
||||
enable: Boolean,
|
||||
): CompletionResult<Unit> {
|
||||
private suspend fun toggleSaveWallets(scanResponse: ScanResponse?, enable: Boolean): CompletionResult<Unit> {
|
||||
return if (enable) {
|
||||
saveCurrentWallet(scanResponse, enableAccessCodesSaving = false)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -44,9 +44,7 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
|
|||
}
|
||||
}
|
||||
|
||||
private fun handlePrepareScreen(
|
||||
action: DetailsAction.PrepareScreen,
|
||||
): DetailsState {
|
||||
private fun handlePrepareScreen(action: DetailsAction.PrepareScreen): DetailsState {
|
||||
return DetailsState(
|
||||
scanResponse = action.scanResponse,
|
||||
wallets = action.wallets,
|
||||
|
|
@ -64,8 +62,7 @@ private fun handlePrepareCardSettingsScreen(
|
|||
card: CardDTO,
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
state: DetailsState,
|
||||
):
|
||||
DetailsState {
|
||||
): DetailsState {
|
||||
val cardSettingsState = CardSettingsState(
|
||||
cardInfo = card.toCardInfo(cardTypesResolver),
|
||||
manageSecurityState = prepareSecurityOptions(card, cardTypesResolver),
|
||||
|
|
@ -112,10 +109,7 @@ private fun isResetToFactoryAllowedByCard(card: CardDTO, cardTypesResolver: Card
|
|||
return !isNotAllowed
|
||||
}
|
||||
|
||||
private fun handleEraseWallet(
|
||||
action: DetailsAction.ResetToFactory,
|
||||
state: DetailsState,
|
||||
): DetailsState {
|
||||
private fun handleEraseWallet(action: DetailsAction.ResetToFactory, state: DetailsState): DetailsState {
|
||||
return when (action) {
|
||||
is DetailsAction.ResetToFactory.Confirm ->
|
||||
state.copy(cardSettingsState = state.cardSettingsState?.copy(resetConfirmed = action.confirmed))
|
||||
|
|
@ -123,10 +117,7 @@ private fun handleEraseWallet(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleSecurityAction(
|
||||
action: DetailsAction.ManageSecurity,
|
||||
state: DetailsState,
|
||||
): DetailsState {
|
||||
private fun handleSecurityAction(action: DetailsAction.ManageSecurity, state: DetailsState): DetailsState {
|
||||
return when (action) {
|
||||
is DetailsAction.ManageSecurity.SelectOption -> {
|
||||
val manageSecurityState = state.cardSettingsState?.manageSecurityState?.copy(
|
||||
|
|
@ -155,10 +146,7 @@ private fun handleSecurityAction(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handlePrivacyAction(
|
||||
action: DetailsAction.AppSettings,
|
||||
state: DetailsState,
|
||||
): DetailsState {
|
||||
private fun handlePrivacyAction(action: DetailsAction.AppSettings, state: DetailsState): DetailsState {
|
||||
return when (action) {
|
||||
is DetailsAction.AppSettings.SwitchPrivacySetting -> state.copy(
|
||||
appSettingsState = when (action.setting) {
|
||||
|
|
|
|||
|
|
@ -285,11 +285,7 @@ class WalletConnectMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleScanResponse(
|
||||
scanResponse: ScanResponse,
|
||||
session: WalletConnectSession,
|
||||
blockchain: Blockchain,
|
||||
) {
|
||||
private fun handleScanResponse(scanResponse: ScanResponse, session: WalletConnectSession, blockchain: Blockchain) {
|
||||
val card = scanResponse.card
|
||||
if (!scanResponse.cardTypesResolver.isMultiwalletAllowed()) {
|
||||
store.dispatchOnMain(WalletConnectAction.UnsupportedCard)
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@ package com.tangem.tap.features.details.redux.walletconnect
|
|||
import org.rekotlin.Action
|
||||
|
||||
object WalletConnectReducer {
|
||||
fun reduce(
|
||||
action: Action,
|
||||
state: WalletConnectState,
|
||||
): WalletConnectState {
|
||||
fun reduce(action: Action, state: WalletConnectState): WalletConnectState {
|
||||
if (action !is WalletConnectAction) return state
|
||||
|
||||
return when (action) {
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ data class WcTransactionData(
|
|||
|
||||
enum class WcTransactionType {
|
||||
EthSignTransaction,
|
||||
EthSendTransaction
|
||||
EthSendTransaction,
|
||||
}
|
||||
|
||||
data class WcPersonalSignData(
|
||||
|
|
@ -156,5 +156,5 @@ data class TradeData(
|
|||
val price: String,
|
||||
val quantity: String,
|
||||
val amount: String,
|
||||
val symbol: String
|
||||
val symbol: String,
|
||||
)
|
||||
|
|
@ -30,11 +30,7 @@ class AppSettingsFragment : Fragment(), StoreSubscriber<DetailsState> {
|
|||
viewModel.checkBiometricsStatus()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
isTransitionGroup = true
|
||||
|
|
|
|||
|
|
@ -159,9 +159,7 @@ private fun onCheckedChange(
|
|||
|
||||
// region Preview
|
||||
@Composable
|
||||
private fun AppSettingsScreenSample(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun AppSettingsScreenSample(modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors.background.primary),
|
||||
|
|
@ -199,9 +197,7 @@ private fun AppSettingsScreenPreview_Dark() {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun AppSettingsScreen_EnrollBiometrics_Sample(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun AppSettingsScreen_EnrollBiometrics_Sample(modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier.background(TangemTheme.colors.background.primary)) {
|
||||
AppSettingsScreen(
|
||||
state = AppSettingsScreenState(
|
||||
|
|
|
|||
|
|
@ -63,9 +63,7 @@ internal fun EnrollBiometricsCard(onClick: () -> Unit) {
|
|||
|
||||
// region Preview
|
||||
@Composable
|
||||
private fun EnrollBiometricsCardSample(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun EnrollBiometricsCardSample(modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier.background(TangemTheme.colors.background.secondary),
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -66,9 +66,7 @@ internal fun SettingsAlertDialog(
|
|||
|
||||
// region Preview
|
||||
@Composable
|
||||
private fun SettingsAlertDialogSample(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun SettingsAlertDialogSample(modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors.background.primary),
|
||||
|
|
|
|||
|
|
@ -31,11 +31,7 @@ class CardSettingsFragment : Fragment(), StoreSubscriber<DetailsState> {
|
|||
exitTransition = inflater.inflateTransition(android.R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
isTransitionGroup = true
|
||||
|
|
|
|||
|
|
@ -76,10 +76,7 @@ fun SettingsScreensScaffold(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun ScreenTitle(
|
||||
titleRes: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
fun ScreenTitle(titleRes: Int, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = stringResource(id = titleRes),
|
||||
modifier = modifier.padding(start = 20.dp, end = 20.dp),
|
||||
|
|
@ -111,12 +108,7 @@ fun EmptyTopBarWithNavigation(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun DetailsMainButton(
|
||||
title: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
) {
|
||||
fun DetailsMainButton(title: String, onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true) {
|
||||
Button(
|
||||
onClick = onClick,
|
||||
modifier = modifier
|
||||
|
|
|
|||
|
|
@ -27,11 +27,7 @@ class DetailsFragment : Fragment(), StoreSubscriber<DetailsState> {
|
|||
exitTransition = inflater.inflateTransition(android.R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
isTransitionGroup = true
|
||||
|
|
|
|||
|
|
@ -159,10 +159,7 @@ fun DetailsItem(item: SettingsElement, appCurrency: String, onItemsClick: () ->
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun TangemSocialAccounts(
|
||||
links: List<SocialNetworkLink>,
|
||||
onSocialNetworkClick: (SocialNetworkLink) -> Unit,
|
||||
) {
|
||||
fun TangemSocialAccounts(links: List<SocialNetworkLink>, onSocialNetworkClick: (SocialNetworkLink) -> Unit) {
|
||||
LazyRow(modifier = Modifier.padding(start = 8.dp, end = 8.dp)) {
|
||||
items(links) {
|
||||
Icon(
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ enum class SettingsElement(
|
|||
LinkMoreCards(R.drawable.ic_more_cards, R.string.details_row_title_create_backup),
|
||||
TermsOfService(R.drawable.ic_text, R.string.disclaimer_title), // General Terms of Service of the App
|
||||
PrivacyPolicy(R.drawable.ic_lock_24, R.string.details_row_privacy_policy),
|
||||
TesterMenu(R.drawable.ic_alert_24, R.string.tester_menu)
|
||||
TesterMenu(R.drawable.ic_alert_24, R.string.tester_menu),
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
|
|
|||
|
|
@ -30,11 +30,7 @@ class ResetCardFragment : Fragment(), StoreSubscriber<DetailsState> {
|
|||
exitTransition = inflater.inflateTransition(android.R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
isTransitionGroup = true
|
||||
|
|
|
|||
|
|
@ -134,9 +134,7 @@ fun ResetCardView(state: ResetCardScreenState) {
|
|||
|
||||
// region Preview
|
||||
@Composable
|
||||
private fun ResetCardScreenSample(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun ResetCardScreenSample(modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors.background.secondary),
|
||||
|
|
|
|||
|
|
@ -30,11 +30,7 @@ class SecurityModeFragment : Fragment(), StoreSubscriber<DetailsState> {
|
|||
exitTransition = inflater.inflateTransition(android.R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
isTransitionGroup = true
|
||||
|
|
|
|||
|
|
@ -25,18 +25,17 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) }
|
||||
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
}
|
||||
})
|
||||
activity?.onBackPressedDispatcher?.addCallback(
|
||||
this,
|
||||
object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View? {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
if (!permissionIsGranted()) requestPermission()
|
||||
|
||||
scannerView = ZXingScannerView(activity)
|
||||
|
|
@ -62,11 +61,7 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler {
|
|||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<out String>,
|
||||
grantResults: IntArray,
|
||||
) {
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
if (requestCode != CameraView.PERMISSION_REQUEST_CODE) return
|
||||
|
||||
if (grantResults.isEmpty() || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
|
|
|
|||
|
|
@ -31,11 +31,7 @@ class WalletConnectFragment : Fragment(), StoreSubscriber<WalletConnectState> {
|
|||
exitTransition = inflater.inflateTransition(android.R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
isTransitionGroup = true
|
||||
|
|
|
|||
|
|
@ -65,10 +65,7 @@ fun WalletConnectScreen(state: WalletConnectScreenState, onBackClick: () -> Unit
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun AddSessionFab(
|
||||
onAddSession: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun AddSessionFab(onAddSession: () -> Unit, modifier: Modifier = Modifier) {
|
||||
FloatingActionButton(
|
||||
onClick = onAddSession,
|
||||
backgroundColor = colorResource(id = R.color.button_primary),
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue