From 77c1250ddafb47007fee5a0e0f5c2e2b1fc1e617 Mon Sep 17 00:00:00 2001 From: Sneh Date: Mon, 20 Jan 2025 18:34:54 +0530 Subject: [PATCH] added single journey in multiple groups --- .../location/LocationUpdateReceiver.kt | 6 +- .../data/repository/JourneyGenerator.kt | 8 ++ .../data/repository/JourneyRepository.kt | 45 +++++--- .../service/location/ApiJourneyService.kt | 109 +++++++++++------- 4 files changed, 108 insertions(+), 60 deletions(-) diff --git a/data/src/main/java/com/canopas/yourspace/data/receiver/location/LocationUpdateReceiver.kt b/data/src/main/java/com/canopas/yourspace/data/receiver/location/LocationUpdateReceiver.kt index 2d1aa73d..15720864 100644 --- a/data/src/main/java/com/canopas/yourspace/data/receiver/location/LocationUpdateReceiver.kt +++ b/data/src/main/java/com/canopas/yourspace/data/receiver/location/LocationUpdateReceiver.kt @@ -8,6 +8,7 @@ import com.canopas.yourspace.data.service.auth.AuthService import com.canopas.yourspace.data.service.location.ApiJourneyService import com.canopas.yourspace.data.service.location.ApiLocationService import com.canopas.yourspace.data.service.location.LocationManager +import com.canopas.yourspace.data.storage.UserPreferences import com.google.android.gms.location.LocationResult import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope @@ -37,6 +38,9 @@ class LocationUpdateReceiver : BroadcastReceiver() { @Inject lateinit var journeyRepository: JourneyRepository + @Inject + lateinit var userPreferences: UserPreferences + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) override fun onReceive(context: Context, intent: Intent) { @@ -52,7 +56,7 @@ class LocationUpdateReceiver : BroadcastReceiver() { extractedLocation.longitude, System.currentTimeMillis() ) - journeyRepository.saveLocationJourney(extractedLocation, userId) + journeyRepository.saveLocationJourney(extractedLocation, userId, userPreferences) } } catch (e: Exception) { Timber.e(e, "Error while saving location") diff --git a/data/src/main/java/com/canopas/yourspace/data/repository/JourneyGenerator.kt b/data/src/main/java/com/canopas/yourspace/data/repository/JourneyGenerator.kt index 4d919ade..4c450480 100644 --- a/data/src/main/java/com/canopas/yourspace/data/repository/JourneyGenerator.kt +++ b/data/src/main/java/com/canopas/yourspace/data/repository/JourneyGenerator.kt @@ -8,6 +8,7 @@ import com.canopas.yourspace.data.models.location.isSteady import com.canopas.yourspace.data.models.location.toLocationFromMovingJourney import com.canopas.yourspace.data.models.location.toLocationFromSteadyJourney import com.canopas.yourspace.data.models.location.toRoute +import timber.log.Timber import java.util.Calendar import kotlin.math.sqrt @@ -33,6 +34,7 @@ fun getJourney( ): JourneyResult? { // 1. If there is no previous journey, create a new STEADY journey if (lastKnownJourney == null) { + Timber.tag("XXX").e("No previous journey") val newSteadyJourney = LocationJourney( user_id = userId, from_latitude = newLocation.latitude, @@ -54,12 +56,14 @@ fun getJourney( // 3. Determine how far the newLocation is from our reference point val distance = if (lastKnownJourney.isSteady()) { // Compare newLocation with "from" location + Timber.tag("xxx").e("LastKnownJourney = isSteady") distanceBetween( geometricMedian ?: newLocation, lastKnownJourney.toLocationFromSteadyJourney() ) } else { // Compare newLocation with "to" location + Timber.tag("xxx").e("LastKnownJourney = isMoving") distanceBetween( geometricMedian ?: newLocation, lastKnownJourney.toLocationFromMovingJourney() @@ -102,6 +106,7 @@ fun getJourney( // If distance > MIN_DISTANCE => user started moving if (distance > MIN_DISTANCE) { // 1. Update last STEADY journey with new "from" lat/lng + Timber.tag("xxx").e("lastKnownJourney = isSteady && Distance > MIN_DISTANCE") val updatedJourney = lastKnownJourney.copy( from_latitude = newLocation.latitude, from_longitude = newLocation.longitude, @@ -139,6 +144,7 @@ fun getJourney( // If the user likely stopped moving => (timeDifference > MIN_TIME_DIFFERENCE) if (timeDifference > MIN_TIME_DIFFERENCE) { // 1. Update last moving journey + Timber.tag("xxx").e("timeDifference > MIN_TIME_DIFFERENCE") val updatedJourney = lastKnownJourney.copy( to_latitude = newLocation.latitude, to_longitude = newLocation.longitude, @@ -157,10 +163,12 @@ fun getJourney( updated_at = System.currentTimeMillis(), type = JourneyType.STEADY ) + Timber.e("XXX newSteadyJourney = $newSteadyJourney") return JourneyResult(updatedJourney, newSteadyJourney) } // If user is still moving => distance > MIN_DISTANCE_FOR_MOVING, timeDifference > MIN_UPDATE_INTERVAL_MINUTE => update route else if (distance > MIN_DISTANCE_FOR_MOVING && timeDifference > MIN_UPDATE_INTERVAL_MINUTE) { + Timber.e("XXX distance > MIN_DISTANCE_FOR_MOVING && timeDifference > MIN_UPDATE_INTERVAL_MINUTE") val updatedJourney = lastKnownJourney.copy( to_latitude = newLocation.latitude, to_longitude = newLocation.longitude, diff --git a/data/src/main/java/com/canopas/yourspace/data/repository/JourneyRepository.kt b/data/src/main/java/com/canopas/yourspace/data/repository/JourneyRepository.kt index 1e77da61..6741d1c0 100644 --- a/data/src/main/java/com/canopas/yourspace/data/repository/JourneyRepository.kt +++ b/data/src/main/java/com/canopas/yourspace/data/repository/JourneyRepository.kt @@ -4,6 +4,7 @@ import android.location.Location import com.canopas.yourspace.data.models.location.LocationJourney import com.canopas.yourspace.data.service.location.ApiJourneyService import com.canopas.yourspace.data.storage.LocationCache +import com.canopas.yourspace.data.storage.UserPreferences import timber.log.Timber import javax.inject.Inject import javax.inject.Singleton @@ -15,34 +16,40 @@ class JourneyRepository @Inject constructor( ) { suspend fun saveLocationJourney( extractedLocation: Location, - userId: String + userId: String, + userPreferences: UserPreferences ) { try { cacheLocations(extractedLocation, userId) val lastKnownJourney = getLastKnownLocation(userId) - val result = getJourney( - userId = userId, - newLocation = extractedLocation, - lastKnownJourney = lastKnownJourney, - lastLocations = locationCache.getLastFiveLocations(userId) ?: emptyList() - ) - - result?.updatedJourney?.let { journey -> - locationCache.putLastJourney(journey, userId) - journeyService.updateJourney( + val spaceIds = userPreferences.currentUser?.space_ids ?: emptyList() + spaceIds.forEach { spaceId -> + val result = getJourney( userId = userId, - journey = journey + newLocation = extractedLocation, + lastKnownJourney = lastKnownJourney, + lastLocations = locationCache.getLastFiveLocations(userId) ?: emptyList() ) - } - result?.newJourney?.let { journey -> - val currentJourney = journeyService.addJourney( - userId = userId, - newJourney = journey - ) - locationCache.putLastJourney(currentJourney, userId) + result?.updatedJourney?.let { journey -> + locationCache.putLastJourney(journey, userId) + journeyService.updateJourney( + userId = userId, + journey = journey, + spaceId = spaceId + ) + } + + result?.newJourney?.let { journey -> + val currentJourney = journeyService.addJourney( + userId = userId, + newJourney = journey, + spaceId = spaceId + ) + locationCache.putLastJourney(currentJourney, userId) + } } } catch (e: Exception) { Timber.e(e, "Error while saving location journey") diff --git a/data/src/main/java/com/canopas/yourspace/data/service/location/ApiJourneyService.kt b/data/src/main/java/com/canopas/yourspace/data/service/location/ApiJourneyService.kt index efdf64e9..8b6d1f42 100644 --- a/data/src/main/java/com/canopas/yourspace/data/service/location/ApiJourneyService.kt +++ b/data/src/main/java/com/canopas/yourspace/data/service/location/ApiJourneyService.kt @@ -88,7 +88,11 @@ class ApiJourneyService @Inject constructor( return try { GroupSessionBuilder(bufferedSenderKeyStore).process(groupAddress, distributionMessage) - Triple(distributionMessage, GroupCipher(bufferedSenderKeyStore, groupAddress), distribution.id) + Triple( + distributionMessage, + GroupCipher(bufferedSenderKeyStore, groupAddress), + distribution.id + ) } catch (e: Exception) { Timber.e(e, "Error processing group session") null @@ -140,64 +144,89 @@ class ApiJourneyService @Inject constructor( */ suspend fun addJourney( userId: String, - newJourney: LocationJourney + newJourney: LocationJourney, + spaceId: String ): LocationJourney { var journey: LocationJourney = newJourney - userPreferences.currentUser?.space_ids?.forEach { spaceId -> - val groupKeysDoc = getGroupKeyDoc(spaceId) ?: return@forEach - - val (distributionMessage, groupCipher, keyId) = getGroupCipherByKeyId( - spaceId, - userId, - null, - groupKeysDoc - ) - ?: run { - Timber.e("Failed to get group cipher") + + // Iterate through all spaces the user belongs to + userPreferences.currentUser?.space_ids?.forEach { _ -> + val groupKeysDoc = getGroupKeyDoc(spaceId) ?: run { + Timber.e("xxx Failed to get group keys for space $spaceId") + return@forEach + } + + groupKeysDoc.member_keys.forEach { memberId -> + // Fetch group cipher for the group and the user + val (distributionMessage, groupCipher, keyId) = getGroupCipherByKeyId( + spaceId, + userId, + null, + groupKeysDoc + ) ?: run { + Timber.e("xxx Failed to get group cipher for group $memberId") return@forEach } - val docRef = spaceMemberJourneyRef(spaceId, userId).document(newJourney.id) + val docRef = spaceMemberJourneyRef(spaceId, userId).document(newJourney.id) - journey = newJourney.copy(id = docRef.id, key_id = keyId) + // Update the journey ID and key ID for the new space and member + journey = newJourney.copy(id = docRef.id, key_id = keyId) - val encryptedJourney = - journey.toEncryptedLocationJourney(groupCipher, distributionMessage.distributionId) + // Encrypt the journey + val encryptedJourney = journey.toEncryptedLocationJourney( + groupCipher, + distributionMessage.distributionId + ) - encryptedJourney?.let { docRef.set(it).await() } + // Save the encrypted journey to the document + encryptedJourney?.let { docRef.set(it).await() } + Timber.d("xxx Added journey to group $memberId in space $spaceId") + } } + + // After the iteration, return the updated journey (could be updated multiple times for different spaces) return journey } /** * Updates the last [LocationJourney] for [userId]. */ - suspend fun updateJourney(userId: String, journey: LocationJourney) { - userPreferences.currentUser?.space_ids?.forEach { spaceId -> - val groupKeysDoc = getGroupKeyDoc(spaceId) ?: return@forEach - - val (distributionMessage, groupCipher) = getGroupCipherByKeyId( - spaceId, - userId, - journey.key_id, - groupKeysDoc - ) - ?: run { - Timber.e("Failed to get group cipher") + suspend fun updateJourney(userId: String, journey: LocationJourney, spaceId: String) { + userPreferences.currentUser?.space_ids?.forEach { _ -> + val groupKeysDoc = getGroupKeyDoc(spaceId) ?: return + + // Iterate through all the member groups in the space + val memberIds = groupKeysDoc.member_keys.keys + memberIds.forEach { groupId -> + // Fetch the group cipher and other necessary details using the groupId and journey.key_id + val (distributionMessage, groupCipher) = getGroupCipherByKeyId( + spaceId, + userId, + journey.key_id, + groupKeysDoc + ) ?: run { + Timber.e("Failed to get group cipher for group $groupId in space $spaceId") return@forEach } - val encryptedJourney = - journey.toEncryptedLocationJourney(groupCipher, distributionMessage.distributionId) - try { - encryptedJourney?.let { - spaceMemberJourneyRef(spaceId, userId) - .document(journey.id) - .set(it) - .await() + val encryptedJourney = + journey.toEncryptedLocationJourney( + groupCipher, + distributionMessage.distributionId + ) + try { + // Update the encrypted journey for each group in the space + if (encryptedJourney != null) { + spaceMemberJourneyRef(spaceId, userId) + .document(journey.id) + .set(encryptedJourney) + .await() + } + Timber.d("Updated journey for group $groupId in space $spaceId") + } catch (e: Exception) { + Timber.e(e, "Error updating journey for group $groupId in space $spaceId") } - } catch (e: Exception) { - Timber.e(e, "Error updating journey") } } }