1
0
mirror of https://github.com/oliexdev/openScale.git synced 2025-08-18 22:41:44 +02:00

Recalculate derived values after CSV import

This commit is contained in:
oliexdev
2025-08-04 08:04:54 +02:00
parent c44080aa17
commit 646d5a8f0c
5 changed files with 40 additions and 14 deletions

View File

@@ -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<Pair<Measurement, List<MeasurementValue>>>) { suspend fun insertMeasurementsWithValues(measurementsData: List<Pair<Measurement, List<MeasurementValue>>>) : List<Long> {
val insertedIds = mutableListOf<Long>()
LogManager.i(TAG, "Attempting to insert ${measurementsData.size} measurements with their values.") LogManager.i(TAG, "Attempting to insert ${measurementsData.size} measurements with their values.")
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
measurementsData.forEachIndexed { index, (measurement, values) -> measurementsData.forEachIndexed { index, (measurement, values) ->
try { try {
LogManager.d(TAG, "Inserting measurement ${index + 1}/${measurementsData.size}, userId: ${measurement.userId}, with ${values.size} values.") 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) { } catch (e: Exception) {
LogManager.e(TAG, "Failed to insert measurement (userId: ${measurement.userId}, timestamp: ${measurement.timestamp}) and its values. Error: ${e.message}", e) 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) { suspend fun deleteMeasurementValueById(valueId: Int) {
@@ -204,7 +208,7 @@ class DatabaseRepository(
* *
* @param measurementId The ID of the measurement for which to recalculate derived values. * @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") LogManager.i(DERIVED_VALUES_TAG, "Starting recalculation of derived values for measurementId: $measurementId")
val measurement = measurementDao.getMeasurementById(measurementId) ?: run { val measurement = measurementDao.getMeasurementById(measurementId) ?: run {

View File

@@ -61,9 +61,10 @@ interface MeasurementDao {
* *
* @param measurement The measurement to insert. * @param measurement The measurement to insert.
* @param values The list of associated measurement values. * @param values The list of associated measurement values.
* @return The row ID of the newly inserted measurement.
*/ */
@Transaction @Transaction
suspend fun insertSingleMeasurementWithItsValues(measurement: Measurement, values: List<MeasurementValue>) { suspend fun insertSingleMeasurementWithItsValues(measurement: Measurement, values: List<MeasurementValue>) : Long {
val measurementId = insert(measurement) // Insert the main measurement to get its ID val measurementId = insert(measurement) // Insert the main measurement to get its ID
// Update each MeasurementValue with the correct measurementId // Update each MeasurementValue with the correct measurementId
@@ -75,6 +76,8 @@ interface MeasurementDao {
if (updatedValues.isNotEmpty()) { if (updatedValues.isNotEmpty()) {
insertMeasurementValues(updatedValues) // Insert the updated measurement values insertMeasurementValues(updatedValues) // Insert the updated measurement values
} }
return measurementId
} }
/** /**

View File

@@ -72,7 +72,7 @@ interface UserSettingsRepository {
suspend fun setFileLoggingEnabled(enabled: Boolean) suspend fun setFileLoggingEnabled(enabled: Boolean)
val isFirstAppStart: Flow<Boolean> val isFirstAppStart: Flow<Boolean>
suspend fun setFirstAppStartCompleted(completed: Boolean) // Renamed for clarity suspend fun setFirstAppStartCompleted(completed: Boolean)
val appLanguageCode: Flow<String?> val appLanguageCode: Flow<String?>
suspend fun setAppLanguageCode(languageCode: String?) suspend fun setAppLanguageCode(languageCode: String?)
@@ -134,7 +134,7 @@ class UserSettingsRepositoryImpl(context: Context) : UserSettingsRepository {
override suspend fun setFirstAppStartCompleted(completed: Boolean) { override suspend fun setFirstAppStartCompleted(completed: Boolean) {
LogManager.d(TAG, "Setting first app start completed to: $completed") 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<String?> = dataStore.data override val appLanguageCode: Flow<String?> = dataStore.data

View File

@@ -96,7 +96,7 @@ fun MeasurementTypeSettingsScreen(
}.also { updatedList -> }.also { updatedList ->
// Persist the new display order for each type in the updated list // Persist the new display order for each type in the updated list
updatedList.forEachIndexed { index, type -> updatedList.forEachIndexed { index, type ->
settingsViewModel.updateMeasurementType(type.copy(displayOrder = index)) settingsViewModel.updateMeasurementType(type.copy(displayOrder = index), showSnackbar = false)
} }
} }
} }

View File

@@ -473,10 +473,22 @@ class SettingsViewModel(
} ?: throw IOException("Could not open InputStream for Uri: $uri") } ?: throw IOException("Could not open InputStream for Uri: $uri")
if (newMeasurementsToSave.isNotEmpty()) { if (newMeasurementsToSave.isNotEmpty()) {
repository.insertMeasurementsWithValues(newMeasurementsToSave) val insertedMeasurementIds = repository.insertMeasurementsWithValues(newMeasurementsToSave)
importedMeasurementsCount = newMeasurementsToSave.size importedMeasurementsCount = insertedMeasurementIds.size
LogManager.i(TAG, "CSV Import for User ID $userId successful. $importedMeasurementsCount measurements imported.") 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 = "" var detailsForMessage = ""
if (linesSkippedMissingDate > 0) { if (linesSkippedMissingDate > 0) {
detailsForMessage += " ($linesSkippedMissingDate rows skipped due to missing dates" detailsForMessage += " ($linesSkippedMissingDate rows skipped due to missing dates"
@@ -1070,13 +1082,20 @@ class SettingsViewModel(
* *
* @param type The [MeasurementType] object with updated information. * @param type The [MeasurementType] object with updated information.
*/ */
fun updateMeasurementType(type: MeasurementType) { fun updateMeasurementType(type: MeasurementType, showSnackbar: Boolean = true) {
viewModelScope.launch { viewModelScope.launch {
LogManager.d(TAG, "Updating measurement type (ID: ${type.id})") if (showSnackbar) {
LogManager.d(TAG, "Updating measurement type (ID: ${type.id})")
}
try { try {
repository.updateMeasurementType(type) repository.updateMeasurementType(type)
LogManager.i(TAG, "Measurement type (ID: ${type.id}) updated successfully.") 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() // sharedViewModel.refreshMeasurementTypes()
} catch (e: Exception) { } catch (e: Exception) {
LogManager.e(TAG, "Error updating measurement type (ID: ${type.id})", e) LogManager.e(TAG, "Error updating measurement type (ID: ${type.id})", e)