Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/megh/implement-e2ee-for-location…
Browse files Browse the repository at this point in the history
…s-sp' into megh/implement-e2ee-for-locations-sp
  • Loading branch information
cp-megh-l committed Jan 9, 2025
2 parents 8534114 + 17c89bd commit 3b7092c
Show file tree
Hide file tree
Showing 28 changed files with 537 additions and 593 deletions.
5 changes: 4 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

import org.jetbrains.kotlin.konan.properties.hasProperty
import java.util.Properties

Expand All @@ -14,6 +15,7 @@ plugins {
var versionMajor = 1
var versionMinor = 0
var versionBuild = 0
val targetSdkVersion: Int = 34

android {
namespace = "com.canopas.yourspace"
Expand All @@ -30,6 +32,8 @@ android {
defaultConfig {
applicationId = "com.canopas.yourspace"
minSdk = 24
targetSdk = targetSdkVersion

versionCode = versionMajor * 1000000 + versionMinor * 10000 + versionBuild
versionName = "$versionMajor.$versionMinor.$versionBuild"
setProperty("archivesBaseName", "GroupTrack-$versionName-$versionCode")
Expand Down Expand Up @@ -59,7 +63,6 @@ android {
buildConfigField("String", "PLACE_API_KEY", "\"${p.getProperty("PLACE_API_KEY")}\"")
}
}

signingConfigs {
if (System.getenv("APKSIGN_KEYSTORE") != null) {
create("release") {
Expand Down
14 changes: 6 additions & 8 deletions app/src/main/java/com/canopas/yourspace/ui/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,16 @@ class MainViewModel @Inject constructor(
viewModelScope.launch {
val currentUser = authService.getUser()
val isExistingUser = currentUser != null
val showSetPinScreen =
isExistingUser && currentUser!!.identity_key_public?.toBytes()
.contentEquals(currentUser.identity_key_private?.toBytes())
val showEnterPinScreen =
isExistingUser && currentUser!!.identity_key_public?.toBytes()
.contentEquals(currentUser.identity_key_private?.toBytes()) && userPreferences.getPasskey()
.isNullOrEmpty()
val identityKeysMatch = currentUser?.let {
it.identity_key_public?.toBytes().contentEquals(it.identity_key_private?.toBytes())
} ?: false
val showSetPinScreen = isExistingUser && identityKeysMatch
val showEnterPinScreen = showSetPinScreen && userPreferences.getPasskey().isNullOrEmpty()
val initialRoute = when {
!userPreferences.isIntroShown() -> AppDestinations.intro.path
userPreferences.currentUser == null -> AppDestinations.signIn.path
showSetPinScreen -> AppDestinations.setPin.path
showEnterPinScreen -> AppDestinations.enterPin.path
showSetPinScreen -> AppDestinations.setPin.path
!userPreferences.isOnboardShown() -> AppDestinations.onboard.path
else -> AppDestinations.home.path
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ fun OtpInputField(
pinText: String,
onPinTextChange: (String) -> Unit,
textStyle: TextStyle = AppTheme.appTypography.header2,
digitCount: Int = 6
digitCount: Int = 6,
keyboardType: KeyboardType = KeyboardType.Text
) {
val focusRequester = remember { FocusRequester() }
BoxWithConstraints(
Expand All @@ -55,7 +56,7 @@ fun OtpInputField(
onPinTextChange(it)
}
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
keyboardOptions = KeyboardOptions(keyboardType = keyboardType),
modifier = Modifier.focusRequester(focusRequester),
decorationBox = {
Row(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ private fun MemberInfoView(
val state by viewModel.state.collectAsState()

var address by remember { mutableStateOf("") }
val time = timeAgo(location?.created_at ?: System.currentTimeMillis())
val time = location?.created_at?.let { timeAgo(it) } ?: ""
val userStateText = if (user.noNetwork) {
stringResource(R.string.map_selected_user_item_no_network_state)
} else if (user.locationPermissionDenied) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class JourneyTimelineViewModel @Inject constructor(
try {
val from = _state.value.selectedTimeFrom
val to = _state.value.selectedTimeTo
val lastJourneyTime = allJourneys.minOfOrNull { it.updated_at!! }
val lastJourneyTime = allJourneys.minOfOrNull { it.updated_at }

val locations = if (loadMore) {
journeyService.getMoreJourneyHistory(userId, lastJourneyTime)
Expand All @@ -105,8 +105,8 @@ class JourneyTimelineViewModel @Inject constructor(
}

val filteredLocations = locations.filter {
(it.created_at?.let { created -> created in from..to } ?: false) ||
(it.updated_at?.let { updated -> updated in from..to } ?: false)
it.created_at in from..to ||
it.updated_at in from..to
}

val locationJourneys = (allJourneys + filteredLocations).groupByDate()
Expand Down Expand Up @@ -158,12 +158,12 @@ class JourneyTimelineViewModel @Inject constructor(

private fun List<LocationJourney>.groupByDate(): Map<Long, List<LocationJourney>> {
val journeys = this.distinctBy { it.id }
.sortedByDescending { it.updated_at!! }
.sortedByDescending { it.updated_at }

val groupedItems = mutableMapOf<Long, MutableList<LocationJourney>>()

for (journey in journeys) {
val date = getDayStartTimestamp(journey.created_at!!)
val date = getDayStartTimestamp(journey.created_at)

if (!groupedItems.containsKey(date)) {
groupedItems[date] = mutableListOf()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.canopas.yourspace.R
import com.canopas.yourspace.ui.component.OtpInputField
import com.canopas.yourspace.ui.component.PrimaryButton
import com.canopas.yourspace.ui.flow.pin.setpin.PinErrorState

@OptIn(ExperimentalMaterial3Api::class)
@Composable
Expand All @@ -51,7 +49,6 @@ fun EnterPinScreen() {
private fun EnterPinContent(modifier: Modifier) {
val viewModel = hiltViewModel<EnterPinViewModel>()
val state by viewModel.state.collectAsState()
val context = LocalContext.current

Column(
modifier = modifier
Expand Down Expand Up @@ -81,21 +78,16 @@ private fun EnterPinContent(modifier: Modifier) {
OtpInputField(
pinText = state.pin,
onPinTextChange = { viewModel.onPinChanged(it) },
digitCount = 4
digitCount = 4,
keyboardType = KeyboardType.Number
)

Spacer(modifier = Modifier.height(16.dp))

if (state.pinError != null) {
val pinErrorText = when (state.pinError) {
PinErrorState.LENGTH_ERROR -> context.getString(R.string.enter_pin_error_text_length)
PinErrorState.CHARACTERS_ERROR -> context.getString(R.string.enter_pin_error_characters_input)
PinErrorState.INVALID_PIN -> context.getString(R.string.enter_pin_invalid_pin_text)
else -> ""
}
if (state.isPinInvalid) {
Text(
text = pinErrorText,
color = if (pinErrorText.isNotEmpty()) MaterialTheme.colorScheme.error else Color.Transparent,
text = stringResource(R.string.enter_pin_invalid_pin_text),
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 8.dp)
)
Expand All @@ -108,7 +100,7 @@ private fun EnterPinContent(modifier: Modifier) {
onClick = {
viewModel.processPin()
},
enabled = state.pin != "" && state.pinError == null,
enabled = state.pin != "" && !state.isPinInvalid && state.pin.length == 4,
modifier = Modifier.fillMaxWidth(),
showLoader = state.showLoader
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import com.canopas.yourspace.data.service.auth.AuthService
import com.canopas.yourspace.data.storage.UserPreferences
import com.canopas.yourspace.data.utils.AppDispatcher
import com.canopas.yourspace.domain.utils.ConnectivityObserver
import com.canopas.yourspace.ui.flow.pin.setpin.PinErrorState
import com.canopas.yourspace.ui.navigation.AppDestinations
import com.canopas.yourspace.ui.navigation.AppNavigator
import dagger.hilt.android.lifecycle.HiltViewModel
Expand Down Expand Up @@ -34,16 +33,7 @@ class EnterPinViewModel @Inject constructor(
fun onPinChanged(newPin: String) {
_state.value = _state.value.copy(pin = newPin)
if (newPin.length == 4) {
_state.value = _state.value.copy(pinError = null)
}
}

private fun validatePin() {
val pin = state.value.pin
if (pin.length < 4) {
_state.value = _state.value.copy(pinError = PinErrorState.LENGTH_ERROR, showLoader = false)
} else if (pin.length == 4 && !pin.all { it.isDigit() }) {
_state.value = _state.value.copy(pinError = PinErrorState.CHARACTERS_ERROR, showLoader = false)
_state.value = _state.value.copy(isPinInvalid = false)
}
}

Expand All @@ -62,26 +52,24 @@ class EnterPinViewModel @Inject constructor(
fun processPin() = viewModelScope.launch(appDispatcher.MAIN) {
_state.value = _state.value.copy(showLoader = true)
val pin = state.value.pin
validatePin()
if (state.value.pinError == null) {
val isPinValid = authService.validatePasskey(passKey = pin)
if (isPinValid) {
userPreferences.setOnboardShown(true)
navigator.navigateTo(
AppDestinations.home.path,
popUpToRoute = AppDestinations.signIn.path,
inclusive = true
)
} else {
_state.value = _state.value.copy(pinError = PinErrorState.INVALID_PIN, showLoader = false)
}
val isPinValid = authService.validatePasskey(passKey = pin)
if (isPinValid) {
userPreferences.setOnboardShown(true)
navigator.navigateTo(
AppDestinations.home.path,
popUpToRoute = AppDestinations.signIn.path,
inclusive = true
)
_state.value = _state.value.copy(showLoader = false)
} else {
_state.value = _state.value.copy(isPinInvalid = true, showLoader = false)
}
}
}

data class EnterPinScreenState(
val showLoader: Boolean = false,
val pin: String = "",
val pinError: PinErrorState? = null,
val isPinInvalid: Boolean = false,
val connectivityStatus: ConnectivityObserver.Status = ConnectivityObserver.Status.Available
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
Expand Down Expand Up @@ -51,7 +50,6 @@ fun SetPinScreen() {
private fun SetPinContent(modifier: Modifier) {
val viewModel = hiltViewModel<SetPinViewModel>()
val state by viewModel.state.collectAsState()
val context = LocalContext.current

Column(
modifier = modifier
Expand Down Expand Up @@ -81,33 +79,20 @@ private fun SetPinContent(modifier: Modifier) {
OtpInputField(
pinText = state.pin,
onPinTextChange = { viewModel.onPinChanged(it) },
digitCount = 4
digitCount = 4,
keyboardType = KeyboardType.Number
)

Spacer(modifier = Modifier.height(16.dp))

if (state.pinError != null) {
val pinErrorText = when (state.pinError) {
PinErrorState.LENGTH_ERROR -> context.getString(R.string.set_pin_error_text_length)
PinErrorState.CHARACTERS_ERROR -> context.getString(R.string.set_pin_error_characters_input)
else -> ""
}
Text(
text = pinErrorText,
color = if (pinErrorText.isNotEmpty()) MaterialTheme.colorScheme.error else Color.Transparent,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 8.dp)
)
}

Spacer(modifier = Modifier.height(24.dp))

PrimaryButton(
label = stringResource(R.string.set_pin_button_text),
onClick = {
viewModel.processPin()
},
enabled = state.pin != "" && state.pinError == null,
enabled = state.enableButton,
modifier = Modifier.fillMaxWidth(),
showLoader = state.showLoader
)
Expand Down
Loading

0 comments on commit 3b7092c

Please sign in to comment.