Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import com.atls.hyperion.ui.components.button.locals.LocalState
import com.atls.hyperion.ui.components.button.styles.appearance.ButtonAppearance
import com.atls.hyperion.ui.components.button.styles.shape.ButtonShape
import com.atls.hyperion.ui.shared.addon.AddonSlotManager
Expand All @@ -30,7 +29,6 @@ fun Button(
Text(
text = text,
textAlign = TextAlign.Center,
color = appearance.fromState(LocalState.current).textColor,
style = shape.typography
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.atls.hyperion.ui.components.button

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.LocalContentAlpha
import androidx.compose.material.LocalContentColor
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.Role
import com.atls.hyperion.ui.components.button.styles.appearance.Colors
import com.atls.hyperion.ui.components.button.styles.shape.ButtonShape
import com.atls.hyperion.ui.primitives.elevation
import com.atls.hyperion.ui.theme.tokens.elevation.Elevation

@Composable
internal fun ButtonContainer(
modifier: Modifier,
enabled: Boolean,
interactionSource: MutableInteractionSource,
colors: Colors,
elevation: Elevation,
shape: ButtonShape,
onClick: () -> Unit,
content: @Composable () -> Unit
) {
val buttonShape = RoundedCornerShape(shape.cornerRadius)
val containerModifier = when (colors) {
is Colors.Solid -> modifier
.heightIn(min = shape.minHeight)
.elevation(
elevation = elevation,
backgroundColor = colors.background,
shape = buttonShape
)

is Colors.Gradient -> modifier
.heightIn(min = shape.minHeight)
.elevation(
elevation = elevation,
backgroundBrush = colors.background,
shape = buttonShape,
backgroundAlpha = colors.backgroundAlpha
)
}

Surface(
shape = buttonShape,
color = Color.Transparent,
contentColor = colors.content,
border = BorderStroke(shape.borderWidth, colors.border),
modifier = containerModifier.clickable(
interactionSource = interactionSource,
indication = null,
enabled = enabled,
role = Role.Button,
onClick = onClick
)
) {
CompositionLocalProvider(
LocalContentColor provides colors.content,
LocalContentAlpha provides 1f,
content = content
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.atls.hyperion.ui.components.button

import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import com.atls.hyperion.ui.components.button.styles.shape.ButtonShape
import com.atls.hyperion.ui.shared.addon.Addon
import com.atls.hyperion.ui.shared.addon.AddonPosition
import com.atls.hyperion.ui.shared.addon.AddonSlotManager

@Composable
internal fun ButtonContent(
addons: AddonSlotManager,
shape: ButtonShape,
content: @Composable () -> Unit
) {
val beforeAddons = addons.get(AddonPosition.Before)
val afterAddons = addons.get(AddonPosition.After)

BoxWithConstraints(
modifier = Modifier.padding(shape.paddings),
contentAlignment = Alignment.Center
) {
if (constraints.hasFixedWidth) {
val sideWidth = (shape.addonSize + shape.gap) * maxOf(
beforeAddons.size,
afterAddons.size
).toFloat()

Box(modifier = Modifier.fillMaxWidth()) {
Addons(
addons = beforeAddons,
addonSize = shape.addonSize,
gap = shape.gap,
position = AddonPosition.Before,
modifier = Modifier.align(Alignment.CenterStart)
)
Box(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = sideWidth)
.align(Alignment.Center),
contentAlignment = Alignment.Center,
content = { content() }
Comment thread
comfrt1k marked this conversation as resolved.
)
Addons(
addons = afterAddons,
addonSize = shape.addonSize,
gap = shape.gap,
position = AddonPosition.After,
modifier = Modifier.align(Alignment.CenterEnd)
)
}
} else {
Row(verticalAlignment = Alignment.CenterVertically) {
Addons(
addons = beforeAddons,
addonSize = shape.addonSize,
gap = shape.gap,
position = AddonPosition.Before
)
Box(contentAlignment = Alignment.Center) {
content()
}
Addons(
addons = afterAddons,
addonSize = shape.addonSize,
gap = shape.gap,
position = AddonPosition.After
)
}
}
}
}

@Composable
private fun Addons(
addons: List<Addon>,
addonSize: Dp,
gap: Dp,
position: AddonPosition,
modifier: Modifier = Modifier
) {
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically
) {
if (addons.isNotEmpty() && position == AddonPosition.After) {
Spacer(modifier = Modifier.width(gap))
}
addons.forEachIndexed { index, addon ->
if (index > 0) {
Spacer(modifier = Modifier.width(gap))
}
Box(
modifier = Modifier.size(addonSize),
contentAlignment = Alignment.Center
) {
addon.Content()
}
}
if (addons.isNotEmpty() && position == AddonPosition.Before) {
Spacer(modifier = Modifier.width(gap))
}
}
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,18 @@
package com.atls.hyperion.ui.components.button

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.LocalMinimumInteractiveComponentEnforcement
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import com.atls.hyperion.ui.components.button.locals.LocalState
import com.atls.hyperion.ui.components.button.state.ButtonState
import com.atls.hyperion.ui.components.button.styles.appearance.ButtonAppearance
import com.atls.hyperion.ui.components.button.styles.appearance.Colors
import com.atls.hyperion.ui.components.button.styles.shape.ButtonShape
import com.atls.hyperion.ui.shared.addon.AddonPosition
import com.atls.hyperion.ui.shared.addon.AddonSlotManager
import com.atls.hyperion.ui.theme.tokens.layout.Elevation
import com.atls.hyperion.ui.theme.tokens.colors.LegacyColors as ThemeColors

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun ButtonLayout(
modifier: Modifier = Modifier,
Expand All @@ -39,70 +25,36 @@ fun ButtonLayout(
) {
val interactionSource = remember { MutableInteractionSource() }
val isPressed = interactionSource.collectIsPressedAsState().value
val isFocused = interactionSource.collectIsFocusedAsState().value

val state = when {
!enabled -> ButtonState.Disabled
isPressed -> ButtonState.Pressed
isFocused -> ButtonState.Focused
else -> ButtonState.Default
}
val colors = appearance.fromState(state)
val elevation = when (state) {
ButtonState.Default -> shape.elevations.default
ButtonState.Pressed -> shape.elevations.pressed
ButtonState.Disabled -> shape.elevations.disabled
ButtonState.Focused -> shape.elevations.disabled
Comment thread
comfrt1k marked this conversation as resolved.
}

CompositionLocalProvider(
LocalState provides state,
LocalMinimumInteractiveComponentEnforcement provides false
) {
Button(
onClick = onClick,
shape = RoundedCornerShape(shape.cornerRadius),
colors = ButtonDefaults.buttonColors(
backgroundColor = when (colors) {
is Colors.Solid -> colors.backgroundColor
is Colors.Gradient -> ThemeColors.Palette.transparent
},
contentColor = colors.textColor,
disabledBackgroundColor = when (colors) {
is Colors.Solid -> colors.backgroundColor
is Colors.Gradient -> ThemeColors.Palette.transparent
},
disabledContentColor = colors.textColor
),
border = BorderStroke(shape.borderStroke, colors.borderColor),
contentPadding = shape.paddings,
CompositionLocalProvider(LocalState provides state) {
ButtonContainer(
modifier = modifier,
enabled = enabled,
elevation = ButtonDefaults.elevation(
defaultElevation = Elevation.zero,
pressedElevation = Elevation.zero,
disabledElevation = Elevation.zero
),
interactionSource = interactionSource,
modifier = modifier
.shadow(
elevation = appearance.shadowElevation,
shape = RoundedCornerShape(shape.cornerRadius),
clip = false
)
.then(
if (colors is Colors.Gradient) {
Modifier.background(
colors.backgroundBrush,
RoundedCornerShape(shape.cornerRadius)
)
} else Modifier
)
colors = appearance.fromState(state),
elevation = elevation,
shape = shape,
onClick = onClick
) {
Row(verticalAlignment = Alignment.CenterVertically) {
addons.get(AddonPosition.Before).forEach {
it.Content()
it.Spacer()
}

content()

addons.get(AddonPosition.After).forEach {
it.Spacer()
it.Content()
}
}
ButtonContent(
addons = addons,
shape = shape,
content = content
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ package com.atls.hyperion.ui.components.button.state
enum class ButtonState {
Default,
Disabled,
Pressed
Pressed,
Focused
}
Loading
Loading