Add navigation drawer view model

pull/1964/head
Alex Baker 3 years ago
parent c2e87a86fa
commit 9a33f54202

@ -140,7 +140,7 @@ class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandl
private fun clearUi() { private fun clearUi() {
finishActionMode() finishActionMode()
navigationDrawer?.closeDrawer() navigationDrawer?.dismiss()
} }
private suspend fun getTaskToLoad(filter: Filter?): Task? { private suspend fun getTaskToLoad(filter: Filter?): Task? {

@ -6,7 +6,6 @@
package com.todoroo.astrid.adapter package com.todoroo.astrid.adapter
import android.app.Activity import android.app.Activity
import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
@ -48,14 +47,6 @@ class NavigationDrawerAdapter @Inject constructor(
this.onClick = onClick this.onClick = onClick
} }
fun save(outState: Bundle) {
outState.putParcelable(TOKEN_SELECTED, selected)
}
fun restore(savedInstanceState: Bundle) {
selected = savedInstanceState.getParcelable(TOKEN_SELECTED)
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.dispose() super.dispose()
} }
@ -117,10 +108,6 @@ class NavigationDrawerAdapter @Inject constructor(
old[oldPosition].areContentsTheSame(new[newPosition]) old[oldPosition].areContentsTheSame(new[newPosition])
} }
companion object {
private const val TOKEN_SELECTED = "token_selected"
}
override fun onChanged(position: Int, count: Int, payload: Any?) = override fun onChanged(position: Int, count: Int, payload: Any?) =
notifyItemRangeChanged(position, count, payload) notifyItemRangeChanged(position, count, payload)

@ -16,7 +16,7 @@ import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.PermaSql import com.todoroo.astrid.api.PermaSql
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import com.todoroo.astrid.timers.TimerPlugin import com.todoroo.astrid.timers.TimerPlugin
import dagger.hilt.android.qualifiers.ActivityContext import dagger.hilt.android.qualifiers.ApplicationContext
import org.tasks.R import org.tasks.R
import org.tasks.data.* import org.tasks.data.*
import org.tasks.data.TaskDao.TaskCriteria.activeAndVisible import org.tasks.data.TaskDao.TaskCriteria.activeAndVisible
@ -34,7 +34,7 @@ import javax.inject.Inject
* @author Tim Su <tim></tim>@todoroo.com> * @author Tim Su <tim></tim>@todoroo.com>
*/ */
class BuiltInFilterExposer @Inject constructor( class BuiltInFilterExposer @Inject constructor(
@param:ActivityContext private val context: Context, @param:ApplicationContext private val context: Context,
private val preferences: Preferences, private val preferences: Preferences,
private val taskDao: TaskDao) { private val taskDao: TaskDao) {

@ -7,7 +7,7 @@ import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.FilterListItem import com.todoroo.astrid.api.FilterListItem
import com.todoroo.astrid.api.FilterListItem.NO_ORDER import com.todoroo.astrid.api.FilterListItem.NO_ORDER
import com.todoroo.astrid.core.BuiltInFilterExposer import com.todoroo.astrid.core.BuiltInFilterExposer
import dagger.hilt.android.qualifiers.ActivityContext import dagger.hilt.android.qualifiers.ApplicationContext
import org.tasks.BuildConfig import org.tasks.BuildConfig
import org.tasks.R import org.tasks.R
import org.tasks.activities.GoogleTaskListSettingsActivity import org.tasks.activities.GoogleTaskListSettingsActivity
@ -28,7 +28,7 @@ import org.tasks.ui.NavigationDrawerFragment
import javax.inject.Inject import javax.inject.Inject
class FilterProvider @Inject constructor( class FilterProvider @Inject constructor(
@param:ActivityContext private val context: Context, @param:ApplicationContext private val context: Context,
private val inventory: Inventory, private val inventory: Inventory,
private val builtInFilterExposer: BuiltInFilterExposer, private val builtInFilterExposer: BuiltInFilterExposer,
private val filterDao: FilterDao, private val filterDao: FilterDao,

@ -1,9 +1,6 @@
package org.tasks.ui package org.tasks.ui
import android.app.Activity
import android.app.Dialog import android.app.Dialog
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
@ -11,6 +8,9 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -22,13 +22,11 @@ import com.todoroo.astrid.adapter.NavigationDrawerAdapter
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.FilterListItem import com.todoroo.astrid.api.FilterListItem
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch import kotlinx.coroutines.flow.launchIn
import org.tasks.LocalBroadcastManager import kotlinx.coroutines.flow.onEach
import org.tasks.R import org.tasks.R
import org.tasks.billing.PurchaseActivity import org.tasks.billing.PurchaseActivity
import org.tasks.data.TaskDao
import org.tasks.extensions.Context.openUri import org.tasks.extensions.Context.openUri
import org.tasks.filters.FilterProvider
import org.tasks.filters.NavigationDrawerAction import org.tasks.filters.NavigationDrawerAction
import org.tasks.intents.TaskIntents import org.tasks.intents.TaskIntents
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
@ -36,32 +34,26 @@ import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class NavigationDrawerFragment : BottomSheetDialogFragment() { class NavigationDrawerFragment : BottomSheetDialogFragment() {
private val refreshReceiver = RefreshReceiver()
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
@Inject lateinit var adapter: NavigationDrawerAdapter @Inject lateinit var adapter: NavigationDrawerAdapter
@Inject lateinit var filterProvider: FilterProvider
@Inject lateinit var taskDao: TaskDao
@Inject lateinit var preferences: Preferences @Inject lateinit var preferences: Preferences
override fun getTheme() = R.style.CustomBottomSheetDialog override fun getTheme() = R.style.CustomBottomSheetDialog
private lateinit var recyclerView: RecyclerView private lateinit var recyclerView: RecyclerView
private val viewModel: NavigationDrawerViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
adapter.restore(savedInstanceState)
}
arguments?.getParcelable<Filter>(EXTRA_SELECTED)?.let { arguments?.getParcelable<Filter>(EXTRA_SELECTED)?.let {
adapter.setSelected(it) viewModel.setSelected(it)
} }
} }
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
dialog.setOnShowListener { dialog.setOnShowListener {
val bottomSheet = dialog.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet) val bottomSheet =
dialog.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
val behavior = BottomSheetBehavior.from(bottomSheet!!) val behavior = BottomSheetBehavior.from(bottomSheet!!)
behavior.skipCollapsed = true behavior.skipCollapsed = true
if (preferences.isTopAppBar) { if (preferences.isTopAppBar) {
@ -73,28 +65,29 @@ class NavigationDrawerFragment : BottomSheetDialogFragment() {
return dialog return dialog
} }
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
requireActivity().setDefaultKeyMode(Activity.DEFAULT_KEYS_SEARCH_LOCAL)
setUpList()
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
val layout = inflater.inflate(R.layout.fragment_navigation_drawer, container, false) val layout = inflater.inflate(R.layout.fragment_navigation_drawer, container, false)
recyclerView = layout.findViewById(R.id.recycler_view) recyclerView = layout.findViewById(R.id.recycler_view)
(recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false (recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
return layout adapter.setOnClick(this::onFilterItemSelected)
}
private fun setUpList() {
adapter.setOnClick { item: FilterListItem? -> onFilterItemSelected(item) }
recyclerView.layoutManager = LinearLayoutManager(context) recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = adapter recyclerView.adapter = adapter
viewModel
.viewState
.flowWithLifecycle(lifecycle, Lifecycle.State.RESUMED)
.onEach {
adapter.setSelected(it.selected)
adapter.submitList(it.filters)
}
.launchIn(lifecycleScope)
return layout
} }
private fun onFilterItemSelected(item: FilterListItem?) { private fun onFilterItemSelected(item: FilterListItem?) {
if (item is Filter) { if (item is Filter) {
viewModel.setSelected(item)
activity?.startActivity(TaskIntents.getTaskListIntent(activity, item)) activity?.startActivity(TaskIntents.getTaskListIntent(activity, item))
} else if (item is NavigationDrawerAction) { } else if (item is NavigationDrawerAction) {
when (item.requestCode) { when (item.requestCode) {
@ -104,52 +97,9 @@ class NavigationDrawerFragment : BottomSheetDialogFragment() {
else -> activity?.startActivityForResult(item.intent, item.requestCode) else -> activity?.startActivityForResult(item.intent, item.requestCode)
} }
} }
closeDrawer()
}
override fun onPause() {
super.onPause()
localBroadcastManager.unregisterReceiver(refreshReceiver)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
adapter.save(outState)
}
fun closeDrawer() {
dismiss() dismiss()
} }
override fun onResume() {
super.onResume()
localBroadcastManager.registerRefreshListReceiver(refreshReceiver)
updateFilters()
}
private fun updateFilters() = lifecycleScope.launch {
filterProvider
.navDrawerItems()
.onEach {
if (it is Filter && it.count == -1) {
it.count = taskDao.count(it)
}
}
.let { adapter.submitList(it) }
}
private inner class RefreshReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
if (intent == null) {
return
}
val action = intent.action
if (LocalBroadcastManager.REFRESH == action || LocalBroadcastManager.REFRESH_LIST == action) {
updateFilters()
}
}
}
companion object { companion object {
const val REQUEST_NEW_LIST = 10100 const val REQUEST_NEW_LIST = 10100
const val REQUEST_SETTINGS = 10101 const val REQUEST_SETTINGS = 10101

@ -0,0 +1,68 @@
package org.tasks.ui
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.FilterListItem
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.tasks.LocalBroadcastManager
import org.tasks.data.TaskDao
import org.tasks.filters.FilterProvider
import javax.inject.Inject
@HiltViewModel
class NavigationDrawerViewModel @Inject constructor(
private val filterProvider: FilterProvider,
private val taskDao: TaskDao,
private val localBroadcastManager: LocalBroadcastManager,
) : ViewModel() {
data class ViewState(
val selected: Filter? = null,
val filters: List<FilterListItem> = emptyList(),
)
private val _viewState = MutableStateFlow(ViewState())
private val refreshReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
LocalBroadcastManager.REFRESH,
LocalBroadcastManager.REFRESH_LIST -> updateFilters()
}
}
}
val viewState: StateFlow<ViewState>
get() = _viewState.asStateFlow()
fun setSelected(filter: Filter?) {
_viewState.update { it.copy(selected = filter) }
}
fun updateFilters() = viewModelScope.launch {
filterProvider
.navDrawerItems()
.onEach {
if (it is Filter && it.count == -1) {
it.count = taskDao.count(it)
}
}
.let { filters -> _viewState.update { it.copy(filters = filters) } }
}
override fun onCleared() {
localBroadcastManager.unregisterReceiver(refreshReceiver)
}
init {
localBroadcastManager.registerRefreshListReceiver(refreshReceiver)
updateFilters()
}
}
Loading…
Cancel
Save