Add MainActivity and TaskList event buses

pull/1817/head
Alex Baker 2 years ago
parent 51609e54a9
commit ce191d3325

@ -13,7 +13,9 @@ import android.os.Bundle
import android.view.View import android.view.View
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
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.activity.TaskListFragment.TaskListFragmentCallbackHandler
@ -23,7 +25,12 @@ import com.todoroo.astrid.data.Task
import com.todoroo.astrid.service.TaskCreator import com.todoroo.astrid.service.TaskCreator
import com.todoroo.astrid.timers.TimerControlSet.TimerControlSetCallback import com.todoroo.astrid.timers.TimerControlSet.TimerControlSetCallback
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.tasks.BuildConfig import org.tasks.BuildConfig
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.R import org.tasks.R
@ -49,6 +56,8 @@ import org.tasks.themes.ThemeColor
import org.tasks.ui.DeadlineControlSet.DueDateChangeListener import org.tasks.ui.DeadlineControlSet.DueDateChangeListener
import org.tasks.ui.EmptyTaskEditFragment.Companion.newEmptyTaskEditFragment import org.tasks.ui.EmptyTaskEditFragment.Companion.newEmptyTaskEditFragment
import org.tasks.ui.ListFragment.OnListChanged import org.tasks.ui.ListFragment.OnListChanged
import org.tasks.ui.MainActivityEventBus
import org.tasks.ui.MainActivityEvent
import org.tasks.ui.NavigationDrawerFragment import org.tasks.ui.NavigationDrawerFragment
import org.tasks.ui.NavigationDrawerFragment.Companion.newNavigationDrawer import org.tasks.ui.NavigationDrawerFragment.Companion.newNavigationDrawer
import timber.log.Timber import timber.log.Timber
@ -67,6 +76,7 @@ class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandl
@Inject lateinit var locationDao: LocationDao @Inject lateinit var locationDao: LocationDao
@Inject lateinit var tagDataDao: TagDataDao @Inject lateinit var tagDataDao: TagDataDao
@Inject lateinit var alarmDao: AlarmDao @Inject lateinit var alarmDao: AlarmDao
@Inject lateinit var eventBus: MainActivityEventBus
private var currentNightMode = 0 private var currentNightMode = 0
private var currentPro = false private var currentPro = false
@ -88,6 +98,17 @@ class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandl
applyTheme() applyTheme()
} }
handleIntent() handleIntent()
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
eventBus.collect(this@MainActivity::process)
}
}
}
private suspend fun process(event: MainActivityEvent) = when (event) {
is MainActivityEvent.OpenTask ->
onTaskListItemClicked(event.task)
} }
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@ -377,7 +398,7 @@ class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandl
finish() finish()
} }
val taskListFragment: TaskListFragment? private val taskListFragment: TaskListFragment?
get() = supportFragmentManager.findFragmentByTag(FRAG_TAG_TASK_LIST) as TaskListFragment? get() = supportFragmentManager.findFragmentByTag(FRAG_TAG_TASK_LIST) as TaskListFragment?
val taskEditFragment: TaskEditFragment? val taskEditFragment: TaskEditFragment?

@ -50,7 +50,6 @@ import org.tasks.databinding.FragmentTaskEditBinding
import org.tasks.date.DateTimeUtils.newDateTime import org.tasks.date.DateTimeUtils.newDateTime
import org.tasks.dialogs.DialogBuilder import org.tasks.dialogs.DialogBuilder
import org.tasks.dialogs.Linkify import org.tasks.dialogs.Linkify
import org.tasks.extensions.Context.openUri
import org.tasks.files.FileHelper import org.tasks.files.FileHelper
import org.tasks.fragments.TaskEditControlSetFragmentManager import org.tasks.fragments.TaskEditControlSetFragmentManager
import org.tasks.markdown.MarkdownProvider import org.tasks.markdown.MarkdownProvider
@ -265,22 +264,7 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
return model return model
} }
/** Save task model from values in UI components */ suspend fun save() = editViewModel.save()
suspend fun save() = withContext(NonCancellable) {
val tlf = (activity as MainActivity?)?.taskListFragment
val saved = editViewModel.save()
if (saved && editViewModel.isNew) {
tlf?.let { taskListFragment ->
val model = editViewModel.task!!
taskListFragment.onTaskCreated(model.uuid)
if (!isNullOrEmpty(model.calendarURI)) {
taskListFragment.makeSnackbar(R.string.calendar_event_created, model.title)
?.setAction(R.string.action_open) { context.openUri(model.calendarURI) }
?.show()
}
}
}
}
/* /*
* ====================================================================== * ======================================================================

@ -30,7 +30,9 @@ 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.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.paging.PagedList import androidx.paging.PagedList
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -67,6 +69,7 @@ import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
@ -88,6 +91,7 @@ import org.tasks.db.SuspendDbUtils.chunkedMap
import org.tasks.dialogs.DateTimePicker.Companion.newDateTimePicker import org.tasks.dialogs.DateTimePicker.Companion.newDateTimePicker
import org.tasks.dialogs.DialogBuilder import org.tasks.dialogs.DialogBuilder
import org.tasks.dialogs.SortDialog import org.tasks.dialogs.SortDialog
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.setOnQueryTextListener import org.tasks.extensions.setOnQueryTextListener
@ -106,6 +110,8 @@ import org.tasks.tasklist.TaskViewHolder
import org.tasks.tasklist.ViewHolderFactory import org.tasks.tasklist.ViewHolderFactory
import org.tasks.themes.ColorProvider import org.tasks.themes.ColorProvider
import org.tasks.themes.ThemeColor import org.tasks.themes.ThemeColor
import org.tasks.ui.TaskListEventBus
import org.tasks.ui.TaskListEvent
import org.tasks.ui.TaskListViewModel import org.tasks.ui.TaskListViewModel
import java.time.format.FormatStyle import java.time.format.FormatStyle
import javax.inject.Inject import javax.inject.Inject
@ -141,6 +147,7 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
@Inject lateinit var locale: Locale @Inject lateinit var locale: Locale
@Inject lateinit var firebase: Firebase @Inject lateinit var firebase: Firebase
@Inject lateinit var repeatTaskHelper: RepeatTaskHelper @Inject lateinit var repeatTaskHelper: RepeatTaskHelper
@Inject lateinit var eventBus: TaskListEventBus
private lateinit var swipeRefreshLayout: SwipeRefreshLayout private lateinit var swipeRefreshLayout: SwipeRefreshLayout
private lateinit var emptyRefreshLayout: SwipeRefreshLayout private lateinit var emptyRefreshLayout: SwipeRefreshLayout
@ -159,6 +166,15 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
private lateinit var callbacks: TaskListFragmentCallbackHandler private lateinit var callbacks: TaskListFragmentCallbackHandler
private lateinit var binding: FragmentTaskListBinding private lateinit var binding: FragmentTaskListBinding
private fun process(event: TaskListEvent) = when (event) {
is TaskListEvent.TaskCreated ->
onTaskCreated(event.uuid)
is TaskListEvent.CalendarEventCreated ->
makeSnackbar(R.string.calendar_event_created, event.title)
?.setAction(R.string.action_open) { context?.openUri(event.uri) }
?.show()
}
override fun onRefresh() { override fun onRefresh() {
syncAdapters.sync(true) syncAdapters.sync(true)
lifecycleScope.launch { lifecycleScope.launch {
@ -263,6 +279,13 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
toolbar.setOnMenuItemClickListener(this) toolbar.setOnMenuItemClickListener(this)
toolbar.setNavigationOnClickListener { callbacks.onNavigationIconClicked() } toolbar.setNavigationOnClickListener { callbacks.onNavigationIconClicked() }
setupMenu(toolbar) setupMenu(toolbar)
lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
eventBus.collect(this@TaskListFragment::process)
}
}
return binding.root return binding.root
} }
@ -500,7 +523,7 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
refresh() refresh()
} }
fun makeSnackbar(@StringRes res: Int, vararg args: Any?): Snackbar? { private fun makeSnackbar(@StringRes res: Int, vararg args: Any?): Snackbar? {
return makeSnackbar(getString(res, *args)) return makeSnackbar(getString(res, *args))
} }

@ -0,0 +1,28 @@
package org.tasks.injection
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityRetainedComponent
import dagger.hilt.android.scopes.ActivityRetainedScoped
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import org.tasks.ui.MainActivityEventBus
import org.tasks.ui.TaskListEventBus
@Module
@InstallIn(ActivityRetainedComponent::class)
class ActivityRetainedModule {
@Provides
@ActivityRetainedScoped
fun getTaskListBus(): TaskListEventBus = makeFlow()
@Provides
@ActivityRetainedScoped
fun getMainActivityBus(): MainActivityEventBus = makeFlow()
private fun <T> makeFlow() = MutableSharedFlow<T>(
extraBufferCapacity = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
}

@ -0,0 +1,11 @@
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
}

@ -24,7 +24,6 @@ import com.todoroo.andlib.sql.Criterion
import com.todoroo.andlib.sql.Join import com.todoroo.andlib.sql.Join
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.MainActivity
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.GtasksFilter import com.todoroo.astrid.api.GtasksFilter
import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.dao.TaskDao
@ -60,6 +59,7 @@ class SubtaskControlSet : TaskEditControlFragment(), SubtaskViewHolder.Callbacks
@Inject lateinit var locale: Locale @Inject lateinit var locale: Locale
@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
private val listViewModel: TaskListViewModel by viewModels() private val listViewModel: TaskListViewModel by viewModels()
private val refreshReceiver = RefreshReceiver() private val refreshReceiver = RefreshReceiver()
@ -197,7 +197,9 @@ class SubtaskControlSet : TaskEditControlFragment(), SubtaskViewHolder.Callbacks
} }
override fun openSubtask(task: Task) { override fun openSubtask(task: Task) {
(activity as MainActivity).taskListFragment?.onTaskListItemClicked(task) lifecycleScope.launch {
eventBus.emit(MainActivityEvent.OpenTask(task))
}
} }
override fun toggleSubtask(taskId: Long, collapsed: Boolean) { override fun toggleSubtask(taskId: Long, collapsed: Boolean) {

@ -28,6 +28,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import net.fortuna.ical4j.model.Recur import net.fortuna.ical4j.model.Recur
import org.tasks.Event import org.tasks.Event
import org.tasks.R import org.tasks.R
@ -79,7 +80,8 @@ class TaskEditViewModel @Inject constructor(
private val googleTaskDao: GoogleTaskDao, private val googleTaskDao: GoogleTaskDao,
private val caldavDao: CaldavDao, private val caldavDao: CaldavDao,
private val taskCompleter: TaskCompleter, private val taskCompleter: TaskCompleter,
private val alarmService: AlarmService private val alarmService: AlarmService,
private val taskListEvents: TaskListEventBus,
) : ViewModel() { ) : ViewModel() {
val cleared = MutableLiveData<Event<Boolean>>() val cleared = MutableLiveData<Event<Boolean>>()
@ -320,13 +322,13 @@ class TaskEditViewModel @Inject constructor(
fun cleared() = cleared.value?.value == true fun cleared() = cleared.value?.value == true
@MainThread @MainThread
suspend fun save(): Boolean { suspend fun save() = withContext(NonCancellable) {
if (cleared()) { if (cleared()) {
return false return@withContext
} }
if (!hasChanges()) { if (!hasChanges()) {
discard() discard()
return false return@withContext
} }
clear() clear()
task.title = if (title.isNullOrBlank()) context.getString(R.string.no_title) else title task.title = if (title.isNullOrBlank()) context.getString(R.string.no_title) else title
@ -428,7 +430,13 @@ class TaskEditViewModel @Inject constructor(
taskCompleter.setComplete(task, completed!!) taskCompleter.setComplete(task, completed!!)
} }
return true if (isNew) {
val model = task
taskListEvents.emit(TaskListEvent.TaskCreated(model.uuid))
model.calendarURI?.takeIf { it.isNotBlank() }?.let {
taskListEvents.emit(TaskListEvent.CalendarEventCreated(model.title, it))
}
}
} }
private suspend fun applyCalendarChanges() { private suspend fun applyCalendarChanges() {
@ -478,7 +486,7 @@ class TaskEditViewModel @Inject constructor(
override fun onCleared() { override fun onCleared() {
cleared.value.let { cleared.value.let {
if (it == null || !it.value) { if (it == null || !it.value) {
runBlocking(NonCancellable) { runBlocking {
save() save()
} }
} }

@ -0,0 +1,10 @@
package org.tasks.ui
import kotlinx.coroutines.flow.MutableSharedFlow
typealias TaskListEventBus = MutableSharedFlow<TaskListEvent>
sealed interface TaskListEvent {
data class TaskCreated(val uuid: String) : TaskListEvent
data class CalendarEventCreated(val title: String?, val uri: String) : TaskListEvent
}
Loading…
Cancel
Save