Add option to color system bar icons automatically

This commit is contained in:
MM20
2022-10-21 17:20:09 +02:00
parent 62f4cb6e0e
commit 9db2372253
21 changed files with 99 additions and 75 deletions
@@ -4,6 +4,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings.SystemBarsSettings
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
@@ -23,19 +24,8 @@ class LauncherActivityVM : ViewModel(), KoinComponent {
}
val dimBackground = dimBackgroundState.asLiveData()
val lightStatusBar = combine(
dimBackgroundState,
dataStore.data.map { it.systemBars.lightStatusBar }
) { dim, light ->
!dim && light
}.asLiveData()
val lightNavBar = combine(
dimBackgroundState,
dataStore.data.map { it.systemBars.lightNavBar }
) { dim, light ->
!dim && light
}.asLiveData()
val statusBarColor = dataStore.data.map { it.systemBars.statusBarColor }.asLiveData()
val navBarColor = dataStore.data.map { it.systemBars.statusBarColor }.asLiveData()
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }.asLiveData()
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }.asLiveData()
@@ -35,6 +35,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.preferences.Settings.SystemBarsSettings.SystemBarColors
import de.mm20.launcher2.ui.assistant.AssistantScaffold
import de.mm20.launcher2.ui.base.BaseActivity
import de.mm20.launcher2.ui.base.ProvideCurrentTime
@@ -44,9 +45,12 @@ import de.mm20.launcher2.ui.ktx.animateTo
import de.mm20.launcher2.ui.launcher.transitions.HomeTransition
import de.mm20.launcher2.ui.launcher.transitions.HomeTransitionManager
import de.mm20.launcher2.ui.launcher.transitions.LocalHomeTransitionManager
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
import de.mm20.launcher2.ui.locals.LocalSnackbarHostState
import de.mm20.launcher2.ui.locals.LocalWallpaperColors
import de.mm20.launcher2.ui.locals.LocalWindowSize
import de.mm20.launcher2.ui.theme.LauncherTheme
import de.mm20.launcher2.ui.theme.wallpaperColorsAsState
import kotlin.math.pow
@@ -73,19 +77,26 @@ abstract class SharedLauncherActivity(
setContent {
val snackbarHostState = remember { SnackbarHostState() }
val wallpaperColors by wallpaperColorsAsState()
val dimBackground by viewModel.dimBackground.observeAsState(false)
CompositionLocalProvider(
LocalHomeTransitionManager provides homeTransitionManager,
LocalWindowSize provides windowSize,
LocalSnackbarHostState provides snackbarHostState
LocalSnackbarHostState provides snackbarHostState,
LocalWallpaperColors provides wallpaperColors,
LocalPreferDarkContentOverWallpaper provides (!dimBackground && wallpaperColors.supportsDarkText),
) {
LauncherTheme {
ProvideCurrentTime {
ProvideSettings {
val lightStatus by viewModel.lightStatusBar.observeAsState(false)
val lightNav by viewModel.lightNavBar.observeAsState(false)
val statusBarColor by viewModel.statusBarColor.observeAsState(SystemBarColors.Auto)
val navBarColor by viewModel.navBarColor.observeAsState(SystemBarColors.Auto)
val lightStatus = !dimBackground && (statusBarColor == SystemBarColors.Dark || statusBarColor == SystemBarColors.Auto && wallpaperColors.supportsDarkText)
val lightNav = !dimBackground && (navBarColor == SystemBarColors.Dark || navBarColor == SystemBarColors.Auto && wallpaperColors.supportsDarkText)
val hideStatus by viewModel.hideStatusBar.observeAsState(false)
val hideNav by viewModel.hideNavBar.observeAsState(false)
val dimBackground by viewModel.dimBackground.observeAsState(false)
val layout by viewModel.layout.observeAsState(null)
val systemUiController = rememberSystemUiController()
@@ -4,10 +4,10 @@ import android.appwidget.AppWidgetHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.preferences.Settings.GridSettings
import de.mm20.launcher2.ui.theme.WallpaperColors
val LocalWindowSize = compositionLocalOf { Size(0f, 0f) }
@@ -29,4 +29,8 @@ val LocalDarkTheme = compositionLocalOf { false }
* Workaround a bug in Jetpack Compose which incorrectly places popups
* that are nested inside other popups.
*/
val LocalWindowPosition = compositionLocalOf { 0f }
val LocalWindowPosition = compositionLocalOf { 0f }
val LocalWallpaperColors = compositionLocalOf { WallpaperColors() }
val LocalPreferDarkContentOverWallpaper = compositionLocalOf { false }
@@ -20,6 +20,7 @@ import de.mm20.launcher2.ui.theme.LauncherTheme
import de.mm20.launcher2.ui.base.BaseActivity
import de.mm20.launcher2.ui.locals.LocalCardStyle
import de.mm20.launcher2.ui.locals.LocalNavController
import de.mm20.launcher2.ui.locals.LocalWallpaperColors
import de.mm20.launcher2.ui.settings.about.AboutSettingsScreen
import de.mm20.launcher2.ui.settings.accounts.AccountsSettingsScreen
import de.mm20.launcher2.ui.settings.appearance.AppearanceSettingsScreen
@@ -47,6 +48,7 @@ import de.mm20.launcher2.ui.settings.weatherwidget.WeatherWidgetSettingsScreen
import de.mm20.launcher2.ui.settings.websearch.WebSearchSettingsScreen
import de.mm20.launcher2.ui.settings.widgets.WidgetsSettingsScreen
import de.mm20.launcher2.ui.settings.wikipedia.WikipediaSettingsScreen
import de.mm20.launcher2.ui.theme.wallpaperColorsAsState
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import org.koin.android.ext.android.inject
@@ -72,9 +74,11 @@ class SettingsActivity : BaseActivity() {
}.collectAsState(
Settings.CardSettings.getDefaultInstance()
)
val wallpaperColors by wallpaperColorsAsState()
CompositionLocalProvider(
LocalNavController provides navController,
LocalCardStyle provides cardStyle
LocalCardStyle provides cardStyle,
LocalWallpaperColors provides wallpaperColors,
) {
LauncherTheme {
AnimatedNavHost(
@@ -33,6 +33,7 @@ import de.mm20.launcher2.ktx.isAtLeastApiLevel
import de.mm20.launcher2.preferences.Settings.*
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
import de.mm20.launcher2.preferences.Settings.SystemBarsSettings.SystemBarColors
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
import de.mm20.launcher2.ui.component.getShape
@@ -251,20 +252,30 @@ fun AppearanceSettingsScreen() {
)
}
PreferenceCategory(stringResource(R.string.preference_category_system_bars)) {
val lightStatusBar by viewModel.lightStatusBar.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_light_status_bar),
value = lightStatusBar == true,
val lightStatusBar by viewModel.statusBarIcons.observeAsState()
ListPreference(
title = stringResource(R.string.preference_status_bar_icons),
value = lightStatusBar,
items = listOf(
stringResource(R.string.preference_system_bar_icons_auto) to SystemBarColors.Auto,
stringResource(R.string.preference_system_bar_icons_light) to SystemBarColors.Light,
stringResource(R.string.preference_system_bar_icons_dark) to SystemBarColors.Dark,
),
onValueChanged = {
viewModel.setLightStatusBar(it)
if (it != null) viewModel.setLightStatusBar(it)
}
)
val lightNavBar by viewModel.lightNavBar.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_light_nav_bar),
value = lightNavBar == true,
val lightNavBar by viewModel.navBarIcons.observeAsState()
ListPreference(
title = stringResource(R.string.preference_nav_bar_icons),
value = lightNavBar,
items = listOf(
stringResource(R.string.preference_system_bar_icons_auto) to SystemBarColors.Auto,
stringResource(R.string.preference_system_bar_icons_light) to SystemBarColors.Light,
stringResource(R.string.preference_system_bar_icons_dark) to SystemBarColors.Dark,
),
onValueChanged = {
viewModel.setLightNavBar(it)
if (it != null) viewModel.setLightNavBar(it)
}
)
val hideStatusBar by viewModel.hideStatusBar.observeAsState()
@@ -13,6 +13,7 @@ import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.*
import de.mm20.launcher2.preferences.Settings.SearchBarSettings
import de.mm20.launcher2.preferences.Settings.SystemBarsSettings
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
@@ -217,28 +218,28 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
}
}
val lightStatusBar = dataStore.data.map { it.systemBars.lightStatusBar }.asLiveData()
fun setLightStatusBar(lightStatusBar: Boolean) {
val statusBarIcons = dataStore.data.map { it.systemBars.statusBarColor }.asLiveData()
fun setLightStatusBar(statusBarColor: SystemBarsSettings.SystemBarColors) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSystemBars(
it.systemBars.toBuilder()
.setLightStatusBar(lightStatusBar)
.setStatusBarColor(statusBarColor)
)
.build()
}
}
}
val lightNavBar = dataStore.data.map { it.systemBars.lightNavBar }.asLiveData()
fun setLightNavBar(lightNavBar: Boolean) {
val navBarIcons = dataStore.data.map { it.systemBars.navBarColor }.asLiveData()
fun setLightNavBar(navBarColors: SystemBarsSettings.SystemBarColors) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSystemBars(
it.systemBars.toBuilder()
.setLightNavBar(lightNavBar)
.setNavBarColor(navBarColors)
)
.build()
}
@@ -16,6 +16,7 @@ import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
import de.mm20.launcher2.ui.locals.LocalDarkTheme
import de.mm20.launcher2.ui.locals.LocalWallpaperColors
import de.mm20.launcher2.ui.theme.colorscheme.*
import de.mm20.launcher2.ui.theme.typography.DefaultTypography
import de.mm20.launcher2.ui.theme.typography.getDeviceDefaultTypography
@@ -124,11 +125,10 @@ fun colorSchemeAsState(
}
else -> {
if (Build.VERSION.SDK_INT >= 27 && (Build.VERSION.SDK_INT < 31 || colorScheme == AppearanceSettings.ColorScheme.DebugMaterialYouCompat)) {
val wallpaperColors by wallpaperColorsAsState()
val wallpaperColors = LocalWallpaperColors.current
val state = remember(wallpaperColors, darkTheme) {
mutableStateOf(
wallpaperColors?.let { MaterialYouCompatScheme(it, darkTheme) }
?: if (darkTheme) DarkDefaultColorScheme else LightDefaultColorScheme
MaterialYouCompatScheme(wallpaperColors, darkTheme)
)
}
return state
@@ -5,21 +5,35 @@ import android.os.Build
import android.os.Handler
import android.os.Looper
import androidx.annotation.RequiresApi
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
data class WallpaperColors(val primary: Color, val secondary: Color?, val tertiary: Color?) {
data class WallpaperColors(
val primary: Color = Color(0xFF3C6089),
val secondary: Color? = null,
val tertiary: Color? = null,
private val hints: Int = 0,
) {
val supportsDarkText: Boolean
get() = hints and android.app.WallpaperColors.HINT_SUPPORTS_DARK_TEXT != 0
companion object {
@RequiresApi(Build.VERSION_CODES.O_MR1)
fun fromPlatformType(colors: android.app.WallpaperColors): WallpaperColors {
return WallpaperColors(
Color(colors.primaryColor.toArgb()),
colors.secondaryColor?.toArgb()?.let { Color(it) },
colors.tertiaryColor?.toArgb()?.let { Color(it) }
colors.tertiaryColor?.toArgb()?.let { Color(it) },
colors.colorHints
)
}
}
@@ -27,18 +41,18 @@ data class WallpaperColors(val primary: Color, val secondary: Color?, val tertia
@RequiresApi(Build.VERSION_CODES.O_MR1)
@Composable
fun wallpaperColorsAsState(): State<WallpaperColors?> {
fun wallpaperColorsAsState(): State<WallpaperColors> {
val scope = rememberCoroutineScope()
val context = LocalContext.current
val state = remember { mutableStateOf<WallpaperColors?>(null) }
val state = remember { mutableStateOf(WallpaperColors()) }
DisposableEffect(null) {
val wallpaperManager = WallpaperManager.getInstance(context)
val callback = callback@{ colors: android.app.WallpaperColors?, which: Int ->
if (which or WallpaperManager.FLAG_SYSTEM == 0) return@callback
if (which and WallpaperManager.FLAG_SYSTEM == 0) return@callback
if (colors != null) {
state.value = WallpaperColors.fromPlatformType(colors)
} else {
state.value = null
state.value = WallpaperColors()
}
}
wallpaperManager.addOnColorsChangedListener(
@@ -57,6 +71,4 @@ fun wallpaperColorsAsState(): State<WallpaperColors?> {
}
}
return state
}
internal val DefaultWallpaperColors = WallpaperColors(Color.White, null, null)
}