Skip to content

Commit

Permalink
UI/UX fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
flaviahandrea-vsp committed Oct 1, 2024
1 parent f13b1b6 commit d1e3c24
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
Expand Down Expand Up @@ -54,41 +55,38 @@ fun CustomSnackbar(
} else visible = false
}

AnimatedVisibility(
visible = visible,
enter = slideInVertically(
initialOffsetY = { fullHeight -> fullHeight } // Slide in from bottom
AnimatedVisibility(visible = visible,
enter = slideInVertically(initialOffsetY = { fullHeight -> fullHeight } // Slide in from bottom
) + fadeIn(), // Fade in as well
exit = slideOutVertically(
targetOffsetY = { fullHeight -> fullHeight } // Slide out to bottom
exit = slideOutVertically(targetOffsetY = { fullHeight -> fullHeight } // Slide out to bottom
) + fadeOut(), // Fade out as well
modifier = modifier
) {
modifier = modifier) {
Box(
modifier = modifier
.fillMaxWidth()
.background(
color = colorResource(id = if (isForError) R.color.errorLight else R.color.successLight),
shape = RoundedCornerShape(size = 12.dp)
)
.padding(24.dp), contentAlignment = Alignment.Center
), contentAlignment = Alignment.Center
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.fillMaxWidth()
verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()
) {
Image(
painter = painterResource(id = if (isForError) R.drawable.ic_error_cercle else R.drawable.ic_done_white),
contentDescription = "error",
colorFilter = ColorFilter.tint(
if (isForError) colorResource(id = R.color.error500) else colorResource(
id = R.color.successDark
)
),
contentDescription = "error",
modifier = Modifier.size(16.dp)
modifier = Modifier
.padding(start = 24.dp)
.size(16.dp)
)

Spacer(modifier = Modifier.width(8.dp))

Text(
text = message,
color = if (isForError) colorResource(id = R.color.error500) else colorResource(
Expand All @@ -100,16 +98,30 @@ fun CustomSnackbar(
lineHeight = 24.sp
)

TextButton(onClick = onButtonClick) {
Text(
text = buttonText,
color = if (isForError) colorResource(id = R.color.blue900) else colorResource(
id = R.color.successDark
),
fontFamily = FontFamily(Font(R.font.open_sans_semibold_ttf)),
fontSize = 14.sp,
lineHeight = 24.sp
)
if (isForError) {
Box(modifier = Modifier
.clickable { onButtonClick() }
.padding(top = 24.dp, bottom = 24.dp, end = 24.dp, start = 8.dp)) {
Text(
text = buttonText,
color = colorResource(id = R.color.blue900),
fontFamily = FontFamily(Font(R.font.open_sans_semibold_ttf)),
fontSize = 14.sp,
lineHeight = 24.sp
)
}
} else {
Box(modifier = Modifier
.clickable { onButtonClick() }
.padding(top = 24.dp, bottom = 24.dp, end = 24.dp, start = 8.dp),
contentAlignment = Alignment.Center) {
Image(
painter = painterResource(id = R.drawable.ic_close_white),
contentDescription = "Close",
colorFilter = ColorFilter.tint(colorResource(id = R.color.blue200)),
modifier = Modifier.size(18.dp)
)
}
}
}
}
Expand All @@ -119,8 +131,7 @@ fun CustomSnackbar(
@Preview
@Composable
fun CustomSnackbarPreview() {
CustomSnackbar(
message = "The entered data is invalid",
CustomSnackbar(message = "The entered data is invalid",
buttonText = "OK",
onButtonClick = { /*TODO*/ })
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
Expand Down Expand Up @@ -61,12 +59,8 @@ fun CodeVerificationPage(
val keyboardController = LocalSoftwareKeyboardController.current
val keyboardState by keyboardAsState()

var codeValues by remember {
mutableStateOf(List(4) { "" })
}

// List of FocusRequesters for each TextField
val focusRequesters = List(4) { FocusRequester() }
val codeValues by viewModel.codeValues.collectAsState()
val focusRequesters = remember { List(4) { FocusRequester() } }

Box(
modifier = Modifier.fillMaxSize()
Expand Down Expand Up @@ -113,17 +107,16 @@ fun CodeVerificationPage(
DigitTextField(
value = codeValue,
onValueChange = { newValue ->
codeValues = codeValues.toMutableList().also { it[index] = newValue }
val updatedValues = codeValues.toMutableList().also { it[index] = newValue }
viewModel.updateCodeValues(updatedValues)
},
focusRequester = focusRequesters[index],
previousFocusRequester = if (index > 0) focusRequesters[index - 1] else null,
nextFocusRequester = if (index < 3) focusRequesters[index + 1] else null,
modifier = Modifier
.height(64.dp)
.width(70.dp)
.border(
1.dp, Color.White.copy(alpha = 0.29f), RoundedCornerShape(12.dp)
)
.border(1.dp, Color.White.copy(alpha = 0.29f), RoundedCornerShape(12.dp))
)
}
}
Expand All @@ -137,7 +130,10 @@ fun CodeVerificationPage(
) {
keyboardController?.hide()
val code = codeValues.joinToString("")
viewModel.verifyCode(code)
viewModel.verifyCode(code) {
focusRequesters[0].requestFocus() // Request focus to the first digit field after clearing the code
keyboardController?.hide()
}
}

Spacer(modifier = Modifier.height(32.dp))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ fun SignInPage(
buttonColor = ButtonColor.LIGHT, text = stringResource(id = R.string.sign_in)
) {
keyboardController?.hide()
viewModel.clearSnackbar()
viewModel.login(
true, emailValueState.text.trim(), passwordValueState.text.trim()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class AuthenticationViewModel(application: Application) : ObservableAndroidViewM
private val onUserMissingDefaultArchive = SingleLiveEvent<Void?>()
private val _isBusyState = MutableStateFlow(false)
val isBusyState: StateFlow<Boolean> = _isBusyState
private val _codeValues = MutableStateFlow(List(4) { "" })
val codeValues: StateFlow<List<String>> = _codeValues
private val _snackbarMessage = MutableStateFlow("")
val snackbarMessage: StateFlow<String> = _snackbarMessage
private val _snackbarType = MutableStateFlow(SnackbarType.NONE)
Expand Down Expand Up @@ -169,7 +171,7 @@ class AuthenticationViewModel(application: Application) : ObservableAndroidViewM
}
}

fun verifyCode(code: String) {
fun verifyCode(code: String, onCleared: () -> Unit) {
if (_isBusyState.value) {
return
}
Expand All @@ -189,6 +191,7 @@ class AuthenticationViewModel(application: Application) : ObservableAndroidViewM

override fun onFailed(error: String?) {
_isBusyState.value = false
clearCodeValues(onCleared)
showErrorMessage(
if (error.equals(Constants.ERROR_INVALID_VERIFICATION_CODE)) {
appContext.getString(R.string.code_is_incorrect)
Expand All @@ -200,6 +203,19 @@ class AuthenticationViewModel(application: Application) : ObservableAndroidViewM
})
}

fun updateCodeValues(newValues: List<String>) {
_codeValues.value = newValues
}

private fun clearCodeValues(onCleared: () -> Unit) {
viewModelScope.launch {
_codeValues.value = List(4) { "" }
// Small delay to ensure the state update is propagated before requesting focus
delay(100)
onCleared() // Trigger the focus shift after the state update is fully reflected
}
}

fun showSuccessMessage(message: String) {
clearSnackbar()
// Post the new message with a small delay to allow UI refresh
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="blue50">#E7E8ED</color>
<color name="blue200">#A1A4B7</color>
<color name="blue400">#898DA4</color>
<color name="blue600">#5A5F80</color>
<color name="blue900">#131B4A</color>
Expand Down

0 comments on commit d1e3c24

Please sign in to comment.