Dialog
Kullanıcı onunla ilgilenene kadar uygulamayı durduran bir karar ya da mesaj.
import com.pantrixui.components.overlay.dialog.PantrixDialog
- Başlık, mesaj, eylemler.
titlekısa bir soru ya da cümledir,messagealtındaki açıklama.actionssona yaslı düğmelerdir; yan yana sığmadıklarında alt satıra geçerler. - Güvenli seçenek önce. Klavyeyle açılan dialog'da odak ilk kontrolde, çoğunlukla ilk eylemde başlar; bu yüzden "Vazgeç", "Sil"den önce yazılır. Dokunarak açılınca odak yerinde kalır.
- İkon.
iconbaşlığın üstünde durur ve başlığı ortalar. Süstür: ekran okuyucu onu okumaz. - Kendi içeriği.
contentmesajın altına bir form alanı ya da bir seçenek listesi koyar. - Genişlik. 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 dardır, uzun bir mesaj en geniş hâlinde alt satıra geçer. İçerik taşıyan dialog olabildiğince geniştir.
- Uzun gövde. Pencere kısaysa yalnızca mesaj ve içerik kayar; başlık ve eylemler yerinde kalır.
- Kapatılamayan dialog.
dismissible = falseile scrim, geri tuşu ve Escape bir şey yapmaz; çıkış yalnızca eylemlerdir. - Kapanırken ağaçta kalır. Kapalı bir dialog hiçbir şey kurmaz: ağaçta
visible = falseile durur ve temanın hareketiyle çıkar. Açıkken kompozisyondan çıkarılan dialog hareketsiz, bir anda gider. - Renk ve stil.
colorszemini, başlığı, mesajı, ikonu ve scrim'i değiştirir;styleköşeleri, genişlikleri, pencereyle arasındaki boşluğu, gölgeyi ve ikonun boyutunu. Dialog her platformda aynı görünür; fark stildedir: köşeler Android'de ve iOS'ta büyük, masaüstünde ve web'de orta yuvarlaktır, iOS'ta gölge yoktur.
Ö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.
| Parametre | Tür | Varsayılan | Ne olduğu |
|---|---|---|---|
visible | Boolean | Dialog'un gösterilip gösterilmediği. Temanın hareketiyle girer ve çıkar. | |
onDismissRequest | () -> Unit | dismissible iken geri tuşunda, Escape'te ve scrim'e basılınca çağrılır. Dialog, visible false olana kadar kalır. | |
title | String? | null | Dialog'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.() -> Unit | Sona yaslı, sığmadıklarında alt satıra geçen düğmeler. Kendi test etiketlerini korurlar. | |
modifier | Modifier | Modifier | Dialog'un kendisine uygulanır. Pencereyle arasında bıraktığı boşluk dialog'un parçası değildir. |
message | String? | null | Başlığın altındaki açıklama. Pencere kısaysa content ile birlikte kayar. |
icon | ImageVector? | null | Başlığın üstünde duran, süs olan bir ikon; verilince başlık ortalanır. |
dismissible | Boolean | true | Geri 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. |
style | DialogStyle? | null | Bu ç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. |
colors | DialogColors? | null | Bu çağrının kendi renkleri. Yalnızca verdikleri değişir, gerisi temanınki kalır. |
tagKey | String? | null | Otomasyon 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)? | null | Dialog'un taşıdığı başka her şey, mesajın altında: bir form alanı, bir seçenek listesi. |
DialogStyle
PantrixDialog'un geometrisi.
| Parametre | Tür | Varsayılan | Ne olduğu |
|---|---|---|---|
shape | ShapeSpec | ShapeSpec.Unspecified | Dialog'un köşeleri: Android'de ve iOS'ta büyük, masaüstünde ve web'de orta yuvarlaktır. |
minWidth | Dp | Dp.Unspecified | Dialog'un en az genişliği: başlığı, mesajı ve eylemleri ne kadar kısa olursa olsun bundan dar olmaz. |
maxWidth | Dp | Dp.Unspecified | Dialog'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. |
margin | Dp | Dp.Unspecified | Dialog 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. |
elevation | Dp | Dp.Unspecified | Dialog'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. |
iconSize | Dp | Dp.Unspecified | Baş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.
| Parametre | Tür | Varsayılan | Ne olduğu |
|---|---|---|---|
container | Color | Color.Unspecified | Dialog'un zemini. Temanın surface'ı. |
title | Color | Color.Unspecified | Başlık. Temanın textPrimary'si. |
message | Color | Color.Unspecified | Başlığın altındaki mesaj. Temanın textSecondary'si. |
icon | Color | Color.Unspecified | Başlığın üstündeki ikon. primary rolünün color'ı. |
scrim | Color | Color.Unspecified | Dialog'un arkasında, uygulamanın üstüne serilen scrim, kendi alfasıyla. Temanın scrim'i. |
Erişilebilirlik
- Ekran okuyucu. Başlık dialog açılınca duyurulur ve içindekilerin başlığıdır. Android'de TalkBack dialog'un içinde kalır. Kapatılabilen dialog'da scrim, içerikten sonra okunan tek bir "Kapat" eylemidir.