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/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/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt
index 1890cabce0..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,8 @@ 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
import com.tangem.tap.features.wallet.ui.WalletFragment
@@ -36,5 +38,7 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
AppScreen.Home -> HomeFragment()
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/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/AppReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt
index 68a809b4ec..c02184fd51 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
@@ -3,6 +3,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.send.redux.reducers.SendScreenReducer
+import com.tangem.tap.features.details.redux.DetailsReducer
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 = SendScreenReducer.reduce(action, state.sendState)
+ navigationState = NavigationReducer.reduce(action, state),
+ globalState = globalReducer(action, state),
+ walletState = WalletReducer.reduce(action, state),
+ sendState = SendScreenReducer.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 9e3bdf3e9b..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,11 @@
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
import com.tangem.tap.features.send.redux.states.SendState
@@ -12,17 +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 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/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/common/redux/navigation/NavigationState.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt
index 7fcff63909..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 }
\ 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/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/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/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt
new file mode 100644
index 0000000000..bddb0b3d6c
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt
@@ -0,0 +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 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
new file mode 100644
index 0000000000..50a0d1d452
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt
@@ -0,0 +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
new file mode 100644
index 0000000000..ba2a2b0387
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt
@@ -0,0 +1,96 @@
+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
+
+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.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
+ 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..304e7902c8
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt
@@ -0,0 +1,31 @@
+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 wallet: Wallet? = null,
+ val cardInfo: CardInfo? = null,
+ val appCurrencyState: AppCurrencyState = AppCurrencyState(),
+ val eraseWalletState: EraseWalletState? = null,
+ val confirmScreenState: ConfirmScreenState? = null,
+) : StateType
+
+data class CardInfo(
+ val cardId: String,
+ 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/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/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/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..eeca408c37
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt
@@ -0,0 +1,90 @@
+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.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.*
+import kotlinx.android.synthetic.main.fragment_wallet.toolbar
+import org.rekotlin.StoreSubscriber
+
+class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber {
+
+ private var currencySelectionDialog = CurrencySelectionDialog()
+
+ 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()
+ }
+
+ tv_erase_wallet.setOnClickListener {
+ store.dispatch(DetailsAction.EraseWallet.Check)
+ store.dispatch(DetailsAction.EraseWallet.Proceed)
+ }
+
+ tv_app_currency.text = state.appCurrencyState.fiatCurrencyName
+
+ tv_app_currency_title.setOnClickListener {
+ store.dispatch(DetailsAction.AppCurrencyAction.ChooseAppCurrency)
+ }
+
+ if (state.appCurrencyState.showAppCurrencyDialog &&
+ !state.appCurrencyState.fiatCurrencies.isNullOrEmpty()) {
+ currencySelectionDialog.show(
+ state.appCurrencyState.fiatCurrencies,
+ state.appCurrencyState.fiatCurrencyName,
+ requireContext()
+ )
+ } else {
+ currencySelectionDialog.clear()
+ }
+
+ }
+
+}
\ 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..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
@@ -60,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, TapCurrency.main),
+ 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,
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/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt
index d461023e6d..8aa533ea8d 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 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)
@@ -211,4 +219,25 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber {
+ store.state.globalState.scanNoteResponse?.card?.let { card ->
+ store.dispatch(DetailsAction.PrepareScreen(
+ card, store.state.walletState.wallet,
+ store.state.globalState.appCurrency
+ ))
+ 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/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
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..e15c215225
--- /dev/null
+++ b/app/src/main/res/layout/fragment_details.xml
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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
diff --git a/app/src/main/res/layout/fragment_wallet.xml b/app/src/main/res/layout/fragment_wallet.xml
index ccaf8611ff..66d8297ff7 100644
--- a/app/src/main/res/layout/fragment_wallet.xml
+++ b/app/src/main/res/layout/fragment_wallet.xml
@@ -20,6 +20,7 @@
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
+ app:menu="@menu/wallet"
app:navigationIcon="@drawable/ic_baseline_arrow_back_24"
app:title="@string/wallet_toolbar_title" />
@@ -36,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" />
+
\ 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 d0eaa3b368..a70f1fea25 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -3,6 +3,7 @@
Tangem Tap
Done
+ Cancel
Retry
and
@@ -74,4 +75,18 @@
Maximum amount
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