Updated on 2026-08-14

This commit is contained in:
Tangem 2020-09-08 14:35:08 +03:00
parent 6f62e15621
commit 6f4d7d2ce4
11 changed files with 120 additions and 43 deletions

View file

@ -21,6 +21,6 @@ class TapApplication : Application() {
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}
NetworkConnectivity(store, this)
NetworkConnectivity.createInstance(store, this)
}
}

View file

@ -11,6 +11,7 @@ import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.features.wallet.redux.PayIdState
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.network.NetworkConnectivity
import com.tangem.tap.network.coinmarketcap.CoinMarketCapService
import com.tangem.tap.store
import kotlinx.coroutines.Dispatchers
@ -71,6 +72,10 @@ class TapWalletManager {
withContext(Dispatchers.Main) {
store.dispatch(GlobalAction.SaveScanNoteResponse(data))
if (data.walletManager != null) {
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
store.dispatch(WalletAction.LoadData.NoInternetConnection)
return@withContext
}
data.verifyResponse?.artworkInfo?.id?.let {
store.dispatch(WalletAction.LoadArtwork(data.card, it))
}

View file

@ -12,42 +12,51 @@ import java.math.BigDecimal
sealed class WalletAction : Action {
object LoadData : WalletAction()
object LoadData : WalletAction() {
object NoInternetConnection : WalletAction()
}
object LoadWallet : WalletAction() {
data class Success(val wallet: Wallet): WalletAction()
data class NoAccount(val amountToCreateAccount: Int): WalletAction()
data class Failure(val errorMessage: String? = null): WalletAction()
data class Success(val wallet: Wallet) : WalletAction()
data class NoAccount(val amountToCreateAccount: Int) : WalletAction()
data class Failure(val errorMessage: String? = null) : WalletAction()
}
object LoadFiatRate : WalletAction() {
data class Success(val fiatRates: Pair<String, BigDecimal>) : WalletAction()
object Failure: WalletAction()
object Failure : WalletAction()
}
object LoadPayId : WalletAction() {
data class Success(val payId: String): WalletAction()
object NotCreated: WalletAction()
object Failure: WalletAction()
data class Success(val payId: String) : WalletAction()
object NotCreated : WalletAction()
object Failure : WalletAction()
}
data class LoadArtwork(val card: Card, val artworkId: String) : WalletAction() {
data class Success(val artworkId: String, val artwork: ByteArray) : WalletAction()
object Failure: WalletAction()
object Failure : WalletAction()
}
object Scan : WalletAction()
object Send : WalletAction()
object CreatePayId : WalletAction() {
data class CompleteCreatingPayId(val payId: String): WalletAction()
data class Success(val payId: String): WalletAction()
object EmptyField: WalletAction(), ErrorAction {
data class CompleteCreatingPayId(val payId: String) : WalletAction()
data class Success(val payId: String) : WalletAction()
object EmptyField : WalletAction(), ErrorAction {
override val error = TapError.PayIdEmptyField
}
class Failure(override val error: TapError) : WalletAction(), ErrorAction
object Cancel: WalletAction()
object Cancel : WalletAction()
}
data class CopyAddress(val context: Context) : WalletAction() {
object Success : WalletAction(), NotificationAction {
override val messageResource = R.string.notification_address_copied
}
}
object ShowQrCode : WalletAction()
object HideQrCode : WalletAction()
data class ExploreAddress(val context: Context) : WalletAction()

View file

@ -10,6 +10,7 @@ import com.tangem.tap.common.extensions.copyToClipboard
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.domain.PayIdManager
import com.tangem.tap.domain.TapError
import com.tangem.tap.network.NetworkStateChanged
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
@ -90,7 +91,7 @@ val walletMiddleware: Middleware<AppState> = { dispatch, state ->
}
}
}
is WalletAction.LoadData -> {
is WalletAction.LoadData, is NetworkStateChanged -> {
scope.launch {
store.state.globalState.scanNoteResponse?.let {
store.state.globalState.tapWalletManager.onCardScanned(it)

View file

@ -31,6 +31,23 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
currencyData = BalanceWidgetData(BalanceStatus.EmptyCard),
mainButton = WalletMainButton.CreateWalletButton(true)
)
is WalletAction.LoadData.NoInternetConnection -> {
val wallet = state.globalState.scanNoteResponse?.walletManager?.wallet
val addressData = if (wallet == null) {
null
} else {
AddressData(wallet.address, wallet.shareUrl, wallet.exploreUrl)
}
newState = WalletState(
state = ProgressState.Error,
error = ErrorType.NoInternetConnection,
addressData = addressData,
currencyData = BalanceWidgetData(
status = BalanceStatus.Unreachable,
currency = wallet?.blockchain?.fullName),
mainButton = WalletMainButton.SendButton(false)
)
}
is WalletAction.LoadWallet -> {
val wallet = state.globalState.scanNoteResponse?.walletManager?.wallet
val addressData = if (wallet == null) {

View file

@ -9,6 +9,7 @@ import org.rekotlin.StateType
data class WalletState(
val state: ProgressState = ProgressState.Done,
val error: ErrorType? = null,
val cardImage: Artwork? = null,
val wallet: Wallet? = null,
val pendingTransactions: List<PendingTransaction> = emptyList(),
@ -23,6 +24,8 @@ data class WalletState(
enum class ProgressState { Loading, Done, Error }
enum class ErrorType { NoInternetConnection }
enum class PayIdState { Disabled, Loading, NotCreated, Created, ErrorLoading }
data class PayIdData(

View file

@ -10,13 +10,6 @@ import kotlinx.android.synthetic.main.layout_balance.*
import kotlinx.android.synthetic.main.layout_balance_error.*
import kotlinx.android.synthetic.main.layout_token.view.*
enum class PayIdState {
Loading,
NotCreated,
Loaded,
Error
}
enum class BalanceStatus {
VerifiedOnline,
Unreachable,
@ -54,12 +47,14 @@ class BalanceWidget(
BalanceStatus.Loading -> {
fragment.l_balance.show()
fragment.l_balance_error.hide()
fragment.tv_fiat_amount.hide()
fragment.l_token.hide()
fragment.tv_currency.text = data.currency
fragment.tv_currency_symbol.text = "-"
fragment.tv_amount.text = ""
fragment.tv_fiat_amount.hide()
showStatus(R.id.tv_status_loading)
fragment.l_token.hide()
}
BalanceStatus.VerifiedOnline -> {
fragment.l_balance.show()
@ -78,14 +73,18 @@ class BalanceWidget(
fragment.l_token.tv_token_fiat_amount.text = data.token.fiatAmount
} else {
fragment.l_token.hide()
}
}
BalanceStatus.Unreachable -> {
fragment.l_balance.show()
fragment.l_balance_error.hide()
fragment.l_token.hide()
fragment.tv_fiat_amount.hide()
fragment.tv_currency.text = data.currency
fragment.tv_currency_symbol.text = "-"
fragment.tv_amount.text = ""
showStatus(R.id.tv_status_error)
}
BalanceStatus.EmptyCard -> {
@ -112,15 +111,4 @@ class BalanceWidget(
fragment.tv_status_loading.show(viewRes == R.id.tv_status_loading)
fragment.tv_status_verified.show(viewRes == R.id.tv_status_verified)
}
}
enum class BalanceErrorWidgetState {
NoAccount,
NoWallet,
BlockchainError
}
class BalanceErrorWidget(
)
}

View file

@ -7,13 +7,13 @@ import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.transition.TransitionInflater
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.wallet.redux.*
import com.tangem.tap.features.wallet.redux.PayIdState
import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.card_balance.*
@ -26,6 +26,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
private var qrDialog: QrDialog? = null
private var payIdDialog: PayIdDialog? = null
private var snackbar: Snackbar? = null
private lateinit var viewAdapter: PendingTransactionsAdapter
@ -84,6 +85,8 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
store.dispatch(WalletAction.LoadData)
}
setupNoInternetHandling(state)
setupButtons(state)
setupAddressCard(state)
setupCardImage(state.cardImage?.artwork)
@ -137,6 +140,22 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
}
}
private fun setupNoInternetHandling(state: WalletState) {
if (state.state == ProgressState.Error) {
if (state.error == ErrorType.NoInternetConnection) {
srl_wallet?.isRefreshing = false
snackbar = Snackbar.make(
coordinator_wallet, getString(R.string.notification_no_internet),
Snackbar.LENGTH_INDEFINITE
).setAction(getString(R.string.notification_no_internet_retry))
{ store.dispatch(WalletAction.LoadData) }
.also { it.show() }
}
} else {
snackbar?.dismiss()
}
}
private fun setupButtons(state: WalletState) {
btn_copy.setOnClickListener { store.dispatch(WalletAction.CopyAddress(requireContext())) }
btn_show_qr.setOnClickListener { store.dispatch(WalletAction.ShowQrCode) }

View file

@ -5,8 +5,11 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import org.rekotlin.Action
import org.rekotlin.Store
import java.lang.ref.WeakReference
/**
[REDACTED_AUTHOR]
@ -15,7 +18,8 @@ class NetworkConnectivity(
private val store: Store<*>,
context: Context
) {
private val connectivityManager = context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
private val wContext: WeakReference<Context> = WeakReference(context)
private val receiver = object : BroadcastReceiver() {
override fun onReceive(c: Context?, intent: Intent?) {
@ -26,14 +30,42 @@ class NetworkConnectivity(
init {
val intentFilter = IntentFilter()
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
context.registerReceiver(receiver, intentFilter)
wContext.get()?.registerReceiver(receiver, intentFilter)
store.dispatch(NetworkStateChanged(isOnlineOrConnecting()))
}
fun isOnlineOrConnecting(): Boolean {
val netInfo = connectivityManager.activeNetworkInfo
return netInfo != null && netInfo.isConnectedOrConnecting
val connectivityManager = getConnectivityManager() ?: return false
return if (Build.VERSION.SDK_INT >= 23) {
val capabilities =
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
(capabilities != null) &&
(capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET))
} else {
val networkInfo = connectivityManager.activeNetworkInfo
networkInfo != null && networkInfo.isConnectedOrConnecting
}
}
private fun getConnectivityManager(): ConnectivityManager? {
return wContext.get()?.applicationContext
?.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
}
companion object {
private lateinit var instance: NetworkConnectivity
fun createInstance(store: Store<*>, context: Context): NetworkConnectivity {
instance = NetworkConnectivity(store, context)
return instance
}
fun getInstance(): NetworkConnectivity = instance
}
}

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_wallet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/backgroundLightGray"

View file

@ -3,6 +3,8 @@
<string name="app_name" translatable="false">Tangem Tap</string>
<string name="notification_address_copied">Address was successfully copied</string>
<string name="notification_no_internet">No internet connection</string>
<string name="notification_no_internet_retry">Retry</string>
<string name="generic_done">Done</string>
<string name="home_do_you_have_card">Welcome to Tangem.\nDo you have one of our cards?</string>