From 0bf47d5c94ae8b60aa9cec23eab7e3098dcc66bd Mon Sep 17 00:00:00 2001 From: Achmad Setyabudi Susilo Date: Sun, 28 Jun 2026 20:28:46 +0700 Subject: [PATCH] fix(#21): move DB I/O to Dispatchers.IO in AddEdit screen models Wrap getExpenses.awaitOne, upsertExpense.await, getRecurringExpenses.awaitOne and upsertRecurringExpense.await in withContext(Dispatchers.IO) { ... } so the suspending Room calls run off the main thread. State-flow updates stay inside screenModelScope.launch, which is Main-bound, and execute after the withContext block returns. --- .../add_edit_expense/AddEditExpenseScreenModel.kt | 12 ++++++++++-- .../AddEditRecurringScreenModel.kt | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/dev/achmad/ledgerr/ui/screens/add_edit_expense/AddEditExpenseScreenModel.kt b/app/src/main/java/dev/achmad/ledgerr/ui/screens/add_edit_expense/AddEditExpenseScreenModel.kt index 493fe4a..56bd53f 100644 --- a/app/src/main/java/dev/achmad/ledgerr/ui/screens/add_edit_expense/AddEditExpenseScreenModel.kt +++ b/app/src/main/java/dev/achmad/ledgerr/ui/screens/add_edit_expense/AddEditExpenseScreenModel.kt @@ -8,12 +8,14 @@ import dev.achmad.ledgerr.domain.category.model.Category import dev.achmad.ledgerr.domain.expense.interactor.GetExpenses import dev.achmad.ledgerr.domain.expense.interactor.UpsertExpense import dev.achmad.ledgerr.domain.expense.model.Expense +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.time.LocalDate class AddEditExpenseScreenModel( @@ -52,7 +54,11 @@ class AddEditExpenseScreenModel( init { if (isEditMode) { screenModelScope.launch { - val existing = expenseId?.let { getExpenses.awaitOne(it) } + val existing = expenseId?.let { + withContext(Dispatchers.IO) { + getExpenses.awaitOne(it) + } + } if (existing != null) { _amount.value = "%.2f".format(existing.expense.amount) _categoryId.value = existing.expense.categoryId @@ -97,7 +103,9 @@ class AddEditExpenseScreenModel( recurringExpenseId = null, ) screenModelScope.launch { - upsertExpense.await(expense) + withContext(Dispatchers.IO) { + upsertExpense.await(expense) + } onSuccess() } } diff --git a/app/src/main/java/dev/achmad/ledgerr/ui/screens/add_edit_recurring/AddEditRecurringScreenModel.kt b/app/src/main/java/dev/achmad/ledgerr/ui/screens/add_edit_recurring/AddEditRecurringScreenModel.kt index 8166095..c0a0682 100644 --- a/app/src/main/java/dev/achmad/ledgerr/ui/screens/add_edit_recurring/AddEditRecurringScreenModel.kt +++ b/app/src/main/java/dev/achmad/ledgerr/ui/screens/add_edit_recurring/AddEditRecurringScreenModel.kt @@ -9,12 +9,14 @@ import dev.achmad.ledgerr.domain.recurring.interactor.GetRecurringExpenses import dev.achmad.ledgerr.domain.recurring.interactor.UpsertRecurringExpense import dev.achmad.ledgerr.domain.recurring.model.RecurringExpense import dev.achmad.ledgerr.domain.recurring.model.RecurringInterval +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.time.LocalDate class AddEditRecurringScreenModel( @@ -61,7 +63,11 @@ class AddEditRecurringScreenModel( init { if (isEditMode) { screenModelScope.launch { - val existing = recurringId?.let { getRecurringExpenses.awaitOne(it) } + val existing = recurringId?.let { + withContext(Dispatchers.IO) { + getRecurringExpenses.awaitOne(it) + } + } if (existing != null) { _amount.value = "%.2f".format(existing.amount) _categoryId.value = existing.categoryId @@ -121,7 +127,9 @@ class AddEditRecurringScreenModel( isActive = _isActive.value, ) screenModelScope.launch { - upsertRecurringExpense.await(recurring) + withContext(Dispatchers.IO) { + upsertRecurringExpense.await(recurring) + } onSuccess() } }