Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom text styles and dialog picker #18

Merged
merged 3 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading