Skip to content

Commit

Permalink
buttons: implement new ButtonLinks variants (color & Text-aligned)
Browse files Browse the repository at this point in the history
  • Loading branch information
hrach committed Mar 16, 2022
1 parent 0d33f8b commit f13c4d8
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 33 deletions.
129 changes: 116 additions & 13 deletions catalog/src/main/java/kiwi/orbit/compose/catalog/screens/ButtonScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,114 @@ import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Tab
import androidx.compose.material.TabRow
import androidx.compose.material.TabRowDefaults
import androidx.compose.material.TabRowDefaults.tabIndicatorOffset
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import kiwi.orbit.compose.catalog.Screen
import com.google.accompanist.insets.navigationBarsPadding
import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.rememberPagerState
import kiwi.orbit.compose.ui.OrbitTheme
import kiwi.orbit.compose.ui.controls.ButtonBundleBasic
import kiwi.orbit.compose.ui.controls.ButtonBundleMedium
import kiwi.orbit.compose.ui.controls.ButtonBundleTop
import kiwi.orbit.compose.ui.controls.ButtonCritical
import kiwi.orbit.compose.ui.controls.ButtonCriticalSubtle
import kiwi.orbit.compose.ui.controls.ButtonLink
import kiwi.orbit.compose.ui.controls.ButtonLinkCritical
import kiwi.orbit.compose.ui.controls.ButtonLinkPrimary
import kiwi.orbit.compose.ui.controls.ButtonLinkSecondary
import kiwi.orbit.compose.ui.controls.ButtonPrimary
import kiwi.orbit.compose.ui.controls.ButtonPrimarySubtle
import kiwi.orbit.compose.ui.controls.ButtonPrimitive
import kiwi.orbit.compose.ui.controls.ButtonSecondary
import kiwi.orbit.compose.ui.controls.ButtonTextLinkCritical
import kiwi.orbit.compose.ui.controls.ButtonTextLinkPrimary
import kiwi.orbit.compose.ui.controls.ButtonToggleContainer
import kiwi.orbit.compose.ui.controls.Card
import kiwi.orbit.compose.ui.controls.Scaffold
import kiwi.orbit.compose.ui.controls.Text
import kiwi.orbit.compose.ui.controls.TopAppBar
import kotlinx.coroutines.launch

@OptIn(ExperimentalPagerApi::class)
@Composable
fun ButtonScreen(onNavigateUp: () -> Unit) {
Screen(
title = "Button",
onNavigateUp = onNavigateUp,
val state = rememberPagerState(0)
val scope = rememberCoroutineScope()
Scaffold(
topBar = {
TopAppBar(
title = { Text("Buttons") },
onNavigateUp = onNavigateUp,
extraContent = {
TabRow(
modifier = Modifier.navigationBarsPadding(bottom = false),
selectedTabIndex = state.currentPage,
backgroundColor = OrbitTheme.colors.surface.main,
indicator = { tabPositions ->
TabRowDefaults.Indicator(
modifier = Modifier.tabIndicatorOffset(tabPositions[state.currentPage]),
color = OrbitTheme.colors.primary.main,
)
},
divider = {},
) {
Tab(
selected = state.currentPage == 0,
onClick = { scope.launch { state.animateScrollToPage(0) } },
text = { Text("Button") },
)
Tab(
selected = state.currentPage == 1,
onClick = { scope.launch { state.animateScrollToPage(1) } },
text = { Text("ButtonLink") },
)
}
}
)
},
) { contentPadding ->
Box(
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(contentPadding)
) {
ButtonScreenInner()
HorizontalPager(
count = 2,
state = state,
modifier = Modifier.padding(top = contentPadding.calculateTopPadding()),
) { tabIndex ->
Box(
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(
start = contentPadding.calculateStartPadding(LayoutDirection.Ltr),
end = contentPadding.calculateEndPadding(LayoutDirection.Ltr),
bottom = contentPadding.calculateBottomPadding(),
)
) {
when (tabIndex) {
0 -> ButtonScreenInner()
1 -> ButtonLinkScreenInner()
}
}
}
}
}
Expand All @@ -67,7 +134,6 @@ private fun ButtonScreenInner() {
ButtonBundleBasic(onClick = {}, maxWidth) { Text("Bundle Basic Button") }
ButtonBundleMedium(onClick = {}, maxWidth) { Text("Bundle Medium Button") }
ButtonBundleTop(onClick = {}, maxWidth) { Text("Bundle Top Button") }
ButtonLink(onClick = {}, maxWidth) { Text("Link Button") }

Text("Manually themed", Modifier.padding(top = 16.dp))

Expand All @@ -94,3 +160,40 @@ private fun ButtonScreenInner() {
}
}
}

@Composable
private fun ButtonLinkScreenInner() {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.padding(16.dp),
) {
ButtonLinkPrimary(onClick = {}, Modifier.fillMaxWidth()) { Text("Primary ButtonLink") }
ButtonLinkSecondary(onClick = {}, Modifier.fillMaxWidth()) { Text("Secondary ButtonLink") }
ButtonLinkCritical(onClick = {}, Modifier.fillMaxWidth()) { Text("Critical ButtonLink") }

Card {
Column(Modifier.padding(16.dp)) {
Text(
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam sit amet magna in magna gravida vehicula. Nam quis nulla. Nam sed tellus id magna elementum tincidunt.",
style = OrbitTheme.typography.bodyNormal
)
Spacer(Modifier.size(8.dp))
ButtonTextLinkPrimary("Translate", onClick = {})
}
}

Card {
Row(Modifier.padding(16.dp)) {
Text(
text = "Title",
style = OrbitTheme.typography.title3,
modifier = Modifier
.alignByBaseline()
.weight(1f)
)
Spacer(Modifier.size(8.dp))
ButtonTextLinkCritical("Delete", onClick = {}, modifier = Modifier.alignByBaseline())
}
}
}
}
17 changes: 1 addition & 16 deletions ui/src/main/java/kiwi/orbit/compose/ui/controls/Button.kt
Original file line number Diff line number Diff line change
Expand Up @@ -129,22 +129,7 @@ public fun ButtonBundleTop(
}

@Composable
public fun ButtonLink(
onClick: () -> Unit,
modifier: Modifier = Modifier,
content: @Composable RowScope.() -> Unit
) {
ButtonLargePrimitive(
onClick = onClick,
backgroundColor = Color.Transparent,
contentColor = OrbitTheme.colors.primary.main,
modifier = modifier,
content = content,
)
}

@Composable
private fun ButtonLargePrimitive(
internal fun ButtonLargePrimitive(
onClick: () -> Unit,
backgroundColor: Color,
modifier: Modifier = Modifier,
Expand Down
170 changes: 170 additions & 0 deletions ui/src/main/java/kiwi/orbit/compose/ui/controls/ButtonLink.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package kiwi.orbit.compose.ui.controls

import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.Role
import kiwi.orbit.compose.ui.OrbitTheme
import kiwi.orbit.compose.ui.foundation.LocalContentColor
import kiwi.orbit.compose.ui.layout.expand

/**
* ButtonLink with common button appearance.
*
* Consider using [ButtonTextLinkPrimary] for alignment with Text.
*/
@Composable
public fun ButtonLinkPrimary(
onClick: () -> Unit,
modifier: Modifier = Modifier,
content: @Composable RowScope.() -> Unit
) {
ButtonLargePrimitive(
onClick = onClick,
backgroundColor = Color.Transparent,
contentColor = OrbitTheme.colors.primary.main,
modifier = modifier,
content = content,
)
}

/**
* Text aligning version of ButtonLink.
*
* Suitable for aligning with other text (both horizontally and vertically).
* Touch feedback is drawn 8.dp outside the composable boundaries.
*/
@Composable
public fun ButtonTextLinkPrimary(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
ButtonTextLink(
text = text,
onClick = onClick,
modifier = modifier,
color = OrbitTheme.colors.primary.main,
)
}

/**
* ButtonLink with common button appearance.
*
* Consider using [ButtonTextLinkSecondary] for alignment with Text.
*/
@Composable
public fun ButtonLinkSecondary(
onClick: () -> Unit,
modifier: Modifier = Modifier,
content: @Composable RowScope.() -> Unit
) {
ButtonLargePrimitive(
onClick = onClick,
backgroundColor = Color.Transparent,
contentColor = OrbitTheme.colors.content.normal,
modifier = modifier,
content = content,
)
}

/**
* Text aligning version of ButtonLink.
*
* Suitable for aligning with other text (both horizontally and vertically).
* Touch feedback is drawn 8.dp outside the composable boundaries.
*/
@Composable
public fun ButtonTextLinkSecondary(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
ButtonTextLink(
text = text,
onClick = onClick,
modifier = modifier,
color = OrbitTheme.colors.content.normal,
)
}

/**
* ButtonLink with common button appearance.
*
* Consider using [ButtonTextLinkCritical] for alignment with Text.
*/
@Composable
public fun ButtonLinkCritical(
onClick: () -> Unit,
modifier: Modifier = Modifier,
content: @Composable RowScope.() -> Unit
) {
ButtonLargePrimitive(
onClick = onClick,
backgroundColor = Color.Transparent,
contentColor = OrbitTheme.colors.critical.main,
modifier = modifier,
content = content,
)
}

/**
* Text aligning version of ButtonLink.
*
* Suitable for aligning with other text (both horizontally and vertically).
* Touch feedback is drawn 8.dp outside the composable boundaries.
*/
@Composable
public fun ButtonTextLinkCritical(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
ButtonTextLink(
text = text,
onClick = onClick,
modifier = modifier,
color = OrbitTheme.colors.critical.main,
)
}

@Composable
private fun ButtonTextLink(
text: String,
onClick: () -> Unit,
modifier: Modifier,
color: Color,
) {
CompositionLocalProvider(
LocalContentColor provides color,
) {
Text(
text = text,
style = OrbitTheme.typography.bodyNormalMedium,
modifier = modifier
.expand(
horizontal = ButtonDefaults.ButtonSmallHorizontalPadding,
vertical = ButtonDefaults.ButtonSmallVerticalPadding
)
.clip(OrbitTheme.shapes.normal)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(),
onClick = onClick,
role = Role.Button,
)
.padding(
horizontal = ButtonDefaults.ButtonSmallHorizontalPadding,
vertical = ButtonDefaults.ButtonSmallVerticalPadding
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ public fun ButtonPrimitive(
}

public object ButtonDefaults {
private val ButtonHorizontalPadding = 16.dp
private val ButtonVerticalPadding = 12.dp
private val ButtonSmallHorizontalPadding = 8.dp
private val ButtonSmallVerticalPadding = 8.dp
internal val ButtonHorizontalPadding = 16.dp
internal val ButtonVerticalPadding = 12.dp
internal val ButtonSmallHorizontalPadding = 8.dp
internal val ButtonSmallVerticalPadding = 8.dp

public val ContentPadding: PaddingValues = PaddingValues(
start = ButtonHorizontalPadding,
Expand Down

0 comments on commit f13c4d8

Please sign in to comment.