mirror of
https://github.com/Aviortheking/Neo-Store.git
synced 2025-04-22 19:02:12 +00:00
Add: The main navigation fragments [new UI]
This commit is contained in:
parent
9e9f17fb1d
commit
7271528d7a
@ -0,0 +1,94 @@
|
||||
package com.looker.droidify.ui.fragments
|
||||
|
||||
import android.database.Cursor
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.looker.droidify.R
|
||||
import com.looker.droidify.database.CursorOwner
|
||||
import com.looker.droidify.database.Database
|
||||
import com.looker.droidify.databinding.FragmentExploreXBinding
|
||||
import com.looker.droidify.ui.adapters.AppListAdapter
|
||||
import com.looker.droidify.ui.viewmodels.MainNavFragmentViewModelX
|
||||
import com.looker.droidify.utility.RxUtils
|
||||
import com.looker.droidify.widget.RecyclerFastScroller
|
||||
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.first
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ExploreFragment : MainNavFragmentX(), CursorOwner.Callback {
|
||||
|
||||
override val viewModel: MainNavFragmentViewModelX by viewModels()
|
||||
private lateinit var binding: FragmentExploreXBinding
|
||||
|
||||
override val source = Source.AVAILABLE
|
||||
|
||||
private var repositoriesDisposable: Disposable? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = FragmentExploreXBinding.inflate(inflater, container, false)
|
||||
binding.lifecycleOwner = this
|
||||
|
||||
binding.recyclerView.apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
isMotionEventSplittingEnabled = false
|
||||
isVerticalScrollBarEnabled = false
|
||||
setHasFixedSize(true)
|
||||
recycledViewPool.setMaxRecycledViews(AppListAdapter.ViewType.PRODUCT.ordinal, 30)
|
||||
adapter = AppListAdapter { mainActivityX.navigateProduct(it.packageName) }
|
||||
RecyclerFastScroller(this)
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
mainActivityX.attachCursorOwner(this, viewModel.request(source))
|
||||
repositoriesDisposable = Observable.just(Unit)
|
||||
.concatWith(Database.observable(Database.Subject.Repositories))
|
||||
.observeOn(Schedulers.io())
|
||||
.flatMapSingle { RxUtils.querySingle { Database.RepositoryAdapter.getAll(it) } }
|
||||
.map { list -> list.asSequence().map { Pair(it.id, it) }.toMap() }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { (binding.recyclerView.adapter as? AppListAdapter)?.repositories = it }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
|
||||
mainActivityX.detachCursorOwner(this)
|
||||
repositoriesDisposable?.dispose()
|
||||
repositoriesDisposable = null
|
||||
}
|
||||
|
||||
override fun onCursorData(request: CursorOwner.Request, cursor: Cursor?) {
|
||||
(binding.recyclerView.adapter as? AppListAdapter)?.apply {
|
||||
this.cursor = cursor
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
emptyText = when {
|
||||
cursor == null -> ""
|
||||
viewModel.searchQuery.first()
|
||||
.isNotEmpty() -> getString(R.string.no_matching_applications_found)
|
||||
else -> getString(R.string.no_applications_available)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package com.looker.droidify.ui.fragments
|
||||
|
||||
import android.database.Cursor
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.looker.droidify.R
|
||||
import com.looker.droidify.database.CursorOwner
|
||||
import com.looker.droidify.database.Database
|
||||
import com.looker.droidify.databinding.FragmentInstalledXBinding
|
||||
import com.looker.droidify.ui.adapters.AppListAdapter
|
||||
import com.looker.droidify.ui.viewmodels.MainNavFragmentViewModelX
|
||||
import com.looker.droidify.utility.RxUtils
|
||||
import com.looker.droidify.widget.RecyclerFastScroller
|
||||
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.first
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class InstalledFragment : MainNavFragmentX(), CursorOwner.Callback {
|
||||
|
||||
override val viewModel: MainNavFragmentViewModelX by viewModels()
|
||||
private lateinit var binding: FragmentInstalledXBinding
|
||||
|
||||
override val source = Source.INSTALLED
|
||||
|
||||
private var repositoriesDisposable: Disposable? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = FragmentInstalledXBinding.inflate(inflater, container, false)
|
||||
binding.lifecycleOwner = this
|
||||
|
||||
binding.recyclerView.apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
isMotionEventSplittingEnabled = false
|
||||
isVerticalScrollBarEnabled = false
|
||||
adapter = AppListAdapter { mainActivityX.navigateProduct(it.packageName) }
|
||||
RecyclerFastScroller(this)
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
mainActivityX.attachCursorOwner(this, viewModel.request(source))
|
||||
repositoriesDisposable = Observable.just(Unit)
|
||||
.concatWith(Database.observable(Database.Subject.Repositories))
|
||||
.observeOn(Schedulers.io())
|
||||
.flatMapSingle { RxUtils.querySingle { Database.RepositoryAdapter.getAll(it) } }
|
||||
.map { list -> list.asSequence().map { Pair(it.id, it) }.toMap() }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { (binding.recyclerView.adapter as? AppListAdapter)?.repositories = it }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
|
||||
mainActivityX.detachCursorOwner(this)
|
||||
repositoriesDisposable?.dispose()
|
||||
repositoriesDisposable = null
|
||||
}
|
||||
|
||||
override fun onCursorData(request: CursorOwner.Request, cursor: Cursor?) {
|
||||
// TODO create app list out of cursor and use those on the different RecycleViews
|
||||
(binding.recyclerView.adapter as? AppListAdapter)?.apply {
|
||||
this.cursor = cursor
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
emptyText = when {
|
||||
cursor == null -> ""
|
||||
viewModel.searchQuery.first()
|
||||
.isNotEmpty() -> getString(R.string.no_matching_applications_found)
|
||||
else -> getString(R.string.all_applications_up_to_date)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package com.looker.droidify.ui.fragments
|
||||
|
||||
import android.database.Cursor
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.looker.droidify.R
|
||||
import com.looker.droidify.database.CursorOwner
|
||||
import com.looker.droidify.database.Database
|
||||
import com.looker.droidify.databinding.FragmentLatestXBinding
|
||||
import com.looker.droidify.ui.adapters.AppListAdapter
|
||||
import com.looker.droidify.ui.viewmodels.MainNavFragmentViewModelX
|
||||
import com.looker.droidify.utility.RxUtils
|
||||
import com.looker.droidify.widget.RecyclerFastScroller
|
||||
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.first
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class LatestFragment : MainNavFragmentX(), CursorOwner.Callback {
|
||||
|
||||
override val viewModel: MainNavFragmentViewModelX by viewModels()
|
||||
private lateinit var binding: FragmentLatestXBinding
|
||||
|
||||
override val source = Source.UPDATES
|
||||
|
||||
private var repositoriesDisposable: Disposable? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = FragmentLatestXBinding.inflate(inflater, container, false)
|
||||
binding.lifecycleOwner = this
|
||||
|
||||
binding.recyclerView.apply {
|
||||
id = android.R.id.list
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
isMotionEventSplittingEnabled = false
|
||||
isVerticalScrollBarEnabled = false
|
||||
adapter = AppListAdapter { mainActivityX.navigateProduct(it.packageName) }
|
||||
RecyclerFastScroller(this)
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
mainActivityX.attachCursorOwner(this, viewModel.request(source))
|
||||
repositoriesDisposable = Observable.just(Unit)
|
||||
.concatWith(Database.observable(Database.Subject.Repositories))
|
||||
.observeOn(Schedulers.io())
|
||||
.flatMapSingle { RxUtils.querySingle { Database.RepositoryAdapter.getAll(it) } }
|
||||
.map { list -> list.asSequence().map { Pair(it.id, it) }.toMap() }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { (binding.recyclerView.adapter as? AppListAdapter)?.repositories = it }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
|
||||
mainActivityX.detachCursorOwner(this)
|
||||
repositoriesDisposable?.dispose()
|
||||
repositoriesDisposable = null
|
||||
}
|
||||
|
||||
override fun onCursorData(request: CursorOwner.Request, cursor: Cursor?) {
|
||||
// TODO create app list out of cursor and use those on the different RecycleViews
|
||||
(binding.recyclerView.adapter as? AppListAdapter)?.apply {
|
||||
this.cursor = cursor
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
emptyText = when {
|
||||
cursor == null -> ""
|
||||
viewModel.searchQuery.first()
|
||||
.isNotEmpty() -> getString(R.string.no_matching_applications_found)
|
||||
else -> getString(R.string.all_applications_up_to_date)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.looker.droidify.ui.fragments
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.looker.droidify.R
|
||||
import com.looker.droidify.database.CursorOwner
|
||||
import com.looker.droidify.entity.ProductItem
|
||||
import com.looker.droidify.ui.activities.MainActivityX
|
||||
import com.looker.droidify.ui.viewmodels.MainNavFragmentViewModelX
|
||||
|
||||
abstract class MainNavFragmentX : Fragment(), CursorOwner.Callback {
|
||||
val mainActivityX: MainActivityX
|
||||
get() = requireActivity() as MainActivityX
|
||||
abstract val viewModel: MainNavFragmentViewModelX
|
||||
abstract val source: Source
|
||||
|
||||
open fun onBackPressed(): Boolean = false
|
||||
|
||||
internal fun setSearchQuery(searchQuery: String) {
|
||||
viewModel.setSearchQuery(searchQuery) {
|
||||
if (view != null) {
|
||||
mainActivityX.attachCursorOwner(this, viewModel.request(source))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun setSection(section: ProductItem.Section) {
|
||||
viewModel.setSection(section) {
|
||||
if (view != null) {
|
||||
mainActivityX.attachCursorOwner(this, viewModel.request(source))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun setOrder(order: ProductItem.Order) {
|
||||
viewModel.setOrder(order) {
|
||||
if (view != null) {
|
||||
mainActivityX.attachCursorOwner(this, viewModel.request(source))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class Source(val titleResId: Int, val sections: Boolean, val order: Boolean) {
|
||||
AVAILABLE(R.string.available, true, true),
|
||||
INSTALLED(R.string.installed, false, true),
|
||||
UPDATES(R.string.updates, false, false)
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package com.looker.droidify.ui.viewmodels
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.looker.droidify.database.CursorOwner
|
||||
import com.looker.droidify.entity.ProductItem
|
||||
import com.looker.droidify.ui.fragments.Source
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MainNavFragmentViewModelX : ViewModel() {
|
||||
|
||||
private val _order = MutableStateFlow(ProductItem.Order.LAST_UPDATE)
|
||||
private val _sections = MutableStateFlow<ProductItem.Section>(ProductItem.Section.All)
|
||||
private val _searchQuery = MutableStateFlow("")
|
||||
|
||||
val order: StateFlow<ProductItem.Order> = _order.stateIn(
|
||||
initialValue = ProductItem.Order.LAST_UPDATE,
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5000)
|
||||
)
|
||||
|
||||
val sections: StateFlow<ProductItem.Section> = _sections.stateIn(
|
||||
initialValue = ProductItem.Section.All,
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5000)
|
||||
)
|
||||
val searchQuery: StateFlow<String> = _searchQuery.stateIn(
|
||||
initialValue = "",
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5000)
|
||||
)
|
||||
|
||||
fun request(source: Source): CursorOwner.Request {
|
||||
var mSearchQuery = ""
|
||||
var mSections: ProductItem.Section = ProductItem.Section.All
|
||||
var mOrder: ProductItem.Order = ProductItem.Order.NAME
|
||||
viewModelScope.launch {
|
||||
launch { searchQuery.collect { if (source.sections) mSearchQuery = it } }
|
||||
launch { sections.collect { if (source.sections) mSections = it } }
|
||||
launch { order.collect { if (source.order) mOrder = it } }
|
||||
}
|
||||
return when (source) {
|
||||
Source.AVAILABLE -> CursorOwner.Request.ProductsAvailable(
|
||||
mSearchQuery,
|
||||
mSections,
|
||||
mOrder
|
||||
)
|
||||
Source.INSTALLED -> CursorOwner.Request.ProductsInstalled(
|
||||
mSearchQuery,
|
||||
mSections,
|
||||
mOrder
|
||||
)
|
||||
Source.UPDATES -> CursorOwner.Request.ProductsUpdates(
|
||||
mSearchQuery,
|
||||
mSections,
|
||||
mOrder
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun setSection(newSection: ProductItem.Section, perform: () -> Unit) {
|
||||
viewModelScope.launch {
|
||||
if (newSection != sections.value) {
|
||||
_sections.emit(newSection)
|
||||
launch(Dispatchers.Main) { perform() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setOrder(newOrder: ProductItem.Order, perform: () -> Unit) {
|
||||
viewModelScope.launch {
|
||||
if (newOrder != order.value) {
|
||||
_order.emit(newOrder)
|
||||
launch(Dispatchers.Main) { perform() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setSearchQuery(newSearchQuery: String, perform: () -> Unit) {
|
||||
viewModelScope.launch {
|
||||
if (newSearchQuery != searchQuery.value) {
|
||||
_searchQuery.emit(newSearchQuery)
|
||||
launch(Dispatchers.Main) { perform() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user