fast login with token

This commit is contained in:
2024-07-19 06:01:16 +03:00
parent 1817698031
commit 2b018add7c
3 changed files with 84 additions and 16 deletions
+1
View File
@@ -263,4 +263,5 @@
<string name="captcha_exit_warning">Are you sure? Captcha process will be cancelled</string> <string name="captcha_exit_warning">Are you sure? Captcha process will be cancelled</string>
<string name="validation_exit_warning">Are you sure? Validation process will be cancelled</string> <string name="validation_exit_warning">Are you sure? Validation process will be cancelled</string>
<string name="settings_general_enable_pull_to_refresh_title">Enable pull to refresh</string> <string name="settings_general_enable_pull_to_refresh_title">Enable pull to refresh</string>
<string name="action_authorize">Authorize</string>
</resources> </resources>
@@ -3,6 +3,13 @@ package dev.meloda.fast.auth.login
import android.util.Log import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dev.meloda.fast.auth.login.model.CaptchaArguments
import dev.meloda.fast.auth.login.model.LoginError
import dev.meloda.fast.auth.login.model.LoginScreenState
import dev.meloda.fast.auth.login.model.LoginUserBannedArguments
import dev.meloda.fast.auth.login.model.LoginValidationArguments
import dev.meloda.fast.auth.login.model.LoginValidationResult
import dev.meloda.fast.auth.login.validation.LoginValidator
import dev.meloda.fast.common.LongPollController import dev.meloda.fast.common.LongPollController
import dev.meloda.fast.common.UserConfig import dev.meloda.fast.common.UserConfig
import dev.meloda.fast.common.VkConstants import dev.meloda.fast.common.VkConstants
@@ -17,13 +24,6 @@ import dev.meloda.fast.data.processState
import dev.meloda.fast.datastore.AppSettings import dev.meloda.fast.datastore.AppSettings
import dev.meloda.fast.model.database.AccountEntity import dev.meloda.fast.model.database.AccountEntity
import dev.meloda.fast.network.OAuthErrorDomain import dev.meloda.fast.network.OAuthErrorDomain
import dev.meloda.fast.auth.login.model.CaptchaArguments
import dev.meloda.fast.auth.login.model.LoginError
import dev.meloda.fast.auth.login.model.LoginScreenState
import dev.meloda.fast.auth.login.model.LoginUserBannedArguments
import dev.meloda.fast.auth.login.model.LoginValidationArguments
import dev.meloda.fast.auth.login.model.LoginValidationResult
import dev.meloda.fast.auth.login.validation.LoginValidator
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -44,6 +44,7 @@ interface LoginViewModel {
val captchaArguments: StateFlow<CaptchaArguments?> val captchaArguments: StateFlow<CaptchaArguments?>
val userBannedArguments: StateFlow<LoginUserBannedArguments?> val userBannedArguments: StateFlow<LoginUserBannedArguments?>
val isNeedToOpenMain: StateFlow<Boolean> val isNeedToOpenMain: StateFlow<Boolean>
val isNeedToShowFastSignInAlert: StateFlow<Boolean>
fun onPasswordVisibilityButtonClicked() fun onPasswordVisibilityButtonClicked()
@@ -63,6 +64,9 @@ interface LoginViewModel {
fun onCaptchaCodeReceived(code: String) fun onCaptchaCodeReceived(code: String)
fun onLogoLongClicked() fun onLogoLongClicked()
fun onFastLogInAlertDismissed()
fun onFastLogInAlertConfirmClicked(token: String)
} }
class LoginViewModelImpl( class LoginViewModelImpl(
@@ -82,6 +86,7 @@ class LoginViewModelImpl(
override val captchaArguments = MutableStateFlow<CaptchaArguments?>(null) override val captchaArguments = MutableStateFlow<CaptchaArguments?>(null)
override val userBannedArguments = MutableStateFlow<LoginUserBannedArguments?>(null) override val userBannedArguments = MutableStateFlow<LoginUserBannedArguments?>(null)
override val isNeedToOpenMain = MutableStateFlow(false) override val isNeedToOpenMain = MutableStateFlow(false)
override val isNeedToShowFastSignInAlert = MutableStateFlow(false)
private val validationState: StateFlow<List<LoginValidationResult>> = private val validationState: StateFlow<List<LoginValidationResult>> =
screenState.map(loginValidator::validate) screenState.map(loginValidator::validate)
@@ -145,9 +150,17 @@ class LoginViewModelImpl(
} }
override fun onLogoLongClicked() { override fun onLogoLongClicked() {
val currentAccount = AccountEntity( isNeedToShowFastSignInAlert.update { true }
userId = BuildConfig.debugUserId.toInt(), }
accessToken = BuildConfig.debugAccessToken,
override fun onFastLogInAlertDismissed() {
isNeedToShowFastSignInAlert.update { false }
}
override fun onFastLogInAlertConfirmClicked(token: String) {
var currentAccount = AccountEntity(
userId = -1,
accessToken = token,
fastToken = null, fastToken = null,
trustedHash = null trustedHash = null
).also { account -> ).also { account ->
@@ -158,8 +171,6 @@ class LoginViewModelImpl(
UserConfig.trustedHash = account.trustedHash UserConfig.trustedHash = account.trustedHash
} }
startLongPoll()
usersUseCase.get( usersUseCase.get(
userIds = null, userIds = null,
fields = VkConstants.USER_FIELDS, fields = VkConstants.USER_FIELDS,
@@ -167,19 +178,29 @@ class LoginViewModelImpl(
).listenValue { state -> ).listenValue { state ->
state.processState( state.processState(
error = { error -> error = { error ->
UserConfig.currentUserId = -1
UserConfig.userId = -1
UserConfig.accessToken = ""
// TODO: 19/07/2024, Danil Nikolaev: show error?
}, },
success = { response -> success = { response ->
val actualUserId = response.first().id
currentAccount = currentAccount.copy(userId = actualUserId)
UserConfig.userId = actualUserId
UserConfig.currentUserId = actualUserId
startLongPoll()
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
accountsRepository.storeAccounts(listOf(currentAccount)) accountsRepository.storeAccounts(listOf(currentAccount))
delay(350) delay(350)
isNeedToOpenMain.update { true } isNeedToOpenMain.update { true }
} }
} }
) )
screenState.setValue { old -> old.copy(isLoading = state.isLoading()) } screenState.setValue { old -> old.copy(isLoading = state.isLoading()) }
} }
} }
@@ -17,12 +17,16 @@ import androidx.compose.foundation.layout.width
import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
@@ -31,9 +35,12 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import dev.meloda.fast.ui.theme.LocalThemeConfig import dev.meloda.fast.auth.login.BuildConfig
import dev.meloda.fast.auth.login.LoginViewModel import dev.meloda.fast.auth.login.LoginViewModel
import dev.meloda.fast.auth.login.LoginViewModelImpl import dev.meloda.fast.auth.login.LoginViewModelImpl
import dev.meloda.fast.ui.components.ActionInvokeDismiss
import dev.meloda.fast.ui.components.MaterialDialog
import dev.meloda.fast.ui.theme.LocalThemeConfig
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
import dev.meloda.fast.ui.R as UiR import dev.meloda.fast.ui.R as UiR
@@ -44,6 +51,7 @@ fun LogoRoute(
viewModel: LoginViewModel = koinViewModel<LoginViewModelImpl>() viewModel: LoginViewModel = koinViewModel<LoginViewModelImpl>()
) { ) {
val isNeedToOpenMain by viewModel.isNeedToOpenMain.collectAsStateWithLifecycle() val isNeedToOpenMain by viewModel.isNeedToOpenMain.collectAsStateWithLifecycle()
val isNeedToShowSignInAlert by viewModel.isNeedToShowFastSignInAlert.collectAsStateWithLifecycle()
LaunchedEffect(isNeedToOpenMain) { LaunchedEffect(isNeedToOpenMain) {
if (isNeedToOpenMain) { if (isNeedToOpenMain) {
@@ -56,6 +64,13 @@ fun LogoRoute(
onLogoLongClicked = viewModel::onLogoLongClicked, onLogoLongClicked = viewModel::onLogoLongClicked,
onGoNextButtonClicked = onGoNextButtonClicked onGoNextButtonClicked = onGoNextButtonClicked
) )
if (isNeedToShowSignInAlert) {
SignInAlert(
onDismissRequest = viewModel::onFastLogInAlertDismissed,
onConfirmClick = viewModel::onFastLogInAlertConfirmClicked,
)
}
} }
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@@ -159,3 +174,34 @@ fun LogoScreen(
} }
} }
} }
@Composable
fun SignInAlert(
onDismissRequest: () -> Unit,
onConfirmClick: (token: String) -> Unit
) {
var tokenText by rememberSaveable {
mutableStateOf(BuildConfig.debugAccessToken)
}
val maxWidthModifier = Modifier.fillMaxWidth()
MaterialDialog(
onDismissRequest = onDismissRequest,
title = "Fast authorization",
confirmText = stringResource(id = UiR.string.action_authorize),
confirmAction = { onConfirmClick(tokenText) },
cancelText = stringResource(id = UiR.string.cancel),
actionInvokeDismiss = ActionInvokeDismiss.Always
) {
Column(modifier = maxWidthModifier) {
OutlinedTextField(
modifier = maxWidthModifier.padding(horizontal = 16.dp),
value = tokenText,
onValueChange = { tokenText = it },
placeholder = { Text(text = "Access token") },
label = { Text(text = "Access token") }
)
}
}
}