Pantrix UI

Dialog

Kullanıcı onunla ilgilenene kadar uygulamayı durduran bir karar ya da mesaj.

import com.pantrixui.components.overlay.dialog.PantrixDialog

Örnekler

Onay

Geri alınamayan bir işin onayı: bir başlık, bir mesaj ve iki eylem. Dialog kendini kapatmaz: scrim'e basmak, geri tuşu ve Escape onDismissRequest'i çağırır, eylemler kendi onClick'lerini; üçünde de kapatan open = false satırıdır. Kartın "Son olay" satırı en son hangisinin olduğunu söyler.

Güvenli seçenek önce gelir: "Vazgeç", Destructive "Sil"den önce yazılır. Klavyeyle açılınca odak ondadır.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
PantrixButton(
    text = "Dosyayı sil…",
    onClick = { open = true },
    variant = ButtonVariant.Outline,
    tagKey = "open_delete"
)
PantrixDialog(
    visible = open,
    onDismissRequest = {
        open = false
        report("Silme dialog'u kapatıldı")
    },
    title = "Dosya silinsin mi?",
    message = "Rapor.pdf her cihazdan kaldırılır. Bu işlem geri alınamaz.",
    actions = {
        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"
        )
    },
    tagKey = "delete_file"
)

İkonlu

icon başlığın üstünde durur ve başlık ortalanır. İkon süstür: anlamı başlık taşır, ekran okuyucu ikonu okumaz.

Tek eylemli bir bildirim: araya girecek kadar önemli bir haber. Scrim'e basmak, geri tuşu ve Escape onu da kapatır.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
PantrixButton(
    text = "Oturumu sonlandır",
    onClick = { open = true },
    variant = ButtonVariant.Outline,
    tagKey = "open_session"
)
PantrixDialog(
    visible = open,
    onDismissRequest = {
        open = false
        report("Oturum dialog'u kapatıldı")
    },
    title = "Oturumun süresi doldu",
    message = "Güvenliğin için çıkış yapıldı. Kaldığın yerden devam etmek için yeniden giriş yap.",
    icon = PantrixIcons.Info,
    actions = {
        PantrixButton(
            text = "Yeniden giriş yap",
            onClick = {
                open = false
                report("Yeniden giriş yapıldı")
            },
            tagKey = "sign_in_again"
        )
    },
    tagKey = "session"
)

Form

content mesajın altına çağıranın içeriğini koyar: burada dosyanın yeni adını alan bir alan. İçerik taşıyan dialog, kısa bir başlıkla bile olabildiğince geniştir: alan o yeri doldurur. "Kaydet" ad boşken kapalıdır.

Dokunarak açılınca odak alana geçmez: klavye kendiliğinden açılmaz. Klavyeyle açılınca odak ilk kontrolde başlar.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
val name = rememberTextFieldState()
PantrixButton(
    text = "Yeniden adlandır…",
    onClick = {
        name.setTextAndPlaceCursorAtEnd("Rapor")
        open = true
    },
    variant = ButtonVariant.Outline,
    tagKey = "open_rename"
)
PantrixDialog(
    visible = open,
    onDismissRequest = {
        open = false
        report("Yeniden adlandırma kapatıldı")
    },
    title = "Dosyayı yeniden adlandır",
    actions = {
        PantrixButton(
            text = "Vazgeç",
            onClick = {
                open = false
                report("Yeniden adlandırmaktan vazgeçildi")
            },
            variant = ButtonVariant.Text,
            tagKey = "cancel_rename"
        )
        PantrixButton(
            text = "Kaydet",
            onClick = {
                open = false
                report("Yeni ad: ${name.text}")
            },
            enabled = name.text.isNotBlank(),
            tagKey = "confirm_rename"
        )
    },
    tagKey = "rename_file"
) {
    PantrixTextField(state = name, modifier = Modifier.fillMaxWidth(), label = "Dosya adı", tagKey = "file_name")
}

Seçmek zorunlu

dismissible = false: scrim, geri tuşu ve Escape bir şey yapmaz, onDismissRequest çağrılmaz. Ekran okuyucuya scrim'in "Kapat" eylemi de sunulmaz.

Kullanıcı eylemlerden birini seçmek zorundadır; bu yüzden her çıkış için bir eylem bulunur: koşulları kabul etmeyen "Çıkış yap"a basar. Yalnızca kullanıcının seçmesi gereken yerde kullanılır.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
PantrixButton(
    text = "Koşulları göster",
    onClick = { open = true },
    variant = ButtonVariant.Outline,
    tagKey = "open_terms"
)
PantrixDialog(
    visible = open,
    onDismissRequest = { report("Bu çağrılmaz: dialog kapatılamaz") },
    title = "Koşullar güncellendi",
    message = "Devam etmek için yeni kullanım koşullarını kabul etmen gerekiyor.",
    dismissible = false,
    actions = {
        PantrixButton(
            text = "Çıkış yap",
            onClick = {
                open = false
                report("Koşullar reddedildi")
            },
            variant = ButtonVariant.Text,
            tagKey = "decline_terms"
        )
        PantrixButton(
            text = "Kabul et",
            onClick = {
                open = false
                report("Koşullar kabul edildi")
            },
            tagKey = "accept_terms"
        )
    },
    tagKey = "terms"
)

Uzun içerik

Pencereye sığmayan bir gövde: kırk satırlık sürüm notları. Yalnızca gövde kayar; başlık ve eylem yerinde, görünür kalır. Mesaj da içerikle birlikte kayar.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
PantrixButton(
    text = "Sürüm notları",
    onClick = { open = true },
    variant = ButtonVariant.Outline,
    tagKey = "open_notes"
)
PantrixDialog(
    visible = open,
    onDismissRequest = {
        open = false
        report("Sürüm notları kapatıldı")
    },
    title = "Sürüm notları",
    message = "Bu sürümle gelen değişiklikler.",
    actions = {
        PantrixButton(
            text = "Tamam",
            onClick = {
                open = false
                report("Sürüm notları okundu")
            },
            tagKey = "close_notes"
        )
    },
    tagKey = "release_notes"
) {
    RELEASE_NOTES.forEachIndexed { index, note ->
        PantrixText(text = "${index + 1}. $note", tagKey = "note_$index")
    }
}

private val RELEASE_NOTES = List(size = 40) { index ->
    when (index % 4) {
        0 -> "Dosyalar artık sürüklenerek klasörlere taşınıyor."
        1 -> "Paylaşılan klasörlerde kimin ne değiştirdiği görünüyor."
        2 -> "Arama, dosya içindeki metni de buluyor."
        else -> "Çevrimdışıyken yapılan değişiklikler bağlantı gelince eşitleniyor."
    }
}

Kısa soru, uzun mesaj

Başlık, mesaj ve eylemlerden oluşan dialog en geniş parçası kadar geniştir, stilin iki genişliği arasında. Kısa bir soru en dar hâlindedir (DialogStyle.minWidth); uzun bir mesaj en geniş hâlinde (maxWidth) alt satıra geçer.

İkisini sırayla aç: fark geniş bir pencerede belirgindir. İlki aynı zamanda en az yazılan dialog'dur: bir başlık ve eylemler.

var asking by rememberSaveable { mutableStateOf(false) }
var telling by rememberSaveable { mutableStateOf(false) }
FlowRow(
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
    verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)
) {
    PantrixButton(
        text = "Kısa bir soru",
        onClick = { asking = true },
        variant = ButtonVariant.Outline,
        tagKey = "open_sign_out"
    )
    PantrixButton(
        text = "Uzun bir mesaj",
        onClick = { telling = true },
        variant = ButtonVariant.Outline,
        tagKey = "open_sync_paused"
    )
}
PantrixDialog(
    visible = asking,
    onDismissRequest = { asking = false },
    title = "Çıkış yapılsın mı?",
    actions = {
        PantrixButton(text = "Vazgeç", onClick = { asking = false }, variant = ButtonVariant.Text, tagKey = "stay")
        PantrixButton(text = "Çıkış yap", onClick = { asking = false }, tagKey = "sign_out")
    },
    tagKey = "sign_out"
)
PantrixDialog(
    visible = telling,
    onDismissRequest = { telling = false },
    title = "Eşitleme duraklatıldı",
    message = "Cihaz mobil veriye geçtiği için dosyaların eşitlenmesi duraklatıldı. Wi-Fi'a bağlanınca kaldığı " +
        "yerden sürer; beklemek istemiyorsan ayarlardan mobil veride eşitlemeyi açabilirsin.",
    actions = {
        PantrixButton(text = "Tamam", onClick = { telling = false }, tagKey = "sync_paused_ok")
    },
    tagKey = "sync_paused"
)

Kendi renkleri

colors ile verilen renkler değişir, verilmeyen temanın kalır: burada zemin, başlık, mesaj ve ikon uygulamanın kendi morunda, scrim temanın.

Bu mor temanın hiçbir rolünde yok; bu yüzden üstünde okunan başlık ve mesaj rengini de çağıran verir. Zemin temanın bir rol rengi olsaydı başlık, mesaj ve ikon o rolle eşlenen rengi kendiliğinden alırdı.

var open by rememberSaveable { mutableStateOf(false) }
val report = LocalExampleEvents.current
val own = ownColors()
PantrixButton(
    text = "Planı yükselt",
    onClick = { open = true },
    variant = ButtonVariant.Outline,
    tagKey = "open_upgrade"
)
PantrixDialog(
    visible = open,
    onDismissRequest = {
        open = false
        report("Yükseltme dialog'u kapatıldı")
    },
    title = "Pro'ya geç",
    message = "Sınırsız proje, paylaşılan klasörler ve öncelikli destek.",
    icon = PantrixIcons.Star,
    colors = DialogColors(
        container = own.container,
        title = own.onContainer,
        message = own.onContainer,
        icon = own.color
    ),
    actions = {
        PantrixButton(
            text = "Şimdi değil",
            onClick = {
                open = false
                report("Yükseltme ertelendi")
            },
            variant = ButtonVariant.Text,
            tagKey = "later"
        )
        PantrixButton(
            text = "Yükselt",
            onClick = {
                open = false
                report("Plan yükseltildi")
            },
            tagKey = "upgrade"
        )
    },
    tagKey = "upgrade"
)

Kendi stili

style yalnızca bu çağrının geometrisini değiştirir: köşeler temanın en küçük yuvarlaklığında (ShapeRole.ExtraSmall), en fazla genişlik 360dp, ikon 40dp. Verilmeyen alanlar, en az genişlik, pencereyle arasındaki boşluk ve gölge, platformun stilinden gelir.

var open by rememberSaveable { mutableStateOf(false) }
PantrixButton(
    text = "Klasörü paylaş…",
    onClick = { open = true },
    variant = ButtonVariant.Outline,
    tagKey = "open_share_folder"
)
PantrixDialog(
    visible = open,
    onDismissRequest = { open = false },
    title = "Klasör paylaşılsın mı?",
    message = "Bağlantıyı bilen herkes Raporlar klasöründeki dosyaları görebilir.",
    icon = PantrixIcons.Folder,
    style = DialogStyle(shape = ShapeRole.ExtraSmall, maxWidth = 360.dp, iconSize = 40.dp),
    actions = {
        PantrixButton(
            text = "Vazgeç",
            onClick = { open = false },
            variant = ButtonVariant.Text,
            tagKey = "cancel_share_folder"
        )
        PantrixButton(text = "Paylaş", onClick = { open = false }, tagKey = "confirm_share_folder")
    },
    tagKey = "share_folder"
)

Başka temadaki bir bölümde

Sayfanın tersi renkte bir bölüm ve içinden açılan bir dialog. Bölüm ikinci bir temadır (PantrixTheme(darkTheme = …)); dialog da o temanın içinde çağrıldığı için onun renklerindedir: açık sayfada koyu, koyu sayfada açık bir dialog açılı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)) {
            PantrixButton(text = "Bu bölümden aç", onClick = { open = true }, tagKey = "open_in_part")
        }
    }
    PantrixDialog(
        visible = open,
        onDismissRequest = {
            open = false
            report("Bölümün dialog'u kapatıldı")
        },
        title = "Değişiklikler kaydedilsin mi?",
        message = "Kaydetmezsen bu bölümde yaptıkların kaybolur.",
        actions = {
            PantrixButton(
                text = "Kaydetme",
                onClick = {
                    open = false
                    report("Değişiklikler atıldı")
                },
                variant = ButtonVariant.Text,
                tagKey = "discard"
            )
            PantrixButton(
                text = "Kaydet",
                onClick = {
                    open = false
                    report("Değişiklikler kaydedildi")
                },
                tagKey = "save"
            )
        },
        tagKey = "save_changes"
    )
}

Kapanırken ağaçta kalan dialog

Kapalı bir dialog hiçbir şey kurmaz; bu yüzden ağaçta visible = false ile durur ve kapanırken temanın hareketiyle çıkar. İlk dialog böyledir.

İkincisi bir if'in içindedir: kapanınca kompozisyondan çıkar ve hareketsiz, bir anda gider. Kaybedilen yalnızca çıkış hareketidir. İkisini sırayla kapat ve çıkışlarına bak; hareketin azaltıldığı temada ikisi de bir anda gider.

var kept by rememberSaveable { mutableStateOf(false) }
var removed by rememberSaveable { mutableStateOf(false) }
FlowRow(
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
    verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)
) {
    PantrixButton(
        text = "Ağaçta kalan",
        onClick = { kept = true },
        variant = ButtonVariant.Outline,
        tagKey = "open_kept"
    )
    PantrixButton(
        text = "Ağaçtan çıkarılan",
        onClick = { removed = true },
        variant = ButtonVariant.Outline,
        tagKey = "open_removed"
    )
}
PantrixDialog(
    visible = kept,
    onDismissRequest = { kept = false },
    title = "Hareketle çıkar",
    message = "Kapalıyken de ağaçta: visible = false olunca temanın hareketiyle çıkar.",
    actions = { PantrixButton(text = "Kapat", onClick = { kept = false }, tagKey = "close_kept") },
    tagKey = "kept"
)
if (removed) {
    PantrixDialog(
        visible = true,
        onDismissRequest = { removed = false },
        title = "Bir anda gider",
        message = "Kapanınca kompozisyondan çıkar: çıkış hareketi oynamaz.",
        actions = { PantrixButton(text = "Kapat", onClick = { removed = false }, tagKey = "close_removed") },
        tagKey = "removed"
    )
}

API

visible

Kullanıcı onunla ilgilenene kadar uygulamayı durduran bir karar ya da mesaj.

ParametreTürVarsayılanNe olduğu
visibleBooleanDialog'un gösterilip gösterilmediği. Temanın hareketiyle girer ve çıkar.
onDismissRequest() -> Unitdismissible iken geri tuşunda, Escape'te ve scrim'e basılınca çağrılır. Dialog, visible false olana kadar kalır.
titleString?nullDialog'un ne hakkında olduğu, kısa bir soru ya da cümle olarak: "Bu dosya silinsin mi?". Olmayacaksa null ya da boş: ona satır ayrılmaz ve dialog açılınca ekran okuyucu bir ad duyurmaz.
actions@Composable RowScope.() -> UnitSona yaslı, sığmadıklarında alt satıra geçen düğmeler. Kendi test etiketlerini korurlar.
modifierModifierModifierDialog'un kendisine uygulanır. Pencereyle arasında bıraktığı boşluk dialog'un parçası değildir.
messageString?nullBaşlığın altındaki açıklama. Pencere kısaysa content ile birlikte kayar.
iconImageVector?nullBaşlığın üstünde duran, süs olan bir ikon; verilince başlık ortalanır.
dismissibleBooleantrueGeri tuşunun, Escape'in ve scrim'e basmanın kapatmayı isteyip istemediği. Yalnızca kullanıcının actions'tan birini seçmesi gereken yerde false ver.
styleDialogStyle?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.
colorsDialogColors?nullBu çağrının kendi renkleri. Yalnızca verdikleri değişir, gerisi temanınki kalır.
tagKeyString?nullOtomasyon için, dilden bağımsız bir anahtar: dialog'un test etiketi Dialog_<tagKey> olur ve çizildiği hâliyle dialog'un kendisine verilir.
content(@Composable ColumnScope.() -> Unit)?nullDialog'un taşıdığı başka her şey, mesajın altında: bir form alanı, bir seçenek listesi.

DialogStyle

PantrixDialog'un geometrisi.

ParametreTürVarsayılanNe olduğu
shapeShapeSpecShapeSpec.UnspecifiedDialog'un köşeleri: Android'de ve iOS'ta büyük, masaüstünde ve web'de orta yuvarlaktır.
minWidthDpDp.UnspecifiedDialog'un en az genişliği: başlığı, mesajı ve eylemleri ne kadar kısa olursa olsun bundan dar olmaz.
maxWidthDpDp.UnspecifiedDialog'un en çok genişliği: daha uzun metin alt satıra geçer. Çağıranın içeriğini taşıyan dialog bu genişliktedir.
marginDpDp.UnspecifiedDialog ile pencerenin kenarları arasında boş bırakılan yer: böylece küçük bir pencerede de dialog'un çevresinde scrim görünür. minWidth ile iki kenar boşluğunun toplamından dar bir pencere dialog'a kalan yeri verir.
elevationDpDp.UnspecifiedDialog'un scrim'in üstünde ne kadar yüksekte durduğu, yani gölgesinin ne kadar büyük olduğu. iOS'ta gölge yoktur.
iconSizeDpDp.UnspecifiedBaşlığın üstündeki ikonun boyutu.

DialogColors

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

ParametreTürVarsayılanNe olduğu
containerColorColor.UnspecifiedDialog'un zemini. Temanın surface'ı.
titleColorColor.UnspecifiedBaşlık. Temanın textPrimary'si.
messageColorColor.UnspecifiedBaşlığın altındaki mesaj. Temanın textSecondary'si.
iconColorColor.UnspecifiedBaşlığın üstündeki ikon. primary rolünün color'ı.
scrimColorColor.UnspecifiedDialog'un arkasında, uygulamanın üstüne serilen scrim, kendi alfasıyla. Temanın scrim'i.

Erişilebilirlik