From 1ac39cc6bf35302186a9bb0bb90b6da2d25dce85 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Mon, 22 Dec 2025 17:37:04 -0600 Subject: [PATCH] Restore task edit state if activity is lost --- .../astrid/activity/MainActivityViewModel.kt | 9 ++++- .../org/tasks/ui/TaskEditControlFragment.kt | 5 ++- .../java/org/tasks/ui/TaskEditViewModel.kt | 34 ++++++++++++++----- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/todoroo/astrid/activity/MainActivityViewModel.kt b/app/src/main/java/com/todoroo/astrid/activity/MainActivityViewModel.kt index 460e2f4e0..c6211db22 100644 --- a/app/src/main/java/com/todoroo/astrid/activity/MainActivityViewModel.kt +++ b/app/src/main/java/com/todoroo/astrid/activity/MainActivityViewModel.kt @@ -50,7 +50,7 @@ import javax.inject.Inject @HiltViewModel class MainActivityViewModel @Inject constructor( - savedStateHandle: SavedStateHandle, + private val savedStateHandle: SavedStateHandle, private val defaultFilterProvider: DefaultFilterProvider, private val filterProvider: FilterProvider, private val taskDao: TaskDao, @@ -81,10 +81,15 @@ class MainActivityViewModel @Inject constructor( } ?: runBlocking { defaultFilterProvider.getStartupFilter() }, begForMoney = if (IS_GENERIC) !inventory.hasTasksAccount else !inventory.hasPro, + task = savedStateHandle.get(EXTRA_TASK), ) ) val state = _state.asStateFlow() + companion object { + private const val EXTRA_TASK = "extra_task" + } + val accountExists: Flow get() = caldavDao.watchAccountExists() @@ -107,6 +112,7 @@ class MainActivityViewModel @Inject constructor( if (filter == _state.value.filter && task == null) { return } + savedStateHandle[EXTRA_TASK] = task _state.update { it.copy( filter = filter, @@ -226,6 +232,7 @@ class MainActivityViewModel @Inject constructor( } fun setTask(task: Task?) { + savedStateHandle[EXTRA_TASK] = task _state.update { it.copy(task = task) } } diff --git a/app/src/main/java/org/tasks/ui/TaskEditControlFragment.kt b/app/src/main/java/org/tasks/ui/TaskEditControlFragment.kt index 779879532..ad372f6ae 100644 --- a/app/src/main/java/org/tasks/ui/TaskEditControlFragment.kt +++ b/app/src/main/java/org/tasks/ui/TaskEditControlFragment.kt @@ -5,18 +5,17 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.compose.runtime.Composable import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import androidx.fragment.compose.content -import androidx.hilt.navigation.compose.hiltViewModel abstract class TaskEditControlFragment : Fragment() { - lateinit var viewModel: TaskEditViewModel + protected val viewModel: TaskEditViewModel by viewModels({ requireParentFragment() }) override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ) = content { - viewModel = hiltViewModel(viewModelStoreOwner = requireParentFragment()) Content() } diff --git a/app/src/main/java/org/tasks/ui/TaskEditViewModel.kt b/app/src/main/java/org/tasks/ui/TaskEditViewModel.kt index 6d3729b80..39c90c075 100644 --- a/app/src/main/java/org/tasks/ui/TaskEditViewModel.kt +++ b/app/src/main/java/org/tasks/ui/TaskEditViewModel.kt @@ -87,8 +87,8 @@ import javax.inject.Inject @HiltViewModel class TaskEditViewModel @Inject constructor( - @ApplicationContext private val context: Context, - savedStateHandle: SavedStateHandle, + @param:ApplicationContext private val context: Context, + private val savedStateHandle: SavedStateHandle, private val taskDao: TaskDao, private val taskDeleter: TaskDeleter, private val timerPlugin: TimerPlugin, @@ -116,9 +116,24 @@ class TaskEditViewModel @Inject constructor( private val resources = context.resources private var cleared = false - private val task: Task = savedStateHandle.get(TaskEditFragment.EXTRA_TASK) - ?.apply { notes = notes?.stripCarriageReturns() } // copying here broke tests 🙄 - ?: throw IllegalArgumentException("task is null") + private val task: Task = run { + val argTask = savedStateHandle.get(TaskEditFragment.EXTRA_TASK) + ?: throw IllegalArgumentException("task is null") + + val wasRecreated = savedStateHandle.contains(EXTRA_WAS_INIT) + .also { savedStateHandle[EXTRA_WAS_INIT] = true } + if (wasRecreated) { + runBlocking { + if (argTask.isNew) { + taskDao.fetch(argTask.uuid) + } else { + taskDao.fetch(argTask.id) + } + } ?: argTask + } else { + argTask + } + }.apply { notes = notes?.stripCarriageReturns() } // copying here broke tests 🙄 private val _originalState = MutableStateFlow( TaskEditViewState( @@ -364,12 +379,11 @@ class TaskEditViewModel @Inject constructor( taskDao.createNew(subtask) alarmDao.insert(subtask.getDefaultAlarms()) firebase?.addTask("subtasks") - val filter = selectedList when { - filter.isGoogleTasks -> { + selectedList.isGoogleTasks -> { val googleTask = CaldavTask( task = subtask.id, - calendar = filter.uuid, + calendar = selectedList.uuid, remoteId = null, ) subtask.parent = task.id @@ -595,7 +609,7 @@ class TaskEditViewModel @Inject constructor( val attachments = async { taskAttachmentDao .getAttachments(task.id) - .filter { FileHelper.fileExists(context, Uri.parse(it.uri)) } + .filter { FileHelper.fileExists(context, it.uri.toUri()) } .toPersistentSet() } val alarms = async { @@ -630,6 +644,8 @@ class TaskEditViewModel @Inject constructor( } companion object { + private const val EXTRA_WAS_INIT = "extra_was_init" + // one spark tasks for windows adds these fun String?.stripCarriageReturns(): String? = this?.replace("\\r\\n?".toRegex(), "\n")