Use bookRepository at application start.

This commit is contained in:
Thomas Andres Gomez 2021-05-11 18:37:30 +02:00
parent b94eaba31b
commit 45f5e9023e
9 changed files with 256 additions and 145 deletions

View file

@ -52,7 +52,7 @@ fun LoadingCard(
private fun LoadingCardLightPreview() {
BibLibTheme(darkTheme = false) {
LoadingCard(
message = stringResource(id = R.string.loading)
message = stringResource(id = R.string.loading_authentication)
)
}
}
@ -62,7 +62,7 @@ private fun LoadingCardLightPreview() {
private fun LoadingCardDarkPreview() {
BibLibTheme(darkTheme = true) {
LoadingCard(
message = stringResource(id = R.string.loading)
message = stringResource(id = R.string.loading_book)
)
}
}

View file

@ -60,7 +60,7 @@ fun SuccessCard(
@Composable
private fun SuccessLightPreview() {
BibLibTheme(darkTheme = false) {
SuccessCard(message = stringResource(id = R.string.authentication_success))
SuccessCard(message = stringResource(id = R.string.success_authentication))
}
}
@ -68,6 +68,6 @@ private fun SuccessLightPreview() {
@Composable
private fun SuccessDarkPreview() {
BibLibTheme(darkTheme = true) {
SuccessCard(message = stringResource(id = R.string.authentication_success))
SuccessCard(message = stringResource(id = R.string.success_authentication))
}
}

View file

@ -45,15 +45,19 @@ import com.pixelized.biblib.ui.composable.items.dialog.SuccessCard
import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.ui.viewmodel.authentication.AuthenticationViewModel
import com.pixelized.biblib.ui.viewmodel.authentication.IAuthentication
import com.pixelized.biblib.ui.viewmodel.initialisation.IInitialisation
import com.pixelized.biblib.ui.viewmodel.initialisation.InitialisationViewModel
import com.pixelized.biblib.ui.viewmodel.navigation.INavigation
import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel
import kotlinx.coroutines.delay
private const val LE_LOAD_BOOK = "LE_LOAD_BOOK"
@Composable
fun LoginScreenComposable(
navigation: INavigation = viewModel<NavigationViewModel>(),
authentication: IAuthentication = viewModel<AuthenticationViewModel>(),
initialisation: IInitialisation = viewModel<InitialisationViewModel>()
) {
Box(
modifier = Modifier
@ -61,10 +65,10 @@ fun LoginScreenComposable(
.fillMaxHeight()
) {
authentication.PrepareLoginWithGoogle()
LoginScreenNavigationComposable(navigation, authentication)
LoginScreenNavigationComposable(navigation, authentication, initialisation)
LoginScreenContentComposable(authentication)
LoginScreenDialogComposable(authentication)
LoginScreenDialogComposable(authentication, initialisation)
}
}
@ -91,49 +95,87 @@ private fun LoginScreenContentComposable(
@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun LoginScreenDialogComposable(
authentication: IAuthentication
authentication: IAuthentication,
initialisation: IInitialisation,
) {
val state = authentication.state.observeAsState()
val authenticationState = authentication.state.observeAsState()
val bookLoadingState = initialisation.state.observeAsState()
CrossFadeOverlay(
modifier = Modifier.clickable {
if (state.value is IAuthentication.State.Error) {
if (authenticationState.value is IAuthentication.State.Error) {
authentication.clearState()
}
},
visible = (state.value is IAuthentication.State.Initial).not()
visible = (authenticationState.value is IAuthentication.State.Initial
&& bookLoadingState.value is IInitialisation.State.Initial).not()
) {
AnimatedVisibility(
modifier = Modifier.align(Alignment.Center),
visible = state.value is IAuthentication.State.Error,
visible = authenticationState.value is IAuthentication.State.Error,
initiallyVisible = false,
enter = expandVertically(Alignment.CenterVertically),
exit = shrinkVertically(Alignment.CenterVertically),
) {
ErrorCard(
message = stringResource(id = R.string.error_generic),
exception = (state.value as? IAuthentication.State.Error)?.exception
exception = (authenticationState.value as? IAuthentication.State.Error)?.exception
)
}
AnimatedVisibility(
modifier = Modifier.align(Alignment.Center),
visible = state.value is IAuthentication.State.Loading,
visible = authenticationState.value is IAuthentication.State.Loading,
initiallyVisible = false,
enter = expandVertically(Alignment.CenterVertically),
exit = shrinkVertically(Alignment.CenterVertically),
) {
LoadingCard(
message = stringResource(id = R.string.loading)
message = stringResource(id = R.string.loading_authentication)
)
}
AnimatedVisibility(
modifier = Modifier.align(Alignment.Center),
visible = state.value is IAuthentication.State.Connect,
visible = authenticationState.value is IAuthentication.State.Connect,
initiallyVisible = false,
enter = expandVertically(Alignment.CenterVertically),
exit = shrinkVertically(Alignment.CenterVertically),
) {
SuccessCard(
message = stringResource(id = R.string.authentication_success)
message = stringResource(id = R.string.success_authentication)
)
}
AnimatedVisibility(
modifier = Modifier.align(Alignment.Center),
visible = bookLoadingState.value is IInitialisation.State.Error,
initiallyVisible = false,
enter = expandVertically(Alignment.CenterVertically),
exit = shrinkVertically(Alignment.CenterVertically),
) {
ErrorCard(
message = stringResource(id = R.string.error_generic),
exception = (bookLoadingState.value as? IInitialisation.State.Error)?.exception
)
}
AnimatedVisibility(
modifier = Modifier.align(Alignment.Center),
visible = bookLoadingState.value is IInitialisation.State.Loading,
initiallyVisible = false,
enter = expandVertically(Alignment.CenterVertically),
exit = shrinkVertically(Alignment.CenterVertically),
) {
LoadingCard(
message = stringResource(id = R.string.loading_book)
)
}
AnimatedVisibility(
modifier = Modifier.align(Alignment.Center),
visible = bookLoadingState.value is IInitialisation.State.Finished,
initiallyVisible = false,
enter = expandVertically(Alignment.CenterVertically),
exit = shrinkVertically(Alignment.CenterVertically),
) {
SuccessCard(
message = stringResource(id = R.string.success_book)
)
}
}
@ -142,15 +184,21 @@ private fun LoginScreenDialogComposable(
@Composable
private fun LoginScreenNavigationComposable(
navigation: INavigation,
authentication: IAuthentication
authentication: IAuthentication,
initialisation: IInitialisation,
) {
val state = authentication.state.observeAsState()
if (state.value == IAuthentication.State.Connect) {
LaunchedEffect(key1 = "navigateTo(MainScreen)") {
delay(1000)
navigation.navigateTo(INavigation.Screen.MainScreen)
val authenticationState = authentication.state.observeAsState()
val bookLoadingState = initialisation.state.observeAsState()
if (authenticationState.value == IAuthentication.State.Connect) {
LaunchedEffect(LE_LOAD_BOOK) {
initialisation.loadBook()
}
}
if (bookLoadingState.value is IInitialisation.State.Finished) {
navigation.navigateTo(INavigation.Screen.MainScreen)
}
}
@Composable
@ -317,6 +365,7 @@ fun LoginScreenComposablePreview() {
BibLibTheme {
val navigationViewModel = INavigation.Mock()
val authenticationViewModel = IAuthentication.Mock()
LoginScreenComposable(navigationViewModel, authenticationViewModel)
val initialisation = IInitialisation.Mock()
LoginScreenComposable(navigationViewModel, authenticationViewModel, initialisation)
}
}

View file

@ -2,11 +2,14 @@ package com.pixelized.biblib.ui.composable.screen
import androidx.compose.animation.*
import androidx.compose.animation.core.tween
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@ -15,6 +18,8 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.pixelized.biblib.BuildConfig
import com.pixelized.biblib.R
import com.pixelized.biblib.ui.composable.items.dialog.CrossFadeOverlay
import com.pixelized.biblib.ui.composable.items.dialog.ErrorCard
import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.ui.viewmodel.initialisation.IInitialisation
import com.pixelized.biblib.ui.viewmodel.initialisation.InitialisationViewModel
@ -23,12 +28,16 @@ import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel
import kotlinx.coroutines.delay
import java.util.*
private const val ANIMATION_DURATION = 1000
private const val LAUNCH_EFFECT_LOAD_APPLICATION = "LoadApplication"
@Preview
@Composable
fun SplashScreenComposablePreview() {
BibLibTheme {
SplashScreenComposable(IInitialisation.Mock(), INavigation.Mock())
val initialisation = IInitialisation.Mock(IInitialisation.State.Loading)
val navigation = INavigation.Mock()
SplashScreenComposable(initialisation, navigation, true)
}
}
@ -36,92 +45,138 @@ fun SplashScreenComposablePreview() {
@Composable
fun SplashScreenComposable(
initialisation: IInitialisation = viewModel<InitialisationViewModel>(),
navigation: INavigation = viewModel<NavigationViewModel>()
navigation: INavigation = viewModel<NavigationViewModel>(),
initiallyVisible: Boolean = false,
) {
val state by initialisation.state.observeAsState()
LaunchedEffect(LAUNCH_EFFECT_LOAD_APPLICATION) {
initialisation.loadApplication()
}
ContentComposable(state = state, initiallyVisible = initiallyVisible)
DialogComposable(state = state)
NavigationComposable(navigation = navigation, state = state)
}
@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun ContentComposable(
state: IInitialisation.State?,
duration: Int = ANIMATION_DURATION,
initiallyVisible: Boolean = false,
) {
val duration = 1000
val typography = MaterialTheme.typography
initialisation.LoadApplication {
val visible = it !is IInitialisation.State.Finished
val visible = state !is IInitialisation.State.Finished
Box(
Box(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
.padding(16.dp),
) {
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
.padding(16.dp),
.width(240.dp)
.align(Alignment.Center)
) {
Column(
modifier = Modifier
.width(240.dp)
.align(Alignment.Center)
) {
AnimatedVisibility(
visible = visible,
initiallyVisible = false,
enter = fadeIn(animationSpec = tween(duration))
+ slideInVertically(
initialOffsetY = { height -> -height },
animationSpec = tween(duration)
),
exit = fadeOut(animationSpec = tween(duration))
+ slideOutVertically(
targetOffsetY = { height -> -height },
animationSpec = tween(duration)
),
) {
Text(
style = typography.h4,
text = "Welcome to"
)
}
AnimatedVisibility(
modifier = Modifier.align(Alignment.End),
visible = visible,
initiallyVisible = false,
enter = fadeIn(animationSpec = tween(duration))
+ slideInVertically(
initialOffsetY = { height -> height },
animationSpec = tween(duration)
),
exit = fadeOut(animationSpec = tween(duration))
+ slideOutVertically(
targetOffsetY = { height -> height },
animationSpec = tween(duration)
),
) {
Text(
style = typography.h4,
text = stringResource(id = R.string.app_name)
)
}
}
AnimatedVisibility(
modifier = Modifier.align(Alignment.BottomEnd),
visible = visible,
enter = fadeIn(animationSpec = tween(duration)),
exit = fadeOut(animationSpec = tween(duration)),
initiallyVisible = initiallyVisible,
enter = fadeIn(animationSpec = tween(duration))
+ slideInVertically(
initialOffsetY = { height -> -height },
animationSpec = tween(duration)
),
exit = fadeOut(animationSpec = tween(duration))
+ slideOutVertically(
targetOffsetY = { height -> -height },
animationSpec = tween(duration)
),
) {
Text(
style = typography.caption,
text = stringResource(
R.string.app_version,
BuildConfig.BUILD_TYPE.toUpperCase(Locale.getDefault()),
BuildConfig.VERSION_NAME,
BuildConfig.VERSION_CODE
)
style = typography.h4,
text = "Welcome to"
)
}
AnimatedVisibility(
modifier = Modifier.align(Alignment.End),
visible = visible,
initiallyVisible = initiallyVisible,
enter = fadeIn(animationSpec = tween(duration))
+ slideInVertically(
initialOffsetY = { height -> height },
animationSpec = tween(duration)
),
exit = fadeOut(animationSpec = tween(duration))
+ slideOutVertically(
targetOffsetY = { height -> height },
animationSpec = tween(duration)
),
) {
Text(
style = typography.h4,
text = stringResource(id = R.string.app_name)
)
}
}
if (it is IInitialisation.State.Finished) {
LaunchedEffect(key1 = "SplashScreen.navigateTo()") {
delay(1000)
if (it.needLogin) {
navigation.navigateTo(INavigation.Screen.LoginScreen)
} else {
navigation.navigateTo(INavigation.Screen.MainScreen)
}
}
AnimatedVisibility(
modifier = Modifier.align(Alignment.BottomEnd),
visible = visible,
initiallyVisible = initiallyVisible,
enter = fadeIn(animationSpec = tween(duration)),
exit = fadeOut(animationSpec = tween(duration)),
) {
Text(
style = typography.caption,
text = stringResource(
R.string.app_version,
BuildConfig.BUILD_TYPE.toUpperCase(Locale.getDefault()),
BuildConfig.VERSION_NAME,
BuildConfig.VERSION_CODE
)
)
}
}
}
@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun DialogComposable(state: IInitialisation.State?) {
CrossFadeOverlay(
modifier = Modifier.clickable {},
visible = state is IInitialisation.State.Error
) {
AnimatedVisibility(
modifier = Modifier.align(Alignment.Center),
visible = true,
initiallyVisible = false,
enter = expandVertically(Alignment.CenterVertically),
exit = shrinkVertically(Alignment.CenterVertically),
) {
ErrorCard(
message = stringResource(id = R.string.error_generic),
exception = (state as? IInitialisation.State.Error)?.exception
)
}
}
}
@Composable
private fun NavigationComposable(
navigation: INavigation,
state: IInitialisation.State?,
duration: Int = ANIMATION_DURATION,
) {
if (state is IInitialisation.State.Finished) {
LaunchedEffect(key1 = "SplashScreen.navigateTo()") {
delay(duration.toLong())
if (state.needLogin) {
navigation.navigateTo(INavigation.Screen.LoginScreen)
} else {
navigation.navigateTo(INavigation.Screen.MainScreen)
}
}
}
}