From 5e72165d0b0313dd6a601e9fb537f078a65a0a19 Mon Sep 17 00:00:00 2001 From: LooKeR Date: Sun, 31 Oct 2021 19:06:55 +0530 Subject: [PATCH] Improve: Move Away from RxJava and use coroutines (#NoRxGang) --- .../com/looker/droidify/MainApplication.kt | 33 ++++++++++-------- .../looker/droidify/content/Preferences.kt | 34 +++++++++++-------- .../droidify/screen/EditRepositoryFragment.kt | 26 +++++--------- .../droidify/screen/SettingsFragment.kt | 25 +++++++------- .../looker/droidify/screen/TabsFragment.kt | 13 +++---- 5 files changed, 66 insertions(+), 65 deletions(-) diff --git a/src/main/kotlin/com/looker/droidify/MainApplication.kt b/src/main/kotlin/com/looker/droidify/MainApplication.kt index f332473e..0587011b 100644 --- a/src/main/kotlin/com/looker/droidify/MainApplication.kt +++ b/src/main/kotlin/com/looker/droidify/MainApplication.kt @@ -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() + } } } } diff --git a/src/main/kotlin/com/looker/droidify/content/Preferences.kt b/src/main/kotlin/com/looker/droidify/content/Preferences.kt index 0200d40c..260a7cd7 100644 --- a/src/main/kotlin/com/looker/droidify/content/Preferences.kt +++ b/src/main/kotlin/com/looker/droidify/content/Preferences.kt @@ -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>() + private val _subject = MutableSharedFlow>() + 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> - get() = subject - sealed class Value { abstract val value: T internal abstract fun get( preferences: SharedPreferences, key: String, - defaultValue: Value + defaultValue: Value, ): 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 + defaultValue: Value, ): Boolean { return preferences.getBoolean(key, defaultValue.value) } @@ -71,7 +75,7 @@ object Preferences { override fun get( preferences: SharedPreferences, key: String, - defaultValue: Value + defaultValue: Value, ): Int { return preferences.getInt(key, defaultValue.value) } @@ -85,7 +89,7 @@ object Preferences { override fun get( preferences: SharedPreferences, key: String, - defaultValue: Value + defaultValue: Value, ): String { return preferences.getString(key, defaultValue.value) ?: defaultValue.value } @@ -99,7 +103,7 @@ object Preferences { override fun get( preferences: SharedPreferences, key: String, - defaultValue: Value + defaultValue: Value, ): T { val value = preferences.getString(key, defaultValue.value.valueString) return defaultValue.value.values.find { it.valueString == value } diff --git a/src/main/kotlin/com/looker/droidify/screen/EditRepositoryFragment.kt b/src/main/kotlin/com/looker/droidify/screen/EditRepositoryFragment.kt index 99bec4f3..e71f7a90 100644 --- a/src/main/kotlin/com/looker/droidify/screen/EditRepositoryFragment.kt +++ b/src/main/kotlin/com/looker/droidify/screen/EditRepositoryFragment.kt @@ -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() @@ -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) { diff --git a/src/main/kotlin/com/looker/droidify/screen/SettingsFragment.kt b/src/main/kotlin/com/looker/droidify/screen/SettingsFragment.kt index ba3c2d1a..3c215a30 100644 --- a/src/main/kotlin/com/looker/droidify/screen/SettingsFragment.kt +++ b/src/main/kotlin/com/looker/droidify/screen/SettingsFragment.kt @@ -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, 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 LinearLayoutCompat.addPreference( key: Preferences.Key, title: String, - summaryProvider: () -> String, dialogProvider: ((Context) -> AlertDialog)? + summaryProvider: () -> String, dialogProvider: ((Context) -> AlertDialog)?, ): Preference { val preference = Preference(key, this@SettingsFragment, this, title, summaryProvider, dialogProvider) @@ -228,7 +227,7 @@ class SettingsFragment : ScreenFragment() { private fun LinearLayoutCompat.addSwitch( key: Preferences.Key, 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 LinearLayoutCompat.addEdit( key: Preferences.Key, 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, 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 > LinearLayoutCompat.addEnumeration( key: Preferences.Key, 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(R.id.title)!! diff --git a/src/main/kotlin/com/looker/droidify/screen/TabsFragment.kt b/src/main/kotlin/com/looker/droidify/screen/TabsFragment.kt index a151b70e..9b19fdc2 100644 --- a/src/main/kotlin/com/looker/droidify/screen/TabsFragment.kt +++ b/src/main/kotlin/com/looker/droidify/screen/TabsFragment.kt @@ -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()