feat: update colour picker sheet for material 3; shader checkerboard

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2024-10-26 17:15:30 +02:00
parent 5cb9df731b
commit b37f7c1c9c
1 changed files with 140 additions and 64 deletions

View File

@ -1,5 +1,7 @@
package chat.revolt.sheets package chat.revolt.sheets
import android.graphics.RuntimeShader
import android.os.Build
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.Canvas import androidx.compose.foundation.Canvas
@ -36,6 +38,7 @@ import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.Slider import androidx.compose.material3.Slider
import androidx.compose.material3.SliderDefaults import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.SliderState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -47,15 +50,20 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.onFocusChanged 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.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape 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.graphics.toArgb
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import chat.revolt.R import chat.revolt.R
import chat.revolt.internals.TailwindColourScheme import chat.revolt.internals.TailwindColourScheme
import org.intellij.lang.annotations.Language
enum class ColourPickerMode { enum class ColourPickerMode {
Sliders, Sliders,
@ -83,6 +91,21 @@ private fun Color.asHsv(): Triple<Float, Float, Float> {
return Triple(hue, saturation, max) 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 { private fun Color.asHexString(): String {
val alpha = (alpha * 255).toInt() val alpha = (alpha * 255).toInt()
val red = (red * 255).toInt() val red = (red * 255).toInt()
@ -226,6 +249,21 @@ val palette = listOf(
TailwindColourScheme.rose[10], 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) @OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
@Composable @Composable
fun ColumnScope.ColourPickerSheet( fun ColumnScope.ColourPickerSheet(
@ -245,6 +283,20 @@ fun ColumnScope.ColourPickerSheet(
val colorHsv by remember(color) { derivedStateOf { color.asHsv() } } 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( Column(
Modifier Modifier
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
@ -322,18 +374,22 @@ fun ColumnScope.ColourPickerSheet(
1f 1f
) )
), ),
track = { track = { state ->
Canvas( with(MaterialTheme.colorScheme) {
Modifier Canvas(
.fillMaxWidth() Modifier
.height(4.dp) .fillMaxWidth()
) { .height(16.dp)
drawRect( ) {
Brush.horizontalGradient( drawRoundRect(
hueTrackColours, Brush.horizontalGradient(
endX = size.width hueTrackColours,
endX = size.width
),
cornerRadius = CornerRadius(999f, 999f)
) )
) drawThumbMargin(surfaceContainerLow, state)
}
} }
} }
) )
@ -370,29 +426,33 @@ fun ColumnScope.ColourPickerSheet(
1f 1f
) )
), ),
track = { track = { state ->
Canvas( with(MaterialTheme.colorScheme) {
Modifier Canvas(
.fillMaxWidth() Modifier
.height(4.dp) .fillMaxWidth()
) { .height(16.dp)
drawRect( ) {
Brush.horizontalGradient( drawRoundRect(
listOf( Brush.horizontalGradient(
Color.hsv( listOf(
colorHsv.first, Color.hsv(
0f, colorHsv.first,
1f 0f,
1f
),
Color.hsv(
colorHsv.first,
1f,
1f
)
), ),
Color.hsv( endX = size.width
colorHsv.first,
1f,
1f
)
), ),
endX = size.width cornerRadius = CornerRadius(999f, 999f)
) )
) drawThumbMargin(surfaceContainerLow, state)
}
} }
} }
) )
@ -429,29 +489,33 @@ fun ColumnScope.ColourPickerSheet(
colorHsv.third colorHsv.third
) )
), ),
track = { track = { state ->
Canvas( with(MaterialTheme.colorScheme) {
Modifier Canvas(
.fillMaxWidth() Modifier
.height(4.dp) .fillMaxWidth()
) { .height(16.dp)
drawRect( ) {
Brush.horizontalGradient( drawRoundRect(
listOf( Brush.horizontalGradient(
Color.hsv( listOf(
colorHsv.first, Color.hsv(
colorHsv.second, colorHsv.first,
0f colorHsv.second,
0f
),
Color.hsv(
colorHsv.first,
colorHsv.second,
1f
)
), ),
Color.hsv( endX = size.width
colorHsv.first,
colorHsv.second,
1f
)
), ),
endX = size.width cornerRadius = CornerRadius(999f, 999f)
) )
) drawThumbMargin(surfaceContainerLow, state)
}
} }
} }
) )
@ -481,21 +545,33 @@ fun ColumnScope.ColourPickerSheet(
colors = SliderDefaults.colors().copy( colors = SliderDefaults.colors().copy(
thumbColor = color thumbColor = color
), ),
track = { track = { state ->
Canvas( with(MaterialTheme.colorScheme) {
Modifier Canvas(
.fillMaxWidth() Modifier
.height(4.dp) .fillMaxWidth()
) { .height(16.dp)
drawRect( ) {
Brush.horizontalGradient( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
listOf( checkerboardShader?.let { shader ->
color.copy(alpha = 0f), drawRoundRect(
color.copy(alpha = 1f) 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)
}
} }
} }
) )