Pantrix UI

Elastic Date Picker

Saatle birlikte kayabilen bir zaman aralığı; bir pano onunla süzülür: "son 15 dakika" bir sonraki yenilemede yine son 15 dakikadır. Elastic UI'ın EuiSuperDatePicker'ı, Pantrix üzerinde yeniden.

import com.pantrixui.components.date.elasticdatepicker.PantrixElasticDatePicker

Örnekler

Son kullanılanlarla bir pano

Bir panonun son 15 dakikası. Seçilen aralıklar hızlı menünün "Son kullanılanlar"ında birikir; Yenile bir yüklemeyi bir saniye sürdürür ve düğme bu sürede döner. Altında aralığın şimdi düştüğü iki an ve son yenilemenin saati.

var range by remember { mutableStateOf(LAST_QUARTER) }
var refreshed by remember { mutableStateOf<Instant?>(null) }
val report = LocalExampleEvents.current
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = {
            range = it
            refreshed = Clock.System.now()
            report("Aralık seçildi")
        },
        recentlyUsed = rememberRecentRanges(),
        onRefresh = {
            delay(LOADING_MILLIS)
            refreshed = Clock.System.now()
            report("Yenilendi")
        },
        tagKey = "dashboard"
    )
    Resolved(range)
    refreshed?.let { PantrixText(text = "Son yenileme: ${moment(it)}", style = PantrixTheme.typography.footnote) }
}

@Composable
private fun Resolved(range: PantrixTimeRange) {
    val read = range.resolve()
    PantrixText(
        text = read?.let { "${moment(it.start)} – ${moment(it.endInclusive)}" } ?: "Son, başlangıçtan önce",
        style = PantrixTheme.typography.footnote,
        color = PantrixTheme.colors.textSecondary
    )
}

@Composable
private fun moment(at: Instant): String {
    val strings = PantrixTheme.strings
    val day = PantrixDate.of(at)
    val time = PantrixTime.of(at)
    return "${strings.date(day.day, day.month, day.year)} ${strings.clock(time.hour, time.minute, time.second)}"
}

private val LAST_QUARTER = last(15, PantrixTimeUnit.Minutes)

private const val LOADING_MILLIS = 1000L

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

Güncelle düğmesi: sözlü, yalnız simge, düğmesiz

Yandaki düğmenin üç hâli. Sözlü düğme bir düzenleme beklerken Güncelle der; yalnız simge aynı işi daha az yerle yapar; düğmesiz seçicide bir uçtaki her düzenleme hemen verilir. Bir ucu değiştirip farkı görün.

var button by remember { mutableStateOf(ElasticDatePickerUpdateButton.Text) }
var range by remember { mutableStateOf(LAST_QUARTER) }
val report = LocalExampleEvents.current
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixSegmentButton(
        options = listOf(
            SegmentOption(ElasticDatePickerUpdateButton.Text, "Sözlü", tagKey = "text"),
            SegmentOption(ElasticDatePickerUpdateButton.Icon, "Yalnız simge", tagKey = "icon"),
            SegmentOption(ElasticDatePickerUpdateButton.None, "Düğmesiz", tagKey = "none")
        ),
        selected = button,
        onSelect = { button = it },
        fullWidth = false,
        tagKey = "update_button"
    )
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = {
            range = it
            report("Aralık verildi")
        },
        updateButton = button,
        tagKey = "update"
    )
    Resolved(range)
}

@Composable
private fun Resolved(range: PantrixTimeRange) {
    val read = range.resolve()
    PantrixText(
        text = read?.let { "${moment(it.start)} – ${moment(it.endInclusive)}" } ?: "Son, başlangıçtan önce",
        style = PantrixTheme.typography.footnote,
        color = PantrixTheme.colors.textSecondary
    )
}

private val LAST_QUARTER = last(15, PantrixTimeUnit.Minutes)

@Composable
private fun moment(at: Instant): String {
    val strings = PantrixTheme.strings
    val day = PantrixDate.of(at)
    val time = PantrixTime.of(at)
    return "${strings.date(day.day, day.month, day.year)} ${strings.clock(time.hour, time.minute, time.second)}"
}

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

Popover, sheet ya da dialog

Panellerin neyde açılacağı her platformda aynıdır: presentation = Popover ile parçanın yanında bir popover, presentation = Sheet ile ekranın kenarından gelen bir sheet, presentation = Dialog ile pencerenin ortasında, panel kadar geniş bir dialog. Varsayılan Adaptive: dar bir pencerede sheet, daha genişte popover; karttaki pencere seçicisinden "Dar" ile "Geniş" arasında geç. Hiçbirinin üstünde başlık yoktur. Hızlı menü, başlangıç ve bitiş üçü de seçilen biçimde açılır.

var presentation by remember { mutableStateOf(DatePickerPresentation.Sheet) }
val today = PantrixQuickRange.commonlyUsed(PantrixTheme.strings).first().range
var range by remember { mutableStateOf(today) }
// Kartın penceresi örnek kadar uzundur: dar bir pencerede açılan sheet'e yer kalsın diye örnek uzun tutulur.
Column(
    modifier = Modifier.fillMaxWidth().height(480.dp),
    verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)
) {
    PantrixSegmentButton(
        options = listOf(
            SegmentOption(DatePickerPresentation.Popover, "Popover", tagKey = "popover"),
            SegmentOption(DatePickerPresentation.Sheet, "Sheet", tagKey = "sheet"),
            SegmentOption(DatePickerPresentation.Dialog, "Dialog", tagKey = "dialog"),
            SegmentOption(DatePickerPresentation.Adaptive, "Uyarlanır", tagKey = "adaptive")
        ),
        selected = presentation,
        onSelect = { presentation = it },
        fullWidth = false,
        tagKey = "presentation"
    )
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        presentation = presentation,
        tagKey = "presentation"
    )
}

Hızlı menünün kendi aralıkları

Hızlı menünün aralıkları uygulamanındır: burada Elastic UI'ın sekizi yerine son 15 dakikadan son bir yıla yedi aralık. "Son kullanılanlar"ı açıp kapatmak listeyi gösterir ya da gizler; adı olan bir aralık alanda adıyla durur.

val ranges = remember {
    listOf(
        PantrixQuickRange("Son 15 dakika", last(15, PantrixTimeUnit.Minutes)),
        PantrixQuickRange("Son 1 saat", last(1, PantrixTimeUnit.Hours)),
        PantrixQuickRange("Son 24 saat", last(24, PantrixTimeUnit.Hours)),
        PantrixQuickRange("Son 7 gün", last(7, PantrixTimeUnit.Days)),
        PantrixQuickRange("Son 30 gün", last(30, PantrixTimeUnit.Days)),
        PantrixQuickRange("Son 90 gün", last(90, PantrixTimeUnit.Days)),
        PantrixQuickRange("Son 1 yıl", last(1, PantrixTimeUnit.Years))
    )
}
var range by remember { mutableStateOf(ranges[4].range) }
var showRecent by remember { mutableStateOf(true) }
val recent = rememberRecentRanges(max = 5)
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixSwitchButton(
        checked = showRecent,
        onCheckedChange = { showRecent = it },
        label = "Son kullanılanlar",
        tagKey = "show_recent"
    )
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        commonlyUsed = ranges,
        recentlyUsed = recent.takeIf { showRecent },
        tagKey = "own_ranges"
    )
}

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

Genişlik ve boy

Seçici verilen genişliği style'ın maxWidth'ine kadar doldurur (varsayılan 560dp, Elastic UI'ın "restricted"ı). maxWidth = Dp.Infinity tam genişlik verir; dar bir yerde yandaki sözlü düğme yalnız simgesine iner; height ile alan sıkışık olur.

var range by remember { mutableStateOf(SINCE_YESTERDAY) }
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md)) {
    PantrixText(text = "Varsayılan (560dp'ye kadar)", style = PantrixTheme.typography.footnote)
    PantrixElasticDatePicker(range = range, onRangeChange = { range = it }, tagKey = "restricted")
    PantrixText(text = "Tam genişlik", style = PantrixTheme.typography.footnote)
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        style = ElasticDatePickerStyle(maxWidth = Dp.Infinity),
        tagKey = "full"
    )
    PantrixText(text = "Dar bir yerde (320dp)", style = PantrixTheme.typography.footnote)
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        modifier = Modifier.width(NARROW_WIDTH),
        tagKey = "narrow"
    )
    PantrixText(text = "Sıkışık (32dp)", style = PantrixTheme.typography.footnote)
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        style = ElasticDatePickerStyle(height = COMPRESSED_HEIGHT),
        tagKey = "compressed"
    )
}

private val SINCE_YESTERDAY = PantrixTimeRange(
    PantrixTimePoint.Relative(-1, PantrixTimeUnit.Days, roundTo = PantrixTimeUnit.Days),
    PantrixTimePoint.Now
)

private val NARROW_WIDTH = 320.dp

private val COMPRESSED_HEIGHT = 32.dp

Yükleniyor ve kapalı

Bir yükleme ve seçim almayan bir seçici. Yüklenirken yandaki düğme döner ve basılmaz; kapalı bir seçici soluk çizilir ve hiçbir panel açmaz.

var range by remember { mutableStateOf(LAST_HOUR) }
var loading by remember { mutableStateOf(true) }
var enabled by remember { mutableStateOf(true) }
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixSwitchButton(
        checked = loading,
        onCheckedChange = { loading = it },
        label = "Yükleniyor",
        tagKey = "loading"
    )
    PantrixSwitchButton(
        checked = enabled,
        onCheckedChange = { enabled = it },
        label = "Etkin",
        tagKey = "enabled"
    )
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        loading = loading,
        enabled = enabled,
        tagKey = "states"
    )
}

private val LAST_HOUR = last(1, PantrixTimeUnit.Hours)

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

Seçilebilen günler

Takvim yalnızca bu ayın günlerini sunar (minDate ve maxDate): bir ucun Mutlak sekmesinde ayın dışındaki günler soluk ve seçilemez. Göreli bir uç sınırlardan etkilenmez.

val today = rememberToday()
val first = PantrixDate(today.year, today.month, 1)
val last = first.plusMonths(1).plusDays(-1)
var range by remember {
    mutableStateOf(PantrixTimeRange(PantrixTimePoint.Absolute(first.at(PantrixTime(0, 0))), PantrixTimePoint.Now))
}
PantrixElasticDatePicker(
    range = range,
    onRangeChange = { range = it },
    minDate = first,
    maxDate = last,
    tagKey = "bounds"
)

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

Saat düzeni, haftanın başı ve birimler

Anların yazılışı ve okunuşu: 12 ya da 24 saat (is24Hour), haftanın ilk günü (firstDayOfWeek, /w yuvarlamasını da belirler) ve göreli bir ucun en iyi okunan birime konup konmaması (roundRelativeUnits: 90 dakika "~ 2 saat önce" ya da "90 dakika önce"). Dil, sayfanın dil düğmesinden.

var is24Hour by remember { mutableStateOf(true) }
var mondayFirst by remember { mutableStateOf(true) }
var roundUnits by remember { mutableStateOf(true) }
var range by remember { mutableStateOf(NINETY_TO_THIRTY_AGO) }
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixSwitchButton(checked = is24Hour, onCheckedChange = { is24Hour = it }, label = "24 saat", tagKey = "clock")
    PantrixSwitchButton(
        checked = mondayFirst,
        onCheckedChange = { mondayFirst = it },
        label = "Hafta pazartesi başlar",
        tagKey = "monday"
    )
    PantrixSwitchButton(
        checked = roundUnits,
        onCheckedChange = { roundUnits = it },
        label = "Birimleri yuvarla",
        tagKey = "round"
    )
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        roundRelativeUnits = roundUnits,
        firstDayOfWeek = if (mondayFirst) 1 else SUNDAY,
        is24Hour = is24Hour,
        tagKey = "clock"
    )
}

private val NINETY_TO_THIRTY_AGO = PantrixTimeRange(
    PantrixTimePoint.Relative(-90, PantrixTimeUnit.Minutes),
    PantrixTimePoint.Relative(-30, PantrixTimeUnit.Minutes)
)

private const val SUNDAY = 7

Adresteki tarih matematiği

Aralık bir adreste tarih matematiği olarak durur: from ve to her seçimde yeniden yazılır. Alanlara bir uç yazılıp Uygula'ya basılınca aralık oradan okunur; okunamayan bir uç alanı hatalı çizer.

var range by remember { mutableStateOf(SINCE_YESTERDAY) }
val written = range.toDateMath()
var from by remember(written) { mutableStateOf(written.first) }
var to by remember(written) { mutableStateOf(written.second) }
val start = PantrixTimePoint.parseDateMath(from)
val end = PantrixTimePoint.parseDateMath(to)
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixElasticDatePicker(range = range, onRangeChange = { range = it }, tagKey = "url")
    PantrixText(text = "?from=${written.first}&to=${written.second}", style = PantrixTheme.typography.footnote)
    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
        verticalAlignment = Alignment.Bottom
    ) {
        PantrixTextField(
            value = from,
            onValueChange = { from = it },
            modifier = Modifier.weight(1f),
            label = "from",
            error = start == null,
            showCharacterCount = false,
            tagKey = "from"
        )
        PantrixTextField(
            value = to,
            onValueChange = { to = it },
            modifier = Modifier.weight(1f),
            label = "to",
            error = end == null,
            showCharacterCount = false,
            tagKey = "to"
        )
    }
    PantrixButton(
        text = "Uygula",
        onClick = { if (start != null && end != null) range = PantrixTimeRange(start, end) },
        variant = ButtonVariant.Outline,
        enabled = start != null && end != null,
        tagKey = "read"
    )
}

private val SINCE_YESTERDAY = PantrixTimeRange(
    PantrixTimePoint.Relative(-1, PantrixTimeUnit.Days, roundTo = PantrixTimeUnit.Days),
    PantrixTimePoint.Now
)

Kendi renkleri

Alanın kendi renkleri: zemin, kenar, sözler ve ikonlar, açık ucun kenarı, bekleyen düzenlemenin ve sırası bozuk uçların renkleri. Verilmeyen her renk temanınkidir. Bir ucu değiştirip bekleyen renge bakın.

var range by remember { mutableStateOf(LAST_QUARTER) }
val colors = PantrixTheme.colors
PantrixElasticDatePicker(
    range = range,
    onRangeChange = { range = it },
    colors = ElasticDatePickerColors(
        container = colors.neutral.container,
        border = colors.neutral.color,
        active = colors.warning.color,
        pendingContainer = colors.info.container,
        pendingContent = colors.info.onContainer
    ),
    tagKey = "colors"
)

private val LAST_QUARTER = last(15, PantrixTimeUnit.Minutes)

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

Otomatik yenileme

Pano kendini her on saniyede yeniler: alanın sonunda ne sıklıkla olduğu kısaca yazar, ona basmak hızlı menüyü açar. Menünün "Yenileme aralığı" bölümü onu açar, kapatır ve sıklığını değiştirir; beş saniyeden kısası alınmaz (minAutoRefresh). Her turda onRefresh çalışır ve bir sonraki tur onun bitmesini bekler.

var range by remember { mutableStateOf(LAST_QUARTER) }
var refresh by remember { mutableStateOf(PantrixAutoRefresh(every = 10, paused = false)) }
var count by remember { mutableStateOf(0) }
val report = LocalExampleEvents.current
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        onRefresh = {
            count++
            report("Yenilendi")
        },
        tagKey = "auto_refresh",
        autoRefresh = refresh,
        onAutoRefreshChange = {
            refresh = it
            report(if (it.paused) "Otomatik yenileme durdu" else "Otomatik yenileme değişti")
        },
        minAutoRefresh = 5.seconds
    )
    PantrixText(text = "Yenileme sayısı: $count", style = PantrixTheme.typography.footnote)
}

private val LAST_QUARTER = last(15, PantrixTimeUnit.Minutes)

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

Yalnız otomatik yenileme

Zaman verisi olmayan bir sayfa için yalnız otomatik yenileme (layout = AutoRefreshOnly): alan "Otomatik yenileme" ve ne sıklıkla ya da kapalı olduğunu söyler, basınca yalnız onu ayarlayan menü açılır. Sıklık burada dakikayla verildi (unit = AutoRefreshUnit.Minutes): dakikada bir.

var refresh by remember { mutableStateOf(PantrixAutoRefresh(every = 1, unit = AutoRefreshUnit.Minutes)) }
var count by remember { mutableStateOf(0) }
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixElasticDatePicker(
        range = LAST_QUARTER,
        onRangeChange = { count++ },
        tagKey = "auto_refresh_only",
        autoRefresh = refresh,
        onAutoRefreshChange = { refresh = it },
        layout = ElasticDatePickerLayout.AutoRefreshOnly
    )
    PantrixText(text = "Yenileme sayısı: $count", style = PantrixTheme.typography.footnote)
}

private val LAST_QUARTER = last(15, PantrixTimeUnit.Minutes)

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

Yalnız hızlı seçim

Aralığın başka bir yerde gösterildiği bir sayfa için yalnız hızlı menünün düğmesi ve yanındaki düğme (layout = QuickSelectOnly). Seçilen aralık altta yazar.

var range by remember { mutableStateOf(LAST_QUARTER) }
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        tagKey = "quick_select_only",
        layout = ElasticDatePickerLayout.QuickSelectOnly
    )
    Resolved(range)
}

@Composable
private fun Resolved(range: PantrixTimeRange) {
    val read = range.resolve()
    PantrixText(
        text = read?.let { "${moment(it.start)} – ${moment(it.endInclusive)}" } ?: "Son, başlangıçtan önce",
        style = PantrixTheme.typography.footnote,
        color = PantrixTheme.colors.textSecondary
    )
}

private val LAST_QUARTER = last(15, PantrixTimeUnit.Minutes)

@Composable
private fun moment(at: Instant): String {
    val strings = PantrixTheme.strings
    val day = PantrixDate.of(at)
    val time = PantrixTime.of(at)
    return "${strings.date(day.day, day.month, day.year)} ${strings.clock(time.hour, time.minute, time.second)}"
}

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

Zaman penceresi düğmeleri

Alanın yanında Elastic UI'ın zaman penceresi düğmeleri: ‹ ve › aralığı kendi uzunluğu kadar kaydırır, uzaklaştırma onu uzunluğunun zoomFactor kadarıyla genişletir, yakınlaştırma aynı kadar daraltır; yakınlaştırma istenmedikçe yoktur. Verdikleri aralık anlardan oluşur.

var range by remember { mutableStateOf(LAST_HOUR) }
var zoomIn by remember { mutableStateOf(false) }
var factor by remember { mutableStateOf(HALF) }
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixSwitchButton(checked = zoomIn, onCheckedChange = { zoomIn = it }, label = "Yakınlaştır", tagKey = "zoom_in")
    PantrixSegmentButton(
        options = listOf(
            SegmentOption(HALF, "Yarısı (0.5)", tagKey = "half"),
            SegmentOption(QUARTER, "Çeyreği (0.25)", tagKey = "quarter")
        ),
        selected = factor,
        onSelect = { factor = it },
        fullWidth = false,
        tagKey = "zoom_factor"
    )
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        tagKey = "time_window",
        timeWindowButtons = ElasticTimeWindowButtons(zoomIn = zoomIn, zoomFactor = factor)
    )
    Resolved(range)
}

@Composable
private fun Resolved(range: PantrixTimeRange) {
    val read = range.resolve()
    PantrixText(
        text = read?.let { "${moment(it.start)} – ${moment(it.endInclusive)}" } ?: "Son, başlangıçtan önce",
        style = PantrixTheme.typography.footnote,
        color = PantrixTheme.colors.textSecondary
    )
}

private val LAST_HOUR = last(1, PantrixTimeUnit.Hours)

private const val HALF = 0.5

private const val QUARTER = 0.25

@Composable
private fun moment(at: Instant): String {
    val strings = PantrixTheme.strings
    val day = PantrixDate.of(at)
    val time = PantrixTime.of(at)
    return "${strings.date(day.day, day.month, day.year)} ${strings.clock(time.hour, time.minute, time.second)}"
}

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

Hızlı menünün kendi panelleri ve sırası

Hızlı menüde uygulamanın kendi paneli (customQuickPanels), varsayılan olarak son kullanılanlardan sonra. "Kendi sıram" menüyü quickMenu ile kurar: önce kayıtlı aralıklar, sonra hızlı seçim; adıyla sunulan aralıklar yok. Menünün parçaları ElasticQuickMenuScope'tadır: quickMenu o kapsamda çağrılır.

var range by remember { mutableStateOf(LAST_QUARTER) }
var own by remember { mutableStateOf(false) }
val saved = remember {
    listOf(
        "Gece vardiyası" to PantrixTimeRange(
            PantrixTimePoint.Relative(-1, PantrixTimeUnit.Days, roundTo = PantrixTimeUnit.Days),
            PantrixTimePoint.Relative(-16, PantrixTimeUnit.Hours)
        ),
        "Son dağıtımdan beri" to last(3, PantrixTimeUnit.Hours)
    )
}
val panel = ElasticQuickPanel("Kayıtlı aralıklar") {
    Column {
        saved.forEachIndexed { index, (name, kept) ->
            PantrixLink(text = name, onClick = { range = kept }, tagKey = "saved_$index")
        }
    }
}
val ownMenu: @Composable ElasticQuickMenuScope.() -> Unit = {
    CustomPanels()
    QuickSelect()
}
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixSegmentButton(
        options = listOf(
            SegmentOption(false, "Elastic UI'ın sırası", tagKey = "elastic"),
            SegmentOption(true, "Kendi sıram", tagKey = "own")
        ),
        selected = own,
        onSelect = { own = it },
        fullWidth = false,
        tagKey = "order"
    )
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        tagKey = "quick_panels",
        customQuickPanels = listOf(panel),
        quickMenu = if (own) ownMenu else null
    )
    Resolved(range)
}

@Composable
private fun Resolved(range: PantrixTimeRange) {
    val read = range.resolve()
    PantrixText(
        text = read?.let { "${moment(it.start)} – ${moment(it.endInclusive)}" } ?: "Son, başlangıçtan önce",
        style = PantrixTheme.typography.footnote,
        color = PantrixTheme.colors.textSecondary
    )
}

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

private val LAST_QUARTER = last(15, PantrixTimeUnit.Minutes)

@Composable
private fun moment(at: Instant): String {
    val strings = PantrixTheme.strings
    val day = PantrixDate.of(at)
    val time = PantrixTime.of(at)
    return "${strings.date(day.day, day.month, day.year)} ${strings.clock(time.hour, time.minute, time.second)}"
}

Saat dilimi

Anlar seçilen saat diliminin farkıyla okunur ve yazılır (utcOffset); uçların panelleri dilimi adıyla ve UTC'den farkıyla söyler (timeZoneName). Ad yalnızca söyler, bir şey değiştirmez.

var range by remember { mutableStateOf(SINCE_YESTERDAY) }
var zone by remember { mutableStateOf(ZONES.first()) }
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixSegmentButton(
        options = ZONES.mapIndexed { index, it -> SegmentOption(it, it.first, tagKey = "zone_$index") },
        selected = zone,
        onSelect = { zone = it },
        fullWidth = false,
        tagKey = "zone"
    )
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        tagKey = "time_zone",
        timeZoneName = zone.first,
        utcOffset = { zone.second }
    )
}

private val SINCE_YESTERDAY = PantrixTimeRange(
    PantrixTimePoint.Relative(-1, PantrixTimeUnit.Days, roundTo = PantrixTimeUnit.Days),
    PantrixTimePoint.Now
)

private val ZONES = listOf("Europe/Istanbul" to 3.hours, "Asia/Tokyo" to 9.hours, "UTC" to Duration.ZERO)

Kapalı ve kendi yazısı

Seçim almayan bir seçici aralığı yerine kendi yazısını gösterebilir (disabledText), Elastic UI'ın isDisabled.display'i gibi: burada "Tüm zamanlar".

var words by remember { mutableStateOf(true) }
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
    PantrixSwitchButton(checked = words, onCheckedChange = { words = it }, label = "Kendi yazısı", tagKey = "words")
    PantrixElasticDatePicker(
        range = LAST_QUARTER,
        onRangeChange = {},
        enabled = false,
        tagKey = "disabled_text",
        disabledText = if (words) "Tüm zamanlar" else null
    )
}

private val LAST_QUARTER = last(15, PantrixTimeUnit.Minutes)

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

KQL deseni

Elastic UI'ın KQL deseni: bir arama alanının yanında seçici. Arama alanı odaktayken seçici hızlı menünün düğmesine küçülür (layout = QuickSelectOnly) ve yer sorguya kalır; odak gidince aralık geri gelir.

var range by remember { mutableStateOf(LAST_QUARTER) }
var query by remember { mutableStateOf("") }
var searching by remember { mutableStateOf(false) }
Row(
    modifier = Modifier.fillMaxWidth(),
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
    verticalAlignment = Alignment.CenterVertically
) {
    PantrixTextField(
        value = query,
        onValueChange = { query = it },
        modifier = Modifier.weight(1f).onFocusChanged { searching = it.hasFocus },
        placeholder = "KQL ile ara",
        showCharacterCount = false,
        contentDescription = "Arama sorgusu",
        tagKey = "query"
    )
    PantrixElasticDatePicker(
        range = range,
        onRangeChange = { range = it },
        modifier = if (searching) Modifier else Modifier.weight(PICKER_SHARE),
        updateButton = ElasticDatePickerUpdateButton.Icon,
        tagKey = "query_range",
        layout = if (searching) ElasticDatePickerLayout.QuickSelectOnly else ElasticDatePickerLayout.Full
    )
}

private val LAST_QUARTER = last(15, PantrixTimeUnit.Minutes)

private const val PICKER_SHARE = 1.4f

private fun last(
    amount: Int,
    unit: PantrixTimeUnit
): PantrixTimeRange = PantrixTimeRange(PantrixTimePoint.Relative(-amount, unit), PantrixTimePoint.Now)

API

range

Saatle birlikte kayabilen bir zaman aralığı; bir pano onunla süzülür: "son 15 dakika" bir sonraki yenilemede yine son 15 dakikadır. Elastic UI'ın EuiSuperDatePicker'ı, Pantrix üzerinde yeniden.

ParametreTürVarsayılanNe olduğu
rangePantrixTimeRangegösterilen aralık. Uçları şimdiye göre olabilir.
onRangeChange(PantrixTimeRange) -> Unitokurun hızlı menüden seçtiği ya da bir düzenlemeden sonra güncellediği aralığı, onRefresh yokken bir yenilemede aynı aralığı alır.
modifierModifierModifierseçicinin modifier'ı. Seçici verilen genişliği style'ın maxWidth'ine kadar doldurur.
commonlyUsedList<PantrixQuickRange>PantrixQuickRange.commonlyUsed(PantrixTheme.strings)hızlı menünün adıyla sunduğu aralıklar: varsayılan Elastic UI'ın sekizi, temanın dilinde. Gösterilen aralık bunlardan biriyse adıyla anılır.
recentlyUsedPantrixRecentRanges?nullokurun son seçtiği aralıklar; hızlı menü onları listeler ve okurun uyguladığı her aralık onlara kaydedilir; hiçbiri için null. rememberRecentRanges() onları bir yapılandırma değişikliğinde korur.
updateButtonElasticDatePickerUpdateButtonElasticDatePickerUpdateButton.Textalanın yanındaki düğme: sözü ve simgesi, yalnız simgesi ya da hiç; o zaman her düzenleme hemen verilir.
presentationDatePickerPresentationDatePickerPresentation.Adaptivepanellerin neyde açıldığı: varsayılan dar bir pencerede bir sheet, daha geniş pencerede basılan parçanın yanında bir popover, bir panel açılırken seçilir; ya da her zaman bir popover, bir sheet ya da bir dialog. Her platformda aynı.
loadingBooleanfalsearalığın süzdüğünün yüklenip yüklenmediği: alanın yanındaki düğme döner ve basılmaz.
enabledBooleantrueseçicinin bir seçim alıp almadığı. Almayan soluk çizilir ve hiçbir şey açmaz.
minDatePantrixDate?nullbir ucun takviminin sunduğu ilk gün; o kadar erken bir sınır yoksa null.
maxDatePantrixDate?nullsunduğu son gün; o kadar geç bir sınır yoksa null.
onRefresh(suspend () -> Unit)?nullbir düzenleme beklemezken Yenile'nin yaptığı; bu sürerken düğme döner; aynı aralığı onRangeChange'e vermek için null.
roundRelativeUnitsBooleantrueşimdiden bir süre olan bir ucun en iyi okunan birime konup konmadığı, 90 dakika için "~ 2 saat önce", ya da kendi birimini koruyup korumadığı.
firstDayOfWeekInt?nulltakvimin haftalarının başladığı ve bir haftanın yuvarlandığı gün; günleri ISO 8601 sayar: 1 pazartesidir. Null dilinkidir, PantrixLocale.firstDayOfWeek.
is24HourBooleantruebir anın 24 saatlik bir saatle mi, 22:00, yoksa 12 saatlikle mi, 10:00 PM, yazılıp seçildiği.
styleElasticDatePickerStyle?nullalanın bu çağrıya ait stili: kapsayan her stilin üstünde, yoğunluğun altında.
colorsElasticDatePickerColors?nullalanın kendi renkleri: verdikleri, kalanı için temanınkiler.
tagKeyString?nullseçicinin otomasyon anahtarı: ElasticDatePicker_<tagKey> olur, parçaları .Button_quick_menu, .Button_name, .Button_start, .Button_end, .Button_auto_refresh, zaman penceresi düğmeleri .Button_window_previous, .Button_window_zoom_in, .Button_window_zoom_out ve .Button_window_next, alanın yanındaki düğme Button_<tagKey>_update.
autoRefreshPantrixAutoRefresh?nullaralığın kendiliğinden ne sıklıkla yeniden okunduğu; hiç için null. Duraklatılmamışken alan ne sıklıkla olduğunu kısaca yazarak biter ve her turda Yenile yapılır: bir sonraki tur sayılmadan önce bitmesi beklenen onRefresh, o yoksa aynı aralıkla onRangeChange. Başarısız olan bir onRefresh onu duraklatır ve bunu onAutoRefreshChange ile söyler.
onAutoRefreshChange((PantrixAutoRefresh) -> Unit)?nullokur hızlı menüde ayarladıkça otomatik yenilemeyi alır; menüde bunun için kendi bölümü olur; böyle bir bölüm olmaması için null.
minAutoRefreshDurationDuration.ZEROokurun ayarlayabileceği en kısa otomatik yenileme: daha kısası miktarını yanlış çizer.
layoutElasticDatePickerLayoutElasticDatePickerLayout.Fullalanın ne gösterdiği: aralığı, yalnız hızlı menünün düğmesini ya da yalnız otomatik yenilemeyi.
timeWindowButtonsElasticTimeWindowButtons?nullElastic UI'ın alanın yanındaki, aralığı uzunluğu kadar kaydıran ve yakınlaştırıp uzaklaştıran düğmeleri; hiçbiri için null.
customQuickPanelsList<ElasticQuickPanel>emptyList()hızlı menüde çağıranın kendi panelleri, son kullanılan aralıklardan sonra.
quickMenu(@Composable ElasticQuickMenuScope.() -> Unit)?nullhızlı menünün parçaları çağıranın kendi sırasında, bazıları dışarıda bırakılmış ya da aralarına kendi panelleri konmuş; Elastic UI'ın sırası için null.
timeZoneNameString?nullanların bulunduğu saat dilimi; uçların panellerinde UTC'den farkıyla adlandırılır: "Saat dilimi: Europe/Istanbul (UTC+03:00)". Yalnızca adlandırır, bir şey değiştirmez; böyle bir satır olmaması için null.
utcOffset((Instant) -> Duration)?nullanların bir anda okunup yazıldığı UTC farkı; ekranın saatininki (LocalPantrixClock) için null, bir test ya da önizleme başkasını vermedikçe cihazınki.
disabledTextString?nullseçim almayan bir seçicinin aralığının yerinde gösterdiği yazı; aralık için null.

ElasticDatePickerStyle

PantrixElasticDatePicker'ın alanı: ne kadar yüksek olduğu, köşeleri, içindeki boşluk, yanındaki düğmeyle arası ve ne kadar genişlediği.

ParametreTürVarsayılanNe olduğu
heightDpDp.UnspecifiedAlanın yüksekliği.
shapeShapeSpecShapeSpec.UnspecifiedAlanın köşeleri.
paddingDpDp.UnspecifiedAlanın kenarı ile içindekiler arasındaki boşluk, iki uçta da.
gapDpDp.UnspecifiedAlan ile yanındaki düğme arasındaki ve alanın içindeki parçalar arasındaki ara.
maxWidthDpDp.UnspecifiedAlanın ve düğmesinin en geniş hâli; verildiği kadar geniş olması için Dp.Infinity.

ElasticDatePickerColors

Bir PantrixElasticDatePicker'ın alanının temanın renkleri yerine boyandığı renkler: verilen renk kullanılır, verilmeyen temanın kalır. Alanın açtıkları bir popover'ın, bir sheet'in, bir takvimin ve sekmelerin renkleriyle boyanır.

ParametreTürVarsayılanNe olduğu
containerColorColor.UnspecifiedAlanın zemini. Bir metin alanınınki gibi temanın surface'ı.
borderColorColor.UnspecifiedAlanın kenarı ve hızlı menünün düğmesi ile aralık arasındaki çizgi. Temanın border'ı.
contentColorColor.UnspecifiedAralığın ve uçlarının sözleri. Temanın textPrimary'si.
iconColorColor.UnspecifiedAlanın simgeleri: hızlı menünün takvimi ve uçlar arasındaki ok. Temanın textSecondary'si.
activeColorColor.UnspecifiedPaneli açık olan ucun çevresine çizilen kenar. Birincil rolün color'ı.
pendingContainerColorColor.UnspecifiedBir düzenleme Güncelle'yi beklerken alanın zemini. Başarı rolünün container'ı.
pendingContentColorColor.UnspecifiedÜstündeki sözler, ok ve işaret. Başarı rolünün onContainer'ı.
invalidContainerColorColor.UnspecifiedSonu başlangıcından önce geldiğinde alanın zemini. Tehlike rolünün container'ı.
invalidContentColorColor.UnspecifiedÜstündeki sözler, ok ve işaret. Tehlike rolünün onContainer'ı.
disabledColorColor.UnspecifiedSeçim almayan bir alanın sözleri ve simgeleri. Temanın textDisabled'ı.

Erişilebilirlik