Skip to content

Commit

Permalink
Merge pull request #642 from Orange-OpenSource/641-technical-refactor…
Browse files Browse the repository at this point in the history
…-odscomponentcontent

641 - Technical - Refactor OdsComponentContent
  • Loading branch information
paulinea authored Oct 4, 2023
2 parents 87c6d06 + 7033380 commit c0dacba
Show file tree
Hide file tree
Showing 22 changed files with 152 additions and 81 deletions.
4 changes: 2 additions & 2 deletions app/src/main/java/com/orange/ods/app/ui/MainTopAppBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ fun MainTopAppBar(
}

@Composable
private fun getTopAppBarSearchTextFieldAction(searchedText: MutableState<TextFieldValue>): OdsComponentContent {
return object : OdsComponentContent() {
private fun getTopAppBarSearchTextFieldAction(searchedText: MutableState<TextFieldValue>): OdsComponentContent<Nothing> {
return object : OdsComponentContent<Nothing>() {

@Composable
override fun Content(modifier: Modifier) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fun OdsLargeTopAppBarInternal(
title: String,
modifier: Modifier = Modifier,
navigationIcon: OdsTopAppBarNavigationIcon? = null,
actions: List<OdsComponentContent> = emptyList(),
actions: List<OdsComponentContent<*>> = emptyList(),
overflowMenuActions: List<OdsTopAppBarOverflowMenuActionItem> = emptyList(),
scrollBehavior: TopAppBarScrollBehavior? = null
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fun OdsTopAppBarInternal(
title: String,
modifier: Modifier = Modifier,
navigationIcon: OdsTopAppBarNavigationIcon? = null,
actions: List<OdsComponentContent> = emptyList(),
actions: List<OdsComponentContent<*>> = emptyList(),
overflowMenuActions: List<OdsTopAppBarOverflowMenuActionItem> = emptyList(),
elevated: Boolean = true
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import com.orange.ods.compose.component.menu.OdsDropdownMenuItem
import com.orange.ods.compose.theme.OdsTheme

@Composable
internal fun OdsTopAppBarActions(actions: List<OdsComponentContent>, overflowMenuActions: List<OdsTopAppBarOverflowMenuActionItem>) {
internal fun OdsTopAppBarActions(actions: List<OdsComponentContent<*>>, overflowMenuActions: List<OdsTopAppBarOverflowMenuActionItem>) {
val maxTotalActionCount = 3
val maxActionCount = if (overflowMenuActions.isNotEmpty()) maxTotalActionCount - 1 else maxTotalActionCount
actions.take(maxActionCount).forEach { it.Content() }
Expand All @@ -53,7 +53,7 @@ internal fun OdsTopAppBarActions(actions: List<OdsComponentContent>, overflowMen
/**
* A navigation icon in an [OdsTopAppBar].
*/
class OdsTopAppBarNavigationIcon : OdsComponentIcon {
class OdsTopAppBarNavigationIcon : OdsComponentIcon<Nothing> {

/**
* Creates an instance of [OdsTopAppBarNavigationIcon].
Expand Down Expand Up @@ -86,7 +86,7 @@ class OdsTopAppBarNavigationIcon : OdsComponentIcon {
/**
* An action button displayed in an [OdsTopAppBar].
*/
open class OdsTopAppBarActionButton : OdsComponentIcon {
open class OdsTopAppBarActionButton : OdsComponentIcon<Nothing> {

/**
* Creates an instance of [OdsTopAppBarActionButton].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ fun OdsBanner(
* @param text Text of the button.
* @param onClick Will be called when the user clicks the button.
*/
class OdsBannerButton(private val text: String, private val onClick: () -> Unit) : OdsComponentContent() {
class OdsBannerButton(private val text: String, private val onClick: () -> Unit) : OdsComponentContent<Nothing>() {

@Composable
override fun Content(modifier: Modifier) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ class OdsBottomNavigationItem(
val enabled: Boolean = true,
val label: String? = null,
val alwaysShowLabel: Boolean = true
) : OdsComponentScopeContent<RowScope>() {
) : OdsComponentScopeContent<RowScope, Nothing>() {

@Composable
override fun RowScope.Content() {
override fun RowScope.Content(modifier: Modifier) {
BottomNavigationItem(
selected = selected,
onClick = onClick,
Expand All @@ -122,7 +122,7 @@ class OdsBottomNavigationItem(
/**
* An icon in an [OdsBottomNavigationItem].
*/
class OdsBottomNavigationItemIcon : OdsComponentIcon {
class OdsBottomNavigationItemIcon : OdsComponentIcon<Nothing> {

/**
* Creates an instance of [OdsBottomNavigationItemIcon].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import com.orange.ods.compose.component.content.OdsComponentContent
import com.orange.ods.compose.component.content.OdsComponentIcon
import com.orange.ods.compose.theme.OdsDisplaySurface

Expand All @@ -27,7 +28,7 @@ import com.orange.ods.compose.theme.OdsDisplaySurface
* A button icon in an [OdsButton].
* It is non-clickable and no content description is needed cause a button label is always present.
*/
class OdsButtonIcon : OdsComponentIcon {
class OdsButtonIcon : OdsComponentIcon<Nothing> {

/**
* Creates an instance of [OdsButtonIcon].
Expand Down Expand Up @@ -60,7 +61,12 @@ class OdsButtonIcon : OdsComponentIcon {
/**
* An icon in an [OdsIconButton].
*/
class OdsIconButtonIcon : OdsComponentIcon {
class OdsIconButtonIcon : OdsComponentIcon<OdsIconButtonIcon.ExtraParameters> {

data class ExtraParameters(
val enabled: Boolean,
val displaySurface: OdsDisplaySurface
) : OdsComponentContent.ExtraParameters()

/**
* Creates an instance of [OdsIconButtonIcon].
Expand Down Expand Up @@ -91,10 +97,10 @@ class OdsIconButtonIcon : OdsComponentIcon {
get() = iconButtonTintColor(displaySurface = displaySurface)

@Composable
internal fun Content(enabled: Boolean, displaySurface: OdsDisplaySurface = OdsDisplaySurface.Default) {
this.enabled = enabled
this.displaySurface = displaySurface
Content()
override fun Content(modifier: Modifier) {
enabled = extraParameters.enabled
displaySurface = extraParameters.displaySurface
super.Content(modifier)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ fun OdsExtendedFloatingActionButton(
/**
* A button icon in an [OdsFloatingActionButton].
*/
class OdsFloatingActionButtonIcon : OdsComponentIcon {
class OdsFloatingActionButtonIcon : OdsComponentIcon<Nothing> {

/**
* Creates an instance of [OdsFloatingActionButtonIcon].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fun OdsIconButton(
LocalRippleTheme provides displaySurface.rippleTheme
) {
IconButton(onClick = onClick, modifier = modifier, enabled = enabled) {
icon.Content(enabled = enabled, displaySurface = displaySurface)
icon.Content(OdsIconButtonIcon.ExtraParameters(enabled, displaySurface))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ fun OdsIconToggleButton(
enabled = enabled
) {
val icon = if (checked) checkedIcon else uncheckedIcon
icon.Content(enabled = enabled, displaySurface = displaySurface)
icon.Content(OdsIconButtonIcon.ExtraParameters(enabled, displaySurface))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.unit.dp
import com.orange.ods.compose.component.OdsComposable
import com.orange.ods.compose.component.content.OdsComponentContent
import com.orange.ods.compose.component.content.OdsComponentIcon
import com.orange.ods.compose.component.utilities.DisabledInteractionSource
import com.orange.ods.compose.component.utilities.Preview
Expand Down Expand Up @@ -76,9 +77,11 @@ fun OdsIconToggleButtonsRow(
)
) {
icons.forEachIndexed { index, icon ->
icon.Content(index = index, displaySurface = displaySurface, selected = selectedIndex == index, onClick = { clickedButtonIndex ->
onSelectedIndexChange(clickedButtonIndex)
})
icon.Content(
OdsIconToggleButtonsRowIcon.ExtraParameters(index, displaySurface, selectedIndex == index) { clickedButtonIndex ->
onSelectedIndexChange(clickedButtonIndex)
}
)
if (index < icons.size) {
Divider(
modifier = Modifier
Expand All @@ -94,7 +97,14 @@ fun OdsIconToggleButtonsRow(
/**
* An icon of an [OdsIconToggleButtonsRow].
*/
class OdsIconToggleButtonsRowIcon : OdsComponentIcon {
class OdsIconToggleButtonsRowIcon : OdsComponentIcon<OdsIconToggleButtonsRowIcon.ExtraParameters> {

data class ExtraParameters(
val index: Int,
val displaySurface: OdsDisplaySurface,
val selected: Boolean,
val onClick: (Int) -> Unit
) : OdsComponentContent.ExtraParameters()

/**
* Creates an instance of [OdsIconToggleButtonsRowIcon].
Expand Down Expand Up @@ -126,45 +136,34 @@ class OdsIconToggleButtonsRowIcon : OdsComponentIcon {
*/
constructor(bitmap: ImageBitmap, contentDescription: String, enabled: Boolean = true) : super(bitmap, contentDescription, enabled)

private var index: Int = 0
private var onClick: (Int) -> Unit = {}
private var selected: Boolean = false

override val tint: Color
@Composable
get() {
return getIconColor(displaySurface, selected, enabled)
return with(extraParameters) { getIconColor(displaySurface, selected, enabled) }
}

@Composable
internal fun Content(index: Int, onClick: (Int) -> Unit, displaySurface: OdsDisplaySurface = OdsDisplaySurface.Default, selected: Boolean = false) {
this.index = index
this.onClick = onClick
this.displaySurface = displaySurface
this.selected = selected
Content()
}

@Composable
override fun Content(modifier: Modifier) {
val backgroundAlpha = if (selected && enabled) 0.12f else 0f
val toggleIconStateDescription = selectionStateDescription(selected = selected)
with(extraParameters) {
val backgroundAlpha = if (selected && enabled) 0.12f else 0f
val toggleIconStateDescription = selectionStateDescription(selected = selected)

super.Content(
modifier
.background(color = buttonToggleBackgroundColor(displaySurface).copy(alpha = backgroundAlpha))
.padding(12.dp)
.run {
if (enabled) {
clickable(interactionSource = remember { DisabledInteractionSource() }, indication = null) { onClick(index) }
} else {
this
super.Content(
modifier
.background(color = buttonToggleBackgroundColor(displaySurface).copy(alpha = backgroundAlpha))
.padding(12.dp)
.run {
if (enabled) {
clickable(interactionSource = remember { DisabledInteractionSource() }, indication = null) { onClick(index) }
} else {
this
}
}
}
.semantics {
stateDescription = toggleIconStateDescription
}
)
.semantics {
stateDescription = toggleIconStateDescription
}
)
}
}

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ internal fun OdsCard(modifier: Modifier, onClick: (() -> Unit)?, content: @Compo
* @param text Text of the button.
* @param onClick Will be called when the user clicks the button.
*/
class OdsCardButton(private val text: String, private val onClick: () -> Unit) : OdsComponentContent() {
class OdsCardButton(private val text: String, private val onClick: () -> Unit) : OdsComponentContent<Nothing>() {

@Composable
override fun Content(modifier: Modifier) {
Expand All @@ -62,7 +62,7 @@ class OdsCardImage private constructor(
alignment: Alignment = Alignment.Center,
contentScale: ContentScale = ContentScale.Crop,
private val backgroundColor: Color? = null
) : OdsComponentImage(graphicsObject, contentDescription, alignment, contentScale) {
) : OdsComponentImage<Nothing>(graphicsObject, contentDescription, alignment, contentScale) {

/**
* Creates an instance of [OdsCardImage].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import com.orange.ods.compose.component.content.OdsComponentImage
/**
* A leading icon in an [OdsChip].
*/
class OdsChipLeadingIcon : OdsComponentIcon {
class OdsChipLeadingIcon : OdsComponentIcon<Nothing> {

/**
* Creates an instance of [OdsChipLeadingIcon].
Expand Down Expand Up @@ -66,7 +66,7 @@ class OdsChipLeadingIcon : OdsComponentIcon {
/**
* A leading avatar in an [OdsChip].
*/
class OdsChipLeadingAvatar : OdsComponentImage {
class OdsChipLeadingAvatar : OdsComponentImage<Nothing> {

/**
* Creates an instance of [OdsChipLeadingAvatar].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import androidx.compose.ui.unit.dp
abstract class OdsComponentCircleImage private constructor(
graphicsObject: Any,
contentDescription: String
) : OdsComponentImage(graphicsObject, contentDescription, contentScale = ContentScale.Crop) {
) : OdsComponentImage<Nothing>(graphicsObject, contentDescription, contentScale = ContentScale.Crop) {

/**
* Creates an instance of [OdsComponentCircleImage].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,50 @@ import androidx.compose.ui.Modifier
* This prevents using generic composable methods that can encapsulate any kind of views and thus helps developers to follow UI guidelines more easily.
* This also allows to group parameters that are related to the same content inside a component.
* For instance it is possible to create an `Icon` subclass to replace both `icon: @Composable () -> Unit` and `onIconClick: () -> Unit` parameters with a single `icon: Icon` parameter.
*
* @param T the type of extra parameters.
*/
abstract class OdsComponentContent {
abstract class OdsComponentContent<T> where T : OdsComponentContent.ExtraParameters {

/**
* Extra parameters that can be passed to the `Content` method when other parameters than those provided by the user are needed to layout the component.
*/
abstract class ExtraParameters

/**
* The extra parameters.
*/
protected lateinit var extraParameters: T

/**
* The Jetpack Compose UI for this component content.
*
* Calls `Content(Modifier)` with the default `Modifier`.
*/
@Composable
fun Content() = Content(modifier = Modifier)
internal fun Content() = Content(modifier = Modifier)

/**
* The Jetpack Compose UI for this component content.
*
* Calls `Content(Modifier, T)` with the default `Modifier`.
*
* @param extraParameters the extra parameters for this content.
*/
@Composable
internal fun Content(extraParameters: T) = Content(modifier = Modifier, extraParameters = extraParameters)

/**
* The Jetpack Compose UI for this component content.
*
* @param modifier the Modifier for this content.
* @param extraParameters the extra parameters for this content.
*/
@Composable
internal fun Content(modifier: Modifier, extraParameters: T) {
this.extraParameters = extraParameters
Content(modifier = modifier)
}

/**
* The Jetpack Compose UI for this component content.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ import com.orange.ods.extension.orElse
/**
* An icon in a component.
*/
abstract class OdsComponentIcon internal constructor(
abstract class OdsComponentIcon<T> internal constructor(
private val graphicsObject: Any,
private val contentDescription: String,
protected var enabled: Boolean = true,
private val onClick: (() -> Unit)? = null,
protected var displaySurface: OdsDisplaySurface = OdsDisplaySurface.Default
) : OdsComponentContent() {
) : OdsComponentContent<T>() where T : OdsComponentContent.ExtraParameters {

protected open val tint: Color?
@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import androidx.compose.ui.layout.ContentScale
/**
* An image in a component.
*/
abstract class OdsComponentImage internal constructor(
abstract class OdsComponentImage<T> internal constructor(
private val graphicsObject: Any,
private val contentDescription: String,
private val alignment: Alignment = Alignment.Center,
private val contentScale: ContentScale = ContentScale.Fit
) : OdsComponentContent() {
) : OdsComponentContent<T>() where T: OdsComponentContent.ExtraParameters {

protected constructor(
painter: Painter,
Expand Down
Loading

0 comments on commit c0dacba

Please sign in to comment.