Revision control
Copy as Markdown
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
package org.mozilla.fenix.compose
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
import org.mozilla.fenix.theme.FirefoxTheme
/**
* Special caption text for a tab layout shown on one line.
*
* This will combine [firstText] with a interdot and then [secondText] ensuring that the second text
* (which is assumed to be smaller) always fills as much space as needed with the [firstText] automatically
* being resized to be smaller with an added ellipsis characters if needed.
*
* Possible results:
* ```
* - when both texts would fit the screen
* ------------------------------------------
* |firstText · secondText |
* ------------------------------------------
*
* - when both text do not fit, second is shown in entirety, first is ellipsised.
* ------------------------------------------
* |longerFirstTextOrSmallSc... · secondText|
* ------------------------------------------
* ```
*
* @param firstText Text shown at the start of the row.
* @param secondText Text shown at the end of the row.
*/
@Composable
fun TabSubtitleWithInterdot(
firstText: String,
secondText: String,
) {
val currentLayoutDirection = LocalLayoutDirection.current
Layout(
content = {
Text(
text = firstText,
color = FirefoxTheme.colors.textSecondary,
fontSize = 12.sp,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
Text(
text = " \u00b7 ",
color = FirefoxTheme.colors.textSecondary,
fontSize = 12.sp,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
Text(
text = secondText,
color = FirefoxTheme.colors.textSecondary,
fontSize = 12.sp,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
},
) { items, constraints ->
// We need to measure from the end to start to ensure the secondItem will always be on screen
// and depending on secondItem's width and interdot's width the firstItem is automatically resized.
val secondItem = items[2].measure(constraints)
val interdot = items[1].measure(
constraints.copy(maxWidth = constraints.maxWidth - secondItem.width),
)
val firstItem = items[0].measure(
constraints.copy(maxWidth = constraints.maxWidth - secondItem.width - interdot.width),
)
layout(constraints.maxWidth, constraints.maxHeight) {
val itemsPositions = IntArray(items.size)
with(Arrangement.Start) {
arrange(
constraints.maxWidth,
intArrayOf(firstItem.width, interdot.width, secondItem.width),
currentLayoutDirection,
itemsPositions,
)
}
val placementHeight = constraints.maxHeight - firstItem.height
listOf(firstItem, interdot, secondItem).forEachIndexed { index, item ->
item.place(itemsPositions[index], placementHeight)
}
}
}
}
@Composable
@Preview
private fun TabSubtitleWithInterdotPreview() {
FirefoxTheme {
Box(Modifier.background(FirefoxTheme.colors.layer2)) {
TabSubtitleWithInterdot(
firstText = "firstText",
secondText = "secondText",
)
}
}
}