mirror of
https://github.com/bitwarden/android.git
synced 2025-12-11 22:52:20 -06:00
BIT-147: Improve splash screen handling for all OS levels (#72)
This commit is contained in:
parent
a223e2fed5
commit
5fc78afa0a
@ -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.
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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 },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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),
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -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 |
@ -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>
|
|
||||||
@ -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>
|
|
||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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" }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user