From cc66f0389592825f0b673e629b3a175f32fb755b Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 3 May 2022 15:39:37 +0300 Subject: [PATCH 001/111] Updated on 2026-08-14 --- domain/src/main/java/com/tangem/domain/DomainException.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/domain/src/main/java/com/tangem/domain/DomainException.kt b/domain/src/main/java/com/tangem/domain/DomainException.kt index b6fc362990..a2661db781 100644 --- a/domain/src/main/java/com/tangem/domain/DomainException.kt +++ b/domain/src/main/java/com/tangem/domain/DomainException.kt @@ -6,7 +6,9 @@ import com.tangem.common.module.ModuleException /** [REDACTED_AUTHOR] */ -sealed class AddCustomTokenException(override val message: String) : Throwable(message), ModuleException { +sealed class DomainException(override val message: String) : Throwable(message), ModuleException + +sealed class AddCustomTokenException(message: String) : DomainException(message) { data class SelectTokeNetworkException(val networkId: String) : AddCustomTokenException( "Unknown network [$networkId] should not be included in the network selection dialog." From 097a377af378b7b71f9a3bc799e43f6c9124083d Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 3 May 2022 16:37:13 +0300 Subject: [PATCH 002/111] Updated on 2026-08-14 --- app/build.gradle | 24 +++++++++---------- .../tangem/tap/domain/configurable/Loader.kt | 6 ++--- dependencies.gradle | 6 +++++ domain/build.gradle | 10 ++++++++ 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 8771cec1c3..550a83ec13 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,11 +3,7 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' - -ext.configVar = [ - configEnvironment: "CONFIG_ENVIRONMENT", - testActionEnabled: "TEST_ACTION_ENABLED", -] +apply from: '../dependencies.gradle' android { compileSdkVersion 31 @@ -19,7 +15,8 @@ android { targetSdkVersion 31 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - buildConfigField 'Boolean', configVar.testActionEnabled, 'false' + buildConfigField 'Boolean', environmentConfig.testActionEnabled, 'false' + buildConfigField 'Boolean', environmentConfig.logEnabled, 'false' } buildFeatures { compose true @@ -31,8 +28,9 @@ android { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.debug - buildConfigField 'String', configVar.configEnvironment, '\"prod\"' - buildConfigField 'Boolean', configVar.testActionEnabled, 'false' + buildConfigField 'String', environmentConfig.environment, '\"prod\"' + buildConfigField 'Boolean', environmentConfig.testActionEnabled, 'false' + buildConfigField 'Boolean', environmentConfig.logEnabled, 'false' } debug { debuggable true @@ -42,16 +40,18 @@ android { firebaseCrashlytics { mappingFileUploadEnabled false } - buildConfigField 'String', configVar.configEnvironment, '\"dev\"' - buildConfigField 'Boolean', configVar.testActionEnabled, 'true' + buildConfigField 'String', environmentConfig.environment, '\"dev\"' + buildConfigField 'Boolean', environmentConfig.testActionEnabled, 'true' + buildConfigField 'Boolean', environmentConfig.logEnabled, 'true' } debug_beta { initWith release debuggable false versionNameSuffix "-beta" applicationIdSuffix ".debug" - buildConfigField 'String', configVar.configEnvironment, '\"prod\"' - buildConfigField 'Boolean', configVar.testActionEnabled, 'false' + buildConfigField 'String', environmentConfig.environment, '\"prod\"' + buildConfigField 'Boolean', environmentConfig.testActionEnabled, 'false' + buildConfigField 'Boolean', environmentConfig.logEnabled, 'false' } } diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/Loader.kt b/app/src/main/java/com/tangem/tap/domain/configurable/Loader.kt index 873b71c500..5354d0b219 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/Loader.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/Loader.kt @@ -9,8 +9,8 @@ interface Loader { fun load(onComplete: (T) -> Unit) companion object { - const val featuresName = "features_${BuildConfig.CONFIG_ENVIRONMENT}" - const val configValuesName = "tangem-app-config/config_${BuildConfig.CONFIG_ENVIRONMENT}" - const val warnings = "warnings_${BuildConfig.CONFIG_ENVIRONMENT}" + const val featuresName = "features_${BuildConfig.ENVIRONMENT}" + const val configValuesName = "tangem-app-config/config_${BuildConfig.ENVIRONMENT}" + const val warnings = "warnings_${BuildConfig.ENVIRONMENT}" } } \ No newline at end of file diff --git a/dependencies.gradle b/dependencies.gradle index 5ceeadcc6e..d463106208 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -2,3 +2,9 @@ ext.versions = [ kotlin : '1.6.10', build_gradle: '7.1.3', ] + +ext.environmentConfig = [ + environment: "ENVIRONMENT", + testActionEnabled: "TEST_ACTION_ENABLED", + logEnabled : "LOG_ENABLED", +] \ No newline at end of file diff --git a/domain/build.gradle b/domain/build.gradle index 4b5b520869..b156723a15 100644 --- a/domain/build.gradle +++ b/domain/build.gradle @@ -3,6 +3,8 @@ plugins { id 'org.jetbrains.kotlin.android' } +apply from: '../dependencies.gradle' + android { compileSdk 31 @@ -12,6 +14,8 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" + buildConfigField 'Boolean', environmentConfig.testActionEnabled, 'false' + buildConfigField 'Boolean', environmentConfig.logEnabled, 'false' } buildTypes { @@ -19,13 +23,19 @@ android { debuggable false minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + buildConfigField 'Boolean', environmentConfig.testActionEnabled, 'false' + buildConfigField 'Boolean', environmentConfig.logEnabled, 'false' } debug { debuggable true minifyEnabled false + buildConfigField 'Boolean', environmentConfig.testActionEnabled, 'true' + buildConfigField 'Boolean', environmentConfig.logEnabled, 'true' } debug_beta { initWith release + buildConfigField 'Boolean', environmentConfig.testActionEnabled, 'true' + buildConfigField 'Boolean', environmentConfig.logEnabled, 'true' } } kotlinOptions { From a085c2998c4717ebd1c664054c3e9b15f6a47540 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 3 May 2022 16:39:21 +0300 Subject: [PATCH 003/111] Updated on 2026-08-14 --- .../addCustomToken/redux/AddCustomTokenHub.kt | 27 ++++++++------- .../com/tangem/domain/redux/ReStoreHub.kt | 34 ++++++------------- .../domain/redux/global/DomainGlobalHub.kt | 30 ++++++++++------ 3 files changed, 44 insertions(+), 47 deletions(-) diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt index 19e2dcc43c..73db7237db 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt @@ -18,11 +18,9 @@ import com.tangem.domain.common.form.* import com.tangem.domain.features.addCustomToken.* import com.tangem.domain.features.addCustomToken.CustomTokenFieldId.* import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenAction.* -import com.tangem.domain.redux.BaseStoreHub -import com.tangem.domain.redux.DomainState -import com.tangem.domain.redux.dispatchOnMain -import com.tangem.domain.redux.domainStore +import com.tangem.domain.redux.* import com.tangem.domain.redux.global.DomainGlobalAction +import com.tangem.domain.redux.global.DomainGlobalState import com.tangem.network.api.tangemTech.CoinsResponse import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -38,6 +36,8 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT private val hubState: AddCustomTokenState get() = domainStore.state.addCustomTokensState + override fun getReducer(): ReStoreReducer = AddCustomTokenReducer(globalState) + override fun getHubState(storeState: DomainState): AddCustomTokenState = hubState override fun updateStoreState(storeState: DomainState, newHubState: AddCustomTokenState): DomainState { @@ -515,10 +515,17 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT dispatchOnMain(Warning.Replace(setOf(this), setOf(to))) } -// private suspend fun Warning.replace(replace: Boolean, to: Warning) { -// if (replace) dispatchOnMain(Warning.Replace(setOf(this), setOf(to))) -// } + @Throws + private fun throwUnAppropriateInitialization(objName: String) { + throw AddCustomTokenException.UnAppropriateInitializationException( + "AddCustomTokenHub", "$objName must be not NULL" + ) + } +} +private class AddCustomTokenReducer( + private val globalState: DomainGlobalState, +) : ReStoreReducer { override fun reduceAction(action: Action, state: AddCustomTokenState): AddCustomTokenState { return when (action) { @@ -679,10 +686,4 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT return state.copy(form = Form(state.form.fieldList)) } - @Throws - private fun throwUnAppropriateInitialization(objName: String) { - throw AddCustomTokenException.UnAppropriateInitializationException( - "AddCustomTokenHub", "$objName must be not NULL" - ) - } } \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/redux/ReStoreHub.kt b/domain/src/main/java/com/tangem/domain/redux/ReStoreHub.kt index 72aa9ca605..06775baafd 100644 --- a/domain/src/main/java/com/tangem/domain/redux/ReStoreHub.kt +++ b/domain/src/main/java/com/tangem/domain/redux/ReStoreHub.kt @@ -17,14 +17,13 @@ import java.util.concurrent.Executors * a state behavior. * All ReStoreHub's must be marked as internal */ -internal interface ReStoreHub : HubMiddleware, HubReducer - -internal interface HubMiddleware { +internal interface ReStoreHub { fun getMiddleware(): Middleware + fun reduce(action: Action, domainState: StoreState): StoreState } -internal interface HubReducer { - fun reduce(action: Action, storeState: StoreState): StoreState +internal interface ReStoreReducer { + fun reduceAction(action: Action, state: State): State } /** @@ -87,13 +86,13 @@ internal abstract class BaseStoreHub( * Reduce the action and check it. If the action hasn't updated the hubState, then it doesn't need to update * storeState */ - override fun reduce(action: Action, storeState: DomainState): DomainState { - val oldState = getHubState(storeState) - val newState = reduceAction(action, oldState) - return if (oldState === newState) { - storeState + override fun reduce(action: Action, domainState: DomainState): DomainState { + val hubOldState = getHubState(domainState) + val hubNewState = getReducer().reduceAction(action, hubOldState) + return if (hubOldState === hubNewState) { + domainState } else { - updateStoreState(storeState, newState) + updateStoreState(domainState, hubNewState) } } @@ -102,24 +101,13 @@ internal abstract class BaseStoreHub( } protected abstract suspend fun handleAction(action: Action, storeState: DomainState, cancel: ValueCallback) - - @Deprecated( - replaceWith = ReplaceWith("ReStoreReducer"), - message = "must return a Reducer instance. The reducer must be a separate component - this closes " + - "access to the states that can be obtained from ReStoreHub" - ) - abstract fun reduceAction(action: Action, state: State): State -// protected abstract fun getReducer(): ReStoreReducer + protected abstract fun getReducer(): ReStoreReducer protected abstract fun getHubState(storeState: DomainState): State protected abstract fun updateStoreState(storeState: DomainState, newHubState: State): DomainState } -internal interface ReStoreReducer { - fun reduceAction(action: Action, state: State): State -} - internal suspend inline fun ReStoreHub<*, *>.dispatchOnMain(vararg actions: Action) { withMainContext { actions.forEach { domainStore.dispatch(it) } } } diff --git a/domain/src/main/java/com/tangem/domain/redux/global/DomainGlobalHub.kt b/domain/src/main/java/com/tangem/domain/redux/global/DomainGlobalHub.kt index 92fc243edd..d80b0bab73 100644 --- a/domain/src/main/java/com/tangem/domain/redux/global/DomainGlobalHub.kt +++ b/domain/src/main/java/com/tangem/domain/redux/global/DomainGlobalHub.kt @@ -4,6 +4,7 @@ import android.webkit.ValueCallback import com.tangem.common.extensions.toHexString import com.tangem.domain.redux.BaseStoreHub import com.tangem.domain.redux.DomainState +import com.tangem.domain.redux.ReStoreReducer import com.tangem.network.common.CardPublicKeyHttpInterceptor import org.rekotlin.Action @@ -34,17 +35,24 @@ internal class DomainGlobalHub : BaseStoreHub("DomainGlobalHu } } - override fun reduceAction(action: Action, state: DomainGlobalState): DomainGlobalState = when (action) { - is DomainGlobalAction.SaveScanNoteResponse -> { - val cardPublicKeyHex = action.scanResponse.card.cardPublicKey.toHexString() - state.networkServices.tangemTechService.addHeaderInterceptors( - listOf(CardPublicKeyHttpInterceptor(cardPublicKeyHex)) - ) - state.copy(scanResponse = action.scanResponse) + override fun getReducer(): ReStoreReducer = DomainGlobalReducer() +} + +private class DomainGlobalReducer : ReStoreReducer { + + override fun reduceAction(action: Action, state: DomainGlobalState): DomainGlobalState { + return when (action) { + is DomainGlobalAction.SaveScanNoteResponse -> { + val cardPublicKeyHex = action.scanResponse.card.cardPublicKey.toHexString() + state.networkServices.tangemTechService.addHeaderInterceptors( + listOf(CardPublicKeyHttpInterceptor(cardPublicKeyHex)) + ) + state.copy(scanResponse = action.scanResponse) + } + is DomainGlobalAction.ShowDialog -> { + state.copy(dialog = action.stateDialog) + } + else -> state } - is DomainGlobalAction.ShowDialog -> { - state.copy(dialog = action.stateDialog) - } - else -> state } } \ No newline at end of file From 853972903271cb994b30f68a32491d2c597b3b46 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 3 May 2022 16:39:56 +0300 Subject: [PATCH 004/111] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 2 + .../java/com/tangem/domain/DomainLayer.kt | 26 ++++++++ .../AddCustomTokenActionStateConverter.kt | 61 ------------------- .../redux/AddCustomTokenState.kt | 56 +++++++++++++++++ .../com/tangem/domain/redux/DomainStore.kt | 38 ++++++++---- .../domain/redux/state/StateConverter.kt | 23 ++++++- .../tangem/domain/redux/state/StateLogger.kt | 35 +++++++++++ .../domain/redux/state/StateObservables.kt | 36 ----------- 8 files changed, 166 insertions(+), 111 deletions(-) create mode 100644 domain/src/main/java/com/tangem/domain/DomainLayer.kt delete mode 100644 domain/src/main/java/com/tangem/domain/features/addCustomToken/AddCustomTokenActionStateConverter.kt create mode 100644 domain/src/main/java/com/tangem/domain/redux/state/StateLogger.kt delete mode 100644 domain/src/main/java/com/tangem/domain/redux/state/StateObservables.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index e4254151fc..28bf6c2485 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -7,6 +7,7 @@ import com.google.firebase.remoteconfig.ktx.remoteConfig import com.google.firebase.remoteconfig.ktx.remoteConfigSettings import com.tangem.Log import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder +import com.tangem.domain.DomainLayer import com.tangem.network.common.MoshiConverter import com.tangem.tap.common.analytics.GlobalAnalyticsHandler import com.tangem.tap.common.images.PicassoHelper @@ -46,6 +47,7 @@ class TapApplication : Application() { override fun onCreate() { super.onCreate() + DomainLayer.init() if (BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) Firebase.remoteConfig.setConfigSettingsAsync(remoteConfigSettings { diff --git a/domain/src/main/java/com/tangem/domain/DomainLayer.kt b/domain/src/main/java/com/tangem/domain/DomainLayer.kt new file mode 100644 index 0000000000..f83049dbf8 --- /dev/null +++ b/domain/src/main/java/com/tangem/domain/DomainLayer.kt @@ -0,0 +1,26 @@ +package com.tangem.domain + +import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenAction +import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenState +import com.tangem.domain.redux.state.ActionStateLoggerImpl + +/** +[REDACTED_AUTHOR] + */ +object DomainLayer { + internal val actionStateLogger = ActionStateLoggerImpl() + + var onInitComplete: ((DomainException?) -> Unit)? = null + + fun init(data: Map? = null) { + initActionStateLogger() + + onInitComplete?.invoke(null) + } + + private fun initActionStateLogger() { + val factory = actionStateLogger.actionStateConvertersFactory + + factory.addConverter(AddCustomTokenAction::class.java, AddCustomTokenState.Converter()) + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/AddCustomTokenActionStateConverter.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/AddCustomTokenActionStateConverter.kt deleted file mode 100644 index 196d7eafc1..0000000000 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/AddCustomTokenActionStateConverter.kt +++ /dev/null @@ -1,61 +0,0 @@ -package com.tangem.domain.features.addCustomToken - -import com.tangem.common.json.MoshiJsonConverter -import com.tangem.domain.common.form.FieldToJsonConverter -import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenAction -import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenState -import com.tangem.domain.redux.DomainState -import com.tangem.domain.redux.state.StringActionConverter -import org.rekotlin.Action - -class AddCustomTokenActionStateConverter : StringActionConverter { - private val jsonConverter: MoshiJsonConverter = MoshiJsonConverter.INSTANCE - private var builder: StringBuilder = StringBuilder() - - override fun convert(action: Action, stateHolder: DomainState): String? { - val action = (action as? AddCustomTokenAction) ?: return null - - val state = stateHolder.addCustomTokensState - val fieldConverter = FieldToJsonConverter(listOf( - CustomTokenFieldId.ContractAddress, - CustomTokenFieldId.Network, - CustomTokenFieldId.Name, - CustomTokenFieldId.Symbol, - CustomTokenFieldId.Decimals, - CustomTokenFieldId.DerivationPath, - ), jsonConverter) - state.visitDataConverter(fieldConverter) - val errors = state.formErrors.map { - "${it.key}: ${it.value::class.java.simpleName}" - } - val warnings = state.warnings.map { it::class.java.simpleName } - - printAction(action, state) - printStateValue("fields", fieldConverter.getConvertedData()) - printStateValue("fieldErrors", toJson(errors)) - printStateValue("warnings", toJson(warnings)) - printStateValue("screenState", toJson(state.screenState)) - printMessage("------------------------------------------------------") - - val printed = builder.toString() - builder = StringBuilder() - - return printed - } - - private fun printStateValue(name: String, value: String) { - printMessage("$name: $value") - } - - private fun printAction(action: AddCustomTokenAction, state: AddCustomTokenState) { - printMessage("action: $action, state: ${state::class.java.simpleName}") - } - - private fun toJson(value: Any): String { - return jsonConverter.prettyPrint(value) - } - - private fun printMessage(message: String) { - builder.append("$message\n") - } -} \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt index 2e19da5307..8d9714ce91 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt @@ -3,6 +3,7 @@ package com.tangem.domain.features.addCustomToken.redux import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle import com.tangem.common.card.FirmwareVersion +import com.tangem.common.json.MoshiJsonConverter import com.tangem.domain.AddCustomTokenError import com.tangem.domain.DomainWrapped import com.tangem.domain.common.extensions.SolanaAvailable @@ -10,7 +11,10 @@ import com.tangem.domain.common.extensions.SolanaTokensAvailable import com.tangem.domain.common.form.* import com.tangem.domain.features.addCustomToken.* import com.tangem.domain.features.addCustomToken.CustomTokenFieldId.* +import com.tangem.domain.redux.DomainState import com.tangem.domain.redux.domainStore +import com.tangem.domain.redux.state.StringActionStateConverter +import org.rekotlin.Action import org.rekotlin.StateType data class AddCustomTokenState( @@ -239,6 +243,58 @@ data class AddCustomTokenState( ) } } + + class Converter : StringActionStateConverter { + private val jsonConverter: MoshiJsonConverter = MoshiJsonConverter.INSTANCE + private var builder: StringBuilder = StringBuilder() + + override fun convert(action: Action, stateHolder: DomainState): String? { + val action = (action as? AddCustomTokenAction) ?: return null + + val state = stateHolder.addCustomTokensState + val fieldConverter = FieldToJsonConverter(listOf( + ContractAddress, + Network, + Name, + Symbol, + Decimals, + DerivationPath, + ), jsonConverter) + state.visitDataConverter(fieldConverter) + val errors = state.formErrors.map { + "${it.key}: ${it.value::class.java.simpleName}" + } + val warnings = state.warnings.map { it::class.java.simpleName } + + printAction(action, state) + printStateValue("fields", fieldConverter.getConvertedData()) + printStateValue("fieldErrors", toJson(errors)) + printStateValue("warnings", toJson(warnings)) + printStateValue("screenState", toJson(state.screenState)) + printMessage("------------------------------------------------------") + + val printed = builder.toString() + builder = StringBuilder() + + return printed + } + + private fun printStateValue(name: String, value: String) { + printMessage("$name: $value") + } + + private fun printAction(action: AddCustomTokenAction, state: AddCustomTokenState) { + printMessage("action: $action, state: ${state::class.java.simpleName}") + } + + private fun toJson(value: Any): String { + return jsonConverter.prettyPrint(value) + } + + private fun printMessage(message: String) { + builder.append("$message\n") + } + } } enum class CustomTokenType { diff --git a/domain/src/main/java/com/tangem/domain/redux/DomainStore.kt b/domain/src/main/java/com/tangem/domain/redux/DomainStore.kt index 78bc7cf624..703ca18a88 100644 --- a/domain/src/main/java/com/tangem/domain/redux/DomainStore.kt +++ b/domain/src/main/java/com/tangem/domain/redux/DomainStore.kt @@ -1,8 +1,9 @@ package com.tangem.domain.redux +import com.tangem.domain.DomainLayer import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenHub import com.tangem.domain.redux.global.DomainGlobalHub -import com.tangem.domain.redux.state.observeReducedStates +import org.rekotlin.Action import org.rekotlin.Store /** @@ -18,16 +19,27 @@ private val RE_STORE_HUBS: List> = listOf( val domainStore = Store( state = DomainState(), middleware = RE_STORE_HUBS.map { it.getMiddleware() }, - reducer = { action, state -> - requireNotNull(state) - - // we can examine the store state after each change by reducer - val reducedSates = RE_STORE_HUBS.mapNotNull { - val reducedState = it.reduce(action, state) - if (reducedState == state) null else Pair(action, reducedState) - } - observeReducedStates(reducedSates) - - if (reducedSates.isEmpty()) state else reducedSates.last().second - } + reducer = { action, state -> reduce(action, state) } ) + +private fun reduce(action: Action, domainState: DomainState?): DomainState { + requireNotNull(domainState) + + // we can examine the store state after each change by reducer + var assembleReducedDomainState: DomainState = domainState + val reducedStatesByAction = mutableListOf>() + + RE_STORE_HUBS.forEach { + val reducedState = it.reduce(action, assembleReducedDomainState) + + assembleReducedDomainState = if (reducedState != assembleReducedDomainState) { + reducedStatesByAction.add(action to assembleReducedDomainState) + reducedState + } else { + assembleReducedDomainState + } + } + DomainLayer.actionStateLogger.log(reducedStatesByAction) + + return assembleReducedDomainState +} diff --git a/domain/src/main/java/com/tangem/domain/redux/state/StateConverter.kt b/domain/src/main/java/com/tangem/domain/redux/state/StateConverter.kt index f6a13aa10f..8e99e0f538 100644 --- a/domain/src/main/java/com/tangem/domain/redux/state/StateConverter.kt +++ b/domain/src/main/java/com/tangem/domain/redux/state/StateConverter.kt @@ -1,5 +1,6 @@ package com.tangem.domain.redux.state +import com.tangem.domain.redux.DomainState import org.rekotlin.Action /** @@ -9,6 +10,26 @@ interface StringStateConverter { fun convert(stateHolder: StateHolder): String } -interface StringActionConverter { +interface StringActionStateConverter { fun convert(action: Action, stateHolder: StateHolder): String? +} + +class ActionStateConvertersFactory { + private val stateConverters = mutableMapOf, StringActionStateConverter>() + + fun addConverter(classOfAction: Class, converter: StringActionStateConverter) { + stateConverters[classOfAction] = converter + } + + fun getConverter(action: Action): StringActionStateConverter? { + val converter = stateConverters.firstNotNullOfOrNull { (classOfAction, converter) -> + if (classOfAction.isAssignableFrom(action::class.java)) { + converter + } else { + null + } + } ?: return null + + return converter + } } \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/redux/state/StateLogger.kt b/domain/src/main/java/com/tangem/domain/redux/state/StateLogger.kt new file mode 100644 index 0000000000..576d398ea8 --- /dev/null +++ b/domain/src/main/java/com/tangem/domain/redux/state/StateLogger.kt @@ -0,0 +1,35 @@ +package com.tangem.domain.redux.state + +import com.tangem.domain.features.BuildConfig +import com.tangem.domain.redux.DomainState +import org.rekotlin.Action +import timber.log.Timber + +/** +[REDACTED_AUTHOR] + * Use it only in debug mode! + */ +internal interface ActionStateLogger { + fun log(reducedSates: List>) +} + +internal class ActionStateLoggerImpl : ActionStateLogger { + + val actionStateConvertersFactory = ActionStateConvertersFactory() + + override fun log(reducedSates: List>) { + if (!BuildConfig.LOG_ENABLED) return + + logStates(reducedSates) + } + + private fun logStates(reducedSates: List>) { + reducedSates.forEach { (action, domainState) -> + val messageToPrint = actionStateConvertersFactory.getConverter(action) + ?.convert(action, domainState) + ?: return@forEach + + Timber.d(messageToPrint) + } + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/redux/state/StateObservables.kt b/domain/src/main/java/com/tangem/domain/redux/state/StateObservables.kt deleted file mode 100644 index 2195ec8645..0000000000 --- a/domain/src/main/java/com/tangem/domain/redux/state/StateObservables.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.tangem.domain.redux.state - -import com.tangem.domain.features.addCustomToken.AddCustomTokenActionStateConverter -import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenAction -import com.tangem.domain.redux.DomainState -import org.rekotlin.Action -import timber.log.Timber - -/** -[REDACTED_AUTHOR] - * Use it only in debug mode! - */ -internal fun observeReducedStates(reducedSates: List>) { - // we can add any logic to watch for changes of actions, states, etc. - val isDebugMode = true - if (!isDebugMode) return - - logStates(reducedSates) -} - -private fun logStates(reducedSates: List>) { - reducedSates.forEach { - val converter = stateConverters.firstNotNullOfOrNull { entry -> - if (entry.key.isAssignableFrom(it.first::class.java)) entry.value else null - } ?: return@forEach - - val messageToPrint = converter.convert(it.first, it.second) ?: return@forEach - - Timber.d(messageToPrint) - } -} - -// TODO: refactoring: mutate to factory -private val stateConverters = mutableMapOf( - AddCustomTokenAction::class.java to AddCustomTokenActionStateConverter() -) \ No newline at end of file From 750a54154067c8f49d662ee146506f6e5b5e3bf4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 5 May 2022 11:12:44 +0300 Subject: [PATCH 005/111] Updated on 2026-08-14 --- .../java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index e843eab420..b8b4799532 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -239,7 +239,6 @@ private class ScanWalletProcessor( blockchainsToDerive.addAll( listOf( BlockchainNetwork(Blockchain.Ethereum, card), - BlockchainNetwork(Blockchain.Binance, card), BlockchainNetwork(Blockchain.EthereumTestnet, card) ) ) From 26dbed5de0aeb62c5e0e79e9ab68dd7a1a147318 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 5 May 2022 16:04:27 +0400 Subject: [PATCH 006/111] Updated on 2026-08-14 --- .../res/drawable/ic_arbitrum_no_color.xml | 13 +++++++++ .../main/res/drawable/ic_arbitrum_round.xml | 13 +++++++++ app/src/main/res/drawable/ic_eth_round.xml | 28 ++++++++----------- .../main/res/drawable/ic_ethc_no_color.xml | 9 ++++++ app/src/main/res/drawable/ic_ethc_round.xml | 9 ++++++ .../main/res/drawable/ic_tron_no_color.xml | 9 ++++++ app/src/main/res/drawable/ic_tron_round.xml | 9 ++++++ 7 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 app/src/main/res/drawable/ic_arbitrum_no_color.xml create mode 100644 app/src/main/res/drawable/ic_arbitrum_round.xml create mode 100644 app/src/main/res/drawable/ic_ethc_no_color.xml create mode 100644 app/src/main/res/drawable/ic_ethc_round.xml create mode 100644 app/src/main/res/drawable/ic_tron_no_color.xml create mode 100644 app/src/main/res/drawable/ic_tron_round.xml diff --git a/app/src/main/res/drawable/ic_arbitrum_no_color.xml b/app/src/main/res/drawable/ic_arbitrum_no_color.xml new file mode 100644 index 0000000000..02164f7121 --- /dev/null +++ b/app/src/main/res/drawable/ic_arbitrum_no_color.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_arbitrum_round.xml b/app/src/main/res/drawable/ic_arbitrum_round.xml new file mode 100644 index 0000000000..632ea33dae --- /dev/null +++ b/app/src/main/res/drawable/ic_arbitrum_round.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_eth_round.xml b/app/src/main/res/drawable/ic_eth_round.xml index e19df6434c..b62152ede8 100644 --- a/app/src/main/res/drawable/ic_eth_round.xml +++ b/app/src/main/res/drawable/ic_eth_round.xml @@ -1,20 +1,14 @@ - - + + - - - - - - - + + + + + + + diff --git a/app/src/main/res/drawable/ic_ethc_no_color.xml b/app/src/main/res/drawable/ic_ethc_no_color.xml new file mode 100644 index 0000000000..8053e14918 --- /dev/null +++ b/app/src/main/res/drawable/ic_ethc_no_color.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_ethc_round.xml b/app/src/main/res/drawable/ic_ethc_round.xml new file mode 100644 index 0000000000..31f3dbacd8 --- /dev/null +++ b/app/src/main/res/drawable/ic_ethc_round.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_tron_no_color.xml b/app/src/main/res/drawable/ic_tron_no_color.xml new file mode 100644 index 0000000000..6494f87e60 --- /dev/null +++ b/app/src/main/res/drawable/ic_tron_no_color.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_tron_round.xml b/app/src/main/res/drawable/ic_tron_round.xml new file mode 100644 index 0000000000..9eaf6cfc9b --- /dev/null +++ b/app/src/main/res/drawable/ic_tron_round.xml @@ -0,0 +1,9 @@ + + + + + + + From 5b75323ac04f9a37edd5d81be54c874e3a292bb3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 16 May 2022 13:10:49 +0300 Subject: [PATCH 007/111] Updated on 2026-08-14 --- .../wallet/ui/dialogs/AmountToSendDialog.kt | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/AmountToSendDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/AmountToSendDialog.kt index 5eea55091b..69219eff90 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/AmountToSendDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/AmountToSendDialog.kt @@ -1,7 +1,6 @@ package com.tangem.tap.features.wallet.ui.dialogs import android.content.Context -import android.content.DialogInterface import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup @@ -26,20 +25,18 @@ class AmountToSendDialog(context: Context) : BottomSheetDialog(context) { setContentView(binding!!.root) } - override fun setOnCancelListener(listener: DialogInterface.OnCancelListener?) { - super.setOnCancelListener(listener) - binding = null - } - fun show(amounts: List?) { - this.setOnDismissListener { + super.show() + + setOnDismissListener { + binding = null store.dispatch(WalletAction.Send.Cancel) } binding!!.rvAmountsToSend.layoutManager = LinearLayoutManager(context) val dividerItemDecoration = DividerItemDecoration( - ContextThemeWrapper(binding!!.root.context, R.style.AppTheme), - DividerItemDecoration.VERTICAL + ContextThemeWrapper(binding!!.root.context, R.style.AppTheme), + DividerItemDecoration.VERTICAL ) binding!!.rvAmountsToSend.addItemDecoration(dividerItemDecoration) @@ -47,8 +44,6 @@ class AmountToSendDialog(context: Context) : BottomSheetDialog(context) { binding!!.rvAmountsToSend.adapter = viewAdapter viewAdapter.submitList(amounts) - - show() } } @@ -69,16 +64,16 @@ class ChooseAmountAdapter object DiffUtilCallback : DiffUtil.ItemCallback() { override fun areContentsTheSame( - oldItem: Amount, newItem: Amount + oldItem: Amount, newItem: Amount ) = oldItem.currencySymbol == newItem.currencySymbol override fun areItemsTheSame( - oldItem: Amount, newItem: Amount + oldItem: Amount, newItem: Amount ) = oldItem == newItem } class AmountViewHolder(val binding: ItemWalletAmountToSendBinding) : - RecyclerView.ViewHolder(binding.root) { + RecyclerView.ViewHolder(binding.root) { fun bind(amount: Amount) = with(binding) { tvCurrencySymbol.text = amount.currencySymbol From 15b5d45d3532914ba66bf59ddde21533634d14a8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 17 May 2022 16:33:42 +0300 Subject: [PATCH 008/111] Updated on 2026-08-14 --- app/build.gradle | 3 +- domain/build.gradle | 3 +- .../domain/common/extensions/CardSdk.kt | 46 +++++++++++- .../addCustomToken/redux/AddCustomTokenHub.kt | 21 +++--- .../redux/AddCustomTokenState.kt | 73 +++++++------------ 5 files changed, 81 insertions(+), 65 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 550a83ec13..d69b335737 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -93,7 +93,8 @@ dependencies { implementation 'com.google.android.play:core-ktx:1.8.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' - implementation 'com.tangem:blockchain:develop-77' + implementation 'com.tangem:blockchain:develop-78' +// implementation 'com.tangem:blockchain:0.0.1' implementation 'com.tangem.tangem-sdk-kotlin:core:develop-142' implementation 'com.tangem.tangem-sdk-kotlin:android:develop-142' diff --git a/domain/build.gradle b/domain/build.gradle index b156723a15..8dd3f9a54c 100644 --- a/domain/build.gradle +++ b/domain/build.gradle @@ -60,7 +60,8 @@ dependencies { implementation implementation(project(path: ':common')) // Tangem sdk's - implementation 'com.tangem:blockchain:develop-77' + implementation 'com.tangem:blockchain:develop-78' +// implementation 'com.tangem:blockchain:0.0.1' implementation 'com.tangem.tangem-sdk-kotlin:core:develop-142' implementation 'com.tangem.tangem-sdk-kotlin:android:develop-142' diff --git a/domain/src/main/java/com/tangem/domain/common/extensions/CardSdk.kt b/domain/src/main/java/com/tangem/domain/common/extensions/CardSdk.kt index ca37d132ba..ea805497c6 100644 --- a/domain/src/main/java/com/tangem/domain/common/extensions/CardSdk.kt +++ b/domain/src/main/java/com/tangem/domain/common/extensions/CardSdk.kt @@ -1,12 +1,50 @@ package com.tangem.domain.common.extensions +import com.tangem.blockchain.common.Blockchain +import com.tangem.common.card.Card +import com.tangem.common.card.EllipticCurve import com.tangem.common.card.FirmwareVersion +import com.tangem.domain.common.TapWorkarounds.isTestCard /** [REDACTED_AUTHOR] */ -val FirmwareVersion.Companion.SolanaAvailable - get() = FirmwareVersion(4, 12) - val FirmwareVersion.Companion.SolanaTokensAvailable - get() = FirmwareVersion(4, 52) \ No newline at end of file + get() = FirmwareVersion(4, 52) + +fun Card.supportedBlockchains(): List { + val supportedBlockchains = when { + firmwareVersion < FirmwareVersion.MultiWalletAvailable -> { + Blockchain.fromCurve(EllipticCurve.Secp256k1) + } + else -> { + Blockchain.fromCurve(EllipticCurve.Secp256k1) + + Blockchain.fromCurve(EllipticCurve.Ed25519) + } + } + val filtered = supportedBlockchains.filter { isTestCard == it.isTestnet() } + return filtered +} + +fun Card.supportedTokens(): List { + val tokensSupportedByBlockchain = supportedBlockchains().filter { it.canHandleTokens() }.toMutableList() + val tokensSupportedByCard = when { + firmwareVersion >= FirmwareVersion.SolanaTokensAvailable -> tokensSupportedByBlockchain + else -> { + tokensSupportedByBlockchain.apply { + remove(Blockchain.Solana) + remove(Blockchain.SolanaTestnet) + } + } + } + val filtered = tokensSupportedByCard.filter { isTestCard == it.isTestnet() } + return filtered +} + +fun Card.canHandleBlockchain(blockchain: Blockchain): Boolean { + return this.supportedBlockchains().contains(blockchain) +} + +fun Card.canHandleToken(blockchain: Blockchain): Boolean { + return this.supportedTokens().contains(blockchain) +} \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt index 73db7237db..82aadfae67 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt @@ -13,6 +13,7 @@ import com.tangem.domain.DomainDialog import com.tangem.domain.DomainWrapped import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.extensions.fromNetworkId +import com.tangem.domain.common.extensions.supportedTokens import com.tangem.domain.common.extensions.toNetworkId import com.tangem.domain.common.form.* import com.tangem.domain.features.addCustomToken.* @@ -141,16 +142,11 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT } } - //TODO: Solana token - /** - * This feature is only needed until Solana coins are added. - * While they are not there - this function excludes the Solana blockchain if the user has - * filled in at least one field of the token. - */ private suspend fun changeBlockchainNetworkList() { val state = hubState val networkBlockchainList = Network.getField().itemList - val newNetworkBlockchainList: List = state.getNetworks(state.getCustomTokenType()) + val card = requireNotNull(globalState.scanResponse?.card) + val newNetworkBlockchainList: List = state.getNetworks(card, state.getCustomTokenType()) val listsIdentical = newNetworkBlockchainList.toSet() == networkBlockchainList.toSet() if (listsIdentical) return @@ -537,9 +533,7 @@ private class AddCustomTokenReducer( } is OnCreate -> { val card = requireNotNull(globalState.scanResponse?.card) - val supportedTokenNetworkIds = AddCustomTokenState.getSupportedTokensBlockchain().map { - it.toNetworkId() - } + val supportedTokenNetworkIds = card.supportedTokens().map { it.toNetworkId() } val tangemTechServiceManager = AddCustomTokenService( tangemTechService = globalState.networkServices.tangemTechService, supportedTokenNetworkIds = supportedTokenNetworkIds @@ -550,7 +544,7 @@ private class AddCustomTokenReducer( DerivationStyle.LEGACY -> derivationPathState.copy(isVisible = true) null, DerivationStyle.NEW -> derivationPathState.copy(isVisible = false) } - val form = Form(AddCustomTokenState.createFormFields(CustomTokenType.Blockchain)) + val form = Form(AddCustomTokenState.createFormFields(card, CustomTokenType.Blockchain)) state.copy( cardDerivationStyle = card.derivationStyle, form = form, @@ -558,7 +552,10 @@ private class AddCustomTokenReducer( screenState = state.screenState.copy(derivationPath = derivationPathState) ) } - is OnDestroy -> state.reset() + is OnDestroy -> { + val card = requireNotNull(globalState.scanResponse?.card) + state.reset(card) + } is UpdateForm -> { updateFormState(action.state) } diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt index 8d9714ce91..2a5f43a3fd 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt @@ -2,17 +2,17 @@ package com.tangem.domain.features.addCustomToken.redux import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle -import com.tangem.common.card.FirmwareVersion +import com.tangem.common.card.Card import com.tangem.common.json.MoshiJsonConverter import com.tangem.domain.AddCustomTokenError import com.tangem.domain.DomainWrapped -import com.tangem.domain.common.extensions.SolanaAvailable -import com.tangem.domain.common.extensions.SolanaTokensAvailable +import com.tangem.domain.common.TapWorkarounds.isTestCard +import com.tangem.domain.common.extensions.supportedBlockchains +import com.tangem.domain.common.extensions.supportedTokens import com.tangem.domain.common.form.* import com.tangem.domain.features.addCustomToken.* import com.tangem.domain.features.addCustomToken.CustomTokenFieldId.* import com.tangem.domain.redux.DomainState -import com.tangem.domain.redux.domainStore import com.tangem.domain.redux.state.StringActionStateConverter import org.rekotlin.Action import org.rekotlin.StateType @@ -109,12 +109,12 @@ data class AddCustomTokenState( null } - fun reset(): AddCustomTokenState { + fun reset(card: Card): AddCustomTokenState { return this.copy( appSavedCurrencies = null, onTokenAddCallback = null, cardDerivationStyle = null, - form = Form(createFormFields(CustomTokenType.Blockchain)), + form = Form(createFormFields(card, CustomTokenType.Blockchain)), formErrors = emptyMap(), tokenId = null, warnings = emptySet(), @@ -135,8 +135,8 @@ data class AddCustomTokenState( .getConvertedData() } - fun getNetworks(type: CustomTokenType): List { - return getNetworksList(type) + fun getNetworks(card: Card, type: CustomTokenType): List { + return getNetworksList(card, type) } companion object { @@ -154,66 +154,45 @@ data class AddCustomTokenState( else -> derivationNetwork }.derivationPath(derivationStyle) - internal fun createFormFields(type: CustomTokenType): List> { + internal fun createFormFields(card: Card, type: CustomTokenType): List> { return listOf( TokenField(ContractAddress), - TokenBlockchainField(Network, getNetworksList(type)), + TokenBlockchainField(Network, getNetworksList(card, type)), TokenField(Name), TokenField(Symbol), TokenField(Decimals), - TokenDerivationPathField(DerivationPath, getSupportedDerivations()), + TokenDerivationPathField(DerivationPath, getSupportedDerivations(card)), ) } - /** - * Serves to determine the tokens that can be received from the TangemTech service - */ - internal fun getSupportedTokensBlockchain(): List { - return Blockchain.values() - .filter { !it.isTestnet() } - .filter { it.canHandleTokens() } - } - /** * Serves to determine the networks (blockchains & tokens) that can be selected by Form.Networks. * Blockchain.Unknown - is the default selection */ - private fun getNetworksList(type: CustomTokenType): List { + private fun getNetworksList(card: Card, type: CustomTokenType): List { val evmBlockchains = Blockchain.values() .filter { it.isEvm() } - .filter { !it.isTestnet() } + .filter { card.isTestCard == it.isTestnet() } val additionalBlockchains = listOf( - Blockchain.Binance, - Blockchain.Solana, + Blockchain.Binance, Blockchain.BinanceTestnet, + Blockchain.Solana, Blockchain.SolanaTestnet, ) - val networks = (evmBlockchains + additionalBlockchains).toMutableList() - - //life hack - val fwCardVersion = domainStore.state.globalState.scanResponse?.card?.firmwareVersion - ?: FirmwareVersion(0, 0) - - val solanaUnsupportedByCard = fwCardVersion < FirmwareVersion.SolanaAvailable - val solanaTokensUnsupportedByCard = fwCardVersion < FirmwareVersion.SolanaTokensAvailable - if (solanaUnsupportedByCard || solanaTokensUnsupportedByCard) networks.remove(Blockchain.Solana) - - if (type == CustomTokenType.Token) networks.removeAll(getUnsupportedTokensBlockchain()) + val supportedByCard = when (type) { + CustomTokenType.Blockchain -> card.supportedBlockchains() + CustomTokenType.Token -> card.supportedTokens() + } + val typedNetworksList = (evmBlockchains + additionalBlockchains) + .filter { supportedByCard.contains(it) } + .toMutableList() val default = Blockchain.Unknown - networks.add(0, default) + typedNetworksList.add(0, default) - return networks + return typedNetworksList } - private fun getUnsupportedTokensBlockchain(): List { - return Blockchain.values() - .filter { !it.isTestnet() } - .filter { !it.canHandleTokens() } - .toMutableList() - } - - private fun createFormValidators(): Map> { return mapOf( ContractAddress to TokenContractAddressValidator(), @@ -224,9 +203,9 @@ data class AddCustomTokenState( ) } - private fun getSupportedDerivations(): List { + private fun getSupportedDerivations(card: Card): List { val evmBlockchains = Blockchain.values().filter { - !it.isTestnet() && it.getChainId() != null + card.isTestCard == it.isTestnet() && it.getChainId() != null } return listOf(Blockchain.Unknown) + evmBlockchains } From bd3ab3e125bbf88aa187e68bbe738bf5456a522a Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 17 May 2022 00:12:17 +0300 Subject: [PATCH 009/111] Updated on 2026-08-14 --- .../features/wallet/models/TotalBalance.kt | 16 ++++ .../tap/features/wallet/redux/WalletState.kt | 22 ++++-- .../redux/reducers/OnWalletLoadedReducer.kt | 77 ++++++++++++++++--- .../wallet/ui/wallet/MultiWalletView.kt | 19 +++++ .../main/res/layout/card_total_balance.xml | 71 +++++++++++++++++ app/src/main/res/layout/fragment_wallet.xml | 14 +++- app/src/main/res/values-ru/strings.xml | 3 +- app/src/main/res/values/strings.xml | 3 +- 8 files changed, 204 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt create mode 100644 app/src/main/res/layout/card_total_balance.xml diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt new file mode 100644 index 0000000000..31cc8a8d7f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt @@ -0,0 +1,16 @@ +package com.tangem.tap.features.wallet.models + +import com.tangem.tap.common.redux.global.FiatCurrencyName +import java.math.BigDecimal + +data class TotalBalance( + val state: State, + val fiatAmount: BigDecimal, + val fiatCurrencyName: FiatCurrencyName, +) { + enum class State { + Loading, + Failed, + Success + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index 278ccee818..b9e63b7190 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -20,6 +20,7 @@ import com.tangem.tap.domain.tokens.BlockchainNetwork import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState import com.tangem.tap.features.tokens.redux.TokenWithBlockchain import com.tangem.tap.features.wallet.models.PendingTransaction +import com.tangem.tap.features.wallet.models.TotalBalance import com.tangem.tap.features.wallet.models.toPendingTransactions import com.tangem.tap.features.wallet.models.toPendingTransactionsForToken import com.tangem.tap.features.wallet.ui.BalanceStatus @@ -44,6 +45,7 @@ data class WalletState( val primaryBlockchain: Blockchain? = null, val primaryToken: Token? = null, val isTestnet: Boolean = false, + val totalBalance: TotalBalance? = null, ) : StateType { // if you do not delegate - the application crashes on startup, @@ -196,18 +198,20 @@ data class WalletState( return copy(wallets = replaceWalletInWallets(walletStore)) } - fun updateWalletStores(walletStores: List): WalletState { - val walletStores = walletStores.toMutableList() + private fun updateWalletStores(walletStores: List): WalletState { + val walletStoresMutable = walletStores.toMutableList() val updatedWallets = wallets.map { oldWalletStore -> - val walletStore = walletStores.find { it.blockchainNetwork == oldWalletStore.blockchainNetwork } + val walletStore = walletStoresMutable.find { + it.blockchainNetwork == oldWalletStore.blockchainNetwork + } if (walletStore != null) { - walletStores.remove(walletStore) + walletStoresMutable.remove(walletStore) walletStore } else { oldWalletStore } } - return copy(wallets = updatedWallets + walletStores) + return copy(wallets = updatedWallets + walletStoresMutable) } fun removeWallet(walletData: WalletData?): WalletState { @@ -268,6 +272,14 @@ data class WalletState( ) } } + + fun updateTotalBalance( + totalBalance: TotalBalance + ): WalletState { + return this.copy( + totalBalance = totalBalance + ) + } } sealed class WalletDialog : StateDialog { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/OnWalletLoadedReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/OnWalletLoadedReducer.kt index acd7c4d8b7..1809910e90 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/OnWalletLoadedReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/OnWalletLoadedReducer.kt @@ -9,6 +9,7 @@ import com.tangem.tap.common.extensions.toFormattedCurrencyString import com.tangem.tap.common.extensions.toFormattedFiatValue import com.tangem.tap.domain.getFirstToken import com.tangem.tap.domain.tokens.BlockchainNetwork +import com.tangem.tap.features.wallet.models.TotalBalance import com.tangem.tap.features.wallet.models.removeUnknownTransactions import com.tangem.tap.features.wallet.models.toPendingTransactions import com.tangem.tap.features.wallet.redux.* @@ -16,6 +17,7 @@ import com.tangem.tap.features.wallet.ui.BalanceStatus import com.tangem.tap.features.wallet.ui.BalanceWidgetData import com.tangem.tap.features.wallet.ui.TokenData import com.tangem.tap.store +import java.math.BigDecimal import java.math.RoundingMode class OnWalletLoadedReducer { @@ -33,13 +35,12 @@ class OnWalletLoadedReducer { blockchainNetwork: BlockchainNetwork, walletState: WalletState ): WalletState { + val walletData = walletState.getWalletData(blockchainNetwork) ?: return walletState + val fiatCurrencySymbol = store.state.globalState.appCurrency val exchangeManager = store.state.globalState.currencyExchangeManager val coinAmountValue = wallet.amounts[AmountType.Coin]?.value - if (walletState.getWalletData(blockchainNetwork) == null) { - return walletState - } val formattedAmount = coinAmountValue?.toFormattedCurrencyString( wallet.blockchain.decimals(), wallet.blockchain.currency @@ -54,10 +55,9 @@ class OnWalletLoadedReducer { } else { BalanceStatus.VerifiedOnline } - val walletData = walletState.getWalletData(blockchainNetwork) - val fiatAmount = walletData?.fiatRate?.let { coinAmountValue?.toFiatValue(it) } - val newWalletData = walletData?.copy( + val fiatAmount = walletData.fiatRate?.let { coinAmountValue?.toFiatValue(it) } + val newWalletData = walletData.copy( currencyData = walletData.currencyData.copy( status = balanceStatus, currency = wallet.blockchain.fullName, currencySymbol = wallet.blockchain.currency, @@ -87,7 +87,7 @@ class OnWalletLoadedReducer { val tokenFiatAmount = tokenWalletData?.fiatRate?.let { rate -> tokenAmountValue?.toFiatValue(rate) } - val tokenSendButton = newWalletData?.shouldEnableTokenSendButton() == true + val tokenSendButton = newWalletData.shouldEnableTokenSendButton() && tokenPendingTransactions.isEmpty() tokenWalletData?.copy( currencyData = tokenWalletData.currencyData.copy( @@ -106,18 +106,27 @@ class OnWalletLoadedReducer { tradeCryptoState = TradeCryptoState.from(exchangeManager, tokenWalletData), ) } - val newWallets = (tokens + newWalletData).mapNotNull { it } + val newWallets = tokens + newWalletData val wallets = walletState.replaceSomeWallets((newWallets)) + val totalBalance = TotalBalance( + state = wallets.findTotalBalanceState(), + fiatAmount = wallets.calculateTotalFiatAmount(), + fiatCurrencyName = fiatCurrencySymbol, + ) + val state = if (wallets.any { it.currencyData.status == BalanceStatus.Loading }) { ProgressState.Loading } else { ProgressState.Done } - val newState = walletState.updateWalletsData(wallets) - return newState.copy( - state = state, error = null - ) + return walletState + .updateWalletsData(wallets) + .updateTotalBalance(totalBalance) + .copy( + state = state, + error = null + ) } private fun onSingleWalletLoaded(wallet: Wallet, walletState: WalletState): WalletState { @@ -183,4 +192,48 @@ class OnWalletLoadedReducer { state = ProgressState.Done, error = null ) } + + private fun List.findTotalBalanceState(): TotalBalance.State { + return this.mapToTotalBalanceState() + .fold(initial = TotalBalance.State.Loading) { accState, newState -> + accState or newState + } + } + + private fun List.calculateTotalFiatAmount(): BigDecimal { + return this.map { it.currencyData.fiatAmount ?: BigDecimal.ZERO } + .reduce(BigDecimal::plus) + } + + private fun List.mapToTotalBalanceState(): List { + return this.map { + when (it.currencyData.status) { + BalanceStatus.VerifiedOnline, + BalanceStatus.SameCurrencyTransactionInProgress, + BalanceStatus.TransactionInProgress -> TotalBalance.State.Success + BalanceStatus.Unreachable, + BalanceStatus.NoAccount, + BalanceStatus.EmptyCard, + BalanceStatus.UnknownBlockchain -> TotalBalance.State.Failed + BalanceStatus.Loading, + null -> TotalBalance.State.Loading + } + } + } + + infix fun TotalBalance.State.or(newState: TotalBalance.State): TotalBalance.State { + return when (this) { + TotalBalance.State.Loading -> when (newState) { + TotalBalance.State.Loading -> this + TotalBalance.State.Failed, + TotalBalance.State.Success -> newState + } + TotalBalance.State.Success, + TotalBalance.State.Failed -> when (newState) { + TotalBalance.State.Loading, + TotalBalance.State.Failed -> newState + TotalBalance.State.Success -> this + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index 16c85a88fb..fc97a44777 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -12,6 +12,7 @@ import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.currenciesRepository import com.tangem.tap.features.tokens.redux.TokensAction +import com.tangem.tap.features.wallet.models.TotalBalance import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletDialog import com.tangem.tap.features.wallet.redux.WalletState @@ -51,6 +52,7 @@ class MultiWalletView : WalletView { btnScanMultiwallet.show() rvMultiwallet.show() btnAddToken.show() + lCardTotalBalance.root.show() setupWalletCardNumber(binding) } @@ -97,6 +99,7 @@ class MultiWalletView : WalletView { val fragment = fragment ?: return val binding = binding ?: return + state.totalBalance?.let { handleTotalBalance(binding, it) } walletsAdapter.submitList(state.walletsData, state.primaryBlockchain, state.primaryToken) binding.btnAddToken.setOnClickListener { @@ -127,6 +130,20 @@ class MultiWalletView : WalletView { handleDialogs(state.walletDialog) } + private fun handleTotalBalance( + binding: FragmentWalletBinding, + totalBalance: TotalBalance, + ) = with(binding.lCardTotalBalance) { + val fiatAmountFormatted = with(totalBalance) { + "${fiatAmount.stripTrailingZeros()} $fiatCurrencyName" + } + tvBalance.text = fiatAmountFormatted + tvCurrencyName.text = totalBalance.fiatCurrencyName + tvCurrencyName.setOnClickListener { + // TODO: Open app currency selector + } + } + private fun handleErrorStates( state: WalletState, binding: FragmentWalletBinding, @@ -148,6 +165,8 @@ class MultiWalletView : WalletView { fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle) ) } + else -> { /* no-op */ + } } } diff --git a/app/src/main/res/layout/card_total_balance.xml b/app/src/main/res/layout/card_total_balance.xml new file mode 100644 index 0000000000..51fa4aecb7 --- /dev/null +++ b/app/src/main/res/layout/card_total_balance.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_wallet.xml b/app/src/main/res/layout/fragment_wallet.xml index bc98ff9e41..829a1f019b 100644 --- a/app/src/main/res/layout/fragment_wallet.xml +++ b/app/src/main/res/layout/fragment_wallet.xml @@ -101,16 +101,26 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/barrier" /> + + + app:layout_constraintTop_toBottomOf="@id/l_card_total_balance" /> - \ No newline at end of file + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 9a0a6881fd..014599d80e 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -382,4 +382,5 @@ Привет, команда поддержки, Пожалуйста, расскажите нам больше о Вашей проблеме. Каждая деталь может быть полезной. Информация ниже не является обязательной. Вы можете стереть её, если хотите. - \ No newline at end of file + Баланс + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c3e70dee2f..82023e7837 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -206,4 +206,5 @@ To avoid paying an increased commission the next time you top up your wallet, reduce the amount by %s XTZ Reduce by %s XTZ No, send all - \ No newline at end of file + Total balance + From 714eaf5668c2cf0a4c1cc89b2415455812b04e8e Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 18 May 2022 11:20:42 +0300 Subject: [PATCH 010/111] Updated on 2026-08-14 --- .../tap/common/entities/FiatCurrency.kt | 18 +++++++++ .../tangem/tap/common/extensions/Specific.kt | 10 +++-- .../tap/common/extensions/WalletManager.kt | 2 +- .../tap/common/redux/global/GlobalAction.kt | 5 ++- .../tap/common/redux/global/GlobalState.kt | 5 +-- .../features/details/redux/DetailsAction.kt | 11 +++--- .../details/redux/DetailsMiddleware.kt | 35 +++++++++++++++--- .../features/details/redux/DetailsReducer.kt | 5 ++- .../features/details/redux/DetailsState.kt | 8 ++-- .../details/ui/CurrencySelectionDialog.kt | 36 +++++++++++------- .../features/details/ui/DetailsFragment.kt | 8 ++-- .../send/redux/reducers/ReceiptReducer.kt | 2 +- .../features/send/redux/states/SendState.kt | 28 +++++++------- .../tap/features/send/ui/SendFragment.kt | 11 +++--- .../features/wallet/models/TotalBalance.kt | 4 +- .../middlewares/TradeCryptoMiddleware.kt | 5 ++- .../redux/middlewares/WalletMiddleware.kt | 4 +- .../redux/reducers/MultiWalletReducer.kt | 2 +- .../redux/reducers/OnWalletLoadedReducer.kt | 14 +++---- .../wallet/redux/reducers/WalletReducer.kt | 37 +++++++++++++------ .../CurrencyExchangeManager.kt | 12 ++++-- 21 files changed, 165 insertions(+), 97 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/entities/FiatCurrency.kt diff --git a/app/src/main/java/com/tangem/tap/common/entities/FiatCurrency.kt b/app/src/main/java/com/tangem/tap/common/entities/FiatCurrency.kt new file mode 100644 index 0000000000..c0df80eb2a --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/entities/FiatCurrency.kt @@ -0,0 +1,18 @@ +package com.tangem.tap.common.entities + +data class FiatCurrency( + val code: String, + val name: String, + val symbol: String, +) { + val displayName: String + get() = "${this.name} (${this.code}) - ${this.symbol}" + + companion object { + val Default = FiatCurrency( + symbol = "$", + code = "USD", + name = "US Dollar", + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt index 4b978e18f6..c7386eb7f0 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt @@ -1,8 +1,10 @@ package com.tangem.tap.common.extensions +import android.text.Spanned +import android.text.SpannedString +import android.text.style.RelativeSizeSpan +import androidx.core.text.buildSpannedString import com.tangem.common.extensions.isZero -import com.tangem.network.api.tangemTech.CurrenciesResponse -import com.tangem.tap.common.redux.global.FiatCurrencyName import java.math.BigDecimal import java.math.RoundingMode import java.text.DecimalFormat @@ -37,7 +39,7 @@ fun BigDecimal.toFormattedCurrencyString( return "$formattedAmount $currency" } -fun BigDecimal.toFiatString(rateValue: BigDecimal, fiatCurrencyName: FiatCurrencyName): String { +fun BigDecimal.toFiatString(rateValue: BigDecimal, fiatCurrencyName: String): String { var fiatValue = rateValue.multiply(this) fiatValue = fiatValue.setScale(2, RoundingMode.HALF_UP) return "≈ ${fiatCurrencyName}  $fiatValue" @@ -48,7 +50,7 @@ fun BigDecimal.toFiatValue(rateValue: BigDecimal): BigDecimal { return fiatValue.setScale(2, RoundingMode.HALF_UP) } -fun BigDecimal.toFormattedFiatValue(fiatCurrencyName: FiatCurrencyName): String { +fun BigDecimal.toFormattedFiatValue(fiatCurrencyName: String): String { return "≈ ${fiatCurrencyName}  $this" } diff --git a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt index 540d23c3f7..d671b60a29 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt @@ -57,7 +57,7 @@ fun WalletManager?.getToUpUrl(): String? { action = CurrencyExchangeManager.Action.Buy, blockchain = wallet.blockchain, cryptoCurrencyName = wallet.blockchain.currency, - fiatCurrency = globalState.appCurrency, + fiatCurrencyName = globalState.appCurrency.code, walletAddress = defaultAddress, ) } diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt index 21fd824d71..b871b7853f 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt @@ -6,6 +6,7 @@ import com.tangem.common.CompletionResult import com.tangem.common.core.TangemError import com.tangem.domain.common.ScanResponse import com.tangem.tap.common.analytics.GlobalAnalyticsHandler +import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.redux.* import com.tangem.tap.domain.TapError import com.tangem.tap.domain.configurable.config.ConfigManager @@ -54,9 +55,9 @@ sealed class GlobalAction : Action { data class SetIfCardVerifiedOnline(val verified: Boolean) : GlobalAction() - data class ChangeAppCurrency(val appCurrency: FiatCurrencyName) : GlobalAction() + data class ChangeAppCurrency(val appCurrency: FiatCurrency) : GlobalAction() object RestoreAppCurrency : GlobalAction() { - data class Success(val appCurrency: FiatCurrencyName) : GlobalAction() + data class Success(val appCurrency: FiatCurrency) : GlobalAction() } data class UpdateWalletSignedHashes( diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt index a58e92b944..75504f3ef2 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt @@ -2,7 +2,7 @@ package com.tangem.tap.common.redux.global import com.tangem.domain.common.ScanResponse import com.tangem.tap.common.analytics.AnalyticsHandler -import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY +import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.domain.PayIdManager import com.tangem.tap.domain.TapWalletManager @@ -22,7 +22,7 @@ data class GlobalState( val configManager: ConfigManager? = null, val warningManager: WarningMessagesManager? = null, val feedbackManager: FeedbackManager? = null, - val appCurrency: FiatCurrencyName = DEFAULT_FIAT_CURRENCY, + val appCurrency: FiatCurrency = FiatCurrency.Default, val scanCardFailsCounter: Int = 0, val dialog: StateDialog? = null, val currencyExchangeManager: CurrencyExchangeManager? = null, @@ -40,7 +40,6 @@ data class AndroidResources( ) } typealias CryptoCurrencyName = String -typealias FiatCurrencyName = String data class OnboardingState( val onboardingStarted: Boolean = false, diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt index 5b572f8fff..16c5bbd1c8 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -4,11 +4,10 @@ import com.tangem.blockchain.common.Wallet import com.tangem.common.card.Card import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.TwinCardNumber -import com.tangem.network.api.tangemTech.CurrenciesResponse import com.tangem.network.api.tangemTech.TangemTechService import com.tangem.operations.pins.CheckUserCodesResponse +import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.redux.NotificationAction -import com.tangem.tap.common.redux.global.FiatCurrencyName import com.tangem.tap.domain.termsOfUse.CardTou import com.tangem.wallet.R import org.rekotlin.Action @@ -19,8 +18,8 @@ sealed class DetailsAction : Action { val scanResponse: ScanResponse, val wallets: List, val cardTou: CardTou, - val fiatCurrencyName: FiatCurrencyName, - val fiatCurrencies: List? = null, + val fiatCurrencyName: FiatCurrency, + val fiatCurrencies: List? = null, val tangemTechService: TangemTechService, ) : DetailsAction() @@ -48,10 +47,10 @@ sealed class DetailsAction : Action { object CreateBackup : DetailsAction() sealed class AppCurrencyAction : DetailsAction() { - data class SetCurrencies(val currencies: List) : AppCurrencyAction() + data class SetCurrencies(val currencies: List) : AppCurrencyAction() object ChooseAppCurrency : AppCurrencyAction() object Cancel : AppCurrencyAction() - data class SelectAppCurrency(val fiatCurrencyName: FiatCurrencyName) : AppCurrencyAction() + data class SelectAppCurrency(val fiatCurrency: FiatCurrency) : AppCurrencyAction() } sealed class ManageSecurity : DetailsAction() { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index 9f1b6b6187..e938026085 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -4,10 +4,12 @@ import com.tangem.common.CompletionResult import com.tangem.common.card.FirmwareVersion import com.tangem.common.core.TangemSdkError import com.tangem.common.services.Result +import com.tangem.network.api.tangemTech.CurrenciesResponse import com.tangem.operations.pins.CheckUserCodesResponse import com.tangem.tap.* import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsParam +import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.dispatchNotification import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.redux.AppState @@ -71,7 +73,11 @@ class DetailsMiddleware { val fiatCurrenciesPrefStorage = preferencesStorage.fiatCurrenciesPrefStorage val storedFiatCurrencies = fiatCurrenciesPrefStorage.restore() if (storedFiatCurrencies.isNotEmpty()) { - store.dispatch(DetailsAction.AppCurrencyAction.SetCurrencies(storedFiatCurrencies)) + store.dispatch( + DetailsAction.AppCurrencyAction.SetCurrencies( + currencies = storedFiatCurrencies.mapToUiModel() + ) + ) } scope.launch { @@ -79,9 +85,15 @@ class DetailsMiddleware { when (val result = tangemTechService.currencies()) { is Result.Success -> { val currenciesList = result.data.currencies - if (currenciesList.isNotEmpty() && currenciesList.toSet() != storedFiatCurrencies.toSet()) { + if (currenciesList.isNotEmpty() && + currenciesList.toSet() != storedFiatCurrencies.toSet() + ) { fiatCurrenciesPrefStorage.save(currenciesList) - dispatchOnMain(DetailsAction.AppCurrencyAction.SetCurrencies(currenciesList)) + dispatchOnMain( + DetailsAction.AppCurrencyAction.SetCurrencies( + currencies = currenciesList.mapToUiModel() + ) + ) } } is Result.Failure -> {} @@ -89,7 +101,17 @@ class DetailsMiddleware { } } - class EraseWalletMiddleware() { + private fun List.mapToUiModel(): List { + return this.map { + FiatCurrency( + code = it.code, + name = it.name, + symbol = it.unit + ) + } + } + + class EraseWalletMiddleware { fun handle(action: DetailsAction.ResetToFactory) { when (action) { is DetailsAction.ResetToFactory.Proceed -> { @@ -137,8 +159,9 @@ class DetailsMiddleware { when (action) { is DetailsAction.AppCurrencyAction.SelectAppCurrency -> { store.state.globalState.tapWalletManager.rates.clear() - preferencesStorage.saveAppCurrency(action.fiatCurrencyName) - store.dispatch(GlobalAction.ChangeAppCurrency(action.fiatCurrencyName)) + preferencesStorage.fiatCurrenciesPrefStorage + .saveAppCurrency(action.fiatCurrency) + store.dispatch(GlobalAction.ChangeAppCurrency(action.fiatCurrency)) store.dispatch(WalletAction.LoadFiatRate()) } } diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index 796c7c171f..a000db965e 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -49,7 +49,7 @@ private fun handlePrepareScreen( wallets = action.wallets, cardInfo = action.scanResponse.card.toCardInfo(), appCurrencyState = state.appCurrencyState.copy( - fiatCurrencyName = action.fiatCurrencyName, + currentFiatCurrency = action.fiatCurrencyName, showAppCurrencyDialog = false, ), cardTermsOfUseUrl = action.cardTou.getUrl(action.scanResponse.card), @@ -109,7 +109,8 @@ private fun handleAppCurrencyAction( is DetailsAction.AppCurrencyAction.SelectAppCurrency -> { state.copy( appCurrencyState = state.appCurrencyState.copy( - fiatCurrencyName = action.fiatCurrencyName, showAppCurrencyDialog = false + currentFiatCurrency = action.fiatCurrency, + showAppCurrencyDialog = false ) ) } diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt index 0d2cf689d5..1315f43e15 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt @@ -3,10 +3,8 @@ package com.tangem.tap.features.details.redux import android.net.Uri import com.tangem.blockchain.common.Wallet import com.tangem.domain.common.ScanResponse -import com.tangem.network.api.tangemTech.CurrenciesResponse import com.tangem.tap.common.entities.Button -import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY -import com.tangem.tap.common.redux.global.FiatCurrencyName +import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState import com.tangem.tap.store import org.rekotlin.StateType @@ -53,7 +51,7 @@ data class SecurityScreenState( enum class SecurityOption { LongTap, PassCode, AccessCode } data class AppCurrencyState( - val fiatCurrencyName: FiatCurrencyName = DEFAULT_FIAT_CURRENCY, + val currentFiatCurrency: FiatCurrency = FiatCurrency.Default, val showAppCurrencyDialog: Boolean = false, - val fiatCurrencies: List? = null, + val fiatCurrencies: List? = null, ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/CurrencySelectionDialog.kt b/app/src/main/java/com/tangem/tap/features/details/ui/CurrencySelectionDialog.kt index d7248b75c8..23e79bd846 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/CurrencySelectionDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/CurrencySelectionDialog.kt @@ -2,9 +2,7 @@ package com.tangem.tap.features.details.ui import android.content.Context import androidx.appcompat.app.AlertDialog -import com.tangem.network.api.tangemTech.CurrenciesResponse -import com.tangem.tap.common.extensions.toFormattedString -import com.tangem.tap.common.redux.global.FiatCurrencyName +import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.store import com.tangem.wallet.R @@ -13,20 +11,30 @@ class CurrencySelectionDialog { var dialog: AlertDialog? = null - fun show(currenciesList: List, currentAppCurrency: FiatCurrencyName, context: Context) { - + fun show( + currenciesList: List, + currentAppCurrency: FiatCurrency, + context: Context + ) { if (dialog == null) { - val currenciesToShow = currenciesList.map { it.toFormattedString() }.toTypedArray() - var currentSelection = currenciesList.indexOfFirst { it.code == currentAppCurrency } + val currenciesToShow = currenciesList + .map { it.displayName } + .toTypedArray() + var currentSelection = currenciesList + .indexOfFirst { it.code == currentAppCurrency.code } dialog = AlertDialog.Builder(context) - .setTitle(context.getString(R.string.details_row_title_currency)) - .setNegativeButton(context.getString(R.string.common_cancel)) { _, _ -> - store.dispatch(DetailsAction.AppCurrencyAction.Cancel) - } - .setPositiveButton(context.getString(R.string.common_done)) { _, _ -> - val selectedCurrency = currenciesList[currentSelection] - store.dispatch(DetailsAction.AppCurrencyAction.SelectAppCurrency(selectedCurrency.code)) + .setTitle(context.getString(R.string.details_row_title_currency)) + .setNegativeButton(context.getString(R.string.common_cancel)) { _, _ -> + store.dispatch(DetailsAction.AppCurrencyAction.Cancel) + } + .setPositiveButton(context.getString(R.string.common_done)) { _, _ -> + val selectedCurrency = currenciesList[currentSelection] + store.dispatch( + DetailsAction.AppCurrencyAction.SelectAppCurrency( + fiatCurrency = selectedCurrency + ) + ) } .setOnDismissListener { store.dispatch(DetailsAction.AppCurrencyAction.Cancel) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt index 781ba05548..2dbab2ee0b 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt @@ -115,7 +115,7 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber amountType.token.symbol diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt index ed98986ae3..98fbfa47e1 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt @@ -5,8 +5,8 @@ import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.WalletManager import com.tangem.common.extensions.isZero import com.tangem.tap.common.CurrencyConverter +import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.entities.IndeterminateProgressButton -import com.tangem.tap.common.entities.TapCurrency import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.common.text.DecimalDigitsInputFilter import com.tangem.tap.domain.TapError @@ -123,18 +123,18 @@ enum class ButtonState { } data class AmountState( - val amountToExtract: Amount? = null, - val typeOfAmount: AmountType = AmountType.Coin, - val viewAmountValue: InputViewValue = InputViewValue(BigDecimal.ZERO.toPlainString()), - val viewBalanceValue: String = BigDecimal.ZERO.toPlainString(), - val mainCurrency: MainCurrency = MainCurrency(MainCurrencyType.FIAT, TapCurrency.DEFAULT_FIAT_CURRENCY), - val amountToSendCrypto: BigDecimal = BigDecimal.ZERO, - val balanceCrypto: BigDecimal = BigDecimal.ZERO, - val cursorAtTheSamePosition: Boolean = true, - val maxLengthOfAmount: Int = 2, - val decimalSeparator: String = ".", - val error: TapError? = null, - val inputIsEnabled: Boolean = true, + val amountToExtract: Amount? = null, + val typeOfAmount: AmountType = AmountType.Coin, + val viewAmountValue: InputViewValue = InputViewValue(BigDecimal.ZERO.toPlainString()), + val viewBalanceValue: String = BigDecimal.ZERO.toPlainString(), + val mainCurrency: MainCurrency = MainCurrency(MainCurrencyType.FIAT, FiatCurrency.Default.code), + val amountToSendCrypto: BigDecimal = BigDecimal.ZERO, + val balanceCrypto: BigDecimal = BigDecimal.ZERO, + val cursorAtTheSamePosition: Boolean = true, + val maxLengthOfAmount: Int = 2, + val decimalSeparator: String = ".", + val error: TapError? = null, + val inputIsEnabled: Boolean = true, ) : SendScreenState { override val stateId: StateId = StateId.AMOUNT @@ -146,7 +146,7 @@ data class AmountState( fun createMainCurrency(type: MainCurrencyType, canSwitched: Boolean): MainCurrency { return if (!canSwitched) MainCurrency(type, amountToExtract?.currencySymbol ?: "NONE", false) else when (type) { - MainCurrencyType.FIAT -> MainCurrency(type, store.state.globalState.appCurrency) + MainCurrencyType.FIAT -> MainCurrency(type, store.state.globalState.appCurrency.code) MainCurrencyType.CRYPTO -> MainCurrency(type, amountToExtract?.currencySymbol ?: "NONE") } } diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt index d999d79bcb..4fa59376fb 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt @@ -17,7 +17,7 @@ import com.tangem.Message import com.tangem.tangem_sdk_new.extensions.dpToPx import com.tangem.tangem_sdk_new.extensions.hideSoftKeyboard import com.tangem.tap.common.KeyboardObserver -import com.tangem.tap.common.entities.TapCurrency +import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.getFromClipboard import com.tangem.tap.common.extensions.setOnImeActionListener import com.tangem.tap.common.qrCodeScan.ScanQrCodeActivity @@ -261,11 +261,10 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { private fun restoreMainCurrency(): MainCurrencyType { val sp = requireContext().getSharedPreferences("SendScreen", Context.MODE_PRIVATE) - val mainCurrency = sp.getString("mainCurrency", TapCurrency.DEFAULT_FIAT_CURRENCY) - val foundType = MainCurrencyType.values() - .firstOrNull { it.name.equals(mainCurrency!!, ignoreCase = true) } - ?: MainCurrencyType.CRYPTO - return foundType + val mainCurrency = sp.getString("mainCurrency", FiatCurrency.Default.code) + return MainCurrencyType.values() + .firstOrNull { it.name.equals(mainCurrency!!, ignoreCase = true) } + ?: MainCurrencyType.CRYPTO } fun saveMainCurrency(type: MainCurrencyType) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt index 31cc8a8d7f..16676936e5 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt @@ -1,12 +1,12 @@ package com.tangem.tap.features.wallet.models -import com.tangem.tap.common.redux.global.FiatCurrencyName +import com.tangem.tap.common.entities.FiatCurrency import java.math.BigDecimal data class TotalBalance( val state: State, val fiatAmount: BigDecimal, - val fiatCurrencyName: FiatCurrencyName, + val fiatCurrency: FiatCurrency, ) { enum class State { Loading, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index 90796fd143..45e34c15f9 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -61,8 +61,9 @@ class TradeCryptoMiddleware { action = exchangeAction, blockchain = currency.blockchain, cryptoCurrencyName = currencySymbol, - fiatCurrency = appCurrency, - walletAddress = defaultAddress)?.let { store.dispatchOnMain(NavigationAction.OpenUrl(it)) } + fiatCurrencyName = appCurrency.code, + walletAddress = defaultAddress + )?.let { store.dispatchOnMain(NavigationAction.OpenUrl(it)) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 034122f2c1..8b9033964d 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -104,7 +104,7 @@ class WalletMiddleware { warningsMiddleware.tryToShowAppRatingWarning(action.wallet) } is WalletAction.LoadFiatRate -> { - val appCurrencyId = globalState.appCurrency + val appCurrencyId = globalState.appCurrency.code scope.launch { val coinsList = when { action.wallet != null -> { @@ -344,4 +344,4 @@ class WalletMiddleware { } } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt index 21e3ed698f..a7437c94eb 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt @@ -126,7 +126,7 @@ class MultiWalletReducer { ), fiatAmountFormatted = tokenWalletData.fiatRate?.let { action.amount.value - ?.toFiatString(it, store.state.globalState.appCurrency) + ?.toFiatString(it, store.state.globalState.appCurrency.code) }, blockchainAmount = wallet.amounts[AmountType.Coin]?.value ?: BigDecimal.ZERO ), diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/OnWalletLoadedReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/OnWalletLoadedReducer.kt index 1809910e90..3f4b539e20 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/OnWalletLoadedReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/OnWalletLoadedReducer.kt @@ -37,7 +37,7 @@ class OnWalletLoadedReducer { ): WalletState { val walletData = walletState.getWalletData(blockchainNetwork) ?: return walletState - val fiatCurrencySymbol = store.state.globalState.appCurrency + val fiatCurrency = store.state.globalState.appCurrency val exchangeManager = store.state.globalState.currencyExchangeManager val coinAmountValue = wallet.amounts[AmountType.Coin]?.value @@ -65,7 +65,7 @@ class OnWalletLoadedReducer { amount = coinAmountValue, amountFormatted = formattedAmount, fiatAmount = fiatAmount, - fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(fiatCurrencySymbol) + fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(fiatCurrency.code) ), pendingTransactions = pendingTransactions.removeUnknownTransactions(), mainButton = WalletMainButton.SendButton(coinSendButton), @@ -99,7 +99,7 @@ class OnWalletLoadedReducer { token.symbol ), fiatAmount = tokenFiatAmount, - fiatAmountFormatted = tokenFiatAmount?.toFormattedFiatValue(fiatCurrencySymbol) + fiatAmountFormatted = tokenFiatAmount?.toFormattedFiatValue(fiatCurrency.code) ), pendingTransactions = tokenPendingTransactions.removeUnknownTransactions(), mainButton = WalletMainButton.SendButton(tokenSendButton), @@ -112,7 +112,7 @@ class OnWalletLoadedReducer { val totalBalance = TotalBalance( state = wallets.findTotalBalanceState(), fiatAmount = wallets.calculateTotalFiatAmount(), - fiatCurrencyName = fiatCurrencySymbol, + fiatCurrency = fiatCurrency, ) val state = if (wallets.any { it.currencyData.status == BalanceStatus.Loading }) { @@ -132,7 +132,7 @@ class OnWalletLoadedReducer { private fun onSingleWalletLoaded(wallet: Wallet, walletState: WalletState): WalletState { if (wallet.blockchain != walletState.primaryBlockchain) return walletState - val fiatCurrencySymbol = store.state.globalState.appCurrency + val fiatCurrencyName = store.state.globalState.appCurrency.code val exchangeManager = store.state.globalState.currencyExchangeManager val token = wallet.getFirstToken() @@ -141,7 +141,7 @@ class OnWalletLoadedReducer { if (tokenAmount != null) { val tokenFiatRate = walletState.primaryWallet?.currencyData?.token?.fiatRate val tokenFiatAmount = - tokenFiatRate?.let { tokenAmount.value?.toFiatString(it, fiatCurrencySymbol) } + tokenFiatRate?.let { tokenAmount.value?.toFiatString(it, fiatCurrencyName) } TokenData( tokenAmount.value?.toFormattedCurrencyString( token.decimals, token.symbol @@ -161,7 +161,7 @@ class OnWalletLoadedReducer { ) val fiatRate = walletState.primaryWallet?.fiatRate val fiatAmountRaw = fiatRate?.multiply(amount)?.setScale(2, RoundingMode.DOWN) - val fiatAmount = fiatRate?.let { amount?.toFiatString(it, fiatCurrencySymbol) } + val fiatAmount = fiatRate?.let { amount?.toFiatString(it, fiatCurrencyName) } val pendingTransactions = wallet.recentTransactions.toPendingTransactions(wallet.address) val sendButtonEnabled = amount?.isZero() == false && pendingTransactions.isEmpty() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index 97e6e778ec..3219b7cd2f 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -4,12 +4,12 @@ import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Wallet import com.tangem.domain.common.TwinCardNumber +import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.toFiatString import com.tangem.tap.common.extensions.toFiatValue import com.tangem.tap.common.extensions.toFormattedCurrencyString import com.tangem.tap.common.extensions.toFormattedFiatValue import com.tangem.tap.common.redux.AppState -import com.tangem.tap.common.redux.global.FiatCurrencyName import com.tangem.tap.domain.TapError import com.tangem.tap.domain.extensions.getArtworkUrl import com.tangem.tap.domain.getFirstToken @@ -377,22 +377,30 @@ private fun handleCheckSignedHashesActions( private fun setNewFiatRate( fiatRate: Pair, - appCurrency: FiatCurrencyName, state: WalletState + appCurrency: FiatCurrency, + state: WalletState ): WalletState { val rate = fiatRate.second ?: return state - val rateFormatted = rate.toFormattedCurrencyString(2, appCurrency, RoundingMode.HALF_UP) + val rateFormatted = rate.toFormattedCurrencyString( + decimals = 2, + currency = appCurrency.code, + roundingMode = RoundingMode.HALF_UP + ) val currency = fiatRate.first return if (!state.isMultiwalletAllowed) { - setSingeWalletFiatRate(rate, rateFormatted, currency, appCurrency, state) + setSingleWalletFiatRate(rate, rateFormatted, currency, appCurrency, state) } else { setMultiWalletFiatRate(rate, rateFormatted, currency, appCurrency, state) } } private fun setMultiWalletFiatRate( - rate: BigDecimal, rateFormatted: String, currency: Currency, - appCurrency: FiatCurrencyName, state: WalletState + rate: BigDecimal, + rateFormatted: String, + currency: Currency, + appCurrency: FiatCurrency, + state: WalletState ): WalletState { val walletStore = state.getWalletStore(currency) ?: return state @@ -405,7 +413,7 @@ private fun setMultiWalletFiatRate( is Currency.Token -> wallet?.getTokenAmount(currency.token)?.value?.toFiatValue(rate) } - val fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(appCurrency) + val fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(appCurrency.code) val newWalletData = state.getWalletData(currency)?.copy( currencyData = walletData.currencyData.copy( fiatAmountFormatted = fiatAmountFormatted, @@ -416,16 +424,19 @@ private fun setMultiWalletFiatRate( return state.updateWalletData(newWalletData) } -private fun setSingeWalletFiatRate( - rate: BigDecimal, rateFormatted: String, currency: Currency, - appCurrency: FiatCurrencyName, state: WalletState +private fun setSingleWalletFiatRate( + rate: BigDecimal, + rateFormatted: String, + currency: Currency, + appCurrency: FiatCurrency, + state: WalletState ): WalletState { val wallet = state.primaryWalletManager?.wallet ?: return state val token = wallet.getFirstToken() if (currency == state.primaryWallet?.currency) { val fiatAmount = wallet.amounts[AmountType.Coin]?.value - ?.toFiatString(rate, appCurrency) + ?.toFiatString(rate, appCurrency.code) val walletData = state.primaryWallet.copy( currencyData = state.primaryWallet.currencyData.copy(fiatAmountFormatted = fiatAmount), fiatRate = rate, @@ -433,7 +444,9 @@ private fun setSingeWalletFiatRate( ) return state.updateWalletData(walletData) } else if (currency is Currency.Token && currency.token == token) { - val tokenFiatAmount = wallet.getTokenAmount(token)?.value?.toFiatString(rate, appCurrency) + val tokenFiatAmount = wallet.getTokenAmount(token) + ?.value + ?.toFiatString(rate, appCurrency.code) val tokenData = state.primaryWallet?.currencyData?.token?.copy( fiatAmount = tokenFiatAmount, fiatRate = rate, diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt index a6e9c55cba..7a89edc4b0 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt @@ -30,7 +30,7 @@ interface ExchangeUrlBuilder { action: CurrencyExchangeManager.Action, blockchain: Blockchain, cryptoCurrencyName: CryptoCurrencyName, - fiatCurrency: String, + fiatCurrencyName: String, walletAddress: String, ): String? @@ -74,13 +74,19 @@ class CurrencyExchangeManager( action: Action, blockchain: Blockchain, cryptoCurrencyName: CryptoCurrencyName, - fiatCurrency: String, + fiatCurrencyName: String, walletAddress: String, ): String? { if (blockchain.isTestnet()) return blockchain.getTestnetTopUpUrl() val urlBuilder = getExchangeUrlBuilder(action) - return urlBuilder.getUrl(action, blockchain, cryptoCurrencyName, fiatCurrency, walletAddress) + return urlBuilder.getUrl( + action, + blockchain, + cryptoCurrencyName, + fiatCurrencyName, + walletAddress + ) } override fun getSellCryptoReceiptUrl(action: Action, transactionId: String): String? { From 47ffea91f29d7f8803e9294b46ef6047b3e59552 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 18 May 2022 11:29:18 +0300 Subject: [PATCH 011/111] Updated on 2026-08-14 --- .../common/redux/global/GlobalMidlleware.kt | 2 +- .../persistence/FiatCurrenciesPrefStorage.kt | 25 ++++++++++++++++--- .../tap/persistence/PreferencesStorage.kt | 12 --------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt index 722fe8a067..75dccd51ab 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt @@ -45,7 +45,7 @@ private val globalMiddlewareHandler: Middleware = { dispatch, appState } is GlobalAction.RestoreAppCurrency -> { store.dispatch(GlobalAction.RestoreAppCurrency.Success( - preferencesStorage.getAppCurrency() + preferencesStorage.fiatCurrenciesPrefStorage.getAppCurrency() )) } is GlobalAction.HideWarningMessage -> { diff --git a/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt b/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt index 3af9991f25..50a8859516 100644 --- a/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt @@ -4,6 +4,7 @@ import android.content.SharedPreferences import androidx.core.content.edit import com.tangem.common.json.MoshiJsonConverter import com.tangem.network.api.tangemTech.CurrenciesResponse +import com.tangem.tap.common.entities.FiatCurrency /** [REDACTED_AUTHOR] @@ -12,15 +13,25 @@ class FiatCurrenciesPrefStorage( private val preferences: SharedPreferences, private val converter: MoshiJsonConverter, ) { - private val FIAT_CURRENCIES_KEY_OLD = "fiatCurrencies" - private val FIAT_CURRENCIES_KEY = "fiatCurrencies_v2" - fun migrate() { preferences.edit(true) { remove(FIAT_CURRENCIES_KEY_OLD) + remove(APP_CURRENCY_KEY_OLD) } } + fun getAppCurrency(): FiatCurrency { + val json = preferences.getString(APP_CURRENCY_KEY, "") + if (json.isNullOrBlank()) return FiatCurrency.Default + + return converter.fromJson(json) ?: FiatCurrency.Default + } + + fun saveAppCurrency(fiatCurrency: FiatCurrency) { + val json = converter.toJson(fiatCurrency) + preferences.edit { putString(APP_CURRENCY_KEY, json) } + } + fun save(currencies: List) { val json: String = converter.toJson(currencies) return preferences.edit().putString(FIAT_CURRENCIES_KEY, json).apply() @@ -33,4 +44,12 @@ class FiatCurrenciesPrefStorage( return converter.fromJson(json, type) ?: emptyList() } + + companion object { + private const val FIAT_CURRENCIES_KEY_OLD = "fiatCurrencies" + private const val APP_CURRENCY_KEY_OLD = "appCurrency" + + private const val FIAT_CURRENCIES_KEY = "fiatCurrencies_v2" + private const val APP_CURRENCY_KEY = "appCurrency_v2" + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt index edc53e26fb..f676467852 100644 --- a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt @@ -5,8 +5,6 @@ import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit import com.tangem.common.json.MoshiJsonConverter -import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY -import com.tangem.tap.common.redux.global.FiatCurrencyName import java.util.* @@ -27,15 +25,6 @@ class PreferencesStorage(applicationContext: Application) { fiatCurrenciesPrefStorage.migrate() } - fun getAppCurrency(): FiatCurrencyName { - return preferences.getString(APP_CURRENCY_KEY, DEFAULT_FIAT_CURRENCY) - ?: DEFAULT_FIAT_CURRENCY - } - - fun saveAppCurrency(fiatCurrencyName: FiatCurrencyName) { - preferences.edit { putString(APP_CURRENCY_KEY, fiatCurrencyName) } - } - fun getCountOfLaunches(): Int = preferences.getInt(APP_LAUNCH_COUNT_KEY, 1) @Deprecated("Use UsedCardsPrefStorage instead") @@ -74,7 +63,6 @@ class PreferencesStorage(applicationContext: Application) { companion object { private const val PREFERENCES_NAME = "tapPrefs" - private const val APP_CURRENCY_KEY = "appCurrency" private const val DISCLAIMER_ACCEPTED_KEY = "disclaimerAccepted" private const val TWINS_ONBOARDING_SHOWN_KEY = "twinsOnboardingShown" private const val APP_LAUNCH_COUNT_KEY = "launchCount" From 355f67a325419ed6255ce7ab7e31544995bc8e25 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 18 May 2022 11:30:57 +0300 Subject: [PATCH 012/111] Updated on 2026-08-14 --- .../tangem/tap/common/extensions/Specific.kt | 24 +++++++++++++++++-- .../wallet/ui/wallet/MultiWalletView.kt | 10 ++++---- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt index c7386eb7f0..83f6b0e3aa 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt @@ -54,8 +54,6 @@ fun BigDecimal.toFormattedFiatValue(fiatCurrencyName: String): String { return "≈ ${fiatCurrencyName}  $this" } -fun CurrenciesResponse.Currency.toFormattedString(): String = "${this.name} (${this.code}) - ${this.unit}" - fun BigDecimal.stripZeroPlainString(): String = this.stripTrailingZeros().toPlainString() // 0.00 -> 0.00 @@ -89,4 +87,26 @@ fun BigDecimal.isGreaterThanOrEqual(value: BigDecimal): Boolean { fun BigDecimal.isLessThanOrEqual(value: BigDecimal): Boolean { val compareResult = this.compareTo(value) return compareResult == -1 || compareResult == 0 +} + +fun BigDecimal.formatAmountAsSpannedString( + currencySymbol: String, + integerPartSizeProportion: Float = 1.4f +): SpannedString { + val amount = this.scaleToFiat(applyPrecision = true) + .stripZeroPlainString() + val integer = amount.substringAfter('.') + val reminder = amount.substringBefore('.') + + return buildSpannedString { + append( + integer, + RelativeSizeSpan(integerPartSizeProportion), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ) + append('.') + append(reminder) + append(' ') + append(currencySymbol) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index fc97a44777..996be5039a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -5,6 +5,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.tangem.common.card.Card import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.TapWorkarounds.isTestCard +import com.tangem.tap.common.extensions.formatAmountAsSpannedString import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show import com.tangem.tap.common.redux.StateDialog @@ -134,11 +135,10 @@ class MultiWalletView : WalletView { binding: FragmentWalletBinding, totalBalance: TotalBalance, ) = with(binding.lCardTotalBalance) { - val fiatAmountFormatted = with(totalBalance) { - "${fiatAmount.stripTrailingZeros()} $fiatCurrencyName" - } - tvBalance.text = fiatAmountFormatted - tvCurrencyName.text = totalBalance.fiatCurrencyName + tvBalance.text = totalBalance.fiatAmount.formatAmountAsSpannedString( + currencySymbol = totalBalance.fiatCurrency.symbol + ) + tvCurrencyName.text = totalBalance.fiatCurrency.code tvCurrencyName.setOnClickListener { // TODO: Open app currency selector } From 2357aa509f0ac1777c0460ecba95a9520acd2161 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 18 May 2022 11:31:36 +0300 Subject: [PATCH 013/111] Updated on 2026-08-14 --- .../tangem/tap/common/entities/TapCurrency.kt | 10 ---- .../common/redux/global/GlobalMidlleware.kt | 2 +- .../details/redux/DetailsMiddleware.kt | 16 ++++-- .../wallet/redux/reducers/WalletReducer.kt | 24 +++++---- .../network/coinmarketcap/CoinMarketCapApi.kt | 33 ------------ .../coinmarketcap/CoinMarketCapService.kt | 36 ------------- .../tap/network/coinmarketcap/Response.kt | 51 ------------------- 7 files changed, 27 insertions(+), 145 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/common/entities/TapCurrency.kt delete mode 100644 app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapApi.kt delete mode 100644 app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapService.kt delete mode 100644 app/src/main/java/com/tangem/tap/network/coinmarketcap/Response.kt diff --git a/app/src/main/java/com/tangem/tap/common/entities/TapCurrency.kt b/app/src/main/java/com/tangem/tap/common/entities/TapCurrency.kt deleted file mode 100644 index 1aa3f5c351..0000000000 --- a/app/src/main/java/com/tangem/tap/common/entities/TapCurrency.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.tap.common.entities - -/** -[REDACTED_AUTHOR] - */ -class TapCurrency { - companion object{ - const val DEFAULT_FIAT_CURRENCY = "USD" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt index 75dccd51ab..1e104b5dd4 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt @@ -24,7 +24,7 @@ class GlobalMiddleware { } } -private val globalMiddlewareHandler: Middleware = { dispatch, appState -> +private val globalMiddlewareHandler: Middleware = { _, appState -> { nextDispatch -> { action -> when (action) { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index e938026085..4dba1b6bd6 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -30,7 +30,7 @@ class DetailsMiddleware { private val eraseWalletMiddleware = EraseWalletMiddleware() private val appCurrencyMiddleware = AppCurrencyMiddleware() private val manageSecurityMiddleware = ManageSecurityMiddleware() - val detailsMiddleware: Middleware = { dispatch, state -> + val detailsMiddleware: Middleware = { _, _ -> { next -> { action -> when (action) { @@ -122,6 +122,8 @@ class DetailsMiddleware { store.dispatch(DetailsAction.ResetToFactory.Proceed.NotAllowedByCard) EraseWalletState.NotEmpty -> store.dispatch(DetailsAction.ResetToFactory.Proceed.NotEmpty) + else -> { /* no-op */ + } } } is DetailsAction.ResetToFactory.Cancel -> { @@ -150,6 +152,8 @@ class DetailsMiddleware { } } } + else -> { /* no-op */ + } } } } @@ -164,6 +168,8 @@ class DetailsMiddleware { store.dispatch(GlobalAction.ChangeAppCurrency(action.fiatCurrency)) store.dispatch(WalletAction.LoadFiatRate()) } + else -> { /* no-op */ + } } } } @@ -234,18 +240,22 @@ class DetailsMiddleware { actionToLog = Analytics.ActionToLog.ChangeSecOptions, parameters = mapOf( AnalyticsParam.NEW_SECURITY_OPTION to - (selectedOption?.name ?: "") + (selectedOption?.name ?: "") ), card = store.state.detailsState.scanResponse?.card ) } store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Failure) } + else -> { /* no-op */ + } } } } } + else -> { /* no-op */ + } } } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index 3219b7cd2f..eb079d3116 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -70,9 +70,9 @@ private fun internalReduce(action: Action, state: AppState): WalletState { when (action.error) { is TapError.NoInternetConnection -> { val wallets = newState.wallets - .map { - it.copy( - walletsData = it.walletsData.map { + .map { store -> + store.copy( + walletsData = store.walletsData.map { it.copy( currencyData = it.currencyData.copy( status = BalanceStatus.Unreachable @@ -110,6 +110,8 @@ private fun internalReduce(action: Action, state: AppState): WalletState { ) ) } + else -> { /* no-op */ + } } } @@ -306,23 +308,23 @@ private fun internalReduce(action: Action, state: AppState): WalletState { } is WalletAction.SetWalletRent -> { var walletData = newState.getWalletData(action.blockchain) - if (walletData == null) { - newState - } else { - walletData = - walletData.copy(warningRent = WalletRent(action.minRent, action.rentExempt)) + if (walletData != null) { + walletData = walletData.copy( + warningRent = WalletRent(action.minRent, action.rentExempt) + ) newState = newState.updateWalletsData(listOf(walletData)) + } } is WalletAction.RemoveWalletRent -> { var walletData = newState.getWalletData(action.blockchain) - if (walletData == null) { - newState - } else { + if (walletData != null) { walletData = walletData.copy(warningRent = null) newState = newState.updateWalletsData(listOf(walletData)) } } + else -> { /* no-op */ + } } return newState } diff --git a/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapApi.kt b/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapApi.kt deleted file mode 100644 index 6836861c8c..0000000000 --- a/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapApi.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.tangem.tap.network.coinmarketcap - -import com.tangem.network.common.AddHeaderInterceptor -import com.tangem.network.common.createRetrofitInstance -import retrofit2.http.GET -import retrofit2.http.Query - -interface CoinMarketCapApi { - - @GET("v1/tools/price-conversion") - suspend fun getRateInfo( - @Query("amount") amount: Int, - @Query("symbol") cryptoCurrencyName: String, - @Query("convert") fiatCurrencyName: String? = null - ): RateInfoResponse - - @GET("v1/fiat/map") - suspend fun getFiatMap(): FiatMapResponse - - - companion object { - private const val baseUrl = "https://pro-api.coinmarketcap.com/" - - fun create(apiKey: String): CoinMarketCapApi { - return createRetrofitInstance( - baseUrl = baseUrl, - interceptors = listOf( - AddHeaderInterceptor(mapOf("X-CMC_PRO_API_KEY" to apiKey)), - ), - ).create(CoinMarketCapApi::class.java) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapService.kt b/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapService.kt deleted file mode 100644 index aa4de2bf44..0000000000 --- a/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapService.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.tangem.tap.network.coinmarketcap - -import com.tangem.common.services.Result -import com.tangem.common.services.performRequest -import com.tangem.tap.common.redux.global.FiatCurrencyName -import com.tangem.tap.store -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import java.math.BigDecimal - -//TODO: refactoring: move to the domain module and aggregate it as the alternative service for TangemTech -class CoinMarketCapService() { - private val api: CoinMarketCapApi by lazy { CoinMarketCapApi.create(getApiKey()) } - - private fun getApiKey(): String { - return store.state.globalState.configManager?.config?.coinMarketCapKey ?: "" - } - - suspend fun getRate( - currency: String, fiatCurrency: FiatCurrencyName? = null - ): Result = withContext(Dispatchers.IO) { - val response = performRequest { api.getRateInfo(1, currency, fiatCurrency) } - return@withContext when (response) { - is Result.Success -> Result.Success(response.data.data.getRate()) - is Result.Failure -> response - } - } - - suspend fun getFiatCurrencies(): Result> = withContext(Dispatchers.IO) { - val response = performRequest { api.getFiatMap() } - return@withContext when (response) { - is Result.Success -> Result.Success(response.data.data.sortedBy { it.name }) - is Result.Failure -> response - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/network/coinmarketcap/Response.kt b/app/src/main/java/com/tangem/tap/network/coinmarketcap/Response.kt deleted file mode 100644 index 7320d9467c..0000000000 --- a/app/src/main/java/com/tangem/tap/network/coinmarketcap/Response.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.tangem.tap.network.coinmarketcap - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass -import java.math.BigDecimal - -@JsonClass(generateAdapter = true) -class RateInfoResponse : CoinMarketResponse() - -@JsonClass(generateAdapter = true) -data class RateData( - val quote: Map -) { - fun getRate(): BigDecimal = quote.values.first().price -} - -@JsonClass(generateAdapter = true) -data class CurrencyRate( - val price: BigDecimal -) - - -@JsonClass(generateAdapter = true) -data class Status( - val timestamp: String, - @Json(name = "error_code") - val errorCode: Int, - @Json(name = "error_message") - val errorMessage: String?, - val elapsed: Int, - @Json(name = "credit_count") - val creditCount: Int, - val notice: String? -) - -@JsonClass(generateAdapter = true) -class FiatMapResponse : CoinMarketResponse>() - -@JsonClass(generateAdapter = true) -open class CoinMarketResponse { - lateinit var status: Status - lateinit var data: T -} - -@JsonClass(generateAdapter = true) -data class FiatCurrency( - val id: Int, - val name: String, - val sign: String, - val symbol: String -) From ea834a06363f579ab8fffbaf3bb6800f4104b119 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 18 May 2022 21:31:21 +0300 Subject: [PATCH 014/111] Updated on 2026-08-14 --- .../recyclerView/SpaceItemDecoration.kt | 72 ++++++++++ .../tap/features/send/ui/SendFragment.kt | 5 +- .../tap/features/wallet/redux/WalletAction.kt | 4 +- .../tap/features/wallet/redux/WalletState.kt | 2 +- .../redux/middlewares/WalletMiddleware.kt | 7 +- .../wallet/redux/reducers/WalletReducer.kt | 31 ++-- .../wallet/ui/WalletDetailsFragment.kt | 68 +++++---- .../tap/features/wallet/ui/WalletFragment.kt | 5 +- .../WalletDetailWarningMessagesAdapter.kt | 64 +++++++++ .../ui/adapters/WarningMessagesAdapter.kt | 29 +--- .../res/layout/fragment_wallet_details.xml | 38 +---- .../layout/layout_wallet_details_warning.xml | 47 ------ app/src/main/res/layout/layout_warning.xml | 135 +++++------------- .../main/res/layout/layout_warning_card.xml | 14 ++ .../res/layout/layout_warning_card_action.xml | 88 ++++++++++++ 15 files changed, 343 insertions(+), 266 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/recyclerView/SpaceItemDecoration.kt create mode 100644 app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletDetailWarningMessagesAdapter.kt delete mode 100644 app/src/main/res/layout/layout_wallet_details_warning.xml create mode 100644 app/src/main/res/layout/layout_warning_card.xml create mode 100644 app/src/main/res/layout/layout_warning_card_action.xml diff --git a/app/src/main/java/com/tangem/tap/common/recyclerView/SpaceItemDecoration.kt b/app/src/main/java/com/tangem/tap/common/recyclerView/SpaceItemDecoration.kt new file mode 100644 index 0000000000..b1d16fc3f6 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/recyclerView/SpaceItemDecoration.kt @@ -0,0 +1,72 @@ +package com.tangem.tap.common.recyclerView + +import android.graphics.Rect +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import com.tangem.tangem_sdk_new.extensions.dpToPx + +class SpaceItemDecoration( + private val horizontalSpaceDp: Float, + private val verticalSpaceDp: Float, +) : RecyclerView.ItemDecoration() { + + private lateinit var space: Space + + 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() + ) + } + + outRect.left = space.horizontal + outRect.right = space.horizontal + + when (state.itemCount) { + 1 -> { + outRect.top = space.vertical + outRect.bottom = space.vertical + } + else -> { + val adapterPosition = parent.getChildAdapterPosition(view) + if (adapterPosition == -1) return + + when (adapterPosition) { + 0 -> { + // first + outRect.top = space.vertical + outRect.bottom = space.vertical / 2 + } + state.itemCount - 1 -> { + // last + outRect.top = space.vertical / 2 + outRect.bottom = space.vertical + } + else -> { + // middle + outRect.top = space.vertical / 2 + outRect.bottom = space.vertical / 2 + } + } + } + } + } + + private data class Space( + val horizontal: Int, + val vertical: Int, + ) + + companion object { + fun all(dp: Float): SpaceItemDecoration = SpaceItemDecoration(dp, dp) + fun vertical(dp: Float): SpaceItemDecoration = SpaceItemDecoration(0f, dp) + fun horizontal(dp: Float): SpaceItemDecoration = SpaceItemDecoration(dp, 0f) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt index d999d79bcb..24c70b0b0a 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt @@ -14,13 +14,13 @@ import androidx.recyclerview.widget.RecyclerView import by.kirich1409.viewbindingdelegate.viewBinding import com.google.android.material.textfield.TextInputEditText import com.tangem.Message -import com.tangem.tangem_sdk_new.extensions.dpToPx import com.tangem.tangem_sdk_new.extensions.hideSoftKeyboard import com.tangem.tap.common.KeyboardObserver import com.tangem.tap.common.entities.TapCurrency import com.tangem.tap.common.extensions.getFromClipboard import com.tangem.tap.common.extensions.setOnImeActionListener import com.tangem.tap.common.qrCodeScan.ScanQrCodeActivity +import com.tangem.tap.common.recyclerView.SpaceItemDecoration import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.common.snackBar.MaxAmountSnackbar import com.tangem.tap.common.text.truncateMiddleWith @@ -36,7 +36,6 @@ import com.tangem.tap.features.send.redux.states.FeeType import com.tangem.tap.features.send.redux.states.MainCurrencyType import com.tangem.tap.features.send.ui.stateSubscribers.SendStateSubscriber import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.features.wallet.ui.adapters.SpacesItemDecoration import com.tangem.tap.features.wallet.ui.adapters.WarningMessagesAdapter import com.tangem.tap.mainScope import com.tangem.tap.store @@ -244,7 +243,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { warningsAdapter = WarningMessagesAdapter() val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) rvWarningMessages.layoutManager = layoutManager - rvWarningMessages.addItemDecoration(SpacesItemDecoration(rvWarningMessages.dpToPx(16f).toInt())) + rvWarningMessages.addItemDecoration(SpaceItemDecoration.all(16f)) rvWarningMessages.adapter = warningsAdapter store.dispatch(SendAction.Warnings.Update) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt index aa7c653e8f..c4e722e6c3 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt @@ -157,10 +157,10 @@ sealed class WalletAction : Action { data class ChangeSelectedAddress(val type: AddressType) : WalletAction() data class SetWalletRent( - val blockchain: BlockchainNetwork, + val wallet: Wallet, val minRent: String, val rentExempt: String ) : WalletAction() - data class RemoveWalletRent(val blockchain: BlockchainNetwork) : WalletAction() + data class RemoveWalletRent(val wallet: Wallet) : WalletAction() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index 278ccee818..cd5c4eefd2 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -345,7 +345,7 @@ data class WalletData( val fiatRate: BigDecimal? = null, val mainButton: WalletMainButton = WalletMainButton.SendButton(false), val currency: Currency, - val warningRent: WalletRent? = null, + val walletRent: WalletRent? = null, ) { fun shouldShowMultipleAddress(): Boolean { val listOfAddresses = walletAddresses?.list ?: return false diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 034122f2c1..d87020fb27 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -24,7 +24,6 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.extensions.toSendableAmounts import com.tangem.tap.domain.failedRates import com.tangem.tap.domain.loadedRates -import com.tangem.tap.domain.tokens.BlockchainNetwork import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.send.redux.PrepareSendScreen @@ -330,14 +329,12 @@ class WalletMiddleware { val currency = walletManager.wallet.blockchain.currency if (show) { dispatchOnMain(WalletAction.SetWalletRent( - blockchain = BlockchainNetwork.fromWalletManager(walletManager), + wallet = walletManager.wallet, minRent = ("${rentProvider.rentAmount().stripZeroPlainString()} $currency"), rentExempt = ("${rentExempt.stripZeroPlainString()} $currency") )) } else { - dispatchOnMain(WalletAction.RemoveWalletRent( - blockchain = BlockchainNetwork.fromWalletManager(walletManager), - )) + dispatchOnMain(WalletAction.RemoveWalletRent(walletManager.wallet)) } } is com.tangem.blockchain.extensions.Result.Failure -> {} diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index 97e6e778ec..fdfee46cfa 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -146,12 +146,9 @@ private fun internalReduce(action: Action, state: AppState): WalletState { } else { val walletManager = newState.getWalletManager(action.blockchain) ?: return newState val currencies = listOf(Currency.fromBlockchainNetwork(action.blockchain)) + - walletManager.cardTokens.map { - Currency.fromBlockchainNetwork( - action.blockchain, - it - ) - } + walletManager.cardTokens.map { + Currency.fromBlockchainNetwork(action.blockchain, it) + } val newWallets = newState.walletsData.filter { currencies.contains(it.currency) } .map { wallet -> wallet.copy( @@ -305,23 +302,15 @@ private fun internalReduce(action: Action, state: AppState): WalletState { ) } is WalletAction.SetWalletRent -> { - var walletData = newState.getWalletData(action.blockchain) - if (walletData == null) { - newState - } else { - walletData = - walletData.copy(warningRent = WalletRent(action.minRent, action.rentExempt)) - newState = newState.updateWalletsData(listOf(walletData)) - } + val walletStore = newState.getWalletStore(action.wallet) ?: return newState + val walletRent = WalletRent(action.minRent, action.rentExempt) + val walletsData = walletStore.walletsData.map { it.copy(walletRent = walletRent) } + newState = newState.updateWalletsData(walletsData) } is WalletAction.RemoveWalletRent -> { - var walletData = newState.getWalletData(action.blockchain) - if (walletData == null) { - newState - } else { - walletData = walletData.copy(warningRent = null) - newState = newState.updateWalletsData(listOf(walletData)) - } + val walletStore = newState.getWalletStore(action.wallet) ?: return newState + val walletsData = walletStore.walletsData.map { it.copy(walletRent = null) } + newState = newState.updateWalletsData(walletsData) } } return newState diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 2c1fa686cd..331f406807 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -13,10 +13,10 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding import com.squareup.picasso.Picasso -import com.tangem.common.extensions.guard import com.tangem.tap.common.SnackbarHandler import com.tangem.tap.common.TestActions import com.tangem.tap.common.extensions.* +import com.tangem.tap.common.recyclerView.SpaceItemDecoration import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.tokens.BlockchainNetwork @@ -24,6 +24,8 @@ import com.tangem.tap.features.onboarding.getQRReceiveMessage import com.tangem.tap.features.wallet.models.PendingTransaction import com.tangem.tap.features.wallet.redux.* import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter +import com.tangem.tap.features.wallet.ui.adapters.WalletDetailWarningMessagesAdapter +import com.tangem.tap.features.wallet.ui.adapters.WalletDetailsWarning import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendDialog import com.tangem.tap.features.wallet.ui.test.TestWalletDetails import com.tangem.tap.store @@ -35,6 +37,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreSubscriber { private lateinit var pendingTransactionAdapter: PendingTransactionsAdapter + private lateinit var warningMessagesAdapter: WalletDetailWarningMessagesAdapter private var dialog: Dialog? = null private val binding: FragmentWalletDetailsBinding by viewBinding(FragmentWalletDetailsBinding::bind) @@ -72,6 +75,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), setupTransactionsRecyclerView() setupButtons() + setupWarningsRecyclerView() setupTestActionButton() } @@ -81,6 +85,13 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), rvPendingTransaction.adapter = pendingTransactionAdapter } + private fun setupWarningsRecyclerView() = with(binding) { + warningMessagesAdapter = WalletDetailWarningMessagesAdapter() + rvWarningMessages.layoutManager = LinearLayoutManager(requireContext()) + rvWarningMessages.adapter = warningMessagesAdapter + rvWarningMessages.addItemDecoration(SpaceItemDecoration.vertical(8f)) + } + private fun setupButtons() = with(binding) { btnConfirm.text = getString(R.string.wallet_button_send) btnConfirm.setOnClickListener { store.dispatch(WalletAction.Send()) } @@ -116,8 +127,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), handleDialogs(state.walletDialog) handleCurrencyIcon(selectedWallet) - handleWalletRent(selectedWallet.warningRent) - handleNotEnoughFundsOnMainCurrency(selectedWallet) + handleWarnings(selectedWallet) binding.srlWalletDetails.setOnRefreshListener { if (selectedWallet.currencyData.status != BalanceStatus.Loading) { @@ -162,31 +172,36 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), btnSell.show(selectedWallet.tradeCryptoState.sellingAllowed) } - private fun handleWalletRent(rent: WalletRent?) = with(binding) { - val rent = rent.guard { - lWarning.root.hide() - return - } - val warningMessage = requireContext().getString( - R.string.solana_rent_warning, rent.minRentValue, rent.rentExemptValue - ) - lWarning.tvWarningMessage.text = warningMessage - lWarning.root.show() - } - - private fun handleNotEnoughFundsOnMainCurrency(selectedWalletData: WalletData) = with(binding) { - if (selectedWalletData.currency.isBlockchain()) return@with - - if (selectedWalletData.shouldShowCoinAmountWarning()) { - val blockchainName = selectedWalletData.currency.blockchain.fullName - val warningMessage = requireContext().getString( - R.string.token_details_send_blocked_fee_format, blockchainName, blockchainName + private fun handleWarnings(selectedWallet: WalletData) = with(binding) { + val walletWarnings = mutableListOf() + if (selectedWallet.currencyData.status == BalanceStatus.SameCurrencyTransactionInProgress) { + val txInProgress = WalletDetailsWarning( + title = R.string.common_warning, + message = R.string.wallet_pending_transaction_warning, ) - lWarning.tvWarningMessage.text = warningMessage - lWarning.root.show() - } else { - lWarning.root.hide() + walletWarnings.add(0, txInProgress) } + if (selectedWallet.walletRent != null) { + val rent = selectedWallet.walletRent + val rentWarning = WalletDetailsWarning( + title = R.string.common_warning, + message = R.string.solana_rent_warning, + messageArgs = listOf(rent.minRentValue, rent.rentExemptValue) + ) + walletWarnings.add(rentWarning) + } + if (!selectedWallet.currency.isBlockchain() && selectedWallet.shouldShowCoinAmountWarning()) { + val blockchainName = selectedWallet.currency.blockchain.fullName + val notEnoughBalanceForFee = WalletDetailsWarning( + title = R.string.common_warning, + message = R.string.token_details_send_blocked_fee_format, + messageArgs = listOf(blockchainName, blockchainName) + ) + walletWarnings.add(notEnoughBalanceForFee) + } + + warningMessagesAdapter.submitList(walletWarnings) + rvWarningMessages.show(walletWarnings.isNotEmpty()) } private fun handleCurrencyIcon(wallet: WalletData) = with(binding.lWalletDetails.lBalance) { @@ -299,7 +314,6 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), ) } } - binding.cardPendingTransactionWarning.show(data.status == BalanceStatus.SameCurrencyTransactionInProgress) } private fun handleDialogs(walletDialog: StateDialog?) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index f633010d0a..acb6309e60 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -13,9 +13,9 @@ import androidx.recyclerview.widget.RecyclerView import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding import com.squareup.picasso.Picasso -import com.tangem.tangem_sdk_new.extensions.dpToPx import com.tangem.tap.MainActivity import com.tangem.tap.common.extensions.show +import com.tangem.tap.common.recyclerView.SpaceItemDecoration import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction @@ -25,7 +25,6 @@ import com.tangem.tap.domain.statePrinter.printWalletState import com.tangem.tap.domain.termsOfUse.CardTou import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.wallet.redux.* -import com.tangem.tap.features.wallet.ui.adapters.SpacesItemDecoration import com.tangem.tap.features.wallet.ui.adapters.WarningMessagesAdapter import com.tangem.tap.features.wallet.ui.wallet.MultiWalletView import com.tangem.tap.features.wallet.ui.wallet.SingleWalletView @@ -100,7 +99,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber(DiffUtilCallback()) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WalletDetailsWarningMessageVH { + val inflater = LayoutInflater.from(parent.context) + val binding = LayoutWarningCardBinding.inflate(inflater, parent, false) + + return WalletDetailsWarningMessageVH(binding) + } + + override fun onBindViewHolder(holder: WalletDetailsWarningMessageVH, position: Int) { + holder.bind(currentList[position]) + } + + private class DiffUtilCallback : DiffUtil.ItemCallback() { + override fun areContentsTheSame(oldItem: WalletDetailsWarning, newItem: WalletDetailsWarning) = + oldItem == newItem + + override fun areItemsTheSame(oldItem: WalletDetailsWarning, newItem: WalletDetailsWarning) = + oldItem == newItem + } +} + +class WalletDetailsWarningMessageVH( + val binding: LayoutWarningCardBinding +) : RecyclerView.ViewHolder(binding.root) { + + fun bind(warning: WalletDetailsWarning) { + binding.warningCard.setCardBackgroundColor(binding.root.getColor(R.color.darkGray2)) + setText(warning) + } + + private fun setText(warning: WalletDetailsWarning) = with(binding.warningContentContainer) { + fun getString( + stringResId: Int, + formatArgs: List = emptyList() + ) = root.getString(stringResId, *formatArgs.toTypedArray()) + + tvTitle.text = getString(warning.title) + tvMessage.text = getString(warning.message, warning.messageArgs) + } +} + +data class WalletDetailsWarning( + val title: Int, + val message: Int, + val titleArgs: List = emptyList(), + val messageArgs: List = emptyList(), +) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt index a566f7b5e6..946e347a65 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt @@ -1,7 +1,6 @@ package com.tangem.tap.features.wallet.ui.adapters import android.content.res.Resources -import android.graphics.Rect import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -9,7 +8,6 @@ import androidx.core.os.ConfigurationCompat import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import androidx.recyclerview.widget.RecyclerView.ItemDecoration import com.google.android.play.core.review.ReviewManagerFactory import com.tangem.tap.common.analytics.AnalyticsEvent import com.tangem.tap.common.extensions.* @@ -20,13 +18,13 @@ import com.tangem.tap.features.feedback.RateCanBeBetterEmail import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.store import com.tangem.wallet.R -import com.tangem.wallet.databinding.LayoutWarningBinding +import com.tangem.wallet.databinding.LayoutWarningCardActionBinding import timber.log.Timber class WarningMessagesAdapter : ListAdapter(DiffUtilCallback) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WarningMessageVH { - val binding = LayoutWarningBinding.inflate( + val binding = LayoutWarningCardActionBinding.inflate( LayoutInflater.from(parent.context), parent, false ) return WarningMessageVH(binding) @@ -45,7 +43,7 @@ class WarningMessagesAdapter : ListAdapter(Dif } } -class WarningMessageVH(val binding: LayoutWarningBinding) : RecyclerView.ViewHolder(binding.root) { +class WarningMessageVH(val binding: LayoutWarningCardActionBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(warning: WarningMessage) { setBgColor(warning.priority) @@ -53,7 +51,7 @@ class WarningMessageVH(val binding: LayoutWarningBinding) : RecyclerView.ViewHol setupControlButtons(warning) } - private fun setText(warning: WarningMessage) = with(binding) { + private fun setText(warning: WarningMessage) = with(binding.warningContentContainer) { fun getString(resId: Int?, default: String, formatArgs: String? = null) = if (resId == null) default else root.getString(resId, formatArgs) @@ -71,7 +69,7 @@ class WarningMessageVH(val binding: LayoutWarningBinding) : RecyclerView.ViewHol WarningMessage.Priority.Warning -> R.color.warning_warning WarningMessage.Priority.Critical -> R.color.warning_critical } - binding.cardView.setCardBackgroundColor(binding.root.getColor(color)) + binding.warningCardAction.setCardBackgroundColor(binding.root.getColor(color)) } private fun setupControlButtons(warning: WarningMessage) = when (warning.type) { @@ -115,7 +113,7 @@ class WarningMessageVH(val binding: LayoutWarningBinding) : RecyclerView.ViewHol val buttonTitle = binding.root.getString( warning.buttonTextId ?: R.string.how_to_got_it_button ) - binding.btnGotIt.setOnClickListener (buttonAction) + binding.btnGotIt.setOnClickListener(buttonAction) binding.btnGotIt.text = buttonTitle } WarningMessage.Type.AppRating -> { @@ -161,19 +159,4 @@ class WarningMessageVH(val binding: LayoutWarningBinding) : RecyclerView.ViewHol } } } -} - -class SpacesItemDecoration(private val spacePx: Int) : ItemDecoration() { - override fun getItemOffsets( - outRect: Rect, - view: View, - parent: RecyclerView, - state: RecyclerView.State - ) { - outRect.left = spacePx - outRect.right = spacePx - - outRect.top = spacePx / 2 - outRect.top = spacePx / 2 - } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_wallet_details.xml b/app/src/main/res/layout/fragment_wallet_details.xml index a2d946a3ca..cd51f4c2fa 100644 --- a/app/src/main/res/layout/fragment_wallet_details.xml +++ b/app/src/main/res/layout/fragment_wallet_details.xml @@ -98,48 +98,22 @@ android:layout_marginTop="16dp" app:layout_constraintTop_toBottomOf="@id/rv_pending_transaction" /> - - - - - - + app:constraint_referenced_ids="l_wallet_details" /> diff --git a/app/src/main/res/layout/layout_wallet_details_warning.xml b/app/src/main/res/layout/layout_wallet_details_warning.xml deleted file mode 100644 index 43eeed159a..0000000000 --- a/app/src/main/res/layout/layout_wallet_details_warning.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/layout_warning.xml b/app/src/main/res/layout/layout_warning.xml index adab88869c..7ba7e096ef 100644 --- a/app/src/main/res/layout/layout_warning.xml +++ b/app/src/main/res/layout/layout_warning.xml @@ -1,110 +1,41 @@ - + android:background="@android:color/transparent"> - + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + android:layout_marginEnd="8dp" + android:textColor="@android:color/white" + android:textStyle="bold" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="Test title" /> - + - - - - -