Add login management.

This commit is contained in:
Thomas Andres Gomez 2021-05-08 14:01:57 +02:00
parent 8fbe3c0b7b
commit 45d2fe1336
14 changed files with 366 additions and 158 deletions

View file

@ -0,0 +1,82 @@
package com.pixelized.biblib.ui.composable.items
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.Card
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.pixelized.biblib.R
import com.pixelized.biblib.ui.theme.BibLibTheme
@Preview
@Composable
fun WaitingComposableLightPreview() {
BibLibTheme(darkTheme = false) {
WaitingComposable(
visible = true,
message = stringResource(id = R.string.loading)
)
}
}
@Preview
@Composable
fun WaitingComposableDarkPreview() {
BibLibTheme(darkTheme = true) {
WaitingComposable(
visible = true,
message = stringResource(id = R.string.loading)
)
}
}
@Composable
fun WaitingComposable(
visible: Boolean,
modifier: Modifier = Modifier,
message: String? = null
) {
Crossfade(
modifier = modifier,
targetState = visible
) {
if (it) {
Card(elevation = 8.dp) {
Column(
modifier = Modifier
.width(200.dp)
.padding(16.dp)
) {
CircularProgressIndicator(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(16.dp)
)
if (message?.isNotEmpty() == true) {
val typography = MaterialTheme.typography
Text(
modifier = Modifier.align(Alignment.CenterHorizontally),
style = typography.body1,
textAlign = TextAlign.Center,
text = message
)
}
}
}
} else {
Box {}
}
}
}

View file

@ -1,10 +1,7 @@
package com.pixelized.biblib.ui.composable.screen
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
@ -24,7 +21,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -33,12 +29,9 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.common.api.ApiException
import com.pixelized.biblib.R
import com.pixelized.biblib.ui.MainActivity
import com.pixelized.biblib.repository.googlesignin.IGoogleSingInRepository.AuthenticationState.Loading
import com.pixelized.biblib.ui.composable.items.WaitingComposable
import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.ui.viewmodel.AuthenticationViewModel
import com.pixelized.biblib.ui.viewmodel.NavigationViewModel
@ -47,121 +40,116 @@ import com.pixelized.biblib.ui.viewmodel.NavigationViewModel
@Composable
fun LoginScreenComposablePreview() {
BibLibTheme {
LoginScreenComposable()
val navigationViewModel = NavigationViewModel()
val authenticationViewModel = AuthenticationViewModel()
LoginScreenComposable(navigationViewModel, authenticationViewModel)
}
}
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun LoginScreenComposable(
navigationViewModel: NavigationViewModel = viewModel(),
authenticationViewModel: AuthenticationViewModel = viewModel(),
navigationViewModel: NavigationViewModel,
authenticationViewModel: AuthenticationViewModel,
) {
// TODO : c'est de la merde ça
val activity = LocalContext.current as MainActivity
val result = remember { mutableStateOf<String?>(null) }
val launcher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
try {
val task = GoogleSignIn.getSignedInAccountFromIntent(it.data)
val account: GoogleSignInAccount? = task.getResult(ApiException::class.java)
val idToken = account?.idToken
// if (idToken != null) {
// viewModel.loginWithGoogle(idToken).observeLogin()
// } else {
// Toast.makeText(requireActivity(), "GoogleSignIn missing Token", Toast.LENGTH_SHORT).show()
// }
Log.e("AuthLoginFragment", "idToken: $idToken")
} catch (exception: Exception) {
// Toast.makeText(requireActivity(), "GoogleSignIn exception: ${exception.message}", Toast.LENGTH_SHORT).show()
Log.e("AuthLoginFragment", exception.message, exception)
}
// // Here we just update the state, but you could imagine
// // pre-processing the result, or updating a MutableSharedFlow that
// // your composable collects
// result.value = it
}
val typography = MaterialTheme.typography
Column(
Box(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.verticalScroll(rememberScrollState())
.padding(16.dp)
) {
Spacer(modifier = Modifier.weight(1f))
val loginWithGoogleRequest = authenticationViewModel.prepareLoginWithGoogle()
val typography = MaterialTheme.typography
Text(
modifier = Modifier
.padding(vertical = 16.dp)
.align(alignment = Alignment.CenterHorizontally),
style = typography.h4,
text = stringResource(id = R.string.welcome_sign_in)
)
Spacer(modifier = Modifier.weight(1f))
val focusRequester = remember { FocusRequester() }
val localFocus = LocalFocusManager.current
LoginField(
viewModel = authenticationViewModel,
Column(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions { focusRequester.requestFocus() }
)
PasswordField(
viewModel = authenticationViewModel,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp)
.focusRequester(focusRequester),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions { localFocus.clearFocus() }
)
CredentialRemember(
viewModel = authenticationViewModel,
modifier = Modifier
.height(48.dp)
.padding(bottom = 16.dp)
)
Row(
modifier = Modifier
.padding(bottom = 16.dp)
.align(Alignment.End)
.fillMaxHeight()
.verticalScroll(rememberScrollState())
.padding(16.dp)
) {
Spacer(modifier = Modifier.weight(1f))
Text(
modifier = Modifier
.padding(vertical = 16.dp)
.align(alignment = Alignment.CenterHorizontally),
style = typography.h4,
text = stringResource(id = R.string.welcome_sign_in)
)
Spacer(modifier = Modifier.weight(1f))
val focusRequester = remember { FocusRequester() }
val localFocus = LocalFocusManager.current
LoginField(
viewModel = authenticationViewModel,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions { focusRequester.requestFocus() }
)
PasswordField(
viewModel = authenticationViewModel,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp)
.focusRequester(focusRequester),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions { localFocus.clearFocus() }
)
CredentialRemember(
viewModel = authenticationViewModel,
modifier = Modifier
.height(48.dp)
.padding(bottom = 16.dp)
)
Row(
modifier = Modifier
.padding(bottom = 16.dp)
.align(Alignment.End)
) {
Button(
modifier = Modifier.padding(end = 8.dp),
colors = outlinedButtonColors(),
onClick = {
authenticationViewModel.register()
}) {
Text(text = stringResource(id = R.string.action_register))
}
Button(onClick = {
authenticationViewModel.login()
}) {
Text(text = stringResource(id = R.string.action_login))
}
}
Spacer(modifier = Modifier.weight(2f))
Button(
modifier = Modifier.padding(end = 8.dp),
modifier = Modifier.fillMaxWidth(),
colors = outlinedButtonColors(),
onClick = {
authenticationViewModel.register()
authenticationViewModel.loginWithGoogle(loginWithGoogleRequest)
}) {
Text(text = stringResource(id = R.string.action_register))
}
Button(onClick = {
authenticationViewModel.login()
}) {
Text(text = stringResource(id = R.string.action_login))
Image(
modifier = Modifier.padding(end = 8.dp),
painter = painterResource(id = R.drawable.ic_google), contentDescription = ""
)
Text(text = stringResource(id = R.string.action_google_sign_in))
}
}
Spacer(modifier = Modifier.weight(2f))
Button(
modifier = Modifier.fillMaxWidth(),
colors = outlinedButtonColors(),
onClick = {
launcher.launch(activity.googleSignIn.signInIntent)
}) {
Image(
modifier = Modifier.padding(end = 8.dp),
painter = painterResource(id = R.drawable.ic_google), contentDescription = ""
)
Text(text = stringResource(id = R.string.action_google_sign_in))
var waiting: Boolean by remember { mutableStateOf(false) }
waiting = when (loginWithGoogleRequest.result.value) {
is Loading -> true
else -> false
}
WaitingComposable(
modifier = Modifier.align(Alignment.Center),
visible = waiting,
message = stringResource(id = R.string.loading)
)
}
}
@ -176,7 +164,7 @@ private fun LoginField(
TextField(
modifier = modifier,
value = login.value ?: "",
onValueChange = { viewModel.updateLogin(it) },
onValueChange = { viewModel.updateLoginField(it) },
label = { Text(text = stringResource(id = R.string.authentication_login)) },
colors = outlinedTextFieldColors(),
maxLines = 1,
@ -198,7 +186,7 @@ private fun PasswordField(
TextField(
modifier = modifier,
value = password.value ?: "",
onValueChange = { viewModel.updatePassword(it) },
onValueChange = { viewModel.updatePasswordField(it) },
label = { Text(text = stringResource(id = R.string.authentication_password)) },
colors = outlinedTextFieldColors(),
maxLines = 1,

View file

@ -1,7 +1,6 @@
package com.pixelized.biblib.ui.composable.screen
import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.tween
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.sharp.ArrowBack
@ -12,7 +11,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.viewmodel.compose.viewModel
import com.pixelized.biblib.R
import com.pixelized.biblib.ui.composable.pages.DetailPageComposable
import com.pixelized.biblib.ui.composable.pages.HomePageComposable
@ -42,13 +40,15 @@ fun ToolbarComposableLightPreview() {
@Composable
fun MainScreenComposablePreview() {
BibLibTheme {
MainScreenComposable()
val viewModel = NavigationViewModel()
MainScreenComposable(viewModel)
}
}
@Composable
fun MainScreenComposable() {
val navigationViewModel = viewModel<NavigationViewModel>()
fun MainScreenComposable(
navigationViewModel: NavigationViewModel
) {
val page by navigationViewModel.page.observeAsState()
LaunchedEffect(key1 = "MainScreen", block = {

View file

@ -11,23 +11,25 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.viewmodel.compose.viewModel
import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.ui.viewmodel.NavigationViewModel
import kotlinx.coroutines.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@Preview
@Composable
fun SplashScreenComposablePreview() {
BibLibTheme {
SplashScreenComposable()
val viewModel = NavigationViewModel()
SplashScreenComposable(viewModel)
}
}
@Composable
fun SplashScreenComposable() {
val navigationViewModel = viewModel<NavigationViewModel>()
fun SplashScreenComposable(
navigationViewModel: NavigationViewModel
) {
val typography = MaterialTheme.typography
Box(