Improve: Move more logic to ViewModel

This commit is contained in:
LooKeR 2021-11-10 14:57:32 +05:30
parent 9afcd3661f
commit 65541e7f4f
2 changed files with 45 additions and 71 deletions

View File

@ -2,7 +2,6 @@ package com.looker.droidify.ui.appsList
import android.database.Cursor import android.database.Cursor
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -22,7 +21,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.first
class AppListFragment() : BaseFragment(), CursorOwner.Callback { class AppListFragment() : BaseFragment(), CursorOwner.Callback {
@ -30,7 +29,6 @@ class AppListFragment() : BaseFragment(), CursorOwner.Callback {
companion object { companion object {
private const val EXTRA_SOURCE = "source" private const val EXTRA_SOURCE = "source"
private const val STATE_LAYOUT_MANAGER = "layoutManager"
} }
enum class Source(val titleResId: Int, val sections: Boolean, val order: Boolean) { enum class Source(val titleResId: Int, val sections: Boolean, val order: Boolean) {
@ -48,51 +46,10 @@ class AppListFragment() : BaseFragment(), CursorOwner.Callback {
val source: Source val source: Source
get() = requireArguments().getString(EXTRA_SOURCE)!!.let(Source::valueOf) get() = requireArguments().getString(EXTRA_SOURCE)!!.let(Source::valueOf)
private val searchQuery: String
get() {
var _searchQuery = ""
lifecycleScope.launchWhenCreated { viewModel.searchQuery.collect { _searchQuery = it } }
return _searchQuery
}
private val section: ProductItem.Section
get() {
var _section: ProductItem.Section = ProductItem.Section.All
lifecycleScope.launchWhenCreated { viewModel.sections.collect { _section = it } }
return _section
}
private val order: ProductItem.Order
get() {
var _order: ProductItem.Order = ProductItem.Order.LAST_UPDATE
lifecycleScope.launchWhenCreated { viewModel.order.collect { _order = it } }
return _order
}
private var layoutManagerState: Parcelable? = null
private var recyclerView: RecyclerView? = null private var recyclerView: RecyclerView? = null
private var repositoriesDisposable: Disposable? = null private var repositoriesDisposable: Disposable? = null
private val request: CursorOwner.Request
get() {
val searchQuery = searchQuery
val section = if (source.sections) section else ProductItem.Section.All
val order = if (source.order) order else ProductItem.Order.NAME
return when (source) {
Source.AVAILABLE -> CursorOwner.Request.ProductsAvailable(
searchQuery,
section,
order
)
Source.INSTALLED -> CursorOwner.Request.ProductsInstalled(
searchQuery,
section,
order
)
Source.UPDATES -> CursorOwner.Request.ProductsUpdates(searchQuery, section, order)
}
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -114,14 +71,13 @@ class AppListFragment() : BaseFragment(), CursorOwner.Callback {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
layoutManagerState = savedInstanceState?.getParcelable(STATE_LAYOUT_MANAGER)
screenActivity.cursorOwner.attach(this, request) screenActivity.cursorOwner.attach(this, viewModel.request(source))
repositoriesDisposable = Observable.just(Unit) repositoriesDisposable = Observable.just(Unit)
.concatWith(Database.observable(Database.Subject.Repositories)) .concatWith(Database.observable(Database.Subject.Repositories))
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.flatMapSingle { RxUtils.querySingle { Database.RepositoryAdapter.getAll(it) } } .flatMapSingle { RxUtils.querySingle { Database.RepositoryAdapter.getAll(it) } }
.map { it.asSequence().map { Pair(it.id, it) }.toMap() } .map { list -> list.asSequence().map { Pair(it.id, it) }.toMap() }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { (recyclerView?.adapter as? ProductsAdapter)?.repositories = it } .subscribe { (recyclerView?.adapter as? ProductsAdapter)?.repositories = it }
} }
@ -136,18 +92,14 @@ class AppListFragment() : BaseFragment(), CursorOwner.Callback {
repositoriesDisposable = null repositoriesDisposable = null
} }
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
(layoutManagerState ?: recyclerView?.layoutManager?.onSaveInstanceState())
?.let { outState.putParcelable(STATE_LAYOUT_MANAGER, it) }
}
override fun onCursorData(request: CursorOwner.Request, cursor: Cursor?) { override fun onCursorData(request: CursorOwner.Request, cursor: Cursor?) {
(recyclerView?.adapter as? ProductsAdapter)?.apply { (recyclerView?.adapter as? ProductsAdapter)?.apply {
this.cursor = cursor this.cursor = cursor
viewLifecycleOwner.lifecycleScope.launchWhenCreated {
emptyText = when { emptyText = when {
cursor == null -> "" cursor == null -> ""
searchQuery.isNotEmpty() -> getString(R.string.no_matching_applications_found) viewModel.searchQuery.first()
.isNotEmpty() -> getString(R.string.no_matching_applications_found)
else -> when (source) { else -> when (source) {
Source.AVAILABLE -> getString(R.string.no_applications_available) Source.AVAILABLE -> getString(R.string.no_applications_available)
Source.INSTALLED -> getString(R.string.no_applications_installed) Source.INSTALLED -> getString(R.string.no_applications_installed)
@ -155,16 +107,13 @@ class AppListFragment() : BaseFragment(), CursorOwner.Callback {
} }
} }
} }
layoutManagerState?.let {
layoutManagerState = null
recyclerView?.layoutManager?.onRestoreInstanceState(it)
} }
} }
internal fun setSearchQuery(searchQuery: String) { internal fun setSearchQuery(searchQuery: String) {
viewModel.setSearchQuery(searchQuery) { viewModel.setSearchQuery(searchQuery) {
if (view != null) { if (view != null) {
screenActivity.cursorOwner.attach(this, request) screenActivity.cursorOwner.attach(this, viewModel.request(source))
} }
} }
} }
@ -172,7 +121,7 @@ class AppListFragment() : BaseFragment(), CursorOwner.Callback {
internal fun setSection(section: ProductItem.Section) { internal fun setSection(section: ProductItem.Section) {
viewModel.setSection(section) { viewModel.setSection(section) {
if (view != null) { if (view != null) {
screenActivity.cursorOwner.attach(this, request) screenActivity.cursorOwner.attach(this, viewModel.request(source))
} }
} }
} }
@ -180,7 +129,7 @@ class AppListFragment() : BaseFragment(), CursorOwner.Callback {
internal fun setOrder(order: ProductItem.Order) { internal fun setOrder(order: ProductItem.Order) {
viewModel.setOrder(order) { viewModel.setOrder(order) {
if (view != null) { if (view != null) {
screenActivity.cursorOwner.attach(this, request) screenActivity.cursorOwner.attach(this, viewModel.request(source))
} }
} }
} }

View File

@ -2,12 +2,10 @@ package com.looker.droidify.ui.appsList
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.looker.droidify.database.CursorOwner
import com.looker.droidify.entity.ProductItem import com.looker.droidify.entity.ProductItem
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class AppListViewModel : ViewModel() { class AppListViewModel : ViewModel() {
@ -21,6 +19,7 @@ class AppListViewModel : ViewModel() {
scope = viewModelScope, scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000) started = SharingStarted.WhileSubscribed(5000)
) )
val sections: StateFlow<ProductItem.Section> = _sections.stateIn( val sections: StateFlow<ProductItem.Section> = _sections.stateIn(
initialValue = ProductItem.Section.All, initialValue = ProductItem.Section.All,
scope = viewModelScope, scope = viewModelScope,
@ -32,6 +31,32 @@ class AppListViewModel : ViewModel() {
started = SharingStarted.WhileSubscribed(5000) started = SharingStarted.WhileSubscribed(5000)
) )
fun request(source: AppListFragment.Source): CursorOwner.Request {
var mSearchQuery = ""
var mSections: ProductItem.Section = ProductItem.Section.All
var mOrder: ProductItem.Order = ProductItem.Order.NAME
viewModelScope.launch { searchQuery.collect { if (source.sections) mSearchQuery = it } }
viewModelScope.launch { sections.collect { if (source.sections) mSections = it } }
viewModelScope.launch { order.collect { if (source.order) mOrder = it } }
return when (source) {
AppListFragment.Source.AVAILABLE -> CursorOwner.Request.ProductsAvailable(
mSearchQuery,
mSections,
mOrder
)
AppListFragment.Source.INSTALLED -> CursorOwner.Request.ProductsInstalled(
mSearchQuery,
mSections,
mOrder
)
AppListFragment.Source.UPDATES -> CursorOwner.Request.ProductsUpdates(
mSearchQuery,
mSections,
mOrder
)
}
}
fun setSection(newSection: ProductItem.Section, perform: () -> Unit) { fun setSection(newSection: ProductItem.Section, perform: () -> Unit) {
viewModelScope.launch(Dispatchers.Main) { viewModelScope.launch(Dispatchers.Main) {
if (newSection != sections.value) { if (newSection != sections.value) {