Skip to content

Commit

Permalink
Support custom text styles and dialog picker
Browse files Browse the repository at this point in the history
  • Loading branch information
cp-megh-l committed Mar 6, 2024
1 parent 89b55d3 commit ed1b66d
Show file tree
Hide file tree
Showing 10 changed files with 388 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ package com.canopas.campose.jetcountypicker
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand All @@ -16,19 +23,20 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.canopas.campose.countrypicker.CountryPickerBottomSheet
import com.canopas.campose.countrypicker.CountryPickerView
import com.canopas.campose.countrypicker.CountryTextField
import com.canopas.campose.countrypicker.countryList
import com.canopas.campose.countrypicker.model.Country
import com.canopas.campose.countrypicker.model.PickerType
import com.canopas.campose.countypickerdemo.R
import com.canopas.campose.jetcountypicker.ui.theme.JetCountyPickerTheme

Expand All @@ -38,7 +46,9 @@ class MainActivity : ComponentActivity() {
setContent {
JetCountyPickerTheme {
Surface(color = MaterialTheme.colorScheme.background) {
SampleCountryPicker()
Column {
SampleCountryPickerDialog()
}
}
}
}
Expand All @@ -47,27 +57,66 @@ class MainActivity : ComponentActivity() {

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SampleCountryPicker() {
var openBottomSheet by rememberSaveable { mutableStateOf(false) }
fun SampleCountryPickerDialog() {
var showCountryPicker by rememberSaveable { mutableStateOf(false) }
var selectedCountry by remember { mutableStateOf<Country?>(null) }
var pickerType by remember {
mutableStateOf(PickerType.DIALOG)
}

Box {
CountryTextField(
label = stringResource(R.string.select_country_text),
modifier = Modifier
.fillMaxWidth()
.padding(top = 50.dp, start = 40.dp, end = 40.dp),
textStyle = MaterialTheme.typography.bodyMedium,
labelTextStyle = MaterialTheme.typography.labelMedium,
selectedCountry = selectedCountry,
defaultCountry = countryList(LocalContext.current).firstOrNull { it.code == "IN" },
onShowCountryPicker = {
openBottomSheet = true
}, isPickerVisible = openBottomSheet
showCountryPicker = true
}, isPickerVisible = showCountryPicker
)
}

if (openBottomSheet) {
CountryPickerBottomSheet(
bottomSheetTitle = {
Column(horizontalAlignment = Alignment.Start) {
Spacer(modifier = Modifier.height(28.dp))
Text(
text = stringResource(R.string.picker_type),
modifier = Modifier.padding(16.dp),
style = MaterialTheme.typography.bodyMedium
)
PickerType.entries.forEach {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable(
onClick = {
pickerType = it
}
),
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(
selected = pickerType == it,
onClick = {
pickerType = it
}
)
Text(
text = stringResource(it.value),
modifier = Modifier.padding(start = 8.dp),
style = MaterialTheme.typography.bodyMedium
)
}
}
}

if (showCountryPicker) {
CountryPickerView(
pickerTitle = {
Text(
modifier = Modifier
.fillMaxWidth()
Expand All @@ -78,12 +127,16 @@ fun SampleCountryPicker() {
fontSize = 20.sp
)
},
containerColor = Color.White,
searchFieldTextStyle = MaterialTheme.typography.bodyMedium,
placeholderTextStyle = MaterialTheme.typography.labelMedium,
countriesTextStyle = MaterialTheme.typography.bodyMedium,
onItemSelected = {
selectedCountry = it
openBottomSheet = false
}, onDismissRequest = {
openBottomSheet = false
showCountryPicker = false
},
pickerType = pickerType,
onDismissRequest = {
showCountryPicker = false
}
)
}
Expand All @@ -93,6 +146,6 @@ fun SampleCountryPicker() {
@Composable
fun DefaultPreview() {
JetCountyPickerTheme {
SampleCountryPicker()
SampleCountryPickerDialog()
}
}
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<resources>
<string name="app_name">JetCountyPicker</string>
<string name="select_country_text">Select country</string>
<string name="picker_type">Picker Type</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material3.BottomSheetDefaults
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.SheetState
import androidx.compose.material3.Text
Expand All @@ -25,22 +27,46 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.canopas.campose.countrypicker.model.Country
import kotlinx.coroutines.launch

/**
* Composable for displaying a bottom sheet country picker.
*
* @param sheetState The state of the bottom sheet.
* @param shape The shape of the bottom sheet.
* @param containerColor The color of the bottom sheet container.
* @param contentColor The color of the bottom sheet content.
* @param tonalElevation The elevation of the bottom sheet.
* @param scrimColor The color of the bottom sheet scrim.
* @param bottomSheetTitle The title composable for the bottom sheet.
* @param onItemSelected Callback when a country is selected.
* @param searchFieldTextStyle The text style for the search field.
* @param placeholderTextStyle The text style for the search field placeholder.
* @param countriesTextStyle The text style for the countries list.
* @param onDismissRequest Callback when the bottom sheet is dismissed.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CountryPickerBottomSheet(
sheetState: SheetState = rememberModalBottomSheetState(skipPartiallyExpanded = false),
shape: Shape = BottomSheetDefaults.ExpandedShape,
shape: Shape = MaterialTheme.shapes.medium,
containerColor: Color = BottomSheetDefaults.ContainerColor,
contentColor: Color = contentColorFor(containerColor),
tonalElevation: Dp = BottomSheetDefaults.Elevation,
scrimColor: Color = BottomSheetDefaults.ScrimColor,
bottomSheetTitle: @Composable () -> Unit,
onItemSelected: (country: Country) -> Unit,
searchFieldTextStyle: TextStyle = LocalTextStyle.current.copy(fontSize = 14.sp),
placeholderTextStyle: TextStyle = MaterialTheme.typography.labelMedium.copy(
color = Color.Gray,
fontSize = 16.sp,
),
countriesTextStyle: TextStyle = TextStyle(),
onDismissRequest: () -> Unit
) {
var searchValue by rememberSaveable { mutableStateOf("") }
Expand All @@ -57,11 +83,11 @@ fun CountryPickerBottomSheet(
) {
bottomSheetTitle()

CountrySearchView(searchValue) {
CountrySearchView(searchValue, searchFieldTextStyle, placeholderTextStyle) {
searchValue = it
}

Countries(searchValue) {
Countries(searchValue, countriesTextStyle) {
scope.launch {
sheetState.hide()
onItemSelected(it)
Expand All @@ -70,9 +96,17 @@ fun CountryPickerBottomSheet(
}
}

/**
* Composable for displaying a list of countries.
*
* @param searchValue The search value for filtering countries.
* @param textStyle The text style for the country list.
* @param onItemSelected Callback when a country is selected.
*/
@Composable
fun Countries(
internal fun Countries(
searchValue: String,
textStyle: TextStyle = TextStyle(),
onItemSelected: (country: Country) -> Unit
) {
val context = LocalContext.current
Expand All @@ -92,21 +126,25 @@ fun Countries(
.clickable { onItemSelected(country) }
.padding(12.dp)
) {
Text(text = localeToEmoji(country.code))
Text(
text = localeToEmoji(country.code),
style = textStyle
)
Text(
text = country.name,
modifier = Modifier
.padding(start = 8.dp)
.weight(2f)
.weight(2f),
style = textStyle
)
Text(
text = country.dial_code,
modifier = Modifier
.padding(start = 8.dp)
.padding(start = 8.dp),
style = textStyle
)
}
Divider(color = Color.LightGray, thickness = 0.5.dp)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.canopas.campose.countrypicker

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.canopas.campose.countrypicker.model.Country
import kotlinx.coroutines.launch


/**
* Composable for displaying a country picker as a dialog.
*
* @param shape The shape of the dialog.
* @param backgroundColor The color of the dialog container.
* @param dialogTitle The title composable for the dialog.
* @param onItemSelected Callback when a country is selected.
* @param searchFieldTextStyle The text style for the search field.
* @param placeholderTextStyle The text style for the search field placeholder.
* @param countriesTextStyle The text style for the countries list.
* @param showFullScreenDialog Whether to show the dialog as a full screen dialog.
* @param onDismissRequest Callback when the dialog is dismissed.
*/
@Composable
fun CountryPickerDialog(
shape: Shape = MaterialTheme.shapes.small,
backgroundColor: Color = MaterialTheme.colorScheme.background,
dialogTitle: @Composable () -> Unit,
onItemSelected: (country: Country) -> Unit,
searchFieldTextStyle: TextStyle = LocalTextStyle.current.copy(fontSize = 14.sp),
placeholderTextStyle: TextStyle = MaterialTheme.typography.labelMedium.copy(
color = Color.Gray,
fontSize = 16.sp,
),
countriesTextStyle: TextStyle = TextStyle(),
showFullScreenDialog: Boolean = false,
onDismissRequest: () -> Unit
) {
var searchValue by rememberSaveable { mutableStateOf("") }
val configuration = LocalConfiguration.current
val screenHeight = configuration.screenHeightDp.dp
val scope = rememberCoroutineScope()
val modifier = if (showFullScreenDialog) {
Modifier
.fillMaxSize()
.background(color = backgroundColor)
} else {
Modifier
.wrapContentHeight()
.heightIn(max = (screenHeight * 0.85f))
.clip(shape = shape)
.background(color = backgroundColor, shape)
}

Dialog(
onDismissRequest = onDismissRequest,
properties = DialogProperties(
usePlatformDefaultWidth = !showFullScreenDialog,
dismissOnBackPress = true,
dismissOnClickOutside = !showFullScreenDialog
)
) {
Column(
modifier = modifier
) {
dialogTitle()
CountrySearchView(searchValue, searchFieldTextStyle, placeholderTextStyle) {
searchValue = it
}

Countries(searchValue, countriesTextStyle) {
scope.launch {
onDismissRequest()
onItemSelected(it)
}
}
}
}
}
Loading

0 comments on commit ed1b66d

Please sign in to comment.