Add task to MainActivityViewModel state

pull/2672/head
Alex Baker 7 months ago
parent 6c031925ba
commit bde1356e7f

@ -21,13 +21,14 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.core.content.IntentCompat.getParcelableExtra
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.composethemeadapter.MdcTheme
import com.todoroo.andlib.utility.AndroidUtilities
import com.todoroo.astrid.activity.TaskEditFragment.Companion.newTaskEditFragment
import com.todoroo.astrid.activity.TaskListFragment.TaskListFragmentCallbackHandler
import com.todoroo.astrid.adapter.SubheaderClickHandler
import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.dao.TaskDao
@ -37,12 +38,13 @@ import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.tasks.BuildConfig
import org.tasks.LocalBroadcastManager
import org.tasks.R
import org.tasks.Tasks.Companion.IS_GENERIC
import org.tasks.activities.NavigationDrawerCustomization
@ -68,15 +70,13 @@ import org.tasks.extensions.Context.openUri
import org.tasks.extensions.hideKeyboard
import org.tasks.filters.FilterProvider
import org.tasks.filters.PlaceFilter
import org.tasks.intents.TaskIntents.getTaskListIntent
import org.tasks.location.LocationPickerActivity
import org.tasks.location.LocationPickerActivity.Companion.EXTRA_PLACE
import org.tasks.preferences.DefaultFilterProvider
import org.tasks.preferences.HelpAndFeedback
import org.tasks.preferences.MainPreferences
import org.tasks.preferences.Preferences
import org.tasks.themes.ColorProvider
import org.tasks.themes.Theme
import org.tasks.themes.ThemeColor
import org.tasks.ui.EmptyTaskEditFragment.Companion.newEmptyTaskEditFragment
import org.tasks.ui.MainActivityEvent
import org.tasks.ui.MainActivityEventBus
@ -84,12 +84,11 @@ import timber.log.Timber
import javax.inject.Inject
@AndroidEntryPoint
class MainActivity : AppCompatActivity(), TaskListFragmentCallbackHandler {
class MainActivity : AppCompatActivity() {
@Inject lateinit var preferences: Preferences
@Inject lateinit var defaultFilterProvider: DefaultFilterProvider
@Inject lateinit var theme: Theme
@Inject lateinit var taskDao: TaskDao
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
@Inject lateinit var taskCreator: TaskCreator
@Inject lateinit var inventory: Inventory
@Inject lateinit var colorProvider: ColorProvider
@ -105,9 +104,6 @@ class MainActivity : AppCompatActivity(), TaskListFragmentCallbackHandler {
private var actionMode: ActionMode? = null
private lateinit var binding: TaskListActivityBinding
private val filter: Filter?
get() = viewModel.state.value.filter
private val settingsRequest =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
recreate()
@ -123,6 +119,7 @@ class MainActivity : AppCompatActivity(), TaskListFragmentCallbackHandler {
currentPro = inventory.hasPro
binding = TaskListActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
logIntent("onCreate")
handleIntent()
binding.composeView.setContent {
@ -164,7 +161,7 @@ class MainActivity : AppCompatActivity(), TaskListFragmentCallbackHandler {
onClick = {
when (it) {
is DrawerItem.Filter -> {
openTaskListFragment(it.type())
viewModel.setFilter(it.type())
scope.launch(Dispatchers.Default) {
sheetState.hide()
viewModel.setDrawerOpen(false)
@ -246,32 +243,95 @@ class MainActivity : AppCompatActivity(), TaskListFragmentCallbackHandler {
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
applyTheme()
updateSystemBars(viewModel.state.value.filter)
}
}
viewModel
.state
.flowWithLifecycle(lifecycle)
.map { it.filter to it.task }
.distinctUntilChanged()
.onEach { (newFilter, task) ->
Timber.d("filter: $newFilter task: $task")
val existingTlf =
supportFragmentManager.findFragmentByTag(FRAG_TAG_TASK_LIST) as TaskListFragment?
val existingFilter = existingTlf?.getFilter()
val tlf = if (
existingFilter != null
&& existingFilter.areItemsTheSame(newFilter)
&& existingFilter == newFilter
// && check if manual sort changed
) {
existingTlf
} else {
clearUi()
TaskListFragment.newTaskListFragment(newFilter)
}
val existingTef =
supportFragmentManager.findFragmentByTag(FRAG_TAG_TASK_EDIT) as TaskEditFragment?
val transaction = supportFragmentManager.beginTransaction()
if (task == null) {
if (intent.finishAffinity) {
finishAffinity()
} else if (existingTef != null) {
if (intent.removeTask && intent.broughtToFront) {
moveTaskToBack(true)
}
hideKeyboard()
transaction
.replace(R.id.detail, newEmptyTaskEditFragment())
.runOnCommit {
if (isSinglePaneLayout) {
binding.master.visibility = View.VISIBLE
binding.detail.visibility = View.GONE
}
}
}
} else if (task != existingTef?.task) {
existingTef?.save(remove = false)
transaction
.replace(R.id.detail, newTaskEditFragment(task), FRAG_TAG_TASK_EDIT)
.runOnCommit {
if (isSinglePaneLayout) {
binding.detail.visibility = View.VISIBLE
binding.master.visibility = View.GONE
}
}
}
defaultFilterProvider.setLastViewedFilter(newFilter)
theme
.withThemeColor(getFilterColor(newFilter))
.applyToContext(this) // must happen before committing fragment
transaction
.replace(R.id.master, tlf, FRAG_TAG_TASK_LIST)
.runOnCommit { updateSystemBars(newFilter) }
.commit()
}
.launchIn(lifecycleScope)
}
private suspend fun process(event: MainActivityEvent) = when (event) {
is MainActivityEvent.OpenTask ->
onTaskListItemClicked(event.task)
private fun process(event: MainActivityEvent) = when (event) {
is MainActivityEvent.ClearTaskEditFragment ->
removeTaskEditFragment()
viewModel.setTask(null)
}
@Deprecated("Deprecated in Java")
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_NEW_LIST ->
if (resultCode == RESULT_OK) {
data
?.getParcelableExtra<Filter>(OPEN_FILTER)
?.let { startActivity(getTaskListIntent(this, it)) }
if (resultCode == RESULT_OK && data != null) {
getParcelableExtra(data, OPEN_FILTER, Filter::class.java)?.let {
viewModel.setFilter(it)
}
}
REQUEST_NEW_PLACE ->
if (resultCode == RESULT_OK) {
data
?.getParcelableExtra<Place>(LocationPickerActivity.EXTRA_PLACE)
?.let { startActivity(getTaskListIntent(this, PlaceFilter(it))) }
if (resultCode == RESULT_OK && data != null) {
getParcelableExtra(data, EXTRA_PLACE, Place::class.java)?.let {
viewModel.setFilter(PlaceFilter(it))
}
}
else ->
super.onActivityResult(requestCode, resultCode, data)
}
@ -280,185 +340,74 @@ class MainActivity : AppCompatActivity(), TaskListFragmentCallbackHandler {
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
logIntent("onNewIntent")
handleIntent()
}
private fun clearUi() {
finishActionMode()
actionMode?.finish()
actionMode = null
viewModel.setDrawerOpen(false)
}
private suspend fun getTaskToLoad(filter: Filter?): Task? {
val intent = intent
if (intent.isFromHistory) {
return null
}
if (intent.hasExtra(CREATE_TASK)) {
private suspend fun getTaskToLoad(filter: Filter?): Task? = when {
intent.isFromHistory -> null
intent.hasExtra(CREATE_TASK) -> {
val source = intent.getStringExtra(CREATE_SOURCE)
firebase.addTask(source ?: "unknown")
intent.removeExtra(CREATE_TASK)
intent.removeExtra(CREATE_SOURCE)
return taskCreator.createWithValues(filter, "")
taskCreator.createWithValues(filter, "")
}
if (intent.hasExtra(OPEN_TASK)) {
val task: Task? = intent.getParcelableExtra(OPEN_TASK)
intent.hasExtra(OPEN_TASK) -> {
val task = getParcelableExtra(intent, OPEN_TASK, Task::class.java)
intent.removeExtra(OPEN_TASK)
return task
task
}
return null
}
private fun openTask(filter: Filter?) = lifecycleScope.launch {
val task = getTaskToLoad(filter)
when {
task != null -> onTaskListItemClicked(task)
taskEditFragment == null -> hideDetailFragment()
else -> showDetailFragment()
}
else -> null
}
private fun handleIntent() {
val intent = intent
val openFilter = intent.getFilter
val loadFilter = intent.getFilterString
val openTask = !intent.isFromHistory
&& (intent.hasExtra(OPEN_TASK) || intent.hasExtra(CREATE_TASK))
val tef = taskEditFragment
private fun logIntent(caller: String) {
if (BuildConfig.DEBUG) {
Timber.d(
"""
**********
broughtToFront: ${intent.broughtToFront}
isFromHistory: ${intent.isFromHistory}
flags: ${intent.flagsToString}
OPEN_FILTER: ${openFilter?.let { "${it.title}: $it" }}
LOAD_FILTER: $loadFilter
OPEN_TASK: ${intent.getParcelableExtra<Task>(OPEN_TASK)}
CREATE_TASK: ${intent.hasExtra(CREATE_TASK)}
taskListFragment: ${taskListFragment?.getFilter()?.let { "${it.title}: $it" }}
taskEditFragment: ${taskEditFragment?.editViewModel?.task}
**********"""
Timber.d("""
$caller
**********
broughtToFront: ${intent.broughtToFront}
isFromHistory: ${intent.isFromHistory}
flags: ${intent.flagsToString}
OPEN_FILTER: ${getParcelableExtra(intent, OPEN_FILTER, Filter::class.java)?.let { "${it.title}: $it" }}
LOAD_FILTER: ${intent.getStringExtra(LOAD_FILTER)}
OPEN_TASK: ${getParcelableExtra(intent, OPEN_TASK, Task::class.java)}
CREATE_TASK: ${intent.hasExtra(CREATE_TASK)}
**********""".trimIndent()
)
}
if (!openTask && (openFilter != null || !loadFilter.isNullOrBlank())) {
tef?.let {
lifecycleScope.launch {
it.save()
}
}
}
if (!loadFilter.isNullOrBlank() || openFilter == null && filter == null) {
lifecycleScope.launch {
val filter = if (loadFilter.isNullOrBlank()) {
defaultFilterProvider.getStartupFilter()
} else {
defaultFilterProvider.getFilterFromPreference(loadFilter)
}
clearUi()
if (isSinglePaneLayout) {
if (openTask) {
setFilter(filter)
openTask(filter)
} else {
openTaskListFragment(filter, true)
}
} else {
openTaskListFragment(filter, true)
openTask(filter)
}
}
} else if (openFilter != null) {
clearUi()
if (isSinglePaneLayout) {
if (openTask) {
setFilter(openFilter)
openTask(openFilter)
} else {
openTaskListFragment(openFilter, true)
}
} else {
openTaskListFragment(openFilter, true)
openTask(openFilter)
}
} else {
val existing = taskListFragment
val target = if (existing == null || existing.getFilter() !== filter) {
TaskListFragment.newTaskListFragment(applicationContext, filter)
} else {
existing
}
if (isSinglePaneLayout) {
if (openTask || tef != null) {
openTask(filter)
} else {
openTaskListFragment(filter, false)
}
} else {
openTaskListFragment(target, false)
openTask(filter)
}
}
}
private fun showDetailFragment() {
if (isSinglePaneLayout) {
binding.detail.visibility = View.VISIBLE
binding.master.visibility = View.GONE
private fun handleIntent() {
lifecycleScope.launch {
val filter = intent.getFilter
?: intent.getFilterString?.let { defaultFilterProvider.getFilterFromPreference(it) }
?: viewModel.state.value.filter
val task = getTaskToLoad(filter)
viewModel.setFilter(filter = filter, task = task)
}
}
private fun hideDetailFragment() {
supportFragmentManager
.beginTransaction()
.replace(R.id.detail, newEmptyTaskEditFragment())
.runOnCommit {
if (isSinglePaneLayout) {
binding.master.visibility = View.VISIBLE
binding.detail.visibility = View.GONE
}
}
.commit()
}
private fun setFilter(newFilter: Filter?) {
newFilter?.let {
viewModel.setFilter(it)
applyTheme()
private fun updateSystemBars(filter: Filter) {
with (getFilterColor(filter)) {
applyToNavigationBar(this@MainActivity)
applyTaskDescription(this@MainActivity, filter.title ?: getString(R.string.app_name))
}
}
private fun openTaskListFragment(filter: Filter?, force: Boolean = false) {
openTaskListFragment(TaskListFragment.newTaskListFragment(applicationContext, filter), force)
}
private fun openTaskListFragment(taskListFragment: TaskListFragment, force: Boolean) {
AndroidUtilities.assertMainThread()
if (supportFragmentManager.isDestroyed) {
return
}
val newFilter = taskListFragment.getFilter()
if (!force && filter == newFilter) {
return
}
viewModel.setFilter(newFilter)
applyTheme()
supportFragmentManager
.beginTransaction()
.replace(R.id.master, taskListFragment, FRAG_TAG_TASK_LIST)
.commitNowAllowingStateLoss()
}
private fun applyTheme() {
val filterColor = filterColor
filterColor.applyToNavigationBar(this)
filterColor.applyTaskDescription(this, filter?.title ?: getString(R.string.app_name))
theme.withThemeColor(filterColor).applyToContext(this)
}
private val filterColor: ThemeColor
get() = filter?.tint?.takeIf { it != 0 }
?.let { colorProvider.getThemeColor(it, true) } ?: theme.themeColor
private fun getFilterColor(filter: Filter) =
if (filter.tint != 0)
colorProvider.getThemeColor(filter.tint, true)
else
theme.themeColor
override fun onResume() {
super.onResume()
@ -477,78 +426,35 @@ class MainActivity : AppCompatActivity(), TaskListFragmentCallbackHandler {
}
}
override suspend fun onTaskListItemClicked(task: Task?) {
private suspend fun newTaskEditFragment(task: Task): TaskEditFragment {
AndroidUtilities.assertMainThread()
if (task == null) {
return
}
taskEditFragment?.save(remove = false)
clearUi()
coroutineScope {
val freshTask = async { if (task.isNew) task else taskDao.fetch(task.id) ?: task }
val list = async { defaultFilterProvider.getList(task) }
val location = async { locationDao.getLocation(task, preferences) }
val tags = async { tagDataDao.getTags(task) }
val alarms = async { alarmDao.getAlarms(task) }
val fragment = withContext(Dispatchers.Default) {
return coroutineScope {
withContext(Dispatchers.Default) {
val freshTask = async { if (task.isNew) task else taskDao.fetch(task.id) ?: task }
val list = async { defaultFilterProvider.getList(task) }
val location = async { locationDao.getLocation(task, preferences) }
val tags = async { tagDataDao.getTags(task) }
val alarms = async { alarmDao.getAlarms(task) }
newTaskEditFragment(
freshTask.await(),
list.await(),
location.await(),
tags.await(),
alarms.await(),
freshTask.await(),
list.await(),
location.await(),
tags.await(),
alarms.await(),
)
}
supportFragmentManager.beginTransaction()
.replace(R.id.detail, fragment, TaskEditFragment.TAG_TASKEDIT_FRAGMENT)
.runOnCommit { showDetailFragment() }
.commitNowAllowingStateLoss()
}
}
override fun onNavigationIconClicked() {
hideKeyboard()
viewModel.setDrawerOpen(true)
}
private val taskListFragment: TaskListFragment?
get() = supportFragmentManager.findFragmentByTag(FRAG_TAG_TASK_LIST) as TaskListFragment?
private val taskEditFragment: TaskEditFragment?
get() = supportFragmentManager.findFragmentByTag(TaskEditFragment.TAG_TASKEDIT_FRAGMENT) as TaskEditFragment?
private val isSinglePaneLayout: Boolean
get() = !resources.getBoolean(R.bool.two_pane_layout)
private fun removeTaskEditFragment() {
val removeTask = intent.removeTask
val finishAffinity = intent.finishAffinity
if (finishAffinity || taskListFragment == null) {
finishAffinity()
} else {
if (removeTask && intent.broughtToFront) {
moveTaskToBack(true)
}
hideKeyboard()
hideDetailFragment()
taskListFragment?.let {
setFilter(it.getFilter())
it.loadTaskListContent()
}
}
}
override fun onSupportActionModeStarted(mode: ActionMode) {
super.onSupportActionModeStarted(mode)
actionMode = mode
}
private fun finishActionMode() {
actionMode?.finish()
actionMode = null
}
companion object {
/** For indicating the new list screen should be launched at fragment setup time */
const val OPEN_FILTER = "open_filter" // $NON-NLS-1$
@ -560,6 +466,7 @@ class MainActivity : AppCompatActivity(), TaskListFragmentCallbackHandler {
const val FINISH_AFFINITY = "finish_affinity"
private const val FRAG_TAG_TASK_LIST = "frag_tag_task_list"
private const val FRAG_TAG_WHATS_NEW = "frag_tag_whats_new"
private const val FRAG_TAG_TASK_EDIT = "frag_tag_task_edit"
private const val FLAG_FROM_HISTORY
= Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
const val REQUEST_NEW_LIST = 10100
@ -569,7 +476,7 @@ class MainActivity : AppCompatActivity(), TaskListFragmentCallbackHandler {
get() = if (isFromHistory) {
null
} else {
getParcelableExtra<Filter?>(OPEN_FILTER)?.let {
getParcelableExtra(this, OPEN_FILTER, Filter::class.java)?.let {
removeExtra(OPEN_FILTER)
it
}

@ -1,18 +1,22 @@
package com.todoroo.astrid.activity
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.todoroo.astrid.activity.MainActivity.Companion.LOAD_FILTER
import com.todoroo.astrid.activity.MainActivity.Companion.OPEN_FILTER
import com.todoroo.astrid.api.CaldavFilter
import com.todoroo.astrid.api.CustomFilter
import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.Filter.Companion.NO_COUNT
import com.todoroo.astrid.api.GtasksFilter
import com.todoroo.astrid.api.TagFilter
import com.todoroo.astrid.data.Task
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
@ -21,6 +25,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.tasks.LocalBroadcastManager
import org.tasks.R
import org.tasks.Tasks.Companion.IS_GENERIC
@ -39,8 +44,9 @@ import timber.log.Timber
import javax.inject.Inject
@HiltViewModel
@SuppressLint("StaticFieldLeak")
class MainActivityViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
@ApplicationContext context: Context,
private val defaultFilterProvider: DefaultFilterProvider,
private val filterProvider: FilterProvider,
private val taskDao: TaskDao,
@ -53,12 +59,22 @@ class MainActivityViewModel @Inject constructor(
data class State(
val begForMoney: Boolean = false,
val filter: Filter? = null,
val filter: Filter,
val task: Task? = null,
val drawerOpen: Boolean = false,
val drawerItems: ImmutableList<DrawerItem> = persistentListOf(),
)
private val _state = MutableStateFlow(State())
private val _state = MutableStateFlow(
State(
filter = savedStateHandle.get<Filter>(OPEN_FILTER)
?: savedStateHandle.get<String>(LOAD_FILTER)?.let {
runBlocking { defaultFilterProvider.getFilterFromPreference(it) }
}
?: runBlocking { defaultFilterProvider.getStartupFilter() },
begForMoney = if (IS_GENERIC) !inventory.hasTasksAccount else !inventory.hasPro,
)
)
val state = _state.asStateFlow()
private val refreshReceiver = object : BroadcastReceiver() {
@ -70,10 +86,18 @@ class MainActivityViewModel @Inject constructor(
}
}
fun setFilter(filter: Filter) {
_state.update { it.copy(filter = filter) }
fun setFilter(
filter: Filter,
task: Task? = null,
) {
_state.update {
it.copy(
filter = filter,
task = task,
)
}
updateFilters()
defaultFilterProvider.lastViewedFilter = filter
defaultFilterProvider.setLastViewedFilter(filter)
}
fun setDrawerOpen(open: Boolean) {
@ -83,11 +107,6 @@ class MainActivityViewModel @Inject constructor(
init {
localBroadcastManager.registerRefreshListReceiver(refreshReceiver)
updateFilters()
_state.update {
it.copy(
begForMoney = if (IS_GENERIC) !inventory.hasTasksAccount else !inventory.hasPro
)
}
}
override fun onCleared() {
@ -171,7 +190,10 @@ class MainActivityViewModel @Inject constructor(
caldavDao.setCollapsed(subheader.id, collapsed)
localBroadcastManager.broadcastRefreshList()
}
else -> {}
}
}
}
fun setTask(task: Task?) {
_state.update { it.copy(task = task) }
}
}

@ -35,6 +35,7 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidViewBinding
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.os.BundleCompat
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
@ -139,6 +140,9 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
activity?.recreate()
}
val task: Task?
get() = BundleCompat.getParcelable(requireArguments(), EXTRA_TASK, Task::class.java)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
requireActivity().onBackPressedDispatcher.addCallback(owner = viewLifecycleOwner) {
@ -514,7 +518,6 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
companion object {
const val TAG_TASKEDIT_FRAGMENT = "taskedit_fragment"
const val EXTRA_TASK = "extra_task"
const val EXTRA_LIST = "extra_list"
const val EXTRA_LOCATION = "extra_location"

@ -34,6 +34,7 @@ import androidx.core.view.forEach
import androidx.core.view.isVisible
import androidx.core.view.setMargins
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
@ -105,9 +106,9 @@ import org.tasks.extensions.Context.openUri
import org.tasks.extensions.Context.toast
import org.tasks.extensions.Fragment.safeStartActivityForResult
import org.tasks.extensions.formatNumber
import org.tasks.extensions.hideKeyboard
import org.tasks.extensions.setOnQueryTextListener
import org.tasks.filters.PlaceFilter
import org.tasks.intents.TaskIntents
import org.tasks.preferences.Device
import org.tasks.preferences.Preferences
import org.tasks.sync.SyncAdapters
@ -160,13 +161,13 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
@Inject lateinit var taskEditEventBus: TaskEditEventBus
private val listViewModel: TaskListViewModel by viewModels()
private val mainViewModel: MainActivityViewModel by activityViewModels()
private lateinit var taskAdapter: TaskAdapter
private var recyclerAdapter: DragAndDropRecyclerAdapter? = null
private lateinit var filter: Filter
private lateinit var search: MenuItem
private var mode: ActionMode? = null
lateinit var themeColor: ThemeColor
private lateinit var callbacks: TaskListFragmentCallbackHandler
private lateinit var binding: FragmentTaskListBinding
private val onBackPressed = object : OnBackPressedCallback(false) {
override fun handleOnBackPressed() {
@ -195,10 +196,10 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
val data = result.data ?: return@registerForActivityResult
when (data.action) {
ACTION_DELETED ->
openFilter(BuiltInFilterExposer.getMyTasksFilter(resources))
mainViewModel.setFilter(BuiltInFilterExposer.getMyTasksFilter(resources))
ACTION_RELOAD ->
IntentCompat.getParcelableExtra(data, MainActivity.OPEN_FILTER, Filter::class.java)?.let {
openFilter(it)
mainViewModel.setFilter(it)
}
}
}
@ -227,11 +228,6 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
}
}
override fun onAttach(context: Context) {
super.onAttach(requireContext())
callbacks = activity as TaskListFragmentCallbackHandler
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val selectedTaskIds: List<Long> = taskAdapter.getSelected()
@ -325,7 +321,10 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
(binding.toolbar.layoutParams as AppBarLayout.LayoutParams).scrollFlags = 0
}
toolbar.setOnMenuItemClickListener(this)
toolbar.setNavigationOnClickListener { callbacks.onNavigationIconClicked() }
toolbar.setNavigationOnClickListener {
activity?.hideKeyboard()
mainViewModel.setDrawerOpen(true)
}
setupMenu(toolbar)
childFragmentManager.setFilterPickerResultListener(this) {
val selected = taskAdapter.getSelected()
@ -411,14 +410,6 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
menu.findItem(R.id.menu_clear_completed).isVisible = filter.isWritable
}
private fun openFilter(filter: Filter?) {
if (filter == null) {
startActivity(TaskIntents.getTaskListByIdIntent(context, null))
} else {
startActivity(TaskIntents.getTaskListIntent(context, filter))
}
}
override fun onMenuItemClick(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_voice_add -> {
@ -649,7 +640,7 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
}
private fun onTaskListItemClicked(task: Task?) = lifecycleScope.launch {
callbacks.onTaskListItemClicked(task)
mainViewModel.setTask(task)
}
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
@ -671,7 +662,7 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
}
override fun onQueryTextSubmit(query: String): Boolean {
openFilter(requireContext().createSearchQuery(query.trim()))
mainViewModel.setFilter(requireContext().createSearchQuery(query.trim()))
search.collapseActionView()
return true
}
@ -828,11 +819,6 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
}
}
interface TaskListFragmentCallbackHandler {
suspend fun onTaskListItemClicked(task: Task?)
fun onNavigationIconClicked()
}
val isActionModeActive: Boolean
get() = mode != null
@ -911,8 +897,7 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
override fun onClick(filter: Filter) {
if (!isActionModeActive) {
val context = activity
context?.startActivity(TaskIntents.getTaskListIntent(context, filter))
mainViewModel.setFilter(filter)
}
}
@ -998,12 +983,11 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
private const val FRAG_TAG_DATE_TIME_PICKER = "frag_tag_date_time_picker"
private const val FRAG_TAG_PRIORITY_PICKER = "frag_tag_priority_picker"
private const val REQUEST_TAG_TASKS = 10106
fun newTaskListFragment(context: Context, filter: Filter?): TaskListFragment {
fun newTaskListFragment(filter: Filter): TaskListFragment {
val fragment = TaskListFragment()
val bundle = Bundle()
bundle.putParcelable(
EXTRA_FILTER,
filter ?: BuiltInFilterExposer.getMyTasksFilter(context.resources))
bundle.putParcelable(EXTRA_FILTER, filter)
fragment.arguments = bundle
return fragment
}

@ -42,6 +42,10 @@ object Context {
val Context.isNightMode: Boolean
get() = nightMode == Configuration.UI_MODE_NIGHT_YES
@Deprecated("Not supposed to use this")
val Context.isSinglePaneLayout: Boolean
get() = !resources.getBoolean(R.bool.two_pane_layout)
fun Context.openUri(resId: Int, vararg formatArgs: Any) = openUri(getString(resId, formatArgs))
fun Context.openUri(url: String?) =

@ -41,10 +41,6 @@ class DefaultFilterProvider @Inject constructor(
@Deprecated("use coroutines") get() = runBlocking { getFilterFromPreference(R.string.p_dashclock_filter) }
set(filter) = setFilterPreference(filter, R.string.p_dashclock_filter)
var lastViewedFilter: Filter
@Deprecated("use coroutines") get() = runBlocking { getFilterFromPreference(R.string.p_last_viewed_list) }
set(filter) = setFilterPreference(filter, R.string.p_last_viewed_list)
var defaultList: Filter
@Deprecated("use coroutines") get() = runBlocking { getDefaultList() }
set(filter) = setFilterPreference(filter, R.string.p_default_list)
@ -62,6 +58,8 @@ class DefaultFilterProvider @Inject constructor(
?.takeIf { it.isWritable }
?: getAnyList()
fun setLastViewedFilter(filter: Filter) = setFilterPreference(filter, R.string.p_last_viewed_list)
private suspend fun getLastViewedFilter() = getFilterFromPreference(R.string.p_last_viewed_list)
suspend fun getDefaultOpenFilter() = getFilterFromPreference(R.string.p_default_open_filter)

@ -1,12 +1,10 @@
package org.tasks.ui
import com.todoroo.astrid.data.Task
import kotlinx.coroutines.flow.MutableSharedFlow
typealias MainActivityEventBus = MutableSharedFlow<MainActivityEvent>
sealed interface MainActivityEvent {
data class OpenTask(val task: Task) : MainActivityEvent
object ClearTaskEditFragment : MainActivityEvent
data object ClearTaskEditFragment : MainActivityEvent
}

@ -5,12 +5,14 @@ import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.google.android.material.composethemeadapter.MdcTheme
import com.todoroo.andlib.sql.Criterion
import com.todoroo.andlib.sql.QueryTemplate
import com.todoroo.andlib.utility.DateUtilities.now
import com.todoroo.astrid.activity.MainActivityViewModel
import com.todoroo.astrid.api.FilterImpl
import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task
@ -36,11 +38,11 @@ class SubtaskControlSet : TaskEditControlFragment() {
@Inject lateinit var taskDao: TaskDao
@Inject lateinit var checkBoxProvider: CheckBoxProvider
@Inject lateinit var chipProvider: ChipProvider
@Inject lateinit var eventBus: MainActivityEventBus
@Inject lateinit var colorProvider: ColorProvider
@Inject lateinit var preferences: Preferences
private lateinit var listViewModel: TaskListViewModel
private val mainViewModel: MainActivityViewModel by activityViewModels()
override fun createView(savedInstanceState: Bundle?) {
viewModel.task.takeIf { it.id > 0 }?.let {
@ -92,7 +94,7 @@ class SubtaskControlSet : TaskEditControlFragment() {
}
private fun openSubtask(task: Task) = lifecycleScope.launch {
eventBus.emit(MainActivityEvent.OpenTask(task))
mainViewModel.setTask(task)
}
private fun toggleSubtask(taskId: Long, collapsed: Boolean) = lifecycleScope.launch {

@ -139,7 +139,6 @@ unstable class MainActivity {
unstable var defaultFilterProvider: DefaultFilterProvider
unstable var theme: Theme
unstable var taskDao: TaskDao
unstable var localBroadcastManager: LocalBroadcastManager
unstable var taskCreator: TaskCreator
unstable var inventory: Inventory
unstable var colorProvider: ColorProvider
@ -156,12 +155,13 @@ unstable class MainActivity {
unstable val settingsRequest: ActivityResultLauncher<@[FlexibleNullability] Intent?>
<runtime stability> = Unstable
}
stable class State {
unstable class State {
stable val begForMoney: Boolean
runtime val filter: Filter?
runtime val filter: Filter
unstable val task: Task?
stable val drawerOpen: Boolean
runtime val drawerItems: ImmutableList<DrawerItem>
<runtime stability> =
<runtime stability> = Unstable
}
unstable class MainActivityViewModel {
unstable val defaultFilterProvider: DefaultFilterProvider
@ -231,13 +231,13 @@ unstable class TaskListFragment {
unstable var taskListEventBus: MutableSharedFlow<TaskListEvent>{ org.tasks.ui.TaskListEventBus }
unstable var taskEditEventBus: MutableSharedFlow<TaskEditEvent>{ org.tasks.ui.TaskEditEventBus }
unstable val listViewModel$delegate: Lazy<TaskListViewModel>
unstable val mainViewModel$delegate: Lazy<MainActivityViewModel>
unstable var taskAdapter: TaskAdapter
unstable var recyclerAdapter: DragAndDropRecyclerAdapter?
runtime var filter: Filter
unstable var search: MenuItem
unstable var mode: ActionMode?
unstable var themeColor: ThemeColor
runtime var callbacks: TaskListFragmentCallbackHandler
unstable var binding: FragmentTaskListBinding
stable val onBackPressed: <no name provided>
unstable val sortRequest: ActivityResultLauncher<@[FlexibleNullability] Intent?>
@ -3071,10 +3071,6 @@ unstable class LocationControlSet {
unstable var permissionChecker: PermissionChecker
<runtime stability> = Unstable
}
unstable class OpenTask {
unstable val task: Task
<runtime stability> = Unstable
}
stable class ClearTaskEditFragment {
<runtime stability> = Stable
}
@ -3086,10 +3082,10 @@ unstable class SubtaskControlSet {
unstable var taskDao: TaskDao
unstable var checkBoxProvider: CheckBoxProvider
unstable var chipProvider: ChipProvider
unstable var eventBus: MutableSharedFlow<MainActivityEvent>{ org.tasks.ui.MainActivityEventBus }
unstable var colorProvider: ColorProvider
unstable var preferences: Preferences
unstable var listViewModel: TaskListViewModel
unstable val mainViewModel$delegate: Lazy<MainActivityViewModel>
<runtime stability> = Unstable
}
unstable class TaskEditControlFragment {

@ -510,6 +510,7 @@ restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun HeaderIte
stable onErrorClick: Function0<Unit>
)
restartable skippable scheme("[androidx.compose.ui.UiComposable, [androidx.compose.ui.UiComposable]]") fun MenuRow(
stable modifier: Modifier? = @static Companion
stable padding: PaddingValues? = @static PaddingValues(
horizontal = 16 . dp
)

@ -4,19 +4,19 @@
"readonlyComposables": 0,
"totalComposables": 544,
"restartGroups": 531,
"totalGroups": 659,
"totalGroups": 660,
"staticArguments": 802,
"certainArguments": 360,
"knownStableArguments": 5198,
"knownStableArguments": 5201,
"knownUnstableArguments": 150,
"unknownStableArguments": 11,
"totalArguments": 5359,
"totalArguments": 5362,
"markedStableClasses": 2,
"inferredStableClasses": 108,
"inferredStableClasses": 107,
"inferredUnstableClasses": 334,
"inferredUncertainClasses": 1,
"effectivelyStableClasses": 110,
"totalClasses": 445,
"effectivelyStableClasses": 109,
"totalClasses": 444,
"memoizedLambdas": 572,
"singletonLambdas": 195,
"singletonComposableLambdas": 97,

Loading…
Cancel
Save