Fix: Resolve race condition when saving items

This commit fixes a bug that prevented new items (notes, recipes, and shopping lists) from being saved and existing items from being renamed.

The issue was caused by a race condition where the item details were being reset before the save operation could complete. This was due to a nested coroutine launch that caused the UI to update prematurely.

The fix involves:
- Removing the nested coroutine launch to ensure sequential execution of the save and UI reset operations.
- Moving the `reset...Details()` calls to the ViewModels to ensure they are only called after the save operation is complete.
This commit is contained in:
2025-11-03 14:00:27 +01:00
parent f613e27c6d
commit de1d02f31b
6 changed files with 22 additions and 18 deletions

View File

@@ -1,5 +1,6 @@
package de.lxtools.noteshop.ui.appshell
import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues

View File

@@ -1,5 +1,6 @@
package de.lxtools.noteshop.ui.appshell
import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
@@ -106,9 +107,8 @@ fun AppDialogs(
onValueChange = onListDetailsChange,
onSave = {
scope.launch {
onSaveList()
shoppingListsViewModel.saveList()
onShowListDialogChange(false)
onResetListDetails()
}
},
onDismiss = { onShowListDialogChange(false) },
@@ -125,9 +125,8 @@ fun AppDialogs(
onValueChange = onNoteDetailsChange,
onSave = {
scope.launch {
onSaveNote()
notesViewModel.saveNote()
onShowNoteDialogChange(false)
onResetNoteDetails()
}
},
onDismiss = { onShowNoteDialogChange(false) },
@@ -144,10 +143,10 @@ fun AppDialogs(
recipeDetails = recipeDetails,
onValueChange = onRecipeDetailsChange,
onSave = {
Log.d("AppDialogs", "RecipeInputDialog onSave called")
scope.launch {
onSaveRecipe()
recipesViewModel.saveRecipe()
onShowRecipeDialogChange(false)
onResetRecipeDetails()
}
},
onDismiss = { onShowRecipeDialogChange(false) },

View File

@@ -79,7 +79,7 @@ class NotesViewModel(private val noteshopRepository: NoteshopRepository) : ViewM
_noteDetails.value = noteDetails
}
suspend fun saveNote() {
suspend fun saveNote() {
if (noteDetails.value.isValid()) {
var currentNote = noteDetails.value.toNote()
@@ -87,10 +87,11 @@ class NotesViewModel(private val noteshopRepository: NoteshopRepository) : ViewM
if (currentNote.id == 0) {
val notesCount = noteshopRepository.getNotesCount()
currentNote = currentNote.copy(displayOrder = notesCount)
val newNote = currentNote.copy(displayOrder = notesCount)
noteshopRepository.insertNote(newNote)
} else {
noteshopRepository.updateNote(currentNote)
}
noteshopRepository.insertNote(currentNote)
}
}

View File

@@ -1,5 +1,6 @@
package de.lxtools.noteshop.ui.recipes
import android.util.Log
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth

View File

@@ -73,10 +73,11 @@ class RecipesViewModel(private val noteshopRepository: NoteshopRepository) : Vie
}
fun updateRecipeDetails(recipeDetails: RecipeDetails) {
Log.d("RecipesViewModel", "updateRecipeDetails called with details: $recipeDetails")
_recipeDetails.value = recipeDetails
}
suspend fun saveRecipe() {
suspend fun saveRecipe() {
if (recipeDetails.value.isValid()) {
var currentRecipe = recipeDetails.value.toRecipe()

View File

@@ -123,7 +123,7 @@ class ShoppingListsViewModel(private val noteshopRepository: NoteshopRepository,
}
suspend fun saveList() {
suspend fun saveList() {
if (listDetails.value.isValid()) {
var currentList = listDetails.value.toShoppingList()
@@ -200,7 +200,7 @@ class ShoppingListsViewModel(private val noteshopRepository: NoteshopRepository,
suspend fun saveShoppingListItem(item: ShoppingListItem) {
suspend fun saveShoppingListItem(item: ShoppingListItem) {
if (item.name.isNotBlank()) {
val parentList = noteshopRepository.getShoppingListWithItemsStream(item.listId).firstOrNull()?.shoppingList
if (parentList?.protectionHash?.isNotEmpty() == true) {
@@ -208,12 +208,13 @@ class ShoppingListsViewModel(private val noteshopRepository: NoteshopRepository,
return
}
var currentItem = item
if (currentItem.id == 0) {
val itemsCount = noteshopRepository.getItemsCount(currentItem.listId)
currentItem = currentItem.copy(displayOrder = itemsCount)
if (item.id == 0) {
val itemsCount = noteshopRepository.getItemsCount(item.listId)
val newItem = item.copy(displayOrder = itemsCount)
noteshopRepository.insertShoppingListItem(newItem)
} else {
noteshopRepository.updateShoppingListItem(item)
}
noteshopRepository.insertShoppingListItem(currentItem)
}
}