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 be2387002a..4522299310 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 @@ -279,16 +279,6 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), SafeStoreSubscriber - 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() } diff --git a/core/datasource/build.gradle.kts b/core/datasource/build.gradle.kts index 3350c7930f..36c8fda7a2 100644 --- a/core/datasource/build.gradle.kts +++ b/core/datasource/build.gradle.kts @@ -22,7 +22,6 @@ dependencies { /** Coroutines */ implementation(deps.kotlin.coroutines) - implementation(deps.kotlin.coroutines.reactive) /** Logging */ implementation(deps.timber) @@ -35,7 +34,6 @@ dependencies { implementation(deps.okHttp.logging) implementation(deps.retrofit) implementation(deps.retrofit.moshi) - implementation(deps.reactive.network) /** Time */ implementation(deps.jodatime) diff --git a/core/datasource/src/main/AndroidManifest.xml b/core/datasource/src/main/AndroidManifest.xml index a87322003a..b7e7790e14 100644 --- a/core/datasource/src/main/AndroidManifest.xml +++ b/core/datasource/src/main/AndroidManifest.xml @@ -3,5 +3,4 @@ xmlns:android="http://schemas.android.com/apk/res/android"> - - + \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/connection/AndroidNetworkConnectionManager.kt b/core/datasource/src/main/java/com/tangem/datasource/connection/AndroidNetworkConnectionManager.kt new file mode 100644 index 0000000000..6581fbb384 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/connection/AndroidNetworkConnectionManager.kt @@ -0,0 +1,110 @@ +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 = _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) + } + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/connection/RealInternetConnectionManager.kt b/core/datasource/src/main/java/com/tangem/datasource/connection/RealInternetConnectionManager.kt deleted file mode 100644 index 669dc8ed20..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/connection/RealInternetConnectionManager.kt +++ /dev/null @@ -1,29 +0,0 @@ -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 = ReactiveNetwork - .observeInternetConnectivity() - .toFlowable(BackpressureStrategy.LATEST) - .asFlow() - .stateIn(scope, SharingStarted.Eagerly, initialValue = false) - - override val isOnline: Boolean - get() = isOnlineFlow.value -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkConnectionModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkConnectionModule.kt index b3eca89707..d112c7ccab 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkConnectionModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkConnectionModule.kt @@ -1,20 +1,20 @@ package com.tangem.datasource.di +import com.tangem.datasource.connection.AndroidNetworkConnectionManager import com.tangem.datasource.connection.NetworkConnectionManager -import com.tangem.datasource.connection.RealInternetConnectionManager +import dagger.Binds import dagger.Module -import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -internal class NetworkConnectionModule { +internal interface NetworkConnectionModule { - @Provides + @Binds @Singleton - fun provideNetworkConnectionManager(): NetworkConnectionManager { - return RealInternetConnectionManager() - } + fun bindNetworkConnectionManager( + androidNetworkConnectionManager: AndroidNetworkConnectionManager, + ): NetworkConnectionManager } \ No newline at end of file diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 0e5f7079a1..01b59c0179 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -69,7 +69,6 @@ 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 @@ -175,7 +174,6 @@ 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" } @@ -211,5 +209,4 @@ 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