From a87cd97df08a1567039a4b36b097a056eb2515e9 Mon Sep 17 00:00:00 2001 From: Alonso Date: Fri, 20 Dec 2024 05:59:37 +0100 Subject: [PATCH] fix: buggy at edit release --- .../com/android/periodpals/MainActivity.kt | 2 - .../model/user/UserModelPowerSync.kt | 155 ++++++------ .../periodpals/model/user/UserViewModel.kt | 238 +++++++++--------- 3 files changed, 205 insertions(+), 190 deletions(-) diff --git a/app/src/main/java/com/android/periodpals/MainActivity.kt b/app/src/main/java/com/android/periodpals/MainActivity.kt index 4d4dec8e..110be358 100644 --- a/app/src/main/java/com/android/periodpals/MainActivity.kt +++ b/app/src/main/java/com/android/periodpals/MainActivity.kt @@ -70,7 +70,6 @@ import io.github.jan.supabase.auth.Auth import io.github.jan.supabase.createSupabaseClient import io.github.jan.supabase.postgrest.Postgrest import io.github.jan.supabase.storage.Storage -import kotlinx.coroutines.runBlocking import org.osmdroid.config.Configuration private const val TAG = "MainActivity" @@ -209,7 +208,6 @@ fun PeriodPalsApp( val dbDriverFactory = rememberDatabaseDriverFactory() val db = remember { PowerSyncDatabase(dbDriverFactory, schema = localSchema) } val supabaseConnector = remember { SupabaseConnector(supabase, BuildConfig.POWERSYNC_URL) } - runBlocking { db.connect(supabaseConnector) } val userModelPowerSync = remember { UserModelPowerSync(db, supabaseConnector, supabase) } val userViewModelPowerSync = remember { UserViewModel(userModelPowerSync) } diff --git a/app/src/main/java/com/android/periodpals/model/user/UserModelPowerSync.kt b/app/src/main/java/com/android/periodpals/model/user/UserModelPowerSync.kt index 1707ad89..46b28be7 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserModelPowerSync.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserModelPowerSync.kt @@ -20,9 +20,9 @@ private const val TAG = "UserModelPowerSync" private const val USERS = "users" class UserModelPowerSync( - private val db: PowerSyncDatabase, - private val connector: SupabaseConnector, - private val supabase: SupabaseClient + private val db: PowerSyncDatabase, + private val connector: SupabaseConnector, + private val supabase: SupabaseClient ) : UserRepository { private suspend fun sync() { @@ -35,24 +35,27 @@ class UserModelPowerSync( } override suspend fun loadUserProfile( - idUser: String, - onSuccess: (UserDto) -> Unit, - onFailure: (Exception) -> Unit + idUser: String, + onSuccess: (UserDto) -> Unit, + onFailure: (Exception) -> Unit ) { try { + db.connect(connector) sync() val user: UserDto = - db.get( - "SELECT name, imageUrl, description, dob, preferred_distance, fcm_token, locationGIS FROM $USERS WHERE user_id = ?", - listOf(idUser)) { - UserDto( - name = it.getString(0)!!, - imageUrl = it.getString(1)!!, - description = it.getString(2)!!, - dob = it.getString(3)!!, - preferred_distance = it.getLong(4)!!.toInt(), - fcm_token = it.getString(5)) - } + db.get( + "SELECT name, imageUrl, description, dob, preferred_distance, fcm_token FROM $USERS WHERE user_id = ?", + listOf(idUser) + ) { + UserDto( + name = it.getString(0)!!, + imageUrl = it.getString(1)!!, + description = it.getString(2)!!, + dob = it.getString(3)!!, + preferred_distance = it.getLong(4)!!.toInt(), + fcm_token = it.getString(5) + ) + } Log.d(TAG, "loadUserProfile: Success") onSuccess(user) @@ -63,23 +66,26 @@ class UserModelPowerSync( } override suspend fun loadUserProfiles( - onSuccess: (List) -> Unit, - onFailure: (Exception) -> Unit + onSuccess: (List) -> Unit, + onFailure: (Exception) -> Unit ) { try { + db.connect(connector) sync() val users: List = - db.getAll( - "SELECT name, imageUrl, description, dob, preferred_distance, fcm_token, locationGIS FROM $USERS", - listOf()) { - UserDto( - name = it.getString(0)!!, - imageUrl = it.getString(1)!!, - description = it.getString(2)!!, - dob = it.getString(3)!!, - preferred_distance = it.getLong(4)!!.toInt(), - fcm_token = it.getString(5)) - } + db.getAll( + "SELECT name, imageUrl, description, dob, preferred_distance, fcm_token, locationGIS FROM $USERS", + listOf() + ) { + UserDto( + name = it.getString(0)!!, + imageUrl = it.getString(1)!!, + description = it.getString(2)!!, + dob = it.getString(3)!!, + preferred_distance = it.getLong(4)!!.toInt(), + fcm_token = it.getString(5) + ) + } Log.d(TAG, "loadUserProfiles: Success") onSuccess(users) @@ -90,15 +96,17 @@ class UserModelPowerSync( } override suspend fun createUserProfile( - user: User, - onSuccess: () -> Unit, - onFailure: (Exception) -> Unit + user: User, + onSuccess: () -> Unit, + onFailure: (Exception) -> Unit ) { try { + db.connect(connector) db.writeTransaction { tx -> tx.execute( - "INSERT INTO $USERS (name, imageUrl, description, dob, preferred_distance, fcm_token) VALUES (?, ?, ?, ?, ?, ?);", - user.asList()) + "INSERT INTO $USERS (name, imageUrl, description, dob, preferred_distance, fcm_token) VALUES (?, ?, ?, ?, ?, ?);", + user.asList() + ) } Log.d(TAG, "createUserProfile: Success") onSuccess() @@ -110,35 +118,42 @@ class UserModelPowerSync( } override suspend fun upsertUserProfile( - userDto: UserDto, - onSuccess: (UserDto) -> Unit, - onFailure: (Exception) -> Unit + userDto: UserDto, + onSuccess: (UserDto) -> Unit, + onFailure: (Exception) -> Unit ) { try { + db.connect(connector) val currUser: String? = supabase.auth.currentUserOrNull()?.id - + Log.d(TAG, "b4") + sync() db.writeTransaction { tx -> tx.execute( - """ - INSERT INTO $USERS (user_id, name, imageUrl, description, dob, preferred_distance, fcm_token) - VALUES (?, ?, ?, ?, ?, ?, ?) - ON CONFLICT (user_id) - DO UPDATE SET name = ?, imageUrl = ?, description = ?, dob = ?, preferred_distance = ?, fcm_token = ?; + """ + INSERT INTO $USERS(user_id, name, imageUrl, description, dob, preferred_distance, fcm_token) + VALUES(?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(user_id) + DO + UPDATE SET name = ?, imageUrl = ?, description = ?, dob = ?, preferred_distance = ?, fcm_token = ? + WHERE user_id = ?; """, - listOf( - currUser, - userDto.name, - userDto.imageUrl, - userDto.description, - userDto.dob, - userDto.preferred_distance, - userDto.fcm_token, - userDto.name, - userDto.imageUrl, - userDto.description, - userDto.dob, - userDto.preferred_distance, - userDto.fcm_token)) + listOf( + currUser, + userDto.name, + userDto.imageUrl, + userDto.description, + userDto.dob, + userDto.preferred_distance, + userDto.fcm_token, + userDto.name, + userDto.imageUrl, + userDto.description, + userDto.dob, + userDto.preferred_distance, + userDto.fcm_token, + currUser + ) + ) } Log.d(TAG, "upsertUserProfile: Success") sync() @@ -150,14 +165,14 @@ class UserModelPowerSync( } override suspend fun deleteUserProfile( - idUser: String, - onSuccess: () -> Unit, - onFailure: (Exception) -> Unit + idUser: String, + onSuccess: () -> Unit, + onFailure: (Exception) -> Unit ) { try { val currUser = - supabase.auth.currentUserOrNull()?.id - ?: throw Exception("Supabase does not have a user logged in") + supabase.auth.currentUserOrNull()?.id + ?: throw Exception("Supabase does not have a user logged in") db.writeTransaction { tx -> tx.execute("DELETE FROM $USERS WHERE user_id = ?", listOf(currUser)) @@ -172,10 +187,10 @@ class UserModelPowerSync( } override suspend fun uploadFile( - filePath: String, - bytes: ByteArray, - onSuccess: () -> Unit, - onFailure: (Exception) -> Unit, + filePath: String, + bytes: ByteArray, + onSuccess: () -> Unit, + onFailure: (Exception) -> Unit, ) { try { withContext(Dispatchers.Main) { @@ -190,9 +205,9 @@ class UserModelPowerSync( } override suspend fun downloadFile( - filePath: String, - onSuccess: (bytes: ByteArray) -> Unit, - onFailure: (Exception) -> Unit, + filePath: String, + onSuccess: (bytes: ByteArray) -> Unit, + onFailure: (Exception) -> Unit, ) { try { withContext(Dispatchers.Main) { diff --git a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt index cb763341..26d73f85 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt @@ -8,11 +8,11 @@ import androidx.lifecycle.viewModelScope import com.dsc.form_builder.FormState import com.dsc.form_builder.TextFieldState import com.dsc.form_builder.Validators +import kotlinx.coroutines.launch import java.text.DateFormat import java.time.LocalDate import java.time.format.DateTimeFormatter import java.util.Locale -import kotlinx.coroutines.launch private const val TAG = "UserViewModel" @@ -24,28 +24,28 @@ private const val ERROR_INVALID_NAME = "Please enter a name" private const val ERROR_NAME_TOO_LONG = "Name must be less than $MAX_NAME_LENGTH characters" private const val ERROR_INVALID_DESCRIPTION = "Please enter a description" private const val ERROR_DESCRIPTION_TOO_LONG = - "Description must be less than $MAX_DESCRIPTION_LENGTH characters" + "Description must be less than $MAX_DESCRIPTION_LENGTH characters" private const val ERROR_INVALID_DOB = "Please enter a valid date" private const val ERROR_TOO_YOUNG = "You must be at least $MIN_AGE years old" private val nameValidators = - listOf( - Validators.Required(message = ERROR_INVALID_NAME), - Validators.Max(message = ERROR_NAME_TOO_LONG, limit = MAX_NAME_LENGTH), - ) + listOf( + Validators.Required(message = ERROR_INVALID_NAME), + Validators.Max(message = ERROR_NAME_TOO_LONG, limit = MAX_NAME_LENGTH), + ) private val descriptionValidators = - listOf( - Validators.Required(message = ERROR_INVALID_DESCRIPTION), - Validators.Max(message = ERROR_DESCRIPTION_TOO_LONG, limit = MAX_DESCRIPTION_LENGTH), - ) + listOf( + Validators.Required(message = ERROR_INVALID_DESCRIPTION), + Validators.Max(message = ERROR_DESCRIPTION_TOO_LONG, limit = MAX_DESCRIPTION_LENGTH), + ) private val dobValidators = - listOf( - Validators.Required(message = ERROR_INVALID_DOB), - Validators.Custom(message = ERROR_INVALID_DOB, function = { validateDate(it as String) }), - Validators.Custom(message = ERROR_TOO_YOUNG, function = { isOldEnough(it as String) }), - ) + listOf( + Validators.Required(message = ERROR_INVALID_DOB), + Validators.Custom(message = ERROR_INVALID_DOB, function = { validateDate(it as String) }), + Validators.Custom(message = ERROR_TOO_YOUNG, function = { isOldEnough(it as String) }), + ) private val profileImageValidators = - emptyList() // TODO: add validators when profile image is implemented + emptyList() // TODO: add validators when profile image is implemented /** * ViewModel for managing user data. @@ -68,15 +68,17 @@ class UserViewModel(private val userRepository: UserRepository) : ViewModel() { val avatar: State = _avatar val formState = - FormState( - fields = - listOf( - TextFieldState(name = NAME_STATE_NAME, validators = nameValidators), - TextFieldState(name = DESCRIPTION_STATE_NAME, validators = descriptionValidators), - TextFieldState(name = DOB_STATE_NAME, validators = dobValidators), - TextFieldState( - name = PROFILE_IMAGE_STATE_NAME, validators = profileImageValidators), - )) + FormState( + fields = + listOf( + TextFieldState(name = NAME_STATE_NAME, validators = nameValidators), + TextFieldState(name = DESCRIPTION_STATE_NAME, validators = descriptionValidators), + TextFieldState(name = DOB_STATE_NAME, validators = dobValidators), + TextFieldState( + name = PROFILE_IMAGE_STATE_NAME, validators = profileImageValidators + ), + ) + ) /** * Loads the user profile and updates the user state. @@ -87,25 +89,25 @@ class UserViewModel(private val userRepository: UserRepository) : ViewModel() { * profile. */ fun loadUser( - idUser: String, - onSuccess: () -> Unit = { Log.d(TAG, "loadUser success callback") }, - onFailure: (Exception) -> Unit = { e: Exception -> - Log.d(TAG, "loadUser failure callback: ${e.message}") - }, + idUser: String, + onSuccess: () -> Unit = { Log.d(TAG, "loadUser success callback") }, + onFailure: (Exception) -> Unit = { e: Exception -> + Log.d(TAG, "loadUser failure callback: ${e.message}") + }, ) { viewModelScope.launch { userRepository.loadUserProfile( - idUser, - onSuccess = { userDto -> - Log.d(TAG, "loadUserProfile: Successful") - _user.value = userDto.asUser() - onSuccess() - }, - onFailure = { e: Exception -> - Log.d(TAG, "loadUserProfile: fail to load user profile: ${e.message}") - _user.value = null - onFailure(e) - }, + idUser, + onSuccess = { userDto -> + Log.d(TAG, "loadUserProfile: Successful") + _user.value = userDto.asUser() + onSuccess() + }, + onFailure = { e: Exception -> + Log.d(TAG, "loadUserProfile: fail to load user profile: ${e.message}") + //_user.value = null + onFailure(e) + }, ) } } @@ -118,23 +120,23 @@ class UserViewModel(private val userRepository: UserRepository) : ViewModel() { * profiles. */ fun loadUsers( - onSuccess: () -> Unit = { Log.d(TAG, "loadUsers success callback") }, - onFailure: (Exception) -> Unit = { e: Exception -> - Log.d(TAG, "loadUsers failure callback: ${e.message}") - }, + onSuccess: () -> Unit = { Log.d(TAG, "loadUsers success callback") }, + onFailure: (Exception) -> Unit = { e: Exception -> + Log.d(TAG, "loadUsers failure callback: ${e.message}") + }, ) { viewModelScope.launch { userRepository.loadUserProfiles( - onSuccess = { userDtos -> - Log.d(TAG, "loadUsers: Successful") - _users.value = userDtos.map { it.asUser() } - onSuccess() - }, - onFailure = { e: Exception -> - Log.d(TAG, "loadUsers: fail to load user profiles: ${e.message}") - _users.value = null - onFailure(e) - }, + onSuccess = { userDtos -> + Log.d(TAG, "loadUsers: Successful") + _users.value = userDtos.map { it.asUser() } + onSuccess() + }, + onFailure = { e: Exception -> + Log.d(TAG, "loadUsers: fail to load user profiles: ${e.message}") + //_users.value = null + onFailure(e) + }, ) } } @@ -147,25 +149,25 @@ class UserViewModel(private val userRepository: UserRepository) : ViewModel() { * @param onFailure Callback function to be called when there is an error saving the user profile. */ fun saveUser( - user: User, - onSuccess: () -> Unit = { Log.d(TAG, "saveUser success callback") }, - onFailure: (Exception) -> Unit = { e: Exception -> - Log.d(TAG, "saveUser failure callback: ${e.message}") - }, + user: User, + onSuccess: () -> Unit = { Log.d(TAG, "saveUser success callback") }, + onFailure: (Exception) -> Unit = { e: Exception -> + Log.d(TAG, "saveUser failure callback: ${e.message}") + }, ) { viewModelScope.launch { userRepository.upsertUserProfile( - user.asUserDto(), - onSuccess = { - Log.d(TAG, "saveUser: Success") - _user.value = it.asUser() - onSuccess() - }, - onFailure = { e: Exception -> - Log.d(TAG, "saveUser: fail to save user: ${e.message}") - _user.value = null - onFailure(e) - }, + user.asUserDto(), + onSuccess = { + Log.d(TAG, "saveUser: Success") + _user.value = it.asUser() + onSuccess() + }, + onFailure = { e: Exception -> + Log.d(TAG, "saveUser: fail to save user: ${e.message}") + //_user.value = null + onFailure(e) + }, ) } } @@ -179,24 +181,24 @@ class UserViewModel(private val userRepository: UserRepository) : ViewModel() { * profile. */ fun deleteUser( - idUser: String, - onSuccess: () -> Unit = { Log.d(TAG, "deleteAccount success callback") }, - onFailure: (Exception) -> Unit = { e: Exception -> - Log.d(TAG, "deleteAccount failure callback: ${e.message}") - }, + idUser: String, + onSuccess: () -> Unit = { Log.d(TAG, "deleteAccount success callback") }, + onFailure: (Exception) -> Unit = { e: Exception -> + Log.d(TAG, "deleteAccount failure callback: ${e.message}") + }, ) { viewModelScope.launch { userRepository.deleteUserProfile( - idUser, - onSuccess = { - Log.d(TAG, "deleteAccount: Success") - _user.value = null - onSuccess() - }, - onFailure = { e: Exception -> - Log.d(TAG, "deleteAccount : fail to delete user: ${e.message}") - onFailure(e) - }, + idUser, + onSuccess = { + Log.d(TAG, "deleteAccount: Success") + _user.value = null + onSuccess() + }, + onFailure = { e: Exception -> + Log.d(TAG, "deleteAccount : fail to delete user: ${e.message}") + onFailure(e) + }, ) } } @@ -210,25 +212,25 @@ class UserViewModel(private val userRepository: UserRepository) : ViewModel() { * @param onFailure Callback function to be called when there is an exception. */ fun uploadFile( - filePath: String, - bytes: ByteArray, - onSuccess: () -> Unit = { Log.d(TAG, "uploadFile success callback") }, - onFailure: (Exception) -> Unit = { e: Exception -> - Log.d(TAG, "uploadFile failure callback: ${e.message}") - }, + filePath: String, + bytes: ByteArray, + onSuccess: () -> Unit = { Log.d(TAG, "uploadFile success callback") }, + onFailure: (Exception) -> Unit = { e: Exception -> + Log.d(TAG, "uploadFile failure callback: ${e.message}") + }, ) { viewModelScope.launch { userRepository.uploadFile( - filePath, - bytes, - onSuccess = { - Log.d(TAG, "uploadFile: Success") - onSuccess() - }, - onFailure = { e: Exception -> - Log.d(TAG, "uploadFile: fail to upload file: ${e.message}") - onFailure(e) - }, + filePath, + bytes, + onSuccess = { + Log.d(TAG, "uploadFile: Success") + onSuccess() + }, + onFailure = { e: Exception -> + Log.d(TAG, "uploadFile: fail to upload file: ${e.message}") + onFailure(e) + }, ) } } @@ -241,24 +243,24 @@ class UserViewModel(private val userRepository: UserRepository) : ViewModel() { * @param onFailure Callback function to be called when there is an exception. */ fun downloadFile( - filePath: String, - onSuccess: () -> Unit = { Log.d(TAG, "downloadFile success callback") }, - onFailure: (Exception) -> Unit = { e: Exception -> - Log.d(TAG, "downloadFile failure callback: ${e.message}") - }, + filePath: String, + onSuccess: () -> Unit = { Log.d(TAG, "downloadFile success callback") }, + onFailure: (Exception) -> Unit = { e: Exception -> + Log.d(TAG, "downloadFile failure callback: ${e.message}") + }, ) { viewModelScope.launch { userRepository.downloadFile( - filePath, - onSuccess = { bytes -> - Log.d(TAG, "downloadFile: Success") - _avatar.value = bytes - onSuccess() - }, - onFailure = { e: Exception -> - Log.d(TAG, "downloadFile: fail to download file: ${e.message}") - onFailure(e) - }, + filePath, + onSuccess = { bytes -> + Log.d(TAG, "downloadFile: Success") + _avatar.value = bytes + onSuccess() + }, + onFailure = { e: Exception -> + Log.d(TAG, "downloadFile: fail to download file: ${e.message}") + onFailure(e) + }, ) } } @@ -290,7 +292,7 @@ fun validateDate(date: String): Boolean { fun isOldEnough(date: String): Boolean { return try { LocalDate.parse(date, DateTimeFormatter.ofPattern("dd/MM/yyyy")) - .isBefore(LocalDate.now().minusYears(MIN_AGE)) + .isBefore(LocalDate.now().minusYears(MIN_AGE)) } catch (e: Exception) { false }