Add task to MainActivityViewModel state

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

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

@ -1,18 +1,22 @@
package com.todoroo.astrid.activity package com.todoroo.astrid.activity
import android.annotation.SuppressLint
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope 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.CaldavFilter
import com.todoroo.astrid.api.CustomFilter import com.todoroo.astrid.api.CustomFilter
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.Filter.Companion.NO_COUNT import com.todoroo.astrid.api.Filter.Companion.NO_COUNT
import com.todoroo.astrid.api.GtasksFilter import com.todoroo.astrid.api.GtasksFilter
import com.todoroo.astrid.api.TagFilter import com.todoroo.astrid.api.TagFilter
import com.todoroo.astrid.data.Task
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList import kotlinx.collections.immutable.toPersistentList
@ -21,6 +25,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.R import org.tasks.R
import org.tasks.Tasks.Companion.IS_GENERIC import org.tasks.Tasks.Companion.IS_GENERIC
@ -39,8 +44,9 @@ import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@SuppressLint("StaticFieldLeak")
class MainActivityViewModel @Inject constructor( class MainActivityViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
@ApplicationContext context: Context,
private val defaultFilterProvider: DefaultFilterProvider, private val defaultFilterProvider: DefaultFilterProvider,
private val filterProvider: FilterProvider, private val filterProvider: FilterProvider,
private val taskDao: TaskDao, private val taskDao: TaskDao,
@ -53,12 +59,22 @@ class MainActivityViewModel @Inject constructor(
data class State( data class State(
val begForMoney: Boolean = false, val begForMoney: Boolean = false,
val filter: Filter? = null, val filter: Filter,
val task: Task? = null,
val drawerOpen: Boolean = false, val drawerOpen: Boolean = false,
val drawerItems: ImmutableList<DrawerItem> = persistentListOf(), 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() val state = _state.asStateFlow()
private val refreshReceiver = object : BroadcastReceiver() { private val refreshReceiver = object : BroadcastReceiver() {
@ -70,10 +86,18 @@ class MainActivityViewModel @Inject constructor(
} }
} }
fun setFilter(filter: Filter) { fun setFilter(
_state.update { it.copy(filter = filter) } filter: Filter,
task: Task? = null,
) {
_state.update {
it.copy(
filter = filter,
task = task,
)
}
updateFilters() updateFilters()
defaultFilterProvider.lastViewedFilter = filter defaultFilterProvider.setLastViewedFilter(filter)
} }
fun setDrawerOpen(open: Boolean) { fun setDrawerOpen(open: Boolean) {
@ -83,11 +107,6 @@ class MainActivityViewModel @Inject constructor(
init { init {
localBroadcastManager.registerRefreshListReceiver(refreshReceiver) localBroadcastManager.registerRefreshListReceiver(refreshReceiver)
updateFilters() updateFilters()
_state.update {
it.copy(
begForMoney = if (IS_GENERIC) !inventory.hasTasksAccount else !inventory.hasPro
)
}
} }
override fun onCleared() { override fun onCleared() {
@ -171,7 +190,10 @@ class MainActivityViewModel @Inject constructor(
caldavDao.setCollapsed(subheader.id, collapsed) caldavDao.setCollapsed(subheader.id, collapsed)
localBroadcastManager.broadcastRefreshList() 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.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidViewBinding import androidx.compose.ui.viewinterop.AndroidViewBinding
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.os.BundleCompat
import androidx.core.widget.addTextChangedListener import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
@ -139,6 +140,9 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
activity?.recreate() activity?.recreate()
} }
val task: Task?
get() = BundleCompat.getParcelable(requireArguments(), EXTRA_TASK, Task::class.java)
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
requireActivity().onBackPressedDispatcher.addCallback(owner = viewLifecycleOwner) { requireActivity().onBackPressedDispatcher.addCallback(owner = viewLifecycleOwner) {
@ -514,7 +518,6 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
} }
companion object { companion object {
const val TAG_TASKEDIT_FRAGMENT = "taskedit_fragment"
const val EXTRA_TASK = "extra_task" const val EXTRA_TASK = "extra_task"
const val EXTRA_LIST = "extra_list" const val EXTRA_LIST = "extra_list"
const val EXTRA_LOCATION = "extra_location" const val EXTRA_LOCATION = "extra_location"

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

@ -42,6 +42,10 @@ object Context {
val Context.isNightMode: Boolean val Context.isNightMode: Boolean
get() = nightMode == Configuration.UI_MODE_NIGHT_YES 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(resId: Int, vararg formatArgs: Any) = openUri(getString(resId, formatArgs))
fun Context.openUri(url: String?) = fun Context.openUri(url: String?) =

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

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

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

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

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

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

Loading…
Cancel
Save