Add option to color system bar icons automatically
This commit is contained in:
@@ -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(
|
||||
|
||||
+21
-10
@@ -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()
|
||||
|
||||
+7
-6
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user