Skip to content

Fiori Horizon List Cards

Design

The Fiori Horizon List Card displays a list of similar cells inside a card view. The List Card can also have a header at the top and/or action buttons at the bottom of the list. The List Card supports both Light mode and Dark mode, determined by the device's settings.

List Cards in Light Mode List Cards in Dark Mode
List Cards on a Large Screen

Development

The Fiori Horizon List Card is implemented entirely using Jetpack Compose, including a Composable FioriHorizonTheme. To understand the fundamentals of Jetpack Compose, refer to the Android Developer's documentation.

The fiori-horizon-cards module provides two UI components for application developers to use out of the box:

  • ListCard: a UI component to display a single List Card.
  • ListCardGrid: a UI component to display a series of List Cards in a vertically scrollable grid that is responsive to different screen sizes.

Usage in an Application

This section describes how to use the List Card components in an application.

Sample Application on a Phone in Light mode Sample Application on a Phone in Dark mode

Sample Android Application on a Large Tablet

1. How to Create a ListCard

ListCard is a Composable function that takes two parameters:

  • A ListCardData that specifies the data to be displayed on the card
  • A Modifier that is used to define the height and width of the card and/or a TestTag needed for Unit Tests. A default listCardModifier is predefined to set the minimum height and width requirements.
@Composable
fun ListCard(
    data: ListCardData,
    modifier: Modifier = listCardModifier
) {
    val uiState = rememberListCardUiState(data = data)
    ListCardContent(
        darkTheme = isSystemInDarkTheme(),
        uiState = uiState,
        modifier = modifier
    )
}

An object of the ListCardData has to be passed in from the application in order to create a ListCard.

@Parcelize
data class ListCardData(
    val listCells: @RawValue List<ListCell>,
    val header: String? = null,
    val imageThumbnail: @RawValue ImageThumbnail? = null,
    val menuItems: List<Pair<String, ()->Unit>>? = listOf(),
    val primaryActionButton: @RawValue ActionButton? = null,
    val secondaryActionButton: @RawValue ActionButton? = null,
    val cardBackgroundColor: @RawValue Color? = null,
    val cardWidth: Int? = null,
) : Parcelable

data class ListCell(
    val title: String,
    val subtitle: String? = null,
    val footnote: String? = null,
    val status: ListCellStatus? = null,
    val imageThumbnail: @RawValue ImageThumbnail? = null,
    val listCellAction: ListCellAction,
    val clickable: Boolean = true,
    val onClick: () -> Unit?
)

Creating a ListCard can be as simple as the following (if there is no need to provide a custom Modifier):

    FioriHorizonTheme(darkTheme = false) {
        val listCardData = remember { generateListCardExample() }
        ListCard(data = listCardData)
    }

You can customize the ListCard's style, including Action Button styles and card background color, by supplying new values in the ListCardData. For example, to change the background color of the ActionButton on the ListCells of a ListCard from the default color to green:

val LC_LISTCELL4 = ListCell(
    title = "Maternity Leave",
    subtitle = "09/10/21 - 01/12/22",
    footnote =  "Leave Request",
    imageThumbnail = ImageThumbnail(
        imageType = ImageType.RESOURCE,
        resId = R.drawable.angular_square,
        imageDesc = "Image Description"
    ),
    listCellAction = ListCellAction(
        actionType = ListCellActionType.TEXT,
        textActionButton = ActionButton("Approve", {}, false, Color.Green, Color.Green)
    ),
    clickable = true,
    onClick = {}
)

val LISTCARDEXAMPLE4 = ListCardData(
    listCells = List(5){ LC_LISTCELL4},
    header = LC_HEADER,
    imageThumbnail = LC_IMAGETHUMBNAIL,
    primaryActionButton = LC_PRIMARYACTIONBUTTON,
    secondaryActionButton = LC_SECONDARYACTIONBUTTON,
    menuItems = listOf(
        Pair("item 1", {}),
        Pair("item 2", {})
    )
)

fun generateListCardExample(): ListCardData {
    return LISTCARDEXAMPLE4
}

FioriHorizonTheme(darkTheme = false) {
    val listCardData = remember { generateListCardExample() }
    ListCard(data = listCardData)
}

When this card is drawn on the screen, the Approve buttons will be green.

List Card with default button color List Card with custom button color

2. How to Create a ListCardGrid

To display a series of ListCards on the screen, use a ListCardGrid.

A ListCardGrid is defined as a Composable function in the fiori-horizon-cards module. In order to create a ListCardGrid, an application only needs to know the signatures of this function.

@Composable
fun ListCardGrid(
    cardList: List<ListCardData>,
    screenType: Enum<ScreenType>,
    modifier: Modifier = Modifier
){
    ...
}

An application should pass in a list of ListCardData objects as well as an Enum value for ScreenType. For example:

    FioriHorizonTheme {
        val listCardDataList = remember { generateListCardList() }
        val screenType = getScreenType()
        ListCardGrid(
            cardList = listCardDataList,
            screenType = screenType,
            modifier = Modifier.then(Modifier.wrapContentHeight(Alignment.Top))
        )
    }

Within the fiori-horizon-cards module, a utility Composable function is provided for applications to detect the ScreenType based on the Android Developers' recommendation documented in Support different screen sizes.

@Composable
fun getScreenType(): ScreenType {
    val screenWidth =
        LocalContext.current.resources.displayMetrics.widthPixels.dp / LocalDensity.current.density
    return when {
        screenWidth < 600.dp -> ScreenType.SMALL
        screenWidth >= 600.dp && screenWidth < 840.dp -> ScreenType.MEDIUM
        screenWidth > 840.dp -> ScreenType.LARGE
        else -> ScreenType.SMALL
    }
}

Last update: June 22, 2022