Skip to content

Commit

Permalink
feat(Fab): add fab and fab extended components
Browse files Browse the repository at this point in the history
  • Loading branch information
FDELAHA24 authored and ManonPolle committed Jan 18, 2023
1 parent 0dd9529 commit 6137bb8
Show file tree
Hide file tree
Showing 26 changed files with 886 additions and 1 deletion.
1 change: 1 addition & 0 deletions fabs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
95 changes: 95 additions & 0 deletions fabs/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Floating Action Button components

## FAB design specs

You can find the design specs on [decathlon.design](https://www.decathlon.design/).

## Usage

If you want to use components of this module in your android mobile application, you should
first add the Gradle dependency in your Gradle file:

```kotlin
implementation("com.decathlon.vitamin.compose:fabs:<versions>")
```

### Primary

**FAB**

```kotlin
object VitaminFabs {
@Composable
fun Primary(
icon: Painter,
contentDescription: String?,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: FabsColor = VitaminFabsColors.primary(),
sizes: FabSizes = VitaminFabSizes.default(),
onClick: () -> Unit
)
}
```

Use FABs for primary, positive actions.

The minimal usage of the component is the fab with an icon and a content description.

```kotlin
VitaminFabs.Primary(
icon = painterResource(id = R.drawable.ic_vtmn_add_fill),
contentDescription = "Add"
) {
// Click event
}
```

Parameters | Descriptions
-- | --
`icon: Painter` | The icon to be displayed inside the FAB
`contentDescription: String?` | The icon content description for accessibility
`modifier: Modifier = Modifier` | The `Modifier` to be applied to the component
`enabled: Boolean = true` | True if you can click on the FAB, otherwise false
`colors: FabsColors = VitaminFabsColors.primary()` | The colors of the background and the content in enabled and disabled
`sizes: FabSizes = VitaminFabSizes.medium()` | The sizes for the icon and the component itself
`onClick: () -> Unit` | The callback to be called when the user click on the FAB


**FAB extended**

```kotlin
object VitaminFabsExtended {
@Composable
fun Primary(
text: String,
modifier: Modifier = Modifier,
enabled: Boolean = true,
icon: Painter? = null,
colors: FabsColors = VitaminFabsColors.primary(),
sizes: FabExtendedSizes = VitaminFabExtendedSizes.default(),
onClick: () -> Unit
)
}


The minimal usage of the component is the fab extended with a label. You can also add an icon.

```kotlin
VitaminFabsExtended.Primary(
text = "Label"
) {
// Click event
}
```

```
Parameters | Descriptions
-- | --
`text: String` | The text inside the FAB extended
`modifier: Modifier = Modifier` | The `Modifier` to be applied to the component
`icon: Painter` | The optional icon to be displayed inside the FAB extended on the right left side of the text
`enabled: Boolean = true` | True if you can click on the FAB, otherwise false
`colors: FabsColors = VitaminFabsColors.primary()` | The colors of the background and the content in enabled and disabled
`sizes: FabSizes = VitaminFabExtendedSizes.default()` | The sizes for the icon, the text and the component itself
`onClick: () -> Unit` | The callback to be called when the user click on the FAB extended
13 changes: 13 additions & 0 deletions fabs/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
plugins {
id("com.android.library")
id("kotlin-android")
id("VitaminComposeLibraryPlugin")
id("com.vanniktech.maven.publish")
id("app.cash.paparazzi")
}

dependencies {
api(project(":foundation"))
implementation(AndroidX.compose.ui.tooling)
testImplementation("com.google.testparameterinjector:test-parameter-injector:1.8")
}
3 changes: 3 additions & 0 deletions fabs/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
POM_ARTIFACT_ID=fabs
POM_NAME=Vitamin Fabs
POM_DESCRIPTION=Fab components with Vitamin design
2 changes: 2 additions & 0 deletions fabs/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.decathlon.vitamin.compose.fabs" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.decathlon.vitamin.compose.fabs

import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.MutableInteractionSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow

internal class NoRippleInteractionSource : MutableInteractionSource {
override val interactions: Flow<Interaction> = emptyFlow()
override suspend fun emit(interaction: Interaction) { /*not used in this context*/ }
override fun tryEmit(interaction: Interaction) = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.decathlon.vitamin.compose.fabs

import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.remember
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.decathlon.vitamin.compose.foundation.VitaminTheme

@Immutable
data class FabExtendedSizes(
val textStyle: TextStyle,
val height: Dp,
val iconSize: Dp,
val horizontalPadding: Dp,
val iconStartPadding: Dp,
val iconEndPadding: Dp
)

object VitaminFabExtendedSizes {
@Composable
fun default(
textStyle: TextStyle = VitaminTheme.typography.button,
height: Dp = 48.dp,
iconSize: Dp = 24.dp,
textHorizontalPadding: Dp = 20.dp,
iconStartPadding: Dp = 16.dp,
iconEndPadding: Dp = 8.dp
): FabExtendedSizes = remember(
textStyle,
height,
iconSize,
textHorizontalPadding,
iconStartPadding,
iconEndPadding
) {
FabExtendedSizes(
textStyle = textStyle,
height = height,
iconSize = iconSize,
horizontalPadding = textHorizontalPadding,
iconStartPadding = iconStartPadding,
iconEndPadding = iconEndPadding
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.decathlon.vitamin.compose.fabs

import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.remember
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

@Immutable
data class FabSizes(
val size: Dp,
val iconSize: Dp
)

object VitaminFabSizes {
@Composable
fun mini(
size: Dp = 40.dp,
iconSize: Dp = 24.dp
): FabSizes = remember(
size,
iconSize
) {
FabSizes(
size = size,
iconSize = iconSize
)
}

@Composable
fun default(
size: Dp = 56.dp,
iconSize: Dp = 24.dp
): FabSizes = remember(
size,
iconSize
) {
FabSizes(
size = size,
iconSize = iconSize
)
}
}
129 changes: 129 additions & 0 deletions fabs/src/main/java/com/decathlon/vitamin/compose/fabs/VitaminFabs.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package com.decathlon.vitamin.compose.fabs

import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.size
import androidx.compose.material.FloatingActionButton
import androidx.compose.material.FloatingActionButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.decathlon.vitamin.compose.foundation.VitaminTheme

object VitaminFabs {

/**
* The FAB must be used for primary, positive actions
* @param icon The icon to be displayed inside the FAB
* @param contentDescription The icon content description for accessibility
* @param modifier The [Modifier] to be applied to the component
* @param enabled True if you can click on the FAB, otherwise false
* @param colors The colors of the background and the content in enabled and disabled
* @param sizes The sizes for the icon and the component itself
* @param onClick The callback to be called when the user click on the FAB
*/
@Composable
fun Primary(
icon: Painter,
contentDescription: String?,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: FabsColors = VitaminFabsColors.primary(),
sizes: FabSizes = VitaminFabSizes.default(),
onClick: () -> Unit,
) {
FloatingActionButton(
interactionSource = if (enabled) {
MutableInteractionSource()
} else {
NoRippleInteractionSource()
},
elevation = if (enabled) {
FloatingActionButtonDefaults.elevation()
} else {
FloatingActionButtonDefaults.elevation(
defaultElevation = 0.dp,
pressedElevation = 0.dp,
focusedElevation = 0.dp,
hoveredElevation = 0.dp
)
},
contentColor = if (enabled) {
colors.contentColor
} else {
colors.disabledContentColor
},
backgroundColor = if (enabled) {
colors.backgroundColor
} else {
colors.disabledBackgroundColor
},
modifier = modifier
.size(sizes.size),
onClick = {
if (enabled) {
onClick()
}
}
) {
Icon(
painter = icon,
contentDescription = contentDescription,
modifier = Modifier.size(sizes.iconSize)
)
}
}
}

@Preview
@Composable
private fun VitaminEnabledFabPreview() {
VitaminTheme {
VitaminFabs.Primary(
icon = rememberVectorPainter(image = Icons.Filled.Add),
contentDescription = "Add"
) {}
}
}

@Preview
@Composable
private fun VitaminDisabledFabPreview() {
VitaminTheme {
VitaminFabs.Primary(
icon = rememberVectorPainter(image = Icons.Filled.Add),
contentDescription = "Add",
enabled = false
) {}
}
}

@Preview
@Composable
private fun VitaminEnabledMiniFabPreview() {
VitaminTheme {
VitaminFabs.Primary(
sizes = VitaminFabSizes.mini(),
icon = rememberVectorPainter(image = Icons.Filled.Add),
contentDescription = "Add"
) {}
}
}

@Preview
@Composable
private fun VitaminDisabledMiniFabPreview() {
VitaminTheme {
VitaminFabs.Primary(
sizes = VitaminFabSizes.mini(),
icon = rememberVectorPainter(image = Icons.Filled.Add),
contentDescription = "Add",
enabled = false
) {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.decathlon.vitamin.compose.fabs

import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.Color
import com.decathlon.vitamin.compose.foundation.VitaminTheme
import com.decathlon.vitamin.compose.foundation.VtmnStatesDisabled

@Immutable
data class FabsColors(
val contentColor: Color,
val backgroundColor: Color,
val disabledContentColor: Color,
val disabledBackgroundColor: Color
)

object VitaminFabsColors {
@Composable
fun primary(
contentColor: Color = VitaminTheme.colors.vtmnContentPrimaryReversed,
backgroundColor: Color = VitaminTheme.colors.vtmnBackgroundBrandPrimary,
disabledContentColor: Color = VitaminTheme.colors.vtmnContentAction.copy(alpha = VtmnStatesDisabled),
disabledBackgroundColor: Color = VitaminTheme.colors.vtmnBackgroundBrandPrimary.copy(alpha = 0.12f),
): FabsColors = remember(
contentColor,
backgroundColor,
disabledContentColor,
disabledBackgroundColor
) {
FabsColors(
contentColor = contentColor,
backgroundColor = backgroundColor,
disabledContentColor = disabledContentColor,
disabledBackgroundColor = disabledBackgroundColor
)
}
}
Loading

0 comments on commit 6137bb8

Please sign in to comment.