Skip to content

Commit

Permalink
navigation above NoteDetail
Browse files Browse the repository at this point in the history
  • Loading branch information
softartdev committed Sep 8, 2024
1 parent 002527a commit f7bc03a
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ fun App(
NoteDetail(
noteViewModel = getViewModel(),
noteId = backStackEntry.arguments!!.getLong("noteId"),
navController = navController
)
}
composable(route = AppNavGraph.Settings.name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,8 @@ class RouterImpl : Router {
popUpTo(route) { inclusive = true }
}

override fun popBackStack(route: String, inclusive: Boolean, saveState: Boolean): Boolean =
navController!!.popBackStack(route, inclusive, saveState)

override fun popBackStack() = navController!!.popBackStack()
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.softartdev.notedelight.shared.navigation.AppNavGraph
import com.softartdev.notedelight.shared.presentation.note.NoteResult
import com.softartdev.notedelight.shared.presentation.note.NoteViewModel
import com.softartdev.theme.material3.PreferableMaterialTheme
Expand All @@ -49,18 +46,14 @@ import org.jetbrains.compose.resources.getString
import org.jetbrains.compose.resources.stringResource

@Composable
fun NoteDetail(
noteViewModel: NoteViewModel,
noteId: Long,
navController: NavHostController = rememberNavController()
) {
fun NoteDetail(noteViewModel: NoteViewModel, noteId: Long) {
LaunchedEffect(key1 = noteId, key2 = noteViewModel) {
when (noteId) {
0L -> noteViewModel.createNote()
else -> noteViewModel.loadNote(noteId)
}
}
val noteResultState: State<NoteResult> = noteViewModel.resultStateFlow.collectAsState()
val noteResultState: State<NoteResult> = noteViewModel.stateFlow.collectAsState()
val titleState: MutableState<String> = remember { mutableStateOf("") }
val textState: MutableState<String> = remember { mutableStateOf("") }
val snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }
Expand All @@ -81,9 +74,6 @@ fun NoteDetail(
val noteSaved = getString(Res.string.note_saved) + ": " + noteResult.title
snackbarHostState.showSnackbar(noteSaved)
}
is NoteResult.NavEditTitle -> navController.navigate(
route = "${AppNavGraph.EditTitleDialog.name}/${noteResult.noteId}",
)
is NoteResult.TitleUpdated -> {
titleState.value = noteResult.title
}
Expand All @@ -92,15 +82,7 @@ fun NoteDetail(
)
is NoteResult.Deleted -> {
snackbarHostState.showSnackbar(message = getString(Res.string.note_deleted))
navController.popBackStack(route = AppNavGraph.Main.name, inclusive = false)
}
is NoteResult.CheckSaveChange -> navController.navigate(
route = AppNavGraph.SaveChangesDialog.name
)
is NoteResult.NavBack -> navController.popBackStack()
is NoteResult.Error -> navController.navigate(
route = AppNavGraph.ErrorDialog.argRoute(noteResult.message),
)
}
}
NoteDetailBody(
Expand All @@ -110,10 +92,7 @@ fun NoteDetail(
onBackClick = { noteViewModel.checkSaveChange(titleState.value, textState.value) },
onSaveClick = noteViewModel::saveNote,
onEditClick = noteViewModel::editTitle,
onDeleteClick = {
noteViewModel.subscribeToDeleteNote()
navController.navigate(AppNavGraph.DeleteNoteDialog.name)
},
onDeleteClick = noteViewModel::subscribeToDeleteNote,
showLoading = noteResultState.value == NoteResult.Loading,
)
BackHandler { noteViewModel.checkSaveChange(titleState.value, textState.value) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import app.cash.turbine.test
import com.softartdev.notedelight.shared.date.createLocalDateTime
import com.softartdev.notedelight.shared.db.Note
import com.softartdev.notedelight.shared.db.NoteDAO
import com.softartdev.notedelight.shared.navigation.AppNavGraph
import com.softartdev.notedelight.shared.navigation.Router
import com.softartdev.notedelight.shared.presentation.MainDispatcherRule
import com.softartdev.notedelight.shared.usecase.note.CreateNoteUseCase
import com.softartdev.notedelight.shared.usecase.note.SaveNoteUseCase
Expand All @@ -31,7 +33,8 @@ class NoteViewModelTest {
private val mockNoteDAO = Mockito.mock(NoteDAO::class.java)
private val mockCreateNoteUseCase = Mockito.mock(CreateNoteUseCase::class.java)
private val mockSaveNoteUseCase = Mockito.mock(SaveNoteUseCase::class.java)
private var noteViewModel = NoteViewModel(mockNoteDAO, mockCreateNoteUseCase, mockSaveNoteUseCase)
private val mockRouter = Mockito.mock(Router::class.java)
private var noteViewModel = NoteViewModel(mockNoteDAO, mockCreateNoteUseCase, mockSaveNoteUseCase, mockRouter)

private val id = 1L
private val title: String = "title"
Expand All @@ -47,12 +50,12 @@ class NoteViewModelTest {

@After
fun tearDown() = runTest {
noteViewModel.resetLoadingResult()
noteViewModel.onCleared()
}

@Test
fun createNote() = runTest {
noteViewModel.resultStateFlow.test {
noteViewModel.stateFlow.test {
assertEquals(NoteResult.Loading, awaitItem())

noteViewModel.createNote()
Expand All @@ -64,7 +67,7 @@ class NoteViewModelTest {

@Test
fun loadNote() = runTest {
noteViewModel.resultStateFlow.test {
noteViewModel.stateFlow.test {
assertEquals(NoteResult.Loading, awaitItem())

noteViewModel.loadNote(id)
Expand All @@ -76,7 +79,7 @@ class NoteViewModelTest {

@Test
fun saveNoteEmpty() = runTest {
noteViewModel.resultStateFlow.test {
noteViewModel.stateFlow.test {
assertEquals(NoteResult.Loading, awaitItem())

noteViewModel.saveNote("", "")
Expand All @@ -88,7 +91,7 @@ class NoteViewModelTest {

@Test
fun saveNote() = runTest {
noteViewModel.resultStateFlow.test {
noteViewModel.stateFlow.test {
assertEquals(NoteResult.Loading, awaitItem())

noteViewModel.setIdForTest(id)
Expand All @@ -101,12 +104,12 @@ class NoteViewModelTest {

@Test
fun editTitle() = runTest {
noteViewModel.resultStateFlow.test {
noteViewModel.stateFlow.test {
assertEquals(NoteResult.Loading, awaitItem())

noteViewModel.setIdForTest(id)
noteViewModel.editTitle()
assertEquals(NoteResult.NavEditTitle(id), awaitItem())
Mockito.verify(mockRouter).navigate(route = "${AppNavGraph.EditTitleDialog.name}/$id")

UpdateTitleUseCase.titleChannel.send(title)
assertEquals(NoteResult.TitleUpdated(title), awaitItem())
Expand All @@ -117,7 +120,7 @@ class NoteViewModelTest {

@Test
fun deleteNote() = runTest {
noteViewModel.resultStateFlow.test {
noteViewModel.stateFlow.test {
assertEquals(NoteResult.Loading, awaitItem())

noteViewModel.setIdForTest(id)
Expand All @@ -130,34 +133,34 @@ class NoteViewModelTest {

@Test
fun checkSaveChange() = runTest {
noteViewModel.resultStateFlow.test {
noteViewModel.stateFlow.test {
assertEquals(NoteResult.Loading, awaitItem())

noteViewModel.setIdForTest(id)
Mockito.`when`(mockNoteDAO.load(id)).thenReturn(note.copy(text = "new text"))
noteViewModel.checkSaveChange(title, text)
assertEquals(NoteResult.CheckSaveChange, awaitItem())
Mockito.verify(mockRouter).navigate(route = AppNavGraph.SaveChangesDialog.name)

cancelAndIgnoreRemainingEvents()
}
}

@Test
fun checkSaveChangeNavBack() = runTest {
noteViewModel.resultStateFlow.test {
noteViewModel.stateFlow.test {
assertEquals(NoteResult.Loading, awaitItem())

noteViewModel.setIdForTest(id)
noteViewModel.checkSaveChange(title, text)
assertEquals(NoteResult.NavBack, awaitItem())
Mockito.verify(mockRouter).popBackStack()

cancelAndIgnoreRemainingEvents()
}
}

@Test
fun checkSaveChangeDeleted() = runTest {
noteViewModel.resultStateFlow.test {
noteViewModel.stateFlow.test {
assertEquals(NoteResult.Loading, awaitItem())

noteViewModel.setIdForTest(id)
Expand All @@ -171,33 +174,33 @@ class NoteViewModelTest {

@Test
fun saveNoteAndNavBack() = runTest {
noteViewModel.resultStateFlow.test {
noteViewModel.stateFlow.test {
assertEquals(NoteResult.Loading, awaitItem())

noteViewModel.setIdForTest(id)
noteViewModel.saveNoteAndNavBack(title, text)
assertEquals(NoteResult.NavBack, awaitItem())
Mockito.verify(mockRouter).popBackStack()

cancelAndIgnoreRemainingEvents()
}
}

@Test
fun doNotSaveAndNavBack() = runTest {
noteViewModel.resultStateFlow.test {
noteViewModel.stateFlow.test {
assertEquals(NoteResult.Loading, awaitItem())

noteViewModel.setIdForTest(id)
noteViewModel.doNotSaveAndNavBack()
assertEquals(NoteResult.NavBack, awaitItem())
Mockito.verify(mockRouter).popBackStack()

cancelAndIgnoreRemainingEvents()
}
}

@Test
fun doNotSaveAndNavBackDeleted() = runTest {
noteViewModel.resultStateFlow.test {
noteViewModel.stateFlow.test {
assertEquals(NoteResult.Loading, awaitItem())

noteViewModel.setIdForTest(id)
Expand All @@ -208,9 +211,4 @@ class NoteViewModelTest {
cancelAndIgnoreRemainingEvents()
}
}

@Test
fun errorResult() {
assertEquals(NoteResult.Error(null), noteViewModel.errorResult(Throwable()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ val viewModelModule: Module = module {
viewModelFactory { SplashViewModel(get(), get()) }
viewModelFactory { SignInViewModel(get(), get()) }
viewModelFactory { MainViewModel(get(), get()) }
viewModelFactory { NoteViewModel(get(), get(), get()) }
viewModelFactory { NoteViewModel(get(), get(), get(), get()) }
viewModelFactory { EditTitleViewModel(get(), get()) }
viewModelFactory { SettingsViewModel(get(), get()) }
viewModelFactory { EnterViewModel(get(), get()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ interface Router {

fun navigateClearingBackStack(route: String)

fun popBackStack(route: String, inclusive: Boolean, saveState: Boolean): Boolean

fun popBackStack(): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,11 @@ package com.softartdev.notedelight.shared.presentation.note
import com.softartdev.notedelight.shared.db.Note

sealed class NoteResult {
object Loading : NoteResult()
data object Loading : NoteResult()
data class Created(val noteId: Long) : NoteResult()
data class Loaded(val result: Note) : NoteResult()
data class Saved(val title: String) : NoteResult()
data class NavEditTitle(val noteId: Long) : NoteResult()
data class TitleUpdated(val title: String) : NoteResult()
object Empty : NoteResult()
object Deleted : NoteResult()
object CheckSaveChange : NoteResult()
object NavBack : NoteResult()
data class Error(val message: String?) : NoteResult()
data object Empty : NoteResult()
data object Deleted : NoteResult()
}
Loading

0 comments on commit f7bc03a

Please sign in to comment.