1
0
mirror of https://github.com/oliexdev/openScale.git synced 2025-08-09 18:26:38 +02:00

Use in SettingViewModel the showSnackbar method by ShareViewModel

This commit is contained in:
oliexdev
2025-08-03 13:52:37 +02:00
parent 5513214d55
commit 7a4b50089a
3 changed files with 49 additions and 64 deletions

View File

@@ -181,7 +181,7 @@ fun AppNavigation(sharedViewModel: SharedViewModel) {
scope.launch { scope.launch {
val messageText: String = if (event.messageResId != Routes.NO_TITLE_RESOURCE_ID) { val messageText: String = if (event.messageResId != Routes.NO_TITLE_RESOURCE_ID) {
try { try {
resources.getString(event.messageResId, *(event.messageFormatArgs ?: emptyArray())) resources.getString(event.messageResId, *event.messageFormatArgs.toTypedArray())
} catch (e: Resources.NotFoundException) { } catch (e: Resources.NotFoundException) {
// Log this error or handle it, then fallback // Log this error or handle it, then fallback
event.message // Fallback to raw message if resource ID is invalid event.message // Fallback to raw message if resource ID is invalid

View File

@@ -76,7 +76,7 @@ private const val TAG = "SharedViewModel"
data class SnackbarEvent( data class SnackbarEvent(
@StringRes val messageResId: Int = 0, @StringRes val messageResId: Int = 0,
val message: String = "", val message: String = "",
val messageFormatArgs: Array<Any>? = null, val messageFormatArgs: List<Any> = emptyList(),
val duration: SnackbarDuration = SnackbarDuration.Short, val duration: SnackbarDuration = SnackbarDuration.Short,
@StringRes val actionLabelResId: Int? = null, @StringRes val actionLabelResId: Int? = null,
val actionLabel: String? = null, val actionLabel: String? = null,
@@ -183,7 +183,7 @@ class SharedViewModel(
fun showSnackbar( fun showSnackbar(
@StringRes messageResId: Int, @StringRes messageResId: Int,
formatArgs: Array<Any>? = null, formatArgs: List<Any> = emptyList(),
duration: SnackbarDuration = SnackbarDuration.Short, duration: SnackbarDuration = SnackbarDuration.Short,
@StringRes actionLabelResId: Int? = null, @StringRes actionLabelResId: Int? = null,
actionLabel: String? = null, actionLabel: String? = null,

View File

@@ -36,7 +36,6 @@ import com.health.openscale.ui.screen.SharedViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
@@ -73,16 +72,6 @@ sealed class SafEvent {
data class RequestOpenFile(val actionId: String, val userId: Int) : SafEvent() data class RequestOpenFile(val actionId: String, val userId: Int) : SafEvent()
} }
/**
* Sealed class for UI messages to be emitted to the UI layer.
* This allows sending either a direct string (rarely, for dynamic error messages not suitable for resources)
* or a resource ID with optional formatting arguments.
*/
sealed class UiMessageEvent {
data class Resource(val resId: Int, val formatArgs: List<Any> = emptyList()) : UiMessageEvent()
// data class Plain(val message: String) : UiMessageEvent() // If you ever need to send raw strings
}
/** /**
* ViewModel for settings-related screens. * ViewModel for settings-related screens.
*/ */
@@ -96,9 +85,6 @@ class SettingsViewModel(
private val _appLanguageCode = MutableStateFlow(getDefaultAppLanguage()) private val _appLanguageCode = MutableStateFlow(getDefaultAppLanguage())
val appLanguageCode: StateFlow<String> = _appLanguageCode.asStateFlow() val appLanguageCode: StateFlow<String> = _appLanguageCode.asStateFlow()
private val _uiMessageEvents = MutableSharedFlow<UiMessageEvent>()
val uiMessageEvents: SharedFlow<UiMessageEvent> = _uiMessageEvents.asSharedFlow()
val allUsers: StateFlow<List<User>> = sharedViewModel.allUsers val allUsers: StateFlow<List<User>> = sharedViewModel.allUsers
private val _showUserSelectionDialogForExport = MutableStateFlow(false) private val _showUserSelectionDialogForExport = MutableStateFlow(false)
@@ -238,7 +224,7 @@ class SettingsViewModel(
if (valueColumnKeys.isEmpty()) { if (valueColumnKeys.isEmpty()) {
LogManager.w(TAG, "No specific data fields (value columns) defined for export for user ID: $userId.") LogManager.w(TAG, "No specific data fields (value columns) defined for export for user ID: $userId.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.export_error_no_specific_fields)) sharedViewModel.showSnackbar(R.string.export_error_no_specific_fields)
} }
val userMeasurementsWithValues: List<MeasurementWithValues> = val userMeasurementsWithValues: List<MeasurementWithValues> =
@@ -246,7 +232,7 @@ class SettingsViewModel(
if (userMeasurementsWithValues.isEmpty()) { if (userMeasurementsWithValues.isEmpty()) {
LogManager.i(TAG, "No measurements found for User ID $userId to export.") LogManager.i(TAG, "No measurements found for User ID $userId to export.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.export_error_no_measurements)) sharedViewModel.showSnackbar(R.string.export_error_no_measurements)
_isLoadingExport.value = false _isLoadingExport.value = false
return@launch return@launch
} }
@@ -287,7 +273,7 @@ class SettingsViewModel(
if (csvRowsData.isEmpty()) { if (csvRowsData.isEmpty()) {
LogManager.w(TAG, "No exportable measurement values found for User ID $userId after transformation.") LogManager.w(TAG, "No exportable measurement values found for User ID $userId after transformation.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.export_error_no_exportable_values)) sharedViewModel.showSnackbar(R.string.export_error_no_exportable_values)
_isLoadingExport.value = false _isLoadingExport.value = false
return@launch return@launch
} }
@@ -305,18 +291,18 @@ class SettingsViewModel(
exportSuccessful = true exportSuccessful = true
LogManager.d(TAG, "CSV data written successfully for User ID $userId to URI: $uri.") LogManager.d(TAG, "CSV data written successfully for User ID $userId to URI: $uri.")
} ?: run { } ?: run {
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.export_error_cannot_create_file)) sharedViewModel.showSnackbar(R.string.export_error_cannot_create_file)
LogManager.e(TAG, "Export failed for user ID $userId: Could not open OutputStream for Uri: $uri") LogManager.e(TAG, "Export failed for user ID $userId: Could not open OutputStream for Uri: $uri")
} }
if (exportSuccessful) { if (exportSuccessful) {
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.export_successful)) sharedViewModel.showSnackbar(R.string.export_successful)
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
LogManager.e(TAG, "Error during CSV export for User ID $userId to URI: $uri", e) LogManager.e(TAG, "Error during CSV export for User ID $userId to URI: $uri", e)
val errorMessage = e.localizedMessage ?: "Unknown error" // In a real app, use R.string.settings_unknown_error val errorMessage = e.localizedMessage ?: "Unknown error" // In a real app, use R.string.settings_unknown_error
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.export_error_generic, listOf(errorMessage))) sharedViewModel.showSnackbar(R.string.export_error_generic, listOf(errorMessage))
} finally { } finally {
_isLoadingExport.value = false _isLoadingExport.value = false
LogManager.i(TAG, "CSV export process finished for user ID: $userId.") LogManager.i(TAG, "CSV export process finished for user ID: $userId.")
@@ -472,14 +458,14 @@ class SettingsViewModel(
if (detailsForMessage.isNotEmpty()) { if (detailsForMessage.isNotEmpty()) {
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.import_successful_records_with_details, listOf(importedMeasurementsCount, detailsForMessage))) sharedViewModel.showSnackbar(R.string.import_successful_records_with_details, listOf(importedMeasurementsCount, detailsForMessage))
} else { } else {
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.import_successful_records, listOf(importedMeasurementsCount))) sharedViewModel.showSnackbar(R.string.import_successful_records, listOf(importedMeasurementsCount))
} }
} else { } else {
LogManager.w(TAG, "No valid data found in CSV for User ID $userId or all rows had errors.") LogManager.w(TAG, "No valid data found in CSV for User ID $userId or all rows had errors.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.import_error_no_valid_data)) sharedViewModel.showSnackbar(R.string.import_error_no_valid_data)
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
@@ -487,15 +473,14 @@ class SettingsViewModel(
val userErrorMessage = when { val userErrorMessage = when {
e is IOException && e.message?.contains("CSV header is missing the mandatory column 'date'") == true -> e is IOException && e.message?.contains("CSV header is missing the mandatory column 'date'") == true ->
// Assuming R.string.import_error_missing_date_column takes dateColumnKey as an argument // Assuming R.string.import_error_missing_date_column takes dateColumnKey as an argument
UiMessageEvent.Resource(R.string.import_error_missing_date_column) sharedViewModel.showSnackbar(R.string.import_error_missing_date_column)
e is IOException && e.message?.contains("Could not open InputStream") == true -> e is IOException && e.message?.contains("Could not open InputStream") == true ->
UiMessageEvent.Resource(R.string.import_error_cannot_read_file) sharedViewModel.showSnackbar(R.string.import_error_cannot_read_file)
else -> { else -> {
val errorMsg = e.localizedMessage ?: "Unknown error" // Use R.string.settings_unknown_error val errorMsg = e.localizedMessage ?: "Unknown error" // Use R.string.settings_unknown_error
UiMessageEvent.Resource(R.string.import_error_generic, listOf(errorMsg)) sharedViewModel.showSnackbar(R.string.import_error_generic, listOf(errorMsg))
} }
} }
_uiMessageEvents.emit(userErrorMessage)
} finally { } finally {
_isLoadingImport.value = false _isLoadingImport.value = false
LogManager.i(TAG, "CSV import process finished for user ID: $userId. Imported: $importedMeasurementsCount, Skipped (missing date): $linesSkippedMissingDate, Skipped (date parse error): $linesSkippedDateParseError, Values skipped (parse error): $valuesSkippedParseError.") LogManager.i(TAG, "CSV import process finished for user ID: $userId. Imported: $importedMeasurementsCount, Skipped (missing date): $linesSkippedMissingDate, Skipped (date parse error): $linesSkippedDateParseError, Values skipped (parse error): $valuesSkippedParseError.")
@@ -507,7 +492,7 @@ class SettingsViewModel(
viewModelScope.launch { viewModelScope.launch {
if (allUsers.value.isEmpty()) { if (allUsers.value.isEmpty()) {
LogManager.i(TAG, "Export process start: No users available for export.") LogManager.i(TAG, "Export process start: No users available for export.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.export_no_users_available)) sharedViewModel.showSnackbar(R.string.export_no_users_available)
return@launch return@launch
} }
if (allUsers.value.size == 1) { if (allUsers.value.size == 1) {
@@ -550,7 +535,7 @@ class SettingsViewModel(
viewModelScope.launch { viewModelScope.launch {
if (allUsers.value.isEmpty()) { if (allUsers.value.isEmpty()) {
LogManager.i(TAG, "Import process start: No users available for import.") LogManager.i(TAG, "Import process start: No users available for import.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.import_no_users_available)) sharedViewModel.showSnackbar(R.string.import_no_users_available)
return@launch return@launch
} }
if (allUsers.value.size == 1) { if (allUsers.value.size == 1) {
@@ -598,7 +583,7 @@ class SettingsViewModel(
_showDeleteConfirmationDialog.value = true _showDeleteConfirmationDialog.value = true
} else { } else {
LogManager.i(TAG, "Initiate delete user data: No user data available to delete.") LogManager.i(TAG, "Initiate delete user data: No user data available to delete.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.delete_data_no_users_available)) sharedViewModel.showSnackbar(R.string.delete_data_no_users_available)
} }
} }
} }
@@ -632,14 +617,14 @@ class SettingsViewModel(
val deletedRowCount = repository.deleteAllMeasurementsForUser(userToDelete.id) val deletedRowCount = repository.deleteAllMeasurementsForUser(userToDelete.id)
if (deletedRowCount > 0) { if (deletedRowCount > 0) {
LogManager.i(TAG, "Data for User ${userToDelete.name} (ID: ${userToDelete.id}) successfully deleted. $deletedRowCount measurement records removed.") LogManager.i(TAG, "Data for User ${userToDelete.name} (ID: ${userToDelete.id}) successfully deleted. $deletedRowCount measurement records removed.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.delete_data_user_successful, listOf(userToDelete.name))) sharedViewModel.showSnackbar(R.string.delete_data_user_successful, listOf(userToDelete.name))
} else { } else {
LogManager.i(TAG, "No measurement data found to delete for User ${userToDelete.name} (ID: ${userToDelete.id}).") LogManager.i(TAG, "No measurement data found to delete for User ${userToDelete.name} (ID: ${userToDelete.id}).")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.delete_data_user_no_data_found, listOf(userToDelete.name))) sharedViewModel.showSnackbar(R.string.delete_data_user_no_data_found, listOf(userToDelete.name))
} }
} catch (e: Exception) { } catch (e: Exception) {
LogManager.e(TAG, "Error deleting data for User ${userToDelete.name} (ID: ${userToDelete.id})", e) LogManager.e(TAG, "Error deleting data for User ${userToDelete.name} (ID: ${userToDelete.id})", e)
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.delete_data_user_error, listOf(userToDelete.name))) sharedViewModel.showSnackbar(R.string.delete_data_user_error, listOf(userToDelete.name))
} finally { } finally {
_isLoadingDeletion.value = false _isLoadingDeletion.value = false
_showDeleteConfirmationDialog.value = false _showDeleteConfirmationDialog.value = false
@@ -649,7 +634,7 @@ class SettingsViewModel(
} }
} ?: run { } ?: run {
viewModelScope.launch { viewModelScope.launch {
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.delete_data_error_no_user_selected)) sharedViewModel.showSnackbar(R.string.delete_data_error_no_user_selected)
_showDeleteConfirmationDialog.value = false _showDeleteConfirmationDialog.value = false
} }
LogManager.w(TAG, "confirmActualDeletion called without a user pending deletion.") LogManager.w(TAG, "confirmActualDeletion called without a user pending deletion.")
@@ -687,7 +672,7 @@ class SettingsViewModel(
val dbFile = applicationContext.getDatabasePath(dbName) val dbFile = applicationContext.getDatabasePath(dbName)
val dbDir = dbFile.parentFile ?: run { val dbDir = dbFile.parentFile ?: run {
LogManager.e(TAG, "Database backup error: Database directory could not be determined for $dbName.") LogManager.e(TAG, "Database backup error: Database directory could not be determined for $dbName.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.backup_error_db_name_not_retrieved)) // Generic error might be better sharedViewModel.showSnackbar(R.string.backup_error_db_name_not_retrieved) // Generic error might be better
_isLoadingBackup.value = false _isLoadingBackup.value = false
return@launch return@launch
} }
@@ -700,7 +685,7 @@ class SettingsViewModel(
) )
if (!dbFile.exists()) { if (!dbFile.exists()) {
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.backup_error_main_db_not_found, listOf(dbName))) sharedViewModel.showSnackbar(R.string.backup_error_main_db_not_found, listOf(dbName))
LogManager.e(TAG, "Database backup error: Main DB file ${dbFile.absolutePath} not found.") LogManager.e(TAG, "Database backup error: Main DB file ${dbFile.absolutePath} not found.")
_isLoadingBackup.value = false _isLoadingBackup.value = false
return@launch return@launch
@@ -735,7 +720,7 @@ class SettingsViewModel(
} }
} }
} ?: run { } ?: run {
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.backup_error_no_output_stream)) sharedViewModel.showSnackbar(R.string.backup_error_no_output_stream)
LogManager.e(TAG, "Backup failed: Could not open OutputStream for Uri: $backupUri") LogManager.e(TAG, "Backup failed: Could not open OutputStream for Uri: $backupUri")
return@withContext // Exit IO context return@withContext // Exit IO context
} }
@@ -743,19 +728,19 @@ class SettingsViewModel(
} catch (e: IOException) { } catch (e: IOException) {
LogManager.e(TAG, "IO Error during database backup zip process to URI $backupUri", e) LogManager.e(TAG, "IO Error during database backup zip process to URI $backupUri", e)
val errorMsg = e.localizedMessage ?: "Unknown I/O error" val errorMsg = e.localizedMessage ?: "Unknown I/O error"
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.backup_error_generic, listOf(errorMsg))) sharedViewModel.showSnackbar(R.string.backup_error_generic, listOf(errorMsg))
return@withContext return@withContext
} }
if (backupSuccessful) { if (backupSuccessful) {
LogManager.i(TAG, "Database backup to $backupUri successful.") LogManager.i(TAG, "Database backup to $backupUri successful.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.backup_successful)) sharedViewModel.showSnackbar(R.string.backup_successful)
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
LogManager.e(TAG, "General error during database backup preparation for URI $backupUri", e) LogManager.e(TAG, "General error during database backup preparation for URI $backupUri", e)
val errorMsg = e.localizedMessage ?: "Unknown error" val errorMsg = e.localizedMessage ?: "Unknown error"
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.backup_error_generic, listOf(errorMsg))) sharedViewModel.showSnackbar(R.string.backup_error_generic, listOf(errorMsg))
} finally { } finally {
_isLoadingBackup.value = false _isLoadingBackup.value = false
LogManager.i(TAG, "Database backup process finished for URI: $backupUri.") LogManager.i(TAG, "Database backup process finished for URI: $backupUri.")
@@ -772,7 +757,7 @@ class SettingsViewModel(
val dbFile = applicationContext.getDatabasePath(dbName) val dbFile = applicationContext.getDatabasePath(dbName)
val dbDir = dbFile.parentFile ?: run { val dbDir = dbFile.parentFile ?: run {
LogManager.e(TAG, "Database restore error: Database directory could not be determined for $dbName.") LogManager.e(TAG, "Database restore error: Database directory could not be determined for $dbName.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.backup_error_db_name_not_retrieved)) sharedViewModel.showSnackbar(R.string.backup_error_db_name_not_retrieved)
_isLoadingRestore.value = false _isLoadingRestore.value = false
return@launch return@launch
} }
@@ -816,14 +801,14 @@ class SettingsViewModel(
} }
} }
} ?: run { } ?: run {
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.restore_error_no_input_stream)) sharedViewModel.showSnackbar(R.string.restore_error_no_input_stream)
LogManager.e(TAG, "Restore failed: Could not open InputStream for Uri: $restoreUri") LogManager.e(TAG, "Restore failed: Could not open InputStream for Uri: $restoreUri")
return@withContext return@withContext
} }
if (!mainDbRestored) { if (!mainDbRestored) {
LogManager.e(TAG, "Restore failed: Main database file '$dbName' not found in the backup archive.") LogManager.e(TAG, "Restore failed: Main database file '$dbName' not found in the backup archive.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.restore_error_db_files_missing)) sharedViewModel.showSnackbar(R.string.restore_error_db_files_missing)
// Attempt to clean up partially restored files might be needed here, or let the user handle it. // Attempt to clean up partially restored files might be needed here, or let the user handle it.
return@withContext return@withContext
} }
@@ -832,18 +817,18 @@ class SettingsViewModel(
} catch (e: IOException) { } catch (e: IOException) {
LogManager.e(TAG, "IO Error during database restore from URI $restoreUri", e) LogManager.e(TAG, "IO Error during database restore from URI $restoreUri", e)
val errorMsg = e.localizedMessage ?: "Unknown I/O error" val errorMsg = e.localizedMessage ?: "Unknown I/O error"
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.restore_error_generic, listOf(errorMsg))) sharedViewModel.showSnackbar(R.string.restore_error_generic, listOf(errorMsg))
return@withContext return@withContext
} catch (e: IllegalStateException) { // Can be thrown by ZipInputStream } catch (e: IllegalStateException) { // Can be thrown by ZipInputStream
LogManager.e(TAG, "Error processing ZIP file during restore from URI $restoreUri", e) LogManager.e(TAG, "Error processing ZIP file during restore from URI $restoreUri", e)
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.restore_error_zip_format)) sharedViewModel.showSnackbar(R.string.restore_error_zip_format)
return@withContext return@withContext
} }
if (restoreSuccessful) { if (restoreSuccessful) {
LogManager.i(TAG, "Database restore from $restoreUri successful. App restart is required.") LogManager.i(TAG, "Database restore from $restoreUri successful. App restart is required.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.restore_successful)) sharedViewModel.showSnackbar(R.string.restore_successful)
// The app needs to be restarted for Room to pick up the new database files correctly. // The app needs to be restarted for Room to pick up the new database files correctly.
// This usually involves sharedViewModel.requestAppRestart() or similar mechanism. // This usually involves sharedViewModel.requestAppRestart() or similar mechanism.
} }
@@ -851,7 +836,7 @@ class SettingsViewModel(
} catch (e: Exception) { } catch (e: Exception) {
LogManager.e(TAG, "General error during database restore from URI $restoreUri", e) LogManager.e(TAG, "General error during database restore from URI $restoreUri", e)
val errorMsg = e.localizedMessage ?: "Unknown error" val errorMsg = e.localizedMessage ?: "Unknown error"
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.restore_error_generic, listOf(errorMsg))) sharedViewModel.showSnackbar(R.string.restore_error_generic, listOf(errorMsg))
} finally { } finally {
// Re-open the database regardless of success, unless app is restarting // Re-open the database regardless of success, unless app is restarting
// If an app restart is requested, reopening might not be necessary or could cause issues. // If an app restart is requested, reopening might not be necessary or could cause issues.
@@ -867,7 +852,7 @@ class SettingsViewModel(
LogManager.i(TAG, "Database re-opened after restore attempt.") LogManager.i(TAG, "Database re-opened after restore attempt.")
} catch (reopenError: Exception) { } catch (reopenError: Exception) {
LogManager.e(TAG, "Error re-opening database after restore attempt. App restart is highly recommended.", reopenError) LogManager.e(TAG, "Error re-opening database after restore attempt. App restart is highly recommended.", reopenError)
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.restore_error_generic, listOf("Error re-opening database."))) sharedViewModel.showSnackbar(R.string.restore_error_generic, listOf("Error re-opening database."))
} }
} }
_isLoadingRestore.value = false _isLoadingRestore.value = false
@@ -915,17 +900,17 @@ class SettingsViewModel(
if (databaseDeleted) { if (databaseDeleted) {
LogManager.i(TAG, "Entire database '$dbName' (and associated files: shm=$shmDeleted, wal=$walDeleted) successfully deleted.") LogManager.i(TAG, "Entire database '$dbName' (and associated files: shm=$shmDeleted, wal=$walDeleted) successfully deleted.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.delete_db_successful)) sharedViewModel.showSnackbar(R.string.delete_db_successful)
// App must be restarted as the database is gone. // App must be restarted as the database is gone.
// TODO sharedViewModel.requestAppRestart() // TODO sharedViewModel.requestAppRestart()
} else { } else {
LogManager.e(TAG, "Failed to delete the entire database '$dbName'. deleteDatabase returned false.") LogManager.e(TAG, "Failed to delete the entire database '$dbName'. deleteDatabase returned false.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.delete_db_error)) sharedViewModel.showSnackbar(R.string.delete_db_error)
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
LogManager.e(TAG, "Error during entire database deletion process.", e) LogManager.e(TAG, "Error during entire database deletion process.", e)
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.delete_db_error)) sharedViewModel.showSnackbar(R.string.delete_db_error)
} finally { } finally {
// No need to reopen DB here as it's supposed to be deleted. // No need to reopen DB here as it's supposed to be deleted.
// If deletion failed, the app state is uncertain, restart is still best. // If deletion failed, the app state is uncertain, restart is still best.
@@ -967,11 +952,11 @@ class SettingsViewModel(
repository.deleteUser(user) repository.deleteUser(user)
LogManager.i(TAG, "User '${user.name}' (ID: ${user.id}) and their data deleted successfully.") LogManager.i(TAG, "User '${user.name}' (ID: ${user.id}) and their data deleted successfully.")
// Optionally, emit a success message or trigger UI refresh // Optionally, emit a success message or trigger UI refresh
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.user_deleted_successfully, listOf(user.name))) sharedViewModel.showSnackbar(R.string.user_deleted_successfully, listOf(user.name))
// sharedViewModel.refreshUsers() // Or handle user list updates through SharedViewModel // sharedViewModel.refreshUsers() // Or handle user list updates through SharedViewModel
} catch (e: Exception) { } catch (e: Exception) {
LogManager.e(TAG, "Error deleting user '${user.name}' (ID: ${user.id})", e) LogManager.e(TAG, "Error deleting user '${user.name}' (ID: ${user.id})", e)
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.user_deleted_error, listOf(user.name))) sharedViewModel.showSnackbar(R.string.user_deleted_error, listOf(user.name))
} }
} }
} }
@@ -988,11 +973,11 @@ class SettingsViewModel(
repository.updateUser(user) repository.updateUser(user)
LogManager.i(TAG, "User '${user.name}' (ID: ${user.id}) updated successfully.") LogManager.i(TAG, "User '${user.name}' (ID: ${user.id}) updated successfully.")
// Optionally, emit a success message or trigger UI refresh // Optionally, emit a success message or trigger UI refresh
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.user_updated_successfully, listOf(user.name))) sharedViewModel.showSnackbar(R.string.user_updated_successfully, listOf(user.name))
// sharedViewModel.refreshUsers() // sharedViewModel.refreshUsers()
} catch (e: Exception) { } catch (e: Exception) {
LogManager.e(TAG, "Error updating user '${user.name}' (ID: ${user.id})", e) LogManager.e(TAG, "Error updating user '${user.name}' (ID: ${user.id})", e)
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.user_updated_error, listOf(user.name))) sharedViewModel.showSnackbar(R.string.user_updated_error, listOf(user.name))
} }
} }
@@ -1009,12 +994,12 @@ class SettingsViewModel(
try { try {
repository.insertMeasurementType(type) repository.insertMeasurementType(type)
LogManager.i(TAG, "Measurement type '${type.key}' added successfully.") LogManager.i(TAG, "Measurement type '${type.key}' added successfully.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.measurement_type_added_successfully, listOf(type.key.toString()))) sharedViewModel.showSnackbar(R.string.measurement_type_added_successfully, listOf(type.key.toString()))
// Optionally, trigger a refresh of measurement types if displayed // Optionally, trigger a refresh of measurement types if displayed
// sharedViewModel.refreshMeasurementTypes() // sharedViewModel.refreshMeasurementTypes()
} catch (e: Exception) { } catch (e: Exception) {
LogManager.e(TAG, "Error adding measurement type '${type.key}'", e) LogManager.e(TAG, "Error adding measurement type '${type.key}'", e)
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.measurement_type_added_error, listOf(type.key.toString()))) sharedViewModel.showSnackbar(R.string.measurement_type_added_error, listOf(type.key.toString()))
} }
} }
} }
@@ -1035,11 +1020,11 @@ class SettingsViewModel(
// Ensure this is handled correctly based on your app's requirements. // Ensure this is handled correctly based on your app's requirements.
repository.deleteMeasurementType(type) repository.deleteMeasurementType(type)
LogManager.i(TAG, "Measurement type (ID: ${type.id}) deleted successfully.") LogManager.i(TAG, "Measurement type (ID: ${type.id}) deleted successfully.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.measurement_type_deleted_successfully, listOf(type.key.toString()))) sharedViewModel.showSnackbar(R.string.measurement_type_deleted_successfully, listOf(type.key.toString()))
// sharedViewModel.refreshMeasurementTypes() // sharedViewModel.refreshMeasurementTypes()
} catch (e: Exception) { } catch (e: Exception) {
LogManager.e(TAG, "Error deleting measurement type (ID: ${type.id})", e) LogManager.e(TAG, "Error deleting measurement type (ID: ${type.id})", e)
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.measurement_type_deleted_error, listOf(type.key.toString()))) sharedViewModel.showSnackbar(R.string.measurement_type_deleted_error, listOf(type.key.toString()))
} }
} }
} }
@@ -1056,11 +1041,11 @@ class SettingsViewModel(
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.")
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.measurement_type_updated_successfully, listOf(type.key.toString()))) 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)
_uiMessageEvents.emit(UiMessageEvent.Resource(R.string.measurement_type_updated_error, listOf(type.key.toString()))) sharedViewModel.showSnackbar(R.string.measurement_type_updated_error, listOf(type.key.toString()))
} }
} }
} }