login refactoring

This commit is contained in:
Minecon724 2024-08-04 09:25:31 +02:00
parent fff16ca0fb
commit 5b27c8783e
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
3 changed files with 93 additions and 40 deletions

View file

@ -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\"")
} }

View file

@ -92,6 +92,7 @@ class LoginActivity : ComponentActivity() {
} }
} }
if (BuildConfig.AUTO_LOGIN)
loginViewModel.loadKey() loginViewModel.loadKey()
enableEdgeToEdge() enableEdgeToEdge()
@ -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()
} }

View file

@ -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()
} }
} }