support for articles; ui & ux & logic fixes for 2fa and captcha screens; fix mentions;

This commit is contained in:
2024-07-13 01:37:24 +03:00
parent 25acc6505b
commit ce1867c22c
38 changed files with 449 additions and 218 deletions
@@ -1,10 +1,8 @@
package com.meloda.app.fast.auth.twofa
import android.util.Log
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.meloda.app.fast.auth.twofa.model.TwoFaArguments
import com.meloda.app.fast.auth.twofa.model.TwoFaScreenState
import com.meloda.app.fast.auth.twofa.model.TwoFaValidationType
import com.meloda.app.fast.auth.twofa.navigation.TwoFa
@@ -20,6 +18,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
@@ -27,6 +26,8 @@ interface TwoFaViewModel {
val screenState: StateFlow<TwoFaScreenState>
val isNeedToOpenLogin: StateFlow<Boolean>
fun onCodeInputChanged(newCode: String)
fun onBackButtonClicked()
@@ -36,8 +37,6 @@ interface TwoFaViewModel {
fun onDoneButtonClicked()
fun onNavigatedToLogin()
fun setArguments(arguments: TwoFaArguments)
}
class TwoFaViewModelImpl(
@@ -48,6 +47,8 @@ class TwoFaViewModelImpl(
override val screenState = MutableStateFlow(TwoFaScreenState.EMPTY)
override val isNeedToOpenLogin = MutableStateFlow(false)
private var delayJob: Job? = null
init {
@@ -88,12 +89,8 @@ class TwoFaViewModelImpl(
}
override fun onCancelButtonClicked() {
screenState.updateValue(
screenState.value.copy(
twoFaCode = null,
isNeedToOpenLogin = true
)
)
screenState.setValue { old -> old.copy(twoFaCode = null) }
isNeedToOpenLogin.update { true }
}
override fun onRequestSmsButtonClicked() {
@@ -107,25 +104,12 @@ class TwoFaViewModelImpl(
override fun onDoneButtonClicked() {
if (!processValidation()) return
screenState.updateValue(screenState.value.copy(isNeedToOpenLogin = true))
isNeedToOpenLogin.update { true }
}
override fun onNavigatedToLogin() {
screenState.updateValue(TwoFaScreenState.EMPTY)
}
override fun setArguments(arguments: TwoFaArguments) {
Log.d("TwoFaViewModel", "TwoFaArguments: $arguments")
// screenState.updateValue(
// screenState.value.copy(
// twoFaSid = arguments.validationSid,
// canResendSms = arguments.canResendSms,
// codeError = arguments.wrongCodeError,
// twoFaText = getTwoFaText(TwoFaValidationType.parse(arguments.validationType)),
// phoneMask = arguments.phoneMask
// )
// )
isNeedToOpenLogin.update { false }
}
private fun processValidation(): Boolean {
@@ -147,7 +131,9 @@ class TwoFaViewModelImpl(
authUseCase.sendSms(validationSid)
.listenValue { state ->
state.processState(
error = { error -> },
error = { error ->
},
success = { response ->
val newValidationType = response.validationType
val newCanResendSms = response.validationResend == "sms"
@@ -9,7 +9,6 @@ data class TwoFaScreenState(
val canResendSms: Boolean,
val codeError: String?,
val delayTime: Int,
val isNeedToOpenLogin: Boolean,
val phoneMask: String
) {
@@ -21,7 +20,6 @@ data class TwoFaScreenState(
canResendSms = false,
codeError = null,
delayTime = 0,
isNeedToOpenLogin = false,
phoneMask = ""
)
}
@@ -1,6 +0,0 @@
package com.meloda.app.fast.auth.twofa.model
sealed class TwoFaUiAction {
data class CodeResult(val code: String) : TwoFaUiAction()
data object BackClicked : TwoFaUiAction()
}
@@ -6,7 +6,6 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import androidx.navigation.toRoute
import com.meloda.app.fast.auth.twofa.model.TwoFaArguments
import com.meloda.app.fast.auth.twofa.model.TwoFaUiAction
import com.meloda.app.fast.auth.twofa.presentation.TwoFaScreen
import com.meloda.app.fast.common.customNavType
import kotlinx.serialization.Serializable
@@ -28,12 +27,8 @@ fun NavGraphBuilder.twoFaRoute(
) {
composable<TwoFa>(typeMap = TwoFa.typeMap) {
TwoFaScreen(
onAction = { action ->
when (action) {
TwoFaUiAction.BackClicked -> onBack()
is TwoFaUiAction.CodeResult -> onResult(action.code)
}
}
onBack = onBack,
onCodeResult = onResult
)
}
}
@@ -42,8 +37,10 @@ fun NavController.navigateToTwoFa(arguments: TwoFaArguments) {
this.navigate(TwoFa(arguments))
}
fun NavController.setTwoFaResult(code: String) {
fun NavController.setTwoFaResult(code: String?) {
this.currentBackStackEntry
?.savedStateHandle
?.set("twofacode", code)
}
@@ -26,6 +26,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -43,7 +44,6 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.meloda.app.fast.auth.twofa.TwoFaViewModel
import com.meloda.app.fast.auth.twofa.TwoFaViewModelImpl
import com.meloda.app.fast.auth.twofa.model.TwoFaUiAction
import com.meloda.app.fast.common.UiText
import com.meloda.app.fast.designsystem.MaterialDialog
import com.meloda.app.fast.designsystem.TextFieldErrorText
@@ -51,17 +51,18 @@ import com.meloda.app.fast.designsystem.getString
import org.koin.androidx.compose.koinViewModel
import com.meloda.app.fast.designsystem.R as UiR
private typealias OnAction = (TwoFaUiAction) -> Unit
@Composable
fun TwoFaScreen(
onAction: OnAction,
onBack: () -> Unit,
onCodeResult: (code: String) -> Unit,
viewModel: TwoFaViewModel = koinViewModel<TwoFaViewModelImpl>(),
) {
val focusManager = LocalFocusManager.current
val screenState by viewModel.screenState.collectAsStateWithLifecycle()
val isNeedToOpenLogin by viewModel.isNeedToOpenLogin.collectAsStateWithLifecycle()
var confirmedExit by rememberSaveable {
mutableStateOf(false)
}
@@ -70,8 +71,10 @@ fun TwoFaScreen(
mutableStateOf(false)
}
if (confirmedExit) {
onAction(TwoFaUiAction.BackClicked)
LaunchedEffect(confirmedExit) {
if (confirmedExit) {
onBack()
}
}
BackHandler(enabled = !confirmedExit) {
@@ -93,17 +96,22 @@ fun TwoFaScreen(
)
}
if (screenState.isNeedToOpenLogin) {
viewModel.onNavigatedToLogin()
LaunchedEffect(isNeedToOpenLogin) {
if (isNeedToOpenLogin) {
viewModel.onNavigatedToLogin()
val code = screenState.twoFaCode
if (code == null) {
onAction(TwoFaUiAction.BackClicked)
} else {
onAction(TwoFaUiAction.CodeResult(code = code))
val code = screenState.twoFaCode
if (code == null) {
onBack()
} else {
onCodeResult(code)
}
}
}
var code by remember { mutableStateOf(TextFieldValue(screenState.twoFaCode.orEmpty())) }
val codeError = screenState.codeError
Scaffold { padding ->
Column(
modifier = Modifier
@@ -113,7 +121,7 @@ fun TwoFaScreen(
verticalArrangement = Arrangement.SpaceBetween
) {
ExtendedFloatingActionButton(
onClick = { onAction(TwoFaUiAction.BackClicked) },
onClick = onBack,
text = {
Text(
text = "Cancel",
@@ -155,9 +163,6 @@ fun TwoFaScreen(
}
Spacer(modifier = Modifier.height(10.dp))
var code by remember { mutableStateOf(TextFieldValue(screenState.twoFaCode.orEmpty())) }
val codeError = screenState.codeError
TextField(
value = code,
onValueChange = { newText ->