fast login with token
This commit is contained in:
@@ -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()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+47
-1
@@ -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") }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user