Improve: Move Away from RxJava and use coroutines (#NoRxGang)

This commit is contained in:
LooKeR 2021-10-31 19:06:55 +05:30
parent 57c3f78021
commit 5e72165d0b
5 changed files with 66 additions and 65 deletions

View File

@ -18,6 +18,9 @@ import com.looker.droidify.service.Connection
import com.looker.droidify.service.SyncService
import com.looker.droidify.utility.Utils.toInstalledItem
import com.looker.droidify.utility.extension.android.Android
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import java.net.InetSocketAddress
import java.net.Proxy
@ -83,20 +86,22 @@ class MainApplication : Application(), ImageLoaderFactory {
updateProxy()
var lastAutoSync = Preferences[Preferences.Key.AutoSync]
var lastUpdateUnstable = Preferences[Preferences.Key.UpdateUnstable]
Preferences.observable.subscribe {
if (it == Preferences.Key.ProxyType || it == Preferences.Key.ProxyHost || it == Preferences.Key.ProxyPort) {
updateProxy()
} else if (it == Preferences.Key.AutoSync) {
val autoSync = Preferences[Preferences.Key.AutoSync]
if (lastAutoSync != autoSync) {
lastAutoSync = autoSync
updateSyncJob(true)
}
} else if (it == Preferences.Key.UpdateUnstable) {
val updateUnstable = Preferences[Preferences.Key.UpdateUnstable]
if (lastUpdateUnstable != updateUnstable) {
lastUpdateUnstable = updateUnstable
forceSyncAll()
MainScope().launch {
Preferences.subject.collect {
if (it == Preferences.Key.ProxyType || it == Preferences.Key.ProxyHost || it == Preferences.Key.ProxyPort) {
updateProxy()
} else if (it == Preferences.Key.AutoSync) {
val autoSync = Preferences[Preferences.Key.AutoSync]
if (lastAutoSync != autoSync) {
lastAutoSync = autoSync
updateSyncJob(true)
}
} else if (it == Preferences.Key.UpdateUnstable) {
val updateUnstable = Preferences[Preferences.Key.UpdateUnstable]
if (lastUpdateUnstable != updateUnstable) {
lastUpdateUnstable = updateUnstable
forceSyncAll()
}
}
}
}

View File

@ -6,14 +6,18 @@ import android.content.res.Configuration
import com.looker.droidify.R
import com.looker.droidify.entity.ProductItem
import com.looker.droidify.utility.extension.android.Android
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.subjects.PublishSubject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
import java.net.Proxy
object Preferences {
private lateinit var preferences: SharedPreferences
private val subject = PublishSubject.create<Key<*>>()
private val _subject = MutableSharedFlow<Key<*>>()
val subject = _subject.asSharedFlow()
private val keys = sequenceOf(
Key.AutoSync,
@ -31,24 +35,24 @@ object Preferences {
fun init(context: Context) {
preferences =
context.getSharedPreferences("${context.packageName}_preferences", Context.MODE_PRIVATE)
context.getSharedPreferences("${context.packageName}_preferences",
Context.MODE_PRIVATE)
preferences.registerOnSharedPreferenceChangeListener { _, keyString ->
keys[keyString]?.let(
subject::onNext
)
MainScope().launch(Dispatchers.IO) {
keys[keyString]?.let {
_subject.emit(it)
}
}
}
}
val observable: Observable<Key<*>>
get() = subject
sealed class Value<T> {
abstract val value: T
internal abstract fun get(
preferences: SharedPreferences,
key: String,
defaultValue: Value<T>
defaultValue: Value<T>,
): T
internal abstract fun set(preferences: SharedPreferences, key: String, value: T)
@ -57,7 +61,7 @@ object Preferences {
override fun get(
preferences: SharedPreferences,
key: String,
defaultValue: Value<Boolean>
defaultValue: Value<Boolean>,
): Boolean {
return preferences.getBoolean(key, defaultValue.value)
}
@ -71,7 +75,7 @@ object Preferences {
override fun get(
preferences: SharedPreferences,
key: String,
defaultValue: Value<Int>
defaultValue: Value<Int>,
): Int {
return preferences.getInt(key, defaultValue.value)
}
@ -85,7 +89,7 @@ object Preferences {
override fun get(
preferences: SharedPreferences,
key: String,
defaultValue: Value<String>
defaultValue: Value<String>,
): String {
return preferences.getString(key, defaultValue.value) ?: defaultValue.value
}
@ -99,7 +103,7 @@ object Preferences {
override fun get(
preferences: SharedPreferences,
key: String,
defaultValue: Value<T>
defaultValue: Value<T>,
): T {
val value = preferences.getString(key, defaultValue.value.valueString)
return defaultValue.value.values.find { it.valueString == value }

View File

@ -15,6 +15,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.looker.droidify.R
import com.looker.droidify.database.Database
@ -28,7 +29,6 @@ import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.extension.resources.getColorFromAttr
import com.looker.droidify.utility.extension.text.nullIfEmpty
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
@ -79,7 +79,6 @@ class EditRepositoryFragment() : ScreenFragment() {
private var layout: Layout? = null
private val syncConnection = Connection(SyncService::class.java)
private var repositoriesDisposable: Disposable? = null
private var checkDisposable: Disposable? = null
private var takenAddresses = emptySet<String>()
@ -239,18 +238,13 @@ class EditRepositoryFragment() : ScreenFragment() {
}
}
repositoriesDisposable = Observable.just(Unit)
.concatWith(Database.observable(Database.Subject.Repositories))
.observeOn(Schedulers.io())
.flatMapSingle { RxUtils.querySingle { Database.RepositoryAdapter.getAll(it) } }
.observeOn(AndroidSchedulers.mainThread())
.subscribe { it ->
takenAddresses = it.asSequence().filter { it.id != repositoryId }
.flatMap { (it.mirrors + it.address).asSequence() }
.map { it.withoutKnownPath }.toSet()
invalidateAddress()
}
lifecycleScope.launchWhenCreated {
val list = Database.RepositoryAdapter.getAll(null)
takenAddresses = list.asSequence().filter { it.id != repositoryId }
.flatMap { (it.mirrors + it.address).asSequence() }
.map { it.withoutKnownPath }.toSet()
invalidateAddress()
}
invalidateAddress()
invalidateFingerprint()
invalidateUsernamePassword()
@ -263,8 +257,6 @@ class EditRepositoryFragment() : ScreenFragment() {
layout = null
syncConnection.unbind(requireContext())
repositoriesDisposable?.dispose()
repositoriesDisposable = null
checkDisposable?.dispose()
checkDisposable = null
}
@ -453,7 +445,7 @@ class EditRepositoryFragment() : ScreenFragment() {
private fun onSaveRepositoryProceedInvalidate(
address: String,
fingerprint: String,
authentication: String
authentication: String,
) {
val binder = syncConnection.binder
if (binder != null) {

View File

@ -15,6 +15,7 @@ import androidx.core.net.toUri
import androidx.core.widget.NestedScrollView
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.google.android.material.circularreveal.CircularRevealFrameLayout
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.switchmaterial.SwitchMaterial
@ -26,13 +27,12 @@ import com.looker.droidify.content.Preferences
import com.looker.droidify.databinding.PreferenceItemBinding
import com.looker.droidify.utility.extension.resources.*
import com.topjohnwu.superuser.Shell
import io.reactivex.rxjava3.disposables.Disposable
import kotlinx.coroutines.flow.collect
class SettingsFragment : ScreenFragment() {
private lateinit var preferenceBinding: PreferenceItemBinding
private val preferences = mutableMapOf<Preferences.Key<*>, Preference<*>>()
private var disposable: Disposable? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -136,7 +136,9 @@ class SettingsFragment : ScreenFragment() {
)
}
disposable = Preferences.observable.subscribe(this::updatePreference)
lifecycleScope.launchWhenStarted {
Preferences.subject.collect { updatePreference(it) }
}
updatePreference(null)
}
@ -167,10 +169,7 @@ class SettingsFragment : ScreenFragment() {
override fun onDestroyView() {
super.onDestroyView()
preferences.clear()
disposable?.dispose()
disposable = null
}
private fun updatePreference(key: Preferences.Key<*>?) {
@ -199,7 +198,7 @@ class SettingsFragment : ScreenFragment() {
private fun LinearLayoutCompat.addCategory(
title: String,
callback: LinearLayoutCompat.() -> Unit
callback: LinearLayoutCompat.() -> Unit,
) {
val text = MaterialTextView(context)
text.typeface = TypefaceExtra.medium
@ -217,7 +216,7 @@ class SettingsFragment : ScreenFragment() {
private fun <T> LinearLayoutCompat.addPreference(
key: Preferences.Key<T>, title: String,
summaryProvider: () -> String, dialogProvider: ((Context) -> AlertDialog)?
summaryProvider: () -> String, dialogProvider: ((Context) -> AlertDialog)?,
): Preference<T> {
val preference =
Preference(key, this@SettingsFragment, this, title, summaryProvider, dialogProvider)
@ -228,7 +227,7 @@ class SettingsFragment : ScreenFragment() {
private fun LinearLayoutCompat.addSwitch(
key: Preferences.Key<Boolean>,
title: String,
summary: String
summary: String,
) {
val preference = addPreference(key, title, { summary }, null)
preference.check.visibility = View.VISIBLE
@ -238,7 +237,7 @@ class SettingsFragment : ScreenFragment() {
private fun <T> LinearLayoutCompat.addEdit(
key: Preferences.Key<T>, title: String, valueToString: (T) -> String,
stringToValue: (String) -> T?, configureEdit: (TextInputEditText) -> Unit
stringToValue: (String) -> T?, configureEdit: (TextInputEditText) -> Unit,
) {
addPreference(key, title, { valueToString(Preferences[key]) }) { it ->
val scroll = NestedScrollView(it)
@ -279,7 +278,7 @@ class SettingsFragment : ScreenFragment() {
private fun LinearLayoutCompat.addEditInt(
key: Preferences.Key<Int>,
title: String,
range: IntRange?
range: IntRange?,
) {
addEdit(key, title, { it.toString() }, { it.toIntOrNull() }) {
it.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
@ -295,7 +294,7 @@ class SettingsFragment : ScreenFragment() {
private fun <T : Preferences.Enumeration<T>> LinearLayoutCompat.addEnumeration(
key: Preferences.Key<T>,
title: String,
valueToString: (T) -> String
valueToString: (T) -> String,
) {
addPreference(key, title, { valueToString(Preferences[key]) }) {
val values = key.default.value.values
@ -319,7 +318,7 @@ class SettingsFragment : ScreenFragment() {
parent: ViewGroup,
titleText: String,
private val summaryProvider: () -> String,
private val dialogProvider: ((Context) -> AlertDialog)?
private val dialogProvider: ((Context) -> AlertDialog)?,
) {
val view = parent.inflate(R.layout.preference_item)
val title = view.findViewById<MaterialTextView>(R.id.title)!!

View File

@ -8,6 +8,7 @@ import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.adapter.FragmentStateAdapter
@ -32,6 +33,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.flow.collect
import kotlin.math.*
class TabsFragment : ScreenFragment() {
@ -88,7 +90,6 @@ class TabsFragment : ScreenFragment() {
}
})
private var sortOrderDisposable: Disposable? = null
private var categoriesDisposable: Disposable? = null
private var repositoriesDisposable: Disposable? = null
private var sectionsAnimator: ValueAnimator? = null
@ -198,9 +199,11 @@ class TabsFragment : ScreenFragment() {
}
updateOrder()
sortOrderDisposable = Preferences.observable.subscribe {
if (it == Preferences.Key.SortOrder) {
updateOrder()
lifecycleScope.launchWhenStarted {
Preferences.subject.collect {
if (it == Preferences.Key.SortOrder) {
updateOrder()
}
}
}
@ -302,8 +305,6 @@ class TabsFragment : ScreenFragment() {
viewPager = null
syncConnection.unbind(requireContext())
sortOrderDisposable?.dispose()
sortOrderDisposable = null
categoriesDisposable?.dispose()
categoriesDisposable = null
repositoriesDisposable?.dispose()