From 14c6876cc98a9ce0e1d43478e939ff32a6c07d03 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 11 Sep 2020 20:26:35 +0300 Subject: [PATCH 1/5] Updated on 2026-08-14 --- .../tap/common/extensions/Navigation.kt | 2 + .../com/tangem/tap/common/redux/AppReducer.kt | 10 +- .../com/tangem/tap/common/redux/AppState.kt | 2 + .../redux/navigation/NavigationState.kt | 2 +- .../features/details/redux/DetailsAction.kt | 10 ++ .../details/redux/DetailsMiddleware.kt | 1 + .../features/details/redux/DetailsReducer.kt | 31 +++++ .../features/details/redux/DetailsState.kt | 15 +++ .../features/details/ui/DetailsFragment.kt | 67 ++++++++++ .../tap/features/wallet/ui/WalletFragment.kt | 26 ++++ app/src/main/res/layout/fragment_details.xml | 118 ++++++++++++++++++ app/src/main/res/layout/fragment_wallet.xml | 1 + app/src/main/res/menu/wallet.xml | 8 ++ app/src/main/res/values/strings.xml | 3 + 14 files changed, 291 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt create mode 100644 app/src/main/res/layout/fragment_details.xml create mode 100644 app/src/main/res/menu/wallet.xml diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt index 1890cabce0..9c7b3cf106 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt @@ -4,6 +4,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentManager import com.tangem.tap.common.redux.navigation.AppScreen +import com.tangem.tap.features.details.ui.DetailsFragment import com.tangem.tap.features.home.HomeFragment import com.tangem.tap.features.send.ui.SendFragment import com.tangem.tap.features.wallet.ui.WalletFragment @@ -36,5 +37,6 @@ private fun fragmentFactory(screen: AppScreen): Fragment { AppScreen.Home -> HomeFragment() AppScreen.Wallet -> WalletFragment() AppScreen.Send -> SendFragment() + AppScreen.Details -> DetailsFragment() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt index 0ce1e1e244..0a8ce24105 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt @@ -2,6 +2,7 @@ package com.tangem.tap.common.redux import com.tangem.tap.common.redux.global.globalReducer import com.tangem.tap.common.redux.navigation.NavigationReducer +import com.tangem.tap.features.details.redux.DetailsReducer import com.tangem.tap.features.send.redux.SendReducer import com.tangem.tap.features.wallet.redux.WalletReducer import org.rekotlin.Action @@ -11,10 +12,11 @@ fun appReducer(action: Action, state: AppState?): AppState { if (action is AppAction.RestoreState) return action.state return AppState( - navigationState = NavigationReducer.reduce(action, state), - globalState = globalReducer(action, state), - walletState = WalletReducer.reduce(action, state), - sendState = SendReducer.reduce(action, state.sendState) + navigationState = NavigationReducer.reduce(action, state), + globalState = globalReducer(action, state), + walletState = WalletReducer.reduce(action, state), + sendState = SendReducer.reduce(action, state.sendState), + detailsState = DetailsReducer.reduce(action, state) ) } diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index 045c802a04..4c153c1a85 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -3,6 +3,7 @@ package com.tangem.tap.common.redux import com.tangem.tap.common.redux.global.GlobalState import com.tangem.tap.common.redux.navigation.NavigationState import com.tangem.tap.common.redux.navigation.navigationMiddleware +import com.tangem.tap.features.details.redux.DetailsState import com.tangem.tap.features.home.redux.homeMiddleware import com.tangem.tap.features.send.redux.SendState import com.tangem.tap.features.send.redux.sendMiddleware @@ -16,6 +17,7 @@ data class AppState( val globalState: GlobalState = GlobalState(), val walletState: WalletState = WalletState(), val sendState: SendState = SendState(), + val detailsState: DetailsState = DetailsState() ) : StateType { companion object { diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt index 7fcff63909..c1b700abec 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt @@ -9,4 +9,4 @@ data class NavigationState( val activity: WeakReference? = null ) : StateType -enum class AppScreen { Home, Wallet, Send } \ No newline at end of file +enum class AppScreen { Home, Wallet, Send, Details } \ No newline at end of file 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 new file mode 100644 index 0000000000..01128b15c7 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -0,0 +1,10 @@ +package com.tangem.tap.features.details.redux + +import com.tangem.commands.Card +import org.rekotlin.Action + +sealed class DetailsAction : Action { + + data class SetCard(val card: Card): DetailsAction() + +} \ No newline at end of file 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 new file mode 100644 index 0000000000..78d6334eea --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -0,0 +1 @@ +package com.tangem.tap.features.details.redux 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 new file mode 100644 index 0000000000..711b3e67a9 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -0,0 +1,31 @@ +package com.tangem.tap.features.details.redux + +import com.tangem.commands.Card +import com.tangem.tap.common.redux.AppState +import org.rekotlin.Action + +class DetailsReducer { + companion object { + fun reduce(action: Action, state: AppState): DetailsState = internalReduce(action, state) + } +} + +private fun internalReduce(action: Action, state: AppState): DetailsState { + + if (action !is DetailsAction) return state.detailsState + + var detailsState = state.detailsState + when (action) { + is DetailsAction.SetCard -> { + detailsState = DetailsState(card = action.card, cardInfo = action.card.toCardInfo()) + } + } + return detailsState +} + +private fun Card.toCardInfo(): CardInfo? { + val cardId = this.cardId.chunked(4).joinToString(separator = " ") + val issuer = this.cardData?.issuerName ?: return null + val signedHashes = this.walletSignedHashes ?: return null + return CardInfo(cardId, issuer, signedHashes) +} \ No newline at end of file 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 new file mode 100644 index 0000000000..0ef9e23e9a --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt @@ -0,0 +1,15 @@ +package com.tangem.tap.features.details.redux + +import com.tangem.commands.Card +import org.rekotlin.StateType + +data class DetailsState( + val card: Card? = null, + val cardInfo: CardInfo? = null +) : StateType + +data class CardInfo( + val cardId: String, + val issuer: String, + val signedHashes: Int +) 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 new file mode 100644 index 0000000000..8ba573d72a --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt @@ -0,0 +1,67 @@ +package com.tangem.tap.features.details.ui + +import android.os.Bundle +import android.view.View +import androidx.activity.OnBackPressedCallback +import androidx.fragment.app.Fragment +import androidx.transition.TransitionInflater +import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.features.details.redux.DetailsState +import com.tangem.tap.store +import com.tangem.wallet.R +import kotlinx.android.synthetic.main.fragment_details.* +import kotlinx.android.synthetic.main.fragment_wallet.toolbar +import org.rekotlin.StoreSubscriber + +class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + store.dispatch(NavigationAction.PopBackTo()) + } + }) + val inflater = TransitionInflater.from(requireContext()) + enterTransition = inflater.inflateTransition(R.transition.slide_right) + exitTransition = inflater.inflateTransition(R.transition.fade) + } + + override fun onStart() { + super.onStart() + store.subscribe(this) { state -> + state.skipRepeats { oldState, newState -> + oldState.detailsState == newState.detailsState + }.select { it.detailsState } + } + } + + override fun onStop() { + super.onStop() + store.unsubscribe(this) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + toolbar.setNavigationOnClickListener { + store.dispatch(NavigationAction.PopBackTo()) + } + } + + + + + + override fun newState(state: DetailsState) { + if (activity == null) return + + + if (state.cardInfo != null) { + tv_card_id.text = state.cardInfo.cardId + tv_issuer.text = state.cardInfo.issuer + tv_signed_hashes.text = state.cardInfo.signedHashes.toString() + } + } + +} \ No newline at end of file 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 d461023e6d..7a5016f045 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 @@ -3,8 +3,12 @@ package com.tangem.tap.features.wallet.ui import android.app.Dialog import android.graphics.Bitmap import android.os.Bundle +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem import android.view.View import androidx.activity.OnBackPressedCallback +import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager import androidx.transition.TransitionInflater @@ -12,7 +16,9 @@ import com.google.android.material.snackbar.Snackbar import com.tangem.tap.common.extensions.getDrawable import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show +import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.wallet.redux.* import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendDialog import com.tangem.tap.features.wallet.ui.dialogs.PayIdDialog @@ -35,6 +41,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber { + store.state.globalState.scanNoteResponse?.card?.let { card -> + store.dispatch(DetailsAction.SetCard(card)) + store.dispatch(NavigationAction.NavigateTo(AppScreen.Details)) + true + } + false + } + else -> super.onOptionsItemSelected(item) + } + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + inflater.inflate(R.menu.wallet, menu) + } + } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_details.xml b/app/src/main/res/layout/fragment_details.xml new file mode 100644 index 0000000000..792fa1942c --- /dev/null +++ b/app/src/main/res/layout/fragment_details.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_wallet.xml b/app/src/main/res/layout/fragment_wallet.xml index ccaf8611ff..1864b49550 100644 --- a/app/src/main/res/layout/fragment_wallet.xml +++ b/app/src/main/res/layout/fragment_wallet.xml @@ -21,6 +21,7 @@ android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:navigationIcon="@drawable/ic_baseline_arrow_back_24" + app:menu="@menu/wallet" app:title="@string/wallet_toolbar_title" /> diff --git a/app/src/main/res/menu/wallet.xml b/app/src/main/res/menu/wallet.xml new file mode 100644 index 0000000000..0f6a7ccd07 --- /dev/null +++ b/app/src/main/res/menu/wallet.xml @@ -0,0 +1,8 @@ + + + + \ 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 c8fa6038ac..d6ccd1164c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -64,4 +64,7 @@ Balance: %1s %2s Maximum amount + Details + + \ No newline at end of file From 81307bff30fa6a04ad2ac204384d925a09a97e1a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 16 Sep 2020 21:18:42 +0300 Subject: [PATCH 2/5] Updated on 2026-08-14 --- .../tap/common/extensions/Navigation.kt | 2 + .../com/tangem/tap/common/redux/AppState.kt | 17 ++- .../redux/navigation/NavigationState.kt | 2 +- .../features/details/redux/DetailsAction.kt | 36 ++++- .../details/redux/DetailsMiddleware.kt | 80 +++++++++++ .../features/details/redux/DetailsReducer.kt | 69 ++++++++- .../features/details/redux/DetailsState.kt | 18 ++- .../features/details/ui/DetailsFragment.kt | 29 +++- .../tap/features/wallet/ui/WalletFragment.kt | 11 +- app/src/main/res/layout/fragment_details.xml | 132 +++++++++++++++++- app/src/main/res/layout/fragment_wallet.xml | 13 +- app/src/main/res/values/strings.xml | 12 ++ 12 files changed, 390 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt index 9c7b3cf106..bd8de9b6be 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt @@ -4,6 +4,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentManager import com.tangem.tap.common.redux.navigation.AppScreen +import com.tangem.tap.features.details.ui.DetailsConfirmFragment import com.tangem.tap.features.details.ui.DetailsFragment import com.tangem.tap.features.home.HomeFragment import com.tangem.tap.features.send.ui.SendFragment @@ -38,5 +39,6 @@ private fun fragmentFactory(screen: AppScreen): Fragment { AppScreen.Wallet -> WalletFragment() AppScreen.Send -> SendFragment() AppScreen.Details -> DetailsFragment() + AppScreen.DetailsConfirm -> DetailsConfirmFragment() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index 125482a2f9..47a422958f 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -1,8 +1,10 @@ package com.tangem.tap.common.redux import com.tangem.tap.common.redux.global.GlobalState +import com.tangem.tap.common.redux.global.globalMiddleware import com.tangem.tap.common.redux.navigation.NavigationState import com.tangem.tap.common.redux.navigation.navigationMiddleware +import com.tangem.tap.features.details.redux.DetailsMiddleware import com.tangem.tap.features.details.redux.DetailsState import com.tangem.tap.features.home.redux.homeMiddleware import com.tangem.tap.features.send.redux.middlewares.sendMiddleware @@ -13,18 +15,19 @@ import org.rekotlin.Middleware import org.rekotlin.StateType data class AppState( - val navigationState: NavigationState = NavigationState(), - val globalState: GlobalState = GlobalState(), - val walletState: WalletState = WalletState(), - val sendState: SendState = SendState(), - val detailsState: DetailsState = DetailsState() + val navigationState: NavigationState = NavigationState(), + val globalState: GlobalState = GlobalState(), + val walletState: WalletState = WalletState(), + val sendState: SendState = SendState(), + val detailsState: DetailsState = DetailsState() ) : StateType { companion object { fun getMiddleware(): List> { return listOf( - logMiddleware, navigationMiddleware, notificationsMiddleware, - homeMiddleware, walletMiddleware, sendMiddleware + logMiddleware, navigationMiddleware, notificationsMiddleware, globalMiddleware, + homeMiddleware, walletMiddleware, sendMiddleware, + DetailsMiddleware().detailsMiddleware ) } } diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt index c1b700abec..60dba22fbc 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt @@ -9,4 +9,4 @@ data class NavigationState( val activity: WeakReference? = null ) : StateType -enum class AppScreen { Home, Wallet, Send, Details } \ No newline at end of file +enum class AppScreen { Home, Wallet, Send, Details, DetailsConfirm } \ No newline at end of file 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 01128b15c7..bddb0b3d6c 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 @@ -1,10 +1,44 @@ package com.tangem.tap.features.details.redux +import com.tangem.blockchain.common.Wallet import com.tangem.commands.Card +import com.tangem.tap.common.redux.NotificationAction +import com.tangem.tap.common.redux.global.FiatCurrencyName +import com.tangem.tap.network.coinmarketcap.FiatCurrency +import com.tangem.wallet.R import org.rekotlin.Action sealed class DetailsAction : Action { - data class SetCard(val card: Card): DetailsAction() + data class PrepareScreen( + val card: Card, + val wallet: Wallet?, + val fiatCurrencyName: FiatCurrencyName, + val fiatCurrencies: List? = null, + ): DetailsAction() + + + sealed class EraseWallet : DetailsAction() { + object Check : EraseWallet() + object Proceed : EraseWallet() { + object NotAllowedByCard: EraseWallet(), NotificationAction { + override val messageResource = R.string.details_notification_erase_wallet_not_allowed + } + object NotEmpty: EraseWallet(), NotificationAction { + override val messageResource = R.string.details_notification_erase_wallet_not_possible + } + } + object Confirm : EraseWallet() + object Cancel : EraseWallet() + object Failure : EraseWallet() + object Success : EraseWallet() + } + + sealed class AppCurrencyAction : DetailsAction() { + data class SetCurrencies(val currencies: List) : AppCurrencyAction() + object ChooseAppCurrency : AppCurrencyAction() + object Cancel: AppCurrencyAction() + data class SelectAppCurrency(val fiatCurrencyName: FiatCurrencyName): AppCurrencyAction() + } } \ No newline at end of file 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 78d6334eea..50a0d1d452 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 @@ -1 +1,81 @@ package com.tangem.tap.features.details.redux + +import com.tangem.commands.common.network.Result +import com.tangem.common.CompletionResult +import com.tangem.tap.common.redux.AppState +import com.tangem.tap.common.redux.global.GlobalAction +import com.tangem.tap.common.redux.navigation.AppScreen +import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.network.coinmarketcap.CoinMarketCapService +import com.tangem.tap.preferencesStorage +import com.tangem.tap.scope +import com.tangem.tap.store +import com.tangem.tap.tangemSdkManager +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.rekotlin.Middleware + +class DetailsMiddleware { + val detailsMiddleware: Middleware = { dispatch, state -> + { next -> + { action -> + when (action) { + is DetailsAction.PrepareScreen -> { + scope.launch { + val loadedCurrencies = preferencesStorage.getFiatCurrencies() + if (loadedCurrencies.isNullOrEmpty()) { + val response = CoinMarketCapService().getFiatCurrencies() + withContext(Dispatchers.Main) { + when (response) { + is Result.Success -> { + preferencesStorage.saveFiatCurrencies(response.data) + store.dispatch(DetailsAction.AppCurrencyAction.SetCurrencies(response.data)) + } + } + } + } else { + withContext(Dispatchers.Main) { + store.dispatch(DetailsAction.AppCurrencyAction.SetCurrencies(loadedCurrencies)) + } + } + } + + } + is DetailsAction.EraseWallet.Proceed -> { + when (store.state.detailsState.eraseWalletState) { + EraseWalletState.Allowed -> + store.dispatch(NavigationAction.NavigateTo(AppScreen.DetailsConfirm)) + EraseWalletState.NotAllowedByCard -> + store.dispatch(DetailsAction.EraseWallet.Proceed.NotAllowedByCard) + EraseWalletState.NotEmpty -> + store.dispatch(DetailsAction.EraseWallet.Proceed.NotEmpty) + } + } + is DetailsAction.EraseWallet.Cancel -> { + store.dispatch(NavigationAction.PopBackTo()) + } + is DetailsAction.EraseWallet.Confirm -> { + scope.launch { + val result = tangemSdkManager.eraseWallet() + withContext(Dispatchers.Main) { + when (result) { + is CompletionResult.Success -> { + store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) + } + } + } + } + } + is DetailsAction.AppCurrencyAction.SelectAppCurrency -> { + preferencesStorage.saveAppCurrency(action.fiatCurrencyName) + store.dispatch(GlobalAction.ChangeAppCurrency(action.fiatCurrencyName)) + store.dispatch(WalletAction.LoadFiatRate) + } + } + next(action) + } + } + } +} 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 711b3e67a9..ba2a2b0387 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 @@ -1,6 +1,8 @@ package com.tangem.tap.features.details.redux import com.tangem.commands.Card +import com.tangem.commands.Settings +import com.tangem.common.extensions.isZero import com.tangem.tap.common.redux.AppState import org.rekotlin.Action @@ -16,13 +18,76 @@ private fun internalReduce(action: Action, state: AppState): DetailsState { var detailsState = state.detailsState when (action) { - is DetailsAction.SetCard -> { - detailsState = DetailsState(card = action.card, cardInfo = action.card.toCardInfo()) + is DetailsAction.PrepareScreen -> { + detailsState = DetailsState( + card = action.card, wallet = action.wallet, + cardInfo = action.card.toCardInfo(), + appCurrencyState = AppCurrencyState( + action.fiatCurrencyName + ) + ) + } + is DetailsAction.EraseWallet -> { + detailsState = handleEraseWallet(action, detailsState) + } + is DetailsAction.AppCurrencyAction -> { + detailsState = handleAppCurrencyAction(action, detailsState) } } return detailsState } +private fun handleEraseWallet(action: DetailsAction.EraseWallet, state: DetailsState): DetailsState { + return when (action) { + DetailsAction.EraseWallet.Check -> { + val notAllowedByCard = state.card?.settingsMask?.contains(Settings.ProhibitPurgeWallet) == true + val notEmpty = state.wallet?.transactions?.isNullOrEmpty() != true || + state.wallet.amounts.toList().unzip().second.map { it.value?.isZero() }.contains(false) + val eraseWalletState = when { + notAllowedByCard -> EraseWalletState.NotAllowedByCard + notEmpty -> EraseWalletState.NotEmpty + else -> EraseWalletState.Allowed + } + state.copy(eraseWalletState = eraseWalletState) + } + DetailsAction.EraseWallet.Proceed -> { + if (state.eraseWalletState == EraseWalletState.Allowed) { + state.copy(confirmScreenState = ConfirmScreenState.EraseWallet) + } else { + state + } + } + DetailsAction.EraseWallet.Cancel -> state.copy(eraseWalletState = null) + DetailsAction.EraseWallet.Failure -> state.copy(eraseWalletState = null) + DetailsAction.EraseWallet.Success -> state.copy(eraseWalletState = null) + else -> state + } +} + +private fun handleAppCurrencyAction( + action: DetailsAction.AppCurrencyAction, state: DetailsState +): DetailsState { + return when (action) { + is DetailsAction.AppCurrencyAction.SetCurrencies -> { + state.copy(appCurrencyState = state.appCurrencyState.copy(fiatCurrencies = action.currencies)) + } + DetailsAction.AppCurrencyAction.ChooseAppCurrency -> { + state.copy(appCurrencyState = state.appCurrencyState.copy(showAppCurrencyDialog = true)) + } + DetailsAction.AppCurrencyAction.Cancel -> { + state.copy(appCurrencyState = state.appCurrencyState.copy(showAppCurrencyDialog = false)) + } + is DetailsAction.AppCurrencyAction.SelectAppCurrency -> { + state.copy( + appCurrencyState = state.appCurrencyState.copy( + fiatCurrencyName = action.fiatCurrencyName, showAppCurrencyDialog = false + ) + ) + } + else -> state + } +} + private fun Card.toCardInfo(): CardInfo? { val cardId = this.cardId.chunked(4).joinToString(separator = " ") val issuer = this.cardData?.issuerName ?: return null 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 0ef9e23e9a..304e7902c8 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 @@ -1,11 +1,19 @@ package com.tangem.tap.features.details.redux +import com.tangem.blockchain.common.Wallet import com.tangem.commands.Card +import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY +import com.tangem.tap.common.redux.global.FiatCurrencyName +import com.tangem.tap.network.coinmarketcap.FiatCurrency import org.rekotlin.StateType data class DetailsState( val card: Card? = null, - val cardInfo: CardInfo? = null + val wallet: Wallet? = null, + val cardInfo: CardInfo? = null, + val appCurrencyState: AppCurrencyState = AppCurrencyState(), + val eraseWalletState: EraseWalletState? = null, + val confirmScreenState: ConfirmScreenState? = null, ) : StateType data class CardInfo( @@ -13,3 +21,11 @@ data class CardInfo( val issuer: String, val signedHashes: Int ) + +enum class EraseWalletState { Allowed, NotAllowedByCard, NotEmpty } +enum class ConfirmScreenState { EraseWallet, LongTap, AccessCode, PassCode } +data class AppCurrencyState( + val fiatCurrencyName: FiatCurrencyName = DEFAULT_FIAT_CURRENCY, + val showAppCurrencyDialog: Boolean = false, + val fiatCurrencies: List? = null, +) 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 8ba573d72a..4875ef6449 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 @@ -6,6 +6,7 @@ import androidx.activity.OnBackPressedCallback import androidx.fragment.app.Fragment import androidx.transition.TransitionInflater import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.details.redux.DetailsState import com.tangem.tap.store import com.tangem.wallet.R @@ -15,6 +16,8 @@ import org.rekotlin.StoreSubscriber class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber { + var currencySelectionDialog = CurrencySelectionDialog() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { @@ -50,9 +53,6 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber R.string.wallet_button_send is WalletMainButton.CreateWalletButton -> R.string.wallet_button_create_wallet } - btn_main.text = getString(buttonTitle) - btn_main.isEnabled = state.mainButton.enabled + btn_confirm.text = getString(buttonTitle) + btn_confirm.isEnabled = state.mainButton.enabled - btn_main.setOnClickListener { + btn_confirm.setOnClickListener { when (state.mainButton) { is WalletMainButton.SendButton -> store.dispatch(WalletAction.Send()) is WalletMainButton.CreateWalletButton -> store.dispatch(WalletAction.CreateWallet) @@ -223,7 +223,10 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber { store.state.globalState.scanNoteResponse?.card?.let { card -> - store.dispatch(DetailsAction.SetCard(card)) + store.dispatch(DetailsAction.PrepareScreen( + card, store.state.walletState.wallet, + store.state.globalState.appCurrency + )) store.dispatch(NavigationAction.NavigateTo(AppScreen.Details)) true } diff --git a/app/src/main/res/layout/fragment_details.xml b/app/src/main/res/layout/fragment_details.xml index 792fa1942c..e15c215225 100644 --- a/app/src/main/res/layout/fragment_details.xml +++ b/app/src/main/res/layout/fragment_details.xml @@ -48,7 +48,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="14dp" - android:text="Card ID" + android:text="@string/details_card_id" android:textColor="@color/darkGray6" android:textSize="16sp" @@ -71,7 +71,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="14dp" - android:text="Issuer" + android:text="@string/details_issuer" android:textColor="@color/darkGray6" android:textSize="16sp" app:layout_constraintStart_toStartOf="parent" @@ -92,8 +92,7 @@ android:id="@+id/tv_signed_hashes_title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingBottom="14dp" - android:text="Signed" + android:text="@string/details_signed_hashes" android:textColor="@color/darkGray6" android:textSize="16sp" app:layout_constraintStart_toStartOf="parent" @@ -103,13 +102,136 @@ android:id="@+id/tv_signed_hashes" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingBottom="14dp" android:textColor="@color/darkGray1" android:textSize="16sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_issuer" tools:text="48 hashes" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_wallet.xml b/app/src/main/res/layout/fragment_wallet.xml index 1864b49550..66d8297ff7 100644 --- a/app/src/main/res/layout/fragment_wallet.xml +++ b/app/src/main/res/layout/fragment_wallet.xml @@ -20,8 +20,8 @@ android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" - app:navigationIcon="@drawable/ic_baseline_arrow_back_24" app:menu="@menu/wallet" + app:navigationIcon="@drawable/ic_baseline_arrow_back_24" app:title="@string/wallet_toolbar_title" /> @@ -37,8 +37,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" - android:overScrollMode="never" - > + android:overScrollMode="never"> + app:layout_constraintTop_toBottomOf="@id/iv_card" /> Tangem Tap Done + Cancel Retry and @@ -75,6 +76,17 @@ Transaction was signed and sent to the blockchain Details + Card settings prohibits from erasing wallet + You balance on this wallet is not zero, or you have unconfirmed transactions + Card ID + Issuer + Signed + Settings + App currency + Card + Validate card + Manage security + Erase wallet \ No newline at end of file From 1966925a947c2159d22657d3a9d2b24c4ff80bdb Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 16 Sep 2020 21:20:09 +0300 Subject: [PATCH 3/5] Updated on 2026-08-14 --- .../com/tangem/tap/domain/TangemSdkManager.kt | 6 + .../details/ui/DetailsConfirmFragment.kt | 77 +++++++++++++ .../res/layout/fragment_details_confirm.xml | 103 ++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/DetailsConfirmFragment.kt create mode 100644 app/src/main/res/layout/fragment_details_confirm.xml diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index 9fdfca3cd7..3c9b613d01 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -3,6 +3,8 @@ package com.tangem.tap.domain import androidx.activity.ComponentActivity import com.tangem.* import com.tangem.commands.CommandResponse +import com.tangem.commands.PurgeWalletCommand +import com.tangem.commands.PurgeWalletResponse import com.tangem.common.CompletionResult import com.tangem.common.extensions.CardType import com.tangem.tangem_sdk_new.extensions.init @@ -28,6 +30,10 @@ class TangemSdkManager(val activity: ComponentActivity) { return runTaskAsyncReturnOnMain(CreateWalletAndRescanTask()) } + suspend fun eraseWallet(): CompletionResult { + return runTaskAsyncReturnOnMain(PurgeWalletCommand()) + } + private suspend fun runTaskAsync( runnable: CardSessionRunnable, cardId: String? = null, initialMessage: Message? = null ): CompletionResult = diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsConfirmFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsConfirmFragment.kt new file mode 100644 index 0000000000..a13937adbf --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsConfirmFragment.kt @@ -0,0 +1,77 @@ +package com.tangem.tap.features.details.ui + +import android.os.Bundle +import android.view.View +import androidx.activity.OnBackPressedCallback +import androidx.fragment.app.Fragment +import androidx.transition.TransitionInflater +import com.tangem.tap.common.extensions.getDrawable +import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.features.details.redux.ConfirmScreenState +import com.tangem.tap.features.details.redux.DetailsAction +import com.tangem.tap.features.details.redux.DetailsState +import com.tangem.tap.store +import com.tangem.wallet.R +import kotlinx.android.synthetic.main.fragment_details_confirm.* +import org.rekotlin.StoreSubscriber + +class DetailsConfirmFragment : Fragment(R.layout.fragment_details_confirm), + StoreSubscriber { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + store.dispatch(NavigationAction.PopBackTo()) + } + }) + val inflater = TransitionInflater.from(requireContext()) + enterTransition = inflater.inflateTransition(R.transition.slide_right) + exitTransition = inflater.inflateTransition(R.transition.fade) + } + + override fun onStart() { + super.onStart() + store.subscribe(this) { state -> + state.skipRepeats { oldState, newState -> + oldState.detailsState == newState.detailsState + }.select { it.detailsState } + } + } + + override fun onStop() { + super.onStop() + store.unsubscribe(this) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + toolbar.setNavigationOnClickListener { + store.dispatch(NavigationAction.PopBackTo()) + } + } + + + override fun newState(state: DetailsState) { + if (activity == null) return + + when (state.confirmScreenState) { + ConfirmScreenState.EraseWallet -> { + toolbar.title = getString(R.string.details_erase_wallet) + btn_confirm.text = getString(R.string.details_erase_wallet) + btn_confirm.setCompoundDrawablesRelativeWithIntrinsicBounds( + null, null, getDrawable(R.drawable.ic_send), null + ) + btn_confirm.setOnClickListener { store.dispatch(DetailsAction.EraseWallet.Confirm) } + } + ConfirmScreenState.LongTap -> TODO() + ConfirmScreenState.AccessCode -> TODO() + ConfirmScreenState.PassCode -> TODO() + null -> TODO() + } + + + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_details_confirm.xml b/app/src/main/res/layout/fragment_details_confirm.xml new file mode 100644 index 0000000000..528dc0aa4c --- /dev/null +++ b/app/src/main/res/layout/fragment_details_confirm.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From a98af7681eb8ee4f37aa98ee43414cef3f1a0c00 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 16 Sep 2020 21:21:58 +0300 Subject: [PATCH 4/5] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 3 ++ .../tangem/tap/common/entities/TapCurrency.kt | 2 +- .../tangem/tap/common/extensions/Specific.kt | 10 ++-- .../tap/common/redux/global/GlobalAction.kt | 8 ++- .../common/redux/global/GlobalMidlleware.kt | 21 ++++++++ .../tap/common/redux/global/GlobalReducer.kt | 10 +++- .../tap/common/redux/global/GlobalState.kt | 21 ++++++-- .../com/tangem/tap/domain/TapWalletManager.kt | 14 ++--- .../details/ui/CurrencySelectionDialog.kt | 45 ++++++++++++++++ .../tap/features/home/redux/HomeMiddleware.kt | 2 + .../send/redux/reducers/AmountReducer.kt | 4 +- .../send/redux/reducers/ReceiptReducer.kt | 4 +- .../send/redux/reducers/SendScreenReducer.kt | 2 +- .../features/send/redux/states/SendState.kt | 3 +- .../tap/features/send/ui/SendFragment.kt | 2 +- .../tap/features/wallet/redux/WalletAction.kt | 3 +- .../features/wallet/redux/WalletMiddleware.kt | 2 +- .../features/wallet/redux/WalletReducer.kt | 23 +++++--- .../network/coinmarketcap/CoinMarketCapApi.kt | 7 ++- .../coinmarketcap/CoinMarketCapService.kt | 17 ++++-- .../tap/network/coinmarketcap/Response.kt | 36 ++++++++----- .../tap/persistence/PreferencesStorage.kt | 54 +++++++++++++++++++ 22 files changed, 241 insertions(+), 52 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/CurrencySelectionDialog.kt create mode 100644 app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index e55d54f88e..45e7e92da3 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -4,6 +4,7 @@ import android.app.Application import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.appReducer import com.tangem.tap.network.NetworkConnectivity +import com.tangem.tap.persistence.PreferencesStorage import com.tangem.wallet.BuildConfig import org.rekotlin.Store import timber.log.Timber @@ -13,10 +14,12 @@ val store = Store( middleware = AppState.getMiddleware(), state = AppState() ) +lateinit var preferencesStorage: PreferencesStorage class TapApplication : Application() { override fun onCreate() { super.onCreate() + preferencesStorage = PreferencesStorage(this) if (BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) 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 index 9e00a33525..1aa3f5c351 100644 --- a/app/src/main/java/com/tangem/tap/common/entities/TapCurrency.kt +++ b/app/src/main/java/com/tangem/tap/common/entities/TapCurrency.kt @@ -5,6 +5,6 @@ package com.tangem.tap.common.entities */ class TapCurrency { companion object{ - val main = "USD" + const val DEFAULT_FIAT_CURRENCY = "USD" } } \ 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 d4d8847066..bf905a0e9e 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 @@ -6,6 +6,8 @@ import com.google.zxing.BarcodeFormat import com.google.zxing.EncodeHintType import com.google.zxing.qrcode.QRCodeWriter import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel +import com.tangem.tap.common.redux.global.FiatCurrencyName +import com.tangem.tap.network.coinmarketcap.FiatCurrency import java.math.BigDecimal import java.math.RoundingMode import java.text.DecimalFormat @@ -46,10 +48,10 @@ fun BigDecimal.toFormattedString(decimals: Int): String { return df.format(bd) } -fun BigDecimal.toFiatString(rateValue: BigDecimal): String? { +fun BigDecimal.toFiatString(rateValue: BigDecimal, fiatCurrencyName: FiatCurrencyName): String? { var fiatValue = rateValue.multiply(this) fiatValue = fiatValue.setScale(2, RoundingMode.DOWN) - return "≈ USD  $fiatValue" + return "≈ ${fiatCurrencyName}  $fiatValue" } fun BigDecimal.stripZeroPlainString(): String = this.stripTrailingZeros().toPlainString() @@ -67,4 +69,6 @@ fun BigDecimal.isGreaterThanOrEqual(value: BigDecimal): Boolean { fun BigDecimal.isLessThanOrEqual(value: BigDecimal): Boolean { val compareResult = this.compareTo(value) return compareResult == -1 || compareResult == 0 -} \ No newline at end of file +} + +fun FiatCurrency.toFormattedString(): String = "${this.name} (${this.symbol}) - ${this.sign}" \ No newline at end of file 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 8a4412c114..b262647600 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 @@ -7,5 +7,11 @@ import java.math.BigDecimal sealed class GlobalAction : Action { data class SaveScanNoteResponse(val scanNoteResponse: ScanNoteResponse) : GlobalAction() - data class SetFiatRate(val fiatRates: Pair) : GlobalAction() + data class SetFiatRate( + val fiatRates: Pair + ) : GlobalAction() + data class ChangeAppCurrency(val appCurrency: FiatCurrencyName) : GlobalAction() + object RestoreAppCurrency : GlobalAction() { + data class Success(val appCurrency: FiatCurrencyName) : GlobalAction() + } } \ 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 new file mode 100644 index 0000000000..d7ec41960f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt @@ -0,0 +1,21 @@ +package com.tangem.tap.common.redux.global + +import com.tangem.tap.common.redux.AppState +import com.tangem.tap.preferencesStorage +import com.tangem.tap.store +import org.rekotlin.Middleware + +val globalMiddleware: Middleware = { dispatch, appState -> + { nextDispatch -> + { action -> + when (action) { + is GlobalAction.RestoreAppCurrency -> { + store.dispatch(GlobalAction.RestoreAppCurrency.Success( + preferencesStorage.getAppCurrency() + )) + } + } + nextDispatch(action) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt index 71fa1cfb50..b3f496719c 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt @@ -13,9 +13,15 @@ fun globalReducer(action: Action, state: AppState): GlobalState { is GlobalAction.SaveScanNoteResponse -> newState = newState.copy(scanNoteResponse = action.scanNoteResponse) is GlobalAction.SetFiatRate -> { - val rates = newState.fiatRates.rates.toMutableMap() + val rates = newState.conversionRates.rates.toMutableMap() rates[action.fiatRates.first] = action.fiatRates.second - newState = newState.copy(fiatRates = FiatRates(rates)) + newState = newState.copy(conversionRates = ConversionRates(rates)) + } + is GlobalAction.ChangeAppCurrency -> { + newState = newState.copy(appCurrency = action.appCurrency, conversionRates = ConversionRates(mapOf())) + } + is GlobalAction.RestoreAppCurrency.Success -> { + newState = newState.copy(appCurrency = action.appCurrency, conversionRates = ConversionRates(mapOf())) } } return newState 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 6ea19cc94e..9da6906d9c 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 @@ -1,22 +1,33 @@ package com.tangem.tap.common.redux.global +import com.tangem.commands.common.network.TangemService +import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY +import com.tangem.tap.domain.PayIdManager import com.tangem.tap.domain.TapWalletManager import com.tangem.tap.domain.tasks.ScanNoteResponse +import com.tangem.tap.network.coinmarketcap.CoinMarketCapService import org.rekotlin.StateType import java.math.BigDecimal data class GlobalState( val scanNoteResponse: ScanNoteResponse? = null, val tapWalletManager: TapWalletManager = TapWalletManager(), - val fiatRates: FiatRates = FiatRates(emptyMap()), + val payIdManager: PayIdManager = PayIdManager(), + val coinMarketCapService: CoinMarketCapService = CoinMarketCapService(), + val tangemService: TangemService = TangemService(), + val conversionRates: ConversionRates = ConversionRates(emptyMap()), + val appCurrency: FiatCurrencyName = DEFAULT_FIAT_CURRENCY ) : StateType -data class FiatRates( - val rates: Map +data class ConversionRates( + val rates: Map, ) { - fun getRateForCryptoCurrency(currency: String): BigDecimal? { - return rates[currency] + + fun getRate(cryptoCurrency: CryptoCurrencyName): BigDecimal? { + return rates[cryptoCurrency] } } +typealias CryptoCurrencyName = String +typealias FiatCurrencyName = String diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index 373d4d5f41..30e36dfd81 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -8,6 +8,8 @@ import com.tangem.commands.common.network.Result import com.tangem.commands.common.network.TangemService import com.tangem.common.extensions.toHexString import com.tangem.tap.TapConfig +import com.tangem.tap.common.redux.global.CryptoCurrencyName +import com.tangem.tap.common.redux.global.FiatCurrencyName import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.tasks.ScanNoteResponse import com.tangem.tap.features.wallet.redux.PayIdState @@ -54,15 +56,15 @@ class TapWalletManager { result?.let { handlePayIdResult(it) } } - suspend fun loadFiatRate() { + suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName) { val wallet = store.state.globalState.scanNoteResponse?.walletManager?.wallet val blockchainCurrency = wallet?.blockchain?.currency val tokenCurrency = wallet?.token?.symbol - val blockchainRate = blockchainCurrency?.let { coinMarketCapService.getRate(it) } - val tokenRate = tokenCurrency?.let { coinMarketCapService.getRate(it) } + val blockchainRate = blockchainCurrency?.let { coinMarketCapService.getRate(it, fiatCurrency) } + val tokenRate = tokenCurrency?.let { coinMarketCapService.getRate(it, fiatCurrency) } - val results = mutableListOf?>>() + val results = mutableListOf?>>() if (blockchainCurrency != null) results.add(blockchainCurrency to blockchainRate) if (tokenCurrency != null) results.add(tokenCurrency to tokenRate) @@ -83,7 +85,7 @@ class TapWalletManager { store.dispatch(WalletAction.LoadWallet) store.dispatch(WalletAction.LoadFiatRate) store.dispatch(WalletAction.LoadPayId) - } else if (data.card.status == CardStatus.Empty){ + } else if (data.card.status == CardStatus.Empty) { store.dispatch(WalletAction.EmptyWallet) } else { store.dispatch(WalletAction.LoadData.Failure(TapError.UnknownBlockchain)) @@ -153,7 +155,7 @@ class TapWalletManager { } } - private suspend fun handleFiatRatesResult(results: List?>>) { + private suspend fun handleFiatRatesResult(results: List?>>) { withContext(Dispatchers.Main) { results.map { when (it.second) { 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 new file mode 100644 index 0000000000..a2267999e0 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/CurrencySelectionDialog.kt @@ -0,0 +1,45 @@ +package com.tangem.tap.features.details.ui + +import android.content.Context +import androidx.appcompat.app.AlertDialog +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.tangem.tap.common.extensions.toFormattedString +import com.tangem.tap.common.redux.global.FiatCurrencyName +import com.tangem.tap.features.details.redux.DetailsAction +import com.tangem.tap.network.coinmarketcap.FiatCurrency +import com.tangem.tap.store +import com.tangem.wallet.R + +class CurrencySelectionDialog { + + var dialog: AlertDialog? = null + + fun show(currencies: List, currentAppCurrency: FiatCurrencyName, context: Context) { + + if (dialog == null) { + val currenciesToShow = currencies.map { it.toFormattedString() }.toTypedArray() + var currentSelection = currencies.indexOfFirst { it.symbol == currentAppCurrency } + + dialog = MaterialAlertDialogBuilder(context) + .setTitle(context.getString(R.string.details_currency)) + .setNeutralButton(context.getString(R.string.generic_cancel)) { _, _ -> + store.dispatch(DetailsAction.AppCurrencyAction.Cancel) + } + .setPositiveButton(context.getString(R.string.generic_done)) { _, _ -> + val selectedCurrency = currencies[currentSelection] + store.dispatch(DetailsAction.AppCurrencyAction.SelectAppCurrency(selectedCurrency.symbol)) + } + .setOnDismissListener { + store.dispatch(DetailsAction.AppCurrencyAction.Cancel) + } + .setSingleChoiceItems(currenciesToShow, currentSelection) { _, which -> + currentSelection = which + }.show() + } + } + + fun clear() { + dialog = null + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index 6a25e7251d..bbb05df3e4 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -5,6 +5,7 @@ import android.net.Uri import androidx.core.content.ContextCompat.startActivity import com.tangem.common.CompletionResult import com.tangem.tap.common.redux.AppState +import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.scope @@ -25,6 +26,7 @@ val homeMiddleware: Middleware = { dispatch, state -> withContext(Dispatchers.Main) { when (result) { is CompletionResult.Success -> { + store.dispatch(GlobalAction.RestoreAppCurrency) store.state.globalState.tapWalletManager.onCardScanned(result.data) store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AmountReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AmountReducer.kt index efeae4552c..5129a95646 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AmountReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AmountReducer.kt @@ -2,7 +2,6 @@ package com.tangem.tap.features.send.redux.reducers import com.tangem.common.extensions.isZero import com.tangem.tap.common.CurrencyConverter -import com.tangem.tap.common.entities.TapCurrency import com.tangem.tap.common.extensions.isNegative import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.features.send.redux.AmountAction @@ -13,6 +12,7 @@ import com.tangem.tap.features.send.redux.states.AmountState import com.tangem.tap.features.send.redux.states.MainCurrencyType import com.tangem.tap.features.send.redux.states.SendState import com.tangem.tap.features.send.redux.states.Value +import com.tangem.tap.store import java.math.BigDecimal /** @@ -42,7 +42,7 @@ class AmountReducer : SendInternalReducer { state.copy( viewAmountValue = fiatToSend.stripZeroPlainString(), viewBalanceValue = converter.toFiat(state.balanceCrypto).stripZeroPlainString(), - mainCurrency = Value(MainCurrencyType.FIAT, TapCurrency.main), + mainCurrency = Value(MainCurrencyType.FIAT, store.state.globalState.appCurrency), maxLengthOfAmount = sendState.getDecimals(action.mainCurrency), cursorAtTheSamePosition = false ) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt index 0776c99fe4..91726cb199 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt @@ -3,11 +3,11 @@ package com.tangem.tap.features.send.redux.reducers import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.Wallet import com.tangem.tap.common.CurrencyConverter -import com.tangem.tap.common.entities.TapCurrency import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.features.send.redux.ReceiptAction.RefreshReceipt import com.tangem.tap.features.send.redux.SendScreenAction import com.tangem.tap.features.send.redux.states.* +import com.tangem.tap.store /** [REDACTED_AUTHOR] @@ -163,7 +163,7 @@ class ReceiptReducer : SendInternalReducer { private fun determineSymbols(wallet: Wallet): ReceiptSymbols { return ReceiptSymbols( - fiat = TapCurrency.main, + fiat = store.state.globalState.appCurrency, crypto = wallet.blockchain.currency, token = wallet.amounts[AmountType.Token]?.currencySymbol ) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt index 6d932b4654..858b626b15 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt @@ -65,7 +65,7 @@ private class PrepareSendScreenStatesReducer : SendInternalReducer { } private fun createCurrencyConverter(walletManager: WalletManager): CurrencyConverter { - val rate = store.state.globalState.fiatRates.getRateForCryptoCurrency(walletManager.wallet.blockchain.currency) + val rate = store.state.globalState.conversionRates.getRate(walletManager.wallet.blockchain.currency) return if (rate == null) CurrencyConverter(BigDecimal.ONE) else CurrencyConverter(rate) } } 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 4d3cc3cd98..c7af7809bd 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,7 +5,6 @@ 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.TapCurrency import com.tangem.tap.features.send.redux.AmountAction import com.tangem.tap.store import org.rekotlin.StateType @@ -60,7 +59,7 @@ enum class SendButtonState { data class AmountState( val viewAmountValue: String = BigDecimal.ZERO.toPlainString(), val viewBalanceValue: String = BigDecimal.ZERO.toPlainString(), - val mainCurrency: Value = Value(MainCurrencyType.FIAT, TapCurrency.main), + val mainCurrency: Value = Value(MainCurrencyType.FIAT, store.state.globalState.appCurrency), val typeOfAmount: AmountType = AmountType.Coin, val amountToSendCrypto: BigDecimal = BigDecimal.ZERO, val balanceCrypto: BigDecimal = BigDecimal.ZERO, 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 5665e0ffa2..8201b03f38 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 @@ -197,7 +197,7 @@ 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.main) + val mainCurrency = sp.getString("mainCurrency", TapCurrency.DEFAULT_FIAT_CURRENCY) val foundType = MainCurrencyType.values() .firstOrNull { it.name.toLowerCase() == mainCurrency!!.toLowerCase() } ?: MainCurrencyType.FIAT return foundType 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 af4908547c..4e1d6ea32e 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 @@ -6,6 +6,7 @@ import com.tangem.blockchain.common.Wallet import com.tangem.commands.Card import com.tangem.tap.common.redux.ErrorAction import com.tangem.tap.common.redux.NotificationAction +import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.domain.TapError import com.tangem.wallet.R import org.rekotlin.Action @@ -24,7 +25,7 @@ sealed class WalletAction : Action { } object LoadFiatRate : WalletAction() { - data class Success(val fiatRates: Pair) : WalletAction() + data class Success(val fiatRates: Pair) : WalletAction() object Failure : WalletAction() } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt index 0bd11d47b6..558f348582 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt @@ -42,7 +42,7 @@ val walletMiddleware: Middleware = { dispatch, state -> } is WalletAction.LoadFiatRate -> { scope.launch { - store.state.globalState.tapWalletManager.loadFiatRate() + store.state.globalState.tapWalletManager.loadFiatRate(store.state.globalState.appCurrency) } } is WalletAction.LoadArtwork -> { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt index f0b29211a5..d015483883 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt @@ -86,10 +86,11 @@ private fun internalReduce(action: Action, state: AppState): WalletState { ) } is WalletAction.LoadWallet.Success -> { + val fiatCurrencySymbol = state.globalState.appCurrency val token = action.wallet.amounts[AmountType.Token] val tokenData = if (token != null) { - val tokenFiatRate = state.globalState.fiatRates.getRateForCryptoCurrency(token.currencySymbol) - val tokenFiatAmount = tokenFiatRate?.let { token.value?.toFiatString(it) } + val tokenFiatRate = state.globalState.conversionRates.getRate(token.currencySymbol) + val tokenFiatAmount = tokenFiatRate?.let { token.value?.toFiatString(it, fiatCurrencySymbol) } TokenData( token.value?.toFormattedString(token.decimals) ?: "", token.currencySymbol, tokenFiatAmount) @@ -97,8 +98,8 @@ private fun internalReduce(action: Action, state: AppState): WalletState { null } val amount = action.wallet.amounts[AmountType.Coin]?.value - val fiatRate = state.globalState.fiatRates.getRateForCryptoCurrency(action.wallet.blockchain.currency) - val fiatAmount = fiatRate?.let { amount?.toFiatString(it) } + val fiatRate = state.globalState.conversionRates.getRate(action.wallet.blockchain.currency) + val fiatAmount = fiatRate?.let { amount?.toFiatString(it, fiatCurrencySymbol) } val pendingTransactions = action.wallet.transactions .toPendingTransactions(action.wallet.address) @@ -135,16 +136,24 @@ private fun internalReduce(action: Action, state: AppState): WalletState { errorMessage = action.errorMessage ) ) + is WalletAction.LoadFiatRate -> { + newState.copy(currencyData = newState.currencyData.copy( + fiatAmount = null, + token = newState.currencyData.token?.copy(fiatAmount = null)) + ) + } is WalletAction.LoadFiatRate.Success -> { - val rate = action.fiatRates.second + val rate = action.fiatRates.second ?: return newState val currency = action.fiatRates.first val fiatAmount = if (currency == newState.wallet?.blockchain?.currency) { - newState.wallet?.amounts?.get(AmountType.Coin)?.value?.toFiatString(rate) + newState.wallet?.amounts?.get(AmountType.Coin)?.value + ?.toFiatString(rate, state.globalState.appCurrency) } else { newState.currencyData.fiatAmount } val tokenFiatAmount = if (currency == newState.wallet?.token?.symbol) { - newState.wallet?.amounts?.get(AmountType.Token)?.value?.toFiatString(rate) + newState.wallet?.amounts?.get(AmountType.Token)?.value + ?.toFiatString(rate, state.globalState.appCurrency) } else { newState.currencyData.token?.fiatAmount } 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 index 0c356d478e..47889ff06d 100644 --- a/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapApi.kt +++ b/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapApi.kt @@ -12,9 +12,14 @@ interface CoinMarketCapApi { @GET("v1/tools/price-conversion") suspend fun getRateInfo( @Query("amount") amount: Int, - @Query("symbol") cryptoId: String + @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/" 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 index 5350bad116..4dc7931623 100644 --- a/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapService.kt +++ b/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapService.kt @@ -2,6 +2,7 @@ package com.tangem.tap.network.coinmarketcap import com.tangem.commands.common.network.Result import com.tangem.commands.common.network.performRequest +import com.tangem.tap.common.redux.global.FiatCurrencyName import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.math.BigDecimal @@ -9,10 +10,20 @@ import java.math.BigDecimal class CoinMarketCapService { private val api: CoinMarketCapApi by lazy { CoinMarketCapApi.create() } - suspend fun getRate(currency: String): Result = withContext(Dispatchers.IO) { - val response = performRequest { api.getRateInfo(1, currency) } + 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.quote.usd.price) + 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 } } 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 index f4ec9fa804..7320d9467c 100644 --- a/app/src/main/java/com/tangem/tap/network/coinmarketcap/Response.kt +++ b/app/src/main/java/com/tangem/tap/network/coinmarketcap/Response.kt @@ -5,21 +5,14 @@ import com.squareup.moshi.JsonClass import java.math.BigDecimal @JsonClass(generateAdapter = true) -data class RateInfoResponse( - val status: Status, - val data: RateData -) +class RateInfoResponse : CoinMarketResponse() @JsonClass(generateAdapter = true) data class RateData( - val quote: Quote -) - -@JsonClass(generateAdapter = true) -data class Quote( - @Json(name = "USD") - val usd: CurrencyRate -) + val quote: Map +) { + fun getRate(): BigDecimal = quote.values.first().price +} @JsonClass(generateAdapter = true) data class CurrencyRate( @@ -38,4 +31,21 @@ data class Status( @Json(name = "credit_count") val creditCount: Int, val notice: String? -) \ No newline at end of file +) + +@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 +) diff --git a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt new file mode 100644 index 0000000000..bbaa2aa7b2 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt @@ -0,0 +1,54 @@ +package com.tangem.tap.persistence + +import android.app.Application +import android.content.Context +import android.content.SharedPreferences +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.Moshi +import com.squareup.moshi.Types +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY +import com.tangem.tap.common.redux.global.FiatCurrencyName +import com.tangem.tap.network.coinmarketcap.FiatCurrency + + +class PreferencesStorage(applicationContext: Application) { + + private val preferences: SharedPreferences by lazy { + applicationContext.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE) + } + + private val fiatCurrenciesAdapter: JsonAdapter> by lazy { + val moshi = Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() + val type = Types.newParameterizedType(List::class.java, FiatCurrency::class.java) + moshi.adapter(type) + } + + fun getAppCurrency(): FiatCurrencyName { + return preferences.getString(APP_CURRENCY_KEY, DEFAULT_FIAT_CURRENCY) + ?: DEFAULT_FIAT_CURRENCY + } + + fun saveAppCurrency(fiatCurrencyName: FiatCurrencyName) { + return preferences.edit().putString(APP_CURRENCY_KEY, fiatCurrencyName).apply() + } + + fun getFiatCurrencies(): List? { + val json = preferences.getString(FIAT_CURRENCIES_KEY, "") + return if (json.isNullOrBlank()) null else fiatCurrenciesAdapter.fromJson(json) as List + } + + fun saveFiatCurrencies(currencies: List) { + val json: String = fiatCurrenciesAdapter.toJson(currencies) + return preferences.edit().putString(FIAT_CURRENCIES_KEY, json).apply() + } + + companion object { + private const val PREFERENCES_NAME = "tapPrefs" + private const val APP_CURRENCY_KEY = "appCurrency" + private const val FIAT_CURRENCIES_KEY = "fiatCurrencies" + } + +} \ No newline at end of file From a0a67096051dd58951d58b3fff42171cba9f90bd Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 17 Sep 2020 13:06:57 +0300 Subject: [PATCH 5/5] Updated on 2026-08-14 --- .idea/dictionaries/romanpotapov.xml | 8 ++++++++ .../com/tangem/tap/features/details/ui/DetailsFragment.kt | 2 +- .../tangem/tap/features/send/redux/states/SendState.kt | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 .idea/dictionaries/romanpotapov.xml diff --git a/.idea/dictionaries/romanpotapov.xml b/.idea/dictionaries/romanpotapov.xml new file mode 100644 index 0000000000..22eae8bc66 --- /dev/null +++ b/.idea/dictionaries/romanpotapov.xml @@ -0,0 +1,8 @@ + + + + blockchain + tangem + + + \ No newline at end of file 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 4875ef6449..eeca408c37 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 @@ -16,7 +16,7 @@ import org.rekotlin.StoreSubscriber class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber { - var currencySelectionDialog = CurrencySelectionDialog() + private var currencySelectionDialog = CurrencySelectionDialog() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) 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 c7af7809bd..7d3df6c928 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,6 +5,7 @@ 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.TapCurrency import com.tangem.tap.features.send.redux.AmountAction import com.tangem.tap.store import org.rekotlin.StateType @@ -59,7 +60,7 @@ enum class SendButtonState { data class AmountState( val viewAmountValue: String = BigDecimal.ZERO.toPlainString(), val viewBalanceValue: String = BigDecimal.ZERO.toPlainString(), - val mainCurrency: Value = Value(MainCurrencyType.FIAT, store.state.globalState.appCurrency), + val mainCurrency: Value = Value(MainCurrencyType.FIAT, TapCurrency.DEFAULT_FIAT_CURRENCY), val typeOfAmount: AmountType = AmountType.Coin, val amountToSendCrypto: BigDecimal = BigDecimal.ZERO, val balanceCrypto: BigDecimal = BigDecimal.ZERO,