network #28

Merged
AmineB merged 28 commits from davidoskky/ReaderForSelfoss-multiplatform:network into master 2022-08-22 19:01:16 +00:00
12 changed files with 251 additions and 9 deletions
Showing only changes of commit 9203012a97 - Show all commits

View File

@ -208,5 +208,7 @@ dependencies {
// Network information
// TODO: When updating this library, check if the todo in RepositoryImpl.startNetwork can be resolved
implementation("com.github.ln-12:multiplatform-connectivity-status:1.1.0")
// TODO: Include this library once this is merged https://github.com/ln-12/multiplatform-connectivity-status/pull/4
// implementation("com.github.ln-12:multiplatform-connectivity-status:1.1.0")
implementation(project(":connectionstatus"))
}

View File

@ -20,7 +20,7 @@ import bou.amine.apps.readerforselfossv2.repository.Repository
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.ftinc.scoop.Scoop
import com.github.`ln-12`.library.ConnectivityStatus
import com.github.ln12.library.ConnectivityStatus
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerImageLoader
import com.russhwolf.settings.Settings
@ -33,7 +33,7 @@ class MyApp : MultiDexApplication(), DIAware {
override val di by DI.lazy {
import(networkModule)
bind<Repository>() with singleton { Repository(instance(), instance(), ConnectivityStatus(applicationContext)) }
bindProvider { AppViewModel(repository = instance()) }
bind<AppViewModel>() with singleton { AppViewModel(repository = instance()) }
}
private val repository: Repository by instance()

View File

@ -10,14 +10,17 @@ import kotlinx.coroutines.launch
class AppViewModel(private val repository: Repository) : ViewModel() {
private val _toastMessageProvider = MutableSharedFlow<String>()
val toastMessageProvider = _toastMessageProvider.asSharedFlow()
private var wasConnected = true
init {
viewModelScope.launch {
repository.isConnectionAvailable.collect { isConnected ->
if (isConnected && repository.connectionMonitored) {
if (isConnected && !wasConnected && repository.connectionMonitored) {
_toastMessageProvider.emit("Network connection is now available")
AmineB marked this conversation as resolved Outdated

It would be better to emit an enum. We'll handle the translation on the android/ios side.

It would be better to emit an enum. We'll handle the translation on the android/ios side.

What do you mean? This view model is already in the android side; these strings will have to be localized. I can do it now

What do you mean? This view model is already in the android side; these strings will have to be localized. I can do it now

I didn´t see that it was in the android side.

Yes, please use localized stringd.

I didn´t see that it was in the android side. Yes, please use localized stringd.
} else if (repository.connectionMonitored){
wasConnected = true
} else if (!isConnected && wasConnected && repository.connectionMonitored){
_toastMessageProvider.emit("Network connection lost")
wasConnected = false
}
}
}

1
connectionstatus/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,65 @@
plugins {
AmineB marked this conversation as resolved Outdated

Instead of adding the library code like this, could you maybe create a jar of the library and add it to the project ?

Instead of adding the library code like this, could you maybe create a jar of the library and add it to the project ?
id("com.android.library")
kotlin("multiplatform")
}
group = "com.github.ln-12"
version = "1.1.0"
repositories {
google()
mavenCentral()
}
kotlin {
android {
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
publishLibraryVariants("release", "debug")
}
ios()
sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val androidMain by getting
val androidTest by getting {
dependencies {
implementation(kotlin("test-junit"))
implementation("junit:junit:4.13.2")
}
}
val iosMain by getting
val iosTest by getting
}
}
android {
compileSdk = 31
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
minSdk = 21
targetSdk = 31
}
}
// metadata is currently not supported for iOS
// https://youtrack.jetbrains.com/issue/KT-44459#focus=Comments-27-4645829.0-0
kotlin.metadata {
compilations.matching { it.name == "iosMain" }.all {
compileKotlinTaskProvider.configure { enabled = false }
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.github.ln12.library">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
</manifest>

View File

@ -0,0 +1,85 @@
package com.github.ln12.library
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import android.util.Log
import kotlinx.coroutines.flow.MutableStateFlow
// From library com.github.ln-12:multiplatform-connectivity-status:1.1.0
// https://github.com/ln-12/multiplatform-connectivity-status
// Copyright 2021 Lorenzo Neumann
// Edited by davidoskky as here: https://github.com/ln-12/multiplatform-connectivity-status/pull/4
actual class ConnectivityStatus(private val context: Context) {
actual val isNetworkConnected = MutableStateFlow(false)
private var connectivityManager: ConnectivityManager? = null
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
Log.d("Connectivity status", "Connected")
isNetworkConnected.value = true
}
override fun onLost(network: Network) {
Log.d("Connectivity status", "Disconnected")
isNetworkConnected.value = false
}
}
actual fun start() {
try {
if (connectivityManager == null) {
connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// API 24 and above
connectivityManager!!.registerDefaultNetworkCallback(networkCallback)
val currentNetwork = connectivityManager!!.activeNetwork
if(currentNetwork == null) {
isNetworkConnected.value = false
Log.d("Connectivity status", "Disconnected")
}
} else {
// API 23 and below
val networkRequest = NetworkRequest.Builder().apply {
addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}
}.build()
connectivityManager!!.registerNetworkCallback(networkRequest, networkCallback)
val currentNetwork = connectivityManager!!.activeNetworkInfo
if(currentNetwork == null || (
currentNetwork.type != ConnectivityManager.TYPE_ETHERNET &&
currentNetwork.type != ConnectivityManager.TYPE_WIFI &&
currentNetwork.type != ConnectivityManager.TYPE_MOBILE
)) {
isNetworkConnected.value = false
Log.d("Connectivity status", "Disconnected")
}
}
Log.d("Connectivity status", "Started")
} catch (e: Exception) {
Log.d("Connectivity status", "Failed to start: ${e.message.toString()}")
e.printStackTrace()
isNetworkConnected.value = false
}
}
actual fun stop() {
connectivityManager?.unregisterNetworkCallback(networkCallback)
Log.d("Connectivity status", "Stopped")
}
}

View File

@ -0,0 +1,12 @@
package com.github.ln12.library
import kotlinx.coroutines.flow.MutableStateFlow
// From library com.github.ln-12:multiplatform-connectivity-status:1.1.0
// https://github.com/ln-12/multiplatform-connectivity-status
// Copyright 2021 Lorenzo Neumann
expect class ConnectivityStatus {
val isNetworkConnected: MutableStateFlow<Boolean>
fun start()
fun stop()
}

View File

@ -0,0 +1,67 @@
package com.github.ln12.library
import kotlinx.coroutines.flow.MutableStateFlow
import cocoapods.Reachability.*
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import platform.Foundation.NSLog
import platform.darwin.dispatch_async
import platform.darwin.dispatch_get_main_queue
import kotlin.native.concurrent.freeze
// From library com.github.ln-12:multiplatform-connectivity-status:1.1.0
// https://github.com/ln-12/multiplatform-connectivity-status
// Copyright 2021 Lorenzo Neumann
actual class ConnectivityStatus {
actual val isNetworkConnected = MutableStateFlow(false)
private var reachability: Reachability? = null
// Swift can't directly use a MutableStateFlow, so the status
// is exposed via a lambda/closure
fun getStatus(success: (Boolean) -> Unit) {
MainScope().launch {
isNetworkConnected.collect { status ->
success(status)
}
}
}
actual fun start() {
dispatch_async(dispatch_get_main_queue()) {
reachability = Reachability.reachabilityForInternetConnection()
val reachableCallback = { reach: Reachability? ->
dispatch_async(dispatch_get_main_queue(), {
NSLog("Connected")
isNetworkConnected.value = true
}.freeze())
}.freeze()
reachability?.reachableBlock = reachableCallback
val unreachableCallback = { reach: Reachability? ->
dispatch_async(dispatch_get_main_queue(), {
NSLog("Disconnected")
isNetworkConnected.value = false
}.freeze())
}.freeze()
reachability?.unreachableBlock = unreachableCallback
reachability?.startNotifier()
dispatch_async(dispatch_get_main_queue(), {
isNetworkConnected.value = reachability?.isReachable() ?: false
NSLog("Initial reachability: ${reachability?.isReachable()}")
}.freeze())
}
}
actual fun stop() {
reachability?.stopNotifier()
}
}

View File

@ -8,4 +8,5 @@ pluginManagement {
rootProject.name = "ReaderForSelfossV2"
include(":androidApp")
include(":shared")
include(":shared")
include(":connectionstatus")

View File

@ -38,7 +38,9 @@ kotlin {
implementation("io.github.aakira:napier:2.6.1")
// Network information
implementation("com.github.ln-12:multiplatform-connectivity-status:1.1.0")
// TODO: Include this library once this is merged https://github.com/ln-12/multiplatform-connectivity-status/pull/4
//implementation("com.github.ln-12:multiplatform-connectivity-status:1.1.0")
implementation(project(":connectionstatus"))
}
}
val commonTest by getting {

View File

@ -5,7 +5,7 @@ import bou.amine.apps.readerforselfossv2.rest.SelfossModel
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
import bou.amine.apps.readerforselfossv2.utils.DateUtils
import bou.amine.apps.readerforselfossv2.utils.ItemType
import com.github.`ln-12`.library.ConnectivityStatus
import com.github.ln12.library.ConnectivityStatus
import com.russhwolf.settings.Settings
import io.github.aakira.napier.Napier
import kotlinx.coroutines.CoroutineScope
@ -348,8 +348,8 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
// com.github.ln-12:multiplatform-connectivity-status:1.1.0
// https://github.com/ln-12/multiplatform-connectivity-status/issues/2
fun startNetwork() {
connectivityStatus.start()
connectionMonitored = true
connectivityStatus.start()
}
fun stopNetwork() {