Compare commits

..

No commits in common. "24c22a72e643e9054402e0c71b3be52b51ef6d86" and "9d0bb452e39b080255c0f2157860327fa742b8b9" have entirely different histories.

17 changed files with 8 additions and 346 deletions

View File

@ -181,9 +181,8 @@ dependencies {
implementation("androidx.viewpager2:viewpager2:1.1.0-beta01")
//Dependency Injection
implementation("org.kodein.di:kodein-di:7.14.0")
implementation("org.kodein.di:kodein-di-framework-android-x:7.14.0")
implementation("org.kodein.di:kodein-di-framework-android-x-viewmodel:7.14.0")
implementation("org.kodein.di:kodein-di:7.12.0")
implementation("org.kodein.di:kodein-di-framework-android-x:7.12.0")
//Settings
implementation("com.russhwolf:multiplatform-settings-no-arg:0.9")
@ -205,7 +204,5 @@ dependencies {
// Network information
// TODO: When updating this library, check if the todo in RepositoryImpl.startNetwork can be resolved
// 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"))
implementation("com.github.ln-12:multiplatform-connectivity-status:1.1.0")
}

View File

@ -6,13 +6,11 @@ import android.view.View
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.lifecycle.lifecycleScope
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityAddSourceBinding
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
import bou.amine.apps.readerforselfossv2.android.utils.Config
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlValid
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
import bou.amine.apps.readerforselfossv2.repository.Repository
import com.ftinc.scoop.Scoop
import kotlinx.coroutines.CoroutineScope
@ -32,7 +30,6 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
override val di by closestDI()
private val repository : Repository by instance()
private val viewModel : AppViewModel by instance()
override fun onCreate(savedInstanceState: Bundle?) {
appColors = AppColors(this@AddSourceActivity)
@ -79,16 +76,6 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
binding.sourceUri.text.toString()
)
}
lifecycleScope.launch {
viewModel.toastMessageProvider.collect { toastMessage ->
Toast.makeText(
this@AddSourceActivity,
toastMessage,
Toast.LENGTH_SHORT
).show()
}
}
}
override fun onResume() {

View File

@ -17,7 +17,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.core.view.doOnNextLayout
import androidx.drawerlayout.widget.DrawerLayout
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.*
import androidx.room.Room
import androidx.work.Constraints
@ -47,7 +46,6 @@ import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper
import bou.amine.apps.readerforselfossv2.android.utils.persistence.toEntity
import bou.amine.apps.readerforselfossv2.android.utils.persistence.toView
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
import bou.amine.apps.readerforselfossv2.utils.ItemType
@ -136,7 +134,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
override val di by closestDI()
private val repository : Repository by instance()
private val viewModel : AppViewModel by instance()
data class DrawerData(val tags: List<SelfossModel.Tag>?, val sources: List<SelfossModel.Source>?)
@ -176,15 +173,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
AppDatabase::class.java, "selfoss-database"
).addMigrations(MIGRATION_1_2).addMigrations(MIGRATION_2_3).addMigrations(MIGRATION_3_4).build()
lifecycleScope.launch {
viewModel.toastMessageProvider.collect { toastMessage ->
Toast.makeText(
this@HomeActivity,
toastMessage,
Toast.LENGTH_SHORT
).show()
}
}
customTabActivityHelper = CustomTabActivityHelper()

View File

@ -10,14 +10,11 @@ import android.view.MenuItem
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityLoginBinding
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlValid
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
import bou.amine.apps.readerforselfossv2.repository.Repository
import com.mikepenz.aboutlibraries.LibsBuilder
import com.russhwolf.settings.Settings
@ -41,7 +38,6 @@ class LoginActivity() : AppCompatActivity(), DIAware {
override val di by closestDI()
private val repository : Repository by instance()
private val viewModel : AppViewModel by instance()
override fun onCreate(savedInstanceState: Bundle?) {
appColors = AppColors(this@LoginActivity)
@ -61,16 +57,6 @@ class LoginActivity() : AppCompatActivity(), DIAware {
}
handleActions()
lifecycleScope.launch {
viewModel.toastMessageProvider.collect { toastMessage ->
Toast.makeText(
this@LoginActivity,
toastMessage,
Toast.LENGTH_SHORT
).show()
}
}
}
private fun handleActions() {

View File

@ -15,12 +15,11 @@ import androidx.preference.PreferenceManager
import bou.amine.apps.readerforselfossv2.DI.networkModule
import bou.amine.apps.readerforselfossv2.android.utils.Config
import bou.amine.apps.readerforselfossv2.android.utils.glide.loadMaybeBasicAuth
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
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.ln12.library.ConnectivityStatus
import com.github.`ln-12`.library.ConnectivityStatus
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerImageLoader
import com.russhwolf.settings.Settings
@ -31,7 +30,6 @@ class MyApp : MultiDexApplication(), DIAware {
override val di by DI.lazy {
import(networkModule)
bind<Repository>() with singleton { Repository(instance(), instance(), ConnectivityStatus(applicationContext)) }
bind<AppViewModel>() with singleton { AppViewModel(repository = instance()) }
}
private val repository: Repository by instance()

View File

@ -5,13 +5,11 @@ import android.content.res.ColorStateList
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import bou.amine.apps.readerforselfossv2.android.adapters.SourcesListAdapter
import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySourcesBinding
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
import com.ftinc.scoop.Scoop
@ -29,7 +27,6 @@ class SourcesActivity : AppCompatActivity(), DIAware {
override val di by closestDI()
private val repository : Repository by instance()
private val viewModel : AppViewModel by instance()
override fun onCreate(savedInstanceState: Bundle?) {
appColors = AppColors(this@SourcesActivity)
@ -50,16 +47,6 @@ class SourcesActivity : AppCompatActivity(), DIAware {
binding.fab.rippleColor = appColors.colorAccentDark
binding.fab.backgroundTintList = ColorStateList.valueOf(appColors.colorAccent)
lifecycleScope.launch {
viewModel.toastMessageProvider.collect { toastMessage ->
Toast.makeText(
this@SourcesActivity,
toastMessage,
Toast.LENGTH_SHORT
).show()
}
}
}
override fun onStop() {

View File

@ -19,7 +19,6 @@ import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.res.ResourcesCompat
import androidx.core.widget.NestedScrollView
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.room.Room
import bou.amine.apps.readerforselfossv2.android.ImageActivity
import bou.amine.apps.readerforselfossv2.android.R
@ -36,7 +35,6 @@ import bou.amine.apps.readerforselfossv2.android.utils.*
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper
import bou.amine.apps.readerforselfossv2.android.utils.glide.getBitmapInputStream
import bou.amine.apps.readerforselfossv2.android.utils.glide.loadMaybeBasicAuth
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
import bou.amine.apps.readerforselfossv2.utils.isEmptyOrNullOrNullString
@ -81,7 +79,6 @@ class ArticleFragment : Fragment(), DIAware {
override val di : DI by closestDI()
private val repository: Repository by instance()
private val viewModel : AppViewModel by instance()
private var settings = Settings()
@ -111,16 +108,6 @@ class ArticleFragment : Fragment(), DIAware {
requireContext(),
AppDatabase::class.java, "selfoss-database"
).addMigrations(MIGRATION_1_2).addMigrations(MIGRATION_2_3).addMigrations(MIGRATION_3_4).build()
lifecycleScope.launch {
viewModel.toastMessageProvider.collect { toastMessage ->
Toast.makeText(
context,
toastMessage,
Toast.LENGTH_SHORT
).show()
}
}
}
override fun onCreateView(

View File

@ -1,28 +0,0 @@
package bou.amine.apps.readerforselfossv2.android.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import bou.amine.apps.readerforselfossv2.repository.Repository
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
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 && !wasConnected && repository.connectionMonitored) {
_toastMessageProvider.emit("Network connection is now available")
wasConnected = true
} else if (!isConnected && wasConnected && repository.connectionMonitored){
_toastMessageProvider.emit("Network connection lost")
wasConnected = false
}
}
}
}
}

View File

@ -1 +0,0 @@
/build

View File

@ -1,65 +0,0 @@
plugins {
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

@ -1,4 +0,0 @@
<?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

@ -1,85 +0,0 @@
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

@ -1,12 +0,0 @@
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

@ -1,67 +0,0 @@
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

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

View File

@ -38,9 +38,7 @@ kotlin {
implementation("io.github.aakira:napier:2.6.1")
// Network information
// 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"))
implementation("com.github.ln-12:multiplatform-connectivity-status:1.1.0")
}
}
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.ln12.library.ConnectivityStatus
import com.github.`ln-12`.library.ConnectivityStatus
import com.russhwolf.settings.Settings
import io.github.aakira.napier.Napier
import kotlinx.coroutines.CoroutineScope
@ -16,8 +16,7 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
val settings = Settings()
var items = ArrayList<SelfossModel.Item>()
val isConnectionAvailable = connectivityStatus.isNetworkConnected
var connectionMonitored = false
private val isConnectionAvailable = connectivityStatus.isNetworkConnected
var baseUrl = apiDetails.getBaseUrl()
lateinit var dateUtils: DateUtils
@ -348,12 +347,10 @@ 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() {
connectionMonitored = true
connectivityStatus.start()
}
fun stopNetwork() {
connectionMonitored = false
connectivityStatus.stop()
}