diff --git a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreenTest.kt b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreenTest.kt index 8ec1e65c4..1cfde328f 100644 --- a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreenTest.kt +++ b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreenTest.kt @@ -29,6 +29,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import com.example.android.architecture.blueprints.todoapp.HiltTestActivity import com.example.android.architecture.blueprints.todoapp.R +import com.example.android.architecture.blueprints.todoapp.TodoDestinationsArgs.USER_MESSAGE_ARG import com.example.android.architecture.blueprints.todoapp.TodoTheme import com.example.android.architecture.blueprints.todoapp.data.TaskRepository import dagger.hilt.android.testing.HiltAndroidRule @@ -255,12 +256,14 @@ class TasksScreenTest { private fun setContent() { composeTestRule.setContent { + // Creating SavedStateHandle manually since we're not actually in a + // NavHost in this test + val savedStateHandle = SavedStateHandle.createHandle(null, null) + savedStateHandle[USER_MESSAGE_ARG] = R.string.successfully_added_task_message TodoTheme { Surface { TasksScreen( - viewModel = TasksViewModel(repository, SavedStateHandle()), - userMessage = R.string.successfully_added_task_message, - onUserMessageDisplayed = { }, + viewModel = TasksViewModel(repository, savedStateHandle), onAddTask = { }, onTaskClick = { }, openDrawer = { } diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoNavGraph.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoNavGraph.kt index 852256c65..cdca86e84 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoNavGraph.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoNavGraph.kt @@ -67,11 +67,9 @@ fun TodoNavGraph( arguments = listOf( navArgument(USER_MESSAGE_ARG) { type = NavType.IntType; defaultValue = 0 } ) - ) { entry -> + ) { AppModalDrawer(drawerState, currentRoute, navActions) { TasksScreen( - userMessage = entry.arguments?.getInt(USER_MESSAGE_ARG)!!, - onUserMessageDisplayed = { entry.arguments?.putInt(USER_MESSAGE_ARG, 0) }, onAddTask = { navActions.navigateToAddEditTask(R.string.add_task, null) }, onTaskClick = { task -> navActions.navigateToTaskDetail(task.id) }, openDrawer = { coroutineScope.launch { drawerState.open() } } diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreen.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreen.kt index 395865d0a..613f85edd 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreen.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreen.kt @@ -44,7 +44,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource @@ -66,10 +65,8 @@ import com.example.android.architecture.blueprints.todoapp.util.TasksTopAppBar @Composable fun TasksScreen( - @StringRes userMessage: Int, onAddTask: () -> Unit, onTaskClick: (Task) -> Unit, - onUserMessageDisplayed: () -> Unit, openDrawer: () -> Unit, modifier: Modifier = Modifier, viewModel: TasksViewModel = hiltViewModel(), @@ -95,6 +92,7 @@ fun TasksScreen( } ) { paddingValues -> val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val userMessageResultCode by viewModel.userMessageResultCode.collectAsStateWithLifecycle() TasksContent( loading = uiState.isLoading, @@ -118,11 +116,9 @@ fun TasksScreen( } // Check if there's a userMessage to show to the user - val currentOnUserMessageDisplayed by rememberUpdatedState(onUserMessageDisplayed) - LaunchedEffect(userMessage) { - if (userMessage != 0) { - viewModel.showEditResultMessage(userMessage) - currentOnUserMessageDisplayed() + LaunchedEffect(userMessageResultCode) { + if (userMessageResultCode != 0) { + viewModel.showEditResultMessage(userMessageResultCode) } } } diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModel.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModel.kt index f95b2d273..72c5e0663 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModel.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModel.kt @@ -23,6 +23,7 @@ import com.example.android.architecture.blueprints.todoapp.ADD_EDIT_RESULT_OK import com.example.android.architecture.blueprints.todoapp.DELETE_RESULT_OK import com.example.android.architecture.blueprints.todoapp.EDIT_RESULT_OK import com.example.android.architecture.blueprints.todoapp.R +import com.example.android.architecture.blueprints.todoapp.TodoDestinationsArgs.USER_MESSAGE_ARG import com.example.android.architecture.blueprints.todoapp.data.Task import com.example.android.architecture.blueprints.todoapp.data.TaskRepository import com.example.android.architecture.blueprints.todoapp.tasks.TasksFilterType.ACTIVE_TASKS @@ -60,6 +61,8 @@ class TasksViewModel @Inject constructor( private val savedStateHandle: SavedStateHandle ) : ViewModel() { + var userMessageResultCode = savedStateHandle.getStateFlow(USER_MESSAGE_ARG, 0) + private val _savedFilterType = savedStateHandle.getStateFlow(TASKS_FILTER_SAVED_STATE_KEY, ALL_TASKS) @@ -131,6 +134,7 @@ class TasksViewModel @Inject constructor( fun snackbarMessageShown() { _userMessage.value = null + savedStateHandle[USER_MESSAGE_ARG] = 0 } private fun showSnackbarMessage(message: Int) { diff --git a/app/src/test/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModelTest.kt b/app/src/test/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModelTest.kt index 97cc75c08..daa84e561 100644 --- a/app/src/test/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModelTest.kt +++ b/app/src/test/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModelTest.kt @@ -192,6 +192,22 @@ class TasksViewModelTest { .isEqualTo(R.string.successfully_deleted_task_message) } + @Test + fun snackbarMessageShownOnlyOnce() = runTest { + // When a snackbar message is set + tasksViewModel.showEditResultMessage(DELETE_RESULT_OK) + + // The snackbar is updated + assertThat(tasksViewModel.uiState.first().userMessage) + .isEqualTo(R.string.successfully_deleted_task_message) + + // When the UI has displayed the message + tasksViewModel.snackbarMessageShown() + + // The snackbar is cleared + assertThat(tasksViewModel.uiState.first().userMessage).isEqualTo(null) + } + @Test fun completeTask_dataAndSnackbarUpdated() = runTest { // With a repository that has an active task