From 40e0e1477ed988302a62edae685f0c024e28ac15 Mon Sep 17 00:00:00 2001 From: 283375 Date: Sun, 30 Aug 2026 12:53:14 +0800 Subject: [PATCH 1/3] ArcaeaRatingClassSelector refactor and INS difficulty support --- .../ui/components/ArcaeaChartSelector.kt | 11 +- .../components/ArcaeaRatingClassSelector.kt | 231 +++++++++--------- .../utilities/UtilitiesCalculatorScreen.kt | 15 +- .../constants/ArcaeaRatingClassDisplay.kt | 23 ++ .../arcaeaoffline/ui/theme/ColorUtils.kt | 8 + .../arcaeaoffline/ui/theme/CustomColors.kt | 2 + 6 files changed, 161 insertions(+), 129 deletions(-) create mode 100644 shared/src/commonMain/kotlin/xyz/sevive/arcaeaoffline/core/constants/ArcaeaRatingClassDisplay.kt diff --git a/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaChartSelector.kt b/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaChartSelector.kt index 4c232d90..6b9568a3 100644 --- a/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaChartSelector.kt +++ b/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaChartSelector.kt @@ -87,13 +87,9 @@ fun ArcaeaChartSelector( allowFakeChart = allowFakeChart, ) - val ratingDetails = + val selectorItems = remember(charts) { - charts.associate { it.ratingClass to (it.rating to it.ratingPlus) } - } - val enabledRatingClasses = - remember(charts) { - charts.map { it.ratingClass } + charts.toRatingClassSelectorItems() } // Emit the change when either [selectedSongId] or [selectedRatingClass] changes. @@ -123,10 +119,9 @@ fun ArcaeaChartSelector( Icon(painterResource(R.drawable.ic_rating_class), contentDescription = null) ArcaeaRatingClassSelector( + items = selectorItems, selectedRatingClass = selectedRatingClass, onRatingClassChange = { selectedRatingClass = it }, - enabledRatingClasses = enabledRatingClasses, - ratingDetails = ratingDetails, ) } } diff --git a/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaRatingClassSelector.kt b/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaRatingClassSelector.kt index d2d3657c..6ae27dba 100644 --- a/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaRatingClassSelector.kt +++ b/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaRatingClassSelector.kt @@ -16,6 +16,7 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.Immutable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -45,10 +46,28 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.em import androidx.core.graphics.ColorUtils import xyz.sevive.arcaeaoffline.core.constants.ArcaeaRatingClass +import xyz.sevive.arcaeaoffline.core.constants.ArcaeaRatingClassDisplay +import xyz.sevive.arcaeaoffline.core.database.entities.Chart import xyz.sevive.arcaeaoffline.ui.theme.ArcaeaOfflineTheme import xyz.sevive.arcaeaoffline.ui.theme.ratingClassColor import kotlin.math.min +@Immutable +data class RatingClassSelectorItem( + val display: ArcaeaRatingClassDisplay, + val rating: Int? = null, + val ratingPlus: Boolean = false, +) + +fun List.toRatingClassSelectorItems(): List = + map { + RatingClassSelectorItem( + display = ArcaeaRatingClassDisplay.of(it.ratingClass), + rating = it.rating, + ratingPlus = it.ratingPlus, + ) + } + private class RatingClassShape( private val isFirst: Boolean = false, ) : Shape { @@ -81,59 +100,57 @@ private class RatingClassShape( } } -internal data class RatingClassBoxColors( - val baseColor: Color, +internal class RatingClassBoxColors( + baseColor: Color, ) { // val bgColor = baseColor.copy(alpha = 0.3f) // val textColor = baseColor.copy() val selectedBgColor = baseColor.copy() val selectedTextColor: Color - get() { - val hsl = floatArrayOf(0f, 0f, 0f) - ColorUtils.colorToHSL(baseColor.toArgb(), hsl) - - hsl[1] = min(1f, hsl[1] + 0.1f) - hsl[2] = 0.95f - return Color(ColorUtils.HSLToColor(hsl)) - } val selectedTextShadowColor: Color - get() { - val hsl = floatArrayOf(0f, 0f, 0f) - ColorUtils.colorToHSL(baseColor.toArgb(), hsl) - - hsl[2] = 0.05f - return Color(ColorUtils.HSLToColor(hsl)) - } val notSelectedBgColor: Color - get() { - val hsl = floatArrayOf(0f, 0f, 0f) - ColorUtils.colorToHSL(baseColor.toArgb(), hsl) - - hsl[1] = 0.015f - hsl[2] = 0.6f - return Color(ColorUtils.HSLToColor(hsl)) - } val notSelectedTextColor: Color - get() { - val hsl = floatArrayOf(0f, 0f, 0f) - ColorUtils.colorToHSL(baseColor.toArgb(), hsl) - - hsl[1] = 0f - hsl[2] = 0.28f - return Color(ColorUtils.HSLToColor(hsl)) - } val disabledBgColor = Color(0xff202020) val disabledTextColor = Color(0xff9f9f9f) + + init { + val selectedTextHsl = floatArrayOf(0f, 0f, 0f) + ColorUtils.colorToHSL(baseColor.toArgb(), selectedTextHsl) + + selectedTextHsl[1] = min(1f, selectedTextHsl[1] + 0.1f) + selectedTextHsl[2] = 0.95f + selectedTextColor = Color(ColorUtils.HSLToColor(selectedTextHsl)) + + val selectedTextShadowHsl = floatArrayOf(0f, 0f, 0f) + ColorUtils.colorToHSL(baseColor.toArgb(), selectedTextShadowHsl) + + selectedTextShadowHsl[2] = 0.05f + selectedTextShadowColor = Color(ColorUtils.HSLToColor(selectedTextShadowHsl)) + + val notSelectedBgHsl = floatArrayOf(0f, 0f, 0f) + ColorUtils.colorToHSL(baseColor.toArgb(), notSelectedBgHsl) + + notSelectedBgHsl[1] = 0.015f + notSelectedBgHsl[2] = 0.6f + notSelectedBgColor = Color(ColorUtils.HSLToColor(notSelectedBgHsl)) + + val notSelectedTextHsl = floatArrayOf(0f, 0f, 0f) + ColorUtils.colorToHSL(baseColor.toArgb(), notSelectedTextHsl) + + notSelectedTextHsl[1] = 0f + notSelectedTextHsl[2] = 0.28f + notSelectedTextColor = Color(ColorUtils.HSLToColor(notSelectedTextHsl)) + } } @Composable internal fun RatingClassBox( onClick: () -> Unit, baseColor: Color, - ratingClass: ArcaeaRatingClass, + label: String, selected: Boolean = false, disabled: Boolean = false, isFirst: Boolean = false, @@ -143,7 +160,7 @@ internal fun RatingClassBox( val height = 50.dp val width = height * 1.4f - val colors = RatingClassBoxColors(baseColor) + val colors = remember(baseColor) { RatingClassBoxColors(baseColor) } val bgColor by animateColorAsState( targetValue = @@ -182,7 +199,6 @@ internal fun RatingClassBox( } } } - val label = ratingClass.toString() // val constantMaxHeight = height * 0.9f val labelMaxHeight = height * 0.4f @@ -289,48 +305,52 @@ private fun RatingClassRowLayout( } } +/** + * The default order of selector items. + */ +private val SelectorSlotRatingClasses = + listOf( + ArcaeaRatingClass.PAST, + ArcaeaRatingClass.PRESENT, + ArcaeaRatingClass.FUTURE, + ArcaeaRatingClass.BEYOND, + ArcaeaRatingClass.ETERNAL, + ) + +/** + * Only show these items when passed in. + */ +private val SelectorOptionalSlotRatingClasses = + setOf(ArcaeaRatingClass.BEYOND, ArcaeaRatingClass.ETERNAL) + @Composable fun ArcaeaRatingClassSelector( + items: List, selectedRatingClass: ArcaeaRatingClass?, onRatingClassChange: (ArcaeaRatingClass) -> Unit, - enabledRatingClasses: List = listOf(), - ratingDetails: Map> = mapOf(), + modifier: Modifier = Modifier, ) { - @Composable - fun RatingClassBoxWrapper( - ratingClass: ArcaeaRatingClass, - isFirst: Boolean = false, - ) { - val ratingGroup = ratingDetails[ratingClass] - val rating = ratingGroup?.first - val ratingPlus = ratingGroup?.second ?: false - - RatingClassBox( - onClick = { onRatingClassChange(ratingClass) }, - baseColor = ratingClassColor(ratingClass), - ratingClass = ratingClass, - selected = selectedRatingClass == ratingClass, - disabled = !enabledRatingClasses.contains(ratingClass), - isFirst = isFirst, - rating = rating, - ratingPlus = ratingPlus, - ) - } - - RatingClassRowLayout { - RatingClassBoxWrapper( - ratingClass = ArcaeaRatingClass.PAST, - isFirst = true, - ) - RatingClassBoxWrapper(ratingClass = ArcaeaRatingClass.PRESENT) - RatingClassBoxWrapper(ratingClass = ArcaeaRatingClass.FUTURE) + RatingClassRowLayout(modifier = modifier) { + SelectorSlotRatingClasses.forEach { slotRatingClass -> + val item = items.find { it.display.ratingClass == slotRatingClass } - if (enabledRatingClasses.contains(ArcaeaRatingClass.BEYOND)) { - RatingClassBoxWrapper(ratingClass = ArcaeaRatingClass.BEYOND) - } + if (item == null && slotRatingClass in SelectorOptionalSlotRatingClasses) { + return@forEach + } - if (enabledRatingClasses.contains(ArcaeaRatingClass.ETERNAL)) { - RatingClassBoxWrapper(ratingClass = ArcaeaRatingClass.ETERNAL) + RatingClassBox( + onClick = { onRatingClassChange(slotRatingClass) }, + baseColor = + item?.let { + ratingClassColor(it.display) + } ?: ratingClassColor(slotRatingClass), + label = item?.display?.name ?: slotRatingClass.name, + selected = selectedRatingClass == slotRatingClass, + disabled = item == null, + isFirst = slotRatingClass == ArcaeaRatingClass.PAST, + rating = item?.rating, + ratingPlus = item?.ratingPlus ?: false, + ) } } } @@ -340,37 +360,26 @@ fun ArcaeaRatingClassSelector( private fun RatingClassSelectorDevicePreview() { var selectedRatingClass by remember { mutableStateOf(ArcaeaRatingClass.PRESENT) } - val ratingClasses = - mutableListOf( - ArcaeaRatingClass.PAST, - ArcaeaRatingClass.PRESENT, - ArcaeaRatingClass.FUTURE, - ArcaeaRatingClass.BEYOND, - ArcaeaRatingClass.ETERNAL, + val itemsCommon = + listOf( + RatingClassSelectorItem(ArcaeaRatingClassDisplay.PAST, 3), + RatingClassSelectorItem(ArcaeaRatingClassDisplay.PRESENT, 7, ratingPlus = true), + RatingClassSelectorItem(ArcaeaRatingClassDisplay.FUTURE, 10, ratingPlus = true), ) - val ratingClassesCommon = ratingClasses.toMutableList() - ratingClassesCommon.removeAll( - arrayOf( - ArcaeaRatingClass.BEYOND, - ArcaeaRatingClass.ETERNAL, - ), - ) + val itemsWithBeyond = + itemsCommon + + RatingClassSelectorItem(ArcaeaRatingClassDisplay.BEYOND, 12) - val ratingClassesWithBeyond = ratingClasses.toMutableList() - ratingClassesWithBeyond.remove(ArcaeaRatingClass.ETERNAL) + val itemsWithEternal = + itemsCommon + + RatingClassSelectorItem(ArcaeaRatingClassDisplay.ETERNAL, 10, ratingPlus = true) - val ratingClassesWithEternal = ratingClasses.toMutableList() - ratingClassesWithEternal.remove(ArcaeaRatingClass.BEYOND) + val itemsWithInscribed = + itemsCommon + + RatingClassSelectorItem(ArcaeaRatingClassDisplay.INSCRIBED, 11) - val ratingDetails = - mapOf( - ArcaeaRatingClass.PAST to Pair(3, false), - ArcaeaRatingClass.PRESENT to Pair(7, true), - ArcaeaRatingClass.FUTURE to Pair(10, true), - ArcaeaRatingClass.BEYOND to Pair(12, false), - ArcaeaRatingClass.ETERNAL to Pair(10, true), - ) + val itemsAll = itemsWithBeyond + itemsWithEternal.last() ArcaeaOfflineTheme { Surface { @@ -379,49 +388,47 @@ private fun RatingClassSelectorDevicePreview() { Text("Common case") ArcaeaRatingClassSelector( + items = itemsCommon, selectedRatingClass = selectedRatingClass, onRatingClassChange = { selectedRatingClass = it }, - enabledRatingClasses = ratingClassesCommon, ) - Text("With constant") + Text("With beyond") ArcaeaRatingClassSelector( + items = itemsWithBeyond, selectedRatingClass = selectedRatingClass, onRatingClassChange = { selectedRatingClass = it }, - enabledRatingClasses = ratingClassesCommon, - ratingDetails = ratingDetails, ) - Text("With beyond") + Text("With eternal") ArcaeaRatingClassSelector( + items = itemsWithEternal, selectedRatingClass = selectedRatingClass, onRatingClassChange = { selectedRatingClass = it }, - enabledRatingClasses = ratingClassesWithBeyond, - ratingDetails = ratingDetails, ) - Text("With eternal") + Text("With inscribed") ArcaeaRatingClassSelector( + items = itemsWithInscribed, selectedRatingClass = selectedRatingClass, onRatingClassChange = { selectedRatingClass = it }, - enabledRatingClasses = ratingClassesWithEternal, - ratingDetails = ratingDetails, ) Text("Last | ???") ArcaeaRatingClassSelector( + items = + listOf( + RatingClassSelectorItem(ArcaeaRatingClassDisplay.BEYOND, 12), + ), selectedRatingClass = selectedRatingClass, onRatingClassChange = { selectedRatingClass = it }, - enabledRatingClasses = listOf(ArcaeaRatingClass.BEYOND), - ratingDetails = ratingDetails, ) - Text("wtf") + Text("All") ArcaeaRatingClassSelector( + items = itemsAll, selectedRatingClass = selectedRatingClass, onRatingClassChange = { selectedRatingClass = it }, - enabledRatingClasses = ratingClasses, - ratingDetails = ratingDetails, ) } } diff --git a/app/src/main/java/xyz/sevive/arcaeaoffline/ui/screens/utilities/UtilitiesCalculatorScreen.kt b/app/src/main/java/xyz/sevive/arcaeaoffline/ui/screens/utilities/UtilitiesCalculatorScreen.kt index 8cd49d6f..92e64b29 100644 --- a/app/src/main/java/xyz/sevive/arcaeaoffline/ui/screens/utilities/UtilitiesCalculatorScreen.kt +++ b/app/src/main/java/xyz/sevive/arcaeaoffline/ui/screens/utilities/UtilitiesCalculatorScreen.kt @@ -10,7 +10,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf @@ -32,6 +31,7 @@ import xyz.sevive.arcaeaoffline.ui.SubScreenContainer import xyz.sevive.arcaeaoffline.ui.components.ArcaeaPackAndSongQuickSearch import xyz.sevive.arcaeaoffline.ui.components.ArcaeaRatingClassSelector import xyz.sevive.arcaeaoffline.ui.components.PlayRatingCalculator +import xyz.sevive.arcaeaoffline.ui.components.toRatingClassSelectorItems import xyz.sevive.arcaeaoffline.ui.navigation.UtilitiesSubScreen @OptIn(ExperimentalMaterial3Api::class) @@ -48,12 +48,10 @@ fun UtilitiesCalculatorScreen( value = chartRepo.findAllBySongId(it).firstOrNull() ?: emptyList() } } - val enabledRatingClasses by remember { - derivedStateOf { charts.map { it.ratingClass } } - } - val ratingDetails by remember { - derivedStateOf { charts.associate { it.ratingClass to (it.rating to it.ratingPlus) } } - } + val selectorItems = + remember(charts) { + charts.toRatingClassSelectorItems() + } LaunchedEffect(selectedRatingClass, charts) { selectedRatingClass?.let { ratingClass -> @@ -90,10 +88,9 @@ fun UtilitiesCalculatorScreen( Icon(painterResource(R.drawable.ic_rating_class), contentDescription = null) ArcaeaRatingClassSelector( + items = selectorItems, selectedRatingClass = selectedRatingClass, onRatingClassChange = { selectedRatingClass = it }, - enabledRatingClasses = enabledRatingClasses, - ratingDetails = ratingDetails, ) } } diff --git a/shared/src/commonMain/kotlin/xyz/sevive/arcaeaoffline/core/constants/ArcaeaRatingClassDisplay.kt b/shared/src/commonMain/kotlin/xyz/sevive/arcaeaoffline/core/constants/ArcaeaRatingClassDisplay.kt new file mode 100644 index 00000000..e19bdcb1 --- /dev/null +++ b/shared/src/commonMain/kotlin/xyz/sevive/arcaeaoffline/core/constants/ArcaeaRatingClassDisplay.kt @@ -0,0 +1,23 @@ +package xyz.sevive.arcaeaoffline.core.constants + +enum class ArcaeaRatingClassDisplay( + val ratingClass: ArcaeaRatingClass, + val alias: Int? = null, +) { + PAST(ArcaeaRatingClass.PAST), + PRESENT(ArcaeaRatingClass.PRESENT), + FUTURE(ArcaeaRatingClass.FUTURE), + BEYOND(ArcaeaRatingClass.BEYOND), + ETERNAL(ArcaeaRatingClass.ETERNAL), + INSCRIBED(ArcaeaRatingClass.BEYOND, alias = 1), + ; + + companion object { + fun of( + ratingClass: ArcaeaRatingClass, + alias: Int? = null, + ): ArcaeaRatingClassDisplay = + entries.find { it.ratingClass == ratingClass && it.alias == alias } + ?: entries.first { it.ratingClass == ratingClass && it.alias == null } + } +} diff --git a/shared/src/commonMain/kotlin/xyz/sevive/arcaeaoffline/ui/theme/ColorUtils.kt b/shared/src/commonMain/kotlin/xyz/sevive/arcaeaoffline/ui/theme/ColorUtils.kt index 892874ec..d6258885 100644 --- a/shared/src/commonMain/kotlin/xyz/sevive/arcaeaoffline/ui/theme/ColorUtils.kt +++ b/shared/src/commonMain/kotlin/xyz/sevive/arcaeaoffline/ui/theme/ColorUtils.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import xyz.sevive.arcaeaoffline.core.constants.ArcaeaRatingClass +import xyz.sevive.arcaeaoffline.core.constants.ArcaeaRatingClassDisplay @Composable fun ratingClassColor(ratingClass: ArcaeaRatingClass): Color = @@ -15,6 +16,13 @@ fun ratingClassColor(ratingClass: ArcaeaRatingClass): Color = ArcaeaRatingClass.ETERNAL -> LocalArcaeaColors.current.eternal } +@Composable +fun ratingClassColor(display: ArcaeaRatingClassDisplay): Color = + when (display) { + ArcaeaRatingClassDisplay.INSCRIBED -> LocalArcaeaColors.current.inscribed + else -> ratingClassColor(display.ratingClass) + } + @Composable fun playResultGradeGradientBrush(score: Int): Brush { val colors = diff --git a/shared/src/commonMain/kotlin/xyz/sevive/arcaeaoffline/ui/theme/CustomColors.kt b/shared/src/commonMain/kotlin/xyz/sevive/arcaeaoffline/ui/theme/CustomColors.kt index 6c07e0b3..4475cbad 100644 --- a/shared/src/commonMain/kotlin/xyz/sevive/arcaeaoffline/ui/theme/CustomColors.kt +++ b/shared/src/commonMain/kotlin/xyz/sevive/arcaeaoffline/ui/theme/CustomColors.kt @@ -36,6 +36,7 @@ data class ArcaeaColors( val past: Color = Color(0xFF5CBAD3), val present: Color = Color(0xFF829438), val future: Color = Color(0xFF913A79), + val inscribed: Color = Color(0xFF293885), val beyond: Color = Color(0xFFBF0D25), val eternal: Color = Color(0xFF8B77A4), val pure: Color = Color(0xFFF22EC6), @@ -50,6 +51,7 @@ data class ArcaeaColors( past = Color(0xFF5CBAD3), present = Color(0xFFB5C76F), future = Color(0xFFC56DAC), + inscribed = Color(0xFF5169C7), beyond = Color(0xFFF24058), eternal = Color(0xFFD3B5F9), ) From cfd7fdc21854ad4ecae055ec07dd796901c37090 Mon Sep 17 00:00:00 2001 From: 283375 Date: Sun, 30 Aug 2026 18:58:18 +0800 Subject: [PATCH 2/3] color and shadow optimization --- app/build.gradle.kts | 1 + .../components/ArcaeaRatingClassSelector.kt | 37 ++++--------------- gradle/libs.versions.toml | 4 ++ 3 files changed, 13 insertions(+), 29 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f4d63aea..83ce7f9e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -194,6 +194,7 @@ dependencies { implementation(libs.kermit) implementation(libs.bignum) implementation(libs.kim) + implementation(libs.materialkolor.color.utilities) implementation(libs.kotlinx.serialization) implementation(libs.ktoml.core) diff --git a/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaRatingClassSelector.kt b/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaRatingClassSelector.kt index 6ae27dba..71c51b81 100644 --- a/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaRatingClassSelector.kt +++ b/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaRatingClassSelector.kt @@ -44,13 +44,12 @@ import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.em -import androidx.core.graphics.ColorUtils +import com.materialkolor.hct.Hct import xyz.sevive.arcaeaoffline.core.constants.ArcaeaRatingClass import xyz.sevive.arcaeaoffline.core.constants.ArcaeaRatingClassDisplay import xyz.sevive.arcaeaoffline.core.database.entities.Chart import xyz.sevive.arcaeaoffline.ui.theme.ArcaeaOfflineTheme import xyz.sevive.arcaeaoffline.ui.theme.ratingClassColor -import kotlin.math.min @Immutable data class RatingClassSelectorItem( @@ -117,32 +116,12 @@ internal class RatingClassBoxColors( val disabledTextColor = Color(0xff9f9f9f) init { - val selectedTextHsl = floatArrayOf(0f, 0f, 0f) - ColorUtils.colorToHSL(baseColor.toArgb(), selectedTextHsl) + val hct = Hct.fromInt(baseColor.toArgb()) - selectedTextHsl[1] = min(1f, selectedTextHsl[1] + 0.1f) - selectedTextHsl[2] = 0.95f - selectedTextColor = Color(ColorUtils.HSLToColor(selectedTextHsl)) - - val selectedTextShadowHsl = floatArrayOf(0f, 0f, 0f) - ColorUtils.colorToHSL(baseColor.toArgb(), selectedTextShadowHsl) - - selectedTextShadowHsl[2] = 0.05f - selectedTextShadowColor = Color(ColorUtils.HSLToColor(selectedTextShadowHsl)) - - val notSelectedBgHsl = floatArrayOf(0f, 0f, 0f) - ColorUtils.colorToHSL(baseColor.toArgb(), notSelectedBgHsl) - - notSelectedBgHsl[1] = 0.015f - notSelectedBgHsl[2] = 0.6f - notSelectedBgColor = Color(ColorUtils.HSLToColor(notSelectedBgHsl)) - - val notSelectedTextHsl = floatArrayOf(0f, 0f, 0f) - ColorUtils.colorToHSL(baseColor.toArgb(), notSelectedTextHsl) - - notSelectedTextHsl[1] = 0f - notSelectedTextHsl[2] = 0.28f - notSelectedTextColor = Color(ColorUtils.HSLToColor(notSelectedTextHsl)) + selectedTextColor = Color(hct.withTone(98.0).toInt()) + selectedTextShadowColor = Color(hct.withTone(10.0).toInt()) + notSelectedBgColor = Color(Hct.from(hct.hue, 3.0, 60.0).toInt()) + notSelectedTextColor = Color(Hct.from(hct.hue, 0.0, 25.0).toInt()) } } @@ -211,11 +190,11 @@ internal fun RatingClassBox( label = "selectedTextShadowColor", ) val selectedTextShadowOffset by animateOffsetAsState( - targetValue = if (selected) Offset(3f, 3f) else Offset(0f, 0f), + targetValue = if (selected) Offset(2f, 2f) else Offset(0f, 0f), label = "selectedTextShadowOffset", ) val selectedTextShadowBlur by animateFloatAsState( - targetValue = if (selected) 5f else 0f, + targetValue = if (selected) 4f else 0f, label = "selectedTextShadowOffset", ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a95e5686..74b83782 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,6 +30,8 @@ kotlinx-io = "0.9.0" bignum = "0.3.10" kim = "0.31.0" +materialkolor = "5.0.1" + junit = "4.13.2" robolectric = "4.16.1" @@ -59,6 +61,8 @@ compose-ui-tooling = { module = "org.jetbrains.compose.ui:ui-tooling", version.r compose-ui-test = { module = "org.jetbrains.compose.ui:ui-test", version.ref = "compose-multiplatform" } compose-material-icons-extended = { module = "org.jetbrains.compose.material:material-icons-extended", version.ref = "compose-material-icons-extended" } +materialkolor-color-utilities = { module = "com.materialkolor:material-color-utilities", version.ref = "materialkolor" } + opencv = { module = "org.opencv:opencv", version.ref = "opencv" } apache-commons-compress = { module = "org.apache.commons:commons-compress", version.ref = "apache-commons-compress" } jSystemThemeDetector = { module = "com.github.Dansoftowner:jSystemThemeDetector", version = "3.9.1" } From 42776d1f46bf0700ebe41a6cbf39bd1597782dac Mon Sep 17 00:00:00 2001 From: 283375 Date: Thu, 3 Sep 2026 07:00:06 +0800 Subject: [PATCH 3/3] minor fixes --- .../ui/components/ArcaeaRatingClassSelector.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaRatingClassSelector.kt b/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaRatingClassSelector.kt index 71c51b81..c4b7d5ff 100644 --- a/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaRatingClassSelector.kt +++ b/app/src/main/java/xyz/sevive/arcaeaoffline/ui/components/ArcaeaRatingClassSelector.kt @@ -195,7 +195,7 @@ internal fun RatingClassBox( ) val selectedTextShadowBlur by animateFloatAsState( targetValue = if (selected) 4f else 0f, - label = "selectedTextShadowOffset", + label = "selectedTextShadowBlur", ) Box( @@ -358,7 +358,10 @@ private fun RatingClassSelectorDevicePreview() { itemsCommon + RatingClassSelectorItem(ArcaeaRatingClassDisplay.INSCRIBED, 11) - val itemsAll = itemsWithBeyond + itemsWithEternal.last() + val itemsAll = + itemsCommon + + RatingClassSelectorItem(ArcaeaRatingClassDisplay.BEYOND, 12) + + RatingClassSelectorItem(ArcaeaRatingClassDisplay.ETERNAL, 10, ratingPlus = true) ArcaeaOfflineTheme { Surface {