Pantrix UI

Popover

Bir öğenin yanında duran ve o öğe hakkında, öğenin kendisinin gösterebileceğinden fazlasını taşıyan katman: bir durumun ne anlama geldiği, bir alanın ne beklediği, bir satır için birkaç kontrol.

import com.pantrixui.components.overlay.popover.PantrixPopover

Örnekler

Bilgi

En yalın hâli: bir satırın yanındaki bilgi düğmesi popover'ı açar; içinde satır hakkında daha fazlası ve bir bağlantı var. Popover'ın açık olup olmadığı ekranın durumudur (visible). Popover kendini kapatmaz: kapanmak istediğinde onDismissRequest'i çağırır, visible'ı false yapan bu koddur. İçindeki bir kontrole basmak kapanmasını istemez: bağlantı popover'ı kendi onClick'inde kapatır.

Dışına basmak, geri tuşu ve Escape kapatır. Klavyeyle açılınca odak bağlantıdadır; kapanınca düğmeye döner. Kartın "Son olay" satırı en son ne olduğunu söyler.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
Row(verticalAlignment = Alignment.CenterVertically) {
    PantrixText(text = "Teslimat: Salı")
    PantrixPopover(
        visible = open,
        onDismissRequest = {
            open = false
            report("Teslimat popover'ı kapatıldı")
        },
        anchor = {
            PantrixIconButton(
                imageVector = PantrixIcons.Info,
                contentDescription = "Teslimat ayrıntıları",
                onClick = { open = true },
                tagKey = "open_delivery"
            )
        },
        title = "Teslimat",
        tagKey = "delivery"
    ) {
        PantrixText(text = "Salı günü 09.00 ile 12.00 arasında gelir. Kurye on dakika önce arar.")
        PantrixLink(
            text = "Kargoyu izle",
            onClick = {
                open = false
                report("Kargo izleme açıldı")
            },
            tagKey = "track"
        )
    }
}

Yön ve hiza

side popover'ın çapanın hangi yanında açılacağını, alignment o yan boyunca nasıl hizalanacağını söyler. Söylenmezse popover altta açılır ve çapaya ortalanır: PopoverSide.Bottom ve PopoverAlignment.Center.

Baş ve Son yazı yönüne göre değişir: soldan sağa bir düzende Baş soldur. Popover çapanın yanındayken (Baş ya da Son) hiza dikeydir: Baş üst kenarları, Son alt kenarları buluşturur.

İstenen yanda yer yoksa popover karşı yana geçer: Üst'ü seç ve düğme pencerenin üst kenarına yakınken aç. İki yanda da yer yoksa popover istenen yanda kalır ve pencerenin içine, çapanın üstüne kayar.

var open by rememberSaveable { mutableStateOf(false) }
var side by rememberSaveable { mutableStateOf(PopoverSide.Bottom) }
var alignment by rememberSaveable { mutableStateOf(PopoverAlignment.Center) }
val report = LocalExampleEvents.current
PantrixSegmentButton(options = SIDES, selected = side, onSelect = { side = it }, tagKey = "side")
PantrixSegmentButton(
    options = ALIGNMENTS,
    selected = alignment,
    onSelect = { alignment = it },
    tagKey = "alignment"
)
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
    PantrixPopover(
        visible = open,
        onDismissRequest = {
            open = false
            report("Popover kapatıldı")
        },
        anchor = {
            PantrixButton(
                text = "Aç",
                onClick = { open = true },
                variant = ButtonVariant.Outline,
                tagKey = "open_placed"
            )
        },
        side = side,
        alignment = alignment,
        tagKey = "placed"
    ) {
        PantrixText(text = "side = ${side.name}, alignment = ${alignment.name}")
    }
}

private val SIDES = listOf(
    SegmentOption(value = PopoverSide.Top, label = "Üst", tagKey = "top"),
    SegmentOption(value = PopoverSide.Bottom, label = "Alt", tagKey = "bottom"),
    SegmentOption(value = PopoverSide.Start, label = "Baş", tagKey = "start"),
    SegmentOption(value = PopoverSide.End, label = "Son", tagKey = "end")
)

private val ALIGNMENTS = listOf(
    SegmentOption(value = PopoverAlignment.Start, label = "Baş", tagKey = "start"),
    SegmentOption(value = PopoverAlignment.Center, label = "Orta", tagKey = "center"),
    SegmentOption(value = PopoverAlignment.End, label = "Son", tagKey = "end")
)

Kenarda

Pencerenin bitiş kenarına yakın bir çapa. Popover çapasına ortalanır; çapa kenara yakınken ortalanan popover pencereden taşardı. Taşmaz: kenardan stilin margin'i kadar içeride kalacak şekilde kayar.

Dar bir pencerede dene: daraltılacak olan, uygulamanın kendi penceresidir. Popover yerini gerçek pencereye göre seçer, bir kartın pencere seçicisinin örneğine verdiği pencereye göre değil; bu kartta o seçici bu yüzden yoktur. Yeterince geniş bir pencerede kartın yanında popover'a yer kalır; orada popover kaymaz, düğmeye ortalanır.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) {
    PantrixPopover(
        visible = open,
        onDismissRequest = {
            open = false
            report("Kenardaki popover kapatıldı")
        },
        anchor = {
            PantrixIconButton(
                imageVector = PantrixIcons.MoreHorizontal,
                contentDescription = "Paylaşım ayrıntıları",
                onClick = { open = true },
                tagKey = "open_shared"
            )
        },
        title = "Paylaşım",
        tagKey = "shared"
    ) {
        PantrixText(text = "Bu klasörü üç kişi görebiliyor: Ada, Deniz ve Umut.")
    }
}

Alanın yanında

Bir alanın ne beklediğini söyleyen popover. Çapa alanın tamamıdır: popover alanın altında, alignment = PopoverAlignment.End ile sonuna hizalı açılır. Açan, alanın sonundaki bilgi düğmesidir.

Popover açıkken altındaki sayfa odak göstermez: alana yazarken açarsan, popover açıkken alan durgun çizilir. Kapanınca odak yine çapadadır.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
val iban = rememberTextFieldState()
PantrixPopover(
    visible = open,
    onDismissRequest = {
        open = false
        report("IBAN yardımı kapatıldı")
    },
    anchor = {
        PantrixTextField(
            state = iban,
            modifier = Modifier.fillMaxWidth(),
            label = "IBAN",
            placeholder = "TR00 0000 0000 0000 0000 0000 00",
            trailingIcon = {
                PantrixIconButton(
                    imageVector = PantrixIcons.Info,
                    contentDescription = "IBAN nedir?",
                    onClick = { open = true },
                    size = ButtonSize.Small,
                    tagKey = "open_iban_help"
                )
            },
            tagKey = "iban"
        )
    },
    alignment = PopoverAlignment.End,
    title = "IBAN",
    tagKey = "iban_help"
) {
    PantrixText(text = "TR ile başlayan 26 haneli hesap numarası. Banka uygulamanda hesap ayrıntılarında yazar.")
}

Onay

Küçük bir onay: geniş bir pencerede bir dialog yerine, işin başladığı düğmenin yanında. İçinde bir cümle ve iki düğme var; her düğme popover'ı kendi onClick'inde kapatır.

Güvenli seçenek önce gelir: klavyeyle açılınca odak ilk kontrolde, "Vazgeç"tedir. alignment = PopoverAlignment.Start popover'ı düğmenin başına hizalar.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
PantrixPopover(
    visible = open,
    onDismissRequest = {
        open = false
        report("Silme onayı kapatıldı")
    },
    anchor = {
        PantrixButton(
            text = "Dosyayı sil…",
            onClick = { open = true },
            variant = ButtonVariant.Outline,
            tagKey = "open_confirm"
        )
    },
    alignment = PopoverAlignment.Start,
    title = "Dosya silinsin mi?",
    tagKey = "delete_file"
) {
    PantrixText(text = "Rapor.pdf her cihazdan kaldırılır.")
    Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
        PantrixButton(
            text = "Vazgeç",
            onClick = {
                open = false
                report("Silmekten vazgeçildi")
            },
            variant = ButtonVariant.Text,
            tagKey = "cancel_delete"
        )
        PantrixButton(
            text = "Sil",
            onClick = {
                open = false
                report("Dosya silindi")
            },
            variant = ButtonVariant.Destructive,
            tagKey = "confirm_delete"
        )
    }
}

Seçmek zorunlu

dismissible = false: dışına basmak, geri tuşu ve Escape bir şey yapmaz, ekran okuyucunun kapatma eylemi de yoktur. Kapatması gereken şey içindedir: çıkış iki düğmedir. dismissible yalnızca böyle, içindeki bir şeyin kapattığı bir popover için false yapılır.

onDismissRequest boş bırakıldı: bu popover'da hiç çağrılmaz.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
PantrixPopover(
    visible = open,
    onDismissRequest = {},
    anchor = {
        PantrixButton(
            text = "Çerez tercihi",
            onClick = { open = true },
            variant = ButtonVariant.Outline,
            tagKey = "open_cookies"
        )
    },
    alignment = PopoverAlignment.Start,
    title = "Çerezler",
    dismissible = false,
    tagKey = "cookies"
) {
    PantrixText(text = "Ölçüm çerezlerine izin veriyor musun?")
    Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
        PantrixButton(
            text = "Yalnız gerekli",
            onClick = {
                open = false
                report("Yalnız gerekli çerezler")
            },
            variant = ButtonVariant.Text,
            tagKey = "cookies_needed"
        )
        PantrixButton(
            text = "İzin ver",
            onClick = {
                open = false
                report("Çerezlere izin verildi")
            },
            tagKey = "cookies_all"
        )
    }
}

Uzun içerik

Otuz satır stilin en çok yüksekliğine (PopoverStyle.maxHeight) sığmaz: popover o yükseklikte kalır, başlık yerinde durur ve içerik altında kayar.

İçinde odaklanacak bir kontrol yoktur. Bu yüzden klavyede odağı popover'ın kendisi alır ve kaydıran tuşlar içeriği kaydırır: ok tuşları, Page Up ve Page Down, boşluk, Home ve End.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
PantrixPopover(
    visible = open,
    onDismissRequest = {
        open = false
        report("Sürüm notları kapatıldı")
    },
    anchor = {
        PantrixButton(
            text = "Sürüm notları",
            onClick = { open = true },
            variant = ButtonVariant.Outline,
            tagKey = "open_notes"
        )
    },
    alignment = PopoverAlignment.Start,
    title = "Sürüm notları",
    tagKey = "notes"
) {
    (1..30).forEach { number -> PantrixText(text = "$number. değişiklik: küçük bir düzeltme.") }
}

Kendi stili

style yalnızca bu popover'ın geometrisini değiştirir: PopoverStyle'ın verilen alanları değişir, gerisi temanın ve platformun stilinden gelir. Burada popover en çok 220dp genişliğindedir ve metin o genişlikte satır atlar; köşeleri temanın büyük köşesidir (ShapeRole.Large) ve çapasından 16dp uzakta durur.

Çapaya uzaklık (gap) temanın yoğunluğuyla ölçeklenir; en çok genişlik ve köşeler ölçeklenmez.

var open by rememberSaveable { mutableStateOf(false) }
PantrixPopover(
    visible = open,
    onDismissRequest = { open = false },
    anchor = {
        PantrixButton(
            text = "Kısayollar",
            onClick = { open = true },
            variant = ButtonVariant.Outline,
            tagKey = "open_shortcuts"
        )
    },
    alignment = PopoverAlignment.Start,
    title = "Kısayollar",
    style = PopoverStyle(shape = ShapeRole.Large, maxWidth = 220.dp, gap = 16.dp),
    tagKey = "shortcuts"
) {
    PantrixText(text = "Ctrl+F arar, F5 yeniler. Del seçili dosyayı siler; geri almak için Ctrl+Z.")
}

Kendi renkleri

colors popover'a temanın değil, verilen renkleri verir: burada temanın hiçbir rolünde olmayan, uygulamanın kendi moru. PopoverColors'ın yalnızca verilen alanları değişir, gerisi temanın kalır.

PopoverColors dolguyu, başlığı ve kenar çizgisini boyar; içeriğin rengi onda yoktur. Rolü olmayan bir dolguda içeriğin rengini içeriği yazan verir: buradaki metin color = own.onContainer ile yazıldı. Dolgu temanın bir rolünün rengiyse, PantrixTheme.colors.info.container gibi, başlık ve içerik kendiliğinden o rolün eş rengini alır.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
val own = ownColors()
PantrixPopover(
    visible = open,
    onDismissRequest = {
        open = false
        report("Pro popover'ı kapatıldı")
    },
    anchor = {
        PantrixButton(
            text = "Pro nedir?",
            onClick = { open = true },
            variant = ButtonVariant.Outline,
            tagKey = "open_pro"
        )
    },
    alignment = PopoverAlignment.Start,
    title = "Pro",
    colors = PopoverColors(container = own.container, title = own.onContainer, border = own.color),
    tagKey = "pro"
) {
    PantrixText(text = "Sınırsız proje, paylaşılan klasörler ve öncelikli destek.", color = own.onContainer)
}

Başka temadaki bir bölümde

Sayfanın tersi renkte bir bölüm ve içinden açılan bir popover. Bölüm ikinci bir temadır (PantrixTheme(darkTheme = …)): açık sayfada koyu, koyu sayfada açık. Popover o temanın içinde çağrıldığı için onun renklerindedir: katmanı pencerenin kökünde kurulsa da çağrıldığı yerin temasını taşır.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
val pageIsDark = PantrixTheme.colors.background.luminance() < 0.5f
PantrixTheme(darkTheme = !pageIsDark) {
    PantrixSurface(modifier = Modifier.fillMaxWidth()) {
        Column(modifier = Modifier.padding(PantrixTheme.spacing.md)) {
            PantrixPopover(
                visible = open,
                onDismissRequest = {
                    open = false
                    report("Bölümün popover'ı kapatıldı")
                },
                anchor = {
                    PantrixButton(text = "Bu bölümden aç", onClick = { open = true }, tagKey = "open_in_part")
                },
                alignment = PopoverAlignment.Start,
                title = "Bu bölüm",
                tagKey = "in_part"
            ) {
                PantrixText(text = "Bölümün temasında açıldı.")
            }
        }
    }
}

Dar pencerede sheet

presentation = OverlayPresentation.Adaptive: dar bir pencerede popover alttan bir sheet olur, başlığı sheet'in başlığı, içeriği altında; daha geniş pencerede düğmenin yanında bir popover. Karttaki pencere seçicisinden "Dar" ile "Geniş" arasında geç. Popover'ın varsayılanı her pencerede Popover'dır: bir bilgi kutusu çoğu zaman yanında kalmalıdır.

var open by rememberSaveable { mutableStateOf(false) }
// Kartın penceresi örnek kadar uzundur: dar bir pencerede açılan sheet'e yer kalsın diye örnek uzun tutulur.
Column(Modifier.fillMaxWidth().height(280.dp)) {
    PantrixPopover(
        visible = open,
        onDismissRequest = { open = false },
        anchor = { PantrixButton(text = "Teslimat", onClick = { open = true }, tagKey = "open_adaptive_popover") },
        title = "Teslimat",
        tagKey = "adaptive_popover",
        presentation = OverlayPresentation.Adaptive
    ) {
        PantrixText("Salı günü dokuz ile on iki arasında gelir; kurye on dakika önce arar.")
        PantrixButton(text = "Kargoyu izle", onClick = { open = false }, tagKey = "adaptive_track")
    }
}

API

visible

Bir öğenin yanında duran ve o öğe hakkında, öğenin kendisinin gösterebileceğinden fazlasını taşıyan katman: bir durumun ne anlama geldiği, bir alanın ne beklediği, bir satır için birkaç kontrol.

ParametreTürVarsayılanNe olduğu
visibleBooleanPopover'ın görünüp görünmediği. Temanın hareketiyle girer ve çıkar.
onDismissRequest() -> Unitdismissible açıkken dışına basılınca, Escape'e ya da geri tuşuna basılınca çağrılır. Popover, visible false olana kadar kalır.
anchor@Composable () -> UnitPopover'ın yanında durduğu şey: onu açan kontrol. Bu kontrol, popover'ın çağrıldığı yerde ve o yerin istediği gibi yerleşir. Popover onun yerleşim kutusuna göre konumlanır, dokunma hedefinin kapladığı yer de bu kutunun içindedir.
modifierModifierModifierPopover'ın kendisine, katmanının içinde uygulanır. Çapaya uygulanmaz.
sidePopoverSidePopoverSide.BottomPopover'ın çapanın hangi yanını tercih ettiği. PopoverSide.Start ve PopoverSide.End yazı yönünü izler.
alignmentPopoverAlignmentPopoverAlignment.CenterPopover'ın o yan boyunca çapayla nasıl hizalanacağı.
titleString?nullPopover'ın en üstündeki başlık. Altındakiler kayarken görünür kalır ve popover açılırken ekran okuyucu onu duyurur. Bir satırdan uzun her popover'a verilir.
dismissibleBooleantrueDışına basmanın, Escape'in, geri tuşunun ve ekran okuyucunun kapatma eyleminin kapanmasını isteyip istemediği. Yalnızca content'teki bir şeyin kapattığı bir popover için false yapılır.
stylePopoverStyle?nullBu çağrının kendi stili: çevresindeki her stili ezer, yoğunluk ona da uygulanır. Yalnızca verdiği alanlar değişir ve her platformda değişir.
colorsPopoverColors?nullBu çağrının kendi renkleri. Yalnızca verdikleri değişir, gerisi temanınki kalır.
tagKeyString?nullotomasyon için yerele bağlı olmayan bir anahtar: popover'ın etiketi Popover_<tagKey>'dir, çizildiği hâliyle popover'ın üstünde, sheet olarak gösterildiğinde de sheet'in üstünde.
presentationOverlayPresentationOverlayPresentation.Popoverpopover'ın nasıl gösterildiği: varsayılan çapanının yanında; pencerenin altından bir sheet olarak, başlığı title, altında content, yanlarında popover'ın kendi boşluğuyla; ya da dar bir pencerede biri, daha geniş pencerede öteki. Açılırken seçilir, kapanana kadar kalır.
content@Composable ColumnScope.() -> UnitPopover'ın içindekiler, başlığın altında bir sütun hâlinde.

PopoverStyle

PantrixPopover'ın geometrisi: ne kadar genişleyip yükseldiği, çapasından ne kadar uzakta durduğu ve pencerenin kenarlarına ne kadar yaklaştığı.

ParametreTürVarsayılanNe olduğu
shapeShapeSpecShapeSpec.UnspecifiedPopover'ın köşeleri: Android'de ve iOS'ta temanın orta, masaüstünde ve web'de küçük köşesidir.
minWidthDpDp.UnspecifiedPopover'ın en az genişliği: içinde ne kadar az şey olursa olsun bundan dar olmaz.
maxWidthDpDp.UnspecifiedPopover'ın en çok genişliği: daha uzun metin satır atlar.
maxHeightDpDp.UnspecifiedPopover'ın en çok yüksekliği: bunu aşan içerik başlığın altında kayar.
elevationDpDp.UnspecifiedPopover'ın uygulamanın üstünde ne kadar yüksekte durduğu, yani gölgesinin ne kadar büyük olduğu.
gapDpDp.UnspecifiedÇapa ile popover'ın arası.
marginDpDp.UnspecifiedPopover ile pencerenin kenarları arasında, bir de pencereyi orada örten şeylerle arasında boş bırakılan yer: bir sistem çubuğu, bir ekran çentiği, klavye.

PopoverColors

Temanın renklerini almayan bir çağrı için PantrixPopover'ın boyandığı renkler: verilen renk kullanılır, verilmeyen temanın kalır.

ParametreTürVarsayılanNe olduğu
containerColorColor.UnspecifiedPopover'ın dolgusu. Temanın surface'ı.
titleColorColor.UnspecifiedBaşlık. Temanın textPrimary'si.
borderColorColor.UnspecifiedPopover'ın çevresindeki ince çizgi: popover'ı, altında duran kendi rengindeki bir yüzeyden ayırır, gölgenin az göründüğü koyu temada olduğu gibi. Temanın kendi zeminlerinde temanın divider'ıdır. Bir dolgunun üstünde, o çizginin okunmayacağı yerde, title'ın bir payıdır: Subtle bir düğmenin kenarı gibi. Saydam bir renk verilirse çizgi çizilmez.

Erişilebilirlik