Updated on 2026-08-14

This commit is contained in:
Tangem 2023-05-19 16:50:09 +03:00
parent 96a450e0e5
commit 91ba31fb84
7 changed files with 53 additions and 118 deletions

View file

@ -279,6 +279,16 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), SafeStoreSubscriber<W
.flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.STARTED)
.distinctUntilChanged()
.collect { isOnline ->
if (isOnline) {
(activity as? MainActivity)?.dismissSnackbar()
} else {
isNetworkConnectionError.value = true
binding.srlWallet.isRefreshing = false
(activity as? MainActivity)?.showSnackbar(
text = R.string.wallet_notification_no_internet,
buttonTitle = R.string.common_retry,
)
}
if (isOnline && isNetworkConnectionError.value) {
refreshWalletData()
}

View file

@ -22,6 +22,7 @@ dependencies {
/** Coroutines */
implementation(deps.kotlin.coroutines)
implementation(deps.kotlin.coroutines.reactive)
/** Logging */
implementation(deps.timber)
@ -34,6 +35,7 @@ dependencies {
implementation(deps.okHttp.logging)
implementation(deps.retrofit)
implementation(deps.retrofit.moshi)
implementation(deps.reactive.network)
/** Time */
implementation(deps.jodatime)

View file

@ -3,4 +3,5 @@
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View file

@ -1,110 +0,0 @@
package com.tangem.datasource.connection
import android.app.Activity
import android.app.Application
import android.app.Application.ActivityLifecycleCallbacks
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
import android.net.ConnectivityManager as AndroidConnectivityManager
/**
* Network connection manager implementation using Android connectivity service
*
* @property context application context for registration lifecycle callbacks
* @property dispatchers coroutine dispatcher provider
*
[REDACTED_AUTHOR]
*/
@Singleton
internal class AndroidNetworkConnectionManager @Inject constructor(
@ApplicationContext private val context: Context,
private val dispatchers: CoroutineDispatcherProvider,
) : NetworkConnectionManager {
private val _isOnline = MutableStateFlow(value = false)
private val callbacks = NetworkConnectionManagerCallbacks()
private val receiver = NetworkConnectionBroadcastReceiver()
override val isOnline: Boolean get() = _isOnline.value
override val isOnlineFlow: StateFlow<Boolean> = _isOnline
init {
(context as? Application)?.registerActivityLifecycleCallbacks(callbacks)
}
private inner class NetworkConnectionManagerCallbacks : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
val intentFilter = IntentFilter().apply {
addAction(AndroidConnectivityManager.CONNECTIVITY_ACTION)
}
activity.registerReceiver(receiver, intentFilter)
}
override fun onActivityStarted(activity: Activity) = Unit
override fun onActivityResumed(activity: Activity) = Unit
override fun onActivityPaused(activity: Activity) = Unit
override fun onActivityStopped(activity: Activity) = Unit
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit
override fun onActivityDestroyed(activity: Activity) {
activity.unregisterReceiver(receiver)
(context as? Application)?.unregisterActivityLifecycleCallbacks(callbacks)
}
}
private inner class NetworkConnectionBroadcastReceiver : BroadcastReceiver() {
private val connectivityManager: android.net.ConnectivityManager? =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as? android.net.ConnectivityManager
override fun onReceive(c: Context?, intent: Intent?) {
val pendingResult = goAsync()
CoroutineScope(SupervisorJob()).launch(dispatchers.io) {
try {
val status = isConnected()
_isOnline.emit(value = status)
Timber.i("Connection status is ${if (status) "ONLINE" else "OFFLINE"}")
} finally {
pendingResult.finish()
}
}
}
private fun isConnected(): Boolean {
connectivityManager ?: return false
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
capabilities != null && capabilities.hasNetworkTransport()
} else {
val networkInfo = connectivityManager.activeNetworkInfo
networkInfo != null && networkInfo.isConnectedOrConnecting
}
}
private fun NetworkCapabilities.hasNetworkTransport(): Boolean {
return hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
}
}
}

View file

@ -0,0 +1,29 @@
package com.tangem.datasource.connection
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler
import io.reactivex.BackpressureStrategy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.reactive.asFlow
internal class RealInternetConnectionManager : NetworkConnectionManager {
private val scope =
CoroutineScope(
SupervisorJob() + Dispatchers.IO + FeatureCoroutineExceptionHandler.create("RealInternetConnectionManager"),
)
override val isOnlineFlow: StateFlow<Boolean> = ReactiveNetwork
.observeInternetConnectivity()
.toFlowable(BackpressureStrategy.LATEST)
.asFlow()
.stateIn(scope, SharingStarted.Eagerly, initialValue = false)
override val isOnline: Boolean
get() = isOnlineFlow.value
}

View file

@ -1,20 +1,20 @@
package com.tangem.datasource.di
import com.tangem.datasource.connection.AndroidNetworkConnectionManager
import com.tangem.datasource.connection.NetworkConnectionManager
import dagger.Binds
import com.tangem.datasource.connection.RealInternetConnectionManager
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal interface NetworkConnectionModule {
internal class NetworkConnectionModule {
@Binds
@Provides
@Singleton
fun bindNetworkConnectionManager(
androidNetworkConnectionManager: AndroidNetworkConnectionManager,
): NetworkConnectionManager
fun provideNetworkConnectionManager(): NetworkConnectionManager {
return RealInternetConnectionManager()
}
}

View file

@ -69,6 +69,7 @@ zxingQrCode = "3.5.1"
mviCore = "1.3.1"
kotlinSerialization = "1.4.1"
arrow = "1.2.0-RC"
reactiveNetwork = "3.0.8"
# endregion Other libraries
# region Tangem
@ -174,6 +175,7 @@ appsflyer = { module = "com.appsflyer:af-android-sdk", version.ref = "appsflyer"
armadillo = { module = "at.favre.lib:armadillo", version.ref = "armadillo" }
coil = { module = "io.coil-kt:coil", version.ref = "coil" }
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutine" }
kotlin-coroutines-reactive = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-reactive", version.ref = "coroutine" }
kotlin-immutable-collections = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlin-immutable-collections" }
desugar = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugarJdkLibs" }
googlePlay-core = { module = "com.google.android.play:core", version.ref = "googlePlayCore" }
@ -209,4 +211,5 @@ mviCore-watcher = { module = "com.github.badoo.mvicore:mvicore-diff", version.re
kotlin-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinSerialization" }
arrow-core = { module = "io.arrow-kt:arrow-core", version.ref = "arrow" }
arrow-fx = { module = "io.arrow-kt:arrow-fx-coroutines", version.ref = "arrow" }
reactive-network = { module = "com.github.pwittchen:reactivenetwork-rx2", version.ref = "reactiveNetwork" }
# endregion Other