From b37f7c1c9c9528601b32946da65712b8f15c7117 Mon Sep 17 00:00:00 2001 From: Infi Date: Sat, 26 Oct 2024 17:15:30 +0200 Subject: [PATCH] feat: update colour picker sheet for material 3; shader checkerboard Signed-off-by: Infi --- .../chat/revolt/sheets/ColourPickerSheet.kt | 204 ++++++++++++------ 1 file changed, 140 insertions(+), 64 deletions(-) diff --git a/app/src/main/java/chat/revolt/sheets/ColourPickerSheet.kt b/app/src/main/java/chat/revolt/sheets/ColourPickerSheet.kt index f7fd18b9..0449fc3e 100644 --- a/app/src/main/java/chat/revolt/sheets/ColourPickerSheet.kt +++ b/app/src/main/java/chat/revolt/sheets/ColourPickerSheet.kt @@ -1,5 +1,7 @@ package chat.revolt.sheets +import android.graphics.RuntimeShader +import android.os.Build import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.Canvas @@ -36,6 +38,7 @@ import androidx.compose.material3.SegmentedButton import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.material3.Slider import androidx.compose.material3.SliderDefaults +import androidx.compose.material3.SliderState import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -47,15 +50,20 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.ShaderBrush +import androidx.compose.ui.graphics.drawscope.DrawScope import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import chat.revolt.R import chat.revolt.internals.TailwindColourScheme +import org.intellij.lang.annotations.Language enum class ColourPickerMode { Sliders, @@ -83,6 +91,21 @@ private fun Color.asHsv(): Triple { return Triple(hue, saturation, max) } +@OptIn(ExperimentalMaterial3Api::class) +private fun DrawScope.drawThumbMargin( + color: Color, + sliderState: SliderState +) { + // Area around the thumb to mimic material3 track + val thumbOutlineXBase = + (sliderState.value / sliderState.valueRange.endInclusive) * size.width + drawRect( + color, + topLeft = Offset(thumbOutlineXBase - 8.dp.toPx(), 0f), + size = androidx.compose.ui.geometry.Size(16.dp.toPx(), size.height) + ) +} + private fun Color.asHexString(): String { val alpha = (alpha * 255).toInt() val red = (red * 255).toInt() @@ -226,6 +249,21 @@ val palette = listOf( TailwindColourScheme.rose[10], ) +@Language("AGSL") +const val CheckerboardShader = """ +layout(color) uniform vec4 color1; +layout(color) uniform vec4 color2; +uniform float squareSize; + +vec4 main(vec2 fragCoord) { + // add 4 to make it less boring + float x = floor((fragCoord.x + 4) / squareSize); + float y = floor((fragCoord.y + 4) / squareSize); + + return mod(x + y, 2.0) == 0.0 ? color1 : color2; +} +""" + @OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class) @Composable fun ColumnScope.ColourPickerSheet( @@ -245,6 +283,20 @@ fun ColumnScope.ColourPickerSheet( val colorHsv by remember(color) { derivedStateOf { color.asHsv() } } + val checkerboardShader = with(MaterialTheme.colorScheme) { + remember { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + RuntimeShader(CheckerboardShader).apply { + setFloatUniform("squareSize", 8f) + setColorUniform("color1", surface.toArgb()) + setColorUniform("color2", surfaceVariant.toArgb()) + } + } else { + null + } + } + } + Column( Modifier .verticalScroll(rememberScrollState()) @@ -322,18 +374,22 @@ fun ColumnScope.ColourPickerSheet( 1f ) ), - track = { - Canvas( - Modifier - .fillMaxWidth() - .height(4.dp) - ) { - drawRect( - Brush.horizontalGradient( - hueTrackColours, - endX = size.width + track = { state -> + with(MaterialTheme.colorScheme) { + Canvas( + Modifier + .fillMaxWidth() + .height(16.dp) + ) { + drawRoundRect( + Brush.horizontalGradient( + hueTrackColours, + endX = size.width + ), + cornerRadius = CornerRadius(999f, 999f) ) - ) + drawThumbMargin(surfaceContainerLow, state) + } } } ) @@ -370,29 +426,33 @@ fun ColumnScope.ColourPickerSheet( 1f ) ), - track = { - Canvas( - Modifier - .fillMaxWidth() - .height(4.dp) - ) { - drawRect( - Brush.horizontalGradient( - listOf( - Color.hsv( - colorHsv.first, - 0f, - 1f + track = { state -> + with(MaterialTheme.colorScheme) { + Canvas( + Modifier + .fillMaxWidth() + .height(16.dp) + ) { + drawRoundRect( + Brush.horizontalGradient( + listOf( + Color.hsv( + colorHsv.first, + 0f, + 1f + ), + Color.hsv( + colorHsv.first, + 1f, + 1f + ) ), - Color.hsv( - colorHsv.first, - 1f, - 1f - ) + endX = size.width ), - endX = size.width + cornerRadius = CornerRadius(999f, 999f) ) - ) + drawThumbMargin(surfaceContainerLow, state) + } } } ) @@ -429,29 +489,33 @@ fun ColumnScope.ColourPickerSheet( colorHsv.third ) ), - track = { - Canvas( - Modifier - .fillMaxWidth() - .height(4.dp) - ) { - drawRect( - Brush.horizontalGradient( - listOf( - Color.hsv( - colorHsv.first, - colorHsv.second, - 0f + track = { state -> + with(MaterialTheme.colorScheme) { + Canvas( + Modifier + .fillMaxWidth() + .height(16.dp) + ) { + drawRoundRect( + Brush.horizontalGradient( + listOf( + Color.hsv( + colorHsv.first, + colorHsv.second, + 0f + ), + Color.hsv( + colorHsv.first, + colorHsv.second, + 1f + ) ), - Color.hsv( - colorHsv.first, - colorHsv.second, - 1f - ) + endX = size.width ), - endX = size.width + cornerRadius = CornerRadius(999f, 999f) ) - ) + drawThumbMargin(surfaceContainerLow, state) + } } } ) @@ -481,21 +545,33 @@ fun ColumnScope.ColourPickerSheet( colors = SliderDefaults.colors().copy( thumbColor = color ), - track = { - Canvas( - Modifier - .fillMaxWidth() - .height(4.dp) - ) { - drawRect( - Brush.horizontalGradient( - listOf( - color.copy(alpha = 0f), - color.copy(alpha = 1f) + track = { state -> + with(MaterialTheme.colorScheme) { + Canvas( + Modifier + .fillMaxWidth() + .height(16.dp) + ) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + checkerboardShader?.let { shader -> + drawRoundRect( + ShaderBrush(shader), + cornerRadius = CornerRadius(999f, 999f) + ) + } + } + drawRoundRect( + Brush.horizontalGradient( + listOf( + color.copy(alpha = 0f), + color.copy(alpha = 1f) + ), + endX = size.width ), - endX = size.width + cornerRadius = CornerRadius(999f, 999f) ) - ) + drawThumbMargin(surfaceContainerLow, state) + } } } )