SplashScreen animation.

This commit is contained in:
Thomas Andres Gomez 2021-05-09 12:03:14 +02:00
parent fa2af6dd90
commit 9cde3f6404
7 changed files with 181 additions and 50 deletions

View file

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

View file

@ -4,4 +4,5 @@ interface ICredentialRepository {
var login: String?
var password: String?
var rememberCredential: Boolean
var bearer: String?
}

View file

@ -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<InitialisationViewModel>(),
navigation: INavigation = viewModel<NavigationViewModel>()
) {
val duration = 1000
val typography = MaterialTheme.typography
initialisation.LoadApplication {
Box(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(),
contentAlignment = Alignment.Center,
.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 BibLib"
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)
)
}
}
val coroutineScope = rememberCoroutineScope()
LaunchedEffect(key1 = "loading", block = {
coroutineScope.launch {
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
)
)
}
}
if (it == IInitialisation.State.Finished) {
LaunchedEffect(key1 = "navigateTo(INavigation.Screen.LoginScreen)") {
delay(1000)
navigation.navigateTo(INavigation.Screen.LoginScreen)
}
})
}
}
}

View file

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

View file

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

View file

@ -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<IInitialisation.State> = 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)
}
}

View file

@ -1,5 +1,6 @@
<resources>
<string name="app_name">BibLib</string>
<string name="app_version">%1$s: %2$s - %3$d</string>
<string name="action_register">Register</string>
<string name="action_login">Login</string>