BIT-147: Improve splash screen handling for all OS levels (#72)

This commit is contained in:
Brian Yencho 2023-09-28 14:18:03 -05:00 committed by Álison Fernandes
parent a223e2fed5
commit 5fc78afa0a
17 changed files with 38 additions and 31 deletions

View File

@ -62,6 +62,11 @@ The following is a list of all third-party dependencies included as part of the
- Purpose: Supplementary Android Compose features. - Purpose: Supplementary Android Compose features.
- License: Apache 2.0 - License: Apache 2.0
- **Core SplashScreen**
- https://developer.android.com/jetpack/androidx/releases/core
- Purpose: Backwards compatible SplashScreen API implementation.
- License: Apache 2.0
- **Dagger Hilt** - **Dagger Hilt**
- https://github.com/google/dagger - https://github.com/google/dagger
- Purpose: Dependency injection framework. - Purpose: Dependency injection framework.

View File

@ -91,6 +91,7 @@ dependencies {
ksp(libs.androidx.room.compiler) ksp(libs.androidx.room.compiler)
implementation(libs.androidx.room.ktx) implementation(libs.androidx.room.ktx)
implementation(libs.androidx.room.runtime) implementation(libs.androidx.room.runtime)
implementation(libs.androidx.splashscreen)
implementation(platform(libs.google.firebase.bom)) implementation(platform(libs.google.firebase.bom))
implementation(libs.bitwarden.sdk) implementation(libs.bitwarden.sdk)
implementation(libs.bumptech.glide) implementation(libs.bumptech.glide)

View File

@ -3,6 +3,7 @@ package com.x8bit.bitwarden
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import com.x8bit.bitwarden.ui.platform.feature.rootnav.RootNavScreen import com.x8bit.bitwarden.ui.platform.feature.rootnav.RootNavScreen
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -13,10 +14,14 @@ import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
var shouldShowSplashScreen = true
installSplashScreen().setKeepOnScreenCondition { shouldShowSplashScreen }
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
BitwardenTheme { BitwardenTheme {
RootNavScreen() RootNavScreen(
onSplashScreenRemoved = { shouldShowSplashScreen = false },
)
} }
} }
} }

View File

@ -4,6 +4,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button import androidx.compose.material3.Button
@ -42,6 +43,7 @@ fun LoginScreen(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(12.dp), verticalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background) .background(MaterialTheme.colorScheme.background)
.padding(horizontal = 16.dp, vertical = 32.dp), .padding(horizontal = 16.dp, vertical = 32.dp),
) { ) {

View File

@ -1,6 +1,7 @@
package com.x8bit.bitwarden.ui.platform.feature.rootnav package com.x8bit.bitwarden.ui.platform.feature.rootnav
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
@ -23,9 +24,15 @@ import com.x8bit.bitwarden.ui.platform.feature.vaultunlocked.vaultUnlockedDestin
fun RootNavScreen( fun RootNavScreen(
viewModel: RootNavViewModel = hiltViewModel(), viewModel: RootNavViewModel = hiltViewModel(),
navController: NavHostController = rememberNavController(), navController: NavHostController = rememberNavController(),
onSplashScreenRemoved: () -> Unit = {},
) { ) {
val state by viewModel.stateFlow.collectAsStateWithLifecycle() val state by viewModel.stateFlow.collectAsStateWithLifecycle()
val isNotSplashScreen = state != RootNavState.Splash
LaunchedEffect(isNotSplashScreen) {
if (isNotSplashScreen) onSplashScreenRemoved()
}
NavHost( NavHost(
navController = navController, navController = navController,
startDestination = SPLASH_ROUTE, startDestination = SPLASH_ROUTE,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="@color/white"/>
</item>
<item>
<bitmap android:src="@drawable/logo_legacy" android:tileMode="disabled" android:gravity="center"/>
</item>
</layer-list>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="@color/dark_gray" />
</item>
<item>
<bitmap
android:gravity="center"
android:src="@drawable/logo_white_legacy"
android:tileMode="disabled" />
</item>
</layer-list>

View File

@ -12,6 +12,7 @@
<item name="android:textCursorDrawable">@null</item> <item name="android:textCursorDrawable">@null</item>
<item name="android:windowActionBar">false</item> <item name="android:windowActionBar">false</item>
<item name="android:windowActionModeOverlay">true</item> <item name="android:windowActionModeOverlay">true</item>
<item name="android:windowBackground">@null</item>
<item name="android:windowNoTitle">true</item> <item name="android:windowNoTitle">true</item>
</style> </style>
@ -20,10 +21,9 @@
</style> </style>
<!-- Launch theme (for auto dark/light based on system) --> <!-- Launch theme (for auto dark/light based on system) -->
<style name="LaunchTheme" parent="BaseTheme"> <style name="LaunchTheme" parent="Theme.SplashScreen">
<item name="android:windowBackground">@drawable/splash_screen_dark</item> <item name="postSplashScreenTheme">@style/BaseTheme</item>
<item name="android:windowNoTitle">true</item> <item name="windowSplashScreenAnimatedIcon">
<item name="android:windowSplashScreenAnimatedIcon" tools:ignore="NewApi">
@drawable/splash_screen_round @drawable/splash_screen_round
</item> </item>
</style> </style>

View File

@ -12,6 +12,7 @@
<item name="android:popupTheme">@android:style/ThemeOverlay.Material.Light</item> <item name="android:popupTheme">@android:style/ThemeOverlay.Material.Light</item>
<item name="android:textCursorDrawable">@null</item> <item name="android:textCursorDrawable">@null</item>
<item name="android:windowActionBar">false</item> <item name="android:windowActionBar">false</item>
<item name="android:windowBackground">@null</item>
<item name="android:windowNoTitle">true</item> <item name="android:windowNoTitle">true</item>
<item name="android:windowActionModeOverlay">true</item> <item name="android:windowActionModeOverlay">true</item>
</style> </style>
@ -21,13 +22,12 @@
</style> </style>
<!-- Launch theme (for auto dark/light based on system) --> <!-- Launch theme (for auto dark/light based on system) -->
<style name="LaunchTheme" parent="BaseTheme"> <style name="LaunchTheme" parent="Theme.SplashScreen">
<item name="android:windowBackground">@drawable/splash_screen</item> <item name="postSplashScreenTheme">@style/BaseTheme</item>
<item name="android:windowNoTitle">true</item> <item name="windowSplashScreenAnimatedIcon">
<item name="android:windowSplashScreenAnimatedIcon" tools:ignore="NewApi">
@drawable/splash_screen_round @drawable/splash_screen_round
</item> </item>
<item name="android:windowSplashScreenBackground" tools:ignore="NewApi"> <item name="windowSplashScreenBackground">
@color/ic_launcher_background @color/ic_launcher_background
</item> </item>
</style> </style>

View File

@ -8,6 +8,8 @@ import io.mockk.mockk
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
class RootNavScreenTest : BaseComposeTest() { class RootNavScreenTest : BaseComposeTest() {
@ -47,15 +49,18 @@ class RootNavScreenTest : BaseComposeTest() {
every { eventFlow } returns emptyFlow() every { eventFlow } returns emptyFlow()
every { stateFlow } returns rootNavStateFlow every { stateFlow } returns rootNavStateFlow
} }
var isSplashScreenRemoved = false
composeTestRule.setContent { composeTestRule.setContent {
RootNavScreen( RootNavScreen(
viewModel = viewModel, viewModel = viewModel,
navController = fakeNavHostController, navController = fakeNavHostController,
onSplashScreenRemoved = { isSplashScreenRemoved = true },
) )
} }
composeTestRule.runOnIdle { composeTestRule.runOnIdle {
fakeNavHostController.assertCurrentRoute("splash") fakeNavHostController.assertCurrentRoute("splash")
} }
assertFalse(isSplashScreenRemoved)
// Make sure navigating to Auth works as expected: // Make sure navigating to Auth works as expected:
rootNavStateFlow.value = RootNavState.Auth rootNavStateFlow.value = RootNavState.Auth
@ -65,6 +70,7 @@ class RootNavScreenTest : BaseComposeTest() {
navOptions = expectedNavOptions, navOptions = expectedNavOptions,
) )
} }
assertTrue(isSplashScreenRemoved)
// Make sure navigating to vault unlocked works as expected: // Make sure navigating to vault unlocked works as expected:
rootNavStateFlow.value = RootNavState.VaultUnlocked rootNavStateFlow.value = RootNavState.VaultUnlocked

View File

@ -16,6 +16,7 @@ androidxHiltNavigationCompose = "1.0.0"
androidxLifecycle = "2.6.1" androidxLifecycle = "2.6.1"
androidxNavigation = "2.7.2" androidxNavigation = "2.7.2"
androidxRoom = "2.5.2" androidxRoom = "2.5.2"
androidxSplash = "1.1.0-alpha02"
# Once the app and SDK reach a critical point of completeness we should begin fixing the version # Once the app and SDK reach a critical point of completeness we should begin fixing the version
# here (BIT-311). # here (BIT-311).
bitwardenSdk = "0.3.0-SNAPSHOT" bitwardenSdk = "0.3.0-SNAPSHOT"
@ -60,6 +61,7 @@ androidx-navigation-compose = { module = "androidx.navigation:navigation-compose
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "androidxRoom" } androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "androidxRoom" }
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidxRoom" } androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidxRoom" }
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "androidxRoom" } androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "androidxRoom" }
androidx-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "androidxSplash" }
bitwarden-sdk = { module = "com.bitwarden:sdk-android", version.ref = "bitwardenSdk" } bitwarden-sdk = { module = "com.bitwarden:sdk-android", version.ref = "bitwardenSdk" }
bumptech-glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" } bumptech-glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
detekt-detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } detekt-detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }