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.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit import androidx.core.content.edit
import com.pixelized.biblib.ui.viewmodel.authentication.AuthenticationViewModel
class CredentialRepository(application: Application) : ICredentialRepository { class CredentialRepository(application: Application) : ICredentialRepository {
private val preferences = private val preferences = application.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE)
application.getSharedPreferences(AuthenticationViewModel.SHARED_PREF, Context.MODE_PRIVATE)
override var login override var login
get() = preferences.login get() = preferences.login
set(value) { set(value) = value.let { preferences.login = it }
preferences.login = value
}
override var password: String? override var password: String?
get() = preferences.password get() = preferences.password
set(value) { set(value) = value.let { preferences.password = it }
preferences.password = value
}
override var rememberCredential: Boolean override var rememberCredential: Boolean
get() = preferences.rememberCredential get() = preferences.rememberCredential
set(value) { set(value) = value.let { preferences.rememberCredential = it }
preferences.rememberCredential = value
} override var bearer: String?
get() = preferences.bearer
set(value) = value.let { preferences.bearer = it }
private var SharedPreferences.login: String? private var SharedPreferences.login: String?
get() = getString(AuthenticationViewModel.REMEMBER_USER, null) get() = getString(REMEMBER_USER, null)
set(value) = edit { putString(AuthenticationViewModel.REMEMBER_USER, value) } set(value) = edit { putString(REMEMBER_USER, value) }
private var SharedPreferences.password: String? private var SharedPreferences.password: String?
get() = getString(AuthenticationViewModel.REMEMBER_PASSWORD, null) get() = getString(REMEMBER_PASSWORD, null)
set(value) = edit { putString(AuthenticationViewModel.REMEMBER_PASSWORD, value) } set(value) = edit { putString(REMEMBER_PASSWORD, value) }
private var SharedPreferences.rememberCredential: Boolean private var SharedPreferences.rememberCredential: Boolean
get() = getBoolean(AuthenticationViewModel.REMEMBER_CREDENTIAL, false) get() = getBoolean(REMEMBER_CREDENTIAL, false)
set(value) = edit { putBoolean(AuthenticationViewModel.REMEMBER_CREDENTIAL, value) } 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 login: String?
var password: String? var password: String?
var rememberCredential: Boolean var rememberCredential: Boolean
var bearer: String?
} }

View file

@ -1,55 +1,121 @@
package com.pixelized.biblib.ui.composable.screen package com.pixelized.biblib.ui.composable.screen
import androidx.compose.foundation.layout.Box import androidx.compose.animation.*
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel 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.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.INavigation
import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import java.util.*
@Preview @Preview
@Composable @Composable
fun SplashScreenComposablePreview() { fun SplashScreenComposablePreview() {
BibLibTheme { BibLibTheme {
SplashScreenComposable(INavigation.Mock()) SplashScreenComposable(IInitialisation.Mock(), INavigation.Mock())
} }
} }
@OptIn(ExperimentalAnimationApi::class)
@Composable @Composable
fun SplashScreenComposable( fun SplashScreenComposable(
initialisation: IInitialisation = viewModel<InitialisationViewModel>(),
navigation: INavigation = viewModel<NavigationViewModel>() navigation: INavigation = viewModel<NavigationViewModel>()
) { ) {
val duration = 1000
val typography = MaterialTheme.typography 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( AnimatedVisibility(
modifier = Modifier modifier = Modifier.align(Alignment.BottomEnd),
.fillMaxHeight() visible = it != IInitialisation.State.Finished,
.fillMaxWidth(), enter = fadeIn(animationSpec = tween(duration)),
contentAlignment = Alignment.Center, exit = fadeOut(animationSpec = tween(duration)),
) { ) {
Text( Text(
style = typography.h4, style = typography.caption,
text = "Welcome to BibLib" text = stringResource(
) R.string.app_version,
} BuildConfig.BUILD_TYPE.toUpperCase(Locale.getDefault()),
BuildConfig.VERSION_NAME,
val coroutineScope = rememberCoroutineScope() BuildConfig.VERSION_CODE
LaunchedEffect(key1 = "loading", block = { )
coroutineScope.launch { )
delay(1000) }
navigation.navigateTo(INavigation.Screen.LoginScreen)
} }
})
} 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) _state.postValue(State.Loading)
launcher?.launch(googleSignIn.client.signInIntent) 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> <resources>
<string name="app_name">BibLib</string> <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_register">Register</string>
<string name="action_login">Login</string> <string name="action_login">Login</string>