Skip to content

Commit

Permalink
fix: solve merge conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
lazarinibruno committed Dec 20, 2024
2 parents 8648e6a + 54d1a4e commit 3d3e18f
Show file tree
Hide file tree
Showing 22 changed files with 703 additions and 397 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.GrantPermissionRule
import com.android.periodpals.model.authentication.AuthenticationViewModel
import com.android.periodpals.model.location.Location
import com.android.periodpals.model.location.UserLocationViewModel
import com.android.periodpals.model.user.AuthenticationUserData
import com.android.periodpals.model.user.UserViewModel
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
import org.junit.After
Expand All @@ -36,7 +36,7 @@ class GPSServiceImplInstrumentedTest {
private lateinit var activity: ComponentActivity
private lateinit var gpsService: GPSServiceImpl
private lateinit var authenticationViewModel: AuthenticationViewModel
private lateinit var userViewModel: UserViewModel
private lateinit var userLocationViewModel: UserLocationViewModel

// Default location
private val defaultLat = Location.DEFAULT_LOCATION.latitude
Expand All @@ -45,7 +45,7 @@ class GPSServiceImplInstrumentedTest {
@Before
fun setup() {
authenticationViewModel = mock(AuthenticationViewModel::class.java)
userViewModel = mock(UserViewModel::class.java)
userLocationViewModel = mock(UserLocationViewModel::class.java)

scenario = ActivityScenario.launch(ComponentActivity::class.java)

Expand All @@ -55,7 +55,7 @@ class GPSServiceImplInstrumentedTest {

scenario.onActivity { activity ->
this.activity = activity
gpsService = GPSServiceImpl(this.activity, authenticationViewModel, userViewModel)
gpsService = GPSServiceImpl(this.activity, authenticationViewModel, userLocationViewModel)
}

// Once the GPSService has been initialized, set its state to resumed
Expand Down
14 changes: 8 additions & 6 deletions app/src/main/java/com/android/periodpals/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import com.android.periodpals.model.authentication.AuthenticationModelSupabase
import com.android.periodpals.model.authentication.AuthenticationViewModel
import com.android.periodpals.model.chat.ChatViewModel
import com.android.periodpals.model.location.LocationViewModel
import com.android.periodpals.model.location.UserLocationModelSupabase
import com.android.periodpals.model.location.UserLocationViewModel
import com.android.periodpals.model.timer.TimerManager
import com.android.periodpals.model.timer.TimerRepositorySupabase
import com.android.periodpals.model.timer.TimerViewModel
Expand Down Expand Up @@ -90,6 +92,9 @@ class MainActivity : ComponentActivity() {
private val userModel = UserRepositorySupabase(supabaseClient)
private val userViewModel = UserViewModel(userModel)

private val userLocationModel = UserLocationModelSupabase(supabaseClient)
private val userLocationViewModel = UserLocationViewModel(userLocationModel)

private val alertModel = AlertModelSupabase(supabaseClient)
private val alertViewModel = AlertViewModel(alertModel)

Expand All @@ -100,7 +105,7 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

gpsService = GPSServiceImpl(this, authenticationViewModel, userViewModel)
gpsService = GPSServiceImpl(this, authenticationViewModel, userLocationViewModel)
pushNotificationsService =
PushNotificationsServiceImpl(this, authenticationViewModel, userViewModel)
timerManager = TimerManager(this)
Expand All @@ -115,10 +120,7 @@ class MainActivity : ComponentActivity() {
GoogleApiAvailability.getInstance().makeGooglePlayServicesAvailable(this)

// Set up the OfflinePlugin for offline storage
val offlinePluginFactory =
StreamOfflinePluginFactory(
appContext = applicationContext,
)
val offlinePluginFactory = StreamOfflinePluginFactory(appContext = applicationContext)
val statePluginFactory =
StreamStatePluginFactory(config = StatePluginConfig(), appContext = this)

Expand Down Expand Up @@ -180,7 +182,7 @@ class MainActivity : ComponentActivity() {
*/
fun userAuthStateLogic(
authenticationViewModel: AuthenticationViewModel,
navigationActions: NavigationActions
navigationActions: NavigationActions,
) {
when (authenticationViewModel.userAuthenticationState.value) {
is UserAuthenticationState.SuccessIsLoggedIn -> navigationActions.navigateTo(Screen.PROFILE)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.android.periodpals.model.location

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
* Data Transfer Object (DTO) representing a user's location.
*
* @property uid The unique identifier of the user.
* @property location The geographical location of the user.
*/
@Serializable
data class UserLocationDto(
@SerialName("uid") val uid: String,
@SerialName("locationGIS") val location: LocationGIS,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.android.periodpals.model.location

/** Interface representing a model for user location. */
interface UserLocationModel {

/**
* Creates a new location.
*
* @param locationDto The [Location] data transfer object to be inserted.
* @param onSuccess A callback function to be invoked upon successful operation.
* @param onFailure A callback function to be invoked with an `Exception` if the operation fails.
*/
suspend fun create(
locationDto: UserLocationDto,
onSuccess: () -> Unit,
onFailure: (Exception) -> Unit,
)

/**
* Inserts or updates a location.
*
* @param locationDto The [Location] data transfer object to be inserted or updated.
* @param onSuccess A callback function to be invoked upon successful operation.
* @param onFailure A callback function to be invoked with an `Exception` if the operation fails.
*/
suspend fun update(
locationDto: UserLocationDto,
onSuccess: () -> Unit,
onFailure: (Exception) -> Unit,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.android.periodpals.model.location

import android.util.Log
import io.github.jan.supabase.SupabaseClient
import io.github.jan.supabase.postgrest.postgrest
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

/**
* Implementation of the UserLocationModel interface using Supabase.
*
* @property supabase The Supabase client used for database operations.
*/
class UserLocationModelSupabase(private val supabase: SupabaseClient) : UserLocationModel {

companion object {
private const val TAG = "UserLocationModelSupabase"
private const val LOCATIONS = "locations"
}

/**
* Creates a new location in the Supabase database.
*
* @param locationDto The [LocationGIS] data transfer object to be inserted.
* @param onSuccess A callback function to be invoked upon successful operation.
* @param onFailure A callback function to be invoked with an Exception if the operation fails.
*/
override suspend fun create(
locationDto: UserLocationDto,
onSuccess: () -> Unit,
onFailure: (Exception) -> Unit,
) {
Log.d(TAG, "create: sending location dto: $locationDto")
try {
withContext(Dispatchers.IO) {
supabase.postgrest[LOCATIONS].insert(locationDto)
Log.d(TAG, "create: success")
onSuccess()
}
} catch (e: Exception) {
Log.e(TAG, "create: fail to create location of user ${locationDto.uid}: ${e.message}")
onFailure(e)
}
}

/**
* Updates a location in the Supabase database.
*
* @param locationDto The [LocationGIS] data transfer object to be inserted or updated.
* @param onSuccess A callback function to be invoked upon successful operation.
* @param onFailure A callback function to be invoked with an Exception if the operation fails.
*/
override suspend fun update(
locationDto: UserLocationDto,
onSuccess: () -> Unit,
onFailure: (Exception) -> Unit,
) {
Log.d(TAG, "update: sending location dto: $locationDto")
try {
withContext(Dispatchers.IO) {
supabase.postgrest[LOCATIONS].update(locationDto) { filter { eq("uid", locationDto.uid) } }
Log.d(TAG, "update: success")
onSuccess()
}
} catch (e: Exception) {
Log.e(TAG, "update: fail to update location of user ${locationDto.uid}: ${e.message}")
onFailure(e)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.android.periodpals.model.location

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch

class UserLocationViewModel(private val userLocationModel: UserLocationModel) : ViewModel() {

companion object {
private const val TAG = "UserLocationViewModel"
}

/**
* Create a user location, or update it if it does already exists.
*
* Note: This implementation does not use upsert for security reasons.
*
* @param uid The unique identifier of the user.
* @param location The new [LocationGIS] of the user.
* @param onSuccess A callback function to be invoked upon successful operation.
* @param onFailure A callback function to be invoked with an `Exception` if the operation fails.
*/
fun uploadUserLocation(
uid: String,
location: LocationGIS,
onSuccess: () -> Unit = { Log.d(TAG, "uploadUserLocation success callback") },
onFailure: (Exception) -> Unit = { e: Exception ->
Log.d(TAG, "uploadUserLocation failure callback: ${e.message}")
},
) {
val locationDto = UserLocationDto(uid = uid, location = location)
viewModelScope.launch {
// try to create a new location
Log.d(TAG, "uploadUserLocation: trying to create location $locationDto for user $uid")
userLocationModel.create(
locationDto = locationDto,
onSuccess = {
Log.d(TAG, "uploadUserLocation: create user location successful")
onSuccess()
},
onFailure = { e: Exception ->
Log.d(TAG, "createUserLocation: location already exists, updating instead")
update(locationDto, onSuccess, onFailure)
},
)
}
}

private fun update(
locationDto: UserLocationDto,
onSuccess: () -> Unit,
onFailure: (Exception) -> Unit,
) {
Log.d(TAG, "update: trying to update location $locationDto")
viewModelScope.launch {
userLocationModel.update(
locationDto = locationDto,
onSuccess = {
Log.d(TAG, "update: update user location successful")
onSuccess()
},
onFailure = { e: Exception ->
Log.d(TAG, "update: failed to upsert location of user ${locationDto.uid}: ${e.message}")
onFailure(e)
},
)
}
}
}
7 changes: 0 additions & 7 deletions app/src/main/java/com/android/periodpals/model/user/User.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package com.android.periodpals.model.user

import com.android.periodpals.model.location.Location
import com.android.periodpals.model.location.LocationGIS
import com.android.periodpals.model.location.parseLocationGIS

/**
* Data class representing a user.
*
Expand All @@ -13,7 +9,6 @@ import com.android.periodpals.model.location.parseLocationGIS
* @property dob The date of birth of the user.
* @property preferredDistance The preferred radius distance for receiving alerts.
* @property fcmToken The Firebase Cloud Messaging token for the user (optional).
* @property locationGIS The geographic location of the user. Default is the default location.
*/
data class User(
val name: String,
Expand All @@ -22,7 +17,6 @@ data class User(
val dob: String,
val preferredDistance: Int,
val fcmToken: String? = null,
val locationGIS: LocationGIS = parseLocationGIS(Location.DEFAULT_LOCATION),
) {
/**
* Converts the User object to a UserDto object.
Expand All @@ -37,7 +31,6 @@ data class User(
dob = this.dob,
preferred_distance = this.preferredDistance,
fcm_token = this.fcmToken,
locationGIS = this.locationGIS,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.android.periodpals.model.user

import com.android.periodpals.model.location.LocationGIS
import kotlinx.serialization.Serializable

/**
Expand All @@ -12,7 +11,6 @@ import kotlinx.serialization.Serializable
* @property dob The age of the user.
* @property preferred_distance The preferred radius distance for receiving alerts.
* @property fcm_token The Firebase Cloud Messaging token for the user (optional).
* @property locationGIS The geographic location of the user.
*/
@Serializable
data class UserDto(
Expand All @@ -22,7 +20,6 @@ data class UserDto(
val dob: String,
val preferred_distance: Int,
val fcm_token: String? = null,
val locationGIS: LocationGIS,
) {
/**
* Converts this UserDto to a User object.
Expand All @@ -37,7 +34,6 @@ data class UserDto(
dob = this.dob,
preferredDistance = this.preferred_distance,
fcmToken = this.fcm_token,
locationGIS = this.locationGIS,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ class UserRepositorySupabase(private val supabase: SupabaseClient) : UserReposit
dob = user.dob,
preferred_distance = user.preferredDistance,
fcm_token = user.fcmToken,
locationGIS = user.locationGIS,
)
supabase.postgrest[USERS].insert(userDto)
}
Expand Down
17 changes: 3 additions & 14 deletions app/src/main/java/com/android/periodpals/resources/C.kt
Original file line number Diff line number Diff line change
Expand Up @@ -175,21 +175,10 @@ object C {

object SettingsScreen {
const val SCREEN = "settingsScreen"
const val NOTIFICATIONS_CONTAINER = "notificationsContainer"
const val THEME_CONTAINER = "themeContainer"
const val REMARK_CONTAINER = "remarkContainer"
const val REMARK_TEXT = "remarkText"
const val SLIDER_CONTAINER = "sliderContainer"
const val ACCOUNT_MANAGEMENT_CONTAINER = "accountManagementContainer"
const val NOTIFICATIONS_DESCRIPTION = "notificationDescription"
const val ORGANIC_DESCRIPTION = "organicDescription"
const val PALS_TEXT = "palsText"
const val PALS_SWITCH = "palsSwitch"
const val HORIZONTAL_DIVIDER = "horizontalDivider"
const val PADS_TEXT = "padsText"
const val PADS_SWITCH = "padsSwitch"
const val TAMPONS_TEXT = "tamponsText"
const val TAMPONS_SWITCH = "tamponsSwitch"
const val ORGANIC_TEXT = "organicText"
const val ORGANIC_SWITCH = "organicSwitch"
const val THEME_DROP_DOWN_MENU_BOX = "themeDropdownMenuBox"
const val THEME_DROP_DOWN_MENU = "themeDropdownMenu"
const val PASSWORD_TEXT = "passwordText"
const val PASSWORD_ICON = "passwordIcon"
Expand Down
Loading

0 comments on commit 3d3e18f

Please sign in to comment.