login refactoring
This commit is contained in:
parent
fff16ca0fb
commit
5b27c8783e
3 changed files with 93 additions and 40 deletions
|
@ -21,6 +21,7 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't forget to add another "s this is counter intuitive I know but not my fault
|
// don't forget to add another "s this is counter intuitive I know but not my fault
|
||||||
|
buildConfigField("Boolean", "AUTO_LOGIN", "true")
|
||||||
buildConfigField("String", "VASTAI_KEY", "\"\"")
|
buildConfigField("String", "VASTAI_KEY", "\"\"")
|
||||||
buildConfigField("String", "VASIAI_API_ENDPOINT", "\"https://cloud.vast.ai/api/v0\"")
|
buildConfigField("String", "VASIAI_API_ENDPOINT", "\"https://cloud.vast.ai/api/v0\"")
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,8 @@ class LoginActivity : ComponentActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loginViewModel.loadKey()
|
if (BuildConfig.AUTO_LOGIN)
|
||||||
|
loginViewModel.loadKey()
|
||||||
|
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
setContent {
|
setContent {
|
||||||
|
@ -128,17 +129,11 @@ class LoginActivity : ComponentActivity() {
|
||||||
fun LoginApp(loginViewModel: LoginViewModel) {
|
fun LoginApp(loginViewModel: LoginViewModel) {
|
||||||
val uiState by loginViewModel.uiState.collectAsState()
|
val uiState by loginViewModel.uiState.collectAsState()
|
||||||
val loginErrorMessage by loginViewModel.error.observeAsState() // TODO put this in uiState
|
val loginErrorMessage by loginViewModel.error.observeAsState() // TODO put this in uiState
|
||||||
|
val apiKey by loginViewModel.apiKey.collectAsState()
|
||||||
|
|
||||||
val isIdle by remember(uiState) { derivedStateOf { uiState !is LoginUiState.Loading } }
|
val isIdle by remember(uiState) { derivedStateOf { uiState !is LoginUiState.Loading } }
|
||||||
|
|
||||||
var apiKey by rememberSaveable { mutableStateOf(BuildConfig.VASTAI_KEY) }
|
|
||||||
var advancedOpen by rememberSaveable { mutableStateOf(false) }
|
var advancedOpen by rememberSaveable { mutableStateOf(false) }
|
||||||
|
|
||||||
val transition = updateTransition(targetState = advancedOpen, label = "Advanced Menu Transition")
|
|
||||||
val arrowRotation by transition.animateFloat(label = "Advanced Menu Arrow Rotation") { state ->
|
|
||||||
if (state) 180f else 0f
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(300.dp)
|
.width(300.dp)
|
||||||
|
@ -146,38 +141,25 @@ fun LoginApp(loginViewModel: LoginViewModel) {
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
TextField(
|
KeyTextField(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
enabled = isIdle,
|
enabled = isIdle,
|
||||||
value = apiKey,
|
apiKey = apiKey,
|
||||||
onValueChange = { apiKey = it },
|
onValueChange = { loginViewModel.onApiKeyChange(it) },
|
||||||
label = { Text(text = stringResource(id = R.string.api_key)) },
|
rainbowText = uiState is LoginUiState.Success,
|
||||||
visualTransformation = PasswordVisualTransformation(),
|
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
|
|
||||||
textStyle = if (uiState is LoginUiState.Success) rainbowTextStyle() else LocalTextStyle.current,
|
|
||||||
singleLine = true,
|
|
||||||
isError = loginErrorMessage != null
|
isError = loginErrorMessage != null
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(10.dp))
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
Row {
|
Row {
|
||||||
TextButton(
|
AdvancedOptionsButton(
|
||||||
enabled = isIdle,
|
enabled = isIdle,
|
||||||
onClick = {
|
onClick = { advancedOpen = !advancedOpen },
|
||||||
advancedOpen = !advancedOpen
|
isOpen = advancedOpen
|
||||||
}
|
)
|
||||||
) {
|
|
||||||
Text(text = stringResource(id = R.string.advanced_options))
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.KeyboardArrowDown,
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.rotate(arrowRotation)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Button(
|
Button(
|
||||||
enabled = isIdle,
|
enabled = isIdle,
|
||||||
onClick = {
|
onClick = {
|
||||||
loginViewModel.tryLogin(apiKey)
|
loginViewModel.tryLogin()
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
if (uiState is LoginUiState.Loading) {
|
if (uiState is LoginUiState.Loading) {
|
||||||
|
@ -187,12 +169,62 @@ fun LoginApp(loginViewModel: LoginViewModel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(visible = advancedOpen) {
|
AnimatedVisibility(visible = advancedOpen) {
|
||||||
AdvancedOptions()
|
AdvancedOptions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun KeyTextField(
|
||||||
|
enabled: Boolean,
|
||||||
|
apiKey: String,
|
||||||
|
onValueChange: (String) -> Unit,
|
||||||
|
rainbowText: Boolean,
|
||||||
|
isError: Boolean
|
||||||
|
) {
|
||||||
|
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
label = { Text(text = stringResource(id = R.string.api_key)) },
|
||||||
|
|
||||||
|
visualTransformation = PasswordVisualTransformation(),
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
|
||||||
|
textStyle = if (rainbowText) rainbowTextStyle() else LocalTextStyle.current,
|
||||||
|
singleLine = true,
|
||||||
|
|
||||||
|
enabled = enabled,
|
||||||
|
value = apiKey,
|
||||||
|
onValueChange = onValueChange,
|
||||||
|
isError = isError
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AdvancedOptionsButton(
|
||||||
|
enabled: Boolean,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
isOpen: Boolean
|
||||||
|
) {
|
||||||
|
val transition = updateTransition(targetState = isOpen, label = "Advanced Menu Transition")
|
||||||
|
val arrowRotation by transition.animateFloat(label = "Advanced Menu Arrow Rotation") { state ->
|
||||||
|
if (state) 180f else 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
TextButton(
|
||||||
|
enabled = enabled,
|
||||||
|
onClick = onClick
|
||||||
|
) {
|
||||||
|
Text(text = stringResource(id = R.string.advanced_options))
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.KeyboardArrowDown,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.rotate(arrowRotation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun rainbowTextStyle(): TextStyle {
|
fun rainbowTextStyle(): TextStyle {
|
||||||
return LocalTextStyle.current.copy(brush = Brush.linearGradient(colors = listOf(
|
return LocalTextStyle.current.copy(brush = Brush.linearGradient(colors = listOf(
|
||||||
|
@ -207,6 +239,6 @@ fun rainbowTextStyle(): TextStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AdvancedOptions() { // TODO put this in viewmodel
|
fun AdvancedOptions() {
|
||||||
FunGame()
|
FunGame()
|
||||||
}
|
}
|
|
@ -11,6 +11,7 @@ import eu.m724.vastapp.vastai.api.UserUrlRequestCallback
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
import org.chromium.net.CronetEngine
|
import org.chromium.net.CronetEngine
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
|
|
||||||
|
@ -25,7 +26,10 @@ class LoginViewModel(
|
||||||
_uiState.asStateFlow()
|
_uiState.asStateFlow()
|
||||||
|
|
||||||
private val _error = MutableLiveData<String?>(null)
|
private val _error = MutableLiveData<String?>(null)
|
||||||
val error: LiveData<String?> = _error // TODO put this in uistate
|
val error: LiveData<String?> = _error
|
||||||
|
|
||||||
|
private val _apiKey = MutableStateFlow<String>("")
|
||||||
|
var apiKey: StateFlow<String> = _apiKey.asStateFlow()
|
||||||
|
|
||||||
private val applicationContext = getApplication<Application>().applicationContext
|
private val applicationContext = getApplication<Application>().applicationContext
|
||||||
private val sharedPreferences = applicationContext.getSharedPreferences("login", Context.MODE_PRIVATE)
|
private val sharedPreferences = applicationContext.getSharedPreferences("login", Context.MODE_PRIVATE)
|
||||||
|
@ -34,19 +38,34 @@ class LoginViewModel(
|
||||||
val apiKey = sharedPreferences.getString("apiKey", null)
|
val apiKey = sharedPreferences.getString("apiKey", null)
|
||||||
|
|
||||||
if (apiKey != null) {
|
if (apiKey != null) {
|
||||||
tryLogin(apiKey)
|
_apiKey.value = apiKey
|
||||||
|
tryLogin(LoginUiState.FullLoading)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tryLogin(apiKey: String) {
|
fun tryLogin() {
|
||||||
|
tryLogin(LoginUiState.Loading)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onApiKeyChange(apiKey: String) {
|
||||||
|
_apiKey.update { apiKey }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveKey() {
|
||||||
|
with (sharedPreferences.edit()) {
|
||||||
|
putString("apiKey", apiKey.value) // TODO encrypt
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryLogin(initialState: LoginUiState) {
|
||||||
|
val apiKey = apiKey.value
|
||||||
|
|
||||||
val vastApi = VastApi(apiKey, cronetEngine, executor)
|
val vastApi = VastApi(apiKey, cronetEngine, executor)
|
||||||
val request = vastApi.buildRequest(
|
val request = vastApi.buildRequest(
|
||||||
ApiRoute.SHOW_USER,
|
ApiRoute.SHOW_USER,
|
||||||
UserUrlRequestCallback({ user ->
|
UserUrlRequestCallback({ user ->
|
||||||
with (sharedPreferences.edit()) {
|
saveKey() // TODO toggle for this
|
||||||
putString("apiKey", apiKey) // TODO encrypt
|
|
||||||
apply()
|
|
||||||
} // TODO toggle for this
|
|
||||||
_uiState.value = LoginUiState.Success(user)
|
_uiState.value = LoginUiState.Success(user)
|
||||||
}, { apiFailure ->
|
}, { apiFailure ->
|
||||||
_uiState.value = LoginUiState.Idle
|
_uiState.value = LoginUiState.Idle
|
||||||
|
@ -54,7 +73,8 @@ class LoginViewModel(
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
_uiState.value = LoginUiState.Loading
|
|
||||||
|
_uiState.value = initialState
|
||||||
request.start()
|
request.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue