feat: leverage android 12 splash screen API
Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
parent
3e7768146d
commit
8be81649b2
|
|
@ -236,6 +236,7 @@ dependencies {
|
||||||
implementation "androidx.webkit:webkit:1.9.0"
|
implementation "androidx.webkit:webkit:1.9.0"
|
||||||
implementation "androidx.datastore:datastore-preferences:1.1.0-alpha07"
|
implementation "androidx.datastore:datastore-preferences:1.1.0-alpha07"
|
||||||
implementation "androidx.datastore:datastore:1.1.0-alpha07"
|
implementation "androidx.datastore:datastore:1.1.0-alpha07"
|
||||||
|
implementation "androidx.core:core-splashscreen:1.0.1"
|
||||||
|
|
||||||
// Libraries used for legacy View-based UI
|
// Libraries used for legacy View-based UI
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.2.0-alpha13"
|
implementation "androidx.constraintlayout:constraintlayout:2.2.0-alpha13"
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
android:name=".activities.MainActivity"
|
android:name=".activities.MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:theme="@style/Theme.Revolt">
|
android:theme="@style/Theme.Revolt.Starting">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
package chat.revolt.activities
|
package chat.revolt.activities
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.animation.AnimatedContentTransitionScope
|
import androidx.compose.animation.AnimatedContentTransitionScope
|
||||||
import androidx.compose.animation.core.EaseInOutExpo
|
import androidx.compose.animation.core.EaseInOutExpo
|
||||||
import androidx.compose.animation.core.FiniteAnimationSpec
|
import androidx.compose.animation.core.FiniteAnimationSpec
|
||||||
|
|
@ -14,20 +21,31 @@ import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSiz
|
||||||
import androidx.compose.material3.windowsizeclass.WindowSizeClass
|
import androidx.compose.material3.windowsizeclass.WindowSizeClass
|
||||||
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
|
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.dialog
|
import androidx.navigation.compose.dialog
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import chat.revolt.BuildConfig
|
import chat.revolt.BuildConfig
|
||||||
|
import chat.revolt.R
|
||||||
|
import chat.revolt.RevoltApplication
|
||||||
|
import chat.revolt.api.RevoltAPI
|
||||||
|
import chat.revolt.api.RevoltHttp
|
||||||
|
import chat.revolt.api.routes.onboard.needsOnboarding
|
||||||
import chat.revolt.api.settings.GlobalState
|
import chat.revolt.api.settings.GlobalState
|
||||||
import chat.revolt.api.settings.SyncedSettings
|
import chat.revolt.api.settings.SyncedSettings
|
||||||
import chat.revolt.ndk.NativeLibraries
|
import chat.revolt.ndk.NativeLibraries
|
||||||
|
import chat.revolt.persistence.KVStorage
|
||||||
|
import chat.revolt.screens.DefaultDestinationScreen
|
||||||
import chat.revolt.screens.SplashScreen
|
import chat.revolt.screens.SplashScreen
|
||||||
import chat.revolt.screens.about.AboutScreen
|
import chat.revolt.screens.about.AboutScreen
|
||||||
import chat.revolt.screens.about.AttributionScreen
|
import chat.revolt.screens.about.AttributionScreen
|
||||||
|
|
@ -50,11 +68,151 @@ import chat.revolt.screens.settings.ProfileSettingsScreen
|
||||||
import chat.revolt.screens.settings.SessionSettingsScreen
|
import chat.revolt.screens.settings.SessionSettingsScreen
|
||||||
import chat.revolt.screens.settings.SettingsScreen
|
import chat.revolt.screens.settings.SettingsScreen
|
||||||
import chat.revolt.ui.theme.RevoltTheme
|
import chat.revolt.ui.theme.RevoltTheme
|
||||||
|
import com.google.android.material.color.DynamicColors
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import io.ktor.client.request.get
|
||||||
import io.sentry.android.core.SentryAndroid
|
import io.sentry.android.core.SentryAndroid
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
class MainActivityViewModel @Inject constructor(
|
||||||
|
private val kvStorage: KVStorage,
|
||||||
|
@ApplicationContext private val context: Context
|
||||||
|
) : ViewModel() {
|
||||||
|
val nextDestination = MutableStateFlow<String?>(null)
|
||||||
|
var isConnected = MutableStateFlow(false)
|
||||||
|
val isReady = MutableStateFlow(false)
|
||||||
|
|
||||||
|
private fun hasInternetConnection(): Boolean {
|
||||||
|
val connectivityManager =
|
||||||
|
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
|
||||||
|
val network = connectivityManager.activeNetwork ?: return false
|
||||||
|
val capabilities =
|
||||||
|
connectivityManager.getNetworkCapabilities(network) ?: return false
|
||||||
|
|
||||||
|
return when {
|
||||||
|
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
|
||||||
|
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
|
||||||
|
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
|
||||||
|
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun canReachRevolt(): Boolean {
|
||||||
|
val res = RevoltHttp.get("/")
|
||||||
|
return res.status.value == 200
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun startWithDestination(destination: String) {
|
||||||
|
nextDestination.emit(destination)
|
||||||
|
isReady.emit(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun startWithoutDestination() {
|
||||||
|
isReady.emit(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkLoggedInState() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
Log.d("MainActivity", "Checking logged in state")
|
||||||
|
|
||||||
|
isConnected.emit(hasInternetConnection())
|
||||||
|
|
||||||
|
Log.d("MainActivity", "Checking if we can reach Revolt")
|
||||||
|
|
||||||
|
if (!isConnected.value) return@launch startWithoutDestination()
|
||||||
|
|
||||||
|
Log.d("MainActivity", "We can reach Revolt, checking if we're logged in")
|
||||||
|
|
||||||
|
val token = kvStorage.get("sessionToken")
|
||||||
|
?: return@launch startWithDestination("login/greeting")
|
||||||
|
val id = kvStorage.get("sessionId") ?: ""
|
||||||
|
|
||||||
|
Log.d(
|
||||||
|
"MainActivity",
|
||||||
|
"We have a session token, checking if it's valid and if we can still reach Revolt"
|
||||||
|
)
|
||||||
|
|
||||||
|
val canReachRevolt = canReachRevolt()
|
||||||
|
val valid = try {
|
||||||
|
RevoltAPI.checkSessionToken(token)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canReachRevolt && !valid) {
|
||||||
|
Log.d("MainActivity", "Session token is invalid, clearing session")
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
context.getString(R.string.token_invalid_toast),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
kvStorage.remove("sessionToken")
|
||||||
|
kvStorage.remove("sessionId")
|
||||||
|
startWithDestination("login/greeting")
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Log.d("MainActivity", "Session token is valid, checking onboarding state")
|
||||||
|
val onboard = needsOnboarding(token)
|
||||||
|
if (onboard) {
|
||||||
|
Log.d("MainActivity", "Onboarding state is incomplete, starting onboarding")
|
||||||
|
startWithDestination("register/onboarding")
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("MainActivity", "Failed to check onboarding state, clearing session", e)
|
||||||
|
kvStorage.remove("sessionToken")
|
||||||
|
kvStorage.remove("sessionId")
|
||||||
|
startWithDestination("login/greeting")
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Log.d("MainActivity", "Onboarding state is complete, logging in")
|
||||||
|
RevoltAPI.loginAs(token)
|
||||||
|
RevoltAPI.setSessionId(id)
|
||||||
|
startWithDestination("chat")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("MainActivity", "Failed to login, clearing session", e)
|
||||||
|
kvStorage.remove("sessionToken")
|
||||||
|
kvStorage.remove("sessionId")
|
||||||
|
startWithDestination("login/greeting")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateNextDestination(destination: String) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
nextDestination.emit(null)
|
||||||
|
nextDestination.emit(destination)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
Log.d("MainActivity", "Starting up")
|
||||||
|
checkLoggedInState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MainActivity : FragmentActivity() {
|
class MainActivity : FragmentActivity() {
|
||||||
|
private val viewModel by viewModels<MainActivityViewModel>()
|
||||||
|
|
||||||
|
// Fix for SDK >=31, where core-splashscreen accidentally removes dynamic colours
|
||||||
|
// See the other one in DefaultDestinationScreen.kt
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
DynamicColors.applyToActivityIfAvailable(this)
|
||||||
|
DynamicColors.applyToActivitiesIfAvailable(RevoltApplication.instance)
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
|
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
@ -66,9 +224,21 @@ class MainActivity : FragmentActivity() {
|
||||||
|
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
|
||||||
|
installSplashScreen().apply {
|
||||||
|
setKeepOnScreenCondition {
|
||||||
|
!viewModel.isReady.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
val windowSizeClass = calculateWindowSizeClass(this)
|
val windowSizeClass = calculateWindowSizeClass(this)
|
||||||
AppEntrypoint(windowSizeClass)
|
AppEntrypoint(
|
||||||
|
windowSizeClass,
|
||||||
|
viewModel.nextDestination.collectAsState().value,
|
||||||
|
viewModel.isConnected.collectAsState().value,
|
||||||
|
viewModel::checkLoggedInState,
|
||||||
|
viewModel::updateNextDestination
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,7 +255,13 @@ val RevoltTweenDp: FiniteAnimationSpec<Dp> = tween(400, easing = EaseInOutExpo)
|
||||||
val RevoltTweenColour: FiniteAnimationSpec<Color> = tween(400, easing = EaseInOutExpo)
|
val RevoltTweenColour: FiniteAnimationSpec<Color> = tween(400, easing = EaseInOutExpo)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppEntrypoint(windowSizeClass: WindowSizeClass) {
|
fun AppEntrypoint(
|
||||||
|
windowSizeClass: WindowSizeClass,
|
||||||
|
nextDestination: String?,
|
||||||
|
isConnected: Boolean,
|
||||||
|
onRetryConnection: () -> Unit,
|
||||||
|
onUpdateNextDestination: (String) -> Unit = {}
|
||||||
|
) {
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
|
|
||||||
RevoltTheme(
|
RevoltTheme(
|
||||||
|
|
@ -98,7 +274,7 @@ fun AppEntrypoint(windowSizeClass: WindowSizeClass) {
|
||||||
) {
|
) {
|
||||||
NavHost(
|
NavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = "splash",
|
startDestination = "default",
|
||||||
enterTransition = {
|
enterTransition = {
|
||||||
slideIntoContainer(
|
slideIntoContainer(
|
||||||
AnimatedContentTransitionScope.SlideDirection.Left,
|
AnimatedContentTransitionScope.SlideDirection.Left,
|
||||||
|
|
@ -124,6 +300,14 @@ fun AppEntrypoint(windowSizeClass: WindowSizeClass) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
composable("default") {
|
||||||
|
DefaultDestinationScreen(
|
||||||
|
navController,
|
||||||
|
nextDestination,
|
||||||
|
isConnected,
|
||||||
|
onRetryConnection
|
||||||
|
)
|
||||||
|
}
|
||||||
composable("splash") { SplashScreen(navController) }
|
composable("splash") { SplashScreen(navController) }
|
||||||
|
|
||||||
composable("login/greeting") { LoginGreetingScreen(navController) }
|
composable("login/greeting") { LoginGreetingScreen(navController) }
|
||||||
|
|
@ -143,9 +327,34 @@ fun AppEntrypoint(windowSizeClass: WindowSizeClass) {
|
||||||
|
|
||||||
RegisterVerifyScreen(navController, email)
|
RegisterVerifyScreen(navController, email)
|
||||||
}
|
}
|
||||||
composable("register/onboarding") { OnboardingScreen(navController) }
|
composable("register/onboarding") {
|
||||||
|
OnboardingScreen(
|
||||||
|
navController,
|
||||||
|
onOnboardingComplete = {
|
||||||
|
onUpdateNextDestination("chat")
|
||||||
|
navController.popBackStack(
|
||||||
|
navController.graph.startDestinationRoute!!,
|
||||||
|
inclusive = true
|
||||||
|
)
|
||||||
|
navController.navigate("default")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
composable("chat") { ChatRouterScreen(navController, windowSizeClass) }
|
composable("chat") {
|
||||||
|
ChatRouterScreen(
|
||||||
|
navController,
|
||||||
|
windowSizeClass,
|
||||||
|
onNullifiedUser = {
|
||||||
|
onRetryConnection()
|
||||||
|
navController.popBackStack(
|
||||||
|
navController.graph.startDestinationRoute!!,
|
||||||
|
inclusive = true
|
||||||
|
)
|
||||||
|
navController.navigate("default")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
composable("discover") { DiscoverScreen(navController) }
|
composable("discover") { DiscoverScreen(navController) }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,11 @@ val RevoltHttp = HttpClient(OkHttp) {
|
||||||
engine {
|
engine {
|
||||||
addInterceptor { chain ->
|
addInterceptor { chain ->
|
||||||
val request = chain.request().newBuilder()
|
val request = chain.request().newBuilder()
|
||||||
.header(RevoltAPI.TOKEN_HEADER_NAME, RevoltAPI.sessionToken)
|
.apply {
|
||||||
|
if (chain.request().headers[RevoltAPI.TOKEN_HEADER_NAME] == null) {
|
||||||
|
header(RevoltAPI.TOKEN_HEADER_NAME, RevoltAPI.sessionToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
.build()
|
.build()
|
||||||
chain.proceed(request)
|
chain.proceed(request)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package chat.revolt.api.internals
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.ContextWrapper
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
|
||||||
|
fun Context.getComponentActivity(): ComponentActivity? = when (this) {
|
||||||
|
is ComponentActivity -> this
|
||||||
|
is ContextWrapper -> baseContext.getComponentActivity()
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,7 @@ suspend fun fetchSelf(): User {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val error = RevoltJson.decodeFromString(RevoltError.serializer(), response)
|
val error = RevoltJson.decodeFromString(RevoltError.serializer(), response)
|
||||||
throw Error(error.type)
|
throw Exception(error.type)
|
||||||
} catch (e: SerializationException) {
|
} catch (e: SerializationException) {
|
||||||
// Not an error
|
// Not an error
|
||||||
}
|
}
|
||||||
|
|
@ -33,7 +33,7 @@ suspend fun fetchSelf(): User {
|
||||||
val user = RevoltJson.decodeFromString(User.serializer(), response)
|
val user = RevoltJson.decodeFromString(User.serializer(), response)
|
||||||
|
|
||||||
if (user.id == null) {
|
if (user.id == null) {
|
||||||
throw Error("Self user ID is null")
|
throw Exception("Self user ID is null")
|
||||||
}
|
}
|
||||||
|
|
||||||
RevoltAPI.userCache[user.id] = user
|
RevoltAPI.userCache[user.id] = user
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package chat.revolt.screens
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import chat.revolt.RevoltApplication
|
||||||
|
import chat.revolt.api.internals.getComponentActivity
|
||||||
|
import chat.revolt.components.screens.splash.DisconnectedScreen
|
||||||
|
import com.google.android.material.color.DynamicColors
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DefaultDestinationScreen(
|
||||||
|
navController: NavController,
|
||||||
|
nextDestination: String? = null,
|
||||||
|
isConnected: Boolean = false,
|
||||||
|
onRetryConnection: () -> Unit = {}
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
if (!isConnected) {
|
||||||
|
DisconnectedScreen(
|
||||||
|
onRetry = {
|
||||||
|
onRetryConnection()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(nextDestination) {
|
||||||
|
nextDestination?.let {
|
||||||
|
// Fix for SDK >=31, where core-splashscreen accidentally removes dynamic colours
|
||||||
|
// See the other one in MainActivity.kt
|
||||||
|
DynamicColors.applyToActivityIfAvailable(context.getComponentActivity() as Activity)
|
||||||
|
DynamicColors.applyToActivitiesIfAvailable(RevoltApplication.instance)
|
||||||
|
|
||||||
|
navController.popBackStack(navController.graph.startDestinationRoute!!, true)
|
||||||
|
navController.navigate(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(Modifier.fillMaxSize())
|
||||||
|
}
|
||||||
|
|
@ -293,6 +293,7 @@ class ChatRouterViewModel @Inject constructor(
|
||||||
fun ChatRouterScreen(
|
fun ChatRouterScreen(
|
||||||
topNav: NavController,
|
topNav: NavController,
|
||||||
windowSizeClass: WindowSizeClass,
|
windowSizeClass: WindowSizeClass,
|
||||||
|
onNullifiedUser: () -> Unit,
|
||||||
viewModel: ChatRouterViewModel = hiltViewModel()
|
viewModel: ChatRouterViewModel = hiltViewModel()
|
||||||
) {
|
) {
|
||||||
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
||||||
|
|
@ -385,11 +386,7 @@ fun ChatRouterScreen(
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.collect { selfId ->
|
.collect { selfId ->
|
||||||
if (selfId == null) {
|
if (selfId == null) {
|
||||||
topNav.popBackStack(
|
onNullifiedUser()
|
||||||
topNav.graph.startDestinationRoute!!,
|
|
||||||
inclusive = true
|
|
||||||
)
|
|
||||||
topNav.navigate("splash")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import chat.revolt.persistence.KVStorage
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun OnboardingScreen(navController: NavController) {
|
fun OnboardingScreen(navController: NavController, onOnboardingComplete: () -> Unit) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
|
@ -40,9 +40,12 @@ fun OnboardingScreen(navController: NavController) {
|
||||||
val error = remember { mutableStateOf("") }
|
val error = remember { mutableStateOf("") }
|
||||||
|
|
||||||
fun onboardingComplete() {
|
fun onboardingComplete() {
|
||||||
navController.navigate("splash") {
|
onOnboardingComplete()
|
||||||
popUpTo("register/onboarding") { inclusive = true }
|
navController.popBackStack(
|
||||||
}
|
navController.graph.startDestinationRoute!!,
|
||||||
|
inclusive = true
|
||||||
|
)
|
||||||
|
navController.navigate("default")
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun onboard() {
|
suspend fun onboard() {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="foreground">#FFFFFFFF</color>
|
<color name="foreground">#FFFFFFFF</color>
|
||||||
|
<color name="splashscreen_background">#FF131722</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -2,5 +2,6 @@
|
||||||
<resources>
|
<resources>
|
||||||
<color name="primary">#FFDA4E5B</color>
|
<color name="primary">#FFDA4E5B</color>
|
||||||
<color name="background">#FF131722</color>
|
<color name="background">#FF131722</color>
|
||||||
|
<color name="splashscreen_background">#FFFFFFFF</color>
|
||||||
<color name="foreground">#FF000000</color>
|
<color name="foreground">#FF000000</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -1,8 +1,15 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<style name="Theme.Revolt" parent="Theme.Material3.DayNight.NoActionBar">
|
<style name="Theme.Revolt" parent="Theme.Material3.DayNight.NoActionBar">
|
||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="Theme.Revolt.Starting" parent="Theme.SplashScreen" tools:targetApi="tiramisu">
|
||||||
|
<item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_launcher_foreground</item>
|
||||||
|
<item name="android:windowSplashScreenBackground">@color/splashscreen_background</item>
|
||||||
|
<item name="android:windowSplashScreenBehavior">icon_preferred</item>
|
||||||
|
<item name="postSplashScreenTheme">@style/Theme.Revolt</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
Reference in New Issue