diff --git a/app/src/androidTest/java/org/tasks/ui/editviewmodel/BaseTaskEditViewModelTest.kt b/app/src/androidTest/java/org/tasks/ui/editviewmodel/BaseTaskEditViewModelTest.kt index dc19435a4..3ef4ed8c8 100644 --- a/app/src/androidTest/java/org/tasks/ui/editviewmodel/BaseTaskEditViewModelTest.kt +++ b/app/src/androidTest/java/org/tasks/ui/editviewmodel/BaseTaskEditViewModelTest.kt @@ -52,6 +52,10 @@ open class BaseTaskEditViewModelTest : InjectingTestCase() { context, SavedStateHandle().apply { set(TaskEditFragment.EXTRA_TASK, task) + set(TaskEditFragment.EXTRA_LIST, defaultFilterProvider.getList(task)) + set(TaskEditFragment.EXTRA_LOCATION, locationDao.getLocation(task, preferences)) + set(TaskEditFragment.EXTRA_TAGS, tagDataDao.getTags(task)) + set(TaskEditFragment.EXTRA_ALARMS, alarmDao.getAlarms(task)) }, taskDao, taskDeleter, @@ -74,7 +78,6 @@ open class BaseTaskEditViewModelTest : InjectingTestCase() { userActivityDao = userActivityDao, taskAttachmentDao = db.taskAttachmentDao, alarmDao = db.alarmDao, - defaultFilterProvider = defaultFilterProvider, ) } diff --git a/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt b/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt index dcc84e0af..105037fdb 100644 --- a/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt +++ b/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt @@ -22,17 +22,22 @@ 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.adapter.SubheaderClickHandler import com.todoroo.astrid.api.Filter import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.data.Task import com.todoroo.astrid.service.TaskCreator 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.R import org.tasks.analytics.Firebase @@ -319,10 +324,25 @@ class MainActivity : AppCompatActivity() { } } - private fun newTaskEditFragment(task: Task): TaskEditFragment { + private suspend fun newTaskEditFragment(task: Task): TaskEditFragment { AndroidUtilities.assertMainThread() clearUi() - return TaskEditFragment.newTaskEditFragment(task) + 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(), + ) + } + } } private val isSinglePaneLayout: Boolean diff --git a/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.kt b/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.kt index 4be2801d0..d3c2da320 100755 --- a/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.kt +++ b/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.kt @@ -45,6 +45,7 @@ import com.google.android.material.appbar.AppBarLayout.Behavior.DragCallback import com.google.android.material.composethemeadapter.MdcTheme import com.todoroo.andlib.utility.AndroidUtilities.atLeastOreoMR1 import com.todoroo.andlib.utility.DateUtilities +import com.todoroo.astrid.api.Filter import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.data.Task import com.todoroo.astrid.files.FilesControlSet @@ -70,6 +71,9 @@ import org.tasks.compose.edit.DueDateRow import org.tasks.compose.edit.InfoRow import org.tasks.compose.edit.ListRow import org.tasks.compose.edit.PriorityRow +import org.tasks.data.Alarm +import org.tasks.data.Location +import org.tasks.data.TagData import org.tasks.data.UserActivityDao import org.tasks.databinding.FragmentTaskEditBinding import org.tasks.databinding.TaskEditCalendarBinding @@ -526,6 +530,10 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener { companion object { const val EXTRA_TASK = "extra_task" + const val EXTRA_LIST = "extra_list" + const val EXTRA_LOCATION = "extra_location" + const val EXTRA_TAGS = "extra_tags" + const val EXTRA_ALARMS = "extra_alarms" private const val FRAG_TAG_GOOGLE_TASK_LIST_SELECTION = "frag_tag_google_task_list_selection" @@ -543,10 +551,18 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener { fun newTaskEditFragment( task: Task, + list: Filter, + location: Location?, + tags: ArrayList, + alarms: ArrayList, ): TaskEditFragment { val taskEditFragment = TaskEditFragment() val arguments = Bundle() arguments.putParcelable(EXTRA_TASK, task) + arguments.putParcelable(EXTRA_LIST, list) + arguments.putParcelable(EXTRA_LOCATION, location) + arguments.putParcelableArrayList(EXTRA_TAGS, tags) + arguments.putParcelableArrayList(EXTRA_ALARMS, alarms) taskEditFragment.arguments = arguments return taskEditFragment } diff --git a/app/src/main/java/org/tasks/ui/TaskEditViewModel.kt b/app/src/main/java/org/tasks/ui/TaskEditViewModel.kt index e8ca5b3da..8d1ade3cd 100644 --- a/app/src/main/java/org/tasks/ui/TaskEditViewModel.kt +++ b/app/src/main/java/org/tasks/ui/TaskEditViewModel.kt @@ -58,7 +58,6 @@ import org.tasks.data.UserActivityDao import org.tasks.date.DateTimeUtils.toDateTime import org.tasks.files.FileHelper import org.tasks.location.GeofenceApi -import org.tasks.preferences.DefaultFilterProvider import org.tasks.preferences.PermissionChecker import org.tasks.preferences.Preferences import org.tasks.time.DateTimeUtils.currentTimeMillis @@ -68,33 +67,32 @@ import javax.inject.Inject @HiltViewModel class TaskEditViewModel @Inject constructor( - @ApplicationContext private val applicationContext: Context, - savedStateHandle: SavedStateHandle, - private val taskDao: TaskDao, - private val taskDeleter: TaskDeleter, - private val timerPlugin: TimerPlugin, - private val permissionChecker: PermissionChecker, - private val calendarEventProvider: CalendarEventProvider, - private val gCalHelper: GCalHelper, - private val taskMover: TaskMover, - private val locationDao: LocationDao, - private val geofenceApi: GeofenceApi, - private val tagDao: TagDao, - private val tagDataDao: TagDataDao, - private val preferences: Preferences, - private val googleTaskDao: GoogleTaskDao, - private val caldavDao: CaldavDao, - private val taskCompleter: TaskCompleter, - private val alarmService: AlarmService, - private val taskListEvents: TaskListEventBus, - private val mainActivityEvents: MainActivityEventBus, - private val firebase: Firebase? = null, - private val userActivityDao: UserActivityDao, - private val alarmDao: AlarmDao, - private val taskAttachmentDao: TaskAttachmentDao, - private val defaultFilterProvider: DefaultFilterProvider, + @ApplicationContext private val context: Context, + savedStateHandle: SavedStateHandle, + private val taskDao: TaskDao, + private val taskDeleter: TaskDeleter, + private val timerPlugin: TimerPlugin, + private val permissionChecker: PermissionChecker, + private val calendarEventProvider: CalendarEventProvider, + private val gCalHelper: GCalHelper, + private val taskMover: TaskMover, + private val locationDao: LocationDao, + private val geofenceApi: GeofenceApi, + private val tagDao: TagDao, + private val tagDataDao: TagDataDao, + private val preferences: Preferences, + private val googleTaskDao: GoogleTaskDao, + private val caldavDao: CaldavDao, + private val taskCompleter: TaskCompleter, + private val alarmService: AlarmService, + private val taskListEvents: TaskListEventBus, + private val mainActivityEvents: MainActivityEventBus, + private val firebase: Firebase? = null, + private val userActivityDao: UserActivityDao, + private val alarmDao: AlarmDao, + private val taskAttachmentDao: TaskAttachmentDao, ) : ViewModel() { - private val resources = applicationContext.resources + private val resources = context.resources private var cleared = false val task: Task = savedStateHandle[TaskEditFragment.EXTRA_TASK]!! @@ -146,19 +144,18 @@ class TaskEditViewModel @Inject constructor( } var selectedCalendar = MutableStateFlow(originalCalendar) - val originalList: Filter = runBlocking { defaultFilterProvider.getList(task) } + val originalList: Filter = savedStateHandle[TaskEditFragment.EXTRA_LIST]!! var selectedList = MutableStateFlow(originalList) - private val originalLocation: Location? = - runBlocking { locationDao.getLocation(task, preferences) } + private var originalLocation: Location? = savedStateHandle[TaskEditFragment.EXTRA_LOCATION] var selectedLocation = MutableStateFlow(originalLocation) - private val originalTags: List = runBlocking { tagDataDao.getTags(task) } + private val originalTags: List = + savedStateHandle.get>(TaskEditFragment.EXTRA_TAGS) ?: emptyList() val selectedTags = MutableStateFlow(ArrayList(originalTags)) - private val originalAttachments: List = - runBlocking { taskAttachmentDao.getAttachments(task.id) } - val selectedAttachments = MutableStateFlow(originalAttachments) + private lateinit var originalAttachments: List + val selectedAttachments = MutableStateFlow(emptyList()) private val originalAlarms: List = if (isNew) { ArrayList().apply { @@ -176,8 +173,9 @@ class TaskEditViewModel @Inject constructor( } } } else { - runBlocking { alarmDao.getAlarms(task) } + savedStateHandle[TaskEditFragment.EXTRA_ALARMS]!! } + var selectedAlarms = MutableStateFlow(originalAlarms) var ringNonstop: Boolean = task.isNotifyModeNonstop @@ -228,7 +226,8 @@ class TaskEditViewModel @Inject constructor( originalList != selectedList.value || originalLocation != selectedLocation.value || originalTags.toHashSet() != selectedTags.value.toHashSet() || - originalAttachments.toHashSet() != selectedAttachments.value.toHashSet() || + (::originalAttachments.isInitialized && + originalAttachments.toHashSet() != selectedAttachments.value.toHashSet()) || newSubtasks.value.isNotEmpty() || getRingFlags() != when { task.isNotifyModeFive -> NOTIFY_MODE_FIVE @@ -363,7 +362,10 @@ class TaskEditViewModel @Inject constructor( task.modificationDate = now() } - if (selectedAttachments.value.toHashSet() != originalAttachments.toHashSet()) { + if ( + this@TaskEditViewModel::originalAttachments.isInitialized && + selectedAttachments.value.toHashSet() != originalAttachments.toHashSet() + ) { originalAttachments .minus(selectedAttachments.value.toSet()) .map { it.remoteId } @@ -428,7 +430,7 @@ class TaskEditViewModel @Inject constructor( if (isNew) { timerPlugin.stopTimer(task) originalAttachments.plus(selectedAttachments.value).toSet().takeIf { it.isNotEmpty() } - ?.onEach { FileHelper.delete(applicationContext, it.uri.toUri()) } + ?.onEach { FileHelper.delete(context, it.uri.toUri()) } ?.let { taskAttachmentDao.delete(it.toList()) } } clear(remove) @@ -468,7 +470,7 @@ class TaskEditViewModel @Inject constructor( fun addComment(message: String?, picture: Uri?) { val userActivity = UserActivity() if (picture != null) { - val output = FileHelper.copyToUri(applicationContext, preferences.attachmentsDirectory!!, picture) + val output = FileHelper.copyToUri(context, preferences.attachmentsDirectory!!, picture) userActivity.setPicture(output) } userActivity.message = message @@ -481,6 +483,15 @@ class TaskEditViewModel @Inject constructor( } } + init { + viewModelScope.launch { + taskAttachmentDao.getAttachments(task.id).let { attachments -> + selectedAttachments.update { attachments } + originalAttachments = attachments + } + } + } + companion object { fun String?.stripCarriageReturns(): String? = this?.replace("\\r\\n?".toRegex(), "\n") }