feat(IconOpts): icon background color selection

Fixes #42
This commit is contained in:
rushiiMachine 2025-03-29 21:42:32 -07:00
parent b8cf2176c6
commit 9f036879a0
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
5 changed files with 142 additions and 13 deletions

View file

@ -133,6 +133,7 @@ android {
kotlin {
sourceSets.all {
languageSettings.enableLanguageFeature("ExplicitBackingFields")
languageSettings.enableLanguageFeature("WhenGuards")
}
}

View file

@ -8,21 +8,56 @@ import com.aliucord.manager.ui.screens.patchopts.PatchOptions.IconReplacement
class IconOptionsModel(
prefilledOptions: IconReplacement,
) : ScreenModel {
var selectedColor by mutableStateOf<Color>(((prefilledOptions as? IconReplacement.CustomColor) ?: IconReplacement.Discord).color)
// ---------- Icon patching mode ---------- //
var mode by mutableStateOf(IconOptionsMode.Original)
private set
fun changeMode(mode: IconOptionsMode) {
this.mode = mode
}
// ---------- Replacement color ---------- //
var selectedColorValue by mutableLongStateOf(0)
val selectedColor: Color
inline get() = Color(selectedColorValue.toULong())
fun changeSelectedColor(color: Color) {
this.selectedColor = color
selectedColorValue = color.value.toLong()
}
fun generateConfig(): IconReplacement {
// TODO: other branches
return IconReplacement.CustomColor(color = selectedColor)
// ---------- Other ---------- //
init {
when (prefilledOptions) {
is IconReplacement.CustomColor if prefilledOptions.color == IconReplacement.Aliucord.color -> {
changeMode(IconOptionsMode.Aliucord)
changeSelectedColor(IconReplacement.Aliucord.color)
}
is IconReplacement.CustomColor -> {
changeMode(IconOptionsMode.CustomColor)
changeSelectedColor(prefilledOptions.color)
}
is IconReplacement.CustomImage -> {
changeMode(IconOptionsMode.CustomImage)
TODO()
}
IconReplacement.Original -> changeMode(IconOptionsMode.Original)
}
}
enum class Mode {
Original,
ReplaceColor,
ReplaceForeground,
fun generateConfig(): IconReplacement = when (mode) {
IconOptionsMode.Original -> IconReplacement.Original
IconOptionsMode.Aliucord -> IconReplacement.Aliucord
IconOptionsMode.CustomColor -> IconReplacement.CustomColor(color = selectedColor)
IconOptionsMode.CustomImage -> TODO()
}
}
enum class IconOptionsMode {
Original,
Aliucord,
CustomColor,
CustomImage,
}

View file

@ -1,17 +1,23 @@
package com.aliucord.manager.ui.screens.iconopts
import android.os.Parcelable
import androidx.compose.animation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.screen.Screen
import com.aliucord.manager.R
import com.aliucord.manager.ui.screens.iconopts.components.IconOptionsAppBar
import com.aliucord.manager.ui.screens.iconopts.components.RadioSelectorItem
import dev.zt64.compose.pipette.CircularColorPicker
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
@ -37,6 +43,8 @@ class IconOptionsScreen(
val model = parent.getIconModel()
IconOptionsScreenContent(
mode = model.mode,
setMode = model::changeMode,
selectedColor = model.selectedColor,
setSelectedColor = model::changeSelectedColor,
)
@ -45,6 +53,8 @@ class IconOptionsScreen(
@Composable
fun IconOptionsScreenContent(
mode: IconOptionsMode,
setMode: (IconOptionsMode) -> Unit,
selectedColor: Color,
setSelectedColor: (Color) -> Unit,
) {
@ -60,11 +70,42 @@ fun IconOptionsScreenContent(
.padding(paddingValues)
.padding(horizontal = 20.dp, vertical = 20.dp)
) {
CircularColorPicker(
color = selectedColor,
onColorChange = setSelectedColor,
modifier = Modifier.size(250.dp)
// TODO: live icon preview
HorizontalDivider(Modifier.padding(vertical = 16.dp))
RadioSelectorItem(
name = stringResource(R.string.discord),
description = stringResource(R.string.iconopts_variant_desc_discord),
selected = mode == IconOptionsMode.Original,
onClick = remember { { setMode(IconOptionsMode.Original) } },
)
RadioSelectorItem(
name = stringResource(R.string.aliucord),
description = stringResource(R.string.iconopts_variant_desc_aliucord),
selected = mode == IconOptionsMode.Aliucord,
onClick = remember { { setMode(IconOptionsMode.Aliucord) } },
)
RadioSelectorItem(
name = stringResource(R.string.iconopts_variant_title_color),
description = stringResource(R.string.iconopts_variant_desc_color),
selected = mode == IconOptionsMode.CustomColor,
onClick = remember { { setMode(IconOptionsMode.CustomColor) } },
)
HorizontalDivider(Modifier.padding(vertical = 16.dp))
AnimatedVisibility(
visible = mode == IconOptionsMode.CustomColor,
enter = fadeIn() + slideInVertically(),
exit = fadeOut() + slideOutVertically { -it / 10 },
) {
CircularColorPicker(
color = selectedColor,
onColorChange = setSelectedColor,
modifier = Modifier.size(230.dp),
)
}
}
}
}

View file

@ -0,0 +1,48 @@
package com.aliucord.manager.ui.screens.iconopts.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.material3.RadioButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import com.aliucord.manager.ui.screens.patchopts.components.options.PatchOption
@Composable
fun RadioSelectorItem(
name: String,
description: String,
selected: Boolean,
modifier: Modifier = Modifier.Companion,
onClick: () -> Unit,
) {
val interactionSource = remember(::MutableInteractionSource)
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
modifier = modifier
.fillMaxWidth()
.padding(end = 12.dp)
.clickable(
onClick = onClick,
interactionSource = interactionSource,
indication = null,
role = Role.Companion.Switch,
),
) {
RadioButton(
selected = selected,
onClick = onClick,
interactionSource = interactionSource,
)
PatchOption(
name = name,
description = description,
content = {},
)
}
}

View file

@ -165,6 +165,10 @@
<string name="patchopts_divider_advanced">Advanced</string>
<string name="iconopts_screen_title">Icon Replacement</string>
<string name="iconopts_variant_title_color">Custom Color</string>
<string name="iconopts_variant_desc_discord">Does not alter the original icon, instead only adding the missing monochrome icon to the APK.</string>
<string name="iconopts_variant_desc_aliucord">Changes the original icon color to Aliucord\'s branding.</string>
<string name="iconopts_variant_desc_color">Select a custom icon background color.</string>
<string name="notif_group_install_title">Active installation</string>
<string name="notif_group_install_desc">Progress notifications sent during a minimized installation</string>