-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(POM-274): Composable button (#128)
- Loading branch information
1 parent
0b7c139
commit bfaf6ee
Showing
24 changed files
with
772 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
plugins { | ||
id 'com.android.library' | ||
id 'org.jetbrains.kotlin.android' | ||
id 'kotlin-parcelize' | ||
} | ||
|
||
android { | ||
|
20 changes: 20 additions & 0 deletions
20
ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POBorderStroke.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.processout.sdk.ui.core.component | ||
|
||
import androidx.compose.foundation.BorderStroke | ||
import androidx.compose.runtime.Immutable | ||
import androidx.compose.ui.graphics.Color | ||
import androidx.compose.ui.unit.Dp | ||
import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi | ||
|
||
/** @suppress */ | ||
@ProcessOutInternalApi | ||
@Immutable | ||
data class POBorderStroke( | ||
val width: Dp, | ||
val color: Color | ||
) | ||
|
||
internal fun POBorderStroke.solid( | ||
width: Dp = this.width, | ||
color: Color = this.color | ||
) = BorderStroke(width = width, color = color) |
267 changes: 267 additions & 0 deletions
267
ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POButton.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,267 @@ | ||
@file:Suppress("MemberVisibilityCanBePrivate") | ||
|
||
package com.processout.sdk.ui.core.component | ||
|
||
import androidx.compose.foundation.BorderStroke | ||
import androidx.compose.foundation.interaction.MutableInteractionSource | ||
import androidx.compose.foundation.interaction.collectIsPressedAsState | ||
import androidx.compose.foundation.layout.PaddingValues | ||
import androidx.compose.foundation.layout.defaultMinSize | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.shape.RoundedCornerShape | ||
import androidx.compose.material3.Button | ||
import androidx.compose.material3.ButtonColors | ||
import androidx.compose.material3.ButtonDefaults | ||
import androidx.compose.material3.ButtonElevation | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.Immutable | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.graphics.Color | ||
import androidx.compose.ui.graphics.Shape | ||
import androidx.compose.ui.res.colorResource | ||
import androidx.compose.ui.text.style.TextOverflow | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.compose.ui.unit.Dp | ||
import androidx.compose.ui.unit.dp | ||
import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi | ||
import com.processout.sdk.ui.core.style.button.POButtonDefaults | ||
import com.processout.sdk.ui.core.style.button.POButtonStateStyle | ||
import com.processout.sdk.ui.core.style.button.POButtonStyle | ||
import com.processout.sdk.ui.core.theme.ProcessOutTheme | ||
|
||
/** @suppress */ | ||
@ProcessOutInternalApi | ||
object POButton { | ||
|
||
@Composable | ||
operator fun invoke( | ||
text: String, | ||
onClick: () -> Unit, | ||
modifier: Modifier = Modifier, | ||
style: Style = primary, | ||
enabled: Boolean = true, | ||
loading: Boolean = false, | ||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() } | ||
) { | ||
val pressed by interactionSource.collectIsPressedAsState() | ||
Button( | ||
onClick = onClick, | ||
modifier = modifier.defaultMinSize(minHeight = ProcessOutTheme.dimensions.formComponentHeight), | ||
enabled = enabled && !loading, | ||
colors = colors(enabled = enabled, loading = loading, pressed = pressed, style = style), | ||
shape = if (enabled) style.normal.shape else style.disabled.shape, | ||
border = border(enabled = enabled, pressed = pressed, style = style), | ||
elevation = elevation(enabled = enabled, loading = loading, style = style), | ||
contentPadding = contentPadding(enabled = enabled, style = style), | ||
interactionSource = interactionSource | ||
) { | ||
if (enabled && loading) { | ||
POCircularProgressIndicator.Small(color = style.progressIndicatorColor) | ||
} else { | ||
POText( | ||
text = text, | ||
style = if (enabled) style.normal.text.textStyle else style.disabled.text.textStyle, | ||
overflow = TextOverflow.Ellipsis, | ||
maxLines = 1 | ||
) | ||
} | ||
} | ||
} | ||
|
||
@Composable | ||
private fun colors( | ||
enabled: Boolean, | ||
loading: Boolean, | ||
pressed: Boolean, | ||
style: Style | ||
): ButtonColors { | ||
val normalTextColor: Color | ||
val normalBackgroundColor: Color | ||
if (pressed) with(style.highlighted) { | ||
normalTextColor = textColor | ||
normalBackgroundColor = backgroundColor | ||
} else with(style.normal) { | ||
normalTextColor = text.color | ||
normalBackgroundColor = backgroundColor | ||
} | ||
|
||
val disabledTextColor: Color | ||
val disabledBackgroundColor: Color | ||
if (enabled && loading) with(style.normal) { | ||
disabledTextColor = text.color | ||
disabledBackgroundColor = backgroundColor | ||
} else with(style.disabled) { | ||
disabledTextColor = text.color | ||
disabledBackgroundColor = backgroundColor | ||
} | ||
|
||
return ButtonDefaults.buttonColors( | ||
containerColor = normalBackgroundColor, | ||
contentColor = normalTextColor, | ||
disabledContainerColor = disabledBackgroundColor, | ||
disabledContentColor = disabledTextColor | ||
) | ||
} | ||
|
||
private fun border( | ||
enabled: Boolean, | ||
pressed: Boolean, | ||
style: Style | ||
): BorderStroke { | ||
val normalBorderColor = if (pressed) style.highlighted.borderColor else style.normal.border.color | ||
return if (enabled) style.normal.border.solid(color = normalBorderColor) | ||
else style.disabled.border.solid() | ||
} | ||
|
||
@Composable | ||
private fun elevation( | ||
enabled: Boolean, | ||
loading: Boolean, | ||
style: Style | ||
): ButtonElevation = ButtonDefaults.buttonElevation( | ||
defaultElevation = style.normal.elevation, | ||
pressedElevation = style.normal.elevation, | ||
focusedElevation = style.normal.elevation, | ||
hoveredElevation = style.normal.elevation, | ||
disabledElevation = if (enabled && loading) | ||
style.normal.elevation else style.disabled.elevation | ||
) | ||
|
||
private fun contentPadding( | ||
enabled: Boolean, | ||
style: Style | ||
): PaddingValues = if (enabled) PaddingValues( | ||
horizontal = style.normal.paddingHorizontal, | ||
vertical = style.normal.paddingVertical | ||
) else PaddingValues( | ||
horizontal = style.disabled.paddingHorizontal, | ||
vertical = style.disabled.paddingVertical | ||
) | ||
|
||
@Immutable | ||
data class Style( | ||
val normal: StateStyle, | ||
val disabled: StateStyle, | ||
val highlighted: HighlightedStyle, | ||
val progressIndicatorColor: Color | ||
) | ||
|
||
@Immutable | ||
data class StateStyle( | ||
val text: POText.Style, | ||
val shape: Shape, | ||
val border: POBorderStroke, | ||
val backgroundColor: Color, | ||
val elevation: Dp, | ||
val paddingHorizontal: Dp = POButtonDefaults.PADDING_HORIZONTAL_DP.dp, | ||
val paddingVertical: Dp = POButtonDefaults.PADDING_VERTICAL_DP.dp | ||
) | ||
|
||
@Immutable | ||
data class HighlightedStyle( | ||
val textColor: Color, | ||
val borderColor: Color, | ||
val backgroundColor: Color | ||
) | ||
|
||
val primary: Style | ||
@Composable get() = with(ProcessOutTheme) { | ||
Style( | ||
normal = StateStyle( | ||
text = POText.Style( | ||
color = colors.text.onColor, | ||
textStyle = typography.fixed.button | ||
), | ||
shape = shapes.roundedCornersSmall, | ||
border = POBorderStroke(width = 0.dp, color = Color.Unspecified), | ||
backgroundColor = colors.action.primaryDefault, | ||
elevation = 2.dp | ||
), | ||
disabled = StateStyle( | ||
text = POText.Style( | ||
color = colors.text.disabled, | ||
textStyle = typography.fixed.button | ||
), | ||
shape = shapes.roundedCornersSmall, | ||
border = POBorderStroke(width = 0.dp, color = Color.Unspecified), | ||
backgroundColor = colors.action.primaryDisabled, | ||
elevation = 0.dp | ||
), | ||
highlighted = HighlightedStyle( | ||
textColor = colors.text.onColor, | ||
borderColor = Color.Unspecified, | ||
backgroundColor = colors.action.primaryPressed | ||
), | ||
progressIndicatorColor = colors.text.onColor | ||
) | ||
} | ||
|
||
val secondary: Style | ||
@Composable get() = with(ProcessOutTheme) { | ||
Style( | ||
normal = StateStyle( | ||
text = POText.Style( | ||
color = colors.text.secondary, | ||
textStyle = typography.fixed.button | ||
), | ||
shape = shapes.roundedCornersSmall, | ||
border = POBorderStroke(width = 1.dp, color = colors.border.default), | ||
backgroundColor = colors.action.secondaryDefault, | ||
elevation = 0.dp | ||
), | ||
disabled = StateStyle( | ||
text = POText.Style( | ||
color = colors.text.disabled, | ||
textStyle = typography.fixed.button | ||
), | ||
shape = shapes.roundedCornersSmall, | ||
border = POBorderStroke(width = 1.dp, color = colors.action.borderDisabled), | ||
backgroundColor = colors.action.secondaryDefault, | ||
elevation = 0.dp | ||
), | ||
highlighted = HighlightedStyle( | ||
textColor = colors.text.secondary, | ||
borderColor = colors.border.default, | ||
backgroundColor = colors.action.secondaryPressed | ||
), | ||
progressIndicatorColor = colors.text.secondary | ||
) | ||
} | ||
|
||
@Composable | ||
fun custom(style: POButtonStyle) = Style( | ||
normal = style.normal.toStateStyle(), | ||
disabled = style.disabled.toStateStyle(), | ||
highlighted = with(style.highlighted) { | ||
HighlightedStyle( | ||
textColor = colorResource(id = textColorResId), | ||
borderColor = colorResource(id = borderColorResId), | ||
backgroundColor = colorResource(id = backgroundColorResId) | ||
) | ||
}, | ||
progressIndicatorColor = colorResource(id = style.progressIndicatorColorResId) | ||
) | ||
|
||
@Composable | ||
private fun POButtonStateStyle.toStateStyle() = StateStyle( | ||
text = POText.custom(style = text), | ||
shape = RoundedCornerShape(size = border.radiusDp.dp), | ||
border = POBorderStroke(width = border.widthDp.dp, color = colorResource(id = border.colorResId)), | ||
backgroundColor = colorResource(id = backgroundColorResId), | ||
elevation = elevationDp.dp, | ||
paddingHorizontal = paddingHorizontalDp.dp, | ||
paddingVertical = paddingVerticalDp.dp | ||
) | ||
} | ||
|
||
@Preview(showBackground = true) | ||
@Composable | ||
internal fun POButtonPreview() { | ||
POButton( | ||
text = "Button", | ||
onClick = {}, | ||
modifier = Modifier.fillMaxWidth() | ||
) | ||
} |
28 changes: 28 additions & 0 deletions
28
ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POCircularProgressIndicator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.processout.sdk.ui.core.component | ||
|
||
import androidx.compose.foundation.layout.size | ||
import androidx.compose.material3.CircularProgressIndicator | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.graphics.Color | ||
import androidx.compose.ui.unit.dp | ||
import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi | ||
|
||
/** @suppress */ | ||
@ProcessOutInternalApi | ||
object POCircularProgressIndicator { | ||
|
||
@Composable | ||
fun Small(color: Color) = CircularProgressIndicator( | ||
modifier = Modifier.size(18.dp), | ||
strokeWidth = 1.dp, | ||
color = color | ||
) | ||
|
||
@Composable | ||
fun Medium(color: Color) = CircularProgressIndicator( | ||
modifier = Modifier.size(28.dp), | ||
strokeWidth = 3.dp, | ||
color = color | ||
) | ||
} |
Oops, something went wrong.