-
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.
Merge pull request #308 from Spendesk/release/1.19.0
Release 1.19.0
- Loading branch information
Showing
9 changed files
with
510 additions
and
85 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
160 changes: 160 additions & 0 deletions
160
library-compose/src/main/java/com/spendesk/grapes/compose/actionmenu/ActionMenuItem.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,160 @@ | ||
package com.spendesk.grapes.compose.actionmenu | ||
|
||
import androidx.compose.foundation.layout.Arrangement | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.PaddingValues | ||
import androidx.compose.foundation.layout.Row | ||
import androidx.compose.foundation.layout.Spacer | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.size | ||
import androidx.compose.foundation.layout.sizeIn | ||
import androidx.compose.foundation.layout.width | ||
import androidx.compose.material3.Button | ||
import androidx.compose.material3.ButtonDefaults | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.material3.LocalContentColor | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.CompositionLocalProvider | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.res.painterResource | ||
import androidx.compose.ui.text.style.TextOverflow | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.compose.ui.unit.dp | ||
import com.spendesk.grapes.compose.R | ||
import com.spendesk.grapes.compose.theme.GrapesTheme | ||
|
||
/** | ||
* @author : RomainGF | ||
* @since : 09/10/2023 | ||
**/ | ||
private val iconMaxSize = 16.dp | ||
private val verticalInnerPadding = 20.dp | ||
private const val ACTION_TEXT_MAX_LINES = 2 | ||
|
||
/** | ||
* ActionMenuItem is a button with an icon and a text. | ||
* | ||
* @param text Text to display on the button | ||
* @param icon Slot for the icon to display on the left of the text. Size is constrained to 16dp. | ||
* @param onClick Callback when the button is clicked | ||
* @param modifier Modifier | ||
* @param enabled Whether the button is enabled or not | ||
*/ | ||
@Composable | ||
fun ActionMenuItem( | ||
text: String, | ||
icon: @Composable () -> Unit, | ||
onClick: () -> Unit, | ||
modifier: Modifier = Modifier, | ||
enabled: Boolean = true, | ||
) { | ||
Button( | ||
onClick = onClick, | ||
enabled = enabled, | ||
colors = ButtonDefaults.buttonColors( | ||
containerColor = GrapesTheme.colors.neutralLightest, | ||
contentColor = GrapesTheme.colors.primaryNormal, | ||
disabledContainerColor = GrapesTheme.colors.neutralLightest, | ||
disabledContentColor = GrapesTheme.colors.neutralNormal, | ||
), | ||
contentPadding = PaddingValues( | ||
start = GrapesTheme.dimensions.paddingXLarge, | ||
end = GrapesTheme.dimensions.paddingLarge, | ||
top = verticalInnerPadding, | ||
bottom = verticalInnerPadding, | ||
), | ||
shape = GrapesTheme.shapes.small, | ||
modifier = modifier, | ||
) { | ||
Row( | ||
verticalAlignment = Alignment.CenterVertically, | ||
) { | ||
ActionMenuItemIcon( | ||
enabled = enabled, | ||
icon = icon, | ||
) | ||
Spacer(Modifier.width(GrapesTheme.dimensions.paddingXLarge)) | ||
Text( | ||
text = text, | ||
maxLines = ACTION_TEXT_MAX_LINES, | ||
overflow = TextOverflow.Ellipsis, | ||
style = GrapesTheme.typography.titleS, | ||
modifier = Modifier.weight(1f), | ||
) | ||
if (enabled) { | ||
Spacer(Modifier.width(GrapesTheme.dimensions.paddingLarge)) | ||
Icon( | ||
painter = painterResource(R.drawable.ic_chevron_right), | ||
contentDescription = null, | ||
tint = GrapesTheme.colors.primaryLighter, | ||
) | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Composable | ||
private fun ActionMenuItemIcon( | ||
enabled: Boolean, | ||
icon: @Composable () -> Unit, | ||
) { | ||
Box( | ||
modifier = Modifier.sizeIn( | ||
maxWidth = iconMaxSize, | ||
maxHeight = iconMaxSize, | ||
), | ||
) { | ||
val iconContentColor = if (enabled) { | ||
GrapesTheme.colors.primaryNormal | ||
} else { | ||
GrapesTheme.colors.neutralNormal | ||
} | ||
CompositionLocalProvider(LocalContentColor provides iconContentColor) { | ||
icon() | ||
} | ||
} | ||
} | ||
|
||
@Preview | ||
@Preview(fontScale = 2f) | ||
@Composable | ||
private fun ActionMenuItemPreview() { | ||
GrapesTheme { | ||
val icon = @Composable { | ||
Icon( | ||
painter = painterResource(R.drawable.ic_neutral), | ||
contentDescription = null, | ||
modifier = Modifier.size(48.dp) | ||
) | ||
} | ||
val text = "Action" | ||
val longText = "Action with a very long title which will not fit in one line. Event two lines will not be enough" | ||
val modifier = Modifier.fillMaxWidth() | ||
Column( | ||
verticalArrangement = Arrangement.spacedBy(8.dp) | ||
) { | ||
ActionMenuItem( | ||
text = text, | ||
icon = icon, | ||
onClick = {}, | ||
modifier = modifier, | ||
) | ||
ActionMenuItem( | ||
text = longText, | ||
icon = icon, | ||
onClick = {}, | ||
modifier = modifier, | ||
) | ||
ActionMenuItem( | ||
text = text, | ||
icon = icon, | ||
onClick = {}, | ||
enabled = false, | ||
modifier = modifier, | ||
) | ||
} | ||
} | ||
} |
137 changes: 137 additions & 0 deletions
137
library-compose/src/main/java/com/spendesk/grapes/compose/actionmenu/ActionMenuSection.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,137 @@ | ||
package com.spendesk.grapes.compose.actionmenu | ||
|
||
import androidx.compose.foundation.layout.Arrangement | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.ColumnScope | ||
import androidx.compose.foundation.layout.Row | ||
import androidx.compose.foundation.layout.fillMaxSize | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.foundation.layout.sizeIn | ||
import androidx.compose.foundation.shape.RoundedCornerShape | ||
import androidx.compose.material3.Card | ||
import androidx.compose.material3.CardDefaults | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.res.painterResource | ||
import androidx.compose.ui.text.style.TextOverflow | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.compose.ui.unit.dp | ||
import com.spendesk.grapes.compose.R | ||
import com.spendesk.grapes.compose.theme.GrapesTheme | ||
|
||
/** | ||
* @author : RomainGF | ||
* @since : 09/10/2023 | ||
**/ | ||
|
||
private val iconMaxSize = 56.dp | ||
private val sectionShape = RoundedCornerShape(16.dp) | ||
private const val TITLE_MAX_LINES = 2 | ||
private const val DESCRIPTION_MAX_LINES = 3 | ||
|
||
@Composable | ||
fun ActionMenuSection( | ||
title: String, | ||
description: String, | ||
illustration: @Composable () -> Unit, | ||
modifier: Modifier = Modifier, | ||
content: @Composable ColumnScope.() -> Unit, | ||
) { | ||
Card( | ||
modifier = modifier, | ||
colors = CardDefaults.cardColors( | ||
containerColor = GrapesTheme.colors.structureSurface, | ||
), | ||
shape = sectionShape, | ||
) { | ||
Column( | ||
verticalArrangement = Arrangement.spacedBy(GrapesTheme.dimensions.paddingSmall), | ||
modifier = Modifier.padding(GrapesTheme.dimensions.paddingSmall), | ||
) { | ||
ActionMenuSectionHeader( | ||
title = title, | ||
description = description, | ||
illustration = illustration, | ||
) | ||
content() | ||
} | ||
} | ||
} | ||
|
||
@Composable | ||
private fun ActionMenuSectionHeader( | ||
title: String, | ||
description: String, | ||
illustration: @Composable () -> Unit, | ||
modifier: Modifier = Modifier, | ||
) { | ||
Row( | ||
horizontalArrangement = Arrangement.spacedBy(GrapesTheme.dimensions.paddingSmall), | ||
verticalAlignment = Alignment.CenterVertically, | ||
modifier = modifier, | ||
) { | ||
Box( | ||
content = { illustration() }, | ||
contentAlignment = Alignment.Center, | ||
modifier = Modifier.sizeIn( | ||
maxWidth = iconMaxSize, | ||
maxHeight = iconMaxSize, | ||
), | ||
) | ||
Column( | ||
verticalArrangement = Arrangement.spacedBy(GrapesTheme.dimensions.paddingXSmall), | ||
modifier = Modifier.padding( | ||
bottom = GrapesTheme.dimensions.paddingSmall, | ||
top = GrapesTheme.dimensions.paddingSmall, | ||
end = GrapesTheme.dimensions.paddingSmall, | ||
) | ||
) { | ||
Text( | ||
text = title, | ||
style = GrapesTheme.typography.titleM, | ||
color = GrapesTheme.colors.structureComplementary, | ||
maxLines = TITLE_MAX_LINES, | ||
overflow = TextOverflow.Ellipsis, | ||
) | ||
Text( | ||
text = description, | ||
style = GrapesTheme.typography.bodyS, | ||
color = GrapesTheme.colors.neutralDark, | ||
maxLines = DESCRIPTION_MAX_LINES, | ||
overflow = TextOverflow.Ellipsis, | ||
) | ||
} | ||
} | ||
} | ||
|
||
@Preview | ||
@Preview(fontScale = 2f) | ||
@Composable | ||
private fun ActionMenuSectionPreview() { | ||
GrapesTheme { | ||
ActionMenuSection( | ||
title = "Make a purchase request", | ||
description = "Order a virtual card to directly use company money online", | ||
illustration = { | ||
Icon(painterResource(R.drawable.ic_neutral), null, Modifier.fillMaxSize()) | ||
}, | ||
modifier = Modifier.fillMaxWidth(), | ||
) { | ||
ActionMenuItem( | ||
text = "Ask for a virtual card", | ||
icon = { Icon(painterResource(R.drawable.ic_neutral), null) }, | ||
onClick = {}, | ||
) | ||
ActionMenuItem( | ||
text = "Ask for a virtual card", | ||
icon = { Icon(painterResource(R.drawable.ic_neutral), null) }, | ||
onClick = {}, | ||
) | ||
} | ||
} | ||
} |
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
Oops, something went wrong.