Pantrix UI

Avatar

The picture of a person or a thing: a photograph, the initials of a name, or an icon standing for either.

import com.pantrixui.components.elements.avatar.PantrixAvatar

Examples

At its plainest

The least it takes: a description and initials. Its tone is Neutral, and its size the style's.

An avatar that stands alone takes its name from its description: a screen reader reads it as an image named "Ayşe Yılmaz". The letters "AY" are not read out; they are what the description shortens.

PantrixAvatar(contentDescription = "Ayşe Yılmaz", initials = "AY", tagKey = "ayse")

Beside a name

An avatar that stands beside its name has no description: contentDescription = null. The name is written beside it; a screen reader does not read the same name twice, and the avatar is hidden from it.

Initials are drawn as they are written, and are not put in upper case: the "ik" in the last row stays in lower case.

CONTACTS.forEachIndexed { index, contact -> ContactRow(contact = contact, key = "contact_$index") }

@Composable
private fun ContactRow(
    contact: AvatarContact,
    key: String
) {
    Row(
        horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
        verticalAlignment = Alignment.CenterVertically
    ) {
        PantrixAvatar(contentDescription = null, initials = contact.initials, tone = contact.tone, tagKey = key)
        Column {
            PantrixText(text = contact.name, style = PantrixTheme.typography.label)
            PantrixText(
                text = contact.lastTransfer,
                style = PantrixTheme.typography.footnote,
                color = PantrixTheme.colors.textSecondary
            )
        }
    }
}

private class AvatarContact(
    val name: String,
    val initials: String,
    val lastTransfer: String,
    val tone: AvatarTone = AvatarTone.Neutral
)

private val CONTACTS = listOf(
    AvatarContact(name = "Ayşe Yılmaz", initials = "AY", lastTransfer = "Sent yesterday: 250,00 TL"),
    AvatarContact(
        name = "İbrahim Öztürk",
        initials = "İÖ",
        lastTransfer = "Received on 3 September: 1.200,00 TL",
        tone = AvatarTone.Info
    ),
    // Initials are drawn as they are written: lower case stays lower case.
    AvatarContact(name = "ilker kaya", initials = "ik", lastTransfer = "No transactions yet", tone = AvatarTone.Success)
)

Tones

tone fills the avatar with the colour of one of the theme's roles, and writes the letters in the colour that reads on it. The default is Neutral: a grey with no meaning at all.

In every tone the avatar is drawn in the role's solid colour, not in its pale container: a small circle of that colour is lost on a light page. A tone says nothing by itself; what a colour is to mean has to be in the words beside it.

FlowRow(
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
    verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)
) {
    AvatarTone.entries.forEachIndexed { index, tone ->
        PantrixAvatar(
            contentDescription = "Avatar in the ${tone.name} tone",
            initials = TONE_INITIALS[index],
            tone = tone,
            tagKey = "tone_${tone.name}"
        )
    }
}

private val TONE_INITIALS = listOf("AL", "GH", "KJ", "MR", "ŞÖ", "WY")

Sizes

size is the avatar's width and height: 24dp in a comment, 32dp in a dense row, 40dp in a row, 56dp on a card, 72dp on a profile. The size can be given by modifier too; it then takes the place of size.

The initials are four tenths of the avatar and the icon six tenths: the proportion stays the same whatever the size, and no second style is needed.

Row(
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
    verticalAlignment = Alignment.CenterVertically
) {
    listOf(24, 32, 40, 56, 72).forEach { size ->
        PantrixAvatar(
            contentDescription = null,
            initials = "DK",
            tone = AvatarTone.Primary,
            size = size.dp,
            tagKey = "size_$size"
        )
    }
}

Initials

Initials are drawn as they are written. They are not put in upper case: i becomes İ in Turkish and I in other languages, and an avatar is not the place to get a name wrong. The first avatar was given "ik", and so it stayed.

The first two letters of what is given are kept, without the spaces between them: the avatar given "Ayşe Yılmaz" writes "Ay", and the one given "D K" writes "DK". How a name is shortened is the app's to say, not the avatar's: the app gives the letters to draw.

Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixAvatar(contentDescription = "ilker kaya", initials = "ik", tagKey = "as_written")
    PantrixAvatar(contentDescription = "Ayşe Yılmaz", initials = "Ayşe Yılmaz", tagKey = "first_two")
    PantrixAvatar(contentDescription = "Deniz Kara", initials = "D K", tagKey = "without_spaces")
    PantrixAvatar(contentDescription = "Zeynep", initials = "Z", tagKey = "one_letter")
}

A photograph that comes later

A profile whose photograph comes later. The avatar is given its image slot from the start, but the slot draws nothing until "Load photo" is pressed: until then the initials show. When the photograph comes it covers the letters. An image loader does the same while it loads, or when it fails.

The slot is as large as the avatar and is cut to its shape. The "photograph" here is a gradient with no size of its own; for a picture that is not square, ask for ContentScale.Crop. What the picture says of itself is not read: the avatar's description stands for both.

var loaded by rememberSaveable { mutableStateOf(false) }
Row(
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
    verticalAlignment = Alignment.CenterVertically
) {
    PantrixAvatar(
        contentDescription = "Deniz Kara's profile photo",
        initials = "DK",
        tone = AvatarTone.Primary,
        size = 72.dp,
        tagKey = "profile"
    ) {
        if (loaded) Photo()
    }
    Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.xs)) {
        PantrixText(text = "Deniz Kara", style = PantrixTheme.typography.callout)
        PantrixButton(
            text = if (loaded) "Remove photo" else "Load photo",
            onClick = { loaded = !loaded },
            variant = ButtonVariant.Outline,
            tagKey = "load_photo"
        )
    }
}

@Composable
private fun Photo() {
    val colors = PantrixTheme.colors
    val gradient = remember(colors) {
        BrushPainter(Brush.linearGradient(listOf(colors.warning.color, colors.danger.color, colors.primary.color)))
    }
    PantrixImage(painter = gradient, contentScale = ContentScale.Crop, contentDescription = null)
}

An avatar with an icon, and an empty one

An avatar without initials draws its icon: a person, a group, a company. Like the letters, the icon is drawn in the colour that reads on the tone.

The second is given neither letters nor an icon: it is a plain circle filled with its tone's colour. Its description still says its name.

Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixAvatar(contentDescription = "Shared account", icon = PantrixIcons.Person, tagKey = "shared")
    PantrixAvatar(contentDescription = "Unknown person", tagKey = "unknown")
}

An avatar with corners

An avatar is a circle on every platform. style changes the style of this avatar alone: AvatarStyle(shape = ...) takes the corners to a step of the theme's shape scale. Here a folder's avatar and a company's are drawn with corners, by ShapeRole.Medium.

Only the field that is set changes: the size and the letters' share come from the theme's style.

val rounded = AvatarStyle(shape = ShapeRole.Medium)
Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixAvatar(
        contentDescription = "Documents",
        icon = PantrixIcons.Folder,
        tone = AvatarTone.Info,
        style = rounded
    )
    PantrixAvatar(
        contentDescription = "Pantrix A.Ş.",
        initials = "PX",
        tone = AvatarTone.Primary,
        style = rounded,
        tagKey = "company"
    )
}

A transparent logo

A picture that is transparent in places shows what is under it. Such a picture is given alone, without initials or an icon: behind this logo there is only the tone's colour.

PantrixAvatar(contentDescription = "Compose Multiplatform", tone = AvatarTone.Primary, tagKey = "logo") {
    PantrixImage(painter = painterResource(Res.drawable.compose_multiplatform), contentDescription = null)
}

A colour of its own

colors gives the avatar a fill of the given colour, not of a tone: a team's own colour, say, or a label's. The first avatar's colour is in none of the theme's roles; both its fill and the colour of its letters are given, because only whoever gives a fill the theme does not know can tell what reads on it.

The second is given a fill alone, and that fill is one of the theme's own colours, success.container. The letters take the colour the theme pairs with that fill, without it being given.

val own = ownColors()
Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixAvatar(
        contentDescription = "Design team",
        initials = "DT",
        colors = AvatarColors(container = own.color, content = own.onColor),
        tagKey = "team"
    )
    PantrixAvatar(
        contentDescription = "Support team",
        initials = "ST",
        colors = AvatarColors(container = PantrixTheme.colors.success.container),
        tagKey = "support_team"
    )
}

API

contentDescription

The picture of a person or a thing: a photograph, the initials of a name, or an icon standing for either.

ParameterTypeDefaultWhat it is
contentDescriptionString?what a screen reader says for the avatar, usually the name it stands for, or null to hide the avatar from it.
modifierModifierModifierthe avatar's modifier. A size given here goes over size.
initialsString?nullthe letters to draw, usually one or two. More than two are cut, and none leaves the icon.
iconImageVector?nullwhat is drawn where there are no initials: a person, a group, a company.
toneAvatarToneAvatarTone.Neutralthe colour under the initials or the icon, and theirs. A picture covers it.
colorsAvatarColors?nullthis avatar's own colours, in place of its tone's: the ones it sets, with the tone's for the rest.
styleAvatarStyle?nullthis call's own style: over every enclosing one and under the density. Only the fields it sets change, on every platform.
sizeDpPantrixTheme.style(AvatarStyle, style).sizethe avatar's width and height: the style's unless given.
tagKeyString?nullthe avatar's automation key: it is Avatar_<tagKey>, and is tagged only when given one.
image(@Composable () -> Unit)?nulla picture that fills the avatar, over the initials or the icon. What it says of itself is not read: the avatar's description stands for both.

AvatarStyle

PantrixAvatar's geometry: how large it is, what its corners are, and how much of it the initials or the icon take.

ParameterTypeDefaultWhat it is
sizeDpDp.UnspecifiedThe avatar's width and height.
shapeShapeSpecShapeSpec.UnspecifiedThe avatar's corners: the round end of the brand's shape scale, a circle, unless a brand or a theme asks for a step of it or a shape of its own.
initialsScaleFloatFloat.NaNThe height the initials are set in, as a fraction of the avatar's shorter side.
iconScaleFloatFloat.NaNThe icon's width and height, as a fraction of the avatar's shorter side.

AvatarColors

What PantrixAvatar is painted with, for an avatar that does not take its tone's colours: a colour that is set is used, and one that is left out stays the tone's.

ParameterTypeDefaultWhat it is
containerColorColor.UnspecifiedThe fill under the initials or the icon, which a picture covers. The color of the tone's role.
contentColorColor.UnspecifiedThe initials or the icon: the colour that reads on container. The onColor of the tone's role.

Accessibility