From 9cde3f6404c146f82efae8ec7fc78a77d828cef7 Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Sun, 9 May 2021 12:03:14 +0200 Subject: [PATCH] SplashScreen animation. --- .../credential/CredentialRepository.kt | 44 ++++--- .../credential/ICredentialRepository.kt | 1 + .../screen/SplashScreenComposable.kt | 116 ++++++++++++++---- .../authentication/AuthenticationViewModel.kt | 7 -- .../initialisation/IInitialisation.kt | 28 +++++ .../initialisation/InitialisationViewModel.kt | 34 +++++ app/src/main/res/values/strings.xml | 1 + 7 files changed, 181 insertions(+), 50 deletions(-) create mode 100644 app/src/main/java/com/pixelized/biblib/ui/viewmodel/initialisation/IInitialisation.kt create mode 100644 app/src/main/java/com/pixelized/biblib/ui/viewmodel/initialisation/InitialisationViewModel.kt diff --git a/app/src/main/java/com/pixelized/biblib/repository/credential/CredentialRepository.kt b/app/src/main/java/com/pixelized/biblib/repository/credential/CredentialRepository.kt index 0b5d1bc..6eb0a27 100644 --- a/app/src/main/java/com/pixelized/biblib/repository/credential/CredentialRepository.kt +++ b/app/src/main/java/com/pixelized/biblib/repository/credential/CredentialRepository.kt @@ -4,39 +4,47 @@ import android.app.Application import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit -import com.pixelized.biblib.ui.viewmodel.authentication.AuthenticationViewModel class CredentialRepository(application: Application) : ICredentialRepository { - private val preferences = - application.getSharedPreferences(AuthenticationViewModel.SHARED_PREF, Context.MODE_PRIVATE) + private val preferences = application.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE) override var login get() = preferences.login - set(value) { - preferences.login = value - } + set(value) = value.let { preferences.login = it } override var password: String? get() = preferences.password - set(value) { - preferences.password = value - } + set(value) = value.let { preferences.password = it } override var rememberCredential: Boolean get() = preferences.rememberCredential - set(value) { - preferences.rememberCredential = value - } + set(value) = value.let { preferences.rememberCredential = it } + + override var bearer: String? + get() = preferences.bearer + set(value) = value.let { preferences.bearer = it } private var SharedPreferences.login: String? - get() = getString(AuthenticationViewModel.REMEMBER_USER, null) - set(value) = edit { putString(AuthenticationViewModel.REMEMBER_USER, value) } + get() = getString(REMEMBER_USER, null) + set(value) = edit { putString(REMEMBER_USER, value) } private var SharedPreferences.password: String? - get() = getString(AuthenticationViewModel.REMEMBER_PASSWORD, null) - set(value) = edit { putString(AuthenticationViewModel.REMEMBER_PASSWORD, value) } + get() = getString(REMEMBER_PASSWORD, null) + set(value) = edit { putString(REMEMBER_PASSWORD, value) } private var SharedPreferences.rememberCredential: Boolean - get() = getBoolean(AuthenticationViewModel.REMEMBER_CREDENTIAL, false) - set(value) = edit { putBoolean(AuthenticationViewModel.REMEMBER_CREDENTIAL, value) } + get() = getBoolean(REMEMBER_CREDENTIAL, false) + set(value) = edit { putBoolean(REMEMBER_CREDENTIAL, value) } + + private var SharedPreferences.bearer: String? + get() = getString(BEARER_TOKEN, null) + set(value) = edit { putString(BEARER_TOKEN, value) } + + companion object { + private const val SHARED_PREF = "BIB_LIB_SHARED_PREF" + private const val REMEMBER_CREDENTIAL = "REMEMBER_CREDENTIAL" + private const val REMEMBER_USER = "REMEMBER_USER" + private const val REMEMBER_PASSWORD = "REMEMBER_PASSWORD" + private const val BEARER_TOKEN = "BEARER_TOKEN" + } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/repository/credential/ICredentialRepository.kt b/app/src/main/java/com/pixelized/biblib/repository/credential/ICredentialRepository.kt index ce7771e..195f749 100644 --- a/app/src/main/java/com/pixelized/biblib/repository/credential/ICredentialRepository.kt +++ b/app/src/main/java/com/pixelized/biblib/repository/credential/ICredentialRepository.kt @@ -4,4 +4,5 @@ interface ICredentialRepository { var login: String? var password: String? var rememberCredential: Boolean + var bearer: String? } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/SplashScreenComposable.kt b/app/src/main/java/com/pixelized/biblib/ui/composable/screen/SplashScreenComposable.kt index 9d163e4..c78859c 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/SplashScreenComposable.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/composable/screen/SplashScreenComposable.kt @@ -1,55 +1,121 @@ package com.pixelized.biblib.ui.composable.screen -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.animation.* +import androidx.compose.animation.core.tween +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.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +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.theme.BibLibTheme +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 -import kotlinx.coroutines.launch +import java.util.* @Preview @Composable fun SplashScreenComposablePreview() { BibLibTheme { - SplashScreenComposable(INavigation.Mock()) + SplashScreenComposable(IInitialisation.Mock(), INavigation.Mock()) } } +@OptIn(ExperimentalAnimationApi::class) @Composable fun SplashScreenComposable( + initialisation: IInitialisation = viewModel(), navigation: INavigation = viewModel() ) { + val duration = 1000 val typography = MaterialTheme.typography + initialisation.LoadApplication { + Box( + modifier = Modifier + .fillMaxHeight() + .fillMaxWidth() + .padding(16.dp), + ) { + Column( + modifier = Modifier + .width(240.dp) + .align(Alignment.Center) + ) { + AnimatedVisibility( + visible = it != IInitialisation.State.Finished, + 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 = it != IInitialisation.State.Finished, + 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) + ) + } + } - Box( - modifier = Modifier - .fillMaxHeight() - .fillMaxWidth(), - contentAlignment = Alignment.Center, - ) { - Text( - style = typography.h4, - text = "Welcome to BibLib" - ) - } - - val coroutineScope = rememberCoroutineScope() - LaunchedEffect(key1 = "loading", block = { - coroutineScope.launch { - delay(1000) - navigation.navigateTo(INavigation.Screen.LoginScreen) + AnimatedVisibility( + modifier = Modifier.align(Alignment.BottomEnd), + visible = it != IInitialisation.State.Finished, + 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 + ) + ) + } } - }) -} \ No newline at end of file + + if (it == IInitialisation.State.Finished) { + LaunchedEffect(key1 = "navigateTo(INavigation.Screen.LoginScreen)") { + delay(1000) + navigation.navigateTo(INavigation.Screen.LoginScreen) + } + } + } +} diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/AuthenticationViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/AuthenticationViewModel.kt index 6cc2133..49e19f4 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/AuthenticationViewModel.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/AuthenticationViewModel.kt @@ -124,11 +124,4 @@ class AuthenticationViewModel : ViewModel(), IAuthentication { _state.postValue(State.Loading) launcher?.launch(googleSignIn.client.signInIntent) } - - companion object { - const val SHARED_PREF = "BIB_LIB_SHARED_PREF" - const val REMEMBER_CREDENTIAL = "REMEMBER_CREDENTIAL" - const val REMEMBER_USER = "REMEMBER_USER" - const val REMEMBER_PASSWORD = "REMEMBER_PASSWORD" - } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/initialisation/IInitialisation.kt b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/initialisation/IInitialisation.kt new file mode 100644 index 0000000..a31bb1f --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/initialisation/IInitialisation.kt @@ -0,0 +1,28 @@ +package com.pixelized.biblib.ui.viewmodel.initialisation + +import androidx.compose.runtime.Composable + +interface IInitialisation { + + @Composable + fun LoadApplication(content: @Composable (State) -> Unit) + + sealed class State { + abstract fun proceed(): State + + object Initial : State() { + override fun proceed() = Loading + } + object Loading : State() { + override fun proceed() = Finished + } + object Finished : State() { + override fun proceed() = Finished + } + } + + class Mock(private val state: State = State.Loading) : IInitialisation { + @Composable + override fun LoadApplication(content: (State) -> Unit) = content(state) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/initialisation/InitialisationViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/initialisation/InitialisationViewModel.kt new file mode 100644 index 0000000..136aed0 --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/initialisation/InitialisationViewModel.kt @@ -0,0 +1,34 @@ +package com.pixelized.biblib.ui.viewmodel.initialisation + +import androidx.compose.runtime.* +import androidx.lifecycle.ViewModel +import com.pixelized.biblib.network.client.IBibLibClient +import com.pixelized.biblib.repository.credential.ICredentialRepository +import com.pixelized.biblib.ui.viewmodel.initialisation.IInitialisation.State.* +import com.pixelized.biblib.utils.injection.inject +import kotlinx.coroutines.delay + +class InitialisationViewModel : ViewModel(), IInitialisation { + private val credentialRepository: ICredentialRepository by inject() + private val client: IBibLibClient by inject() + + @Composable + override fun LoadApplication(content: @Composable (IInitialisation.State) -> Unit) { + val state: MutableState = remember { mutableStateOf(Initial) } + + LaunchedEffect(key1 = "LoadApplication") { + state.value = Loading + delay(2000) + + val bearerToken = credentialRepository.bearer + if (bearerToken != null) { + client.updateBearerToken(bearerToken) + state.value = Finished + } else { + state.value = Finished + } + } + + content(state.value) + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5297498..6d9a4e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ BibLib + %1$s: %2$s - %3$d Register Login