Migrate card settings
This commit is contained in:
parent
a4ead54329
commit
8e96e2b2db
@ -24,13 +24,11 @@ class PreferencesCardFragment : Fragment(R.layout.fragment_card_settings) {
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val previewCard = view.findViewById<LauncherCardView>(R.id.previewCard)
|
val previewCard = view.findViewById<LauncherCardView>(R.id.previewCard)
|
||||||
previewCard.strokeOpacity = 0xFF
|
|
||||||
|
|
||||||
val prefFragment = PreferenesCardInnerFragment()
|
val prefFragment = PreferenesCardInnerFragment()
|
||||||
|
|
||||||
prefFragment.onPreferencesReady = {
|
prefFragment.onPreferencesReady = {
|
||||||
findPreference<Preference>("card_radius")?.let {
|
findPreference<Preference>("card_radius")?.let {
|
||||||
it.summary = preferences.cardRadius.toString()
|
|
||||||
it.setOnPreferenceChangeListener { pref, newValue ->
|
it.setOnPreferenceChangeListener { pref, newValue ->
|
||||||
val value = newValue as Int
|
val value = newValue as Int
|
||||||
previewCard.radius = value * dp
|
previewCard.radius = value * dp
|
||||||
@ -39,7 +37,6 @@ class PreferencesCardFragment : Fragment(R.layout.fragment_card_settings) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
findPreference<Preference>("card_opacity")?.let {
|
findPreference<Preference>("card_opacity")?.let {
|
||||||
it.summary = preferences.cardOpacity.toString()
|
|
||||||
it.setOnPreferenceChangeListener { pref, newValue ->
|
it.setOnPreferenceChangeListener { pref, newValue ->
|
||||||
val value = newValue as Int
|
val value = newValue as Int
|
||||||
previewCard.backgroundOpacity = value
|
previewCard.backgroundOpacity = value
|
||||||
@ -49,7 +46,6 @@ class PreferencesCardFragment : Fragment(R.layout.fragment_card_settings) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
findPreference<Preference>("card_stroke_width")?.let {
|
findPreference<Preference>("card_stroke_width")?.let {
|
||||||
it.summary = preferences.cardRadius.toString()
|
|
||||||
it.setOnPreferenceChangeListener { pref, newValue ->
|
it.setOnPreferenceChangeListener { pref, newValue ->
|
||||||
val value = newValue as Int
|
val value = newValue as Int
|
||||||
previewCard.strokeWidth = (value * dp).roundToInt()
|
previewCard.strokeWidth = (value * dp).roundToInt()
|
||||||
|
|||||||
@ -119,5 +119,11 @@ fun createFactorySettings(context: Context): Settings {
|
|||||||
.setLightNavBar(false)
|
.setLightNavBar(false)
|
||||||
.setLightStatusBar(false)
|
.setLightStatusBar(false)
|
||||||
)
|
)
|
||||||
|
.setCards(
|
||||||
|
Settings.CardSettings.newBuilder()
|
||||||
|
.setBorderWidth(0)
|
||||||
|
.setRadius(8)
|
||||||
|
.setOpacity(1f)
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
@ -49,8 +49,6 @@ class LauncherPreferences(val context: Application, version: Int = 3) {
|
|||||||
|
|
||||||
var appStartAnim by EnumPreference("app_start_anim", default = AppStartAnimation.M)
|
var appStartAnim by EnumPreference("app_start_anim", default = AppStartAnimation.M)
|
||||||
|
|
||||||
var cardOpacity by IntPreference("card_opacity", default = 0xFF)
|
|
||||||
var cardStrokeWidth by IntPreference("card_stroke_width", default = 0)
|
|
||||||
var cardRadius by IntPreference("card_radius", default = 8)
|
var cardRadius by IntPreference("card_radius", default = 8)
|
||||||
|
|
||||||
var easterEggEnabled by BooleanPreference("easter_egg", default = false)
|
var easterEggEnabled by BooleanPreference("easter_egg", default = false)
|
||||||
|
|||||||
@ -164,4 +164,11 @@ message Settings {
|
|||||||
bool lightNavBar = 2;
|
bool lightNavBar = 2;
|
||||||
}
|
}
|
||||||
SystemBarsSettings system_bars = 23;
|
SystemBarsSettings system_bars = 23;
|
||||||
|
|
||||||
|
message CardSettings {
|
||||||
|
float opacity = 1;
|
||||||
|
uint32 radius = 2;
|
||||||
|
uint32 border_width = 3;
|
||||||
|
}
|
||||||
|
CardSettings cards = 24;
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package de.mm20.launcher2.ui.component
|
package de.mm20.launcher2.ui.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
@ -7,20 +8,23 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LauncherCard(
|
fun LauncherCard(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
elevation: Dp = 2.dp,
|
elevation: Dp = 2.dp,
|
||||||
backgroundOpacity: Float = 1f,
|
backgroundOpacity: Float = LocalCardStyle.current.opacity,
|
||||||
content: @Composable () -> Unit = {}
|
content: @Composable () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
shape = RoundedCornerShape(8.dp),
|
shape = RoundedCornerShape(LocalCardStyle.current.radius.dp),
|
||||||
|
border = LocalCardStyle.current.borderWidth.takeIf { it > 0 }
|
||||||
|
?.let { BorderStroke(it.dp, MaterialTheme.colorScheme.surface) },
|
||||||
content = content,
|
content = content,
|
||||||
color = MaterialTheme.colorScheme.surface.copy(alpha = backgroundOpacity.coerceIn(0f, 1f)),
|
color = MaterialTheme.colorScheme.surface.copy(alpha = backgroundOpacity.coerceIn(0f, 1f)),
|
||||||
shadowElevation = elevation,
|
shadowElevation = if (backgroundOpacity == 1f) elevation else 0.dp,
|
||||||
tonalElevation = elevation
|
tonalElevation = elevation
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
package de.mm20.launcher2.ui.component.preferences
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.Slider
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import de.mm20.launcher2.ktx.ceilToInt
|
||||||
|
import java.text.DecimalFormat
|
||||||
|
import kotlin.math.floor
|
||||||
|
import kotlin.math.log
|
||||||
|
import kotlin.math.pow
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SliderPreference(
|
||||||
|
title: String,
|
||||||
|
icon: ImageVector? = null,
|
||||||
|
value: Float,
|
||||||
|
min: Float = 0f,
|
||||||
|
max: Float = 1f,
|
||||||
|
step: Float? = null,
|
||||||
|
onValueChanged: (Float) -> Unit,
|
||||||
|
enabled: Boolean = true
|
||||||
|
) {
|
||||||
|
var sliderValue by remember(value) { mutableStateOf(value) }
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 16.dp)
|
||||||
|
.alpha(if (enabled) 1f else 0.38f),
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(48.dp)
|
||||||
|
.padding(start = 4.dp),
|
||||||
|
contentAlignment = Alignment.CenterStart
|
||||||
|
) {
|
||||||
|
if (icon != null) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.padding(start = 8.dp),
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.titleMedium
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Slider(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
value = sliderValue,
|
||||||
|
onValueChange = {
|
||||||
|
sliderValue = it
|
||||||
|
},
|
||||||
|
valueRange = min..max,
|
||||||
|
steps = step?.let { ((max - min) / it).toInt() - 1 } ?: 0,
|
||||||
|
onValueChangeFinished = {
|
||||||
|
onValueChanged(sliderValue)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
val decimalPlaces = -log(step ?: 0.01f, 10f)
|
||||||
|
val format = remember { DecimalFormat().apply {
|
||||||
|
maximumFractionDigits = floor(decimalPlaces).toInt()
|
||||||
|
minimumFractionDigits = 0
|
||||||
|
} }
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.width(56.dp).padding(start = 24.dp),
|
||||||
|
text = format.format(sliderValue),
|
||||||
|
style = MaterialTheme.typography.titleSmall
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SliderPreference(
|
||||||
|
title: String,
|
||||||
|
icon: ImageVector? = null,
|
||||||
|
value: Int,
|
||||||
|
min: Int = 0,
|
||||||
|
max: Int = 100,
|
||||||
|
step: Int = 1,
|
||||||
|
onValueChanged: (Int) -> Unit,
|
||||||
|
enabled: Boolean = true
|
||||||
|
) {
|
||||||
|
SliderPreference(
|
||||||
|
title = title,
|
||||||
|
icon = icon,
|
||||||
|
value = value.toFloat(),
|
||||||
|
enabled = enabled,
|
||||||
|
min = min.toFloat(),
|
||||||
|
max = max.toFloat(),
|
||||||
|
step = step.toFloat(),
|
||||||
|
onValueChanged = {
|
||||||
|
onValueChanged(it.roundToInt())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -49,6 +49,7 @@ import de.mm20.launcher2.search.data.Websearch
|
|||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.LauncherCard
|
import de.mm20.launcher2.ui.component.LauncherCard
|
||||||
import de.mm20.launcher2.ui.launcher.LauncherActivityVM
|
import de.mm20.launcher2.ui.launcher.LauncherActivityVM
|
||||||
|
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||||
import de.mm20.launcher2.ui.settings.SettingsActivity
|
import de.mm20.launcher2.ui.settings.SettingsActivity
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import org.koin.androidx.compose.inject
|
import org.koin.androidx.compose.inject
|
||||||
@ -176,10 +177,11 @@ fun SearchBar(
|
|||||||
durationMillis = 200,
|
durationMillis = 200,
|
||||||
delayMillis = 200
|
delayMillis = 200
|
||||||
)
|
)
|
||||||
else -> tween(durationMillis = 500)
|
else -> tween(durationMillis = 200)
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
when {
|
when {
|
||||||
|
it == SearchBarLevel.Active -> LocalCardStyle.current.opacity
|
||||||
style != SearchBarSettings.SearchBarStyle.Transparent -> 1f
|
style != SearchBarSettings.SearchBarStyle.Transparent -> 1f
|
||||||
it == SearchBarLevel.Resting -> 0f
|
it == SearchBarLevel.Resting -> 0f
|
||||||
else -> 1f
|
else -> 1f
|
||||||
|
|||||||
@ -6,21 +6,32 @@ import android.util.Log
|
|||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.platform.ComposeView
|
import androidx.compose.ui.platform.ComposeView
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
|
import de.mm20.launcher2.preferences.Settings
|
||||||
import de.mm20.launcher2.ui.LegacyLauncherTheme
|
import de.mm20.launcher2.ui.LegacyLauncherTheme
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.launcher.search.SearchBar
|
import de.mm20.launcher2.ui.launcher.search.SearchBar
|
||||||
import de.mm20.launcher2.ui.launcher.search.SearchBarLevel
|
import de.mm20.launcher2.ui.launcher.search.SearchBarLevel
|
||||||
|
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||||
|
import de.mm20.launcher2.ui.locals.LocalNavController
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import org.koin.core.component.KoinComponent
|
||||||
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class SearchBar @JvmOverloads constructor(
|
class SearchBar @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = R.attr.materialCardViewStyle
|
defStyleAttr: Int = R.attr.materialCardViewStyle
|
||||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
) : FrameLayout(context, attrs, defStyleAttr), KoinComponent {
|
||||||
|
|
||||||
var level: SearchBarLevel = SearchBarLevel.Resting
|
var level: SearchBarLevel = SearchBarLevel.Resting
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -28,6 +39,7 @@ class SearchBar @JvmOverloads constructor(
|
|||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val dataStore: LauncherDataStore by inject()
|
||||||
private val levelState = MutableLiveData(level)
|
private val levelState = MutableLiveData(level)
|
||||||
|
|
||||||
var onFocus: (() -> Unit)? = null
|
var onFocus: (() -> Unit)? = null
|
||||||
@ -36,12 +48,21 @@ class SearchBar @JvmOverloads constructor(
|
|||||||
val view = ComposeView(context)
|
val view = ComposeView(context)
|
||||||
view.setContent {
|
view.setContent {
|
||||||
val level by levelState.observeAsState(SearchBarLevel.Resting)
|
val level by levelState.observeAsState(SearchBarLevel.Resting)
|
||||||
LegacyLauncherTheme {
|
val cardStyle by remember {
|
||||||
Box(contentAlignment = Alignment.TopCenter) {
|
dataStore.data.map { it.cards }.distinctUntilChanged()
|
||||||
SearchBar(
|
}.collectAsState(
|
||||||
level,
|
Settings.CardSettings.getDefaultInstance()
|
||||||
onFocus = { onFocus?.invoke() }
|
)
|
||||||
)
|
CompositionLocalProvider(
|
||||||
|
LocalCardStyle provides cardStyle
|
||||||
|
) {
|
||||||
|
LegacyLauncherTheme {
|
||||||
|
Box(contentAlignment = Alignment.TopCenter) {
|
||||||
|
SearchBar(
|
||||||
|
level,
|
||||||
|
onFocus = { onFocus?.invoke() }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,20 +3,51 @@ package de.mm20.launcher2.ui.legacy.view
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import de.mm20.launcher2.ktx.dp
|
import de.mm20.launcher2.ktx.dp
|
||||||
|
import de.mm20.launcher2.ktx.lifecycleOwner
|
||||||
|
import de.mm20.launcher2.ktx.lifecycleScope
|
||||||
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
import de.mm20.launcher2.preferences.LauncherPreferences
|
import de.mm20.launcher2.preferences.LauncherPreferences
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.koin.core.component.KoinComponent
|
||||||
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
open class InnerCardView @JvmOverloads constructor(
|
open class InnerCardView @JvmOverloads constructor(
|
||||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.attr.materialCardViewStyle
|
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.attr.materialCardViewStyle
|
||||||
) : MaterialCardView(context, attrs, defStyleAttr) {
|
) : MaterialCardView(context, attrs, defStyleAttr), KoinComponent {
|
||||||
init {
|
init {
|
||||||
|
|
||||||
radius = LauncherPreferences.instance.cardRadius * dp
|
radius = LauncherCardView.currentCardStyle.radius * dp
|
||||||
strokeColor = ContextCompat.getColor(context, R.color.color_divider)
|
strokeColor = ContextCompat.getColor(context, R.color.color_divider)
|
||||||
strokeWidth = (1 * dp).toInt()
|
strokeWidth = (1 * dp).toInt()
|
||||||
cardElevation = 2 * dp
|
cardElevation = 2 * dp
|
||||||
outlineProvider = null
|
outlineProvider = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val dataStore: LauncherDataStore by inject()
|
||||||
|
private var job: Job? = null
|
||||||
|
override fun onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow()
|
||||||
|
job?.cancel()
|
||||||
|
job = lifecycleScope.launch {
|
||||||
|
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
|
dataStore.data.map { it.cards.radius }.distinctUntilChanged().collectLatest {
|
||||||
|
radius = it * dp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun onDetachedFromWindow() {
|
||||||
|
super.onDetachedFromWindow()
|
||||||
|
job?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,10 +3,22 @@ package de.mm20.launcher2.ui.legacy.view
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import de.mm20.launcher2.ktx.dp
|
import de.mm20.launcher2.ktx.dp
|
||||||
import de.mm20.launcher2.preferences.LauncherPreferences
|
import de.mm20.launcher2.ktx.lifecycleOwner
|
||||||
|
import de.mm20.launcher2.ktx.lifecycleScope
|
||||||
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
|
import de.mm20.launcher2.preferences.Settings
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.koin.core.component.KoinComponent
|
||||||
|
import org.koin.core.component.inject
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,15 +27,12 @@ import kotlin.math.roundToInt
|
|||||||
* (2) Elevation overlay color
|
* (2) Elevation overlay color
|
||||||
*/
|
*/
|
||||||
open class LauncherCardView @JvmOverloads constructor(
|
open class LauncherCardView @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = R.attr.materialCardViewStyle
|
defStyleAttr: Int = R.attr.materialCardViewStyle
|
||||||
) : MaterialCardView(context, attrs, defStyleAttr) {
|
) : MaterialCardView(context, attrs, defStyleAttr), KoinComponent {
|
||||||
|
|
||||||
private val isDarkTheme = resources.getBoolean(R.bool.is_dark_theme)
|
var backgroundOpacity: Int = (currentCardStyle.opacity * 255).roundToInt()
|
||||||
|
|
||||||
|
|
||||||
var backgroundOpacity: Int = LauncherPreferences.instance.cardOpacity
|
|
||||||
set(value) {
|
set(value) {
|
||||||
setCardBackgroundColor(cardBackgroundColor.defaultColor.let {
|
setCardBackgroundColor(cardBackgroundColor.defaultColor.let {
|
||||||
ColorStateList.valueOf((it and 0xFFFFFF) or (value shl 24))
|
ColorStateList.valueOf((it and 0xFFFFFF) or (value shl 24))
|
||||||
@ -31,7 +40,7 @@ open class LauncherCardView @JvmOverloads constructor(
|
|||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
var strokeOpacity: Int = if (LauncherPreferences.instance.cardStrokeWidth > 0) 0xFF else 0
|
private var strokeOpacity: Int = if (currentCardStyle.borderWidth > 0) 0xFF else 0
|
||||||
set(value) {
|
set(value) {
|
||||||
setStrokeColor(strokeColorStateList?.defaultColor?.let {
|
setStrokeColor(strokeColorStateList?.defaultColor?.let {
|
||||||
ColorStateList.valueOf((it and 0xFFFFFF) or (value shl 24))
|
ColorStateList.valueOf((it and 0xFFFFFF) or (value shl 24))
|
||||||
@ -39,23 +48,24 @@ open class LauncherCardView @JvmOverloads constructor(
|
|||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var overrideBackgroundOpacity = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
/*val cardColor = when (LauncherPreferences.instance.cardBackground) {
|
|
||||||
CardBackground.DEFAULT-> context.getColor(R.color.cardview_background)
|
|
||||||
CardBackground.BLACK -> context.getColor(R.color.cardview_background_black)
|
|
||||||
}
|
|
||||||
setCardBackgroundColor(cardColor)*/
|
|
||||||
strokeColor = cardBackgroundColor.defaultColor
|
strokeColor = cardBackgroundColor.defaultColor
|
||||||
strokeWidth = (LauncherPreferences.instance.cardStrokeWidth * dp).roundToInt()
|
strokeWidth = (currentCardStyle.borderWidth * dp).roundToInt()
|
||||||
radius = LauncherPreferences.instance.cardRadius * dp
|
radius = currentCardStyle.radius * dp
|
||||||
|
|
||||||
context.theme.obtainStyledAttributes(
|
context.theme.obtainStyledAttributes(
|
||||||
attrs,
|
attrs,
|
||||||
R.styleable.LauncherCardView,
|
R.styleable.LauncherCardView,
|
||||||
0, 0).apply {
|
0, 0
|
||||||
|
).apply {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
backgroundOpacity = getInt(R.styleable.LauncherCardView_backgroundOpacity, LauncherPreferences.instance.cardOpacity)
|
if (hasValue(R.styleable.LauncherCardView_backgroundOpacity)) {
|
||||||
|
overrideBackgroundOpacity = true
|
||||||
|
backgroundOpacity = getInt(R.styleable.LauncherCardView_backgroundOpacity, 255)
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
recycle()
|
recycle()
|
||||||
}
|
}
|
||||||
@ -64,4 +74,36 @@ open class LauncherCardView @JvmOverloads constructor(
|
|||||||
elevation = if (backgroundOpacity == 255) elevation else 0f
|
elevation = if (backgroundOpacity == 255) elevation else 0f
|
||||||
cardElevation = elevation
|
cardElevation = elevation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val dataStore: LauncherDataStore by inject()
|
||||||
|
|
||||||
|
private var job: Job? = null
|
||||||
|
override fun onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow()
|
||||||
|
job?.cancel()
|
||||||
|
job = lifecycleScope.launch {
|
||||||
|
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
|
dataStore.data.map { it.cards }.distinctUntilChanged().collectLatest {
|
||||||
|
currentCardStyle = it
|
||||||
|
if (!overrideBackgroundOpacity) {
|
||||||
|
backgroundOpacity = (it.opacity * 255).roundToInt()
|
||||||
|
strokeOpacity = if (backgroundOpacity == 0) 0 else 0xFF
|
||||||
|
elevation = if (backgroundOpacity == 255) elevation else 0f
|
||||||
|
cardElevation = elevation
|
||||||
|
}
|
||||||
|
strokeWidth = (it.borderWidth * dp).roundToInt()
|
||||||
|
radius = it.radius * dp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetachedFromWindow() {
|
||||||
|
super.onDetachedFromWindow()
|
||||||
|
job?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
internal var currentCardStyle = Settings.CardSettings.getDefaultInstance()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -13,23 +13,28 @@ import androidx.annotation.DrawableRes
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.animation.doOnEnd
|
import androidx.core.animation.doOnEnd
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.*
|
||||||
import androidx.lifecycle.asLiveData
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import de.mm20.launcher2.favorites.FavoritesRepository
|
import de.mm20.launcher2.favorites.FavoritesRepository
|
||||||
import de.mm20.launcher2.ktx.dp
|
import de.mm20.launcher2.ktx.dp
|
||||||
import de.mm20.launcher2.preferences.LauncherPreferences
|
import de.mm20.launcher2.ktx.lifecycleOwner
|
||||||
|
import de.mm20.launcher2.ktx.lifecycleScope
|
||||||
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
import de.mm20.launcher2.search.data.Searchable
|
import de.mm20.launcher2.search.data.Searchable
|
||||||
import de.mm20.launcher2.transition.ChangingLayoutTransition
|
import de.mm20.launcher2.transition.ChangingLayoutTransition
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
class SwipeCardView @JvmOverloads constructor(
|
class SwipeCardView @JvmOverloads constructor(
|
||||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||||
) : MaterialCardView(context, attrs, defStyleAttr) {
|
) : MaterialCardView(context, attrs, defStyleAttr), KoinComponent {
|
||||||
|
|
||||||
private val backdrop = FrameLayout(context)
|
private val backdrop = FrameLayout(context)
|
||||||
private val icon = ImageView(context)
|
private val icon = ImageView(context)
|
||||||
@ -44,10 +49,9 @@ class SwipeCardView @JvmOverloads constructor(
|
|||||||
icon.setColorFilter(iconColor)
|
icon.setColorFilter(iconColor)
|
||||||
super.addView(content)
|
super.addView(content)
|
||||||
content.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
content.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||||
content.radius = radius
|
|
||||||
content.transitionName = "SwipeCardView/content"
|
content.transitionName = "SwipeCardView/content"
|
||||||
radius = LauncherPreferences.instance.cardRadius * dp
|
radius = LauncherCardView.currentCardStyle.radius * dp
|
||||||
//content.setCardBackgroundColor(cardBackgroundColor)
|
content.radius = radius
|
||||||
super.setCardBackgroundColor(
|
super.setCardBackgroundColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
context,
|
context,
|
||||||
@ -362,6 +366,25 @@ class SwipeCardView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val dataStore: LauncherDataStore by inject()
|
||||||
|
private var job: Job? = null
|
||||||
|
override fun onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow()
|
||||||
|
job?.cancel()
|
||||||
|
job = lifecycleScope.launch {
|
||||||
|
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
|
dataStore.data.map { it.cards.radius }.distinctUntilChanged().collectLatest {
|
||||||
|
radius = it * dp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun onDetachedFromWindow() {
|
||||||
|
super.onDetachedFromWindow()
|
||||||
|
job?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
open class SwipeAction(
|
open class SwipeAction(
|
||||||
@DrawableRes var icon: Int,
|
@DrawableRes var icon: Int,
|
||||||
var color: Int,
|
var color: Int,
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import android.appwidget.AppWidgetHost
|
|||||||
import androidx.compose.runtime.compositionLocalOf
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
import androidx.compose.ui.geometry.Size
|
import androidx.compose.ui.geometry.Size
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
|
import de.mm20.launcher2.preferences.Settings
|
||||||
import de.mm20.launcher2.ui.theme.WallpaperColors
|
import de.mm20.launcher2.ui.theme.WallpaperColors
|
||||||
import de.mm20.launcher2.ui.theme.colors.ColorPalette
|
import de.mm20.launcher2.ui.theme.colors.ColorPalette
|
||||||
import de.mm20.launcher2.ui.theme.colors.DefaultColorPalette
|
import de.mm20.launcher2.ui.theme.colors.DefaultColorPalette
|
||||||
@ -16,4 +17,6 @@ val LocalWallpaperColors = compositionLocalOf<WallpaperColors?> { null }
|
|||||||
|
|
||||||
val LocalColorScheme = compositionLocalOf<ColorPalette> { DefaultColorPalette() }
|
val LocalColorScheme = compositionLocalOf<ColorPalette> { DefaultColorPalette() }
|
||||||
|
|
||||||
val LocalNavController = compositionLocalOf<NavController?> { null }
|
val LocalNavController = compositionLocalOf<NavController?> { null }
|
||||||
|
|
||||||
|
val LocalCardStyle = compositionLocalOf<Settings.CardSettings> { Settings.CardSettings.getDefaultInstance() }
|
||||||
@ -7,6 +7,8 @@ import androidx.compose.animation.core.tween
|
|||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.navigation.navArgument
|
import androidx.navigation.navArgument
|
||||||
import com.google.accompanist.navigation.animation.AnimatedNavHost
|
import com.google.accompanist.navigation.animation.AnimatedNavHost
|
||||||
@ -14,37 +16,54 @@ import com.google.accompanist.navigation.animation.composable
|
|||||||
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
||||||
import de.mm20.launcher2.licenses.AppLicense
|
import de.mm20.launcher2.licenses.AppLicense
|
||||||
import de.mm20.launcher2.licenses.OpenSourceLicenses
|
import de.mm20.launcher2.licenses.OpenSourceLicenses
|
||||||
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
|
import de.mm20.launcher2.preferences.Settings
|
||||||
import de.mm20.launcher2.ui.LegacyLauncherTheme
|
import de.mm20.launcher2.ui.LegacyLauncherTheme
|
||||||
import de.mm20.launcher2.ui.base.BaseActivity
|
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.LocalNavController
|
||||||
import de.mm20.launcher2.ui.settings.about.AboutSettingsScreen
|
import de.mm20.launcher2.ui.settings.about.AboutSettingsScreen
|
||||||
|
import de.mm20.launcher2.ui.settings.accounts.AccountsSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.appearance.AppearanceSettingsScreen
|
import de.mm20.launcher2.ui.settings.appearance.AppearanceSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.badges.BadgeSettingsScreen
|
import de.mm20.launcher2.ui.settings.badges.BadgeSettingsScreen
|
||||||
|
import de.mm20.launcher2.ui.settings.buildinfo.BuildInfoSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.calendarwidget.CalendarWidgetSettingsScreen
|
import de.mm20.launcher2.ui.settings.calendarwidget.CalendarWidgetSettingsScreen
|
||||||
|
import de.mm20.launcher2.ui.settings.cards.CardsSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.clockwidget.ClockWidgetSettingsScreen
|
import de.mm20.launcher2.ui.settings.clockwidget.ClockWidgetSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.debug.DebugSettingsScreen
|
import de.mm20.launcher2.ui.settings.debug.DebugSettingsScreen
|
||||||
|
import de.mm20.launcher2.ui.settings.easteregg.EasterEggSettingsScreen
|
||||||
|
import de.mm20.launcher2.ui.settings.filesearch.FileSearchSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.license.LicenseScreen
|
import de.mm20.launcher2.ui.settings.license.LicenseScreen
|
||||||
import de.mm20.launcher2.ui.settings.main.MainSettingsScreen
|
import de.mm20.launcher2.ui.settings.main.MainSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.musicwidget.MusicWidgetSettingsScreen
|
import de.mm20.launcher2.ui.settings.musicwidget.MusicWidgetSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.search.SearchSettingsScreen
|
import de.mm20.launcher2.ui.settings.search.SearchSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.accounts.AccountsSettingsScreen
|
|
||||||
import de.mm20.launcher2.ui.settings.buildinfo.BuildInfoSettingsScreen
|
|
||||||
import de.mm20.launcher2.ui.settings.easteregg.EasterEggSettingsScreen
|
|
||||||
import de.mm20.launcher2.ui.settings.filesearch.FileSearchSettingsScreen
|
|
||||||
import de.mm20.launcher2.ui.settings.weatherwidget.WeatherWidgetSettingsScreen
|
import de.mm20.launcher2.ui.settings.weatherwidget.WeatherWidgetSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.websearch.WebSearchSettingsScreen
|
import de.mm20.launcher2.ui.settings.websearch.WebSearchSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.widgets.WidgetsSettingsScreen
|
import de.mm20.launcher2.ui.settings.widgets.WidgetsSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.wikipedia.WikipediaSettingsScreen
|
import de.mm20.launcher2.ui.settings.wikipedia.WikipediaSettingsScreen
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
class SettingsActivity : BaseActivity() {
|
class SettingsActivity : BaseActivity() {
|
||||||
|
|
||||||
|
private val dataStore: LauncherDataStore by inject()
|
||||||
|
|
||||||
@OptIn(ExperimentalAnimationApi::class)
|
@OptIn(ExperimentalAnimationApi::class)
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
val navController = rememberAnimatedNavController()
|
val navController = rememberAnimatedNavController()
|
||||||
CompositionLocalProvider(LocalNavController provides navController) {
|
val cardStyle by remember {
|
||||||
|
dataStore.data.map { it.cards }.distinctUntilChanged()
|
||||||
|
}.collectAsState(
|
||||||
|
Settings.CardSettings.getDefaultInstance()
|
||||||
|
)
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalNavController provides navController,
|
||||||
|
LocalCardStyle provides cardStyle
|
||||||
|
) {
|
||||||
LegacyLauncherTheme {
|
LegacyLauncherTheme {
|
||||||
AnimatedNavHost(
|
AnimatedNavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
@ -60,6 +79,9 @@ class SettingsActivity : BaseActivity() {
|
|||||||
composable("settings/appearance") {
|
composable("settings/appearance") {
|
||||||
AppearanceSettingsScreen()
|
AppearanceSettingsScreen()
|
||||||
}
|
}
|
||||||
|
composable("settings/appearance/cards") {
|
||||||
|
CardsSettingsScreen()
|
||||||
|
}
|
||||||
composable("settings/search") {
|
composable("settings/search") {
|
||||||
SearchSettingsScreen()
|
SearchSettingsScreen()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,6 +37,7 @@ import de.mm20.launcher2.ui.component.preferences.*
|
|||||||
import de.mm20.launcher2.ui.launcher.search.SearchBar
|
import de.mm20.launcher2.ui.launcher.search.SearchBar
|
||||||
import de.mm20.launcher2.ui.launcher.search.SearchBarLevel
|
import de.mm20.launcher2.ui.launcher.search.SearchBarLevel
|
||||||
import de.mm20.launcher2.ui.legacy.view.LauncherIconView
|
import de.mm20.launcher2.ui.legacy.view.LauncherIconView
|
||||||
|
import de.mm20.launcher2.ui.locals.LocalNavController
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
|
|
||||||
@ -44,6 +45,7 @@ import kotlinx.coroutines.isActive
|
|||||||
fun AppearanceSettingsScreen() {
|
fun AppearanceSettingsScreen() {
|
||||||
val viewModel: AppearanceSettingsScreenVM = viewModel()
|
val viewModel: AppearanceSettingsScreenVM = viewModel()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val navController = LocalNavController.current
|
||||||
PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) {
|
PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) {
|
||||||
item {
|
item {
|
||||||
PreferenceCategory {
|
PreferenceCategory {
|
||||||
@ -74,6 +76,13 @@ fun AppearanceSettingsScreen() {
|
|||||||
viewModel.setColorScheme(newValue)
|
viewModel.setColorScheme(newValue)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
Preference(
|
||||||
|
title = stringResource(R.string.preference_cards),
|
||||||
|
summary = stringResource(R.string.preference_cards_summary),
|
||||||
|
onClick = {
|
||||||
|
navController?.navigate("settings/appearance/cards")
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
PreferenceCategory(title = stringResource(R.string.preference_category_grid)) {
|
PreferenceCategory(title = stringResource(R.string.preference_category_grid)) {
|
||||||
val columnCount by viewModel.columnCount.observeAsState()
|
val columnCount by viewModel.columnCount.observeAsState()
|
||||||
|
|||||||
@ -0,0 +1,83 @@
|
|||||||
|
package de.mm20.launcher2.ui.settings.cards
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.rounded.BorderStyle
|
||||||
|
import androidx.compose.material.icons.rounded.LineWeight
|
||||||
|
import androidx.compose.material.icons.rounded.Opacity
|
||||||
|
import androidx.compose.material.icons.rounded.RoundedCorner
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import de.mm20.launcher2.ui.R
|
||||||
|
import de.mm20.launcher2.ui.component.LauncherCard
|
||||||
|
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||||
|
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||||
|
import de.mm20.launcher2.ui.component.preferences.SliderPreference
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CardsSettingsScreen() {
|
||||||
|
val viewModel: CardsSettingsScreenVM = viewModel()
|
||||||
|
PreferenceScreen(title = stringResource(R.string.preference_cards)) {
|
||||||
|
item {
|
||||||
|
Box(modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(MaterialTheme.colorScheme.secondary)) {
|
||||||
|
LauncherCard(
|
||||||
|
modifier = Modifier
|
||||||
|
.height(200.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
PreferenceCategory {
|
||||||
|
val opacity by viewModel.opacity.observeAsState(0f)
|
||||||
|
SliderPreference(
|
||||||
|
title = stringResource(R.string.preference_cards_opacity),
|
||||||
|
icon = Icons.Rounded.Opacity,
|
||||||
|
value = opacity,
|
||||||
|
min = 0f,
|
||||||
|
max = 1f,
|
||||||
|
onValueChanged = {
|
||||||
|
viewModel.setOpacity(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
val radius by viewModel.radius.observeAsState(0)
|
||||||
|
SliderPreference(
|
||||||
|
title = stringResource(R.string.preference_cards_corner_radius),
|
||||||
|
icon = Icons.Rounded.RoundedCorner,
|
||||||
|
value = radius,
|
||||||
|
min = 0,
|
||||||
|
max = 24,
|
||||||
|
step = 1,
|
||||||
|
onValueChanged = {
|
||||||
|
viewModel.setRadius(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
val borderWidth by viewModel.borderWidth.observeAsState(0)
|
||||||
|
SliderPreference(
|
||||||
|
title = stringResource(R.string.preference_cards_stroke_width),
|
||||||
|
icon = Icons.Rounded.LineWeight,
|
||||||
|
value = borderWidth,
|
||||||
|
min = 0,
|
||||||
|
max = 8,
|
||||||
|
step = 1,
|
||||||
|
onValueChanged = {
|
||||||
|
viewModel.setBorderWidth(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package de.mm20.launcher2.ui.settings.cards
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.asLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.koin.core.component.KoinComponent
|
||||||
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
|
class CardsSettingsScreenVM: ViewModel(), KoinComponent {
|
||||||
|
private val dataStore: LauncherDataStore by inject()
|
||||||
|
|
||||||
|
val opacity = dataStore.data.map { it.cards.opacity }.asLiveData()
|
||||||
|
fun setOpacity(opacity: Float) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
dataStore.updateData {
|
||||||
|
it.toBuilder()
|
||||||
|
.setCards(it.cards.toBuilder()
|
||||||
|
.setOpacity(opacity)
|
||||||
|
).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val radius = dataStore.data.map { it.cards.radius }.asLiveData()
|
||||||
|
fun setRadius(radius: Int) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
dataStore.updateData {
|
||||||
|
it.toBuilder()
|
||||||
|
.setCards(it.cards.toBuilder()
|
||||||
|
.setRadius(radius)
|
||||||
|
).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val borderWidth = dataStore.data.map { it.cards.borderWidth }.asLiveData()
|
||||||
|
fun setBorderWidth(borderWidth: Int) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
dataStore.updateData {
|
||||||
|
it.toBuilder()
|
||||||
|
.setCards(it.cards.toBuilder()
|
||||||
|
.setBorderWidth(borderWidth)
|
||||||
|
).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user