Fix navigation issue when navigating back to a deleted list

Some refactoring
This commit is contained in:
Geoffroy Bonneville
2025-10-09 16:43:27 -04:00
parent 7dddc62377
commit 8e78f9b464
7 changed files with 83 additions and 29 deletions

View File

@@ -232,6 +232,18 @@
<option name="screenX" value="1080" /> <option name="screenX" value="1080" />
<option name="screenY" value="2640" /> <option name="screenY" value="2640" />
</PersistentDeviceSelectionData> </PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="36" />
<option name="brand" value="google" />
<option name="codename" value="blazer" />
<option name="id" value="blazer" />
<option name="labId" value="google" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 10 Pro" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2410" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData> <PersistentDeviceSelectionData>
<option name="api" value="32" /> <option name="api" value="32" />
<option name="brand" value="google" /> <option name="brand" value="google" />
@@ -439,6 +451,18 @@
<option name="screenX" value="720" /> <option name="screenX" value="720" />
<option name="screenY" value="1600" /> <option name="screenY" value="1600" />
</PersistentDeviceSelectionData> </PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="36" />
<option name="brand" value="google" />
<option name="codename" value="frankel" />
<option name="id" value="frankel" />
<option name="labId" value="google" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 10" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2424" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData> <PersistentDeviceSelectionData>
<option name="api" value="34" /> <option name="api" value="34" />
<option name="brand" value="samsung" /> <option name="brand" value="samsung" />
@@ -657,6 +681,18 @@
<option name="screenX" value="720" /> <option name="screenX" value="720" />
<option name="screenY" value="1600" /> <option name="screenY" value="1600" />
</PersistentDeviceSelectionData> </PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="36" />
<option name="brand" value="google" />
<option name="codename" value="mustang" />
<option name="id" value="mustang" />
<option name="labId" value="google" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 10 Pro XL" />
<option name="screenDensity" value="390" />
<option name="screenX" value="1080" />
<option name="screenY" value="2404" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData> <PersistentDeviceSelectionData>
<option name="api" value="34" /> <option name="api" value="34" />
<option name="brand" value="samsung" /> <option name="brand" value="samsung" />
@@ -755,6 +791,18 @@
<option name="screenX" value="1080" /> <option name="screenX" value="1080" />
<option name="screenY" value="2340" /> <option name="screenY" value="2340" />
</PersistentDeviceSelectionData> </PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="36" />
<option name="brand" value="google" />
<option name="codename" value="rango" />
<option name="id" value="rango" />
<option name="labId" value="google" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 10 Pro Fold" />
<option name="screenDensity" value="390" />
<option name="screenX" value="2076" />
<option name="screenY" value="2152" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData> <PersistentDeviceSelectionData>
<option name="api" value="30" /> <option name="api" value="30" />
<option name="brand" value="google" /> <option name="brand" value="google" />

View File

@@ -15,7 +15,6 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import com.wismna.geoffroy.donext.domain.model.Task import com.wismna.geoffroy.donext.domain.model.Task
import com.wismna.geoffroy.donext.presentation.viewmodel.DueTodayViewModel import com.wismna.geoffroy.donext.presentation.viewmodel.DueTodayViewModel
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskItemViewModel
@Composable @Composable
fun DueTodayTasksScreen( fun DueTodayTasksScreen(
@@ -41,7 +40,7 @@ fun DueTodayTasksScreen(
items(tasks, key = { it.id!! }) { task -> items(tasks, key = { it.id!! }) { task ->
TaskItemScreen( TaskItemScreen(
modifier = Modifier.animateItem(), modifier = Modifier.animateItem(),
viewModel = TaskItemViewModel(task), task = task,
onTaskClick = { onTaskClick(task) }, onTaskClick = { onTaskClick(task) },
onSwipeLeft = { onSwipeLeft = {
viewModel.updateTaskDone(task.id!!) viewModel.updateTaskDone(task.id!!)

View File

@@ -18,6 +18,7 @@ import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DrawerState import androidx.compose.material3.DrawerState
import androidx.compose.material3.DrawerValue import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
@@ -31,7 +32,10 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberDrawerState import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -60,7 +64,7 @@ fun MainScreen(
val navController = rememberNavController() val navController = rememberNavController()
val drawerState = rememberDrawerState(DrawerValue.Closed) val drawerState = rememberDrawerState(DrawerValue.Closed)
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
// TODO: find a way to get rid of this // TODO: find a way to do this better
val taskViewModel: TaskViewModel = hiltViewModel() val taskViewModel: TaskViewModel = hiltViewModel()
if (viewModel.isLoading) { if (viewModel.isLoading) {
@@ -154,9 +158,13 @@ fun AppContent(
floatingActionButton = { floatingActionButton = {
when (val dest = viewModel.currentDestination) { when (val dest = viewModel.currentDestination) {
is AppDestination.TaskList -> { is AppDestination.TaskList -> {
TaskListFab( ExtendedFloatingActionButton(
taskListId = dest.taskListId, onClick = {
showBottomSheet = { viewModel.showTaskSheet = it } taskViewModel.startNewTask(dest.taskListId)
viewModel.showTaskSheet = true
},
icon = { Icon(Icons.Filled.Add, "Create a task.") },
text = { Text("Create a task") },
) )
} }
else -> null else -> null
@@ -192,7 +200,16 @@ fun AppContent(
type = NavType.LongType type = NavType.LongType
}) })
) { navBackStackEntry -> ) { navBackStackEntry ->
// TODO: when task list has been deleted, we should not navigate to it event if in the stack val taskListId = navBackStackEntry.arguments?.getLong("taskListId") ?: return@composable
val listExists by remember(taskListId, viewModel.destinations) {
derivedStateOf { viewModel.doesListExist(taskListId) }
}
LaunchedEffect(listExists) {
if (!viewModel.doesListExist(taskListId)) {
navController.popBackStack()
}
}
val taskListViewModel: TaskListViewModel = hiltViewModel(navBackStackEntry) val taskListViewModel: TaskListViewModel = hiltViewModel(navBackStackEntry)
TaskListScreen( TaskListScreen(
viewModel = taskListViewModel, viewModel = taskListViewModel,

View File

@@ -31,7 +31,6 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import com.wismna.geoffroy.donext.domain.model.Task import com.wismna.geoffroy.donext.domain.model.Task
import com.wismna.geoffroy.donext.presentation.viewmodel.RecycleBinViewModel import com.wismna.geoffroy.donext.presentation.viewmodel.RecycleBinViewModel
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskItemViewModel
@Composable @Composable
fun RecycleBinScreen( fun RecycleBinScreen(
@@ -77,7 +76,7 @@ fun RecycleBinScreen(
items(items, key = { it.task.id!! }) { item -> items(items, key = { it.task.id!! }) { item ->
TaskItemScreen( TaskItemScreen(
modifier = Modifier.animateItem(), modifier = Modifier.animateItem(),
viewModel = TaskItemViewModel(item.task), task = item.task,
onTaskClick = { onTaskClick(item.task) }, onTaskClick = { onTaskClick(item.task) },
onSwipeLeft = { onSwipeLeft = {
viewModel.restore(item.task.id!!) viewModel.restore(item.task.id!!)

View File

@@ -38,16 +38,18 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.wismna.geoffroy.donext.domain.model.Priority import com.wismna.geoffroy.donext.domain.model.Priority
import com.wismna.geoffroy.donext.domain.model.Task
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskItemViewModel import com.wismna.geoffroy.donext.presentation.viewmodel.TaskItemViewModel
@Composable @Composable
fun TaskItemScreen( fun TaskItemScreen(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: TaskItemViewModel, task: Task,
onTaskClick: (taskId: Long) -> Unit, onTaskClick: (taskId: Long) -> Unit,
onSwipeLeft: () -> Unit, onSwipeLeft: () -> Unit,
onSwipeRight: () -> Unit onSwipeRight: () -> Unit
) { ) {
val viewModel = TaskItemViewModel(task)
// TODO: change this // TODO: change this
val dismissState = rememberSwipeToDismissBoxState( val dismissState = rememberSwipeToDismissBoxState(
confirmValueChange = { confirmValueChange = {

View File

@@ -21,7 +21,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import com.wismna.geoffroy.donext.domain.model.Task import com.wismna.geoffroy.donext.domain.model.Task
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskItemViewModel
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskListViewModel import com.wismna.geoffroy.donext.presentation.viewmodel.TaskListViewModel
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskViewModel import com.wismna.geoffroy.donext.presentation.viewmodel.TaskViewModel
@@ -50,7 +49,7 @@ fun TaskListScreen(
) { task -> ) { task ->
TaskItemScreen( TaskItemScreen(
modifier = Modifier.animateItem(), modifier = Modifier.animateItem(),
viewModel = TaskItemViewModel(task), task = task,
onTaskClick = { onTaskClick(task) }, onTaskClick = { onTaskClick(task) },
onSwipeLeft = { onSwipeLeft = {
viewModel.updateTaskDone(task.id!!, true) viewModel.updateTaskDone(task.id!!, true)
@@ -81,7 +80,7 @@ fun TaskListScreen(
) { task -> ) { task ->
TaskItemScreen( TaskItemScreen(
modifier = Modifier.animateItem(), modifier = Modifier.animateItem(),
viewModel = TaskItemViewModel(task), task = task,
onTaskClick = { onTaskClick(task) }, onTaskClick = { onTaskClick(task) },
onSwipeLeft = { onSwipeLeft = {
viewModel.updateTaskDone(task.id!!, false) viewModel.updateTaskDone(task.id!!, false)
@@ -95,20 +94,4 @@ fun TaskListScreen(
} }
} }
}
@Composable
fun TaskListFab(
taskListId: Long,
viewModel: TaskViewModel = hiltViewModel(),
showBottomSheet: (Boolean) -> Unit = {}
) {
ExtendedFloatingActionButton(
onClick = {
viewModel.startNewTask(taskListId)
showBottomSheet(true)
},
icon = { Icon(Icons.Filled.Add, "Create a task.") },
text = { Text("Create a task") },
)
} }

View File

@@ -61,4 +61,10 @@ class MainViewModel @Inject constructor(
} }
} ?: startDestination } ?: startDestination
} }
fun doesListExist(taskListId: Long): Boolean {
return destinations.any { dest ->
dest is AppDestination.TaskList && dest.taskListId == taskListId
}
}
} }