diff --git a/app/src/androidTest/java/com/example/cahier/data/FakeNotesRepository.kt b/app/src/androidTest/java/com/example/cahier/data/FakeNotesRepository.kt index c8bd26c..f45a541 100644 --- a/app/src/androidTest/java/com/example/cahier/data/FakeNotesRepository.kt +++ b/app/src/androidTest/java/com/example/cahier/data/FakeNotesRepository.kt @@ -25,7 +25,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.update class FakeNotesRepository : NotesRepository { @@ -42,8 +41,8 @@ class FakeNotesRepository : NotesRepository { .map { it.values.toList().sortedByDescending { note -> note.id } } } - override fun getNoteStream(id: Long): Flow { - return notesFlow.asStateFlow().mapNotNull { it[id] } + override fun getNoteStream(id: Long): Flow { + return notesFlow.asStateFlow().map { it[id] } } override suspend fun addNote(note: Note): Long { diff --git a/app/src/androidTest/java/com/example/cahier/data/NoteDaoTest.kt b/app/src/androidTest/java/com/example/cahier/data/NoteDaoTest.kt index 98a8148..24b4766 100644 --- a/app/src/androidTest/java/com/example/cahier/data/NoteDaoTest.kt +++ b/app/src/androidTest/java/com/example/cahier/data/NoteDaoTest.kt @@ -65,7 +65,7 @@ class NoteDaoTest { val updatedNote = Note(id = 1, title = "Updated Title") noteDao.updateNote(updatedNote) val retrievedNote = noteDao.getNote(1).first() - assertEquals(retrievedNote.title, "Updated Title") + assertEquals(retrievedNote?.title, "Updated Title") } @Test diff --git a/app/src/main/java/com/example/cahier/data/NoteDao.kt b/app/src/main/java/com/example/cahier/data/NoteDao.kt index c9b16e5..fd8d2f6 100644 --- a/app/src/main/java/com/example/cahier/data/NoteDao.kt +++ b/app/src/main/java/com/example/cahier/data/NoteDao.kt @@ -32,7 +32,7 @@ interface NoteDao { fun getAllNotes(): Flow> @Query("SELECT * FROM notes WHERE id = :id") - fun getNote(id: Long): Flow + fun getNote(id: Long): Flow @Insert(onConflict = OnConflictStrategy.IGNORE) suspend fun addNote(note: Note): Long diff --git a/app/src/main/java/com/example/cahier/data/NotesRepository.kt b/app/src/main/java/com/example/cahier/data/NotesRepository.kt index 98e1477..92cbd37 100644 --- a/app/src/main/java/com/example/cahier/data/NotesRepository.kt +++ b/app/src/main/java/com/example/cahier/data/NotesRepository.kt @@ -28,9 +28,9 @@ interface NotesRepository { fun getAllNotesStream(): Flow> /** - * Retrieve an note from the given data source that matches with the [id]. + * Retrieve a note from the given data source that matches with the [id]. */ - fun getNoteStream(id: Long): Flow + fun getNoteStream(id: Long): Flow /** * Insert note in the data source diff --git a/app/src/main/java/com/example/cahier/data/OfflineNotesRepository.kt b/app/src/main/java/com/example/cahier/data/OfflineNotesRepository.kt index eeef68e..125734b 100644 --- a/app/src/main/java/com/example/cahier/data/OfflineNotesRepository.kt +++ b/app/src/main/java/com/example/cahier/data/OfflineNotesRepository.kt @@ -34,7 +34,7 @@ class OfflineNotesRepository( override fun getAllNotesStream(): Flow> = notesDao.getAllNotes() - override fun getNoteStream(id: Long): Flow = notesDao.getNote(id) + override fun getNoteStream(id: Long): Flow = notesDao.getNote(id) override suspend fun addNote(note: Note): Long { return notesDao.addNote(note) diff --git a/app/src/main/java/com/example/cahier/ui/viewmodels/HomeScreenViewModel.kt b/app/src/main/java/com/example/cahier/ui/viewmodels/HomeScreenViewModel.kt index 13b26ce..124882d 100644 --- a/app/src/main/java/com/example/cahier/ui/viewmodels/HomeScreenViewModel.kt +++ b/app/src/main/java/com/example/cahier/ui/viewmodels/HomeScreenViewModel.kt @@ -27,6 +27,8 @@ import com.example.cahier.data.NotesRepository import com.example.cahier.ui.CahierUiState import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.Job import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -51,6 +53,8 @@ class HomeScreenViewModel @Inject constructor( private val _newWindowEvent = Channel>() val newWindowEvent = _newWindowEvent.receiveAsFlow() + private var selectNoteJob: Job? = null + /** * Holds ui state for the list of notes on the home pane. * The list of items are retrieved from [NotesRepository] and mapped to @@ -65,7 +69,8 @@ class HomeScreenViewModel @Inject constructor( ) fun selectNote(noteId: Long) { - viewModelScope.launch { + selectNoteJob?.cancel() + selectNoteJob = viewModelScope.launch { _uiState.value = _uiState.value.copy(isLoading = true) try { noteRepository.getNoteStream(noteId) @@ -79,6 +84,7 @@ class HomeScreenViewModel @Inject constructor( _uiState.value = CahierUiState(note = note, strokes = strokes) } } catch (e: Exception) { + if (e is CancellationException) throw e _uiState.value = _uiState.value.copy( error = "Error retrieving note: ${e.message}", isLoading = false @@ -129,6 +135,9 @@ class HomeScreenViewModel @Inject constructor( try { viewModelScope.launch { noteRepository.deleteNote(noteToDelete) + if (_uiState.value.note.id == noteToDelete.id) { + clearSelection() + } } } catch (e: Exception) { Log.e(TAG, "Error deleting note: ${e.message}") @@ -143,7 +152,9 @@ class HomeScreenViewModel @Inject constructor( noteRepository.toggleFavorite(noteId) if (_uiState.value.note.id == noteId) { val updatedNote = noteRepository.getNoteStream(noteId).first() - _uiState.update { it.copy(note = updatedNote) } + updatedNote?.let { note -> + _uiState.update { it.copy(note = note) } + } } } catch (e: Exception) { Log.e(TAG, "Error toggling favorite: ${e.message}") @@ -152,6 +163,7 @@ class HomeScreenViewModel @Inject constructor( } fun clearSelection() { + selectNoteJob?.cancel() _uiState.update { CahierUiState() } } diff --git a/app/src/test/java/com/example/cahier/data/FakeNotesRepository.kt b/app/src/test/java/com/example/cahier/data/FakeNotesRepository.kt index c8bd26c..abcfaea 100644 --- a/app/src/test/java/com/example/cahier/data/FakeNotesRepository.kt +++ b/app/src/test/java/com/example/cahier/data/FakeNotesRepository.kt @@ -42,8 +42,8 @@ class FakeNotesRepository : NotesRepository { .map { it.values.toList().sortedByDescending { note -> note.id } } } - override fun getNoteStream(id: Long): Flow { - return notesFlow.asStateFlow().mapNotNull { it[id] } + override fun getNoteStream(id: Long): Flow { + return notesFlow.asStateFlow().map { it[id] } } override suspend fun addNote(note: Note): Long { diff --git a/app/src/test/java/com/example/cahier/ui/viewmodels/CanvasScreenViewModelTest.kt b/app/src/test/java/com/example/cahier/ui/viewmodels/CanvasScreenViewModelTest.kt index f25d83d..49613a7 100644 --- a/app/src/test/java/com/example/cahier/ui/viewmodels/CanvasScreenViewModelTest.kt +++ b/app/src/test/java/com/example/cahier/ui/viewmodels/CanvasScreenViewModelTest.kt @@ -81,7 +81,7 @@ class CanvasScreenViewModelTest { viewModel.updateNoteTitle(newTitle) notesRepository.getNoteStream(noteId).test { - assertEquals(newTitle, awaitItem().title) + assertEquals(newTitle, awaitItem()!!.title) cancelAndIgnoreRemainingEvents() } } @@ -92,7 +92,7 @@ class CanvasScreenViewModelTest { viewModel.updateNoteText(newText) notesRepository.getNoteStream(noteId).test { - assertEquals(newText, awaitItem().text) + assertEquals(newText, awaitItem()!!.text) cancelAndIgnoreRemainingEvents() } } @@ -102,7 +102,7 @@ class CanvasScreenViewModelTest { viewModel.toggleFavorite() notesRepository.getNoteStream(noteId).test { - assertTrue(awaitItem().isFavorite) + assertTrue(awaitItem()!!.isFavorite) cancelAndIgnoreRemainingEvents() } } diff --git a/app/src/test/java/com/example/cahier/ui/viewmodels/HomeScreenViewModelTest.kt b/app/src/test/java/com/example/cahier/ui/viewmodels/HomeScreenViewModelTest.kt index 5625315..fc42ffd 100644 --- a/app/src/test/java/com/example/cahier/ui/viewmodels/HomeScreenViewModelTest.kt +++ b/app/src/test/java/com/example/cahier/ui/viewmodels/HomeScreenViewModelTest.kt @@ -112,11 +112,10 @@ class HomeScreenViewModelTest { fun toggleFavorite_toggles_favorite_status_in_repository() = runTest { val noteId = runBlocking { notesRepository.addNote(Note(title = "My Note", isFavorite = false)) } - viewModel.toggleFavorite(noteId) notesRepository.getNoteStream(noteId).test { - assertTrue(awaitItem().isFavorite) + assertTrue(awaitItem()!!.isFavorite) cancelAndIgnoreRemainingEvents() } }