enhancement: add workaround for solid status bar color (#303)

* define interface for workaround

* expose opaque theme support in bar color provider

* update iOS implementation or bar color provider

* update Android implementation or bar color provider

* restore option in advanced settings

* update Gradle scripts

* apply workaround in MainActivity
This commit is contained in:
Dieguitux 2025-01-27 23:33:22 +01:00 committed by GitHub
parent a49cc6258e
commit c17f31e8ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 112 additions and 27 deletions

View File

@ -94,9 +94,11 @@ dependencies {
implementation(libs.voyager.tab)
implementation(projects.shared)
implementation(projects.core.appearance)
implementation(projects.core.di)
implementation(projects.core.utils)
implementation(projects.core.navigation)
implementation(projects.core.persistence)
implementation(projects.core.resources)
kover(projects.shared)

View File

@ -10,12 +10,19 @@ import androidx.activity.enableEdgeToEdge
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.lifecycleScope
import com.livefast.eattrash.raccoonforlemmy.MainView
import com.livefast.eattrash.raccoonforlemmy.core.appearance.data.toUiBarTheme
import com.livefast.eattrash.raccoonforlemmy.core.appearance.data.toUiTheme
import com.livefast.eattrash.raccoonforlemmy.core.appearance.di.getBarColorProvider
import com.livefast.eattrash.raccoonforlemmy.core.appearance.theme.SolidBarColorWorkaround
import com.livefast.eattrash.raccoonforlemmy.core.navigation.ComposeEvent
import com.livefast.eattrash.raccoonforlemmy.core.navigation.TabNavigationSection
import com.livefast.eattrash.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
import com.livefast.eattrash.raccoonforlemmy.core.persistence.di.getAccountRepository
import com.livefast.eattrash.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.livefast.eattrash.raccoonforlemmy.feature.home.ui.HomeTab
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@ -79,6 +86,11 @@ class MainActivity : ComponentActivity() {
handleIntent(intent)
}
override fun onResume() {
super.onResume()
applyWorkaroundForSolidStatusBar()
}
private fun handleIntent(intent: Intent?) =
intent?.apply {
when (action) {
@ -110,4 +122,20 @@ class MainActivity : ComponentActivity() {
val navigationCoordinator = getNavigationCoordinator()
navigationCoordinator.submitComposeEvent(event)
}
private fun applyWorkaroundForSolidStatusBar() {
val barColorProvider = getBarColorProvider()
val settingsRepository = getSettingsRepository()
val accountRepository = getAccountRepository()
val settings =
runBlocking {
val accountId = accountRepository.getActive()?.id
settingsRepository.getSettings(accountId)
}
(barColorProvider as? SolidBarColorWorkaround)?.apply(
activity = this@MainActivity,
theme = settings.theme.toUiTheme(),
barTheme = settings.systemBarTheme.toUiBarTheme(),
)
}
}

View File

@ -2,6 +2,7 @@ package com.livefast.eattrash.raccoonforlemmy.core.appearance.theme
import android.app.Activity
import android.os.Build
import android.view.WindowInsets
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -12,9 +13,14 @@ import androidx.core.view.WindowCompat
import com.livefast.eattrash.raccoonforlemmy.core.appearance.data.UiBarTheme
import com.livefast.eattrash.raccoonforlemmy.core.appearance.data.UiTheme
internal class DefaultBarColorProvider : BarColorProvider {
override val isBarThemeSupported: Boolean
get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM
internal class DefaultBarColorProvider :
BarColorProvider,
SolidBarColorWorkaround {
override val isBarThemeSupported = true
override val isOpaqueThemeSupported: Boolean
get() {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM
}
@Composable
override fun setBarColorAccordingToTheme(
@ -25,24 +31,8 @@ internal class DefaultBarColorProvider : BarColorProvider {
val isSystemInDarkTheme = isSystemInDarkTheme()
LaunchedEffect(theme, barTheme) {
(view.context as? Activity)?.window?.apply {
val baseColor =
when (theme) {
UiTheme.Light -> Color.White
UiTheme.Black, UiTheme.Dark -> Color.Black
UiTheme.Default ->
if (isSystemInDarkTheme) {
Color.Black
} else {
Color.White
}
else -> Color.Black
}
val barColor =
when (barTheme) {
UiBarTheme.Opaque -> baseColor.copy(alpha = 0.25f)
UiBarTheme.Transparent -> baseColor.copy(alpha = 0.01f)
else -> baseColor
}.toArgb()
val baseColor = theme.getBaseColor(isSystemInDarkTheme)
val barColor = barTheme.getBarColor(baseColor).toArgb()
if (isBarThemeSupported) {
statusBarColor = barColor
navigationBarColor = barColor
@ -50,7 +40,7 @@ internal class DefaultBarColorProvider : BarColorProvider {
WindowCompat.setDecorFitsSystemWindows(this, false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
if (isBarThemeSupported) {
isStatusBarContrastEnforced = true
}
isNavigationBarContrastEnforced = true
@ -71,4 +61,50 @@ internal class DefaultBarColorProvider : BarColorProvider {
}
}
}
override fun apply(
activity: Activity,
theme: UiTheme,
barTheme: UiBarTheme,
) {
if (barTheme == UiBarTheme.Transparent) {
return
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
return
}
val decorView = activity.window.decorView
val isSystemInDarkTheme = activity.resources.configuration.isNightModeActive
val baseColor = theme.getBaseColor(isSystemInDarkTheme)
val barColor = barTheme.getBarColor(baseColor).toArgb()
decorView.setOnApplyWindowInsetsListener { view, insets ->
val systemBarInsets = insets.getInsets(WindowInsets.Type.systemBars())
view.setBackgroundColor(barColor)
view.setPadding(0, systemBarInsets.top, 0, systemBarInsets.bottom)
insets
}
}
}
private fun UiTheme.getBaseColor(isSystemInDarkTheme: Boolean): Color =
when (this) {
UiTheme.Light -> Color.White
UiTheme.Black, UiTheme.Dark -> Color.Black
UiTheme.Default ->
if (isSystemInDarkTheme) {
Color.Black
} else {
Color.White
}
else -> Color.Black
}
private fun UiBarTheme.getBarColor(baseColor: Color): Color =
when (this) {
UiBarTheme.Opaque -> baseColor.copy(alpha = 0.25f)
UiBarTheme.Transparent -> baseColor.copy(alpha = 0.01f)
else -> baseColor
}

View File

@ -0,0 +1,13 @@
package com.livefast.eattrash.raccoonforlemmy.core.appearance.theme
import android.app.Activity
import com.livefast.eattrash.raccoonforlemmy.core.appearance.data.UiBarTheme
import com.livefast.eattrash.raccoonforlemmy.core.appearance.data.UiTheme
interface SolidBarColorWorkaround {
fun apply(
activity: Activity,
theme: UiTheme,
barTheme: UiBarTheme,
)
}

View File

@ -6,6 +6,7 @@ import com.livefast.eattrash.raccoonforlemmy.core.appearance.data.UiTheme
interface BarColorProvider {
val isBarThemeSupported: Boolean
val isOpaqueThemeSupported: Boolean
@Composable
fun setBarColorAccordingToTheme(

View File

@ -11,6 +11,7 @@ import platform.UIKit.setStatusBarStyle
internal class DefaultBarColorProvider : BarColorProvider {
override val isBarThemeSupported = false
override val isOpaqueThemeSupported = false
@Composable
override fun setBarColorAccordingToTheme(

View File

@ -131,6 +131,7 @@ interface AdvancedSettingsMviModel :
val enableAlternateMarkdownRendering: Boolean = false,
val restrictLocalUserSearch: Boolean = false,
val isBarThemeSupported: Boolean = false,
val isBarOpaqueThemeSupported: Boolean = false,
val markAsReadOnInteraction: Boolean = true,
)

View File

@ -665,11 +665,13 @@ class AdvancedSettingsScreen : Screen {
if (barThemeBottomSheetOpened) {
val values =
listOf(
UiBarTheme.Transparent,
UiBarTheme.Opaque,
UiBarTheme.Solid,
)
buildList {
this += UiBarTheme.Transparent
if (uiState.isBarOpaqueThemeSupported) {
this += UiBarTheme.Opaque
}
this += UiBarTheme.Solid
}
CustomModalBottomSheet(
title = LocalStrings.current.settingsBarTheme,
items =

View File

@ -167,6 +167,7 @@ class AdvancedSettingsViewModel(
enableAlternateMarkdownRendering = settings.enableAlternateMarkdownRendering,
restrictLocalUserSearch = settings.restrictLocalUserSearch,
isBarThemeSupported = barColorProvider.isBarThemeSupported,
isBarOpaqueThemeSupported = barColorProvider.isOpaqueThemeSupported,
markAsReadOnInteraction = settings.markAsReadOnInteraction,
)
}