feat: splash screen, move login branching logic out of greeter

This commit is contained in:
Infi 2022-12-23 16:41:43 +01:00
parent 4356f759e0
commit a5288e4ed7
5 changed files with 103 additions and 89 deletions

View File

@ -12,6 +12,7 @@ import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.IntOffset
import chat.revolt.screens.SplashScreen
import chat.revolt.screens.about.AboutScreen
import chat.revolt.screens.about.AttributionScreen
import chat.revolt.screens.about.PlaceholderScreen
@ -52,7 +53,7 @@ fun AppEntrypoint() {
AnimatedNavHost(
navController = navController,
startDestination = "login/greeting",
startDestination = "splash",
enterTransition = {
slideIntoContainer(
AnimatedContentScope.SlideDirection.Left,
@ -78,6 +79,8 @@ fun AppEntrypoint() {
) + fadeOut(animationSpec = RevoltTweenFloat)
}
) {
composable("splash") { SplashScreen(navController) }
composable("login/greeting") { GreeterScreen(navController) }
composable("login/login") { LoginScreen(navController) }
composable("login/mfa/{mfaTicket}/{allowedAuthTypes}") { backStackEntry ->

View File

@ -3,6 +3,7 @@ package chat.revolt.api
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.compose.runtime.mutableStateMapOf
import chat.revolt.api.realtime.RealtimeSocket
import chat.revolt.api.routes.user.fetchSelf
import chat.revolt.api.schemas.*
@ -61,11 +62,11 @@ object RevoltAPI {
const val TOKEN_HEADER_NAME = "x-session-token"
// FIXME discount caching solutions! LRU would be better but this is fine for now
val userCache = mutableMapOf<String, User>()
val serverCache = mutableMapOf<String, Server>()
val channelCache = mutableMapOf<String, Channel>()
val emojiCache = mutableMapOf<String, Emoji>()
val messageCache = mutableMapOf<String, Message>()
val userCache = mutableStateMapOf<String, User>()
val serverCache = mutableStateMapOf<String, Server>()
val channelCache = mutableStateMapOf<String, Channel>()
val emojiCache = mutableStateMapOf<String, Emoji>()
val messageCache = mutableStateMapOf<String, Message>()
var selfId: String? = null

View File

@ -0,0 +1,92 @@
package chat.revolt.screens
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.api.RevoltAPI
import chat.revolt.components.generic.RemoteImage
import chat.revolt.components.generic.drawableResource
import chat.revolt.persistence.KVStorage
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class SplashScreenViewModel @Inject constructor(
private val kvStorage: KVStorage
) : ViewModel() {
private var _navigateTo by mutableStateOf("")
val navigateTo: String
get() = _navigateTo
fun setNavigateTo(value: String) {
_navigateTo = value
}
init {
viewModelScope.launch {
val token = kvStorage.get("sessionToken") ?: return@launch setNavigateTo("login")
val valid = RevoltAPI.checkSessionToken(token)
if (!valid) {
kvStorage.remove("sessionToken")
setNavigateTo("login")
} else {
RevoltAPI.loginAs(token)
setNavigateTo("home")
}
}
}
}
@Composable
fun SplashScreen(navController: NavController, viewModel: SplashScreenViewModel = hiltViewModel()) {
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
RemoteImage(
url = drawableResource(R.drawable.revolt_logo_wide),
description = "Revolt Logo",
contentScale = ContentScale.Fit,
modifier = Modifier
.fillMaxWidth()
.height(60.dp)
)
}
if (viewModel.navigateTo.isNotEmpty()) {
when (viewModel.navigateTo) {
"login" -> {
navController.navigate("login/greeting") {
popUpTo("splash") {
inclusive = true
}
}
}
"home" -> {
navController.navigate("chat/home") {
popUpTo("splash") {
inclusive = true
}
}
}
}
viewModel.setNavigateTo("")
}
}

View File

@ -105,7 +105,6 @@ fun HomeScreen(navController: NavController, viewModel: HomeScreenViewModel = hi
}
}
// a scrollable list of all users in user cache
Text(
text = "User cache",
style = MaterialTheme.typography.displaySmall.copy(

View File

@ -7,9 +7,6 @@ import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@ -19,90 +16,12 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavController
import chat.revolt.api.RevoltAPI
import chat.revolt.components.generic.RemoteImage
import chat.revolt.components.generic.drawableResource
import chat.revolt.persistence.KVStorage
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class GreeterViewModel @Inject constructor(
private val kvStorage: KVStorage
) : ViewModel() {
private var _skipLogin by mutableStateOf(false)
val skipLogin: Boolean
get() = _skipLogin
private var _finishedLoading by mutableStateOf(false)
val finishedLoading: Boolean
get() = _finishedLoading
fun setSkipLogin(value: Boolean) {
_skipLogin = value
}
fun setFinishedLoading(value: Boolean) {
_finishedLoading = value
}
init {
viewModelScope.launch {
val token = kvStorage.get("sessionToken")
if (token != null) {
val valid = RevoltAPI.checkSessionToken(token)
if (!valid) {
kvStorage.remove("sessionToken")
RevoltAPI.setSessionHeader("")
}
}
if (RevoltAPI.isLoggedIn()) {
RevoltAPI.loginAs(token ?: "")
_skipLogin = true
}
setFinishedLoading(true)
}
}
}
@Composable
fun GreeterScreen(navController: NavController, viewModel: GreeterViewModel = hiltViewModel()) {
if (viewModel.skipLogin) {
navController.navigate("chat/home") {
popUpTo("login/greeting") {
inclusive = true
}
}
viewModel.setSkipLogin(false)
}
if (!viewModel.finishedLoading) {
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
RemoteImage(
url = drawableResource(R.drawable.revolt_logo_wide),
description = "Revolt Logo",
contentScale = ContentScale.Fit,
modifier = Modifier
.fillMaxWidth()
.height(60.dp)
)
}
return
}
fun GreeterScreen(navController: NavController) {
Column(
modifier = Modifier
.fillMaxWidth()