1+ package com.mindorks.example.jetpack.compose.dialog
2+
3+ import android.os.Bundle
4+ import androidx.appcompat.app.AppCompatActivity
5+ import androidx.compose.foundation.Text
6+ import androidx.compose.foundation.layout.*
7+ import androidx.compose.foundation.lazy.LazyColumnFor
8+ import androidx.compose.foundation.selection.selectable
9+ import androidx.compose.foundation.shape.RoundedCornerShape
10+ import androidx.compose.material.*
11+ import androidx.compose.runtime.*
12+ import androidx.compose.ui.Modifier
13+ import androidx.compose.ui.graphics.Color
14+ import androidx.compose.ui.platform.setContent
15+ import androidx.compose.ui.text.style.TextAlign
16+ import androidx.compose.ui.unit.dp
17+ import androidx.compose.ui.window.Dialog
18+ import java.util.*
19+
20+
21+ // The state should be at the lower most common parent of the
22+ // composables, which are going to interact.
23+ val dialogState by lazy { mutableStateOf(false ) }
24+ val selectedCountry by lazy { mutableStateOf(" " ) }
25+
26+ val countriesList = getCountries().values.toList()
27+
28+ class SingleChoiceDialogActivity : AppCompatActivity () {
29+ override fun onCreate (savedInstanceState : Bundle ? ) {
30+ super .onCreate(savedInstanceState)
31+ setContent {
32+ CountriesDialog ()
33+ SingleChoiceDialogActivityContent ()
34+ }
35+ }
36+ }
37+
38+ @Composable
39+ fun SingleChoiceDialogActivityContent () {
40+ Column {
41+ Button (
42+ onClick = {
43+ dialogState.value = true
44+ },
45+ modifier = Modifier .padding(16 .dp).fillMaxWidth(),
46+ shape = RoundedCornerShape (8 .dp),
47+ backgroundColor = Color .Gray
48+ ) {
49+ Text (
50+ text = " Show Countries List" ,
51+ textAlign = TextAlign .Center ,
52+ color = Color .White
53+ )
54+ }
55+ Divider (color = Color .Black )
56+ Text (
57+ text = selectedCountry.value,
58+ textAlign = TextAlign .Center ,
59+ color = Color .Black
60+ )
61+ }
62+ }
63+
64+ @Composable
65+ fun CountriesDialog () {
66+ SingleSelectDialog (
67+ dialogState = dialogState,
68+ title = " Choice your Country" ,
69+ optionsList = countriesList,
70+ submitButtonText = " Select" ,
71+ onSubmitButtonClick = { selectedCountry.value = countriesList[it] },
72+ onDismissRequest = { dialogState.value = false }
73+ )
74+ }
75+
76+ @Composable
77+ // Generally it's a good habit that we create 2 composables, one which accepts
78+ // state and one which maintain its own state. That way,
79+ // the developer has more control which approach he/she want to follow.
80+ fun SingleSelectDialog (
81+ dialogState : MutableState <Boolean >,
82+ title : String ,
83+ optionsList : List <String >,
84+ defaultSelected : Int = -1,
85+ submitButtonText : String ,
86+ onSubmitButtonClick : (Int ) -> Unit ,
87+ onDismissRequest : () -> Unit
88+ ) {
89+ if (dialogState.value) {
90+ SingleSelectDialog (
91+ title = title,
92+ optionsList = optionsList,
93+ defaultSelected = defaultSelected,
94+ submitButtonText = submitButtonText,
95+ onSubmitButtonClick = onSubmitButtonClick,
96+ onDismissRequest = onDismissRequest
97+ )
98+ }
99+ }
100+
101+ @Composable
102+ fun SingleSelectDialog (
103+ title : String ,
104+ optionsList : List <String >,
105+ defaultSelected : Int = -1,
106+ submitButtonText : String ,
107+ onSubmitButtonClick : (Int ) -> Unit ,
108+ onDismissRequest : () -> Unit
109+ ) {
110+ val selectedOption = mutableStateOf(defaultSelected)
111+ Dialog (onDismissRequest = { onDismissRequest.invoke() }) {
112+ Surface (
113+ modifier = Modifier .preferredWidth(300 .dp),
114+ shape = RoundedCornerShape (10 .dp)
115+ ) {
116+ Column (modifier = Modifier .padding(10 .dp)) {
117+ Text (text = title)
118+ Spacer (modifier = Modifier .preferredHeight(10 .dp))
119+ LazyColumnFor (
120+ items = optionsList,
121+ modifier = Modifier .preferredHeight(500 .dp)
122+ ) {
123+ val selected = if (selectedOption.value == - 1 ) {
124+ " "
125+ } else {
126+ optionsList[selectedOption.value]
127+ }
128+
129+ RadioButton (it, selected) { selectedValue ->
130+ selectedOption.value = optionsList.indexOf(selectedValue)
131+ }
132+ }
133+ Spacer (modifier = Modifier .preferredHeight(10 .dp))
134+ Button (
135+ onClick = {
136+ onSubmitButtonClick.invoke(selectedOption.value)
137+ onDismissRequest.invoke()
138+ },
139+ shape = MaterialTheme .shapes.medium
140+ ) {
141+ Text (text = submitButtonText)
142+ }
143+ }
144+
145+ }
146+ }
147+ }
148+
149+
150+ @Composable
151+ fun RadioButton (text : String , selectedValue : String , onClickListener : (String ) -> Unit ) {
152+ Row (Modifier
153+ .fillMaxWidth()
154+ .selectable(
155+ selected = (text == selectedValue),
156+ onClick = {
157+ onClickListener(text)
158+ }
159+ )
160+ .padding(horizontal = 16 .dp)
161+ ) {
162+ // The Default Radio Button in Jetpack Compose doesn't accept text as an argument. So have Text Composable to show text.
163+ RadioButton (
164+ selected = (text == selectedValue),
165+ onClick = {
166+ onClickListener(text)
167+ }
168+ )
169+ Text (
170+ text = text,
171+ style = MaterialTheme .typography.body1.merge(),
172+ modifier = Modifier .padding(start = 16 .dp)
173+ )
174+ }
175+ }
176+
177+ // Dummy Util function for the sake of example
178+ fun getCountries (): Map <String , String > {
179+ val countriesMap = hashMapOf<String , String >()
180+ val isoCountries = Locale .getISOCountries()
181+ isoCountries.forEach {
182+ val locale = Locale (" " , it)
183+ countriesMap[locale.country.toLowerCase(Locale .getDefault())] = locale.displayCountry
184+ }
185+ return countriesMap.toList().sortedBy { (_, value) -> value }.toMap()
186+ }
0 commit comments