From 646d5a8f0ce8f777a58d0e7c2614e99722e58847 Mon Sep 17 00:00:00 2001 From: oliexdev Date: Mon, 4 Aug 2025 08:04:54 +0200 Subject: [PATCH] Recalculate derived values after CSV import --- .../core/database/DatabaseRepository.kt | 14 +++++---- .../openscale/core/database/MeasurementDao.kt | 5 +++- .../core/database/UserSettingsRepository.kt | 4 +-- .../settings/MeasurementTypeSettingsScreen.kt | 2 +- .../ui/screen/settings/SettingsViewModel.kt | 29 +++++++++++++++---- 5 files changed, 40 insertions(+), 14 deletions(-) diff --git a/android_app/app/src/main/java/com/health/openscale/core/database/DatabaseRepository.kt b/android_app/app/src/main/java/com/health/openscale/core/database/DatabaseRepository.kt index c84b02c2..412da7bc 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/database/DatabaseRepository.kt +++ b/android_app/app/src/main/java/com/health/openscale/core/database/DatabaseRepository.kt @@ -137,21 +137,25 @@ class DatabaseRepository( } /** - * Inserts a list of measurements, each with its associated values. + * Inserts a list of measurements, each with its associated values, + * and returns the IDs of the newly inserted main Measurement records. */ - suspend fun insertMeasurementsWithValues(measurementsData: List>>) { + suspend fun insertMeasurementsWithValues(measurementsData: List>>) : List { + val insertedIds = mutableListOf() LogManager.i(TAG, "Attempting to insert ${measurementsData.size} measurements with their values.") withContext(Dispatchers.IO) { measurementsData.forEachIndexed { index, (measurement, values) -> try { LogManager.d(TAG, "Inserting measurement ${index + 1}/${measurementsData.size}, userId: ${measurement.userId}, with ${values.size} values.") - measurementDao.insertSingleMeasurementWithItsValues(measurement, values) + val newMeasurementId = measurementDao.insertSingleMeasurementWithItsValues(measurement, values) + insertedIds.add(newMeasurementId) } catch (e: Exception) { LogManager.e(TAG, "Failed to insert measurement (userId: ${measurement.userId}, timestamp: ${measurement.timestamp}) and its values. Error: ${e.message}", e) } } } - LogManager.i(TAG, "Finished inserting measurements with values.") + LogManager.i(TAG, "Finished inserting measurements. ${insertedIds.size} measurements successfully inserted.") + return insertedIds } suspend fun deleteMeasurementValueById(valueId: Int) { @@ -204,7 +208,7 @@ class DatabaseRepository( * * @param measurementId The ID of the measurement for which to recalculate derived values. */ - private suspend fun recalculateDerivedValuesForMeasurement(measurementId: Int) { + suspend fun recalculateDerivedValuesForMeasurement(measurementId: Int) { LogManager.i(DERIVED_VALUES_TAG, "Starting recalculation of derived values for measurementId: $measurementId") val measurement = measurementDao.getMeasurementById(measurementId) ?: run { diff --git a/android_app/app/src/main/java/com/health/openscale/core/database/MeasurementDao.kt b/android_app/app/src/main/java/com/health/openscale/core/database/MeasurementDao.kt index e00cf390..968da823 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/database/MeasurementDao.kt +++ b/android_app/app/src/main/java/com/health/openscale/core/database/MeasurementDao.kt @@ -61,9 +61,10 @@ interface MeasurementDao { * * @param measurement The measurement to insert. * @param values The list of associated measurement values. + * @return The row ID of the newly inserted measurement. */ @Transaction - suspend fun insertSingleMeasurementWithItsValues(measurement: Measurement, values: List) { + suspend fun insertSingleMeasurementWithItsValues(measurement: Measurement, values: List) : Long { val measurementId = insert(measurement) // Insert the main measurement to get its ID // Update each MeasurementValue with the correct measurementId @@ -75,6 +76,8 @@ interface MeasurementDao { if (updatedValues.isNotEmpty()) { insertMeasurementValues(updatedValues) // Insert the updated measurement values } + + return measurementId } /** diff --git a/android_app/app/src/main/java/com/health/openscale/core/database/UserSettingsRepository.kt b/android_app/app/src/main/java/com/health/openscale/core/database/UserSettingsRepository.kt index aeed1b67..3b728eb7 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/database/UserSettingsRepository.kt +++ b/android_app/app/src/main/java/com/health/openscale/core/database/UserSettingsRepository.kt @@ -72,7 +72,7 @@ interface UserSettingsRepository { suspend fun setFileLoggingEnabled(enabled: Boolean) val isFirstAppStart: Flow - suspend fun setFirstAppStartCompleted(completed: Boolean) // Renamed for clarity + suspend fun setFirstAppStartCompleted(completed: Boolean) val appLanguageCode: Flow suspend fun setAppLanguageCode(languageCode: String?) @@ -134,7 +134,7 @@ class UserSettingsRepositoryImpl(context: Context) : UserSettingsRepository { override suspend fun setFirstAppStartCompleted(completed: Boolean) { LogManager.d(TAG, "Setting first app start completed to: $completed") - saveSetting(UserPreferenceKeys.IS_FIRST_APP_START.name, !completed) + saveSetting(UserPreferenceKeys.IS_FIRST_APP_START.name, completed) } override val appLanguageCode: Flow = dataStore.data diff --git a/android_app/app/src/main/java/com/health/openscale/ui/screen/settings/MeasurementTypeSettingsScreen.kt b/android_app/app/src/main/java/com/health/openscale/ui/screen/settings/MeasurementTypeSettingsScreen.kt index aaaf095d..013b2b02 100644 --- a/android_app/app/src/main/java/com/health/openscale/ui/screen/settings/MeasurementTypeSettingsScreen.kt +++ b/android_app/app/src/main/java/com/health/openscale/ui/screen/settings/MeasurementTypeSettingsScreen.kt @@ -96,7 +96,7 @@ fun MeasurementTypeSettingsScreen( }.also { updatedList -> // Persist the new display order for each type in the updated list updatedList.forEachIndexed { index, type -> - settingsViewModel.updateMeasurementType(type.copy(displayOrder = index)) + settingsViewModel.updateMeasurementType(type.copy(displayOrder = index), showSnackbar = false) } } } diff --git a/android_app/app/src/main/java/com/health/openscale/ui/screen/settings/SettingsViewModel.kt b/android_app/app/src/main/java/com/health/openscale/ui/screen/settings/SettingsViewModel.kt index 347228f2..f20fc56f 100644 --- a/android_app/app/src/main/java/com/health/openscale/ui/screen/settings/SettingsViewModel.kt +++ b/android_app/app/src/main/java/com/health/openscale/ui/screen/settings/SettingsViewModel.kt @@ -473,10 +473,22 @@ class SettingsViewModel( } ?: throw IOException("Could not open InputStream for Uri: $uri") if (newMeasurementsToSave.isNotEmpty()) { - repository.insertMeasurementsWithValues(newMeasurementsToSave) - importedMeasurementsCount = newMeasurementsToSave.size + val insertedMeasurementIds = repository.insertMeasurementsWithValues(newMeasurementsToSave) + importedMeasurementsCount = insertedMeasurementIds.size LogManager.i(TAG, "CSV Import for User ID $userId successful. $importedMeasurementsCount measurements imported.") + if (insertedMeasurementIds.isNotEmpty()) { + LogManager.d(TAG, "Starting derived value recalculation for ${insertedMeasurementIds.size} imported measurements.") + insertedMeasurementIds.forEach { measurementId -> + try { + repository.recalculateDerivedValuesForMeasurement(measurementId.toInt()) + } catch (e: Exception) { + LogManager.e(TAG, "Error recalculating derived values for measurement ID $measurementId post-import.", e) + } + } + LogManager.i(TAG, "Derived value recalculation for ${insertedMeasurementIds.size} imported measurements completed.") + } + var detailsForMessage = "" if (linesSkippedMissingDate > 0) { detailsForMessage += " ($linesSkippedMissingDate rows skipped due to missing dates" @@ -1070,13 +1082,20 @@ class SettingsViewModel( * * @param type The [MeasurementType] object with updated information. */ - fun updateMeasurementType(type: MeasurementType) { + fun updateMeasurementType(type: MeasurementType, showSnackbar: Boolean = true) { viewModelScope.launch { - LogManager.d(TAG, "Updating measurement type (ID: ${type.id})") + if (showSnackbar) { + LogManager.d(TAG, "Updating measurement type (ID: ${type.id})") + } try { repository.updateMeasurementType(type) LogManager.i(TAG, "Measurement type (ID: ${type.id}) updated successfully.") - sharedViewModel.showSnackbar(R.string.measurement_type_updated_successfully, listOf(type.key.toString())) + if (showSnackbar) { + sharedViewModel.showSnackbar( + R.string.measurement_type_updated_successfully, + listOf(type.key.toString()) + ) + } // sharedViewModel.refreshMeasurementTypes() } catch (e: Exception) { LogManager.e(TAG, "Error updating measurement type (ID: ${type.id})", e)