Pantrix UI

Page Jump

Goes to a page of a long list by its number: the words "Go to page" and, beside them, a short field the number is typed in.

import com.pantrixui.components.data.pagination.PantrixPageJump

Examples

In a table's foot: page size and go to page

A table's foot: PantrixPageSize chooses how many orders a page shows, PantrixPagination moves between the pages, and PantrixPageJump goes to the page whose number is typed. The three are in a FlowRow: where there is room they stand side by side, and in a narrow place the one that does not fit goes down to the next line; on a phone held upright the three stand one under another. A Row does not take what does not fit down a line: it squeezes the last one into the room that is left. The three may not be the same height: itemVerticalAlignment lines them up by their middles.

All three read the screen's state, and none knows of the others. Change the page size: forty-eight orders make sixteen pages three at a time, and five pages ten at a time; the row's numbers and the number of digits the field takes follow the new number of pages. As the size changes the first order shown stays on screen: the page that is opened is the one that order falls on at the new size. On the fourth page, with orders 16–20 shown, choose 10: the second page comes, orders 11–20. For forty-eight orders the sizes are small: 3 and 5, before the first of the ready sizes (DefaultPageSizes), 10.

Type a number in the field and press Enter: that page is opened, the field is emptied and the focus stays in the field. A number larger than the last page opens the last page; the field takes nothing but digits. The page that was asked for, whatever asked for it, is written on the card's "Last event" line.

val report = LocalExampleEvents.current
var pageSize by rememberSaveable { mutableIntStateOf(ORDERS_PER_PAGE) }
var page by rememberSaveable { mutableIntStateOf(1) }
val pageCount = (ORDER_COUNT + pageSize - 1) / pageSize
val first = (page - 1) * pageSize + 1
val last = minOf(page * pageSize, ORDER_COUNT)
val open: (Int) -> Unit = { asked ->
    page = asked
    report("Page $asked was asked for")
}
OrderRows(first = first, last = last, rows = pageSize, tagKey = "row")
PantrixText(
    text = "$first–$last of $ORDER_COUNT orders",
    color = PantrixTheme.colors.textSecondary,
    tagKey = "foot_shown"
)
FlowRow(
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.lg),
    verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
    itemVerticalAlignment = Alignment.CenterVertically
) {
    PantrixPageSize(
        pageSize = pageSize,
        onPageSizeChange = { size ->
            // The page that is opened is the one the first order shown falls on at the new size: the order stays on screen.
            val kept = (first - 1) / size + 1
            pageSize = size
            page = kept
            report("$size orders to a page: page $kept was opened")
        },
        pageSizes = listOf(3, 5) + DefaultPageSizes.first(),
        tagKey = "foot"
    )
    PantrixPagination(page = page, pageCount = pageCount, onPageChange = open, tagKey = "foot")
    PantrixPageJump(pageCount = pageCount, onPageChange = open, tagKey = "foot")
}

@Composable
private fun OrderRows(
    first: Int,
    last: Int,
    rows: Int,
    tagKey: String
) {
    PantrixSurface(modifier = Modifier.fillMaxWidth(), border = PantrixTheme.colors.divider) {
        Column {
            for (order in first until first + rows) {
                val listed = order <= last
                // The line of an empty row keeps its place too, but is not drawn.
                val line = if (listed) Color.Unspecified else Color.Transparent
                if (order > first) PantrixHorizontalDivider(color = line)
                Row(
                    modifier = Modifier.fillMaxWidth().padding(PantrixTheme.spacing.md),
                    horizontalArrangement = Arrangement.SpaceBetween
                ) {
                    if (listed) {
                        PantrixText(text = "Order #${FIRST_ORDER + order}", tagKey = "${tagKey}_$order")
                        PantrixText(text = "Items: ${1 + order % 4}", color = PantrixTheme.colors.textSecondary)
                    } else {
                        // An empty text is a line tall too; it has nothing to say to a screen reader.
                        PantrixText(text = "", role = TextRole.Decorative)
                    }
                }
            }
        }
    }
}

private const val ORDER_COUNT = 48

private const val ORDERS_PER_PAGE = 5

private const val FIRST_ORDER = 4800

API

pageCount

Goes to a page of a long list by its number: the words "Go to page" and, beside them, a short field the number is typed in.

ParameterTypeDefaultWhat it is
pageCountInthow many pages there are: the last page a number is taken as, and how many digits the field holds. A count under one is taken as one, as PantrixPagination takes it.
onPageChange(page: Int) -> Unittold the page that was asked for, by its number, counted from one.
modifierModifierModifierapplied to the row.
labelStringPantrixTheme.strings.goToPagethe words before the field, and the field's name for a screen reader: the theme's "Go to page" unless given.
enabledBooleantruewhether a number can be typed: a row that cannot be used has its words in the disabled text colour and a field that is disabled, which takes no focus and says so.
tagKeyString?nulla locale-independent key for automation: the row's tag is PageJump_<tagKey> and its words are PageJump_<tagKey>.Text_label. The field in it has the key <tagKey>_page_jump, and is tagged as a text field is: TextField_<tagKey>_page_jump. A key too long for a tag is cut, and _page_jump is kept whole. A page that is asked for is reported as PageJump, with the page and never with what was typed. That the field took the focus is reported as PageJump too, with the row's tag: the row is one component, and reports under one name.

Accessibility