(feat) transparency schemes
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
package de.mm20.launcher2.ui.base
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import de.mm20.launcher2.preferences.IconShape
|
||||
import de.mm20.launcher2.preferences.ui.CardStyle
|
||||
import de.mm20.launcher2.preferences.ui.GridSettings
|
||||
@@ -9,8 +13,6 @@ import de.mm20.launcher2.ui.component.ProvideIconShape
|
||||
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||
import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled
|
||||
import de.mm20.launcher2.ui.locals.LocalGridSettings
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.TransparencyScheme
|
||||
import de.mm20.launcher2.widgets.FavoritesWidget
|
||||
import de.mm20.launcher2.widgets.WidgetRepository
|
||||
import kotlinx.coroutines.flow.combine
|
||||
@@ -48,10 +50,6 @@ fun ProvideSettings(
|
||||
LocalCardStyle provides cardStyle,
|
||||
LocalFavoritesEnabled provides favoritesEnabled,
|
||||
LocalGridSettings provides gridSettings,
|
||||
LocalTransparencyScheme provides TransparencyScheme(
|
||||
background = cardStyle.opacity * 0.85f,
|
||||
surface = cardStyle.opacity,
|
||||
)
|
||||
) {
|
||||
ProvideIconShape(iconShape) {
|
||||
content()
|
||||
|
||||
@@ -40,7 +40,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.themes.Colors
|
||||
import de.mm20.launcher2.themes.colors.Colors
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.component.LargeMessage
|
||||
|
||||
@@ -5,9 +5,8 @@ import android.net.Uri
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.ColorsDescriptor
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.themes.Colors
|
||||
import de.mm20.launcher2.themes.colors.Colors
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import de.mm20.launcher2.themes.fromLegacyJson
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -58,9 +57,9 @@ class ImportThemeSheetVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
private fun importTheme(colors: Colors, apply: Boolean) {
|
||||
themeRepository.createColors(colors)
|
||||
themeRepository.colors.create(colors)
|
||||
if (apply) {
|
||||
uiSettings.setColors(ColorsDescriptor.Custom(colors.id.toString()))
|
||||
uiSettings.setColorsId(colors.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,29 @@
|
||||
package de.mm20.launcher2.ui.component
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.material3.LocalAbsoluteTonalElevation
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.draw.drawWithCache
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.drawOutline
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
import androidx.compose.ui.graphics.drawscope.withTransform
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
|
||||
@Composable
|
||||
fun LauncherCard(
|
||||
modifier: Modifier = Modifier,
|
||||
elevation: Dp = 2.dp,
|
||||
backgroundOpacity: Float = LocalTransparencyScheme.current.surface,
|
||||
backgroundOpacity: Float = MaterialTheme.transparency.surface,
|
||||
shape: Shape = MaterialTheme.shapes.medium,
|
||||
color: Color = MaterialTheme.colorScheme.surface.copy(alpha = backgroundOpacity.coerceIn(0f, 1f)),
|
||||
color: Color = MaterialTheme.colorScheme.surface.copy(
|
||||
alpha = backgroundOpacity.coerceIn(
|
||||
0f,
|
||||
1f
|
||||
)
|
||||
),
|
||||
border: BorderStroke? = LocalCardStyle.current.borderWidth.takeIf { it > 0 }
|
||||
?.let { BorderStroke(it.dp, MaterialTheme.colorScheme.surface) },
|
||||
content: @Composable () -> Unit = {}
|
||||
@@ -48,150 +38,4 @@ fun LauncherCard(
|
||||
shadowElevation = if (backgroundOpacity == 1f) elevation else 0.dp,
|
||||
tonalElevation = elevation,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PartialLauncherCard(
|
||||
modifier: Modifier = Modifier,
|
||||
isTop: Boolean = false,
|
||||
isBottom: Boolean = false,
|
||||
elevation: Dp = 2.dp,
|
||||
backgroundOpacity: Float = LocalTransparencyScheme.current.surface,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
|
||||
if (isTop && isBottom) {
|
||||
LauncherCard(modifier = modifier, content = content)
|
||||
} else if (!isTop && !isBottom) {
|
||||
CardMiddlePiece(modifier = modifier, elevation = elevation, content = content)
|
||||
} else {
|
||||
CardEndPiece(
|
||||
modifier = modifier,
|
||||
isTop = isTop,
|
||||
isBottom = isBottom,
|
||||
elevation = elevation,
|
||||
backgroundOpacity = backgroundOpacity,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CardMiddlePiece(
|
||||
modifier: Modifier,
|
||||
elevation: Dp,
|
||||
backgroundOpacity: Float = LocalTransparencyScheme.current.surface,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val borderWidth = LocalCardStyle.current.borderWidth.dp
|
||||
val borderColor = MaterialTheme.colorScheme.surface
|
||||
|
||||
val absoluteElevation = LocalAbsoluteTonalElevation.current + elevation
|
||||
Box(
|
||||
modifier = modifier
|
||||
.shadow(if (backgroundOpacity < 1f) 0.dp else elevation, RectangleShape, true)
|
||||
.background(
|
||||
if (backgroundOpacity == 1f) {
|
||||
MaterialTheme.colorScheme.surfaceColorAtElevation(absoluteElevation)
|
||||
} else {
|
||||
MaterialTheme.colorScheme.surface.copy(
|
||||
alpha = backgroundOpacity.coerceIn(
|
||||
0f,
|
||||
1f
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
.drawBehind {
|
||||
if (borderWidth == 0.dp) return@drawBehind
|
||||
val border = borderWidth.toPx()
|
||||
drawRect(
|
||||
color = borderColor,
|
||||
topLeft = Offset.Zero,
|
||||
size = size.copy(width = border)
|
||||
)
|
||||
drawRect(
|
||||
color = borderColor,
|
||||
topLeft = Offset(size.width - border, 0f),
|
||||
size = size.copy(width = border)
|
||||
)
|
||||
},
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides MaterialTheme.colorScheme.onSurface,
|
||||
LocalAbsoluteTonalElevation provides absoluteElevation,
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CardEndPiece(
|
||||
modifier: Modifier = Modifier,
|
||||
isTop: Boolean,
|
||||
isBottom: Boolean,
|
||||
elevation: Dp,
|
||||
backgroundOpacity: Float,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val shape = when {
|
||||
isTop -> MaterialTheme.shapes.medium.copy(
|
||||
bottomEnd = CornerSize(0),
|
||||
bottomStart = CornerSize(0),
|
||||
)
|
||||
isBottom -> MaterialTheme.shapes.medium.copy(
|
||||
topEnd = CornerSize(0),
|
||||
topStart = CornerSize(0),
|
||||
)
|
||||
else -> RectangleShape
|
||||
}
|
||||
|
||||
val borderWidth = LocalCardStyle.current.borderWidth.dp
|
||||
val borderColor = MaterialTheme.colorScheme.surface
|
||||
|
||||
val absoluteElevation = LocalAbsoluteTonalElevation.current + elevation
|
||||
Box(
|
||||
modifier = modifier
|
||||
.shadow(if (backgroundOpacity < 1f) 0.dp else elevation, shape, true)
|
||||
.background(
|
||||
if (backgroundOpacity == 1f) {
|
||||
MaterialTheme.colorScheme.surfaceColorAtElevation(absoluteElevation)
|
||||
} else {
|
||||
MaterialTheme.colorScheme.surface.copy(
|
||||
alpha = backgroundOpacity.coerceIn(
|
||||
0f,
|
||||
1f
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
.drawWithCache {
|
||||
val border = borderWidth.toPx()
|
||||
val outline = shape.createOutline(
|
||||
size.copy(height = size.height + border),
|
||||
layoutDirection,
|
||||
Density(density, fontScale)
|
||||
)
|
||||
onDrawBehind {
|
||||
if (borderWidth == 0.dp) return@onDrawBehind
|
||||
withTransform({
|
||||
translate(0f, if (isBottom) -border else 0f)
|
||||
}) {
|
||||
drawOutline(
|
||||
outline,
|
||||
borderColor,
|
||||
style = Stroke(width = border * 2)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides MaterialTheme.colorScheme.onSurface,
|
||||
LocalAbsoluteTonalElevation provides absoluteElevation,
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.layout.BottomReversed
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
|
||||
@Composable
|
||||
fun SearchBar(
|
||||
@@ -102,7 +102,7 @@ fun SearchBar(
|
||||
}
|
||||
}) {
|
||||
when {
|
||||
it == SearchBarLevel.Active -> LocalTransparencyScheme.current.surface
|
||||
it == SearchBarLevel.Active -> MaterialTheme.transparency.surface
|
||||
style != SearchBarStyle.Transparent -> 1f
|
||||
it == SearchBarLevel.Resting -> 0f
|
||||
else -> 1f
|
||||
|
||||
@@ -100,7 +100,7 @@ import de.mm20.launcher2.ui.launcher.helper.WallpaperBlur
|
||||
import de.mm20.launcher2.ui.launcher.search.SearchVM
|
||||
import de.mm20.launcher2.ui.launcher.search.filters.KeyboardFilterBar
|
||||
import de.mm20.launcher2.ui.launcher.searchbar.LauncherSearchBar
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
import dev.chrisbanes.haze.hazeEffect
|
||||
import dev.chrisbanes.haze.hazeSource
|
||||
import dev.chrisbanes.haze.rememberHazeState
|
||||
@@ -1416,7 +1416,7 @@ internal fun LauncherScaffold(
|
||||
.homePageAnimation(
|
||||
state,
|
||||
if (config.homeComponent.drawBackground) {
|
||||
config.backgroundColor.copy(alpha = LocalTransparencyScheme.current.background)
|
||||
config.backgroundColor.copy(alpha = MaterialTheme.transparency.background)
|
||||
} else {
|
||||
Color.Transparent
|
||||
}
|
||||
@@ -1516,7 +1516,7 @@ internal fun LauncherScaffold(
|
||||
blurRadius = 4.dp
|
||||
}
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceContainer.copy(alpha = LocalTransparencyScheme.current.background)
|
||||
MaterialTheme.colorScheme.surfaceContainer.copy(alpha = MaterialTheme.transparency.background)
|
||||
)
|
||||
.statusBarsPadding()
|
||||
)
|
||||
@@ -1536,7 +1536,7 @@ internal fun LauncherScaffold(
|
||||
blurRadius = 4.dp
|
||||
}
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceContainer.copy(alpha = LocalTransparencyScheme.current.background)
|
||||
MaterialTheme.colorScheme.surfaceContainer.copy(alpha = MaterialTheme.transparency.background)
|
||||
)
|
||||
.navigationBarsPadding()
|
||||
)
|
||||
@@ -1583,7 +1583,7 @@ private fun SecondaryPage(
|
||||
.fillMaxSize()
|
||||
.secondaryPageAnimation(
|
||||
state,
|
||||
config.backgroundColor.copy(alpha = LocalTransparencyScheme.current.background),
|
||||
config.backgroundColor.copy(alpha = MaterialTheme.transparency.background),
|
||||
)
|
||||
val composable = composables[component]
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ import de.mm20.launcher2.ui.launcher.sheets.HiddenItemsSheet
|
||||
import de.mm20.launcher2.ui.launcher.sheets.LocalBottomSheetManager
|
||||
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||
import de.mm20.launcher2.ui.locals.LocalGridSettings
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
|
||||
@Composable
|
||||
fun SearchColumn(
|
||||
@@ -370,7 +370,7 @@ fun LazyListScope.SingleResult(
|
||||
vertical = 4.dp,
|
||||
),
|
||||
color = if (highlight) MaterialTheme.colorScheme.secondaryContainer
|
||||
else MaterialTheme.colorScheme.surface.copy(LocalTransparencyScheme.current.surface)
|
||||
else MaterialTheme.colorScheme.surface.copy(MaterialTheme.transparency.surface)
|
||||
) {
|
||||
content()
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ import de.mm20.launcher2.ui.launcher.transitions.HandleEnterHomeTransition
|
||||
import de.mm20.launcher2.ui.locals.LocalGridSettings
|
||||
import de.mm20.launcher2.ui.locals.LocalWindowSize
|
||||
import de.mm20.launcher2.ui.overlays.Overlay
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
@@ -266,7 +267,7 @@ fun ItemPopup(origin: IntRect, searchable: Searchable, onDismissRequest: () -> U
|
||||
) {
|
||||
LauncherCard(
|
||||
elevation = 8.dp * animationProgress.value,
|
||||
backgroundOpacity = 1f,
|
||||
backgroundOpacity = MaterialTheme.transparency.elevatedSurface,
|
||||
modifier = Modifier
|
||||
.placeOverlay(
|
||||
origin.translate(
|
||||
|
||||
+4
-4
@@ -13,7 +13,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.search.SavableSearchable
|
||||
import de.mm20.launcher2.ui.ktx.withCorners
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
import kotlin.math.ceil
|
||||
|
||||
fun <T : SavableSearchable> LazyListScope.GridResults(
|
||||
@@ -39,7 +39,7 @@ fun <T : SavableSearchable> LazyListScope.GridResults(
|
||||
bottom = if (!reverse && isBottom) 8.dp else 0.dp,
|
||||
)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = LocalTransparencyScheme.current.surface),
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = MaterialTheme.transparency.surface),
|
||||
MaterialTheme.shapes.medium.withCorners(
|
||||
topStart = isTop,
|
||||
topEnd = isTop,
|
||||
@@ -72,7 +72,7 @@ fun <T : SavableSearchable> LazyListScope.GridResults(
|
||||
bottom = if (!reverse && isLast) 8.dp else 0.dp,
|
||||
)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = LocalTransparencyScheme.current.surface),
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = MaterialTheme.transparency.surface),
|
||||
MaterialTheme.shapes.medium.withCorners(
|
||||
topStart = isFirst && !reverse || isLast && reverse,
|
||||
topEnd = isFirst && !reverse || isLast && reverse,
|
||||
@@ -120,7 +120,7 @@ fun <T : SavableSearchable> LazyListScope.GridResults(
|
||||
bottom = if (!reverse) 8.dp else 0.dp,
|
||||
)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = LocalTransparencyScheme.current.surface),
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = MaterialTheme.transparency.surface),
|
||||
MaterialTheme.shapes.medium.withCorners(
|
||||
topStart = isTop,
|
||||
topEnd = isTop,
|
||||
|
||||
+6
-8
@@ -1,6 +1,5 @@
|
||||
package de.mm20.launcher2.ui.launcher.search.common.list
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.animateDp
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.updateTransition
|
||||
@@ -12,7 +11,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyItemScope
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -22,10 +20,9 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.search.SavableSearchable
|
||||
import de.mm20.launcher2.ui.ktx.animateCorners
|
||||
import de.mm20.launcher2.ui.ktx.animateShapeAsState
|
||||
import de.mm20.launcher2.ui.layout.BottomReversed
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
|
||||
fun <T : SavableSearchable> LazyListScope.ListResults(
|
||||
key: String,
|
||||
@@ -101,12 +98,13 @@ fun LazyItemScope.ListItemSurface(
|
||||
content: @Composable ColumnScope.() -> Unit,
|
||||
) {
|
||||
val transition = updateTransition(isExpanded)
|
||||
val elevation by transition.animateDp {
|
||||
if (it) 2.dp else 0.dp
|
||||
}
|
||||
val backgroundAlpha by transition.animateFloat {
|
||||
if (it) 1f else LocalTransparencyScheme.current.surface
|
||||
if (it) MaterialTheme.transparency.elevatedSurface else MaterialTheme.transparency.surface
|
||||
}
|
||||
val elevation by transition.animateDp {
|
||||
if (it && backgroundAlpha == 1f) 2.dp else 0.dp
|
||||
}
|
||||
|
||||
|
||||
val padding by transition.animateDp {
|
||||
if (it) 8.dp else 1.dp
|
||||
|
||||
+2
-2
@@ -22,7 +22,7 @@ import de.mm20.launcher2.ui.common.FavoritesTagSelector
|
||||
import de.mm20.launcher2.ui.component.Banner
|
||||
import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid
|
||||
import de.mm20.launcher2.ui.layout.BottomReversed
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
|
||||
fun LazyListScope.SearchFavorites(
|
||||
favorites: List<SavableSearchable>,
|
||||
@@ -47,7 +47,7 @@ fun LazyListScope.SearchFavorites(
|
||||
)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surface.copy(
|
||||
LocalTransparencyScheme.current.surface
|
||||
MaterialTheme.transparency.surface
|
||||
),
|
||||
MaterialTheme.shapes.medium
|
||||
)
|
||||
|
||||
@@ -72,7 +72,7 @@ import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.plugin.PluginRepository
|
||||
import de.mm20.launcher2.plugin.PluginType
|
||||
import de.mm20.launcher2.search.calendar.CalendarListType
|
||||
import de.mm20.launcher2.themes.atTone
|
||||
import de.mm20.launcher2.themes.colors.atTone
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.base.LocalAppWidgetHost
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
@@ -95,7 +95,6 @@ import de.mm20.launcher2.widgets.NotesWidget
|
||||
import de.mm20.launcher2.widgets.WeatherWidget
|
||||
import de.mm20.launcher2.widgets.Widget
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.koin.androidx.compose.get
|
||||
import org.koin.compose.koinInject
|
||||
import java.time.ZonedDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
@@ -41,7 +41,7 @@ import de.mm20.launcher2.ui.launcher.widgets.favorites.FavoritesWidget
|
||||
import de.mm20.launcher2.ui.launcher.widgets.music.MusicWidget
|
||||
import de.mm20.launcher2.ui.launcher.widgets.notes.NotesWidget
|
||||
import de.mm20.launcher2.ui.launcher.widgets.weather.WeatherWidget
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
import de.mm20.launcher2.widgets.AppWidget
|
||||
import de.mm20.launcher2.widgets.CalendarWidget
|
||||
import de.mm20.launcher2.widgets.FavoritesWidget
|
||||
@@ -73,7 +73,7 @@ fun WidgetItem(
|
||||
} else null
|
||||
|
||||
val backgroundOpacity by animateFloatAsState(
|
||||
if (widget is AppWidget && !widget.config.background && !editMode) 0f else LocalTransparencyScheme.current.surface,
|
||||
if (widget is AppWidget && !widget.config.background && !editMode) 0f else MaterialTheme.transparency.surface,
|
||||
label = "widgetCardBackgroundOpacity",
|
||||
)
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ import de.mm20.launcher2.ui.ktx.conditional
|
||||
import de.mm20.launcher2.ui.launcher.transitions.EnterHomeTransitionParams
|
||||
import de.mm20.launcher2.ui.launcher.transitions.HandleEnterHomeTransition
|
||||
import de.mm20.launcher2.ui.locals.LocalWindowSize
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
import de.mm20.launcher2.widgets.MusicWidget
|
||||
import kotlin.math.min
|
||||
|
||||
@@ -352,7 +352,7 @@ fun MusicWidget(widget: MusicWidget) {
|
||||
) {
|
||||
FilledTonalIconButton(
|
||||
colors = IconButtonDefaults.filledTonalIconButtonColors(
|
||||
containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = LocalTransparencyScheme.current.surface),
|
||||
containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = MaterialTheme.transparency.surface),
|
||||
),
|
||||
onClick = { viewModel.togglePause() },
|
||||
) {
|
||||
|
||||
@@ -86,7 +86,7 @@ import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||
import de.mm20.launcher2.ui.component.Tooltip
|
||||
import de.mm20.launcher2.ui.component.weather.AnimatedWeatherIcon
|
||||
import de.mm20.launcher2.ui.component.weather.WeatherIcon
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
import de.mm20.launcher2.weather.DailyForecast
|
||||
import de.mm20.launcher2.weather.Forecast
|
||||
import de.mm20.launcher2.widgets.WeatherWidget
|
||||
@@ -187,7 +187,7 @@ fun WeatherWidget(widget: WeatherWidget) {
|
||||
val currentDayForecasts by viewModel.currentDayForecasts
|
||||
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.surfaceContainer.copy(alpha = LocalTransparencyScheme.current.surface),
|
||||
color = MaterialTheme.colorScheme.surfaceContainer.copy(alpha = MaterialTheme.transparency.surface),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Column(
|
||||
@@ -299,7 +299,7 @@ fun CurrentWeather(forecast: Forecast, imperialUnits: Boolean) {
|
||||
topEnd = CornerSize(0),
|
||||
bottomEnd = CornerSize(0)
|
||||
),
|
||||
color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = LocalTransparencyScheme.current.surface),
|
||||
color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = MaterialTheme.transparency.surface),
|
||||
) {
|
||||
Text(
|
||||
text = "${forecast.provider} (${
|
||||
|
||||
@@ -80,6 +80,10 @@ import de.mm20.launcher2.ui.settings.shapes.ShapeSchemeSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.shapes.ShapeSchemesSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.tags.TagsSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.tasks.TasksIntegrationSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.transparencies.TransparencySchemeSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.transparencies.TransparencySchemeSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.transparencies.TransparencySchemesSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.transparencies.TransparencySchemesSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.unitconverter.UnitConverterHelpSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.unitconverter.UnitConverterSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.weather.WeatherIntegrationSettingsScreen
|
||||
@@ -206,6 +210,14 @@ class SettingsActivity : BaseActivity() {
|
||||
} ?: return@composable
|
||||
ShapeSchemeSettingsScreen(id)
|
||||
}
|
||||
composable<TransparencySchemesSettingsRoute> {
|
||||
TransparencySchemesSettingsScreen()
|
||||
}
|
||||
composable<TransparencySchemeSettingsRoute> {
|
||||
val route: TransparencySchemeSettingsRoute = it.toRoute()
|
||||
?: return@composable
|
||||
TransparencySchemeSettingsScreen(UUID.fromString(route.id))
|
||||
}
|
||||
composable("settings/appearance/cards") {
|
||||
CardsSettingsScreen()
|
||||
}
|
||||
|
||||
+11
@@ -6,6 +6,7 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ArrowCircleDown
|
||||
import androidx.compose.material.icons.rounded.ArrowCircleUp
|
||||
import androidx.compose.material.icons.rounded.CropSquare
|
||||
import androidx.compose.material.icons.rounded.Opacity
|
||||
import androidx.compose.material.icons.rounded.Palette
|
||||
import androidx.compose.material.icons.rounded.TextFields
|
||||
import androidx.compose.material3.Text
|
||||
@@ -27,6 +28,7 @@ import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import de.mm20.launcher2.ui.component.preferences.value
|
||||
import de.mm20.launcher2.ui.locals.LocalNavController
|
||||
import de.mm20.launcher2.ui.settings.transparencies.TransparencySchemesSettingsRoute
|
||||
import de.mm20.launcher2.ui.theme.getTypography
|
||||
|
||||
@Composable
|
||||
@@ -36,6 +38,7 @@ fun AppearanceSettingsScreen() {
|
||||
val navController = LocalNavController.current
|
||||
val colorThemeName by viewModel.colorThemeName.collectAsStateWithLifecycle(null)
|
||||
val shapeThemeName by viewModel.shapeThemeName.collectAsStateWithLifecycle(null)
|
||||
val transparencyThemeName by viewModel.transparencyThemeName.collectAsStateWithLifecycle(null)
|
||||
val compatModeColors by viewModel.compatModeColors.collectAsState()
|
||||
|
||||
val importLauncher = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) {
|
||||
@@ -101,6 +104,14 @@ fun AppearanceSettingsScreen() {
|
||||
},
|
||||
icon = Icons.Rounded.CropSquare,
|
||||
)
|
||||
Preference(
|
||||
title = stringResource(id = R.string.preference_screen_transparencies),
|
||||
summary = transparencyThemeName,
|
||||
onClick = {
|
||||
navController?.navigate(TransparencySchemesSettingsRoute)
|
||||
},
|
||||
icon = Icons.Rounded.Opacity,
|
||||
)
|
||||
|
||||
Preference(
|
||||
title = stringResource(R.string.preference_cards),
|
||||
|
||||
+14
-7
@@ -25,15 +25,22 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
uiSettings.setColorScheme(colorScheme)
|
||||
}
|
||||
|
||||
val colorThemeName = uiSettings.colors.flatMapLatest {
|
||||
themeRepository.getColorsOrDefault(it)
|
||||
}.map {
|
||||
it.name
|
||||
}
|
||||
val colorThemeName = uiSettings.colorsId.flatMapLatest {
|
||||
themeRepository.colors.getOrDefault(it)
|
||||
}.map {
|
||||
it.name
|
||||
}
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val shapeThemeName = uiSettings.shapes.flatMapLatest {
|
||||
themeRepository.getShapesOrDefault(it)
|
||||
val shapeThemeName = uiSettings.shapesId.flatMapLatest {
|
||||
themeRepository.shapes.getOrDefault(it)
|
||||
}.map {
|
||||
it.name
|
||||
}
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val transparencyThemeName = uiSettings.transparenciesId.flatMapLatest {
|
||||
themeRepository.transparencies.getOrDefault(it)
|
||||
}.map {
|
||||
it.name
|
||||
}
|
||||
|
||||
+14
-1
@@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.CropSquare
|
||||
import androidx.compose.material.icons.rounded.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.rounded.Opacity
|
||||
import androidx.compose.material.icons.rounded.Palette
|
||||
import androidx.compose.material.icons.rounded.Save
|
||||
import androidx.compose.material.icons.rounded.Share
|
||||
@@ -50,10 +51,11 @@ fun ExportThemeSettingsScreen() {
|
||||
|
||||
val colorSchemes by viewModel.colorSchemes.collectAsState(emptyList())
|
||||
val shapeThemes by viewModel.shapeSchemes.collectAsState(emptyList())
|
||||
val transparencySchemes by viewModel.transparencySchemes.collectAsState(emptyList())
|
||||
|
||||
val isValidSelection by remember {
|
||||
derivedStateOf {
|
||||
viewModel.colorScheme != null || viewModel.shapeScheme != null
|
||||
viewModel.colorScheme != null || viewModel.shapeScheme != null || viewModel.transparencyScheme != null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +113,17 @@ fun ExportThemeSettingsScreen() {
|
||||
viewModel.setShapeScheme(newValue)
|
||||
}
|
||||
)
|
||||
ListPreference(
|
||||
stringResource(R.string.preference_screen_transparencies),
|
||||
icon = Icons.Rounded.Opacity,
|
||||
value = viewModel.transparencyScheme,
|
||||
items = listOf(stringResource(R.string.no_selection) to null) + transparencySchemes.map {
|
||||
it.name to it
|
||||
},
|
||||
onValueChanged = { newValue ->
|
||||
viewModel.setTransparencyScheme(newValue)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
item {
|
||||
|
||||
+15
-6
@@ -3,7 +3,6 @@ package de.mm20.launcher2.ui.settings.appearance
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
@@ -11,11 +10,11 @@ import androidx.core.content.FileProvider
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.ktx.tryStartActivity
|
||||
import de.mm20.launcher2.themes.Colors
|
||||
import de.mm20.launcher2.themes.Shapes
|
||||
import de.mm20.launcher2.themes.colors.Colors
|
||||
import de.mm20.launcher2.themes.shapes.Shapes
|
||||
import de.mm20.launcher2.themes.ThemeBundle
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import de.mm20.launcher2.themes.toLegacyJson
|
||||
import de.mm20.launcher2.themes.transparencies.Transparencies
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -28,8 +27,9 @@ class ExportThemeSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
|
||||
private val themeRepository: ThemeRepository by inject()
|
||||
|
||||
val colorSchemes = themeRepository.getAllColors().map { it.filter { !it.builtIn } }
|
||||
val shapeSchemes = themeRepository.getAllShapes().map { it.filter { !it.builtIn } }
|
||||
val colorSchemes = themeRepository.colors.getAll().map { it.filter { !it.builtIn } }
|
||||
val shapeSchemes = themeRepository.shapes.getAll().map { it.filter { !it.builtIn } }
|
||||
val transparencySchemes = themeRepository.transparencies.getAll().map { it.filter { !it.builtIn } }
|
||||
|
||||
var themeName by mutableStateOf("")
|
||||
var themeAuthor by mutableStateOf("")
|
||||
@@ -55,12 +55,21 @@ class ExportThemeSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
shapeScheme = scheme
|
||||
}
|
||||
|
||||
var transparencyScheme by mutableStateOf<Transparencies?>(null)
|
||||
@JvmName("_setTransparencyScheme")
|
||||
private set
|
||||
fun setTransparencyScheme(scheme: Transparencies?) {
|
||||
if (themeName.isBlank() && scheme != null) themeName = scheme.name
|
||||
transparencyScheme = scheme
|
||||
}
|
||||
|
||||
private fun getThemeBundle(): ThemeBundle {
|
||||
return ThemeBundle(
|
||||
name = themeName,
|
||||
author = themeAuthor.takeIf { it.isNotBlank() },
|
||||
colors = colorScheme,
|
||||
shapes = shapeScheme,
|
||||
transparencies = transparencyScheme,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+41
-7
@@ -19,6 +19,7 @@ import androidx.compose.material.icons.rounded.Edit
|
||||
import androidx.compose.material.icons.rounded.ErrorOutline
|
||||
import androidx.compose.material.icons.rounded.LightMode
|
||||
import androidx.compose.material.icons.rounded.MoreVert
|
||||
import androidx.compose.material.icons.rounded.Opacity
|
||||
import androidx.compose.material.icons.rounded.Palette
|
||||
import androidx.compose.material.icons.rounded.Star
|
||||
import androidx.compose.material3.Button
|
||||
@@ -35,6 +36,7 @@ import androidx.compose.material3.SegmentedButtonDefaults
|
||||
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -62,9 +64,13 @@ import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
import de.mm20.launcher2.ui.settings.transparencies.checkerboard
|
||||
import de.mm20.launcher2.ui.theme.colorscheme.darkColorSchemeOf
|
||||
import de.mm20.launcher2.ui.theme.colorscheme.lightColorSchemeOf
|
||||
import de.mm20.launcher2.ui.theme.shapes.shapesOf
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparencySchemeOf
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@@ -118,10 +124,15 @@ fun ImportThemeSettingsScreen(
|
||||
} ?: MaterialTheme.colorScheme,
|
||||
shapes = themeBundle.shapes?.let { shapesOf(it) } ?: MaterialTheme.shapes,
|
||||
) {
|
||||
ThemePreview(
|
||||
darkMode = darkModePreview,
|
||||
onDarkModeChanged = { darkModePreview = it }
|
||||
)
|
||||
val transparencies = themeBundle.transparencies?.let { transparencySchemeOf(it) } ?: MaterialTheme.transparency
|
||||
CompositionLocalProvider(
|
||||
LocalTransparencyScheme provides transparencies
|
||||
) {
|
||||
ThemePreview(
|
||||
darkMode = darkModePreview,
|
||||
onDarkModeChanged = { darkModePreview = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
item {
|
||||
@@ -156,6 +167,21 @@ fun ImportThemeSettingsScreen(
|
||||
} else null,
|
||||
)
|
||||
}
|
||||
if (themeBundle.transparencies != null) {
|
||||
Preference(
|
||||
icon = Icons.Rounded.Opacity,
|
||||
title = stringResource(R.string.preference_screen_transparencies),
|
||||
summary = themeBundle.transparencies?.name,
|
||||
controls = if (viewModel.transparenciesExists) {
|
||||
{
|
||||
Icon(
|
||||
Icons.Rounded.ChangeCircle,
|
||||
stringResource(R.string.import_theme_exists)
|
||||
)
|
||||
}
|
||||
} else null,
|
||||
)
|
||||
}
|
||||
if (viewModel.colorsExists || viewModel.shapesExists) {
|
||||
Banner(
|
||||
modifier = Modifier
|
||||
@@ -211,8 +237,13 @@ private fun ThemePreview(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(MaterialTheme.shapes.medium)
|
||||
.checkerboard(
|
||||
MaterialTheme.colorScheme.primary,
|
||||
MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
12.dp,
|
||||
)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceContainer,
|
||||
MaterialTheme.colorScheme.surfaceContainer.copy(alpha = MaterialTheme.transparency.background),
|
||||
MaterialTheme.shapes.medium
|
||||
)
|
||||
.innerShadow(
|
||||
@@ -225,7 +256,7 @@ private fun ThemePreview(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp, start = 12.dp, end = 12.dp),
|
||||
level = SearchBarLevel.Active,
|
||||
level = SearchBarLevel.Raised,
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
@@ -239,7 +270,10 @@ private fun ThemePreview(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp, start = 12.dp, end = 12.dp)
|
||||
.background(MaterialTheme.colorScheme.surface, MaterialTheme.shapes.medium)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = MaterialTheme.transparency.surface),
|
||||
MaterialTheme.shapes.medium
|
||||
)
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Row(
|
||||
|
||||
+29
-12
@@ -8,8 +8,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import de.mm20.launcher2.preferences.ColorsDescriptor
|
||||
import de.mm20.launcher2.preferences.ShapesDescriptor
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.themes.ThemeBundle
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
@@ -19,9 +17,8 @@ import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import kotlin.getValue
|
||||
|
||||
class ImportThemeSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
class ImportThemeSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
private val themeRepository by inject<ThemeRepository>()
|
||||
private val uiSettings by inject<UiSettings>()
|
||||
@@ -35,6 +32,9 @@ class ImportThemeSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
var shapesExists by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
var transparenciesExists by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
var loading by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
@@ -54,11 +54,16 @@ class ImportThemeSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
val text = it.readText()
|
||||
val theme = ThemeBundle.fromJson(text)
|
||||
if (theme != null) {
|
||||
val colors = theme.colors?.id?.let { themeRepository.getColors(it) }?.first()
|
||||
val shapes = theme.shapes?.id?.let { themeRepository.getShapes(it) }?.first()
|
||||
val colors =
|
||||
theme.colors?.id?.let { themeRepository.colors.get(it) }?.first()
|
||||
val shapes =
|
||||
theme.shapes?.id?.let { themeRepository.shapes.get(it) }?.first()
|
||||
val transparencies =
|
||||
theme.transparencies?.id?.let { themeRepository.transparencies.get(it) }?.first()
|
||||
|
||||
colorsExists = colors != null
|
||||
shapesExists = shapes != null
|
||||
transparenciesExists = transparencies != null
|
||||
themeBundle = theme
|
||||
loading = false
|
||||
} else {
|
||||
@@ -77,30 +82,42 @@ class ImportThemeSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
|
||||
val colors = themeBundle.colors
|
||||
val shapes = themeBundle.shapes
|
||||
val transparencies = themeBundle.transparencies
|
||||
|
||||
val colorsExist = this.colorsExists
|
||||
val shapesExist = this.shapesExists
|
||||
val transparenciesExist = this.transparenciesExists
|
||||
|
||||
loading = true
|
||||
return viewModelScope.launch {
|
||||
if (colors != null) {
|
||||
if (colorsExist) {
|
||||
themeRepository.updateColors(colors)
|
||||
themeRepository.colors.update(colors)
|
||||
} else {
|
||||
themeRepository.createColors(colors)
|
||||
themeRepository.colors.create(colors)
|
||||
}
|
||||
if (applyTheme) {
|
||||
uiSettings.setColors(ColorsDescriptor.Custom(colors.id.toString()))
|
||||
uiSettings.setColorsId(colors.id)
|
||||
}
|
||||
}
|
||||
if (shapes != null) {
|
||||
if (shapesExist) {
|
||||
themeRepository.updateShapes(shapes)
|
||||
themeRepository.shapes.update(shapes)
|
||||
} else {
|
||||
themeRepository.createShapes(shapes)
|
||||
themeRepository.shapes.create(shapes)
|
||||
}
|
||||
if (applyTheme) {
|
||||
uiSettings.setShapes(ShapesDescriptor.Custom(shapes.id.toString()))
|
||||
uiSettings.setShapesId(shapes.id)
|
||||
}
|
||||
}
|
||||
if (transparencies != null) {
|
||||
if (transparenciesExist) {
|
||||
themeRepository.transparencies.update(transparencies)
|
||||
} else {
|
||||
themeRepository.transparencies.create(transparencies)
|
||||
}
|
||||
if (applyTheme) {
|
||||
uiSettings.setTransparenciesId(transparencies.id)
|
||||
}
|
||||
}
|
||||
loading = false
|
||||
|
||||
+1
-14
@@ -1,32 +1,19 @@
|
||||
package de.mm20.launcher2.ui.settings.calendarsearch
|
||||
|
||||
import android.app.PendingIntent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ErrorOutline
|
||||
import androidx.compose.material3.CheckboxDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.calendar.providers.CalendarList
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import de.mm20.launcher2.ktx.sendWithBackgroundPermission
|
||||
import de.mm20.launcher2.plugin.PluginState
|
||||
import de.mm20.launcher2.themes.atTone
|
||||
import de.mm20.launcher2.themes.colors.atTone
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.Banner
|
||||
import de.mm20.launcher2.ui.component.preferences.CheckboxPreference
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
|
||||
@@ -47,16 +47,6 @@ fun CardsSettingsScreen() {
|
||||
}
|
||||
item {
|
||||
PreferenceCategory {
|
||||
SliderPreference(
|
||||
title = stringResource(R.string.preference_cards_opacity),
|
||||
icon = Icons.Rounded.Opacity,
|
||||
value = cardStyle.opacity,
|
||||
min = 0f,
|
||||
max = 1f,
|
||||
onValueChanged = {
|
||||
viewModel.setOpacity(it)
|
||||
}
|
||||
)
|
||||
SliderPreference(
|
||||
title = stringResource(R.string.preference_cards_stroke_width),
|
||||
icon = Icons.Rounded.LineWeight,
|
||||
|
||||
+3
-5
@@ -28,7 +28,6 @@ import androidx.compose.material3.FilledTonalIconButton
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.FilterChipDefaults
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -51,7 +50,6 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
@@ -60,9 +58,9 @@ import de.mm20.launcher2.badges.Badge
|
||||
import de.mm20.launcher2.icons.ColorLayer
|
||||
import de.mm20.launcher2.icons.StaticLauncherIcon
|
||||
import de.mm20.launcher2.icons.TintedIconLayer
|
||||
import de.mm20.launcher2.themes.DefaultDarkColorScheme
|
||||
import de.mm20.launcher2.themes.DefaultLightColorScheme
|
||||
import de.mm20.launcher2.themes.merge
|
||||
import de.mm20.launcher2.themes.colors.DefaultDarkColorScheme
|
||||
import de.mm20.launcher2.themes.colors.DefaultLightColorScheme
|
||||
import de.mm20.launcher2.themes.colors.merge
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.Banner
|
||||
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
||||
|
||||
+1
-7
@@ -1,8 +1,5 @@
|
||||
package de.mm20.launcher2.ui.settings.colorscheme
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -17,7 +14,6 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Add
|
||||
import androidx.compose.material.icons.rounded.ContentCopy
|
||||
import androidx.compose.material.icons.rounded.Delete
|
||||
import androidx.compose.material.icons.rounded.Download
|
||||
import androidx.compose.material.icons.rounded.Edit
|
||||
import androidx.compose.material.icons.rounded.MoreVert
|
||||
import androidx.compose.material.icons.rounded.RadioButtonChecked
|
||||
@@ -26,7 +22,6 @@ import androidx.compose.material.icons.rounded.Share
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -45,9 +40,8 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.themes.Colors
|
||||
import de.mm20.launcher2.themes.colors.Colors
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.common.ImportThemeSheet
|
||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
|
||||
+10
-23
@@ -6,11 +6,10 @@ import androidx.core.content.FileProvider
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.ktx.tryStartActivity
|
||||
import de.mm20.launcher2.preferences.ColorsDescriptor
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.themes.BlackAndWhiteThemeId
|
||||
import de.mm20.launcher2.themes.DefaultThemeId
|
||||
import de.mm20.launcher2.themes.Colors
|
||||
import de.mm20.launcher2.themes.colors.Colors
|
||||
import de.mm20.launcher2.themes.HighContrastThemeId
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import de.mm20.launcher2.themes.toLegacyJson
|
||||
@@ -30,39 +29,27 @@ class ColorSchemesSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val themeRepository: ThemeRepository by inject()
|
||||
private val uiSettings: UiSettings by inject()
|
||||
|
||||
val selectedColors = uiSettings.colors.map {
|
||||
when(it) {
|
||||
ColorsDescriptor.Default -> DefaultThemeId
|
||||
ColorsDescriptor.HighContrast -> HighContrastThemeId
|
||||
ColorsDescriptor.BlackAndWhite -> BlackAndWhiteThemeId
|
||||
is ColorsDescriptor.Custom -> UUID.fromString(it.id)
|
||||
}
|
||||
}
|
||||
val colors: Flow<List<Colors>> = themeRepository.getAllColors()
|
||||
val selectedColors = uiSettings.colorsId
|
||||
val colors: Flow<List<Colors>> = themeRepository.colors.getAll()
|
||||
|
||||
fun getTheme(id: UUID): Flow<Colors?> {
|
||||
return themeRepository.getColors(id)
|
||||
return themeRepository.colors.get(id)
|
||||
}
|
||||
|
||||
fun updateTheme(colors: Colors) {
|
||||
themeRepository.updateColors(colors)
|
||||
themeRepository.colors.update(colors)
|
||||
}
|
||||
|
||||
fun selectTheme(colors: Colors) {
|
||||
uiSettings.setColors(when(colors.id) {
|
||||
DefaultThemeId -> ColorsDescriptor.Default
|
||||
HighContrastThemeId -> ColorsDescriptor.HighContrast
|
||||
BlackAndWhiteThemeId -> ColorsDescriptor.BlackAndWhite
|
||||
else -> ColorsDescriptor.Custom(colors.id.toString())
|
||||
})
|
||||
uiSettings.setColorsId(colors.id)
|
||||
}
|
||||
|
||||
fun duplicate(colors: Colors) {
|
||||
themeRepository.createColors(colors.copy(id = UUID.randomUUID()))
|
||||
themeRepository.colors.create(colors.copy(id = UUID.randomUUID()))
|
||||
}
|
||||
|
||||
fun delete(colors: Colors) {
|
||||
themeRepository.deleteColors(colors)
|
||||
themeRepository.colors.delete(colors)
|
||||
}
|
||||
|
||||
fun exportTheme(context: Context, colors: Colors) {
|
||||
@@ -85,10 +72,10 @@ class ColorSchemesSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
fun createNew(context: Context) {
|
||||
themeRepository.createColors(
|
||||
themeRepository.colors.create(
|
||||
Colors(
|
||||
id = UUID.randomUUID(),
|
||||
name = context.getString(R.string.new_color_scheme_name)
|
||||
name = context.getString(R.string.new_theme_name)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
-4
@@ -5,7 +5,6 @@ import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -33,14 +32,11 @@ import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.themes.get
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.component.Tooltip
|
||||
import de.mm20.launcher2.ui.component.colorpicker.HctColorPicker
|
||||
import de.mm20.launcher2.ui.component.colorpicker.rememberHctColorPickerState
|
||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||
|
||||
+7
-10
@@ -4,7 +4,6 @@ import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -12,7 +11,6 @@ import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
@@ -51,21 +49,20 @@ import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.themes.ColorRef
|
||||
import de.mm20.launcher2.themes.CorePaletteColor
|
||||
import de.mm20.launcher2.themes.FullCorePalette
|
||||
import de.mm20.launcher2.themes.StaticColor
|
||||
import de.mm20.launcher2.themes.atTone
|
||||
import de.mm20.launcher2.themes.get
|
||||
import de.mm20.launcher2.themes.colors.ColorRef
|
||||
import de.mm20.launcher2.themes.colors.CorePaletteColor
|
||||
import de.mm20.launcher2.themes.colors.FullCorePalette
|
||||
import de.mm20.launcher2.themes.colors.StaticColor
|
||||
import de.mm20.launcher2.themes.colors.atTone
|
||||
import de.mm20.launcher2.themes.colors.get
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.component.Tooltip
|
||||
import de.mm20.launcher2.ui.component.colorpicker.HctColorPicker
|
||||
import de.mm20.launcher2.ui.component.colorpicker.rememberHctColorPickerState
|
||||
import de.mm20.launcher2.ui.ktx.hct
|
||||
import hct.Hct
|
||||
import kotlin.math.roundToInt
|
||||
import de.mm20.launcher2.themes.Color as ThemeColor
|
||||
import de.mm20.launcher2.themes.colors.Color as ThemeColor
|
||||
|
||||
@Composable
|
||||
fun ThemeColorPreference(
|
||||
|
||||
@@ -14,8 +14,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
@@ -26,11 +24,9 @@ import androidx.compose.material.icons.rounded.Error
|
||||
import androidx.compose.material.icons.rounded.Info
|
||||
import androidx.compose.material.icons.rounded.Settings
|
||||
import androidx.compose.material.icons.rounded.Verified
|
||||
import androidx.compose.material3.CheckboxDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
@@ -40,12 +36,9 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@@ -57,15 +50,12 @@ import coil.compose.AsyncImage
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import de.mm20.launcher2.ktx.sendWithBackgroundPermission
|
||||
import de.mm20.launcher2.plugin.PluginState
|
||||
import de.mm20.launcher2.themes.atTone
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.preferences.CheckboxPreference
|
||||
import de.mm20.launcher2.ui.component.preferences.GuardedPreference
|
||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceWithSwitch
|
||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
import de.mm20.launcher2.ui.locals.LocalNavController
|
||||
|
||||
@Composable
|
||||
|
||||
+3
-3
@@ -66,7 +66,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.icons.CutCorner
|
||||
import de.mm20.launcher2.icons.RoundedCornerAlt
|
||||
import de.mm20.launcher2.themes.CornerStyle
|
||||
import de.mm20.launcher2.themes.shapes.CornerStyle
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
@@ -76,7 +76,7 @@ import de.mm20.launcher2.ui.theme.shapes.shapesOf
|
||||
import java.util.UUID
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import de.mm20.launcher2.themes.Shape as ThemeShape
|
||||
import de.mm20.launcher2.themes.shapes.Shape as ThemeShape
|
||||
|
||||
@Composable
|
||||
fun ShapeSchemeSettingsScreen(themeId: UUID) {
|
||||
@@ -284,7 +284,7 @@ fun ShapeSchemeSettingsScreen(themeId: UUID) {
|
||||
}
|
||||
}
|
||||
item {
|
||||
PreferenceCategory(title = "Large") {
|
||||
PreferenceCategory {
|
||||
ShapePreview(
|
||||
previewShapes = previewShapes,
|
||||
) {
|
||||
|
||||
+3
-3
@@ -35,8 +35,8 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.themes.CornerStyle
|
||||
import de.mm20.launcher2.themes.Shapes
|
||||
import de.mm20.launcher2.themes.shapes.CornerStyle
|
||||
import de.mm20.launcher2.themes.shapes.Shapes
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
@@ -49,7 +49,7 @@ fun ShapeSchemesSettingsScreen() {
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
|
||||
val selectedTheme by viewModel.selectedShapes.collectAsStateWithLifecycle(null)
|
||||
val selectedTheme by viewModel.selectedShapesId.collectAsStateWithLifecycle(null)
|
||||
val themes by viewModel.shapes.collectAsStateWithLifecycle(emptyList())
|
||||
|
||||
var deleteShapes by remember { mutableStateOf<Shapes?>(null) }
|
||||
|
||||
+10
-27
@@ -2,17 +2,11 @@ package de.mm20.launcher2.ui.settings.shapes
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.ViewModel
|
||||
import de.mm20.launcher2.preferences.ShapesDescriptor
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.themes.CutShapesId
|
||||
import de.mm20.launcher2.themes.DefaultThemeId
|
||||
import de.mm20.launcher2.themes.ExtraRoundShapesId
|
||||
import de.mm20.launcher2.themes.RectShapesId
|
||||
import de.mm20.launcher2.themes.Shapes
|
||||
import de.mm20.launcher2.themes.shapes.Shapes
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import de.mm20.launcher2.ui.R
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import java.util.UUID
|
||||
@@ -23,45 +17,34 @@ class ShapeSchemesSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val themeRepository: ThemeRepository by inject()
|
||||
private val uiSettings: UiSettings by inject()
|
||||
|
||||
val selectedShapes = uiSettings.shapes.map {
|
||||
when(it) {
|
||||
ShapesDescriptor.Default -> DefaultThemeId
|
||||
ShapesDescriptor.Cut -> CutShapesId
|
||||
ShapesDescriptor.ExtraRound -> ExtraRoundShapesId
|
||||
ShapesDescriptor.Rect -> RectShapesId
|
||||
is ShapesDescriptor.Custom -> UUID.fromString(it.id)
|
||||
}
|
||||
}
|
||||
val shapes: Flow<List<Shapes>> = themeRepository.getAllShapes()
|
||||
val selectedShapesId = uiSettings.shapesId
|
||||
val shapes: Flow<List<Shapes>> = themeRepository.shapes.getAll()
|
||||
|
||||
fun getShapes(id: UUID): Flow<Shapes?> {
|
||||
return themeRepository.getShapes(id)
|
||||
return themeRepository.shapes.get(id)
|
||||
}
|
||||
|
||||
fun updateShapes(shapes: Shapes) {
|
||||
themeRepository.updateShapes(shapes)
|
||||
themeRepository.shapes.update(shapes)
|
||||
}
|
||||
|
||||
fun selectShapes(shapes: Shapes) {
|
||||
uiSettings.setShapes(when(shapes.id) {
|
||||
DefaultThemeId -> ShapesDescriptor.Default
|
||||
else -> ShapesDescriptor.Custom(shapes.id.toString())
|
||||
})
|
||||
uiSettings.setShapesId(shapes.id)
|
||||
}
|
||||
|
||||
fun duplicate(shapes: Shapes) {
|
||||
themeRepository.createShapes(shapes.copy(id = UUID.randomUUID()))
|
||||
themeRepository.shapes.create(shapes.copy(id = UUID.randomUUID()))
|
||||
}
|
||||
|
||||
fun delete(shapes: Shapes) {
|
||||
themeRepository.deleteShapes(shapes)
|
||||
themeRepository.shapes.delete(shapes)
|
||||
}
|
||||
|
||||
fun createNew(context: Context) {
|
||||
themeRepository.createShapes(
|
||||
themeRepository.shapes.create(
|
||||
Shapes(
|
||||
id = UUID.randomUUID(),
|
||||
name = context.getString(R.string.new_shapes_name)
|
||||
name = context.getString(R.string.new_theme_name)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.mm20.launcher2.ui.settings.transparencies
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.ktx.ceilToInt
|
||||
|
||||
fun Modifier.checkerboard(
|
||||
color1: Color = Color.LightGray,
|
||||
color2: Color = Color.DarkGray,
|
||||
tileSize: Dp = 16.dp
|
||||
): Modifier {
|
||||
return drawBehind {
|
||||
val tileSizePx = with(density) { tileSize.toPx() }
|
||||
val hTiles = (size.width / tileSizePx).ceilToInt()
|
||||
val vTiles = (size.height / tileSizePx).ceilToInt()
|
||||
|
||||
for (i in 0 until hTiles) {
|
||||
for (j in 0 until vTiles) {
|
||||
val color = if ((i + j) % 2 == 0) color1 else color2
|
||||
drawRect(
|
||||
color = color,
|
||||
topLeft = Offset(
|
||||
x = i * tileSizePx,
|
||||
y = j * tileSizePx
|
||||
),
|
||||
size = Size(tileSizePx + 1, tileSizePx + 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+304
@@ -0,0 +1,304 @@
|
||||
package de.mm20.launcher2.ui.settings.transparencies
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.RestartAlt
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LocalAbsoluteTonalElevation
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.themes.transparencies.Transparencies
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.LocalIconShape
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import de.mm20.launcher2.ui.component.surfaceColorAtElevation
|
||||
import de.mm20.launcher2.ui.locals.LocalGridSettings
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparencySchemeOf
|
||||
import de.mm20.launcher2.ui.theme.wallpaperColorsAsState
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.text.DecimalFormat
|
||||
import java.util.UUID
|
||||
import kotlin.math.floor
|
||||
import kotlin.math.log
|
||||
import kotlin.math.round
|
||||
|
||||
@Serializable
|
||||
data class TransparencySchemeSettingsRoute(
|
||||
val id: String
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun TransparencySchemeSettingsScreen(themeId: UUID) {
|
||||
val viewModel: TransparencySchemesSettingsScreenVM = viewModel()
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
val wallpaperColors by wallpaperColorsAsState()
|
||||
|
||||
val theme by remember(
|
||||
viewModel,
|
||||
themeId
|
||||
) { viewModel.getTransparencies(themeId) }.collectAsStateWithLifecycle(null)
|
||||
|
||||
|
||||
var editName by remember { mutableStateOf(false) }
|
||||
|
||||
if (editName) {
|
||||
var name by remember(theme) { mutableStateOf(theme?.name ?: "") }
|
||||
AlertDialog(
|
||||
onDismissRequest = { editName = false },
|
||||
text = {
|
||||
OutlinedTextField(
|
||||
value = name,
|
||||
onValueChange = { name = it },
|
||||
singleLine = true
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
Button(
|
||||
onClick = {
|
||||
viewModel.updateTransparencies(theme!!.copy(name = name))
|
||||
editName = false
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.save))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
PreferenceScreen(
|
||||
title = {
|
||||
Text(
|
||||
theme?.name ?: "",
|
||||
modifier = Modifier.clickable {
|
||||
editName = true
|
||||
},
|
||||
)
|
||||
},
|
||||
helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/customization/color-schemes",
|
||||
) {
|
||||
if (theme == null) return@PreferenceScreen
|
||||
|
||||
item {
|
||||
PreferenceCategory {
|
||||
TransparenciesPreview(theme!!)
|
||||
TransparencyPreference(
|
||||
title = "Background",
|
||||
value = theme!!.background,
|
||||
defaultValue = 0.85f,
|
||||
onValueChange = { viewModel.updateTransparencies(theme!!.copy(background = it)) }
|
||||
)
|
||||
TransparencyPreference(
|
||||
title = "Surface",
|
||||
value = theme!!.surface,
|
||||
defaultValue = 1f,
|
||||
onValueChange = { viewModel.updateTransparencies(theme!!.copy(surface = it)) }
|
||||
)
|
||||
TransparencyPreference(
|
||||
title = "Elevated Surface",
|
||||
value = theme!!.elevatedSurface,
|
||||
defaultValue = 1f,
|
||||
onValueChange = { viewModel.updateTransparencies(theme!!.copy(elevatedSurface = it)) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TransparenciesPreview(
|
||||
theme: Transparencies,
|
||||
) {
|
||||
val transparencyScheme = transparencySchemeOf(theme)
|
||||
|
||||
Box {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(200.dp)
|
||||
.clip(MaterialTheme.shapes.extraSmall)
|
||||
.checkerboard(
|
||||
MaterialTheme.colorScheme.primary,
|
||||
MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
12.dp,
|
||||
)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.fillMaxWidth()
|
||||
.height(160.dp)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceContainer.copy(transparencyScheme.background),
|
||||
MaterialTheme.shapes.large.copy(
|
||||
bottomStart = CornerSize(0f),
|
||||
bottomEnd = CornerSize(0f),
|
||||
)
|
||||
),
|
||||
) {
|
||||
val xs = MaterialTheme.shapes.extraSmall
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(top = 48.dp, start = 12.dp, end = 12.dp, bottom = 2.dp)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceContainer.copy(transparencyScheme.surface),
|
||||
MaterialTheme.shapes.medium.copy(
|
||||
bottomStart = xs.bottomStart,
|
||||
bottomEnd = xs.bottomStart,
|
||||
),
|
||||
)
|
||||
.padding(12.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
repeat(LocalGridSettings.current.columnCount) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(vertical = 12.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(LocalGridSettings.current.iconSize.dp)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.primaryContainer,
|
||||
LocalIconShape.current,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val elevatedSurface = MaterialTheme.colorScheme
|
||||
.surfaceColorAtElevation(8.dp + LocalAbsoluteTonalElevation.current)
|
||||
.copy(alpha = transparencyScheme.elevatedSurface)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(end = 24.dp)
|
||||
.shadow(
|
||||
if (transparencyScheme.elevatedSurface < 1f) 0.dp else 8.dp,
|
||||
MaterialTheme.shapes.medium,
|
||||
clip = true
|
||||
)
|
||||
.background(elevatedSurface)
|
||||
.align(Alignment.CenterEnd)
|
||||
.size(144.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TransparencyPreference(
|
||||
title: String,
|
||||
value: Float?,
|
||||
defaultValue: Float,
|
||||
onValueChange: (Float?) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(MaterialTheme.shapes.extraSmall)
|
||||
.background(MaterialTheme.colorScheme.surface)
|
||||
.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(end = 20.dp)
|
||||
.size(48.dp)
|
||||
.clip(MaterialTheme.shapes.small)
|
||||
.checkerboard(
|
||||
MaterialTheme.colorScheme.primary,
|
||||
MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
12.dp,
|
||||
)
|
||||
.padding(8.dp)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = value ?: defaultValue),
|
||||
MaterialTheme.shapes.extraSmall
|
||||
),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
Text(
|
||||
title,
|
||||
style = MaterialTheme.typography.bodyMedium.copy(fontFamily = FontFamily.Monospace),
|
||||
textAlign = TextAlign.Center,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Slider(
|
||||
modifier = Modifier.weight(1f),
|
||||
value = value ?: defaultValue,
|
||||
onValueChange = {
|
||||
val roundedValue = round(it * 100) / 100
|
||||
onValueChange(roundedValue)
|
||||
},
|
||||
valueRange = 0f..1f,
|
||||
)
|
||||
val format = remember { DecimalFormat().apply {
|
||||
maximumFractionDigits = 2
|
||||
minimumFractionDigits = 0
|
||||
} }
|
||||
Text(
|
||||
text = format.format(value ?: defaultValue),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(start = 8.dp).widthIn(min = 48.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
package de.mm20.launcher2.ui.settings.transparencies
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Add
|
||||
import androidx.compose.material.icons.rounded.ContentCopy
|
||||
import androidx.compose.material.icons.rounded.Delete
|
||||
import androidx.compose.material.icons.rounded.Edit
|
||||
import androidx.compose.material.icons.rounded.MoreVert
|
||||
import androidx.compose.material.icons.rounded.RadioButtonChecked
|
||||
import androidx.compose.material.icons.rounded.RadioButtonUnchecked
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.themes.transparencies.Transparencies
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import de.mm20.launcher2.ui.locals.LocalNavController
|
||||
import de.mm20.launcher2.ui.theme.WallpaperColors
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparencySchemeOf
|
||||
import de.mm20.launcher2.ui.theme.wallpaperColorsAsState
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data object TransparencySchemesSettingsRoute
|
||||
|
||||
@Composable
|
||||
fun TransparencySchemesSettingsScreen() {
|
||||
val viewModel: TransparencySchemesSettingsScreenVM = viewModel()
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
|
||||
val selectedTheme by viewModel.selectedTransparencies.collectAsStateWithLifecycle(null)
|
||||
val themes by viewModel.transparencies.collectAsStateWithLifecycle(emptyList())
|
||||
|
||||
var deleteTransparencies by remember { mutableStateOf<Transparencies?>(null) }
|
||||
|
||||
val wallpaperColors = wallpaperColorsAsState().value
|
||||
|
||||
PreferenceScreen(
|
||||
title = stringResource(R.string.preference_screen_transparencies),
|
||||
topBarActions = {
|
||||
IconButton(onClick = { viewModel.createNew(context) }) {
|
||||
Icon(Icons.Rounded.Add, null)
|
||||
}
|
||||
},
|
||||
) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
for (theme in themes) {
|
||||
var showMenu by remember { mutableStateOf(false) }
|
||||
Preference(
|
||||
icon = if (theme.id == selectedTheme) Icons.Rounded.RadioButtonChecked else Icons.Rounded.RadioButtonUnchecked,
|
||||
title = theme.name,
|
||||
controls = {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
TransparenciesPreview(wallpaperColors, theme)
|
||||
IconButton(
|
||||
modifier = Modifier.padding(start = 12.dp),
|
||||
onClick = { showMenu = true }) {
|
||||
Icon(Icons.Rounded.MoreVert, null)
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = showMenu,
|
||||
onDismissRequest = { showMenu = false }
|
||||
) {
|
||||
if (!theme.builtIn) {
|
||||
DropdownMenuItem(
|
||||
leadingIcon = {
|
||||
Icon(Icons.Rounded.Edit, null)
|
||||
},
|
||||
text = { Text(stringResource(R.string.edit)) },
|
||||
onClick = {
|
||||
navController?.navigate(
|
||||
TransparencySchemeSettingsRoute(theme.id.toString())
|
||||
)
|
||||
showMenu = false
|
||||
}
|
||||
)
|
||||
}
|
||||
DropdownMenuItem(
|
||||
leadingIcon = {
|
||||
Icon(Icons.Rounded.ContentCopy, null)
|
||||
},
|
||||
text = { Text(stringResource(R.string.duplicate)) },
|
||||
onClick = {
|
||||
viewModel.duplicate(theme)
|
||||
showMenu = false
|
||||
}
|
||||
)
|
||||
if (!theme.builtIn) {
|
||||
DropdownMenuItem(
|
||||
leadingIcon = {
|
||||
Icon(Icons.Rounded.Delete, null)
|
||||
},
|
||||
text = { Text(stringResource(R.string.menu_delete)) },
|
||||
onClick = {
|
||||
deleteTransparencies = theme
|
||||
showMenu = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
viewModel.selectTransparencies(theme)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (deleteTransparencies != null) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { deleteTransparencies = null },
|
||||
text = {
|
||||
Text(
|
||||
stringResource(
|
||||
R.string.confirmation_delete_transparencies_scheme,
|
||||
deleteTransparencies!!.name
|
||||
)
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
viewModel.delete(deleteTransparencies!!)
|
||||
deleteTransparencies = null
|
||||
}
|
||||
) {
|
||||
Text(stringResource(android.R.string.ok))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = { deleteTransparencies = null }
|
||||
) {
|
||||
Text(stringResource(android.R.string.cancel))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TransparenciesPreview(wallpaperColors: WallpaperColors, theme: Transparencies) {
|
||||
val transparencies = transparencySchemeOf(theme)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(MaterialTheme.shapes.extraSmall)
|
||||
.checkerboard(
|
||||
MaterialTheme.colorScheme.primary,
|
||||
MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
12.dp,
|
||||
)
|
||||
.height(40.dp)
|
||||
.width(56.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.surfaceContainer.copy(alpha = transparencies.background), MaterialTheme.shapes.extraSmall)
|
||||
.height(40.dp)
|
||||
.width(56.dp)
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.surface.copy(alpha = transparencies.surface), MaterialTheme.shapes.extraSmall)
|
||||
.height(24.dp)
|
||||
.width(48.dp)
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(32.dp)
|
||||
.width(36.dp)
|
||||
.shadow(
|
||||
if (transparencies.elevatedSurface < 1f) 0.dp else 8.dp,
|
||||
shape = MaterialTheme.shapes.extraSmall,
|
||||
clip = true,
|
||||
)
|
||||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(8.dp))
|
||||
)
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package de.mm20.launcher2.ui.settings.transparencies
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.ViewModel
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import de.mm20.launcher2.themes.transparencies.Transparencies
|
||||
import de.mm20.launcher2.ui.R
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import java.util.UUID
|
||||
|
||||
class TransparencySchemesSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
private val themeRepository: ThemeRepository by inject()
|
||||
private val uiSettings: UiSettings by inject()
|
||||
|
||||
val selectedTransparencies = uiSettings.transparenciesId
|
||||
val transparencies: Flow<List<Transparencies>> = themeRepository.transparencies.getAll()
|
||||
|
||||
fun getTransparencies(id: UUID): Flow<Transparencies?> {
|
||||
return themeRepository.transparencies.get(id)
|
||||
}
|
||||
|
||||
fun updateTransparencies(transparencies: Transparencies) {
|
||||
themeRepository.transparencies.update(transparencies)
|
||||
}
|
||||
|
||||
fun selectTransparencies(transparencies: Transparencies) {
|
||||
uiSettings.setTransparenciesId(transparencies.id)
|
||||
}
|
||||
|
||||
fun duplicate(transparencies: Transparencies) {
|
||||
themeRepository.transparencies.create(transparencies.copy(id = UUID.randomUUID()))
|
||||
}
|
||||
|
||||
fun delete(transparencies: Transparencies) {
|
||||
themeRepository.transparencies.delete(transparencies)
|
||||
}
|
||||
|
||||
fun createNew(context: Context) {
|
||||
themeRepository.transparencies.create(
|
||||
Transparencies(
|
||||
id = UUID.randomUUID(),
|
||||
name = context.getString(R.string.new_theme_name)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,25 +2,20 @@ package de.mm20.launcher2.ui.theme
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.foundation.shape.CutCornerShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.coerceAtMost
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.preferences.Font
|
||||
import de.mm20.launcher2.preferences.SurfaceShape
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
import de.mm20.launcher2.ui.theme.colorscheme.*
|
||||
import de.mm20.launcher2.ui.theme.shapes.shapesOf
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparencySchemeOf
|
||||
import de.mm20.launcher2.ui.theme.typography.DefaultTypography
|
||||
import de.mm20.launcher2.ui.theme.typography.getDeviceDefaultTypography
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.koin.compose.koinInject
|
||||
import de.mm20.launcher2.preferences.ColorScheme as ColorSchemePref
|
||||
|
||||
@@ -35,14 +30,20 @@ fun LauncherTheme(
|
||||
val themeRepository: ThemeRepository = koinInject()
|
||||
|
||||
val themeColors by remember {
|
||||
uiSettings.colors.flatMapLatest {
|
||||
themeRepository.getColorsOrDefault(it)
|
||||
uiSettings.colorsId.flatMapLatest {
|
||||
themeRepository.colors.getOrDefault(it)
|
||||
}
|
||||
}.collectAsState(null)
|
||||
|
||||
val themeShapes by remember {
|
||||
uiSettings.shapes.flatMapLatest {
|
||||
themeRepository.getShapesOrDefault(it)
|
||||
uiSettings.shapesId.flatMapLatest {
|
||||
themeRepository.shapes.getOrDefault(it)
|
||||
}
|
||||
}.collectAsState(null)
|
||||
|
||||
val themeTransparencies by remember {
|
||||
uiSettings.transparenciesId.flatMapLatest {
|
||||
themeRepository.transparencies.getOrDefault(it)
|
||||
}
|
||||
}.collectAsState(null)
|
||||
|
||||
@@ -52,7 +53,7 @@ fun LauncherTheme(
|
||||
val darkTheme =
|
||||
colorSchemePref == ColorSchemePref.Dark || colorSchemePref == ColorSchemePref.System && isSystemInDarkTheme()
|
||||
|
||||
if (themeColors == null || themeShapes == null) {
|
||||
if (themeColors == null || themeShapes == null || themeTransparencies == null) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -64,6 +65,7 @@ fun LauncherTheme(
|
||||
|
||||
val shapes = shapesOf(themeShapes!!)
|
||||
|
||||
val transparencyScheme = transparencySchemeOf(themeTransparencies!!)
|
||||
|
||||
|
||||
val font by remember { uiSettings.font }.collectAsState(
|
||||
@@ -75,7 +77,8 @@ fun LauncherTheme(
|
||||
}
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalDarkTheme provides darkTheme
|
||||
LocalDarkTheme provides darkTheme,
|
||||
LocalTransparencyScheme provides transparencyScheme,
|
||||
) {
|
||||
MaterialExpressiveTheme(
|
||||
colorScheme = colorScheme,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.mm20.launcher2.ui.theme.colorscheme
|
||||
|
||||
import android.R
|
||||
import android.os.Build
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -11,14 +12,14 @@ import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.core.content.ContextCompat
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.themes.CorePalette
|
||||
import de.mm20.launcher2.themes.DefaultDarkColorScheme
|
||||
import de.mm20.launcher2.themes.DefaultLightColorScheme
|
||||
import de.mm20.launcher2.themes.FullColorScheme
|
||||
import de.mm20.launcher2.themes.PartialCorePalette
|
||||
import de.mm20.launcher2.themes.Colors as ThemeColors
|
||||
import de.mm20.launcher2.themes.get
|
||||
import de.mm20.launcher2.themes.merge
|
||||
import de.mm20.launcher2.themes.colors.CorePalette
|
||||
import de.mm20.launcher2.themes.colors.DefaultDarkColorScheme
|
||||
import de.mm20.launcher2.themes.colors.DefaultLightColorScheme
|
||||
import de.mm20.launcher2.themes.colors.FullColorScheme
|
||||
import de.mm20.launcher2.themes.colors.PartialCorePalette
|
||||
import de.mm20.launcher2.themes.colors.Colors as ThemeColors
|
||||
import de.mm20.launcher2.themes.colors.get
|
||||
import de.mm20.launcher2.themes.colors.merge
|
||||
import de.mm20.launcher2.ui.locals.LocalWallpaperColors
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
@@ -88,11 +89,11 @@ fun systemCorePalette(): CorePalette<Int> {
|
||||
if (Build.VERSION.SDK_INT >= 31 && !compatModeColors) {
|
||||
val context = LocalContext.current
|
||||
return CorePalette(
|
||||
primary = ContextCompat.getColor(context, android.R.color.system_accent1_500),
|
||||
secondary = ContextCompat.getColor(context, android.R.color.system_accent2_500),
|
||||
tertiary = ContextCompat.getColor(context, android.R.color.system_accent3_500),
|
||||
neutral = ContextCompat.getColor(context, android.R.color.system_neutral1_500),
|
||||
neutralVariant = ContextCompat.getColor(context, android.R.color.system_neutral2_500),
|
||||
primary = ContextCompat.getColor(context, R.color.system_accent1_500),
|
||||
secondary = ContextCompat.getColor(context, R.color.system_accent2_500),
|
||||
tertiary = ContextCompat.getColor(context, R.color.system_accent3_500),
|
||||
neutral = ContextCompat.getColor(context, R.color.system_neutral1_500),
|
||||
neutralVariant = ContextCompat.getColor(context, R.color.system_neutral2_500),
|
||||
error = 0xFFB3261E.toInt(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ import androidx.compose.material3.Shapes
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.themes.CornerStyle
|
||||
import de.mm20.launcher2.themes.Shape as ThemeShape
|
||||
import de.mm20.launcher2.themes.Shapes as ThemeShapes
|
||||
import de.mm20.launcher2.themes.shapes.CornerStyle
|
||||
import de.mm20.launcher2.themes.shapes.Shape as ThemeShape
|
||||
import de.mm20.launcher2.themes.shapes.Shapes as ThemeShapes
|
||||
|
||||
@Composable
|
||||
fun shapesOf(shapes: ThemeShapes): Shapes {
|
||||
|
||||
@@ -1,10 +1,31 @@
|
||||
package de.mm20.launcher2.ui.theme.transparency
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.runtime.remember
|
||||
import de.mm20.launcher2.themes.transparencies.Transparencies
|
||||
|
||||
|
||||
@Composable
|
||||
fun transparencySchemeOf(transparencies: Transparencies): TransparencyScheme {
|
||||
return remember(transparencies) {
|
||||
TransparencyScheme(
|
||||
background = transparencies.background ?: 0.85f,
|
||||
surface = transparencies.surface ?: 1f,
|
||||
elevatedSurface = transparencies.elevatedSurface ?: 1f,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class TransparencyScheme(
|
||||
val background: Float,
|
||||
val surface: Float,
|
||||
val background: Float = 0.85f,
|
||||
val surface: Float = 1f,
|
||||
val elevatedSurface: Float = 1f,
|
||||
)
|
||||
|
||||
val LocalTransparencyScheme = compositionLocalOf { TransparencyScheme(0.85f, 1f) }
|
||||
val LocalTransparencyScheme = compositionLocalOf { TransparencyScheme(background = 0.85f, surface = 1f, elevatedSurface = 1f) }
|
||||
|
||||
val MaterialTheme.transparency
|
||||
@Composable
|
||||
get() = LocalTransparencyScheme.current
|
||||
Reference in New Issue
Block a user