2022-03-08 11:05:03 -08:00
|
|
|
package co.electriccoin.zcash.ui.design.component
|
2021-10-31 10:36:51 -07:00
|
|
|
|
2023-10-10 03:41:17 -07:00
|
|
|
import androidx.compose.animation.core.animateFloatAsState
|
|
|
|
import androidx.compose.animation.core.tween
|
2023-09-04 02:05:26 -07:00
|
|
|
import androidx.compose.foundation.border
|
2023-10-10 03:41:17 -07:00
|
|
|
import androidx.compose.foundation.gestures.awaitFirstDown
|
|
|
|
import androidx.compose.foundation.gestures.waitForUpOrCancellation
|
2022-01-13 09:49:08 -08:00
|
|
|
import androidx.compose.foundation.layout.Column
|
2023-04-04 05:21:18 -07:00
|
|
|
import androidx.compose.foundation.layout.PaddingValues
|
2023-09-04 02:05:26 -07:00
|
|
|
import androidx.compose.foundation.layout.defaultMinSize
|
2021-10-31 10:36:51 -07:00
|
|
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
|
|
import androidx.compose.foundation.layout.padding
|
2022-02-21 06:33:40 -08:00
|
|
|
import androidx.compose.material3.Button
|
|
|
|
import androidx.compose.material3.ButtonDefaults
|
|
|
|
import androidx.compose.material3.ButtonDefaults.buttonColors
|
|
|
|
import androidx.compose.material3.MaterialTheme
|
|
|
|
import androidx.compose.material3.Text
|
2021-10-31 10:36:51 -07:00
|
|
|
import androidx.compose.runtime.Composable
|
2023-10-10 03:41:17 -07:00
|
|
|
import androidx.compose.runtime.getValue
|
|
|
|
import androidx.compose.runtime.mutableStateOf
|
|
|
|
import androidx.compose.runtime.remember
|
|
|
|
import androidx.compose.runtime.setValue
|
2021-10-31 10:36:51 -07:00
|
|
|
import androidx.compose.ui.Modifier
|
2023-10-10 03:41:17 -07:00
|
|
|
import androidx.compose.ui.composed
|
2023-09-04 02:05:26 -07:00
|
|
|
import androidx.compose.ui.draw.drawBehind
|
|
|
|
import androidx.compose.ui.graphics.Color
|
|
|
|
import androidx.compose.ui.graphics.Paint
|
|
|
|
import androidx.compose.ui.graphics.PaintingStyle
|
2023-08-04 04:01:16 -07:00
|
|
|
import androidx.compose.ui.graphics.RectangleShape
|
2023-09-04 02:05:26 -07:00
|
|
|
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
2023-10-10 03:41:17 -07:00
|
|
|
import androidx.compose.ui.graphics.graphicsLayer
|
2023-09-04 02:05:26 -07:00
|
|
|
import androidx.compose.ui.graphics.toArgb
|
2023-10-10 03:41:17 -07:00
|
|
|
import androidx.compose.ui.input.pointer.pointerInput
|
2023-09-28 05:17:21 -07:00
|
|
|
import androidx.compose.ui.text.style.TextAlign
|
2022-01-13 09:49:08 -08:00
|
|
|
import androidx.compose.ui.tooling.preview.Preview
|
2023-09-04 02:05:26 -07:00
|
|
|
import androidx.compose.ui.unit.Dp
|
2021-10-31 10:36:51 -07:00
|
|
|
import androidx.compose.ui.unit.dp
|
2022-03-08 11:05:03 -08:00
|
|
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
2021-10-31 10:36:51 -07:00
|
|
|
|
2022-01-13 09:49:08 -08:00
|
|
|
@Preview
|
|
|
|
@Composable
|
2023-06-18 23:59:00 -07:00
|
|
|
private fun ButtonComposablePreview() {
|
2023-10-19 06:00:47 -07:00
|
|
|
ZcashTheme(forceDarkMode = false) {
|
2022-01-13 09:49:08 -08:00
|
|
|
GradientSurface {
|
|
|
|
Column {
|
|
|
|
PrimaryButton(onClick = { }, text = "Primary")
|
|
|
|
SecondaryButton(onClick = { }, text = "Secondary")
|
|
|
|
TertiaryButton(onClick = { }, text = "Tertiary")
|
|
|
|
NavigationButton(onClick = { }, text = "Navigation")
|
2023-09-04 02:05:26 -07:00
|
|
|
DangerousButton(onClick = { }, text = "Dangerous")
|
2022-01-13 09:49:08 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-31 10:36:51 -07:00
|
|
|
@Composable
|
2023-10-12 10:04:23 -07:00
|
|
|
@Suppress("LongParameterList")
|
2021-10-31 10:36:51 -07:00
|
|
|
fun PrimaryButton(
|
|
|
|
onClick: () -> Unit,
|
|
|
|
text: String,
|
2022-02-17 05:08:06 -08:00
|
|
|
modifier: Modifier = Modifier,
|
2023-12-11 01:20:32 -08:00
|
|
|
outerPaddingValues: PaddingValues =
|
|
|
|
PaddingValues(
|
|
|
|
horizontal = ZcashTheme.dimens.spacingNone,
|
|
|
|
vertical = ZcashTheme.dimens.spacingSmall
|
|
|
|
),
|
2023-09-04 02:05:26 -07:00
|
|
|
enabled: Boolean = true,
|
|
|
|
buttonColor: Color = MaterialTheme.colorScheme.primary,
|
|
|
|
textColor: Color = MaterialTheme.colorScheme.onPrimary,
|
2021-10-31 10:36:51 -07:00
|
|
|
) {
|
|
|
|
Button(
|
2023-08-04 04:01:16 -07:00
|
|
|
shape = RectangleShape,
|
2022-02-17 05:08:06 -08:00
|
|
|
enabled = enabled,
|
2023-12-11 01:20:32 -08:00
|
|
|
modifier =
|
|
|
|
modifier.then(Modifier.fillMaxWidth())
|
|
|
|
.padding(outerPaddingValues)
|
|
|
|
.shadow(
|
|
|
|
contentColor = textColor,
|
|
|
|
strokeColor = buttonColor,
|
|
|
|
strokeWidth = 1.dp,
|
|
|
|
offsetX = ZcashTheme.dimens.buttonShadowOffsetX,
|
|
|
|
offsetY = ZcashTheme.dimens.buttonShadowOffsetY,
|
|
|
|
spread = ZcashTheme.dimens.buttonShadowSpread,
|
|
|
|
)
|
|
|
|
.translationClick(
|
|
|
|
// + 6dp to exactly cover the bottom shadow
|
|
|
|
translationX = ZcashTheme.dimens.buttonShadowOffsetX + 6.dp,
|
|
|
|
translationY = ZcashTheme.dimens.buttonShadowOffsetX + 6.dp
|
|
|
|
)
|
|
|
|
.defaultMinSize(ZcashTheme.dimens.buttonWidth, ZcashTheme.dimens.buttonHeight)
|
|
|
|
.border(1.dp, Color.Black),
|
|
|
|
colors =
|
|
|
|
buttonColors(
|
|
|
|
containerColor = buttonColor,
|
|
|
|
disabledContainerColor = ZcashTheme.colors.disabledButtonColor,
|
|
|
|
disabledContentColor = ZcashTheme.colors.disabledButtonTextColor
|
|
|
|
),
|
2023-09-04 02:05:26 -07:00
|
|
|
onClick = onClick,
|
2021-10-31 10:36:51 -07:00
|
|
|
) {
|
2023-09-28 05:17:21 -07:00
|
|
|
Text(
|
|
|
|
style = ZcashTheme.extendedTypography.buttonText,
|
|
|
|
textAlign = TextAlign.Center,
|
|
|
|
text = text.uppercase(),
|
|
|
|
color = textColor
|
|
|
|
)
|
2021-10-31 10:36:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Composable
|
2023-10-12 10:04:23 -07:00
|
|
|
@Suppress("LongParameterList")
|
2021-10-31 10:36:51 -07:00
|
|
|
fun SecondaryButton(
|
|
|
|
onClick: () -> Unit,
|
|
|
|
text: String,
|
2022-05-16 04:40:50 -07:00
|
|
|
modifier: Modifier = Modifier,
|
2023-12-11 01:20:32 -08:00
|
|
|
outerPaddingValues: PaddingValues =
|
|
|
|
PaddingValues(
|
|
|
|
horizontal = ZcashTheme.dimens.spacingNone,
|
|
|
|
vertical = ZcashTheme.dimens.spacingSmall
|
|
|
|
),
|
2023-10-12 10:04:23 -07:00
|
|
|
enabled: Boolean = true,
|
|
|
|
buttonColor: Color = MaterialTheme.colorScheme.secondary,
|
|
|
|
textColor: Color = MaterialTheme.colorScheme.onSecondary,
|
2021-10-31 10:36:51 -07:00
|
|
|
) {
|
|
|
|
Button(
|
2023-08-04 04:01:16 -07:00
|
|
|
shape = RectangleShape,
|
2022-05-16 04:40:50 -07:00
|
|
|
enabled = enabled,
|
2023-12-11 01:20:32 -08:00
|
|
|
modifier =
|
|
|
|
modifier.then(Modifier.fillMaxWidth())
|
|
|
|
.padding(outerPaddingValues)
|
|
|
|
.shadow(
|
|
|
|
contentColor = textColor,
|
|
|
|
strokeColor = textColor,
|
|
|
|
offsetX = ZcashTheme.dimens.buttonShadowOffsetX,
|
|
|
|
offsetY = ZcashTheme.dimens.buttonShadowOffsetY,
|
|
|
|
spread = ZcashTheme.dimens.buttonShadowSpread,
|
|
|
|
)
|
|
|
|
.translationClick(
|
|
|
|
// + 6dp to exactly cover the bottom shadow
|
|
|
|
translationX = ZcashTheme.dimens.buttonShadowOffsetX + 6.dp,
|
|
|
|
translationY = ZcashTheme.dimens.buttonShadowOffsetX + 6.dp
|
|
|
|
)
|
|
|
|
.defaultMinSize(ZcashTheme.dimens.buttonWidth, ZcashTheme.dimens.buttonHeight)
|
|
|
|
.border(1.dp, Color.Black),
|
|
|
|
colors =
|
|
|
|
buttonColors(
|
|
|
|
containerColor = buttonColor,
|
|
|
|
disabledContainerColor = ZcashTheme.colors.disabledButtonColor,
|
|
|
|
disabledContentColor = ZcashTheme.colors.disabledButtonTextColor
|
|
|
|
),
|
2023-10-12 10:04:23 -07:00
|
|
|
onClick = onClick,
|
2021-10-31 10:36:51 -07:00
|
|
|
) {
|
2022-02-21 06:33:40 -08:00
|
|
|
Text(
|
2023-10-12 10:04:23 -07:00
|
|
|
style = ZcashTheme.extendedTypography.buttonText,
|
2023-09-28 05:17:21 -07:00
|
|
|
textAlign = TextAlign.Center,
|
|
|
|
text = text.uppercase(),
|
2023-10-12 10:04:23 -07:00
|
|
|
color = textColor
|
2022-02-21 06:33:40 -08:00
|
|
|
)
|
2021-10-31 10:36:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
fun NavigationButton(
|
|
|
|
onClick: () -> Unit,
|
|
|
|
text: String,
|
2023-04-04 05:21:18 -07:00
|
|
|
modifier: Modifier = Modifier,
|
2023-12-11 01:20:32 -08:00
|
|
|
outerPaddingValues: PaddingValues =
|
|
|
|
PaddingValues(
|
|
|
|
horizontal = ZcashTheme.dimens.spacingDefault,
|
|
|
|
vertical = ZcashTheme.dimens.spacingSmall
|
|
|
|
),
|
2021-10-31 10:36:51 -07:00
|
|
|
) {
|
|
|
|
Button(
|
2023-08-04 04:01:16 -07:00
|
|
|
shape = RectangleShape,
|
2021-10-31 10:36:51 -07:00
|
|
|
onClick = onClick,
|
2023-12-11 01:20:32 -08:00
|
|
|
modifier =
|
|
|
|
modifier.then(
|
|
|
|
Modifier
|
|
|
|
.padding(outerPaddingValues)
|
|
|
|
),
|
2022-02-21 06:33:40 -08:00
|
|
|
colors = buttonColors(containerColor = MaterialTheme.colorScheme.secondary)
|
2021-10-31 10:36:51 -07:00
|
|
|
) {
|
2023-09-28 05:17:21 -07:00
|
|
|
Text(
|
|
|
|
style = MaterialTheme.typography.labelLarge,
|
|
|
|
textAlign = TextAlign.Center,
|
|
|
|
text = text,
|
|
|
|
color = MaterialTheme.colorScheme.onSecondary
|
|
|
|
)
|
2021-10-31 10:36:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
fun TertiaryButton(
|
|
|
|
onClick: () -> Unit,
|
|
|
|
text: String,
|
2022-05-16 04:40:50 -07:00
|
|
|
modifier: Modifier = Modifier,
|
2023-12-11 01:20:32 -08:00
|
|
|
outerPaddingValues: PaddingValues =
|
|
|
|
PaddingValues(
|
|
|
|
horizontal = ZcashTheme.dimens.spacingDefault,
|
|
|
|
vertical = ZcashTheme.dimens.spacingSmall
|
|
|
|
),
|
2022-05-16 04:40:50 -07:00
|
|
|
enabled: Boolean = true
|
2021-10-31 10:36:51 -07:00
|
|
|
) {
|
|
|
|
Button(
|
2023-08-04 04:01:16 -07:00
|
|
|
shape = RectangleShape,
|
2021-10-31 10:36:51 -07:00
|
|
|
onClick = onClick,
|
2023-12-11 01:20:32 -08:00
|
|
|
modifier =
|
|
|
|
modifier.then(
|
|
|
|
Modifier
|
|
|
|
.fillMaxWidth()
|
|
|
|
.padding(outerPaddingValues)
|
|
|
|
),
|
2022-05-16 04:40:50 -07:00
|
|
|
enabled = enabled,
|
2022-02-21 06:33:40 -08:00
|
|
|
elevation = ButtonDefaults.buttonElevation(0.dp, 0.dp, 0.dp),
|
|
|
|
colors = buttonColors(containerColor = ZcashTheme.colors.tertiary)
|
2021-10-31 10:36:51 -07:00
|
|
|
) {
|
2022-02-21 06:33:40 -08:00
|
|
|
Text(
|
|
|
|
style = MaterialTheme.typography.labelLarge,
|
2023-09-28 05:17:21 -07:00
|
|
|
textAlign = TextAlign.Center,
|
2022-02-21 06:33:40 -08:00
|
|
|
text = text,
|
|
|
|
color = ZcashTheme.colors.onTertiary
|
|
|
|
)
|
2021-10-31 10:36:51 -07:00
|
|
|
}
|
|
|
|
}
|
2022-01-26 13:33:02 -08:00
|
|
|
|
|
|
|
@Composable
|
|
|
|
fun DangerousButton(
|
|
|
|
onClick: () -> Unit,
|
|
|
|
text: String,
|
2023-04-04 05:21:18 -07:00
|
|
|
modifier: Modifier = Modifier,
|
2023-12-11 01:20:32 -08:00
|
|
|
outerPaddingValues: PaddingValues =
|
|
|
|
PaddingValues(
|
|
|
|
horizontal = ZcashTheme.dimens.spacingDefault,
|
|
|
|
vertical = ZcashTheme.dimens.spacingSmall
|
|
|
|
),
|
2022-01-26 13:33:02 -08:00
|
|
|
) {
|
|
|
|
Button(
|
2023-08-04 04:01:16 -07:00
|
|
|
shape = RectangleShape,
|
2022-01-26 13:33:02 -08:00
|
|
|
onClick = onClick,
|
2023-12-11 01:20:32 -08:00
|
|
|
modifier =
|
|
|
|
modifier.then(
|
|
|
|
Modifier
|
|
|
|
.fillMaxWidth()
|
|
|
|
.padding(outerPaddingValues)
|
|
|
|
),
|
2022-02-21 06:33:40 -08:00
|
|
|
colors = buttonColors(containerColor = ZcashTheme.colors.dangerous)
|
2022-01-26 13:33:02 -08:00
|
|
|
) {
|
2022-02-21 06:33:40 -08:00
|
|
|
Text(
|
|
|
|
style = MaterialTheme.typography.labelLarge,
|
2023-09-28 05:17:21 -07:00
|
|
|
textAlign = TextAlign.Center,
|
2022-02-21 06:33:40 -08:00
|
|
|
text = text,
|
|
|
|
color = ZcashTheme.colors.onDangerous
|
|
|
|
)
|
2022-01-26 13:33:02 -08:00
|
|
|
}
|
|
|
|
}
|
2023-09-04 02:05:26 -07:00
|
|
|
|
|
|
|
@Suppress("LongParameterList")
|
|
|
|
fun Modifier.shadow(
|
2023-11-14 07:00:00 -08:00
|
|
|
contentColor: Color = Color.Black,
|
|
|
|
strokeColor: Color = Color.Black,
|
|
|
|
strokeWidth: Dp = 2.dp,
|
2023-09-04 02:05:26 -07:00
|
|
|
offsetY: Dp = 0.dp,
|
|
|
|
offsetX: Dp = 0.dp,
|
|
|
|
spread: Dp = 0f.dp,
|
|
|
|
modifier: Modifier = Modifier
|
|
|
|
) = this.then(
|
|
|
|
modifier.drawBehind {
|
|
|
|
this.drawIntoCanvas {
|
2023-11-14 07:00:00 -08:00
|
|
|
val strokePaint = Paint()
|
|
|
|
strokePaint.style = PaintingStyle.Stroke
|
|
|
|
strokePaint.strokeWidth = strokeWidth.toPx()
|
|
|
|
|
|
|
|
val contentPaint = Paint()
|
|
|
|
strokePaint.style = PaintingStyle.Fill
|
2023-09-04 02:05:26 -07:00
|
|
|
|
2023-11-14 07:00:00 -08:00
|
|
|
// Reusable inner function to be able to reach modifier and canvas properties
|
|
|
|
fun drawShadowLayer(
|
|
|
|
paint: Paint,
|
|
|
|
color: Color,
|
|
|
|
paddingWidth: Float
|
|
|
|
) {
|
|
|
|
val frameworkPaint = paint.asFrameworkPaint()
|
|
|
|
val spreadPixel = spread.toPx()
|
|
|
|
val leftPixel = (0f - spreadPixel) + offsetX.toPx()
|
|
|
|
val topPixel = (0f - spreadPixel) + offsetY.toPx()
|
|
|
|
val rightPixel = (this.size.width + spreadPixel)
|
|
|
|
val bottomPixel = (this.size.height + spreadPixel)
|
|
|
|
|
|
|
|
frameworkPaint.color = color.toArgb()
|
|
|
|
it.drawRoundRect(
|
|
|
|
left = leftPixel + paddingWidth,
|
|
|
|
top = topPixel + paddingWidth,
|
|
|
|
right = rightPixel - paddingWidth,
|
|
|
|
bottom = bottomPixel - paddingWidth,
|
|
|
|
radiusX = 0f,
|
|
|
|
radiusY = 0f,
|
|
|
|
paint
|
|
|
|
)
|
2023-09-04 02:05:26 -07:00
|
|
|
}
|
|
|
|
|
2023-11-14 07:00:00 -08:00
|
|
|
// Draw stroke and then content paints
|
|
|
|
drawShadowLayer(strokePaint, strokeColor, 0f)
|
|
|
|
drawShadowLayer(contentPaint, contentColor, strokeWidth.toPx())
|
2023-09-04 02:05:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2023-10-10 03:41:17 -07:00
|
|
|
|
|
|
|
private enum class ButtonState { Pressed, Idle }
|
2023-12-11 01:20:32 -08:00
|
|
|
|
2023-10-10 03:41:17 -07:00
|
|
|
fun Modifier.translationClick(
|
|
|
|
translationX: Dp = 0.dp,
|
|
|
|
translationY: Dp = 0.dp
|
|
|
|
) = composed {
|
|
|
|
var buttonState by remember { mutableStateOf(ButtonState.Idle) }
|
|
|
|
|
|
|
|
val translationXAnimated by animateFloatAsState(
|
2023-12-11 01:20:32 -08:00
|
|
|
targetValue =
|
|
|
|
if (buttonState == ButtonState.Pressed) {
|
|
|
|
translationX.value
|
|
|
|
} else {
|
|
|
|
0f
|
|
|
|
},
|
2023-10-10 03:41:17 -07:00
|
|
|
label = "ClickTranslationXAnimation",
|
2023-12-11 01:20:32 -08:00
|
|
|
animationSpec =
|
|
|
|
tween(
|
|
|
|
durationMillis = 100
|
|
|
|
)
|
2023-10-10 03:41:17 -07:00
|
|
|
)
|
|
|
|
val translationYAnimated by animateFloatAsState(
|
2023-12-11 01:20:32 -08:00
|
|
|
targetValue =
|
|
|
|
if (buttonState == ButtonState.Pressed) {
|
|
|
|
translationY.value
|
|
|
|
} else {
|
|
|
|
0f
|
|
|
|
},
|
2023-10-10 03:41:17 -07:00
|
|
|
label = "ClickTranslationYAnimation",
|
2023-12-11 01:20:32 -08:00
|
|
|
animationSpec =
|
|
|
|
tween(
|
|
|
|
durationMillis = 100
|
|
|
|
)
|
2023-10-10 03:41:17 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
this
|
|
|
|
.graphicsLayer {
|
|
|
|
this.translationX = translationXAnimated
|
|
|
|
this.translationY = translationYAnimated
|
|
|
|
}
|
|
|
|
.pointerInput(buttonState) {
|
|
|
|
awaitPointerEventScope {
|
2023-12-11 01:20:32 -08:00
|
|
|
buttonState =
|
|
|
|
if (buttonState == ButtonState.Pressed) {
|
|
|
|
waitForUpOrCancellation()
|
|
|
|
ButtonState.Idle
|
|
|
|
} else {
|
|
|
|
awaitFirstDown(false)
|
|
|
|
ButtonState.Pressed
|
|
|
|
}
|
2023-10-10 03:41:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|