Updated on 2026-08-14
This commit is contained in:
commit
15cb3d9411
16 changed files with 244 additions and 174 deletions
|
|
@ -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'
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ interface Loader<T> {
|
|||
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}"
|
||||
}
|
||||
}
|
||||
|
|
@ -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",
|
||||
]
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
26
domain/src/main/java/com/tangem/domain/DomainLayer.kt
Normal file
26
domain/src/main/java/com/tangem/domain/DomainLayer.kt
Normal file
|
|
@ -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<String, Any?>? = null) {
|
||||
initActionStateLogger()
|
||||
|
||||
onInitComplete?.invoke(null)
|
||||
}
|
||||
|
||||
private fun initActionStateLogger() {
|
||||
val factory = actionStateLogger.actionStateConvertersFactory
|
||||
|
||||
factory.addConverter(AddCustomTokenAction::class.java, AddCustomTokenState.Converter())
|
||||
}
|
||||
}
|
||||
|
|
@ -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<DomainState> {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
|
@ -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<AddCustomTokenState>("AddCustomT
|
|||
private val hubState: AddCustomTokenState
|
||||
get() = domainStore.state.addCustomTokensState
|
||||
|
||||
override fun getReducer(): ReStoreReducer<AddCustomTokenState> = 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<AddCustomTokenState>("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<AddCustomTokenState> {
|
||||
|
||||
override fun reduceAction(action: Action, state: AddCustomTokenState): AddCustomTokenState {
|
||||
return when (action) {
|
||||
|
|
@ -679,10 +686,4 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
|
|||
return state.copy(form = Form(state.form.fieldList))
|
||||
}
|
||||
|
||||
@Throws
|
||||
private fun throwUnAppropriateInitialization(objName: String) {
|
||||
throw AddCustomTokenException.UnAppropriateInitializationException(
|
||||
"AddCustomTokenHub", "$objName must be not NULL"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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<DomainState> {
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -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<ReStoreHub<DomainState, *>> = 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<Pair<Action, DomainState>>()
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,14 +17,13 @@ import java.util.concurrent.Executors
|
|||
* a state behavior.
|
||||
* All ReStoreHub's must be marked as internal
|
||||
*/
|
||||
internal interface ReStoreHub<StoreState, State> : HubMiddleware<StoreState>, HubReducer<StoreState>
|
||||
|
||||
internal interface HubMiddleware<StoreState> {
|
||||
internal interface ReStoreHub<StoreState, State> {
|
||||
fun getMiddleware(): Middleware<StoreState>
|
||||
fun reduce(action: Action, domainState: StoreState): StoreState
|
||||
}
|
||||
|
||||
internal interface HubReducer<StoreState> {
|
||||
fun reduce(action: Action, storeState: StoreState): StoreState
|
||||
internal interface ReStoreReducer<State> {
|
||||
fun reduceAction(action: Action, state: State): State
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -87,13 +86,13 @@ internal abstract class BaseStoreHub<State>(
|
|||
* 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<State>(
|
|||
}
|
||||
|
||||
protected abstract suspend fun handleAction(action: Action, storeState: DomainState, cancel: ValueCallback<Action>)
|
||||
|
||||
@Deprecated(
|
||||
replaceWith = ReplaceWith("ReStoreReducer<T>"),
|
||||
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<State>
|
||||
protected abstract fun getReducer(): ReStoreReducer<State>
|
||||
|
||||
protected abstract fun getHubState(storeState: DomainState): State
|
||||
protected abstract fun updateStoreState(storeState: DomainState, newHubState: State): DomainState
|
||||
|
||||
}
|
||||
|
||||
internal interface ReStoreReducer<State> {
|
||||
fun reduceAction(action: Action, state: State): State
|
||||
}
|
||||
|
||||
internal suspend inline fun ReStoreHub<*, *>.dispatchOnMain(vararg actions: Action) {
|
||||
withMainContext { actions.forEach { domainStore.dispatch(it) } }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<DomainGlobalState>("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<DomainGlobalState> = DomainGlobalReducer()
|
||||
}
|
||||
|
||||
private class DomainGlobalReducer : ReStoreReducer<DomainGlobalState> {
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -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<StateHolder> {
|
|||
fun convert(stateHolder: StateHolder): String
|
||||
}
|
||||
|
||||
interface StringActionConverter<StateHolder> {
|
||||
interface StringActionStateConverter<StateHolder> {
|
||||
fun convert(action: Action, stateHolder: StateHolder): String?
|
||||
}
|
||||
|
||||
class ActionStateConvertersFactory {
|
||||
private val stateConverters = mutableMapOf<Class<out Action>, StringActionStateConverter<DomainState>>()
|
||||
|
||||
fun addConverter(classOfAction: Class<out Action>, converter: StringActionStateConverter<DomainState>) {
|
||||
stateConverters[classOfAction] = converter
|
||||
}
|
||||
|
||||
fun getConverter(action: Action): StringActionStateConverter<DomainState>? {
|
||||
val converter = stateConverters.firstNotNullOfOrNull { (classOfAction, converter) ->
|
||||
if (classOfAction.isAssignableFrom(action::class.java)) {
|
||||
converter
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} ?: return null
|
||||
|
||||
return converter
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Pair<Action, DomainState>>)
|
||||
}
|
||||
|
||||
internal class ActionStateLoggerImpl : ActionStateLogger {
|
||||
|
||||
val actionStateConvertersFactory = ActionStateConvertersFactory()
|
||||
|
||||
override fun log(reducedSates: List<Pair<Action, DomainState>>) {
|
||||
if (!BuildConfig.LOG_ENABLED) return
|
||||
|
||||
logStates(reducedSates)
|
||||
}
|
||||
|
||||
private fun logStates(reducedSates: List<Pair<Action, DomainState>>) {
|
||||
reducedSates.forEach { (action, domainState) ->
|
||||
val messageToPrint = actionStateConvertersFactory.getConverter(action)
|
||||
?.convert(action, domainState)
|
||||
?: return@forEach
|
||||
|
||||
Timber.d(messageToPrint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Pair<Action, DomainState>>) {
|
||||
// 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<Pair<Action, DomainState>>) {
|
||||
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()
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue