From 15b7d302d5a731c27ed4bc3c304fae3a072c33e7 Mon Sep 17 00:00:00 2001 From: hbb20 Date: Sat, 9 Sep 2023 15:38:28 -0400 Subject: [PATCH 01/10] compose --- app/build.gradle.kts | 6 + buildSrc/src/main/java/Dependencies.kt | 29 +++++ countrypicker/build.gradle.kts | 7 ++ .../compose/CountryPickerComposable.kt | 117 ++++++++++++++++++ .../com/hbb20/countrypicker/compose/Helper.kt | 22 ++++ 5 files changed, 181 insertions(+) create mode 100644 countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt create mode 100644 countrypicker/src/main/java/com/hbb20/countrypicker/compose/Helper.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index fd0c9b6..9e8953c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,6 +20,7 @@ android { buildFeatures { dataBinding = true viewBinding = true + compose = true } compileOptions { @@ -27,6 +28,10 @@ android { targetCompatibility = JavaVersion.VERSION_1_8 } + composeOptions { + kotlinCompilerExtensionVersion = Versions.COMPOSE_COMPILER + } + kotlinOptions { jvmTarget = JavaVersion.VERSION_1_8.toString() } @@ -73,6 +78,7 @@ dependencies { implementation(Deps.viewModels) implementation(Deps.timber) implementArchitectureComponents() + implementCompose() implementEpoxy() implementTesting() implementProject("countrypicker") diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index a935186..e8895ef 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -13,6 +13,7 @@ const val KAPT = "kapt" object Versions { const val BEN_MANES_VERSION_PLUGIN = "0.36.0" const val CHUCKER: String = "3.4.0" + const val COMPOSE_ACCOMPANIST = "0.28.0" const val COROUTINES = "1.6.4" const val DAGGER_2 = "2.29.1" // STOP: 2.30 problem with kaptDebugKotlin const val DETEKT = "1.17.1" @@ -56,6 +57,8 @@ object Versions { object Deps { const val activityKtx = "androidx.activity:activity-ktx:1.2.0-rc01" const val appCompat = "androidx.appcompat:appcompat:1.6.1" + // BOM to library mapping: https://developer.android.com/jetpack/compose/bom/bom-mapping + const val composeBoM = "androidx.compose:compose-bom:2023.01.00" const val constraintLayout = "androidx.constraintlayout:constraintlayout:2.1.4" const val emoji = "androidx.emoji:emoji:1.1.0" const val fragmentKtx = "androidx.fragment:fragment-ktx:1.5.5" @@ -111,3 +114,29 @@ fun DependencyHandlerScope.implementTesting() { add(TEST_IMPLEMENTATION, "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.COROUTINES}") add(TEST_IMPLEMENTATION, "junit:junit:4.13.2") } + + +fun DependencyHandlerScope.implementCompose() { + // BOM brings in compatible versions of other libraries so they work seamlessly internally. + // Since BoM is used, no need to specify versions of other compose libraries. + // To check version of particular library coming from BOM check + // https://developer.android.com/jetpack/compose/setup#bom-version-mapping + add(IMPLEMENTATION, platform(Deps.composeBoM)) + add(IMPLEMENTATION, "androidx.compose.ui:ui") + // Tooling support (Previews, etc.) + add(IMPLEMENTATION, "androidx.compose.ui:ui-tooling") + // Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.) + add(IMPLEMENTATION, "androidx.compose.foundation:foundation") + // Material Design + add(IMPLEMENTATION, "androidx.compose.material:material") + // Material design icons + add(IMPLEMENTATION, "androidx.compose.material:material-icons-core") + add(IMPLEMENTATION, "androidx.compose.material:material-icons-extended") + // Integration with observables + add(IMPLEMENTATION, "androidx.compose.runtime:runtime") + add(IMPLEMENTATION, "androidx.compose.runtime:runtime-livedata") + add(IMPLEMENTATION, "androidx.activity:activity-compose:1.6.1") + + // COMPOSE ACCOMPANIST + add(IMPLEMENTATION, "com.google.accompanist:accompanist-drawablepainter:${Versions.COMPOSE_ACCOMPANIST}") +} diff --git a/countrypicker/build.gradle.kts b/countrypicker/build.gradle.kts index 8d4caca..7b4db2a 100644 --- a/countrypicker/build.gradle.kts +++ b/countrypicker/build.gradle.kts @@ -13,6 +13,7 @@ android { minSdk = BuildData.minSdkVersion } buildFeatures { + compose = true dataBinding = true viewBinding = true } @@ -28,6 +29,11 @@ android { testOptions { unitTests.isIncludeAndroidResources = true } + + composeOptions { + kotlinCompilerExtensionVersion = Versions.COMPOSE_COMPILER + } + namespace = "com.hbb20.countrypicker" } dependencies { @@ -38,6 +44,7 @@ dependencies { implementation(Deps.emoji) implementation(Deps.googleMaterialDesign) implementation(Deps.timber) + implementCompose() implementEpoxy() implementTesting() } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt new file mode 100644 index 0000000..cdc01d4 --- /dev/null +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt @@ -0,0 +1,117 @@ +package com.hbb20.countrypicker.compose + +import androidx.annotation.DrawableRes +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.LocalContentColor +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.emoji.text.EmojiCompat +import com.hbb20.countrypicker.datagenerator.CPDataStoreGenerator +import com.hbb20.countrypicker.datagenerator.CountryFileReading +import com.hbb20.countrypicker.flagprovider.CPFlagImageProvider +import com.hbb20.countrypicker.flagprovider.CPFlagProvider +import com.hbb20.countrypicker.flagprovider.DefaultEmojiFlagProvider +import com.hbb20.countrypicker.models.CPDataStore + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun CountryLayout( + alpha2Code: String?, + cpDataStore: CPDataStore = rememberCPDataStore(), + emptySelectionText: String = cpDataStore.messageGroup.selectionPlaceholderText, + flagProvider: CPFlagProvider? = DefaultEmojiFlagProvider() +) { + val country = cpDataStore.countryList.firstOrNull { it.alpha2.equals(alpha2Code, ignoreCase = true) } + val countryFlag = if (country != null && flagProvider != null) { + when (flagProvider) { + is DefaultEmojiFlagProvider -> { + val emoji = when { + flagProvider.useEmojiCompat -> EmojiCompat.get() + .process(country.flagEmoji) + + else -> country.flagEmoji + } + CountryFlag.EmojiFlag(emoji) + } + + is CPFlagImageProvider -> { + CountryFlag.ImageFlag(flagProvider.getFlag(country.alpha2)) + } + else -> null + } + } else null + + val textToShow = country?.name ?: emptySelectionText + + Row(verticalAlignment = Alignment.CenterVertically) { + val textStyle = MaterialTheme.typography.button + if (countryFlag != null) { + when (countryFlag) { + is CountryFlag.EmojiFlag -> { + Text( + text = countryFlag.emoji.toString(), + style = textStyle, + color = LocalContentColor.current + ) + } + + is CountryFlag.ImageFlag -> { + Image( + painter = painterResource(id = countryFlag.flagImageRes), + contentDescription = null, + modifier = Modifier.height(textStyle.lineHeight.toDp()) + ) + } + } + Spacer(modifier = Modifier.height(8.dp)) + } + Text(text = textToShow, style = textStyle, color = LocalContentColor.current) + } + +} + +sealed class CountryFlag { + data class EmojiFlag(val emoji: CharSequence) : CountryFlag() + data class ImageFlag(@DrawableRes val flagImageRes: Int) : CountryFlag() +} + +@Composable +fun rememberCPDataStore( + customMasterCountries: String = CPDataStoreGenerator.defaultMasterCountries, + customExcludedCountries: String = CPDataStoreGenerator.defaultExcludedCountries, + countryFileReader: CountryFileReading = CPDataStoreGenerator.defaultCountryFileReader, + useCache: Boolean = CPDataStoreGenerator.defaultUseCache +): CPDataStore { + val context = LocalContext.current + return remember { + CPDataStoreGenerator.generate( + context, + customMasterCountries = customMasterCountries, + customExcludedCountries = customExcludedCountries, + countryFileReader = countryFileReader, + useCache = useCache + ) + } +} + +@Preview +@Composable +fun CountryPickerPreview() { + Surface(color = MaterialTheme.colors.surface) { + CountryLayout("gb") + } +} +// \ No newline at end of file diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/Helper.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/Helper.kt new file mode 100644 index 0000000..d9bd42f --- /dev/null +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/Helper.kt @@ -0,0 +1,22 @@ +package com.hbb20.countrypicker.compose + +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit + + +@Composable +fun Dp.toSp() = with(LocalDensity.current) { toSp() } + +@Composable +fun Dp.toPx() = with(LocalDensity.current) { toPx() } + +@Composable +fun Int.toDp() = with(LocalDensity.current) { toDp() } + +@Composable +fun Float.toDp() = with(LocalDensity.current) { toDp() } + +@Composable +fun TextUnit.toDp() = with(LocalDensity.current) { toDp() } \ No newline at end of file From 3fb97b2930a9a93153903e01587773c072bc5835 Mon Sep 17 00:00:00 2001 From: hbb20 Date: Sat, 9 Sep 2023 16:04:58 -0400 Subject: [PATCH 02/10] update deps --- build.gradle.kts | 2 +- buildSrc/src/main/java/BuildData.kt | 4 +-- buildSrc/src/main/java/Dependencies.kt | 32 ++++++++++++------------ gradle.properties | 3 +++ gradle/wrapper/gradle-wrapper.properties | 6 ++--- 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 49c37a8..e5681e4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ buildscript { } dependencies { - classpath("com.android.tools.build:gradle:7.4.2") + classpath("com.android.tools.build:gradle:8.1.1") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.KOTLIN_GRADLE_PLUGIN}") classpath("org.jlleitschuh.gradle:ktlint-gradle:${Versions.KTLINT_GRADLE}") classpath("androidx.navigation:navigation-safe-args-gradle-plugin:${Versions.NAVIGATION_GRAPH}") diff --git a/buildSrc/src/main/java/BuildData.kt b/buildSrc/src/main/java/BuildData.kt index d2e1264..442015f 100644 --- a/buildSrc/src/main/java/BuildData.kt +++ b/buildSrc/src/main/java/BuildData.kt @@ -10,6 +10,6 @@ object BuildData { // SDK versions const val minSdkVersion = 23 - const val targetSdkVersion = 33 - const val compileSdkVersion = 33 + const val targetSdkVersion = 34 + const val compileSdkVersion = 34 } \ No newline at end of file diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index e8895ef..3e1c3ef 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -13,11 +13,11 @@ const val KAPT = "kapt" object Versions { const val BEN_MANES_VERSION_PLUGIN = "0.36.0" const val CHUCKER: String = "3.4.0" - const val COMPOSE_ACCOMPANIST = "0.28.0" - const val COROUTINES = "1.6.4" + const val COMPOSE_ACCOMPANIST = "0.32.0" + const val COROUTINES = "1.7.3" const val DAGGER_2 = "2.29.1" // STOP: 2.30 problem with kaptDebugKotlin const val DETEKT = "1.17.1" - const val EPOXY = "5.1.1" + const val EPOXY = "5.1.3" const val FIREBASE_CRASHLYTICS_GRADLE = "2.3.0" //2.4.1 causes build error. const val GRADLE_BUILD_TOOL = "4.1.1" const val GRADLE_MAVEN_PUBLISH = "0.24.0" @@ -26,7 +26,7 @@ object Versions { const val MOSHI = "1.9.3" // v1.10+ causes build dependency error. needs investigation. const val MOSHI_SEALED = "0.2.0" const val RETROFIT = "2.9.0" - const val NAVIGATION_GRAPH = "2.5.3" + const val NAVIGATION_GRAPH = "2.7.2" const val SCARLET_VERSION = "0.1.11" const val KOTLIN = "1.4.21" const val KTLINT_GRADLE = "9.4.1" @@ -49,20 +49,20 @@ object Versions { // https://github.com/google/ksp/releases // First half of KSP version shows compatible KOTLIN version, // For example, ksp version 1.8.0-1.0.9 means it's compatible with KOTLIN 1.8.0 - const val COMPOSE_COMPILER = "1.4.3" - const val KOTLIN_GRADLE_PLUGIN = "1.8.10" // STOP : See 'Linked Dependencies' comment - const val KSP = "1.8.10-1.0.9" // STOP : See 'Linked Dependencies' comment + const val COMPOSE_COMPILER = "1.5.3" + const val KOTLIN_GRADLE_PLUGIN = "1.9.10" // STOP : See 'Linked Dependencies' comment + const val KSP = "$KOTLIN_GRADLE_PLUGIN-1.0.13" // STOP : See 'Linked Dependencies' comment } object Deps { const val activityKtx = "androidx.activity:activity-ktx:1.2.0-rc01" const val appCompat = "androidx.appcompat:appcompat:1.6.1" // BOM to library mapping: https://developer.android.com/jetpack/compose/bom/bom-mapping - const val composeBoM = "androidx.compose:compose-bom:2023.01.00" + const val composeBoM = "androidx.compose:compose-bom:2023.09.00" const val constraintLayout = "androidx.constraintlayout:constraintlayout:2.1.4" const val emoji = "androidx.emoji:emoji:1.1.0" - const val fragmentKtx = "androidx.fragment:fragment-ktx:1.5.5" - const val googleMaterialDesign = "com.google.android.material:material:1.9.0-alpha02" + const val fragmentKtx = "androidx.fragment:fragment-ktx:1.6.1" + const val googleMaterialDesign = "com.google.android.material:material:1.11.0-alpha02" const val viewModels = "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" const val timber = "com.jakewharton.timber:timber:5.0.1" const val apacheCSV = "org.apache.commons:commons-csv:1.7" @@ -83,8 +83,8 @@ fun DependencyHandlerScope.implementArchitectureComponents() { add(IMPLEMENTATION, "androidx.navigation:navigation-ui-ktx:${Versions.NAVIGATION_GRAPH}") add(IMPLEMENTATION, "androidx.lifecycle:lifecycle-extensions:2.2.0") add(IMPLEMENTATION, "androidx.legacy:legacy-support-v4:1.0.0") - add(IMPLEMENTATION, "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.0") - add(IMPLEMENTATION, "androidx.lifecycle:lifecycle-livedata-ktx:2.6.0") + add(IMPLEMENTATION, "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2") + add(IMPLEMENTATION, "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2") add(IMPLEMENTATION, "com.github.hadilq.liveevent:liveevent:1.2.0") } @@ -95,7 +95,7 @@ fun DependencyHandlerScope.implementEpoxy() { fun DependencyHandlerScope.implementKotlin(version: String) { add(IMPLEMENTATION, kotlin("stdlib-jdk7", version)) - add(IMPLEMENTATION, "androidx.core:core-ktx:1.9.0") + add(IMPLEMENTATION, "androidx.core:core-ktx:1.12.0") } fun DependencyHandlerScope.implementTesting() { @@ -105,12 +105,12 @@ fun DependencyHandlerScope.implementTesting() { // https://github.com/robolectric/robolectric/issues/5848 Will be able to update to 4.4 only after mockk can be updated to > 1.10.0 - add(TEST_IMPLEMENTATION, "org.robolectric:robolectric:4.9.2") + add(TEST_IMPLEMENTATION, "org.robolectric:robolectric:4.10.3") add(TEST_IMPLEMENTATION, "androidx.arch.core:core-testing:2.2.0") add(TEST_IMPLEMENTATION, "androidx.test:core:1.5.0") add(TEST_IMPLEMENTATION, "androidx.test:core-ktx:1.5.0") - add(TEST_IMPLEMENTATION, "io.mockk:mockk:1.13.4") + add(TEST_IMPLEMENTATION, "io.mockk:mockk:1.13.7") add(TEST_IMPLEMENTATION, "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.COROUTINES}") add(TEST_IMPLEMENTATION, "junit:junit:4.13.2") } @@ -135,7 +135,7 @@ fun DependencyHandlerScope.implementCompose() { // Integration with observables add(IMPLEMENTATION, "androidx.compose.runtime:runtime") add(IMPLEMENTATION, "androidx.compose.runtime:runtime-livedata") - add(IMPLEMENTATION, "androidx.activity:activity-compose:1.6.1") + add(IMPLEMENTATION, "androidx.activity:activity-compose:1.7.2") // COMPOSE ACCOMPANIST add(IMPLEMENTATION, "com.google.accompanist:accompanist-drawablepainter:${Versions.COMPOSE_ACCOMPANIST}") diff --git a/gradle.properties b/gradle.properties index ae98111..a9699db 100644 --- a/gradle.properties +++ b/gradle.properties @@ -34,5 +34,8 @@ POM_DEVELOPER_ID=hbb20 POM_DEVELOPER_NAME=Harsh Bhakta POM_DEVELOPER_URL=https://github.com/hbb20 VERSION_NAME=0.0.7 +android.defaults.buildfeatures.buildconfig=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false # ./gradlew countrypicker:uploadArchives --no-daemon --no-parallel -i # ./gradlew flagpack1:uploadArchives --no-daemon --no-parallel -i \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 671f4b4..48b4b44 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Dec 29 14:47:53 MST 2022 +#Sat Sep 09 15:42:56 EDT 2023 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists From ebcbc4dc4be11f2e9df360ee77c28200dbd30592 Mon Sep 17 00:00:00 2001 From: hbb20 Date: Sat, 18 Nov 2023 10:13:55 -0500 Subject: [PATCH 03/10] better slot api --- .../compose/CountryPickerComposable.kt | 519 ++++++++++++++++-- .../datagenerator/CPDataStoreGenerator.kt | 23 + 2 files changed, 503 insertions(+), 39 deletions(-) diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt index cdc01d4..d7929ff 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt @@ -2,73 +2,203 @@ package com.hbb20.countrypicker.compose import androidx.annotation.DrawableRes import androidx.compose.foundation.Image +import androidx.compose.foundation.background +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.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.Card +import androidx.compose.material.Divider import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon import androidx.compose.material.LocalContentColor import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface +import androidx.compose.material.OutlinedTextField import androidx.compose.material.Text +import androidx.compose.material.TextButton +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties import androidx.emoji.text.EmojiCompat +import com.hbb20.countrypicker.compose.CountryFlag.EmojiFlag +import com.hbb20.countrypicker.compose.CountryFlag.ImageFlag import com.hbb20.countrypicker.datagenerator.CPDataStoreGenerator import com.hbb20.countrypicker.datagenerator.CountryFileReading import com.hbb20.countrypicker.flagprovider.CPFlagImageProvider import com.hbb20.countrypicker.flagprovider.CPFlagProvider import com.hbb20.countrypicker.flagprovider.DefaultEmojiFlagProvider +import com.hbb20.countrypicker.helper.CPCountryDetector +import com.hbb20.countrypicker.models.CPCountry import com.hbb20.countrypicker.models.CPDataStore @OptIn(ExperimentalMaterialApi::class) +val countryMasterListTransformer = { countryList: List -> + var finalList = countryList + // to keep only a few countries + val countriesToInclude = + hashSetOf("IN", "PK", "US", "GB", "CA", "AU", "NZ", "DE", "FR", "ES", "IT") + finalList = finalList.filter { countriesToInclude.contains(it.alpha2) } + + // to remove only a few countries + val countriesToExclude = hashSetOf("GB") + finalList = finalList.filterNot { countriesToExclude.contains(it.alpha2) } + + // to sort by a particular order + finalList = finalList.sortedBy { it.phoneCode.toString() } + + // to modify any property of country + finalList = finalList.map { country -> + if (country.alpha2 == "IN") { + country.copy(name = "Bharat") + } else { + country + } + } + + finalList +} + @Composable -fun CountryLayout( +fun CountryPicker( alpha2Code: String?, cpDataStore: CPDataStore = rememberCPDataStore(), - emptySelectionText: String = cpDataStore.messageGroup.selectionPlaceholderText, - flagProvider: CPFlagProvider? = DefaultEmojiFlagProvider() + flagProvider: CPFlagProvider? = DefaultEmojiFlagProvider(), + modifier: Modifier = Modifier, + selectedCountryLayout: @Composable (( + country: CPCountry?, + countryFlag: CountryFlag?, + emptySelectionText: String, + modifier: Modifier, + showCountryPickerDialog: () -> Unit + ) -> Unit) = { country, countryFlag, emptySelectionText, modifier, showCountryPickerDialog -> + DefaultSelectedCountryLayout( + country, + countryFlag, + emptySelectionText, + modifier, + showCountryPickerDialog + ) + }, + pickerDialog: @Composable (( + cpDataStore: CPDataStore, + flagProvider: CPFlagProvider?, + onDismissRequest: () -> Unit, + onCountrySelected: (CPCountry?) -> Unit, + ) -> Unit) = { cpDataStore, + flagProvider, + onDismissRequest, + onCountrySelected -> + CountryPickerDialog( + cpDataStore = cpDataStore, + flagProvider = flagProvider, + onDismissRequest = onDismissRequest, + onCountrySelected = onCountrySelected + ) + }, + onCountrySelected: (CPCountry?) -> Unit, ) { - val country = cpDataStore.countryList.firstOrNull { it.alpha2.equals(alpha2Code, ignoreCase = true) } - val countryFlag = if (country != null && flagProvider != null) { - when (flagProvider) { - is DefaultEmojiFlagProvider -> { - val emoji = when { - flagProvider.useEmojiCompat -> EmojiCompat.get() - .process(country.flagEmoji) - - else -> country.flagEmoji - } - CountryFlag.EmojiFlag(emoji) - } - - is CPFlagImageProvider -> { - CountryFlag.ImageFlag(flagProvider.getFlag(country.alpha2)) - } - else -> null + val (showPickerDialog, setShowPickerDialog) = remember { mutableStateOf(false) } + val launchPickerDialog = remember { { setShowPickerDialog(true) } } + val country = rememberCountry(alpha2Code, cpDataStore) + val countryFlag = rememberFlag(country, flagProvider) + selectedCountryLayout( + country, + countryFlag, + cpDataStore.messageGroup.selectionPlaceholderText, + modifier, + launchPickerDialog, + ) + if (showPickerDialog) { + pickerDialog( + cpDataStore, + flagProvider, + { setShowPickerDialog(false) }) { + onCountrySelected(it) + setShowPickerDialog(false) } - } else null + } +} - val textToShow = country?.name ?: emptySelectionText - Row(verticalAlignment = Alignment.CenterVertically) { - val textStyle = MaterialTheme.typography.button +@Preview +@Composable +fun CountryLayoutPreview() { + val (selectedCountry, setSelectedCountry) = remember { mutableStateOf("IN") } + Column( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colors.background) + ) { + CountryPicker( + alpha2Code = selectedCountry, + modifier = Modifier + .fillMaxWidth() + .heightIn(min = 48.dp), + onCountrySelected = { setSelectedCountry(it?.alpha2) } + ) + } +} + +@Composable +private fun DefaultSelectedCountryLayout( + country: CPCountry?, + countryFlag: CountryFlag?, + emptySelectionText: String, + modifier: Modifier, + showCountryPickerDialog: () -> Unit, +) { + val textToShow = country?.name ?: emptySelectionText + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + .clip(RoundedCornerShape(4.dp)) + .clickable { showCountryPickerDialog() } + .padding(8.dp), + horizontalArrangement = Arrangement.Center + ) { + val textStyle = MaterialTheme.typography.body1 if (countryFlag != null) { when (countryFlag) { - is CountryFlag.EmojiFlag -> { + is EmojiFlag -> { Text( text = countryFlag.emoji.toString(), - style = textStyle, + style = MaterialTheme.typography.body1, color = LocalContentColor.current ) } - is CountryFlag.ImageFlag -> { + is ImageFlag -> { Image( painter = painterResource(id = countryFlag.flagImageRes), contentDescription = null, @@ -76,11 +206,36 @@ fun CountryLayout( ) } } - Spacer(modifier = Modifier.height(8.dp)) + Spacer(modifier = Modifier.width(8.dp)) } Text(text = textToShow, style = textStyle, color = LocalContentColor.current) + Icon( + Icons.Default.ArrowDropDown, + contentDescription = null, + tint = LocalContentColor.current, + ) } +} +@Composable +private fun rememberFlag( + country: CPCountry?, + flagProvider: CPFlagProvider? +) = remember(country, flagProvider) { + if (country != null && flagProvider != null) { + when (flagProvider) { + is DefaultEmojiFlagProvider -> { + val emoji = when { + flagProvider.useEmojiCompat -> EmojiCompat.get().process(country.flagEmoji) + else -> country.flagEmoji + } + EmojiFlag(emoji) + } + + is CPFlagImageProvider -> ImageFlag(flagProvider.getFlag(country.alpha2)) + else -> null + } + } else null } sealed class CountryFlag { @@ -90,28 +245,314 @@ sealed class CountryFlag { @Composable fun rememberCPDataStore( - customMasterCountries: String = CPDataStoreGenerator.defaultMasterCountries, - customExcludedCountries: String = CPDataStoreGenerator.defaultExcludedCountries, countryFileReader: CountryFileReading = CPDataStoreGenerator.defaultCountryFileReader, - useCache: Boolean = CPDataStoreGenerator.defaultUseCache + countryListTransformer: ((List) -> List)? = null, ): CPDataStore { val context = LocalContext.current - return remember { + return remember(countryFileReader) { CPDataStoreGenerator.generate( context, - customMasterCountries = customMasterCountries, - customExcludedCountries = customExcludedCountries, countryFileReader = countryFileReader, - useCache = useCache + countryListTransformer = countryListTransformer + ) + } +} + +@Composable +fun CountryPickerDialog( + cpDataStore: CPDataStore = rememberCPDataStore(), + flagProvider: CPFlagProvider? = DefaultEmojiFlagProvider(), + quickAccessCountries: List? = rememberQuickAccessCountries(), + showFilter: Boolean = cpDataStore.countryList.size >= 6, + fillHeight: Boolean = showFilter, + allowClearSelection: Boolean = true, + queryFilter: (country: CPCountry, filterQuery: String) -> Boolean = { country, filterQuery -> + defaultFilter(country, filterQuery) + }, + onDismissRequest: () -> Unit, + onCountrySelected: (CPCountry?) -> Unit, +) { + Dialog( + onDismissRequest = { onDismissRequest() }, + properties = DialogProperties(usePlatformDefaultWidth = true) + ) { + DefaultCountryPickerDialogContent( + quickAccessCountriesCodes = quickAccessCountries, + cpDataStore = cpDataStore, + onDismissRequest = onDismissRequest, + onCountrySelected = onCountrySelected, + showFilter = showFilter, + fillHeight = fillHeight, + flagProvider = flagProvider, + allowClearSelection = allowClearSelection, + queryFilter = queryFilter + ) + } +} + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +private fun DefaultCountryPickerDialogContent( + cpDataStore: CPDataStore, + flagProvider: CPFlagProvider?, + quickAccessCountriesCodes: List?, + onCountrySelected: (CPCountry?) -> Unit, + showFilter: Boolean, + fillHeight: Boolean, + allowClearSelection: Boolean, + queryFilter: (country: CPCountry, filterQuery: String) -> Boolean = { country, filterQuery -> + defaultFilter(country, filterQuery) + }, + searchFieldLayout: @Composable (( + searchQuery: String, + setSearchQuery: (String) -> Unit, + cpDataStore: CPDataStore + ) -> Unit) = { searchQuery, setSearchQuery, cpDataStore -> + DefaultSearchField(searchQuery, setSearchQuery, cpDataStore) + }, + onDismissRequest: () -> Unit, +) { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + shape = RoundedCornerShape(16.dp), + ) { + val countryList = remember(cpDataStore) { + cpDataStore.countryList + } + val quickAccessCountries = remember(quickAccessCountriesCodes, countryList) { + quickAccessCountriesCodes.orEmpty().mapNotNull { alpha2 -> + countryList.firstOrNull { it.alpha2.equals(alpha2, ignoreCase = true) } + } + } + val (searchQuery, setSearchQuery) = remember { mutableStateOf("") } + val filteredList = remember(countryList, searchQuery) { + countryList.filter { queryFilter(it, searchQuery) } + } + val filteredQuickAccessCountries = remember(showFilter, quickAccessCountries, searchQuery) { + if (showFilter == false) emptyList() + else quickAccessCountries.filter { queryFilter(it, searchQuery) } + } + Column { + if (showFilter) { + searchFieldLayout(searchQuery, setSearchQuery, cpDataStore) + } + LazyColumn(modifier = Modifier.weight(1f, fill = fillHeight)) { + if (filteredQuickAccessCountries.isNotEmpty()) { + filteredQuickAccessCountries.forEach { country -> + item("quickAccess-" + country.alpha2) { + CountryListItemRowLayout( + country = country, + flagProvider = flagProvider, + ) { + onCountrySelected(it) + onDismissRequest() + } + } + } + item { Divider() } + } + filteredList.forEach { country -> + item(country.alpha2) { + CountryListItemRowLayout( + country = country, + flagProvider = flagProvider, + ) { + onCountrySelected(it) + onDismissRequest() + } + } + } + } + if (allowClearSelection) { + TextButton( + onClick = { onCountrySelected(null) }, + modifier = Modifier.padding(start = 8.dp, bottom = 8.dp) + ) { + Text( + text = cpDataStore.messageGroup.clearSelectionText, + style = MaterialTheme.typography.button, + color = MaterialTheme.colors.onBackground + ) + } + } + } + } +} + +@Composable +@OptIn(ExperimentalComposeUiApi::class) +private fun DefaultSearchField( + searchQuery: String, + setSearchQuery: (String) -> Unit, + cpDataStore: CPDataStore +) { + val keyboardController = LocalSoftwareKeyboardController.current + val focusManager = LocalFocusManager.current + val searchFieldFocusRequester = remember { + FocusRequester() + } + OutlinedTextField( + value = searchQuery, + onValueChange = { setSearchQuery(it) }, + placeholder = { + Text( + text = cpDataStore.messageGroup.searchHint, + style = MaterialTheme.typography.body1, + color = MaterialTheme.colors.onSurface + ) + }, + textStyle = MaterialTheme.typography.body1, + singleLine = true, + keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Search), + keyboardActions = KeyboardActions(onAny = { + keyboardController?.hide() + focusManager.clearFocus() + }), + modifier = Modifier + .padding(horizontal = 16.dp) + .padding(top = 16.dp) + .fillMaxWidth() + .focusRequester(searchFieldFocusRequester), + ) + + LaunchedEffect(key1 = Unit) { + searchFieldFocusRequester.requestFocus() + } +} + +@Composable +private fun CountryListItemRowLayout( + country: CPCountry, + flagProvider: CPFlagProvider?, + onClicked: (CPCountry) -> Unit, +) { + val countryFlag = rememberFlag(country, flagProvider) + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { + onClicked(country) + } + .padding(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + if (countryFlag != null) { + when (countryFlag) { + is EmojiFlag -> { + Text( + text = countryFlag.emoji.toString(), + style = MaterialTheme.typography.body1, + color = LocalContentColor.current + ) + } + + is ImageFlag -> { + Image( + painter = painterResource(id = countryFlag.flagImageRes), + contentDescription = null, + modifier = Modifier.height(MaterialTheme.typography.body1.lineHeight.toDp()) + ) + } + } + Spacer(modifier = Modifier.width(16.dp)) + } + Column(modifier = Modifier.weight(1f)) { + Text( + text = "${country.name} (${country.alpha2})", + style = MaterialTheme.typography.body1, + color = MaterialTheme.colors.onSurface, + ) + Text( + text = "${country.capitalEnglishName} - ${country.population}", + style = MaterialTheme.typography.body1, + color = MaterialTheme.colors.onSurface + ) + } + Text( + text = "+${country.phoneCode}", + style = MaterialTheme.typography.body2, + color = MaterialTheme.colors.onBackground ) } } +private fun defaultFilter( + country: CPCountry, + filterQuery: String, +) = if (filterQuery.isBlank()) true +else { + val properties = listOf( + country.name, + country.englishName, + country.alpha2, + country.alpha3, + ) + properties.any { it.contains(filterQuery, ignoreCase = true) } +} + @Preview @Composable -fun CountryPickerPreview() { - Surface(color = MaterialTheme.colors.surface) { - CountryLayout("gb") +fun PreviewSomeDialogContent() { + MaterialTheme { + Box( + modifier = Modifier + .fillMaxSize() + .background(Color.Gray) + .padding(20.dp), + contentAlignment = Alignment.Center, + ) { + DefaultCountryPickerDialogContent( + cpDataStore = rememberCPDataStore(countryListTransformer = countryMasterListTransformer), + flagProvider = DefaultEmojiFlagProvider(), + quickAccessCountriesCodes = null, + showFilter = false, + fillHeight = false, + allowClearSelection = true, + queryFilter = { cpCountry, query -> defaultFilter(cpCountry, query) }, + onDismissRequest = {}, + onCountrySelected = {}, + ) + } + } +} + +@Composable +fun rememberCountry( + countryCode: String?, + cpDataStore: CPDataStore = rememberCPDataStore() +): CPCountry? { + return remember(countryCode, cpDataStore) { + cpDataStore.countryList.firstOrNull { it.alpha2.equals(countryCode, ignoreCase = true) } + } +} + +@Composable +fun rememberAutoDetectedCountryCode( + sourceOrder: List = listOf( + CPCountryDetector.Source.SIM, + CPCountryDetector.Source.NETWORK, + CPCountryDetector.Source.LOCALE + ) +): String? { + val context = LocalContext.current + return remember(sourceOrder) { + CPCountryDetector(context).detectCountry(sourceOrder) } } + +@Composable +fun rememberQuickAccessCountries(): List { + val countryDetector = CPCountryDetector(LocalContext.current) + return remember { + listOf( + countryDetector.detectSIMCountry(), + countryDetector.detectNetworkCountry(), + countryDetector.detectLocaleCountry() + ).filterNotNull().distinct() + } +} + + // \ No newline at end of file diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/datagenerator/CPDataStoreGenerator.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/datagenerator/CPDataStoreGenerator.kt index 8c9e8e0..798b553 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/datagenerator/CPDataStoreGenerator.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/datagenerator/CPDataStoreGenerator.kt @@ -10,6 +10,7 @@ object CPDataStoreGenerator { private var masterDataStore: CPDataStore? = null const val defaultMasterCountries = "" const val defaultExcludedCountries = "" + @Deprecated("no-longer-used") const val defaultUseCache = true val defaultCountryFileReader = CPFileReader @@ -45,6 +46,28 @@ object CPDataStoreGenerator { throw IllegalStateException("MasterDataStore can not be null at this point.") } + fun generate( + context: Context, + countryFileReader: CountryFileReading = defaultCountryFileReader, + countryListTransformer: ((List) -> List)? + ): CPDataStore { + onMethodBegin("GenerateDataStore") + if (masterDataStore == null) { + masterDataStore = countryFileReader.readMasterDataFromFiles(context) + } + + masterDataStore?.let { + var countryList: List = it.countryList + countryList = countryList.sortedBy { cpCountry -> cpCountry.name } + countryListTransformer?.let { transformer -> + countryList = transformer(countryList) + } + return it.copy(countryList.toMutableList()) + } + + throw IllegalStateException("MasterDataStore can not be null at this point.") + } + private fun filterExcludedCountriesList( countryList: List, customExcludedCountries: String From 9b0e3a312350a0c9f618f90e572c86d6b3ac61dc Mon Sep 17 00:00:00 2001 From: hbb20 Date: Sat, 18 Nov 2023 10:14:23 -0500 Subject: [PATCH 04/10] make modifier first optional param --- .../com/hbb20/countrypicker/compose/CountryPickerComposable.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt index d7929ff..db21fb6 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt @@ -92,9 +92,9 @@ val countryMasterListTransformer = { countryList: List -> @Composable fun CountryPicker( alpha2Code: String?, + modifier: Modifier = Modifier, cpDataStore: CPDataStore = rememberCPDataStore(), flagProvider: CPFlagProvider? = DefaultEmojiFlagProvider(), - modifier: Modifier = Modifier, selectedCountryLayout: @Composable (( country: CPCountry?, countryFlag: CountryFlag?, From f659acfc8b2e342405cba63e2976b26b7f11b88d Mon Sep 17 00:00:00 2001 From: hbb20 Date: Sat, 18 Nov 2023 10:39:20 -0500 Subject: [PATCH 05/10] add demo activity --- app/build.gradle.kts | 7 ++- app/src/main/AndroidManifest.xml | 10 +++- .../androidcountrypicker/DemoApplication.kt | 6 +-- .../androidcountrypicker/MainActivity.kt | 5 ++ .../compose/ComposeDemoActivity.kt | 54 +++++++++++++++++++ app/src/main/res/layout/activity_main.xml | 12 +++++ app/src/main/res/values/strings.xml | 1 + .../compose/CountryPickerComposable.kt | 16 ++---- 8 files changed, 91 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9e8953c..2a4a69a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -16,6 +16,9 @@ android { versionCode = BuildData.versionCode versionName = BuildData.versionName testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } } buildFeatures { dataBinding = true @@ -31,10 +34,10 @@ android { composeOptions { kotlinCompilerExtensionVersion = Versions.COMPOSE_COMPILER } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8.toString() + jvmTarget = "1.8" } + packagingOptions { jniLibs { excludes += setOf("META-INF/licenses/**") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index de5a8c7..f7e388b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,10 +9,16 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - + + - diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/DemoApplication.kt b/app/src/main/java/com/hbb20/androidcountrypicker/DemoApplication.kt index 1ddfe0d..757670a 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/DemoApplication.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/DemoApplication.kt @@ -7,8 +7,8 @@ class DemoApplication : Application() { override fun onCreate() { super.onCreate() - if (BuildConfig.DEBUG) { - Timber.plant(Timber.DebugTree()) - } +// if (BuildConfig.DEBUG) { +// Timber.plant(Timber.DebugTree()) +// } } } diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/MainActivity.kt b/app/src/main/java/com/hbb20/androidcountrypicker/MainActivity.kt index 93f6a99..65a85ae 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/MainActivity.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/MainActivity.kt @@ -5,6 +5,7 @@ import android.os.Bundle import android.view.View import androidx.appcompat.app.AppCompatActivity import com.hbb20.CountryPickerView +import com.hbb20.androidcountrypicker.compose.ComposeDemoActivity import com.hbb20.androidcountrypicker.databinding.ActivityMainBinding import com.hbb20.contrypicker.flagpack1.FlagPack1 import com.hbb20.countrypicker.flagprovider.CPFlagImageProvider @@ -48,4 +49,8 @@ class MainActivity : AppCompatActivity() { fun openCpViewDemo(view: View) { startActivity(Intent(this, CountryPickerViewDemoActivity::class.java)) } + + fun openComposeDemo(view: View) { + startActivity(Intent(this, ComposeDemoActivity::class.java)) + } } diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt b/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt new file mode 100644 index 0000000..790cd70 --- /dev/null +++ b/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt @@ -0,0 +1,54 @@ +package com.hbb20.androidcountrypicker.compose + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.hbb20.countrypicker.compose.CountryPicker + +class ComposeDemoActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + MaterialTheme { + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colors.background + ) { + val (countryCode, setCountryCode) = remember { mutableStateOf("In") } + Column { + CountryPicker(alpha2Code = countryCode) { + setCountryCode(it?.alpha2) + } + } + } + } + } + } +} + +@Composable +fun Greeting(name: String, modifier: Modifier = Modifier) { + Text( + text = "Hello $name!", + modifier = modifier + ) +} + +@Preview(showBackground = true) +@Composable +fun GreetingPreview() { + MaterialTheme { + Greeting("Android") + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 85bd758..fc0fdb2 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -121,6 +121,18 @@ android:paddingLeft="8dp" android:text="CP View Demo" android:textStyle="bold" /> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c6442ff..db24175 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6,4 +6,5 @@ File icon Category icon Error Icon + ComposeDemoActivity diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt index db21fb6..04edaa3 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt @@ -274,7 +274,7 @@ fun CountryPickerDialog( ) { Dialog( onDismissRequest = { onDismissRequest() }, - properties = DialogProperties(usePlatformDefaultWidth = true) + properties = DialogProperties(usePlatformDefaultWidth = false) ) { DefaultCountryPickerDialogContent( quickAccessCountriesCodes = quickAccessCountries, @@ -332,7 +332,7 @@ private fun DefaultCountryPickerDialogContent( } val filteredQuickAccessCountries = remember(showFilter, quickAccessCountries, searchQuery) { if (showFilter == false) emptyList() - else quickAccessCountries.filter { queryFilter(it, searchQuery) } + else quickAccessCountries.filter { queryFilter(it, searchQuery) }.distinctBy(CPCountry::alpha2) } Column { if (showFilter) { @@ -460,21 +460,11 @@ private fun CountryListItemRowLayout( } Column(modifier = Modifier.weight(1f)) { Text( - text = "${country.name} (${country.alpha2})", + text = country.name, style = MaterialTheme.typography.body1, color = MaterialTheme.colors.onSurface, ) - Text( - text = "${country.capitalEnglishName} - ${country.population}", - style = MaterialTheme.typography.body1, - color = MaterialTheme.colors.onSurface - ) } - Text( - text = "+${country.phoneCode}", - style = MaterialTheme.typography.body2, - color = MaterialTheme.colors.onBackground - ) } } From 4f435f1d32d2be4c5ed89939663361799e8800fb Mon Sep 17 00:00:00 2001 From: hbb20 Date: Mon, 18 Dec 2023 10:08:23 -0700 Subject: [PATCH 06/10] add compose-support --- .../compose/ComposeDemoActivity.kt | 346 +++++++++++++++++- buildSrc/src/main/java/Dependencies.kt | 20 +- .../compose/CountryPickerComposable.kt | 208 ++++++----- .../src/main/res/drawable/ic_cp_search.xml | 5 + 4 files changed, 480 insertions(+), 99 deletions(-) create mode 100644 countrypicker/src/main/res/drawable/ic_cp_search.xml diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt b/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt index 790cd70..97f7cdb 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt @@ -3,17 +3,49 @@ package com.hbb20.androidcountrypicker.compose import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Card +import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface import androidx.compose.material.Text +import androidx.compose.material.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.hbb20.androidcountrypicker.R +import com.hbb20.contrypicker.flagpack1.FlagPack1 +import com.hbb20.countrypicker.compose.CountryFlagLayout import com.hbb20.countrypicker.compose.CountryPicker +import com.hbb20.countrypicker.compose.CountryPickerDialog +import com.hbb20.countrypicker.compose.rememberAutoDetectedCountryCode +import com.hbb20.countrypicker.compose.rememberCPDataStore +import com.hbb20.countrypicker.compose.rememberCountry +import com.hbb20.countrypicker.compose.rememberCountryFlag +import com.hbb20.countrypicker.flagprovider.CPFlagImageProvider +import com.hbb20.countrypicker.flagprovider.DefaultEmojiFlagProvider class ComposeDemoActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -26,15 +58,325 @@ class ComposeDemoActivity : ComponentActivity() { color = MaterialTheme.colors.background ) { val (countryCode, setCountryCode) = remember { mutableStateOf("In") } - Column { + Column(modifier = Modifier.verticalScroll(rememberScrollState())) { CountryPicker(alpha2Code = countryCode) { setCountryCode(it?.alpha2) } + OutOfBox() + AutoDetectedInitialCountry() + UseFlagPack() + UseCustomFlagDrawables() + UseNoFlag() + PhoneCodePicker() + CountryCurrencyPicker() } } } } } + + @Composable + private fun OutOfBox() { + CardTemplate( + "Out of box", + "This is how it works without any other config changes" + ) { + val (countryCode, setCountryCode) = remember { mutableStateOf(null) } + CountryPicker(alpha2Code = countryCode) { + setCountryCode(it?.alpha2) + } + } + } + + @Composable + private fun AutoDetectedInitialCountry() { + CardTemplate( + "Initial auto detected country", + "Detect country and set it as initial country. Optionally pass order of sources (SIM, NETWORK, LOCALE) for country detection.", + ) { + val initialCountryCode = rememberAutoDetectedCountryCode() + // Note: for state management, + // if you need to hoist the selected country code outside of compose + // then use CPCountryDetector::detectCountry() + val (countryCode, setCountryCode) = remember { mutableStateOf(initialCountryCode) } + CountryPicker(alpha2Code = countryCode) { + setCountryCode(it?.alpha2) + } + } + } + + + @Composable + private fun UseFlagPack() { + CardTemplate( + "Use flag pack", + "Use flag pack images instead of emoji flags", + ) { + val initialCountryCode = rememberAutoDetectedCountryCode() + val (countryCode, setCountryCode) = remember { mutableStateOf(initialCountryCode) } + CountryPicker( + alpha2Code = countryCode, + flagProvider = CPFlagImageProvider( + FlagPack1.alpha2ToFlag, + FlagPack1.missingFlagPlaceHolder + ) + ) { + setCountryCode(it?.alpha2) + } + } + } + + @Composable + private fun UseNoFlag() { + CardTemplate( + "Dont show flag", + "Dont show flags", + ) { + val initialCountryCode = rememberAutoDetectedCountryCode() + val (countryCode, setCountryCode) = remember { mutableStateOf(initialCountryCode) } + CountryPicker( + alpha2Code = countryCode, + flagProvider = null, + ) { + setCountryCode(it?.alpha2) + } + } + } + + + @Composable + private fun UseCustomFlagDrawables() { + CardTemplate( + "Custom flag images", + "Use your flag drawables", + ) { + val initialCountryCode = rememberAutoDetectedCountryCode() + val (countryCode, setCountryCode) = remember { mutableStateOf(initialCountryCode) } + CountryPicker( + alpha2Code = countryCode, + flagProvider = CPFlagImageProvider( + // map of alpha2 to drawable resource id + alpha2ToFlag = mapOf( + "IN" to R.drawable.ic_flag, + "US" to R.drawable.ic_flag, + "GB" to R.drawable.ic_flag, + ), + // drawable resource id for missing flag + missingFlagPlaceHolder = R.drawable.ic_flag + ) + ) { + setCountryCode(it?.alpha2) + } + } + } + + @Composable + private fun PhoneCodePicker() { + CardTemplate( + "Use as Country Phone Code Picker", + "Commonly used to select country with phone input box. Note: This does not auto format the phone number. Phone number formatting is beyond the scope of this library.", + ) { + val initialCountryCode = rememberAutoDetectedCountryCode() + val cpDataStore = rememberCPDataStore() + val (countryCode, setCountryCode) = remember { mutableStateOf(initialCountryCode) } + val (phoneNumber, setPhoneNumber) = remember { mutableStateOf("") } + val (showPickerDialog, setShowPickerDialog) = remember { mutableStateOf(false) } + val flagProvider = DefaultEmojiFlagProvider() + + Row( + modifier = Modifier.height(IntrinsicSize.Min), + verticalAlignment = CenterVertically + ) { + // + Row(modifier = Modifier + .fillMaxHeight() + .clickable { setShowPickerDialog(true) } + .padding(8.dp), verticalAlignment = CenterVertically) { + val country = rememberCountry(countryCode) + val flag = rememberCountryFlag(country, flagProvider) + + CountryFlagLayout(flag) + Spacer(modifier = Modifier.padding(4.dp)) + val text = + if (country == null) cpDataStore.messageGroup.selectionPlaceholderText else "+${country.phoneCode} " + Text(text = text) + Icon( + painter = painterResource(id = R.drawable.ic_arrow_drop_down), + contentDescription = null, + modifier = Modifier + .padding(4.dp) + .size(16.dp) + ) + } + TextField( + value = phoneNumber, + onValueChange = { setPhoneNumber(it) }, + keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number) + ) + } + + if(showPickerDialog){ + CountryPickerDialog( + cpDataStore = cpDataStore, + flagProvider = flagProvider, + onDismissRequest = { setShowPickerDialog(false) }, + countryRowLayout = { country, flagProvider, onClicked -> + Row(modifier = Modifier + .fillMaxWidth() + .heightIn(min = 48.dp) + .clickable { onClicked(country) } + .padding(12.dp), + verticalAlignment = CenterVertically) { + CountryFlagLayout(rememberCountryFlag(country, flagProvider)) + Spacer(modifier = Modifier.padding(4.dp)) + Text( + text = country.name, + modifier = Modifier.weight(1f) + ) + Text(text = "+${country.phoneCode}") + } + }, + queryFilter = { country, query -> + val properties = listOf( + country.name, + country.englishName, + country.alpha2, + country.alpha3, + country.phoneCode.toString(), + ) + properties.any { it.contains(query, ignoreCase = true) } + }, + ) { + setCountryCode(it?.alpha2) + // your logic to use phone code + } + } + } + } + + @Composable + private fun CountryCurrencyPicker() { + CardTemplate( + "Use as Country's Currency Picker", + "Commonly used to select currency with money input. " + + "\nNote: This does not auto format the phone number." + + " Phone number formatting is beyond the scope of this library.", + ) { + val initialCountryCode = rememberAutoDetectedCountryCode() + val (countryCode, setCountryCode) = remember { mutableStateOf(initialCountryCode) } + val (amount, setAmount) = remember { mutableStateOf("") } + CountryPicker(alpha2Code = countryCode, + cpDataStore = rememberCPDataStore { originalCountryList -> + originalCountryList.sortedBy { it.currencyName } + .filterNot { it.currencyCode.isBlank() } + }, + selectedCountryLayout = { country, flag, emptySelectionText, modifier, showCountryPickerDialog -> + Row( + modifier = Modifier.height(IntrinsicSize.Min), + verticalAlignment = CenterVertically + ) { + Row(modifier = modifier + .fillMaxHeight() + .clickable { showCountryPickerDialog() } + .padding(8.dp), verticalAlignment = CenterVertically) { + CountryFlagLayout(flag) + Spacer(modifier = Modifier.padding(4.dp)) + val text = + if (country == null) emptySelectionText else "${country.currencyCode} ${country.currencySymbol}" + Text(text = text) + } + TextField( + value = amount, + onValueChange = { setAmount(it) }, + keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number) + ) + } + }, + pickerDialog = { cpDataStore, flagProvider, onDismissRequest, onCountrySelected -> + CountryPickerDialog( + cpDataStore = cpDataStore, + flagProvider = flagProvider, + onDismissRequest = onDismissRequest, + countryRowLayout = { country, flagProvider, onClicked -> + Row(modifier = Modifier + .fillMaxWidth() + .heightIn(min = 48.dp) + .clickable { onClicked(country) } + .padding(12.dp), + verticalAlignment = CenterVertically) { + CountryFlagLayout(rememberCountryFlag(country, flagProvider)) + Spacer(modifier = Modifier.padding(4.dp)) + Column(modifier = Modifier.weight(1f)) { + + Text( + text = "${country.currencyName} (${country.currencySymbol})", + style = MaterialTheme.typography.subtitle2 + ) + Text( + text = country.name, + style = MaterialTheme.typography.body2 + ) + } + Text( + text = "${country.currencyCode}", + style = MaterialTheme.typography.subtitle1 + ) + } + }, + queryFilter = { country, query -> + val sanitizedQuery = query.trim().removePrefix("+") + val properties = listOf( + country.name, + country.englishName, + country.alpha2, + country.alpha3, + country.currencyName, + country.currencyCode, + country.currencySymbol, + ) + properties.any { it.contains(sanitizedQuery, ignoreCase = true) } + }, + ) { + setCountryCode(it?.alpha2) + val currencyCode = it?.currencyCode + // your logic to use currency code + } + } + ) { + setCountryCode(it?.alpha2) + } + } + } + + + @Composable + private fun CardTemplate( + title: String, + body: String, + countryPickerLayout: @Composable () -> Unit + ) { + Card( + modifier = Modifier + .fillMaxWidth() + .background(MaterialTheme.colors.surface) + .padding(16.dp) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = title, + style = MaterialTheme.typography.subtitle1, + color = Color.Black + ) + Text( + text = body, + style = MaterialTheme.typography.body2, + color = Color.DarkGray + ) + Spacer(modifier = Modifier.padding(8.dp)) + countryPickerLayout() + } + } + } } @Composable @@ -51,4 +393,4 @@ fun GreetingPreview() { MaterialTheme { Greeting("Android") } -} \ No newline at end of file +} diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 3e1c3ef..9b8c66c 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -26,7 +26,7 @@ object Versions { const val MOSHI = "1.9.3" // v1.10+ causes build dependency error. needs investigation. const val MOSHI_SEALED = "0.2.0" const val RETROFIT = "2.9.0" - const val NAVIGATION_GRAPH = "2.7.2" + const val NAVIGATION_GRAPH = "2.7.5" const val SCARLET_VERSION = "0.1.11" const val KOTLIN = "1.4.21" const val KTLINT_GRADLE = "9.4.1" @@ -49,20 +49,20 @@ object Versions { // https://github.com/google/ksp/releases // First half of KSP version shows compatible KOTLIN version, // For example, ksp version 1.8.0-1.0.9 means it's compatible with KOTLIN 1.8.0 - const val COMPOSE_COMPILER = "1.5.3" - const val KOTLIN_GRADLE_PLUGIN = "1.9.10" // STOP : See 'Linked Dependencies' comment - const val KSP = "$KOTLIN_GRADLE_PLUGIN-1.0.13" // STOP : See 'Linked Dependencies' comment + const val COMPOSE_COMPILER = "1.5.4" + const val KOTLIN_GRADLE_PLUGIN = "1.9.20" // STOP : See 'Linked Dependencies' comment + const val KSP = "$KOTLIN_GRADLE_PLUGIN-1.0.14" // STOP : See 'Linked Dependencies' comment } object Deps { const val activityKtx = "androidx.activity:activity-ktx:1.2.0-rc01" const val appCompat = "androidx.appcompat:appcompat:1.6.1" // BOM to library mapping: https://developer.android.com/jetpack/compose/bom/bom-mapping - const val composeBoM = "androidx.compose:compose-bom:2023.09.00" + const val composeBoM = "androidx.compose:compose-bom:2023.10.01" const val constraintLayout = "androidx.constraintlayout:constraintlayout:2.1.4" const val emoji = "androidx.emoji:emoji:1.1.0" - const val fragmentKtx = "androidx.fragment:fragment-ktx:1.6.1" - const val googleMaterialDesign = "com.google.android.material:material:1.11.0-alpha02" + const val fragmentKtx = "androidx.fragment:fragment-ktx:1.6.2" + const val googleMaterialDesign = "com.google.android.material:material:1.12.0-alpha01" const val viewModels = "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" const val timber = "com.jakewharton.timber:timber:5.0.1" const val apacheCSV = "org.apache.commons:commons-csv:1.7" @@ -105,12 +105,12 @@ fun DependencyHandlerScope.implementTesting() { // https://github.com/robolectric/robolectric/issues/5848 Will be able to update to 4.4 only after mockk can be updated to > 1.10.0 - add(TEST_IMPLEMENTATION, "org.robolectric:robolectric:4.10.3") + add(TEST_IMPLEMENTATION, "org.robolectric:robolectric:4.11.1") add(TEST_IMPLEMENTATION, "androidx.arch.core:core-testing:2.2.0") add(TEST_IMPLEMENTATION, "androidx.test:core:1.5.0") add(TEST_IMPLEMENTATION, "androidx.test:core-ktx:1.5.0") - add(TEST_IMPLEMENTATION, "io.mockk:mockk:1.13.7") + add(TEST_IMPLEMENTATION, "io.mockk:mockk:1.13.8") add(TEST_IMPLEMENTATION, "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.COROUTINES}") add(TEST_IMPLEMENTATION, "junit:junit:4.13.2") } @@ -135,7 +135,7 @@ fun DependencyHandlerScope.implementCompose() { // Integration with observables add(IMPLEMENTATION, "androidx.compose.runtime:runtime") add(IMPLEMENTATION, "androidx.compose.runtime:runtime-livedata") - add(IMPLEMENTATION, "androidx.activity:activity-compose:1.7.2") + add(IMPLEMENTATION, "androidx.activity:activity-compose:1.8.1") // COMPOSE ACCOMPANIST add(IMPLEMENTATION, "com.google.accompanist:accompanist-drawablepainter:${Versions.COMPOSE_ACCOMPANIST}") diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt index 04edaa3..a3eadb3 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt @@ -16,7 +16,9 @@ import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Card @@ -25,9 +27,9 @@ import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.Icon import androidx.compose.material.LocalContentColor import androidx.compose.material.MaterialTheme -import androidx.compose.material.OutlinedTextField import androidx.compose.material.Text import androidx.compose.material.TextButton +import androidx.compose.material.TextFieldDefaults import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.runtime.Composable @@ -38,19 +40,21 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.emoji.text.EmojiCompat +import com.hbb20.countrypicker.R import com.hbb20.countrypicker.compose.CountryFlag.EmojiFlag import com.hbb20.countrypicker.compose.CountryFlag.ImageFlag import com.hbb20.countrypicker.datagenerator.CPDataStoreGenerator @@ -131,7 +135,7 @@ fun CountryPicker( val (showPickerDialog, setShowPickerDialog) = remember { mutableStateOf(false) } val launchPickerDialog = remember { { setShowPickerDialog(true) } } val country = rememberCountry(alpha2Code, cpDataStore) - val countryFlag = rememberFlag(country, flagProvider) + val countryFlag = rememberCountryFlag(country, flagProvider) selectedCountryLayout( country, countryFlag, @@ -189,23 +193,7 @@ private fun DefaultSelectedCountryLayout( ) { val textStyle = MaterialTheme.typography.body1 if (countryFlag != null) { - when (countryFlag) { - is EmojiFlag -> { - Text( - text = countryFlag.emoji.toString(), - style = MaterialTheme.typography.body1, - color = LocalContentColor.current - ) - } - - is ImageFlag -> { - Image( - painter = painterResource(id = countryFlag.flagImageRes), - contentDescription = null, - modifier = Modifier.height(textStyle.lineHeight.toDp()) - ) - } - } + CountryFlagLayout(countryFlag, emojiFlagTextStyle = textStyle) Spacer(modifier = Modifier.width(8.dp)) } Text(text = textToShow, style = textStyle, color = LocalContentColor.current) @@ -218,9 +206,39 @@ private fun DefaultSelectedCountryLayout( } @Composable -private fun rememberFlag( +fun CountryFlagLayout( + countryFlag: CountryFlag?, + modifier: Modifier = Modifier, + emojiFlagTextStyle: TextStyle = MaterialTheme.typography.body1, + imageFlagHeight: Dp = emojiFlagTextStyle.fontSize.toDp(), +) { + when (countryFlag) { + is EmojiFlag -> { + Text( + text = countryFlag.emoji.toString(), + style = emojiFlagTextStyle, + color = LocalContentColor.current, + modifier = modifier + ) + } + + is ImageFlag -> { + Image( + painter = painterResource(id = countryFlag.flagImageRes), + contentDescription = null, + modifier = modifier.height(imageFlagHeight) + ) + } + + null -> { /* do nothing */ + } + } +} + +@Composable +fun rememberCountryFlag( country: CPCountry?, - flagProvider: CPFlagProvider? + flagProvider: CPFlagProvider? = DefaultEmojiFlagProvider() ) = remember(country, flagProvider) { if (country != null && flagProvider != null) { when (flagProvider) { @@ -267,7 +285,14 @@ fun CountryPickerDialog( fillHeight: Boolean = showFilter, allowClearSelection: Boolean = true, queryFilter: (country: CPCountry, filterQuery: String) -> Boolean = { country, filterQuery -> - defaultFilter(country, filterQuery) + defaultCountrySearchFilter(country, filterQuery) + }, + countryRowLayout: @Composable (( + country: CPCountry, + flagProvider: CPFlagProvider?, + onClicked: (CPCountry) -> Unit, + ) -> Unit) = { country, flagProvider, onClicked -> + CountryListItemRowLayout(country, flagProvider, onClicked) }, onDismissRequest: () -> Unit, onCountrySelected: (CPCountry?) -> Unit, @@ -285,7 +310,8 @@ fun CountryPickerDialog( fillHeight = fillHeight, flagProvider = flagProvider, allowClearSelection = allowClearSelection, - queryFilter = queryFilter + queryFilter = queryFilter, + countryRowLayout = countryRowLayout, ) } } @@ -300,8 +326,9 @@ private fun DefaultCountryPickerDialogContent( showFilter: Boolean, fillHeight: Boolean, allowClearSelection: Boolean, + modifier: Modifier = Modifier, queryFilter: (country: CPCountry, filterQuery: String) -> Boolean = { country, filterQuery -> - defaultFilter(country, filterQuery) + defaultCountrySearchFilter(country, filterQuery) }, searchFieldLayout: @Composable (( searchQuery: String, @@ -310,17 +337,25 @@ private fun DefaultCountryPickerDialogContent( ) -> Unit) = { searchQuery, setSearchQuery, cpDataStore -> DefaultSearchField(searchQuery, setSearchQuery, cpDataStore) }, + countryRowLayout: @Composable (( + country: CPCountry, + flagProvider: CPFlagProvider?, + onClicked: (CPCountry) -> Unit, + ) -> Unit) = { country, flagProvider, onClicked -> + CountryListItemRowLayout(country, flagProvider, onClicked) + }, onDismissRequest: () -> Unit, ) { Card( - modifier = Modifier - .fillMaxWidth() + modifier = modifier + .fillMaxWidth(0.8f) .padding(16.dp), shape = RoundedCornerShape(16.dp), ) { val countryList = remember(cpDataStore) { cpDataStore.countryList } + val scrollState = rememberLazyListState() val quickAccessCountries = remember(quickAccessCountriesCodes, countryList) { quickAccessCountriesCodes.orEmpty().mapNotNull { alpha2 -> countryList.firstOrNull { it.alpha2.equals(alpha2, ignoreCase = true) } @@ -332,20 +367,21 @@ private fun DefaultCountryPickerDialogContent( } val filteredQuickAccessCountries = remember(showFilter, quickAccessCountries, searchQuery) { if (showFilter == false) emptyList() - else quickAccessCountries.filter { queryFilter(it, searchQuery) }.distinctBy(CPCountry::alpha2) + else quickAccessCountries.filter { queryFilter(it, searchQuery) } + .distinctBy(CPCountry::alpha2) + } + LaunchedEffect(key1 = filteredList, key2 = filteredQuickAccessCountries) { + scrollState.scrollToItem(0) } Column { if (showFilter) { searchFieldLayout(searchQuery, setSearchQuery, cpDataStore) } - LazyColumn(modifier = Modifier.weight(1f, fill = fillHeight)) { + LazyColumn(modifier = Modifier.weight(1f, fill = fillHeight), state = scrollState) { if (filteredQuickAccessCountries.isNotEmpty()) { filteredQuickAccessCountries.forEach { country -> item("quickAccess-" + country.alpha2) { - CountryListItemRowLayout( - country = country, - flagProvider = flagProvider, - ) { + countryRowLayout(country, flagProvider) { onCountrySelected(it) onDismissRequest() } @@ -355,10 +391,7 @@ private fun DefaultCountryPickerDialogContent( } filteredList.forEach { country -> item(country.alpha2) { - CountryListItemRowLayout( - country = country, - flagProvider = flagProvider, - ) { + countryRowLayout(country, flagProvider) { onCountrySelected(it) onDismissRequest() } @@ -367,7 +400,10 @@ private fun DefaultCountryPickerDialogContent( } if (allowClearSelection) { TextButton( - onClick = { onCountrySelected(null) }, + onClick = { + onCountrySelected(null) + onDismissRequest() + }, modifier = Modifier.padding(start = 8.dp, bottom = 8.dp) ) { Text( @@ -390,35 +426,43 @@ private fun DefaultSearchField( ) { val keyboardController = LocalSoftwareKeyboardController.current val focusManager = LocalFocusManager.current - val searchFieldFocusRequester = remember { - FocusRequester() - } - OutlinedTextField( - value = searchQuery, - onValueChange = { setSearchQuery(it) }, - placeholder = { - Text( - text = cpDataStore.messageGroup.searchHint, - style = MaterialTheme.typography.body1, - color = MaterialTheme.colors.onSurface + + Column { + Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { + Icon( + painter = painterResource(id = R.drawable.ic_cp_search), + contentDescription = null, + modifier = Modifier.padding(16.dp), + tint = MaterialTheme.colors.onSurface.copy(alpha = 0.5f) ) - }, - textStyle = MaterialTheme.typography.body1, - singleLine = true, - keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Search), - keyboardActions = KeyboardActions(onAny = { - keyboardController?.hide() - focusManager.clearFocus() - }), - modifier = Modifier - .padding(horizontal = 16.dp) - .padding(top = 16.dp) - .fillMaxWidth() - .focusRequester(searchFieldFocusRequester), - ) + Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterStart) { + BasicTextField( + value = searchQuery, + onValueChange = { setSearchQuery(it) }, + textStyle = MaterialTheme.typography.body1, + cursorBrush = SolidColor( + TextFieldDefaults.outlinedTextFieldColors() + .cursorColor(isError = false).value + ), + singleLine = true, + keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Search), + keyboardActions = KeyboardActions(onAny = { + keyboardController?.hide() + focusManager.clearFocus() + }), + modifier = Modifier + .fillMaxWidth() + ) - LaunchedEffect(key1 = Unit) { - searchFieldFocusRequester.requestFocus() + if (searchQuery.isEmpty()) { + Text( + text = cpDataStore.messageGroup.searchHint, + style = MaterialTheme.typography.body1, + color = MaterialTheme.colors.onSurface.copy(alpha = 0.5f) + ) + } + } + } } } @@ -428,10 +472,11 @@ private fun CountryListItemRowLayout( flagProvider: CPFlagProvider?, onClicked: (CPCountry) -> Unit, ) { - val countryFlag = rememberFlag(country, flagProvider) + val countryFlag = rememberCountryFlag(country, flagProvider) Row( modifier = Modifier .fillMaxWidth() + .clip(RoundedCornerShape(4.dp)) .clickable { onClicked(country) } @@ -439,23 +484,7 @@ private fun CountryListItemRowLayout( verticalAlignment = Alignment.CenterVertically ) { if (countryFlag != null) { - when (countryFlag) { - is EmojiFlag -> { - Text( - text = countryFlag.emoji.toString(), - style = MaterialTheme.typography.body1, - color = LocalContentColor.current - ) - } - - is ImageFlag -> { - Image( - painter = painterResource(id = countryFlag.flagImageRes), - contentDescription = null, - modifier = Modifier.height(MaterialTheme.typography.body1.lineHeight.toDp()) - ) - } - } + CountryFlagLayout(countryFlag) Spacer(modifier = Modifier.width(16.dp)) } Column(modifier = Modifier.weight(1f)) { @@ -468,7 +497,7 @@ private fun CountryListItemRowLayout( } } -private fun defaultFilter( +fun defaultCountrySearchFilter( country: CPCountry, filterQuery: String, ) = if (filterQuery.isBlank()) true @@ -497,10 +526,10 @@ fun PreviewSomeDialogContent() { cpDataStore = rememberCPDataStore(countryListTransformer = countryMasterListTransformer), flagProvider = DefaultEmojiFlagProvider(), quickAccessCountriesCodes = null, - showFilter = false, + showFilter = true, fillHeight = false, allowClearSelection = true, - queryFilter = { cpCountry, query -> defaultFilter(cpCountry, query) }, + queryFilter = { cpCountry, query -> defaultCountrySearchFilter(cpCountry, query) }, onDismissRequest = {}, onCountrySelected = {}, ) @@ -518,6 +547,11 @@ fun rememberCountry( } } +/** + * For state management, + * if you need to hoist the selected country code outside of compose + * then use CPCountryDetector::detectCountry() + */ @Composable fun rememberAutoDetectedCountryCode( sourceOrder: List = listOf( diff --git a/countrypicker/src/main/res/drawable/ic_cp_search.xml b/countrypicker/src/main/res/drawable/ic_cp_search.xml new file mode 100644 index 0000000..d29c6ea --- /dev/null +++ b/countrypicker/src/main/res/drawable/ic_cp_search.xml @@ -0,0 +1,5 @@ + + + + + From 79bf923fd76c71e096ce49687641c2b7945b9c4d Mon Sep 17 00:00:00 2001 From: hbb20 Date: Tue, 26 Dec 2023 07:22:08 -0700 Subject: [PATCH 07/10] custom flag works and ignore cases --- .../compose/ComposeDemoActivity.kt | 53 ++++++++++++------- .../compose/theme/Colors.kt | 50 +++++++++++++++++ app/src/main/res/drawable/ic_flag_blue.xml | 6 +++ .../res/drawable/ic_flag_green_outlint.xml | 12 +++++ app/src/main/res/drawable/ic_flag_yellow.xml | 10 ++++ .../compose/CountryPickerComposable.kt | 3 +- .../flagprovider/CPFlagProvider.kt | 22 ++++---- .../hbb20/countrypicker/models/CPLanguage.kt | 2 +- .../hbb20/countrypicker/view/CPViewHelper.kt | 2 +- 9 files changed, 128 insertions(+), 32 deletions(-) create mode 100644 app/src/main/java/com/hbb20/androidcountrypicker/compose/theme/Colors.kt create mode 100644 app/src/main/res/drawable/ic_flag_blue.xml create mode 100644 app/src/main/res/drawable/ic_flag_green_outlint.xml create mode 100644 app/src/main/res/drawable/ic_flag_yellow.xml diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt b/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt index 97f7cdb..af3c7c9 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.hbb20.androidcountrypicker.R +import com.hbb20.androidcountrypicker.compose.theme.DemoTheme import com.hbb20.contrypicker.flagpack1.FlagPack1 import com.hbb20.countrypicker.compose.CountryFlagLayout import com.hbb20.countrypicker.compose.CountryPicker @@ -51,7 +52,7 @@ class ComposeDemoActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { - MaterialTheme { + DemoTheme { // A surface container using the 'background' color from the theme Surface( modifier = Modifier.fillMaxSize(), @@ -157,13 +158,22 @@ class ComposeDemoActivity : ComponentActivity() { flagProvider = CPFlagImageProvider( // map of alpha2 to drawable resource id alpha2ToFlag = mapOf( - "IN" to R.drawable.ic_flag, - "US" to R.drawable.ic_flag, - "GB" to R.drawable.ic_flag, + "IN" to R.drawable.ic_flag_green_outlint, + "gb" to R.drawable.ic_flag_yellow, + "US" to R.drawable.ic_flag_blue, ), // drawable resource id for missing flag missingFlagPlaceHolder = R.drawable.ic_flag - ) + ), + pickerDialog = { cpDataStore, flagProvider, onDismissRequest, onCountrySelected -> + CountryPickerDialog( + cpDataStore = cpDataStore, + flagProvider = flagProvider, + onDismissRequest = onDismissRequest, + onCountrySelected = onCountrySelected, + quickAccessCountries = listOf("IN", "us", "GB"), + ) + } ) { setCountryCode(it?.alpha2) } @@ -215,7 +225,7 @@ class ComposeDemoActivity : ComponentActivity() { ) } - if(showPickerDialog){ + if (showPickerDialog) { CountryPickerDialog( cpDataStore = cpDataStore, flagProvider = flagProvider, @@ -359,21 +369,24 @@ class ComposeDemoActivity : ComponentActivity() { modifier = Modifier .fillMaxWidth() .background(MaterialTheme.colors.surface) - .padding(16.dp) + .padding(16.dp), + backgroundColor = MaterialTheme.colors.surface ) { - Column(modifier = Modifier.padding(16.dp)) { - Text( - text = title, - style = MaterialTheme.typography.subtitle1, - color = Color.Black - ) - Text( - text = body, - style = MaterialTheme.typography.body2, - color = Color.DarkGray - ) - Spacer(modifier = Modifier.padding(8.dp)) - countryPickerLayout() + Surface(color = MaterialTheme.colors.surface) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = title, + style = MaterialTheme.typography.subtitle1, + color = MaterialTheme.colors.onSurface + ) + Text( + text = body, + style = MaterialTheme.typography.body2, + color = MaterialTheme.colors.onSurface + ) + Spacer(modifier = Modifier.padding(8.dp)) + countryPickerLayout() + } } } } diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/compose/theme/Colors.kt b/app/src/main/java/com/hbb20/androidcountrypicker/compose/theme/Colors.kt new file mode 100644 index 0000000..589665b --- /dev/null +++ b/app/src/main/java/com/hbb20/androidcountrypicker/compose/theme/Colors.kt @@ -0,0 +1,50 @@ +package com.hbb20.androidcountrypicker.compose.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color + + +@Composable +fun DemoTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + MaterialTheme( + colors = if (darkTheme) darkThemeColors else lightThemeColors, + content = content + ) +} + +val lightThemeColors = lightColors( + primary = Color(0xFF008577), + primaryVariant = Color(0xFF00574B), + secondary = Color(0xFF3F51B5), + secondaryVariant = Color(0xFF3F51B5), + onPrimary = Color(0xFFFFFFFF), + onSecondary = Color(0xFFFFFFFF), + error = Color(0xFFED5933), + onError = Color(0xFFFFFFFF), + background = Color(0xFFF4F4F7), + onBackground = Color(0xFF000000), + surface = Color(0xFFFFFFFF), + onSurface = Color(0xFF000000) +) + +val darkThemeColors = darkColors( + primary = Color(0xFF00E0C9), + primaryVariant = Color(0xFF00C7AB), + secondary = Color(0xFF3F51B5), + secondaryVariant = Color(0xFF3F51B5), + onPrimary = Color(0xFFFFFFFF), + onSecondary = Color(0xFFFFFFFF), + error = Color(0xFFED5933), + onError = Color(0xFFFFFFFF), + background = Color(0xFF000000), + onBackground = Color(0xFFFAFAFC), + surface = Color(0xFF292B2E), + onSurface = Color(0xFFFAFAFC) +) diff --git a/app/src/main/res/drawable/ic_flag_blue.xml b/app/src/main/res/drawable/ic_flag_blue.xml new file mode 100644 index 0000000..4ea8b2e --- /dev/null +++ b/app/src/main/res/drawable/ic_flag_blue.xml @@ -0,0 +1,6 @@ + + + diff --git a/app/src/main/res/drawable/ic_flag_green_outlint.xml b/app/src/main/res/drawable/ic_flag_green_outlint.xml new file mode 100644 index 0000000..5dd8f92 --- /dev/null +++ b/app/src/main/res/drawable/ic_flag_green_outlint.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_flag_yellow.xml b/app/src/main/res/drawable/ic_flag_yellow.xml new file mode 100644 index 0000000..2198d8c --- /dev/null +++ b/app/src/main/res/drawable/ic_flag_yellow.xml @@ -0,0 +1,10 @@ + + + diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt index a3eadb3..15cb1f3 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt @@ -351,6 +351,7 @@ private fun DefaultCountryPickerDialogContent( .fillMaxWidth(0.8f) .padding(16.dp), shape = RoundedCornerShape(16.dp), + backgroundColor = MaterialTheme.colors.surface, ) { val countryList = remember(cpDataStore) { cpDataStore.countryList @@ -439,7 +440,7 @@ private fun DefaultSearchField( BasicTextField( value = searchQuery, onValueChange = { setSearchQuery(it) }, - textStyle = MaterialTheme.typography.body1, + textStyle = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onSurface), cursorBrush = SolidColor( TextFieldDefaults.outlinedTextFieldColors() .cursorColor(isError = false).value diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/flagprovider/CPFlagProvider.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/flagprovider/CPFlagProvider.kt index 6d4c9a2..fd9b2ad 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/flagprovider/CPFlagProvider.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/flagprovider/CPFlagProvider.kt @@ -1,6 +1,7 @@ package com.hbb20.countrypicker.flagprovider import androidx.annotation.DrawableRes +import java.util.Locale abstract class CPFlagProvider @@ -18,14 +19,17 @@ class DefaultEmojiFlagProvider(val useEmojiCompat: Boolean = false) : CPFlagProv * other flags in this pack to maintain visual symmetry. */ class CPFlagImageProvider( - val alpha2ToFlag: Map, + alpha2ToFlag: Map, @DrawableRes val missingFlagPlaceHolder: Int ) : CPFlagProvider() { + private val flagMap = alpha2ToFlag.map { it.key.uppercase(Locale.ENGLISH) to it.value }.toMap() @DrawableRes fun getFlag(alpha2Code: String): Int { - return alpha2ToFlag.getOrElse( - getNormalizedAlpha2ForFlag(alpha2Code) + val upperCaseAlpha2Code = alpha2Code.uppercase(Locale.ENGLISH) + val flag = flagMap[upperCaseAlpha2Code] + return flag ?: flagMap.getOrElse( + getNormalizedAlpha2ForFlag(upperCaseAlpha2Code) ) { missingFlagPlaceHolder } } @@ -35,12 +39,12 @@ class CPFlagImageProvider( * This function will convert "UM" to "US" */ private fun getNormalizedAlpha2ForFlag(alpha2Code: String): String { - return when (alpha2Code.toLowerCase()) { - "um" -> "us" - "sj" -> "no" - "bv" -> "no" - "hm" -> "au" - else -> alpha2Code.toLowerCase() + return when (alpha2Code.uppercase(Locale.ENGLISH)) { + "UM" -> "US" + "SJ" -> "NO" + "BV" -> "NO" + "HM" -> "AU" + else -> alpha2Code.uppercase(Locale.ENGLISH) } } } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPLanguage.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPLanguage.kt index 4724e40..a2ab75c 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPLanguage.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPLanguage.kt @@ -40,5 +40,5 @@ enum class CPLanguage( UZBEK("uz"), VIETNAMESE("vi"); - val translationFileName: String by lazy { "cp_${name.toLowerCase(Locale.ROOT)}.xml" } + val translationFileName: String by lazy { "cp_${name.lowercase(Locale.ROOT)}.xml" } } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/view/CPViewHelper.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/view/CPViewHelper.kt index d53ee55..cbb215d 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/view/CPViewHelper.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/view/CPViewHelper.kt @@ -77,7 +77,7 @@ class CPViewHelper( val detectedAlpha2 = if (isInEditMode) "US" else countryDetector.detectCountry(countryDetectSources) val detectedCountry = cpDataStore.countryList.firstOrNull { - it.alpha2.toLowerCase(Locale.ROOT) == detectedAlpha2?.toLowerCase( + it.alpha2.lowercase(Locale.ROOT) == detectedAlpha2?.lowercase( Locale.ROOT ) } From e64ef2b8a3f17f42e35d577dc7d28ec1371836b6 Mon Sep 17 00:00:00 2001 From: hbb20 Date: Sat, 30 Dec 2023 14:23:27 -0700 Subject: [PATCH 08/10] update ktlint and other deps --- .editorconfig | 16 + CHANGELOG.md | 2 + app/build.gradle.kts | 39 +- .../NoCriticalErrorTest.kt | 31 - .../CountryPickerViewDemoActivity.kt | 20 +- .../CustomRecyclerViewActivity.kt | 49 +- .../androidcountrypicker/DemoApplication.kt | 2 - .../androidcountrypicker/MainActivity.kt | 5 +- .../OpenDialogDirectlyActivity.kt | 34 +- .../compose/ComposeDemoActivity.kt | 219 +- .../compose/theme/Colors.kt | 63 +- .../androidcountrypicker/FlagPackTest.kt | 18 +- build.gradle.kts | 4 +- buildSrc/src/main/java/BuildData.kt | 4 + buildSrc/src/main/java/Dependencies.kt | 16 +- countrypicker/build.gradle.kts | 6 +- .../main/java/com/hbb20/CountryPickerView.kt | 109 +- .../compose/CountryPickerComposable.kt | 282 +- .../com/hbb20/countrypicker/compose/Helper.kt | 3 +- .../countrypicker/config/CPDialogConfig.kt | 27 +- .../countrypicker/config/CPListConfig.kt | 2 +- .../hbb20/countrypicker/config/CPRowConfig.kt | 2 +- .../countrypicker/config/CPViewConfig.kt | 2 +- .../datagenerator/CPDataStoreGenerator.kt | 48 +- .../datagenerator/CPFileReader.kt | 36 +- .../countrypicker/dialog/CPDialogExtension.kt | 72 +- .../countrypicker/dialog/CPDialogHelper.kt | 15 +- .../flagprovider/CPFlagProvider.kt | 4 +- .../countrypicker/helper/CPCountryDetector.kt | 25 +- .../helper/CountryPickerDialogAttrReader.kt | 18 +- .../helper/CountryPickerListAttrReader.kt | 2 +- .../hbb20/countrypicker/logger/CPLogger.kt | 1 - .../countrypicker/models/Alpha2Collection.kt | 3 + .../hbb20/countrypicker/models/CPCountry.kt | 7 +- .../hbb20/countrypicker/models/CPDataStore.kt | 4 +- .../hbb20/countrypicker/models/CPLanguage.kt | 5 +- .../hbb20/countrypicker/models/Constants.kt | 25 - .../hbb20/countrypicker/models/CountryInfo.kt | 2 +- .../countrypicker/models/MasterInfoList.kt | 7504 ++++++++--------- .../countrypicker/models/alpha2Collection.kt | 3 - .../recyclerview/CPRecyclerViewExtensions.kt | 50 +- .../recyclerview/CPRecyclerViewHelper.kt | 56 +- .../recyclerview/CountryListController.kt | 9 +- .../countrypicker/recyclerview/CountryRow.kt | 183 +- .../countrypicker/recyclerview/DividerRow.kt | 19 +- .../countrypicker/recyclerview/NoMatchRow.kt | 34 +- .../countrypicker/view/CPViewExtension.kt | 84 +- .../hbb20/countrypicker/view/CPViewHelper.kt | 73 +- .../com/hbb20/CPDataStoreGeneratorTest.kt | 37 +- .../com/hbb20/CPRecyclerViewHelperTest.kt | 159 +- .../java/com/hbb20/MockCountryFileReader.kt | 3 +- .../test/java/com/hbb20/SampleDataStore.kt | 44 +- .../config/CPDialogConfigTest.kt | 3 +- .../CountryPickerDialogAttrReaderKtTest.kt | 73 +- .../CountryPickerListAttrReaderKtTest.kt | 8 +- flagpack1/build.gradle.kts | 6 +- .../hbb20/contrypicker/flagpack1/FlagPack1.kt | 509 +- .../contrypicker/flagpack1/ExampleUnitTest.kt | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 59 files changed, 5091 insertions(+), 4992 deletions(-) create mode 100644 .editorconfig delete mode 100644 app/src/androidTest/java/com/hbb20/androidcountrypicker/NoCriticalErrorTest.kt create mode 100644 countrypicker/src/main/java/com/hbb20/countrypicker/models/Alpha2Collection.kt delete mode 100644 countrypicker/src/main/java/com/hbb20/countrypicker/models/alpha2Collection.kt diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8780a8e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ + +[*.kt] +# Recommended is 100 but some action names are very long that can not fit in the limit. +# 120 seems to be a sweet point for this project +# In general length should be 100 so added visual guide should help +max_line_length=120 +ij_visual_guides =100,120 +ktlint_function_naming_ignore_when_annotated_with=Composable +ktlint_standard_no-wildcard-imports = disabled + + +[*Test.kt] +max_line_length=off +ktlint_function_naming_ignore_when_annotated_with=Composable +ktlint_standard_no-wildcard-imports = disabled + diff --git a/CHANGELOG.md b/CHANGELOG.md index bfd0795..ef8dcde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). not find required country in the preferred countries so that section is of no use when searching. Although, preferred country will continue to show up in regular filtered list if matches for query. @hbb20 +- Add support to JetPack Compose @hbb20 +- Out of box composables for Material2 @hbb20 ## v0.0.7 2022-01 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2a4a69a..dfa3fb4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -27,37 +27,38 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = BuildData.appJavaVersion + targetCompatibility = BuildData.appJavaVersion } composeOptions { kotlinCompilerExtensionVersion = Versions.COMPOSE_COMPILER } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = BuildData.appJavaVersion.toString() } - packagingOptions { + packaging { jniLibs { excludes += setOf("META-INF/licenses/**") } resources { - excludes += setOf( - "META-INF/DEPENDENCIES", - "META-INF/LICENSE", - "META-INF/LICENSE.txt", - "META-INF/license.txt", - "META-INF/licenses/**", - "META-INF/NOTICE", - "META-INF/NOTICE.txt", - "META-INF/notice.txt", - "META-INF/ASL2.0", - "META-INF/AL2.0", - "META-INF/*.kotlin_module", - "META-INF/LGPL2.1", - "**/attach_hotspot_windows.dll" - ) + excludes += + setOf( + "META-INF/DEPENDENCIES", + "META-INF/LICENSE", + "META-INF/LICENSE.txt", + "META-INF/license.txt", + "META-INF/licenses/**", + "META-INF/NOTICE", + "META-INF/NOTICE.txt", + "META-INF/notice.txt", + "META-INF/ASL2.0", + "META-INF/AL2.0", + "META-INF/*.kotlin_module", + "META-INF/LGPL2.1", + "**/attach_hotspot_windows.dll", + ) } } namespace = "com.hbb20.androidcountrypicker" diff --git a/app/src/androidTest/java/com/hbb20/androidcountrypicker/NoCriticalErrorTest.kt b/app/src/androidTest/java/com/hbb20/androidcountrypicker/NoCriticalErrorTest.kt deleted file mode 100644 index c90a964..0000000 --- a/app/src/androidTest/java/com/hbb20/androidcountrypicker/NoCriticalErrorTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.hbb20.androidcountrypicker - -import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.action.ViewActions.click -import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.matcher.ViewMatchers.withId -import androidx.test.espresso.matcher.ViewMatchers.withText -import androidx.test.filters.LargeTest -import androidx.test.rule.ActivityTestRule -import androidx.test.runner.AndroidJUnit4 -import org.junit.Ignore -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith - -@LargeTest -@RunWith(AndroidJUnit4::class) -class NoCriticalErrorTest { - - @Rule - @JvmField - var mActivityTestRule = ActivityTestRule(MainActivity::class.java) - - @Test - @Ignore - fun noCriticalErrorTest() { - onView(withId(R.id.btnOpenTestActivity)).perform(click()) - Thread.sleep(200) - onView(withId(R.id.tvCriticalSummaryCount)).check(matches(withText("0"))) - } -} diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/CountryPickerViewDemoActivity.kt b/app/src/main/java/com/hbb20/androidcountrypicker/CountryPickerViewDemoActivity.kt index 9042244..d9403cc 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/CountryPickerViewDemoActivity.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/CountryPickerViewDemoActivity.kt @@ -15,6 +15,7 @@ import com.hbb20.countrypicker.view.prepareCustomCountryPickerView class CountryPickerViewDemoActivity : AppCompatActivity() { lateinit var binding: ActivityCountryPickerViewDemoBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityCountryPickerViewDemoBinding.inflate(layoutInflater) @@ -41,8 +42,8 @@ class CountryPickerViewDemoActivity : AppCompatActivity() { binding.cpFlagPack.changeFlagProvider( CPFlagImageProvider( FlagPack1.alpha2ToFlag, - FlagPack1.missingFlagPlaceHolder - ) + FlagPack1.missingFlagPlaceHolder, + ), ) binding.cpNoFlag.changeFlagProvider(null) } @@ -58,7 +59,7 @@ class CountryPickerViewDemoActivity : AppCompatActivity() { containerViewGroup = customCPContainer, tvSelectedCountryInfo = customCPSelectedCountryTextView, tvSelectedCountryEmojiFlag = customCPEmojiTextView, - initialSelection = CPViewConfig.InitialSelection.AutoDetectCountry() + initialSelection = CPViewConfig.InitialSelection.AutoDetectCountry(), ) { selectedCountry: CPCountry? -> // listen to change through callback // your code to handle selected country @@ -74,11 +75,12 @@ class CountryPickerViewDemoActivity : AppCompatActivity() { val customCPSelectedCountryTextView = findViewById(R.id.tvSelectedCountry) val customCPEmojiTextView = findViewById(R.id.tvSelectedCountryEmojiFlag) - val cpViewHelper = prepareCustomCountryPickerView( - containerViewGroup = customCPContainer, - tvSelectedCountryInfo = customCPSelectedCountryTextView, - tvSelectedCountryEmojiFlag = customCPEmojiTextView - ) + val cpViewHelper = + prepareCustomCountryPickerView( + containerViewGroup = customCPContainer, + tvSelectedCountryInfo = customCPSelectedCountryTextView, + tvSelectedCountryEmojiFlag = customCPEmojiTextView, + ) // observe live data cpViewHelper.selectedCountry.observe( @@ -86,7 +88,7 @@ class CountryPickerViewDemoActivity : AppCompatActivity() { { selectedCountry: CPCountry? -> // observe live data // your code to handle selected country - } + }, ) // Modify CPViewConfig if you need. Access cpViewConfig through `cpViewHelper` diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/CustomRecyclerViewActivity.kt b/app/src/main/java/com/hbb20/androidcountrypicker/CustomRecyclerViewActivity.kt index c9e6223..4650b98 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/CustomRecyclerViewActivity.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/CustomRecyclerViewActivity.kt @@ -14,6 +14,7 @@ import com.hbb20.countrypicker.recyclerview.loadCountries class CustomRecyclerViewActivity : AppCompatActivity() { lateinit var binding: ActivityCustomRecyclerViewBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityCustomRecyclerViewBinding.inflate(layoutInflater) @@ -22,7 +23,6 @@ class CustomRecyclerViewActivity : AppCompatActivity() { } private fun setupRecyclerView() { - val primaryTextGenerator = { cpCountry: CPCountry -> "${cpCountry.name} (${cpCountry.alpha3})" } @@ -35,21 +35,22 @@ class CustomRecyclerViewActivity : AppCompatActivity() { "+${cpCountry.phoneCode}" } - val cpListConfig = CPListConfig( - preferredCountryCodes = "IN,US,NZ,AU" - ) + val cpListConfig = + CPListConfig( + preferredCountryCodes = "IN,US,NZ,AU", + ) binding.recyclerView.loadCountries { selectedCountry: CPCountry -> // your code to handle selected country } binding.recyclerView.loadCountries( - preferredCountryCodes = "IN,US,NZ,AU" + preferredCountryCodes = "IN,US,NZ,AU", ) { selectedCountry -> Toast.makeText(this, selectedCountry.name, Toast.LENGTH_SHORT).show() } - val dataFileReader = CPDataStoreGenerator.defaultCountryFileReader + val dataFileReader = CPDataStoreGenerator.DEFAULT_FILE_READER val customFlagImageProvider = CPRowConfig.defaultFlagProvider // binding.recyclerView.loadCountries { selectedCountry: CPCountry -> @@ -80,13 +81,17 @@ class CustomRecyclerViewActivity : AppCompatActivity() { // See CPDataStore for available configuration val cpDataStore = CPDataStoreGenerator.generate(this) - val cpRecyclerViewHelper = CPRecyclerViewHelper( - cpDataStore = cpDataStore, // required - cpListConfig = cpListConfig, // Default: CPListConfig() - cpRowConfig = cpRowConfig // Default: CPRowConfig() - ) { selectedCountry: CPCountry -> - // required: handle selected country - } + val cpRecyclerViewHelper = + CPRecyclerViewHelper( + // required + cpDataStore = cpDataStore, + // Default: CPListConfig() + cpListConfig = cpListConfig, + // Default: CPRowConfig() + cpRowConfig = cpRowConfig, + ) { selectedCountry: CPCountry -> + // required: handle selected country + } // attach recyclerView to show list in recyclerView cpRecyclerViewHelper.attachRecyclerView(binding.recyclerView) @@ -107,13 +112,17 @@ class CustomRecyclerViewActivity : AppCompatActivity() { // Check CPRowConfig for available configuration val cpRowConfig: CPRowConfig = CPRowConfig() - val cpRecyclerViewHelper = CPRecyclerViewHelper( - cpDataStore = cpDataStore, // required - cpListConfig = cpListConfig, // Default: CPListConfig() - cpRowConfig = cpRowConfig // Default: CPRowConfig() - ) { selectedCountry: CPCountry -> - // required: handle selected country - } + val cpRecyclerViewHelper = + CPRecyclerViewHelper( + // required + cpDataStore = cpDataStore, + // Default: CPListConfig() + cpListConfig = cpListConfig, + // Default: CPRowConfig() + cpRowConfig = cpRowConfig, + ) { selectedCountry: CPCountry -> + // required: handle selected country + } // attach recyclerView to show list in recyclerView cpRecyclerViewHelper.attachRecyclerView(binding.recyclerView) diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/DemoApplication.kt b/app/src/main/java/com/hbb20/androidcountrypicker/DemoApplication.kt index 757670a..6866ba4 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/DemoApplication.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/DemoApplication.kt @@ -1,10 +1,8 @@ package com.hbb20.androidcountrypicker import android.app.Application -import timber.log.Timber class DemoApplication : Application() { - override fun onCreate() { super.onCreate() // if (BuildConfig.DEBUG) { diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/MainActivity.kt b/app/src/main/java/com/hbb20/androidcountrypicker/MainActivity.kt index 65a85ae..0328c30 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/MainActivity.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/MainActivity.kt @@ -13,6 +13,7 @@ import com.hbb20.countrypicker.models.CPCountry class MainActivity : AppCompatActivity() { lateinit var binding: ActivityMainBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) @@ -30,8 +31,8 @@ class MainActivity : AppCompatActivity() { countryPicker.changeFlagProvider( CPFlagImageProvider( FlagPack1.alpha2ToFlag, - FlagPack1.missingFlagPlaceHolder - ) + FlagPack1.missingFlagPlaceHolder, + ), ) } diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/OpenDialogDirectlyActivity.kt b/app/src/main/java/com/hbb20/androidcountrypicker/OpenDialogDirectlyActivity.kt index d3e39d8..6233ce6 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/OpenDialogDirectlyActivity.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/OpenDialogDirectlyActivity.kt @@ -11,6 +11,7 @@ import com.hbb20.countrypicker.models.CPCountry class OpenDialogDirectlyActivity : AppCompatActivity() { lateinit var binding: ActivityOpenDialogDirectlyBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityOpenDialogDirectlyBinding.inflate(layoutInflater) @@ -21,7 +22,7 @@ class OpenDialogDirectlyActivity : AppCompatActivity() { private fun setClickListeners() { binding.btnCustomMasterList.setOnClickListener { launchCountryPickerDialog( - customMasterCountries = "ca,us,mx" + customMasterCountries = "ca,us,mx", ) { selectedCountry -> // your code here } @@ -29,7 +30,7 @@ class OpenDialogDirectlyActivity : AppCompatActivity() { binding.btnCustomExcludedList.setOnClickListener { launchCountryPickerDialog( - customExcludedCountries = "jp" + customExcludedCountries = "jp", ) { selectedCountry -> // your code here } @@ -54,9 +55,9 @@ class OpenDialogDirectlyActivity : AppCompatActivity() { "\uD83C\uDFC1", 0, "Paradise", - ) + ), ) - } + }, ) { selectedCountry -> // your code here } @@ -68,7 +69,7 @@ class OpenDialogDirectlyActivity : AppCompatActivity() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { dataStore.countryList.replaceAll { if (it.alpha2 == "IN") it.copy(name = "Bharat") else it } } - } + }, ) { selectedCountry -> // your code here } @@ -76,7 +77,7 @@ class OpenDialogDirectlyActivity : AppCompatActivity() { binding.btnPreferredCountries.setOnClickListener { launchCountryPickerDialog( - preferredCountryCodes = "IN,JP,US,CA" + preferredCountryCodes = "IN,JP,US,CA", ) { selectedCountry -> // your code here } @@ -84,10 +85,11 @@ class OpenDialogDirectlyActivity : AppCompatActivity() { binding.btnFlagPack1.setOnClickListener { launchCountryPickerDialog( - cpFlagProvider = CPFlagImageProvider( - FlagPack1.alpha2ToFlag, - FlagPack1.missingFlagPlaceHolder - ) + cpFlagProvider = + CPFlagImageProvider( + FlagPack1.alpha2ToFlag, + FlagPack1.missingFlagPlaceHolder, + ), ) { selectedCountry -> // your code here } @@ -95,7 +97,7 @@ class OpenDialogDirectlyActivity : AppCompatActivity() { binding.btnFlagNone.setOnClickListener { launchCountryPickerDialog( - cpFlagProvider = null + cpFlagProvider = null, ) { selectedCountry -> // your code here } @@ -106,8 +108,7 @@ class OpenDialogDirectlyActivity : AppCompatActivity() { primaryTextGenerator = { cpCountry -> "${cpCountry.name} (${cpCountry.alpha2})" }, secondaryTextGenerator = { cpCountry -> cpCountry.capitalEnglishName }, highlightedTextGenerator = { cpCountry -> "+${cpCountry.phoneCode}" }, - - ) { selectedCountry -> + ) { selectedCountry -> // your code here } } @@ -123,20 +124,17 @@ class OpenDialogDirectlyActivity : AppCompatActivity() { binding.btnAllowClearSelection.setOnClickListener { launchCountryPickerDialog( allowClearSelection = true, - - ) { selectedCountry -> + ) { selectedCountry -> // your code here } } binding.btnDontAllowClearSelection.setOnClickListener { launchCountryPickerDialog( - allowClearSelection = false + allowClearSelection = false, ) { selectedCountry -> // your code here } } - } - } diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt b/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt index af3c7c9..3966138 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt @@ -30,7 +30,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview @@ -56,7 +55,7 @@ class ComposeDemoActivity : ComponentActivity() { // A surface container using the 'background' color from the theme Surface( modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colors.background + color = MaterialTheme.colors.background, ) { val (countryCode, setCountryCode) = remember { mutableStateOf("In") } Column(modifier = Modifier.verticalScroll(rememberScrollState())) { @@ -80,7 +79,7 @@ class ComposeDemoActivity : ComponentActivity() { private fun OutOfBox() { CardTemplate( "Out of box", - "This is how it works without any other config changes" + "This is how it works without any other config changes", ) { val (countryCode, setCountryCode) = remember { mutableStateOf(null) } CountryPicker(alpha2Code = countryCode) { @@ -93,7 +92,8 @@ class ComposeDemoActivity : ComponentActivity() { private fun AutoDetectedInitialCountry() { CardTemplate( "Initial auto detected country", - "Detect country and set it as initial country. Optionally pass order of sources (SIM, NETWORK, LOCALE) for country detection.", + "Detect country and set it as initial country. " + + "Optionally pass order of sources (SIM, NETWORK, LOCALE) for country detection.", ) { val initialCountryCode = rememberAutoDetectedCountryCode() // Note: for state management, @@ -106,7 +106,6 @@ class ComposeDemoActivity : ComponentActivity() { } } - @Composable private fun UseFlagPack() { CardTemplate( @@ -117,10 +116,11 @@ class ComposeDemoActivity : ComponentActivity() { val (countryCode, setCountryCode) = remember { mutableStateOf(initialCountryCode) } CountryPicker( alpha2Code = countryCode, - flagProvider = CPFlagImageProvider( - FlagPack1.alpha2ToFlag, - FlagPack1.missingFlagPlaceHolder - ) + flagProvider = + CPFlagImageProvider( + FlagPack1.alpha2ToFlag, + FlagPack1.missingFlagPlaceHolder, + ), ) { setCountryCode(it?.alpha2) } @@ -144,7 +144,6 @@ class ComposeDemoActivity : ComponentActivity() { } } - @Composable private fun UseCustomFlagDrawables() { CardTemplate( @@ -155,16 +154,18 @@ class ComposeDemoActivity : ComponentActivity() { val (countryCode, setCountryCode) = remember { mutableStateOf(initialCountryCode) } CountryPicker( alpha2Code = countryCode, - flagProvider = CPFlagImageProvider( - // map of alpha2 to drawable resource id - alpha2ToFlag = mapOf( - "IN" to R.drawable.ic_flag_green_outlint, - "gb" to R.drawable.ic_flag_yellow, - "US" to R.drawable.ic_flag_blue, + flagProvider = + CPFlagImageProvider( + // map of alpha2 to drawable resource id + alpha2ToFlag = + mapOf( + "IN" to R.drawable.ic_flag_green_outlint, + "gb" to R.drawable.ic_flag_yellow, + "US" to R.drawable.ic_flag_blue, + ), + // drawable resource id for missing flag + missingFlagPlaceHolder = R.drawable.ic_flag, ), - // drawable resource id for missing flag - missingFlagPlaceHolder = R.drawable.ic_flag - ), pickerDialog = { cpDataStore, flagProvider, onDismissRequest, onCountrySelected -> CountryPickerDialog( cpDataStore = cpDataStore, @@ -173,7 +174,7 @@ class ComposeDemoActivity : ComponentActivity() { onCountrySelected = onCountrySelected, quickAccessCountries = listOf("IN", "us", "GB"), ) - } + }, ) { setCountryCode(it?.alpha2) } @@ -184,7 +185,9 @@ class ComposeDemoActivity : ComponentActivity() { private fun PhoneCodePicker() { CardTemplate( "Use as Country Phone Code Picker", - "Commonly used to select country with phone input box. Note: This does not auto format the phone number. Phone number formatting is beyond the scope of this library.", + "Commonly used to select country with phone input box. " + + "Note: This does not auto format the phone number." + + " Phone number formatting is beyond the scope of this library.", ) { val initialCountryCode = rememberAutoDetectedCountryCode() val cpDataStore = rememberCPDataStore() @@ -195,33 +198,42 @@ class ComposeDemoActivity : ComponentActivity() { Row( modifier = Modifier.height(IntrinsicSize.Min), - verticalAlignment = CenterVertically + verticalAlignment = CenterVertically, ) { // - Row(modifier = Modifier - .fillMaxHeight() - .clickable { setShowPickerDialog(true) } - .padding(8.dp), verticalAlignment = CenterVertically) { + Row( + modifier = + Modifier + .fillMaxHeight() + .clickable { setShowPickerDialog(true) } + .padding(8.dp), + verticalAlignment = CenterVertically, + ) { val country = rememberCountry(countryCode) val flag = rememberCountryFlag(country, flagProvider) CountryFlagLayout(flag) Spacer(modifier = Modifier.padding(4.dp)) val text = - if (country == null) cpDataStore.messageGroup.selectionPlaceholderText else "+${country.phoneCode} " + if (country == null) { + cpDataStore.messageGroup.selectionPlaceholderText + } else { + "+${country.phoneCode} " + } Text(text = text) Icon( painter = painterResource(id = R.drawable.ic_arrow_drop_down), contentDescription = null, - modifier = Modifier - .padding(4.dp) - .size(16.dp) + modifier = + Modifier + .padding(4.dp) + .size(16.dp), ) } TextField( value = phoneNumber, onValueChange = { setPhoneNumber(it) }, - keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number) + keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number), ) } @@ -231,29 +243,33 @@ class ComposeDemoActivity : ComponentActivity() { flagProvider = flagProvider, onDismissRequest = { setShowPickerDialog(false) }, countryRowLayout = { country, flagProvider, onClicked -> - Row(modifier = Modifier - .fillMaxWidth() - .heightIn(min = 48.dp) - .clickable { onClicked(country) } - .padding(12.dp), - verticalAlignment = CenterVertically) { + Row( + modifier = + Modifier + .fillMaxWidth() + .heightIn(min = 48.dp) + .clickable { onClicked(country) } + .padding(12.dp), + verticalAlignment = CenterVertically, + ) { CountryFlagLayout(rememberCountryFlag(country, flagProvider)) Spacer(modifier = Modifier.padding(4.dp)) Text( text = country.name, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f), ) Text(text = "+${country.phoneCode}") } }, queryFilter = { country, query -> - val properties = listOf( - country.name, - country.englishName, - country.alpha2, - country.alpha3, - country.phoneCode.toString(), - ) + val properties = + listOf( + country.name, + country.englishName, + country.alpha2, + country.alpha3, + country.phoneCode.toString(), + ) properties.any { it.contains(query, ignoreCase = true) } }, ) { @@ -269,36 +285,46 @@ class ComposeDemoActivity : ComponentActivity() { CardTemplate( "Use as Country's Currency Picker", "Commonly used to select currency with money input. " + - "\nNote: This does not auto format the phone number." + - " Phone number formatting is beyond the scope of this library.", + "\nNote: This does not auto format the phone number." + + " Phone number formatting is beyond the scope of this library.", ) { val initialCountryCode = rememberAutoDetectedCountryCode() val (countryCode, setCountryCode) = remember { mutableStateOf(initialCountryCode) } val (amount, setAmount) = remember { mutableStateOf("") } - CountryPicker(alpha2Code = countryCode, - cpDataStore = rememberCPDataStore { originalCountryList -> - originalCountryList.sortedBy { it.currencyName } - .filterNot { it.currencyCode.isBlank() } - }, + CountryPicker( + alpha2Code = countryCode, + cpDataStore = + rememberCPDataStore { originalCountryList -> + originalCountryList.sortedBy { it.currencyName } + .filterNot { it.currencyCode.isBlank() } + }, selectedCountryLayout = { country, flag, emptySelectionText, modifier, showCountryPickerDialog -> Row( modifier = Modifier.height(IntrinsicSize.Min), - verticalAlignment = CenterVertically + verticalAlignment = CenterVertically, ) { - Row(modifier = modifier - .fillMaxHeight() - .clickable { showCountryPickerDialog() } - .padding(8.dp), verticalAlignment = CenterVertically) { + Row( + modifier = + modifier + .fillMaxHeight() + .clickable { showCountryPickerDialog() } + .padding(8.dp), + verticalAlignment = CenterVertically, + ) { CountryFlagLayout(flag) Spacer(modifier = Modifier.padding(4.dp)) val text = - if (country == null) emptySelectionText else "${country.currencyCode} ${country.currencySymbol}" + if (country == null) { + emptySelectionText + } else { + "${country.currencyCode} ${country.currencySymbol}" + } Text(text = text) } TextField( value = amount, onValueChange = { setAmount(it) }, - keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number) + keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number), ) } }, @@ -308,81 +334,81 @@ class ComposeDemoActivity : ComponentActivity() { flagProvider = flagProvider, onDismissRequest = onDismissRequest, countryRowLayout = { country, flagProvider, onClicked -> - Row(modifier = Modifier - .fillMaxWidth() - .heightIn(min = 48.dp) - .clickable { onClicked(country) } - .padding(12.dp), - verticalAlignment = CenterVertically) { + Row( + modifier = + Modifier + .fillMaxWidth() + .heightIn(min = 48.dp) + .clickable { onClicked(country) } + .padding(12.dp), + verticalAlignment = CenterVertically, + ) { CountryFlagLayout(rememberCountryFlag(country, flagProvider)) Spacer(modifier = Modifier.padding(4.dp)) Column(modifier = Modifier.weight(1f)) { - Text( text = "${country.currencyName} (${country.currencySymbol})", - style = MaterialTheme.typography.subtitle2 + style = MaterialTheme.typography.subtitle2, ) Text( text = country.name, - style = MaterialTheme.typography.body2 + style = MaterialTheme.typography.body2, ) } Text( text = "${country.currencyCode}", - style = MaterialTheme.typography.subtitle1 + style = MaterialTheme.typography.subtitle1, ) } }, queryFilter = { country, query -> val sanitizedQuery = query.trim().removePrefix("+") - val properties = listOf( - country.name, - country.englishName, - country.alpha2, - country.alpha3, - country.currencyName, - country.currencyCode, - country.currencySymbol, - ) + val properties = + listOf( + country.name, + country.englishName, + country.alpha2, + country.alpha3, + country.currencyName, + country.currencyCode, + country.currencySymbol, + ) properties.any { it.contains(sanitizedQuery, ignoreCase = true) } }, - ) { - setCountryCode(it?.alpha2) - val currencyCode = it?.currencyCode - // your logic to use currency code - } - } + onCountrySelected = onCountrySelected, + ) + }, ) { setCountryCode(it?.alpha2) } } } - @Composable private fun CardTemplate( title: String, body: String, - countryPickerLayout: @Composable () -> Unit + countryPickerLayout: @Composable () -> Unit, ) { Card( - modifier = Modifier - .fillMaxWidth() - .background(MaterialTheme.colors.surface) - .padding(16.dp), - backgroundColor = MaterialTheme.colors.surface + modifier = + Modifier + .fillMaxWidth() + .background(MaterialTheme.colors.surface) + .padding(16.dp), + backgroundColor = MaterialTheme.colors.surface, ) { Surface(color = MaterialTheme.colors.surface) { Column(modifier = Modifier.padding(16.dp)) { Text( text = title, style = MaterialTheme.typography.subtitle1, - color = MaterialTheme.colors.onSurface + color = MaterialTheme.colors.onSurface, ) Text( text = body, style = MaterialTheme.typography.body2, - color = MaterialTheme.colors.onSurface + color = MaterialTheme.colors.onSurface, ) Spacer(modifier = Modifier.padding(8.dp)) countryPickerLayout() @@ -393,10 +419,13 @@ class ComposeDemoActivity : ComponentActivity() { } @Composable -fun Greeting(name: String, modifier: Modifier = Modifier) { +fun Greeting( + name: String, + modifier: Modifier = Modifier, +) { Text( text = "Hello $name!", - modifier = modifier + modifier = modifier, ) } diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/compose/theme/Colors.kt b/app/src/main/java/com/hbb20/androidcountrypicker/compose/theme/Colors.kt index 589665b..b018391 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/compose/theme/Colors.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/compose/theme/Colors.kt @@ -7,44 +7,45 @@ import androidx.compose.material.lightColors import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color - @Composable fun DemoTheme( darkTheme: Boolean = isSystemInDarkTheme(), - content: @Composable () -> Unit + content: @Composable () -> Unit, ) { MaterialTheme( colors = if (darkTheme) darkThemeColors else lightThemeColors, - content = content + content = content, ) } -val lightThemeColors = lightColors( - primary = Color(0xFF008577), - primaryVariant = Color(0xFF00574B), - secondary = Color(0xFF3F51B5), - secondaryVariant = Color(0xFF3F51B5), - onPrimary = Color(0xFFFFFFFF), - onSecondary = Color(0xFFFFFFFF), - error = Color(0xFFED5933), - onError = Color(0xFFFFFFFF), - background = Color(0xFFF4F4F7), - onBackground = Color(0xFF000000), - surface = Color(0xFFFFFFFF), - onSurface = Color(0xFF000000) -) +val lightThemeColors = + lightColors( + primary = Color(0xFF008577), + primaryVariant = Color(0xFF00574B), + secondary = Color(0xFF3F51B5), + secondaryVariant = Color(0xFF3F51B5), + onPrimary = Color(0xFFFFFFFF), + onSecondary = Color(0xFFFFFFFF), + error = Color(0xFFED5933), + onError = Color(0xFFFFFFFF), + background = Color(0xFFF4F4F7), + onBackground = Color(0xFF000000), + surface = Color(0xFFFFFFFF), + onSurface = Color(0xFF000000), + ) -val darkThemeColors = darkColors( - primary = Color(0xFF00E0C9), - primaryVariant = Color(0xFF00C7AB), - secondary = Color(0xFF3F51B5), - secondaryVariant = Color(0xFF3F51B5), - onPrimary = Color(0xFFFFFFFF), - onSecondary = Color(0xFFFFFFFF), - error = Color(0xFFED5933), - onError = Color(0xFFFFFFFF), - background = Color(0xFF000000), - onBackground = Color(0xFFFAFAFC), - surface = Color(0xFF292B2E), - onSurface = Color(0xFFFAFAFC) -) +val darkThemeColors = + darkColors( + primary = Color(0xFF00E0C9), + primaryVariant = Color(0xFF00C7AB), + secondary = Color(0xFF3F51B5), + secondaryVariant = Color(0xFF3F51B5), + onPrimary = Color(0xFFFFFFFF), + onSecondary = Color(0xFFFFFFFF), + error = Color(0xFFED5933), + onError = Color(0xFFFFFFFF), + background = Color(0xFF000000), + onBackground = Color(0xFFFAFAFC), + surface = Color(0xFF292B2E), + onSurface = Color(0xFFFAFAFC), + ) diff --git a/app/src/test/java/com/hbb20/androidcountrypicker/FlagPackTest.kt b/app/src/test/java/com/hbb20/androidcountrypicker/FlagPackTest.kt index 4293b42..29004d8 100644 --- a/app/src/test/java/com/hbb20/androidcountrypicker/FlagPackTest.kt +++ b/app/src/test/java/com/hbb20/androidcountrypicker/FlagPackTest.kt @@ -14,14 +14,15 @@ import org.robolectric.RobolectricTestRunner */ @RunWith(RobolectricTestRunner::class) class FlagPackTest { - // add new flag pack here - val allFlagPacksProviders = listOf( - "FlagPack1" to CPFlagImageProvider( - FlagPack1.alpha2ToFlag, - FlagPack1.missingFlagPlaceHolder + val allFlagPacksProviders = + listOf( + "FlagPack1" to + CPFlagImageProvider( + FlagPack1.alpha2ToFlag, + FlagPack1.missingFlagPlaceHolder, + ), ) - ) @Test fun `list missing flags in flagpacks`() { @@ -38,8 +39,9 @@ class FlagPackTest { println("Great!!! There is no missing flag in any flag pack") } else { missingFlags.groupBy { it.first }.forEach { (flagPackName, missingFlagAlpha2) -> - println("$flagPackName is missing following flag(s): " + - missingFlagAlpha2.joinToString { it.second } + println( + "$flagPackName is missing following flag(s): " + + missingFlagAlpha2.joinToString { it.second }, ) } } diff --git a/build.gradle.kts b/build.gradle.kts index e5681e4..f9a5f79 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ buildscript { } dependencies { - classpath("com.android.tools.build:gradle:8.1.1") + classpath("com.android.tools.build:gradle:8.2.0") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.KOTLIN_GRADLE_PLUGIN}") classpath("org.jlleitschuh.gradle:ktlint-gradle:${Versions.KTLINT_GRADLE}") classpath("androidx.navigation:navigation-safe-args-gradle-plugin:${Versions.NAVIGATION_GRAPH}") @@ -27,7 +27,6 @@ apply(plugin = "com.github.ben-manes.versions") ktlint { version.set(Versions.KTLINT) - additionalEditorconfigFile.set(file("./.editorconfig")) } plugins { id("io.gitlab.arturbosch.detekt").version(Versions.DETEKT) @@ -61,6 +60,7 @@ tasks.register("clean", Delete::class) { tasks.withType { val nonStableKeywords = listOf("rc", "Alpha", "Beta", "SNAPSHOT", "ea", "preview") + fun isNonStable(version: String): Boolean { val containsNonStableKeyword = nonStableKeywords.any { version.toUpperCase().contains(it.toUpperCase()) } diff --git a/buildSrc/src/main/java/BuildData.kt b/buildSrc/src/main/java/BuildData.kt index 442015f..776ed1d 100644 --- a/buildSrc/src/main/java/BuildData.kt +++ b/buildSrc/src/main/java/BuildData.kt @@ -1,3 +1,5 @@ +import org.gradle.api.JavaVersion + object BuildData { const val demoApplicationId = "com.hbb20.androidcountrypicker" @@ -12,4 +14,6 @@ object BuildData { const val minSdkVersion = 23 const val targetSdkVersion = 34 const val compileSdkVersion = 34 + + val appJavaVersion = JavaVersion.VERSION_17 } \ No newline at end of file diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 9b8c66c..a132314 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -26,11 +26,11 @@ object Versions { const val MOSHI = "1.9.3" // v1.10+ causes build dependency error. needs investigation. const val MOSHI_SEALED = "0.2.0" const val RETROFIT = "2.9.0" - const val NAVIGATION_GRAPH = "2.7.5" + const val NAVIGATION_GRAPH = "2.7.6" const val SCARLET_VERSION = "0.1.11" const val KOTLIN = "1.4.21" - const val KTLINT_GRADLE = "9.4.1" - const val KTLINT = "0.40.0" + const val KTLINT_GRADLE = "12.0.3" // Stop: Until https://github.com/JLLeitschuh/ktlint-gradle/issues/727 + const val KTLINT = "1.1.0" // Stop: Manual update https://github.com/pinterest/ktlint/releases const val REALM_GRADLE_PLUGIN = "10.2.0" const val ROOM = "2.2.6" const val BINTRAY_GRADLE = "1.8.5" @@ -49,9 +49,9 @@ object Versions { // https://github.com/google/ksp/releases // First half of KSP version shows compatible KOTLIN version, // For example, ksp version 1.8.0-1.0.9 means it's compatible with KOTLIN 1.8.0 - const val COMPOSE_COMPILER = "1.5.4" - const val KOTLIN_GRADLE_PLUGIN = "1.9.20" // STOP : See 'Linked Dependencies' comment - const val KSP = "$KOTLIN_GRADLE_PLUGIN-1.0.14" // STOP : See 'Linked Dependencies' comment + const val COMPOSE_COMPILER = "1.5.6" + const val KOTLIN_GRADLE_PLUGIN = "1.9.21" // STOP : See 'Linked Dependencies' comment + const val KSP = "$KOTLIN_GRADLE_PLUGIN-1.0.15" // STOP : See 'Linked Dependencies' comment } object Deps { @@ -62,7 +62,7 @@ object Deps { const val constraintLayout = "androidx.constraintlayout:constraintlayout:2.1.4" const val emoji = "androidx.emoji:emoji:1.1.0" const val fragmentKtx = "androidx.fragment:fragment-ktx:1.6.2" - const val googleMaterialDesign = "com.google.android.material:material:1.12.0-alpha01" + const val googleMaterialDesign = "com.google.android.material:material:1.12.0-alpha02" const val viewModels = "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" const val timber = "com.jakewharton.timber:timber:5.0.1" const val apacheCSV = "org.apache.commons:commons-csv:1.7" @@ -135,7 +135,7 @@ fun DependencyHandlerScope.implementCompose() { // Integration with observables add(IMPLEMENTATION, "androidx.compose.runtime:runtime") add(IMPLEMENTATION, "androidx.compose.runtime:runtime-livedata") - add(IMPLEMENTATION, "androidx.activity:activity-compose:1.8.1") + add(IMPLEMENTATION, "androidx.activity:activity-compose:1.8.2") // COMPOSE ACCOMPANIST add(IMPLEMENTATION, "com.google.accompanist:accompanist-drawablepainter:${Versions.COMPOSE_ACCOMPANIST}") diff --git a/countrypicker/build.gradle.kts b/countrypicker/build.gradle.kts index 7b4db2a..719548a 100644 --- a/countrypicker/build.gradle.kts +++ b/countrypicker/build.gradle.kts @@ -18,12 +18,12 @@ android { viewBinding = true } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = BuildData.appJavaVersion + targetCompatibility = BuildData.appJavaVersion } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8.toString() + jvmTarget = BuildData.appJavaVersion.toString() } testOptions { diff --git a/countrypicker/src/main/java/com/hbb20/CountryPickerView.kt b/countrypicker/src/main/java/com/hbb20/CountryPickerView.kt index 64a9ace..96875c8 100644 --- a/countrypicker/src/main/java/com/hbb20/CountryPickerView.kt +++ b/countrypicker/src/main/java/com/hbb20/CountryPickerView.kt @@ -16,60 +16,65 @@ import com.hbb20.countrypicker.helper.readListConfigFromAttrs import com.hbb20.countrypicker.helper.readViewConfigFromAttrs import com.hbb20.countrypicker.view.CPViewHelper -class CountryPickerView @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0 -) : ConstraintLayout(context, attrs, defStyleAttr) { - val tvCountryInfo: TextView by lazy { findViewById(R.id.tvCountryInfo) } - val tvEmojiFlag: TextView by lazy { findViewById(R.id.tvEmojiFlag) } - val imgFlag: ImageView by lazy { findViewById(R.id.imgFlag) } - val imgDropDownIcon: ImageView by lazy { findViewById(R.id.icDropdown) } - var cpViewHelper: CPViewHelper +class CountryPickerView + @JvmOverloads + constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + ) : ConstraintLayout(context, attrs, defStyleAttr) { + val tvCountryInfo: TextView by lazy { findViewById(R.id.tvCountryInfo) } + val tvEmojiFlag: TextView by lazy { findViewById(R.id.tvEmojiFlag) } + val imgFlag: ImageView by lazy { findViewById(R.id.imgFlag) } + val imgDropDownIcon: ImageView by lazy { findViewById(R.id.icDropdown) } + var cpViewHelper: CPViewHelper - init { - applyLayout(attrs) - cpViewHelper = prepareHelperFromAttr(attrs) - cpViewHelper.attachViewComponents(this, tvCountryInfo, tvEmojiFlag, imgFlag) - } + init { + applyLayout(attrs) + cpViewHelper = prepareHelperFromAttr(attrs) + cpViewHelper.attachViewComponents(this, tvCountryInfo, tvEmojiFlag, imgFlag) + } - private fun prepareHelperFromAttr(attrs: AttributeSet?): CPViewHelper { - val styledAttrs = - context.theme.obtainStyledAttributes(attrs, R.styleable.CountryPickerView, 0, 0) - val dataStore = CPDataStoreGenerator.generate(context) - val dialogConfig = readDialogConfigFromAttrs(styledAttrs) - val listConfig = readListConfigFromAttrs(styledAttrs) - val viewConfig = readViewConfigFromAttrs(styledAttrs) - val rowConfig = CPRowConfig() - return CPViewHelper( - context, - dataStore, - viewConfig, - dialogConfig, - listConfig, - rowConfig, - isInEditMode - ) - } + private fun prepareHelperFromAttr(attrs: AttributeSet?): CPViewHelper { + val styledAttrs = + context.theme.obtainStyledAttributes(attrs, R.styleable.CountryPickerView, 0, 0) + val dataStore = CPDataStoreGenerator.generate(context) + val dialogConfig = readDialogConfigFromAttrs(styledAttrs) + val listConfig = readListConfigFromAttrs(styledAttrs) + val viewConfig = readViewConfigFromAttrs(styledAttrs) + val rowConfig = CPRowConfig() + return CPViewHelper( + context, + dataStore, + viewConfig, + dialogConfig, + listConfig, + rowConfig, + isInEditMode, + ) + } - /** - * If width is match_parent, 0 - */ - private fun applyLayout(attrs: AttributeSet?) { - val xmlWidth = - attrs?.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_width") - val wrapContentValues = - setOf(ViewGroup.LayoutParams.WRAP_CONTENT.toString(), "wrap_content") - val layoutFile = - if (xmlWidth == null || xmlWidth in wrapContentValues) R.layout.cp_country_picker_view - else R.layout.cp_country_picker_view_constrained - LayoutInflater.from(context) - .inflate(layoutFile, this, true) - } + /** + * If width is match_parent, 0 + */ + private fun applyLayout(attrs: AttributeSet?) { + val xmlWidth = + attrs?.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_width") + val wrapContentValues = + setOf(ViewGroup.LayoutParams.WRAP_CONTENT.toString(), "wrap_content") + val layoutFile = + if (xmlWidth == null || xmlWidth in wrapContentValues) { + R.layout.cp_country_picker_view + } else { + R.layout.cp_country_picker_view_constrained + } + LayoutInflater.from(context) + .inflate(layoutFile, this, true) + } - fun changeFlagProvider(flagProvider: CPFlagProvider?) { - cpViewHelper.cpViewConfig.cpFlagProvider = flagProvider - cpViewHelper.cpRowConfig.cpFlagProvider = flagProvider - cpViewHelper.refreshView() + fun changeFlagProvider(flagProvider: CPFlagProvider?) { + cpViewHelper.cpViewConfig.cpFlagProvider = flagProvider + cpViewHelper.cpRowConfig.cpFlagProvider = flagProvider + cpViewHelper.refreshView() + } } -} diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt index 15cb1f3..0a37977 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/CountryPickerComposable.kt @@ -82,13 +82,14 @@ val countryMasterListTransformer = { countryList: List -> finalList = finalList.sortedBy { it.phoneCode.toString() } // to modify any property of country - finalList = finalList.map { country -> - if (country.alpha2 == "IN") { - country.copy(name = "Bharat") - } else { - country + finalList = + finalList.map { country -> + if (country.alpha2 == "IN") { + country.copy(name = "Bharat") + } else { + country + } } - } finalList } @@ -99,35 +100,38 @@ fun CountryPicker( modifier: Modifier = Modifier, cpDataStore: CPDataStore = rememberCPDataStore(), flagProvider: CPFlagProvider? = DefaultEmojiFlagProvider(), - selectedCountryLayout: @Composable (( - country: CPCountry?, - countryFlag: CountryFlag?, - emptySelectionText: String, - modifier: Modifier, - showCountryPickerDialog: () -> Unit - ) -> Unit) = { country, countryFlag, emptySelectionText, modifier, showCountryPickerDialog -> + selectedCountryLayout: + @Composable ( + ( + country: CPCountry?, + countryFlag: CountryFlag?, + emptySelectionText: String, + modifier: Modifier, + showCountryPickerDialog: () -> Unit, + ) -> Unit + ) = { country, countryFlag, emptySelectionText, modifier, showCountryPickerDialog -> DefaultSelectedCountryLayout( country, countryFlag, emptySelectionText, modifier, - showCountryPickerDialog + showCountryPickerDialog, ) }, - pickerDialog: @Composable (( - cpDataStore: CPDataStore, - flagProvider: CPFlagProvider?, - onDismissRequest: () -> Unit, - onCountrySelected: (CPCountry?) -> Unit, - ) -> Unit) = { cpDataStore, - flagProvider, - onDismissRequest, - onCountrySelected -> + pickerDialog: + @Composable ( + ( + cpDataStore: CPDataStore, + flagProvider: CPFlagProvider?, + onDismissRequest: () -> Unit, + onCountrySelected: (CPCountry?) -> Unit, + ) -> Unit + ) = { cpDataStore, flagProvider, onDismissRequest, onCountrySelected -> CountryPickerDialog( cpDataStore = cpDataStore, flagProvider = flagProvider, onDismissRequest = onDismissRequest, - onCountrySelected = onCountrySelected + onCountrySelected = onCountrySelected, ) }, onCountrySelected: (CPCountry?) -> Unit, @@ -144,32 +148,30 @@ fun CountryPicker( launchPickerDialog, ) if (showPickerDialog) { - pickerDialog( - cpDataStore, - flagProvider, - { setShowPickerDialog(false) }) { + pickerDialog(cpDataStore, flagProvider, { setShowPickerDialog(false) }) { onCountrySelected(it) setShowPickerDialog(false) } } } - @Preview @Composable fun CountryLayoutPreview() { val (selectedCountry, setSelectedCountry) = remember { mutableStateOf("IN") } Column( - modifier = Modifier - .fillMaxSize() - .background(MaterialTheme.colors.background) + modifier = + Modifier + .fillMaxSize() + .background(MaterialTheme.colors.background), ) { CountryPicker( alpha2Code = selectedCountry, - modifier = Modifier - .fillMaxWidth() - .heightIn(min = 48.dp), - onCountrySelected = { setSelectedCountry(it?.alpha2) } + modifier = + Modifier + .fillMaxWidth() + .heightIn(min = 48.dp), + onCountrySelected = { setSelectedCountry(it?.alpha2) }, ) } } @@ -185,11 +187,12 @@ private fun DefaultSelectedCountryLayout( val textToShow = country?.name ?: emptySelectionText Row( verticalAlignment = Alignment.CenterVertically, - modifier = modifier - .clip(RoundedCornerShape(4.dp)) - .clickable { showCountryPickerDialog() } - .padding(8.dp), - horizontalArrangement = Arrangement.Center + modifier = + modifier + .clip(RoundedCornerShape(4.dp)) + .clickable { showCountryPickerDialog() } + .padding(8.dp), + horizontalArrangement = Arrangement.Center, ) { val textStyle = MaterialTheme.typography.body1 if (countryFlag != null) { @@ -218,7 +221,7 @@ fun CountryFlagLayout( text = countryFlag.emoji.toString(), style = emojiFlagTextStyle, color = LocalContentColor.current, - modifier = modifier + modifier = modifier, ) } @@ -226,11 +229,11 @@ fun CountryFlagLayout( Image( painter = painterResource(id = countryFlag.flagImageRes), contentDescription = null, - modifier = modifier.height(imageFlagHeight) + modifier = modifier.height(imageFlagHeight), ) } - null -> { /* do nothing */ + null -> { // do nothing } } } @@ -238,32 +241,38 @@ fun CountryFlagLayout( @Composable fun rememberCountryFlag( country: CPCountry?, - flagProvider: CPFlagProvider? = DefaultEmojiFlagProvider() + flagProvider: CPFlagProvider? = DefaultEmojiFlagProvider(), ) = remember(country, flagProvider) { if (country != null && flagProvider != null) { when (flagProvider) { is DefaultEmojiFlagProvider -> { - val emoji = when { - flagProvider.useEmojiCompat -> EmojiCompat.get().process(country.flagEmoji) - else -> country.flagEmoji - } + val emoji = + when { + flagProvider.useEmojiCompat -> EmojiCompat.get().process(country.flagEmoji) + else -> country.flagEmoji + } EmojiFlag(emoji) } is CPFlagImageProvider -> ImageFlag(flagProvider.getFlag(country.alpha2)) else -> null } - } else null + } else { + null + } } sealed class CountryFlag { data class EmojiFlag(val emoji: CharSequence) : CountryFlag() - data class ImageFlag(@DrawableRes val flagImageRes: Int) : CountryFlag() + + data class ImageFlag( + @DrawableRes val flagImageRes: Int, + ) : CountryFlag() } @Composable fun rememberCPDataStore( - countryFileReader: CountryFileReading = CPDataStoreGenerator.defaultCountryFileReader, + countryFileReader: CountryFileReading = CPDataStoreGenerator.DEFAULT_FILE_READER, countryListTransformer: ((List) -> List)? = null, ): CPDataStore { val context = LocalContext.current @@ -271,7 +280,7 @@ fun rememberCPDataStore( CPDataStoreGenerator.generate( context, countryFileReader = countryFileReader, - countryListTransformer = countryListTransformer + countryListTransformer = countryListTransformer, ) } } @@ -287,11 +296,13 @@ fun CountryPickerDialog( queryFilter: (country: CPCountry, filterQuery: String) -> Boolean = { country, filterQuery -> defaultCountrySearchFilter(country, filterQuery) }, - countryRowLayout: @Composable (( + countryRowLayout: @Composable ( + ( country: CPCountry, flagProvider: CPFlagProvider?, onClicked: (CPCountry) -> Unit, - ) -> Unit) = { country, flagProvider, onClicked -> + ) -> Unit + ) = { country, flagProvider, onClicked -> CountryListItemRowLayout(country, flagProvider, onClicked) }, onDismissRequest: () -> Unit, @@ -299,7 +310,7 @@ fun CountryPickerDialog( ) { Dialog( onDismissRequest = { onDismissRequest() }, - properties = DialogProperties(usePlatformDefaultWidth = false) + properties = DialogProperties(usePlatformDefaultWidth = false), ) { DefaultCountryPickerDialogContent( quickAccessCountriesCodes = quickAccessCountries, @@ -330,47 +341,59 @@ private fun DefaultCountryPickerDialogContent( queryFilter: (country: CPCountry, filterQuery: String) -> Boolean = { country, filterQuery -> defaultCountrySearchFilter(country, filterQuery) }, - searchFieldLayout: @Composable (( + searchFieldLayout: @Composable ( + ( searchQuery: String, setSearchQuery: (String) -> Unit, - cpDataStore: CPDataStore - ) -> Unit) = { searchQuery, setSearchQuery, cpDataStore -> + cpDataStore: CPDataStore, + ) -> Unit + ) = { searchQuery, setSearchQuery, cpDataStore -> DefaultSearchField(searchQuery, setSearchQuery, cpDataStore) }, - countryRowLayout: @Composable (( + countryRowLayout: @Composable ( + ( country: CPCountry, flagProvider: CPFlagProvider?, onClicked: (CPCountry) -> Unit, - ) -> Unit) = { country, flagProvider, onClicked -> + ) -> Unit + ) = { country, flagProvider, onClicked -> CountryListItemRowLayout(country, flagProvider, onClicked) }, onDismissRequest: () -> Unit, ) { Card( - modifier = modifier - .fillMaxWidth(0.8f) - .padding(16.dp), + modifier = + modifier + .fillMaxWidth(0.8f) + .padding(16.dp), shape = RoundedCornerShape(16.dp), backgroundColor = MaterialTheme.colors.surface, ) { - val countryList = remember(cpDataStore) { - cpDataStore.countryList - } + val countryList = + remember(cpDataStore) { + cpDataStore.countryList + } val scrollState = rememberLazyListState() - val quickAccessCountries = remember(quickAccessCountriesCodes, countryList) { - quickAccessCountriesCodes.orEmpty().mapNotNull { alpha2 -> - countryList.firstOrNull { it.alpha2.equals(alpha2, ignoreCase = true) } + val quickAccessCountries = + remember(quickAccessCountriesCodes, countryList) { + quickAccessCountriesCodes.orEmpty().mapNotNull { alpha2 -> + countryList.firstOrNull { it.alpha2.equals(alpha2, ignoreCase = true) } + } } - } val (searchQuery, setSearchQuery) = remember { mutableStateOf("") } - val filteredList = remember(countryList, searchQuery) { - countryList.filter { queryFilter(it, searchQuery) } - } - val filteredQuickAccessCountries = remember(showFilter, quickAccessCountries, searchQuery) { - if (showFilter == false) emptyList() - else quickAccessCountries.filter { queryFilter(it, searchQuery) } - .distinctBy(CPCountry::alpha2) - } + val filteredList = + remember(countryList, searchQuery) { + countryList.filter { queryFilter(it, searchQuery) } + } + val filteredQuickAccessCountries = + remember(showFilter, quickAccessCountries, searchQuery) { + if (showFilter == false) { + emptyList() + } else { + quickAccessCountries.filter { queryFilter(it, searchQuery) } + .distinctBy(CPCountry::alpha2) + } + } LaunchedEffect(key1 = filteredList, key2 = filteredQuickAccessCountries) { scrollState.scrollToItem(0) } @@ -400,17 +423,14 @@ private fun DefaultCountryPickerDialogContent( } } if (allowClearSelection) { - TextButton( - onClick = { - onCountrySelected(null) - onDismissRequest() - }, - modifier = Modifier.padding(start = 8.dp, bottom = 8.dp) - ) { + TextButton(onClick = { + onCountrySelected(null) + onDismissRequest() + }, modifier = Modifier.padding(start = 8.dp, bottom = 8.dp)) { Text( text = cpDataStore.messageGroup.clearSelectionText, style = MaterialTheme.typography.button, - color = MaterialTheme.colors.onBackground + color = MaterialTheme.colors.onBackground, ) } } @@ -423,7 +443,7 @@ private fun DefaultCountryPickerDialogContent( private fun DefaultSearchField( searchQuery: String, setSearchQuery: (String) -> Unit, - cpDataStore: CPDataStore + cpDataStore: CPDataStore, ) { val keyboardController = LocalSoftwareKeyboardController.current val focusManager = LocalFocusManager.current @@ -434,32 +454,33 @@ private fun DefaultSearchField( painter = painterResource(id = R.drawable.ic_cp_search), contentDescription = null, modifier = Modifier.padding(16.dp), - tint = MaterialTheme.colors.onSurface.copy(alpha = 0.5f) + tint = MaterialTheme.colors.onSurface.copy(alpha = 0.5f), ) Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterStart) { BasicTextField( value = searchQuery, onValueChange = { setSearchQuery(it) }, textStyle = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onSurface), - cursorBrush = SolidColor( - TextFieldDefaults.outlinedTextFieldColors() - .cursorColor(isError = false).value - ), + cursorBrush = + SolidColor( + TextFieldDefaults.outlinedTextFieldColors() + .cursorColor(isError = false).value, + ), singleLine = true, keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Search), - keyboardActions = KeyboardActions(onAny = { - keyboardController?.hide() - focusManager.clearFocus() - }), - modifier = Modifier - .fillMaxWidth() + keyboardActions = + KeyboardActions(onAny = { + keyboardController?.hide() + focusManager.clearFocus() + }), + modifier = Modifier.fillMaxWidth(), ) if (searchQuery.isEmpty()) { Text( text = cpDataStore.messageGroup.searchHint, style = MaterialTheme.typography.body1, - color = MaterialTheme.colors.onSurface.copy(alpha = 0.5f) + color = MaterialTheme.colors.onSurface.copy(alpha = 0.5f), ) } } @@ -475,14 +496,15 @@ private fun CountryListItemRowLayout( ) { val countryFlag = rememberCountryFlag(country, flagProvider) Row( - modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(4.dp)) - .clickable { - onClicked(country) - } - .padding(16.dp), - verticalAlignment = Alignment.CenterVertically + modifier = + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(4.dp)) + .clickable { + onClicked(country) + } + .padding(16.dp), + verticalAlignment = Alignment.CenterVertically, ) { if (countryFlag != null) { CountryFlagLayout(countryFlag) @@ -501,14 +523,10 @@ private fun CountryListItemRowLayout( fun defaultCountrySearchFilter( country: CPCountry, filterQuery: String, -) = if (filterQuery.isBlank()) true -else { - val properties = listOf( - country.name, - country.englishName, - country.alpha2, - country.alpha3, - ) +) = if (filterQuery.isBlank()) { + true +} else { + val properties = listOf(country.name, country.englishName, country.alpha2, country.alpha3) properties.any { it.contains(filterQuery, ignoreCase = true) } } @@ -517,14 +535,18 @@ else { fun PreviewSomeDialogContent() { MaterialTheme { Box( - modifier = Modifier - .fillMaxSize() - .background(Color.Gray) - .padding(20.dp), + modifier = + Modifier + .fillMaxSize() + .background(Color.Gray) + .padding(20.dp), contentAlignment = Alignment.Center, ) { DefaultCountryPickerDialogContent( - cpDataStore = rememberCPDataStore(countryListTransformer = countryMasterListTransformer), + cpDataStore = + rememberCPDataStore( + countryListTransformer = countryMasterListTransformer, + ), flagProvider = DefaultEmojiFlagProvider(), quickAccessCountriesCodes = null, showFilter = true, @@ -541,7 +563,7 @@ fun PreviewSomeDialogContent() { @Composable fun rememberCountry( countryCode: String?, - cpDataStore: CPDataStore = rememberCPDataStore() + cpDataStore: CPDataStore = rememberCPDataStore(), ): CPCountry? { return remember(countryCode, cpDataStore) { cpDataStore.countryList.firstOrNull { it.alpha2.equals(countryCode, ignoreCase = true) } @@ -555,11 +577,12 @@ fun rememberCountry( */ @Composable fun rememberAutoDetectedCountryCode( - sourceOrder: List = listOf( - CPCountryDetector.Source.SIM, - CPCountryDetector.Source.NETWORK, - CPCountryDetector.Source.LOCALE - ) + sourceOrder: List = + listOf( + CPCountryDetector.Source.SIM, + CPCountryDetector.Source.NETWORK, + CPCountryDetector.Source.LOCALE, + ), ): String? { val context = LocalContext.current return remember(sourceOrder) { @@ -574,10 +597,9 @@ fun rememberQuickAccessCountries(): List { listOf( countryDetector.detectSIMCountry(), countryDetector.detectNetworkCountry(), - countryDetector.detectLocaleCountry() + countryDetector.detectLocaleCountry(), ).filterNotNull().distinct() } } - -// \ No newline at end of file +// diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/Helper.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/Helper.kt index d9bd42f..abb0fa9 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/compose/Helper.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/compose/Helper.kt @@ -5,7 +5,6 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.TextUnit - @Composable fun Dp.toSp() = with(LocalDensity.current) { toSp() } @@ -19,4 +18,4 @@ fun Int.toDp() = with(LocalDensity.current) { toDp() } fun Float.toDp() = with(LocalDensity.current) { toDp() } @Composable -fun TextUnit.toDp() = with(LocalDensity.current) { toDp() } \ No newline at end of file +fun TextUnit.toDp() = with(LocalDensity.current) { toDp() } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPDialogConfig.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPDialogConfig.kt index 6ba1b46..28f00f4 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPDialogConfig.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPDialogConfig.kt @@ -6,19 +6,18 @@ import com.hbb20.countrypicker.R data class CPDialogConfig( var dialogViewIds: CPDialogViewIds = defaultCPDialogViewIds, - var allowSearch: Boolean = defaultCPDialogAllowSearch, - var allowClearSelection: Boolean = defaultCPDialogAllowClearSelection, - var showTitle: Boolean = defaultCPDialogDefaultShowTitle, - var showFullScreen: Boolean = defaultCPDialogShowFullScreen, - var sizeMode: SizeMode = defaultCPDialogDefaultSizeMode, + var allowSearch: Boolean = DEFAULT_CP_DIALOG_ALLOW_SEARCH, + var allowClearSelection: Boolean = DEFAULT_CP_DIALOG_ALLOW_CLEAR_SELECTION, + var showTitle: Boolean = DEFAULT_CP_DIALOG_SHOW_TITLE, + var showFullScreen: Boolean = DEFAULT_CP_DIALOG_SHOW_FULL_SCREEN, + var sizeMode: SizeMode = DEFAULT_CP_DIALOG_SIZE_MODE, ) { - companion object { - const val defaultCPDialogAllowSearch = true - const val defaultCPDialogShowFullScreen = false - const val defaultCPDialogAllowClearSelection = false - const val defaultCPDialogDefaultShowTitle = true - val defaultCPDialogDefaultSizeMode: SizeMode = SizeMode.Auto + const val DEFAULT_CP_DIALOG_ALLOW_SEARCH = true + const val DEFAULT_CP_DIALOG_SHOW_FULL_SCREEN = false + const val DEFAULT_CP_DIALOG_ALLOW_CLEAR_SELECTION = false + const val DEFAULT_CP_DIALOG_SHOW_TITLE = true + val DEFAULT_CP_DIALOG_SIZE_MODE: SizeMode = SizeMode.Auto val defaultCPDialogViewIds = CPDialogViewIds( @@ -28,7 +27,7 @@ data class CPDialogConfig( R.id.tvTitle, R.id.etQuery, R.id.imgClearQuery, - R.id.btnClearSelection + R.id.btnClearSelection, ) } @@ -56,11 +55,13 @@ data class CPDialogViewIds( @IdRes val titleTextViewId: Int?, @IdRes val queryEditTextId: Int?, @IdRes val clearQueryImageViewId: Int?, - @IdRes val clearSelectionButtonId: Int? + @IdRes val clearSelectionButtonId: Int?, ) sealed class SizeMode { object Auto : SizeMode() + object Unchanged : SizeMode() + object Wrap : SizeMode() } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPListConfig.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPListConfig.kt index a67d573..0b13e67 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPListConfig.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPListConfig.kt @@ -1,7 +1,7 @@ package com.hbb20.countrypicker.config data class CPListConfig( - var preferredCountryCodes: String? = defaultCPListPreferredCountryCodes + var preferredCountryCodes: String? = defaultCPListPreferredCountryCodes, ) { companion object { val defaultCPListPreferredCountryCodes: String? = null diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPRowConfig.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPRowConfig.kt index 6ee016f..89ef39b 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPRowConfig.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPRowConfig.kt @@ -8,7 +8,7 @@ data class CPRowConfig( var cpFlagProvider: CPFlagProvider? = defaultFlagProvider, var primaryTextGenerator: ((CPCountry) -> String) = defaultPrimaryTextGenerator, var secondaryTextGenerator: ((CPCountry) -> String)? = defaultSecondaryTextGenerator, - var highlightedTextGenerator: ((CPCountry) -> String)? = defaultHighlightedTextGenerator + var highlightedTextGenerator: ((CPCountry) -> String)? = defaultHighlightedTextGenerator, ) { companion object { val defaultFlagProvider = DefaultEmojiFlagProvider() diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPViewConfig.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPViewConfig.kt index aa26744..a67a4a0 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPViewConfig.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/config/CPViewConfig.kt @@ -8,7 +8,7 @@ import com.hbb20.countrypicker.models.CPCountry data class CPViewConfig( val initialSelection: InitialSelection = defaultCPInitialSelectionMode, var viewTextGenerator: ((CPCountry) -> String) = defaultSelectedCountryInfoTextGenerator, - var cpFlagProvider: CPFlagProvider? = DefaultEmojiFlagProvider() + var cpFlagProvider: CPFlagProvider? = DefaultEmojiFlagProvider(), ) { companion object { val defaultCPInitialSelectionMode = InitialSelection.EmptySelection diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/datagenerator/CPDataStoreGenerator.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/datagenerator/CPDataStoreGenerator.kt index 798b553..9bce046 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/datagenerator/CPDataStoreGenerator.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/datagenerator/CPDataStoreGenerator.kt @@ -8,18 +8,19 @@ import java.util.* object CPDataStoreGenerator { private var masterDataStore: CPDataStore? = null - const val defaultMasterCountries = "" - const val defaultExcludedCountries = "" + const val DEFAULT_MASTER_COUNTRIES = "" + const val DEFAULT_EXCLUDED_COUNTRIES = "" + @Deprecated("no-longer-used") - const val defaultUseCache = true - val defaultCountryFileReader = CPFileReader + const val DEFAULT_USE_CACHE = true + val DEFAULT_FILE_READER = CPFileReader fun generate( context: Context, - customMasterCountries: String = defaultMasterCountries, - customExcludedCountries: String = defaultExcludedCountries, - countryFileReader: CountryFileReading = defaultCountryFileReader, - useCache: Boolean = defaultUseCache + customMasterCountries: String = DEFAULT_MASTER_COUNTRIES, + customExcludedCountries: String = DEFAULT_EXCLUDED_COUNTRIES, + countryFileReader: CountryFileReading = DEFAULT_FILE_READER, + useCache: Boolean = DEFAULT_USE_CACHE, ): CPDataStore { onMethodBegin("GenerateDataStore") if (masterDataStore == null || !useCache) { @@ -30,16 +31,17 @@ object CPDataStoreGenerator { var countryList = filterCustomMasterList( it.countryList, - customMasterCountries + customMasterCountries, ) countryList = filterExcludedCountriesList( countryList, - customExcludedCountries + customExcludedCountries, ) return it.copy( - countryList = countryList.sortedBy { cpCountry -> cpCountry.name } - .toMutableList() + countryList = + countryList.sortedBy { cpCountry -> cpCountry.name } + .toMutableList(), ) } @@ -48,8 +50,8 @@ object CPDataStoreGenerator { fun generate( context: Context, - countryFileReader: CountryFileReading = defaultCountryFileReader, - countryListTransformer: ((List) -> List)? + countryFileReader: CountryFileReading = DEFAULT_FILE_READER, + countryListTransformer: ((List) -> List)?, ): CPDataStore { onMethodBegin("GenerateDataStore") if (masterDataStore == null) { @@ -70,13 +72,14 @@ object CPDataStoreGenerator { private fun filterExcludedCountriesList( countryList: List, - customExcludedCountries: String + customExcludedCountries: String, ): List { val countryAlphaCodes = customExcludedCountries.split(",").map { it.trim().toUpperCase(Locale.US) } - val filteredCountries = countryList.filterNot { - countryAlphaCodes.contains(it.alpha2) || countryAlphaCodes.contains(it.alpha3) - } + val filteredCountries = + countryList.filterNot { + countryAlphaCodes.contains(it.alpha2) || countryAlphaCodes.contains(it.alpha3) + } return if (filteredCountries.isNotEmpty()) { filteredCountries } else { @@ -86,13 +89,14 @@ object CPDataStoreGenerator { private fun filterCustomMasterList( masterCountryList: List, - customExcludedCountries: String + customExcludedCountries: String, ): List { val countryAlphaCodes = customExcludedCountries.split(",").map { it.trim().toUpperCase(Locale.US) } - val customMasterCountries = masterCountryList.filter { - countryAlphaCodes.contains(it.alpha2) || countryAlphaCodes.contains(it.alpha3) - } + val customMasterCountries = + masterCountryList.filter { + countryAlphaCodes.contains(it.alpha2) || countryAlphaCodes.contains(it.alpha3) + } /** * If there is no valid master country, return default master list diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/datagenerator/CPFileReader.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/datagenerator/CPFileReader.kt index c652beb..f234476 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/datagenerator/CPFileReader.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/datagenerator/CPFileReader.kt @@ -12,9 +12,7 @@ import com.hbb20.countrypicker.models.CountryInfo import com.hbb20.countrypicker.models.countryInfoList interface CountryFileReading { - fun readMasterDataFromFiles( - context: Context - ): CPDataStore + fun readMasterDataFromFiles(context: Context): CPDataStore } object CPFileReader : CountryFileReading { @@ -24,17 +22,17 @@ object CPFileReader : CountryFileReading { onMethodBegin("readMasterDataFromFiles") val messageGroup = loadMessageGroup( - context.resources + context.resources, ) val translations = loadCountryNameTranslations( - context + context, ) val cpCountries = countryInfos.map { CPCountry.from(it, translations[it.alpha2]) } logMethodEnd("readMasterDataFromFiles") return CPDataStore( cpCountries.toMutableList(), - messageGroup + messageGroup, ) } @@ -46,11 +44,12 @@ object CPFileReader : CountryFileReading { val result = hashMapOf() countryInfoList.forEach { country -> Log.d("CountryPicker", "Lookinng up resourcee for cp_${country.alpha2}_name") - val resId: Int = context.resources.getIdentifier( - "cp_${country.alpha2}_name", - "string", - context.packageName - ) + val resId: Int = + context.resources.getIdentifier( + "cp_${country.alpha2}_name", + "string", + context.packageName, + ) val name: String = context.getString(resId) Log.d("CountryPicker", "found resourcee for cp_${country.alpha2}_name = $name") @@ -65,13 +64,14 @@ object CPFileReader : CountryFileReading { */ private fun loadMessageGroup(resources: Resources): CPDataStore.MessageGroup { onMethodBegin("loadMessageGroup") - val messageGroup = CPDataStore.MessageGroup( - noMatchMsg = resources.getString(R.string.cp_no_match_msg), - searchHint = resources.getString(R.string.cp_search_hint), - dialogTitle = resources.getString(R.string.cp_dialog_title), - selectionPlaceholderText = resources.getString(R.string.cp_selection_placeholder), - clearSelectionText = resources.getString(R.string.cp_clear_selection) - ) + val messageGroup = + CPDataStore.MessageGroup( + noMatchMsg = resources.getString(R.string.cp_no_match_msg), + searchHint = resources.getString(R.string.cp_search_hint), + dialogTitle = resources.getString(R.string.cp_dialog_title), + selectionPlaceholderText = resources.getString(R.string.cp_selection_placeholder), + clearSelectionText = resources.getString(R.string.cp_clear_selection), + ) logMethodEnd("loadMessageGroup") return messageGroup } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/dialog/CPDialogExtension.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/dialog/CPDialogExtension.kt index 927d717..7283fdc 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/dialog/CPDialogExtension.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/dialog/CPDialogExtension.kt @@ -10,10 +10,10 @@ import com.hbb20.countrypicker.models.CPDataStore import com.hbb20.countrypicker.recyclerview.defaultDataStoreModifier fun Context.launchCountryPickerDialog( - customMasterCountries: String = CPDataStoreGenerator.defaultMasterCountries, - customExcludedCountries: String = CPDataStoreGenerator.defaultExcludedCountries, - countryFileReader: CountryFileReading = CPDataStoreGenerator.defaultCountryFileReader, - useCache: Boolean = CPDataStoreGenerator.defaultUseCache, + customMasterCountries: String = CPDataStoreGenerator.DEFAULT_MASTER_COUNTRIES, + customExcludedCountries: String = CPDataStoreGenerator.DEFAULT_EXCLUDED_COUNTRIES, + countryFileReader: CountryFileReading = CPDataStoreGenerator.DEFAULT_FILE_READER, + useCache: Boolean = CPDataStoreGenerator.DEFAULT_USE_CACHE, customDataStoreModifier: ((CPDataStore) -> (Unit))? = defaultDataStoreModifier, cpFlagProvider: CPFlagProvider? = CPRowConfig.defaultFlagProvider, primaryTextGenerator: ((CPCountry) -> String) = CPRowConfig.defaultPrimaryTextGenerator, @@ -21,42 +21,46 @@ fun Context.launchCountryPickerDialog( highlightedTextGenerator: ((CPCountry) -> String)? = CPRowConfig.defaultHighlightedTextGenerator, preferredCountryCodes: String? = null, dialogViewIds: CPDialogViewIds = CPDialogConfig.defaultCPDialogViewIds, - allowSearch: Boolean = CPDialogConfig.defaultCPDialogAllowSearch, - allowClearSelection: Boolean = CPDialogConfig.defaultCPDialogAllowClearSelection, - showTitle: Boolean = CPDialogConfig.defaultCPDialogDefaultShowTitle, - showFullScreen: Boolean = CPDialogConfig.defaultCPDialogShowFullScreen, - sizeMode: SizeMode = CPDialogConfig.defaultCPDialogDefaultSizeMode, - onCountryClickListener: ((CPCountry?) -> Unit) + allowSearch: Boolean = CPDialogConfig.DEFAULT_CP_DIALOG_ALLOW_SEARCH, + allowClearSelection: Boolean = CPDialogConfig.DEFAULT_CP_DIALOG_ALLOW_CLEAR_SELECTION, + showTitle: Boolean = CPDialogConfig.DEFAULT_CP_DIALOG_SHOW_TITLE, + showFullScreen: Boolean = CPDialogConfig.DEFAULT_CP_DIALOG_SHOW_FULL_SCREEN, + sizeMode: SizeMode = CPDialogConfig.DEFAULT_CP_DIALOG_SIZE_MODE, + onCountryClickListener: ((CPCountry?) -> Unit), ) { - val cpDataStore = CPDataStoreGenerator.generate( - context = this, - customMasterCountries = customMasterCountries, - customExcludedCountries = customExcludedCountries, - countryFileReader = countryFileReader, - useCache = useCache - ) + val cpDataStore = + CPDataStoreGenerator.generate( + context = this, + customMasterCountries = customMasterCountries, + customExcludedCountries = customExcludedCountries, + countryFileReader = countryFileReader, + useCache = useCache, + ) customDataStoreModifier?.invoke(cpDataStore) - val cpDialogConfig = CPDialogConfig( - dialogViewIds = dialogViewIds, - allowSearch = allowSearch, - allowClearSelection = allowClearSelection, - showTitle = showTitle, - showFullScreen = showFullScreen, - sizeMode = sizeMode, - ) + val cpDialogConfig = + CPDialogConfig( + dialogViewIds = dialogViewIds, + allowSearch = allowSearch, + allowClearSelection = allowClearSelection, + showTitle = showTitle, + showFullScreen = showFullScreen, + sizeMode = sizeMode, + ) - val cpCountryRowConfig = CPRowConfig( - cpFlagProvider = cpFlagProvider, - primaryTextGenerator = primaryTextGenerator, - secondaryTextGenerator = secondaryTextGenerator, - highlightedTextGenerator = highlightedTextGenerator - ) + val cpCountryRowConfig = + CPRowConfig( + cpFlagProvider = cpFlagProvider, + primaryTextGenerator = primaryTextGenerator, + secondaryTextGenerator = secondaryTextGenerator, + highlightedTextGenerator = highlightedTextGenerator, + ) - val cpListConfig = CPListConfig( - preferredCountryCodes = preferredCountryCodes - ) + val cpListConfig = + CPListConfig( + preferredCountryCodes = preferredCountryCodes, + ) val helper = CPDialogHelper( diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/dialog/CPDialogHelper.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/dialog/CPDialogHelper.kt index eb79e72..aa89de5 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/dialog/CPDialogHelper.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/dialog/CPDialogHelper.kt @@ -27,7 +27,7 @@ class CPDialogHelper( private val cpDialogConfig: CPDialogConfig, private val cpListConfig: CPListConfig, private val cpRowConfig: CPRowConfig, - val onCountryClickListener: (CPCountry?) -> Unit + val onCountryClickListener: (CPCountry?) -> Unit, ) { fun createDialog(context: Context): Dialog { val dialog = Dialog(context) @@ -43,16 +43,17 @@ class CPDialogHelper( val etQuery: EditText? = cpDialogConfig.dialogViewIds.queryEditTextId?.let { etQueryId -> dialogView.findViewById( - etQueryId + etQueryId, ) } val imgClearQuery: ImageView? = cpDialogConfig.dialogViewIds.clearQueryImageViewId?.let { imgClearQueryId -> dialogView.findViewById(imgClearQueryId) } - val tvTitle: TextView? = cpDialogConfig.dialogViewIds.titleTextViewId?.let { tvTitleId -> - dialogView.findViewById(tvTitleId) - } + val tvTitle: TextView? = + cpDialogConfig.dialogViewIds.titleTextViewId?.let { tvTitleId -> + dialogView.findViewById(tvTitleId) + } val btnClearSelection: Button? = cpDialogConfig.dialogViewIds.clearSelectionButtonId?.let { btnClearSelectionId -> dialogView.findViewById(btnClearSelectionId) @@ -84,7 +85,7 @@ class CPDialogHelper( cpDataStore, cpRowConfig, cpListConfig, - etQuery + etQuery, ) { selectedCountry -> onCountryClickListener(selectedCountry) dialog.dismiss() @@ -99,7 +100,7 @@ class CPDialogHelper( if (cpDialogConfig.showFullScreen) { dialog.window?.setLayout( WindowManager.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.MATCH_PARENT + WindowManager.LayoutParams.MATCH_PARENT, ) } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/flagprovider/CPFlagProvider.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/flagprovider/CPFlagProvider.kt index fd9b2ad..746a9f1 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/flagprovider/CPFlagProvider.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/flagprovider/CPFlagProvider.kt @@ -20,7 +20,7 @@ class DefaultEmojiFlagProvider(val useEmojiCompat: Boolean = false) : CPFlagProv */ class CPFlagImageProvider( alpha2ToFlag: Map, - @DrawableRes val missingFlagPlaceHolder: Int + @DrawableRes val missingFlagPlaceHolder: Int, ) : CPFlagProvider() { private val flagMap = alpha2ToFlag.map { it.key.uppercase(Locale.ENGLISH) to it.value }.toMap() @@ -29,7 +29,7 @@ class CPFlagImageProvider( val upperCaseAlpha2Code = alpha2Code.uppercase(Locale.ENGLISH) val flag = flagMap[upperCaseAlpha2Code] return flag ?: flagMap.getOrElse( - getNormalizedAlpha2ForFlag(upperCaseAlpha2Code) + getNormalizedAlpha2ForFlag(upperCaseAlpha2Code), ) { missingFlagPlaceHolder } } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/helper/CPCountryDetector.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/helper/CPCountryDetector.kt index 20e0f3b..275a2f8 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/helper/CPCountryDetector.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/helper/CPCountryDetector.kt @@ -5,20 +5,21 @@ import android.os.Build import android.telephony.TelephonyManager class CPCountryDetector(val context: Context) { - fun detectCountry( - sources: List = listOf( - Source.SIM, - Source.NETWORK, - Source.LOCALE - ) + sources: List = + listOf( + Source.SIM, + Source.NETWORK, + Source.LOCALE, + ), ): String? { sources.forEach { - val detectedCountry = when (it) { - Source.SIM -> detectSIMCountry() - Source.NETWORK -> detectNetworkCountry() - Source.LOCALE -> detectLocaleCountry() - } + val detectedCountry = + when (it) { + Source.SIM -> detectSIMCountry() + Source.NETWORK -> detectNetworkCountry() + Source.LOCALE -> detectLocaleCountry() + } if (detectedCountry != null) return detectedCountry } return null @@ -61,7 +62,9 @@ class CPCountryDetector(val context: Context) { sealed class Source(val name: String) { object SIM : Source("Sim") + object NETWORK : Source("Network") + object LOCALE : Source("Locale") } } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/helper/CountryPickerDialogAttrReader.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/helper/CountryPickerDialogAttrReader.kt index 3bdb54b..5fffce0 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/helper/CountryPickerDialogAttrReader.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/helper/CountryPickerDialogAttrReader.kt @@ -3,41 +3,41 @@ package com.hbb20.countrypicker.helper import android.content.res.TypedArray import com.hbb20.countrypicker.R.styleable.* import com.hbb20.countrypicker.config.CPDialogConfig -import com.hbb20.countrypicker.config.CPDialogConfig.Companion.defaultCPDialogAllowClearSelection -import com.hbb20.countrypicker.config.CPDialogConfig.Companion.defaultCPDialogAllowSearch -import com.hbb20.countrypicker.config.CPDialogConfig.Companion.defaultCPDialogDefaultShowTitle -import com.hbb20.countrypicker.config.CPDialogConfig.Companion.defaultCPDialogShowFullScreen +import com.hbb20.countrypicker.config.CPDialogConfig.Companion.DEFAULT_CP_DIALOG_ALLOW_CLEAR_SELECTION +import com.hbb20.countrypicker.config.CPDialogConfig.Companion.DEFAULT_CP_DIALOG_ALLOW_SEARCH +import com.hbb20.countrypicker.config.CPDialogConfig.Companion.DEFAULT_CP_DIALOG_SHOW_FULL_SCREEN +import com.hbb20.countrypicker.config.CPDialogConfig.Companion.DEFAULT_CP_DIALOG_SHOW_TITLE internal fun readDialogConfigFromAttrs(attrs: TypedArray?): CPDialogConfig { return if (attrs == null) { CPDialogConfig() } else { val allowSearch = - attrs.getBoolean(CountryPickerView_cpDialog_allowSearch, defaultCPDialogAllowSearch) + attrs.getBoolean(CountryPickerView_cpDialog_allowSearch, DEFAULT_CP_DIALOG_ALLOW_SEARCH) val allowClearSelection = attrs.getBoolean( CountryPickerView_cpDialog_allowClearSelection, - defaultCPDialogAllowClearSelection + DEFAULT_CP_DIALOG_ALLOW_CLEAR_SELECTION, ) val showTitle = attrs.getBoolean( CountryPickerView_cpDialog_showTitle, - defaultCPDialogDefaultShowTitle + DEFAULT_CP_DIALOG_SHOW_TITLE, ) val showFullScreen = attrs.getBoolean( CountryPickerView_cpDialog_showFullScreen, - defaultCPDialogShowFullScreen + DEFAULT_CP_DIALOG_SHOW_FULL_SCREEN, ) CPDialogConfig( allowSearch = allowSearch, allowClearSelection = allowClearSelection, showTitle = showTitle, - showFullScreen = showFullScreen + showFullScreen = showFullScreen, ) } } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/helper/CountryPickerListAttrReader.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/helper/CountryPickerListAttrReader.kt index 379f482..95c299d 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/helper/CountryPickerListAttrReader.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/helper/CountryPickerListAttrReader.kt @@ -12,7 +12,7 @@ internal fun readListConfigFromAttrs(attrs: TypedArray?): CPListConfig { attrs.getString(CountryPickerView_cpList_preferredCountryCodes) CPListConfig( - preferredCountryCodes = preferredCountryCodes + preferredCountryCodes = preferredCountryCodes, ) } } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/logger/CPLogger.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/logger/CPLogger.kt index 34d8443..0a78089 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/logger/CPLogger.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/logger/CPLogger.kt @@ -4,7 +4,6 @@ import android.util.Log import com.hbb20.countrypicker.models.CP_TAG object CPLogger { - fun d(message: String) { Log.d(CP_TAG, message) } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/models/Alpha2Collection.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/models/Alpha2Collection.kt new file mode 100644 index 0000000..58d0c9c --- /dev/null +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/models/Alpha2Collection.kt @@ -0,0 +1,3 @@ +package com.hbb20.countrypicker.models + +val allCountryAlpha2List = countryInfoList.map { it.alpha2 } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPCountry.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPCountry.kt index a51c998..2efc85c 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPCountry.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPCountry.kt @@ -18,13 +18,12 @@ data class CPCountry( var cctld: String, var flagEmoji: String, var phoneCode: Short, - var name: String + var name: String, ) : Comparable { - companion object { internal fun from( countryInfo: CountryInfo, - translatedName: String? + translatedName: String?, ): CPCountry { countryInfo.apply { return CPCountry( @@ -41,7 +40,7 @@ data class CPCountry( cctld, flagEmoji, phoneCode, - translatedName ?: englishName + translatedName ?: englishName, ) } } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPDataStore.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPDataStore.kt index 296ad3e..8b66c4d 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPDataStore.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPDataStore.kt @@ -2,13 +2,13 @@ package com.hbb20.countrypicker.models data class CPDataStore( var countryList: MutableList, - val messageGroup: MessageGroup + val messageGroup: MessageGroup, ) { data class MessageGroup( var noMatchMsg: String = "No matching result found", var searchHint: String = "Search...", var dialogTitle: String = "Select a country", var selectionPlaceholderText: String = "Country", - var clearSelectionText: String = "Clear Selection" + var clearSelectionText: String = "Clear Selection", ) } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPLanguage.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPLanguage.kt index a2ab75c..b0e2a86 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPLanguage.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/models/CPLanguage.kt @@ -5,7 +5,7 @@ import java.util.* enum class CPLanguage( val code: String, val country: String? = null, - val script: String? = null + val script: String? = null, ) { AFRIKAANS("af"), ARABIC("ar"), @@ -38,7 +38,8 @@ enum class CPLanguage( UKRAINIAN("uk"), URDU("ur"), UZBEK("uz"), - VIETNAMESE("vi"); + VIETNAMESE("vi"), + ; val translationFileName: String by lazy { "cp_${name.lowercase(Locale.ROOT)}.xml" } } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/models/Constants.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/models/Constants.kt index 48c7605..89b9679 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/models/Constants.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/models/Constants.kt @@ -1,28 +1,3 @@ package com.hbb20.countrypicker.models internal const val CP_TAG = "CountryPicker" -const val xmlAlpha2Key = "a2" -const val xmlAlpha3Key = "a3" -const val xmlEnglishNameKey = "eName" -const val xmlPhoneCodeKey = "pCode" -const val xmlFlagEmojiKey = "emoji" -const val xmlCountryKey = "country" -const val xmlTranslationKey = "translation" -const val xmlVerifiedKey = "verified" -const val xmlVerifiedYESValue = "Y" -const val xmlVerifiedNOValue = "N" -const val xmlBaseListFileName = "cp_a_base_country_list.xml" -const val xmlNewLanguageTemplateFileName = "a_new_lang_template.xml" -const val xmlDialogNoResultAckMessageKey = "dialog_no_result_ack_message" -const val xmlDialogSearchHintMessageKey = "dialog_search_hint_message" -const val xmlDialogTitleKey = "dialog_title" -const val xmlEmptySelectionTextKey = "empty_selection_message" -const val xmlTodoTag = "__TODO__" -const val xmlMessageListKey = "a_message_list" -const val xmlDataKey = "data" -const val xmlCountriesKey = "countries" -const val xmlLanguageFileName = "CPLanguage.kt" - -const val CP_COUNTRY_INFO_CSV = "cp_country_info" -const val CP_COUNTRY_TRANSLATION_CSV = "cp_country_translation" -const val CP_MESSAGE_TRANSLATION_CSV = "cp_message_translation" diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/models/CountryInfo.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/models/CountryInfo.kt index e95d97e..e8820af 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/models/CountryInfo.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/models/CountryInfo.kt @@ -13,5 +13,5 @@ internal data class CountryInfo( val currencySymbol: String, val cctld: String, val flagEmoji: String, - val phoneCode: Short + val phoneCode: Short, ) diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/models/MasterInfoList.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/models/MasterInfoList.kt index fcba32b..bb04205 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/models/MasterInfoList.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/models/MasterInfoList.kt @@ -1,3755 +1,3755 @@ package com.hbb20.countrypicker.models -internal val countryInfoList = listOf( - - CountryInfo( - alpha2 = "AD", - alpha3 = "AND", - englishName = "Andorra", - demonym = "Andorrans", - capitalEnglishName = "Andorra la Vella", - areaKM2 = "468", - population = 77265, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "ad", - flagEmoji = "🇦🇩", - phoneCode = 376 - ), - CountryInfo( - alpha2 = "AE", - alpha3 = "ARE", - englishName = "United Arab Emirates", - demonym = "Emirians", - capitalEnglishName = "Abu Dhabi", - areaKM2 = "83600", - population = 9890402, - currencyCode = "AED", - currencyName = "United Arab Emirates Dirham", - currencySymbol = "د.إ", - cctld = "ae", - flagEmoji = "🇦🇪", - phoneCode = 971 - ), - CountryInfo( - alpha2 = "AF", - alpha3 = "AFG", - englishName = "Afghanistan", - demonym = "Afghans", - capitalEnglishName = "Kabul", - areaKM2 = "652230", - population = 38928346, - currencyCode = "AFN", - currencyName = "Afghan Afghani", - currencySymbol = "؋", - cctld = "af", - flagEmoji = "🇦🇫", - phoneCode = 93 - ), - CountryInfo( - alpha2 = "AG", - alpha3 = "ATG", - englishName = "Antigua and Barbuda", - demonym = "Antiguans or Barbudans", - capitalEnglishName = "Saint John's", - areaKM2 = "442", - population = 97929, - currencyCode = "XCD", - currencyName = "East Caribbean Dollar", - currencySymbol = "$", - cctld = "ag", - flagEmoji = "🇦🇬", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "AI", - alpha3 = "AIA", - englishName = "Anguilla", - demonym = "Anguillans", - capitalEnglishName = "The Valley", - areaKM2 = "91", - population = 15003, - currencyCode = "XCD", - currencyName = "East Caribbean Dollar", - currencySymbol = "$", - cctld = "ai", - flagEmoji = "🇦🇮", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "AL", - alpha3 = "ALB", - englishName = "Albania", - demonym = "Albanians", - capitalEnglishName = "Tirana", - areaKM2 = "28748", - population = 2877797, - currencyCode = "ALL", - currencyName = "Albanian Lek", - currencySymbol = "L", - cctld = "al", - flagEmoji = "🇦🇱", - phoneCode = 355 - ), - CountryInfo( - alpha2 = "AM", - alpha3 = "ARM", - englishName = "Armenia", - demonym = "Armenians", - capitalEnglishName = "Yerevan", - areaKM2 = "29743", - population = 2963243, - currencyCode = "AMD", - currencyName = "Armenian Dram", - currencySymbol = "֏", - cctld = "am", - flagEmoji = "🇦🇲", - phoneCode = 374 - ), - CountryInfo( - alpha2 = "AO", - alpha3 = "AGO", - englishName = "Angola", - demonym = "Angolans", - capitalEnglishName = "Luanda", - areaKM2 = "1246700", - population = 32866272, - currencyCode = "AOA", - currencyName = "Angolan Kwanza", - currencySymbol = "Kz", - cctld = "ao", - flagEmoji = "🇦🇴", - phoneCode = 244 - ), - CountryInfo( - alpha2 = "AQ", - alpha3 = "ATA", - englishName = "Antarctica", - demonym = "Antarctic residents", - capitalEnglishName = "-", - areaKM2 = "14000000", - population = 0, - currencyCode = "", - currencyName = "", - currencySymbol = "", - cctld = "aq", - flagEmoji = "🇦🇶", - phoneCode = 672 - ), - CountryInfo( - alpha2 = "AR", - alpha3 = "ARG", - englishName = "Argentina", - demonym = "Argentines", - capitalEnglishName = "Buenos Aires", - areaKM2 = "2780400", - population = 45195774, - currencyCode = "ARS", - currencyName = "Argentine Peso", - currencySymbol = "$", - cctld = "ar", - flagEmoji = "🇦🇷", - phoneCode = 54 - ), - CountryInfo( - alpha2 = "AS", - alpha3 = "ASM", - englishName = "American Samoa", - demonym = "American Samoans", - capitalEnglishName = "Pago Pago", - areaKM2 = "199", - population = 55191, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "as", - flagEmoji = "🇦🇸", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "AT", - alpha3 = "AUT", - englishName = "Austria", - demonym = "Austrians", - capitalEnglishName = "Vienna", - areaKM2 = "83871", - population = 9006398, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "at", - flagEmoji = "🇦🇹", - phoneCode = 43 - ), - CountryInfo( - alpha2 = "AU", - alpha3 = "AUS", - englishName = "Australia", - demonym = "Australians", - capitalEnglishName = "Canberra", - areaKM2 = "7741220", - population = 25499884, - currencyCode = "AUD", - currencyName = "Australian Dollar", - currencySymbol = "$", - cctld = "au", - flagEmoji = "🇦🇺", - phoneCode = 61 - ), - CountryInfo( - alpha2 = "AW", - alpha3 = "ABW", - englishName = "Aruba", - demonym = "Arubans", - capitalEnglishName = "Oranjestad", - areaKM2 = "180", - population = 106766, - currencyCode = "AWG", - currencyName = "Aruban Florin", - currencySymbol = "Afl", - cctld = "aw", - flagEmoji = "🇦🇼", - phoneCode = 297 - ), - CountryInfo( - alpha2 = "AX", - alpha3 = "ALA", - englishName = "Aland Islands", - demonym = "Aland Islanders", - capitalEnglishName = "Mariehamn", - areaKM2 = "1552", - population = 30144, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "ax", - flagEmoji = "🇦🇽", - phoneCode = 358 - ), - CountryInfo( - alpha2 = "AZ", - alpha3 = "AZE", - englishName = "Azerbaijan", - demonym = "Azerbaijanis", - capitalEnglishName = "Baku", - areaKM2 = "86600", - population = 10139177, - currencyCode = "AZN", - currencyName = "Azerbaijani Manat", - currencySymbol = "₼", - cctld = "az", - flagEmoji = "🇦🇿", - phoneCode = 994 - ), - CountryInfo( - alpha2 = "BA", - alpha3 = "BIH", - englishName = "Bosnia and Herzegovina", - demonym = "Bosnians or Herzegovinians", - capitalEnglishName = "Sarajevo", - areaKM2 = "51197", - population = 3280819, - currencyCode = "BAM", - currencyName = "Bosnia And Herzegovina Convertible Mark", - currencySymbol = "KM", - cctld = "ba", - flagEmoji = "🇧🇦", - phoneCode = 387 - ), - CountryInfo( - alpha2 = "BB", - alpha3 = "BRB", - englishName = "Barbados", - demonym = "Barbadians", - capitalEnglishName = "Bridgetown", - areaKM2 = "430", - population = 287375, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "bb", - flagEmoji = "🇧🇧", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "BD", - alpha3 = "BGD", - englishName = "Bangladesh", - demonym = "Bangladeshis", - capitalEnglishName = "Dhaka", - areaKM2 = "143998", - population = 164689383, - currencyCode = "BDT", - currencyName = "Bangladeshi Taka", - currencySymbol = "৳", - cctld = "bd", - flagEmoji = "🇧🇩", - phoneCode = 880 - ), - CountryInfo( - alpha2 = "BE", - alpha3 = "BEL", - englishName = "Belgium", - demonym = "Belgians", - capitalEnglishName = "Brussels", - areaKM2 = "30528", - population = 11589623, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "be", - flagEmoji = "🇧🇪", - phoneCode = 32 - ), - CountryInfo( - alpha2 = "BF", - alpha3 = "BFA", - englishName = "Burkina Faso", - demonym = "Burkinabe", - capitalEnglishName = "Ouagadougou", - areaKM2 = "274200", - population = 20903273, - currencyCode = "XOF", - currencyName = "Cfa Franc Bceao", - currencySymbol = "CFA", - cctld = "bf", - flagEmoji = "🇧🇫", - phoneCode = 226 - ), - CountryInfo( - alpha2 = "BG", - alpha3 = "BGR", - englishName = "Bulgaria", - demonym = "Bulgarians", - capitalEnglishName = "Sofia", - areaKM2 = "110879", - population = 6948445, - currencyCode = "BGN", - currencyName = "Bulgarian Lev", - currencySymbol = "лв", - cctld = "bg", - flagEmoji = "🇧🇬", - phoneCode = 359 - ), - CountryInfo( - alpha2 = "BH", - alpha3 = "BHR", - englishName = "Bahrain", - demonym = "Bahrainis", - capitalEnglishName = "Manama", - areaKM2 = "760", - population = 1701575, - currencyCode = "BHD", - currencyName = "Bahraini Dinar", - currencySymbol = "BD", - cctld = "bh", - flagEmoji = "🇧🇭", - phoneCode = 973 - ), - CountryInfo( - alpha2 = "BI", - alpha3 = "BDI", - englishName = "Burundi", - demonym = "Burundians", - capitalEnglishName = "Bujumbura", - areaKM2 = "27830", - population = 11890784, - currencyCode = "BIF", - currencyName = "Burundian Franc", - currencySymbol = "FBu", - cctld = "bi", - flagEmoji = "🇧🇮", - phoneCode = 257 - ), - CountryInfo( - alpha2 = "BJ", - alpha3 = "BEN", - englishName = "Benin", - demonym = "Beninese", - capitalEnglishName = "Porto-Novo", - areaKM2 = "112622", - population = 12123200, - currencyCode = "XOF", - currencyName = "Cfa Franc Bceao", - currencySymbol = "CFA", - cctld = "bj", - flagEmoji = "🇧🇯", - phoneCode = 229 - ), - CountryInfo( - alpha2 = "BL", - alpha3 = "BLM", - englishName = "Saint Barthelemy", - demonym = "Barthelemois", - capitalEnglishName = "Gustavia", - areaKM2 = "21", - population = 9877, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "gp", - flagEmoji = "🇧🇱", - phoneCode = 590 - ), - CountryInfo( - alpha2 = "BM", - alpha3 = "BMU", - englishName = "Bermuda", - demonym = "Bermudians", - capitalEnglishName = "Hamilton", - areaKM2 = "54", - population = 62278, - currencyCode = "BMD", - currencyName = "Bermudian Dollar", - currencySymbol = "$", - cctld = "bm", - flagEmoji = "🇧🇲", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "BN", - alpha3 = "BRN", - englishName = "Brunei Darussalam", - demonym = "Bruneians", - capitalEnglishName = "Bandar Seri Begawan", - areaKM2 = "5765", - population = 437479, - currencyCode = "SGD", - currencyName = "Brunei Dollar", - currencySymbol = "$", - cctld = "bn", - flagEmoji = "🇧🇳", - phoneCode = 673 - ), - CountryInfo( - alpha2 = "BO", - alpha3 = "BOL", - englishName = "Bolivia (Plurinational State of)", - demonym = "Bolivians", - capitalEnglishName = "Sucre", - areaKM2 = "1098581", - population = 11673021, - currencyCode = "BOB", - currencyName = "Boliviano", - currencySymbol = "Bs", - cctld = "bo", - flagEmoji = "🇧🇴", - phoneCode = 591 - ), - CountryInfo( - alpha2 = "BQ", - alpha3 = "BES", - englishName = "Bonaire, Sint Eustatius and Saba", - demonym = "Bonaire Dutch", - capitalEnglishName = "Kralendijk", - areaKM2 = "328", - population = 26223, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "bq", - flagEmoji = "🇧🇶", - phoneCode = 599 - ), - CountryInfo( - alpha2 = "BR", - alpha3 = "BRA", - englishName = "Brazil", - demonym = "Brazilians", - capitalEnglishName = "Brasilia", - areaKM2 = "8514877", - population = 212559417, - currencyCode = "BRL", - currencyName = "Brazilian Real", - currencySymbol = "Cz$", - cctld = "br", - flagEmoji = "🇧🇷", - phoneCode = 55 - ), - CountryInfo( - alpha2 = "BS", - alpha3 = "BHS", - englishName = "Bahamas", - demonym = "Bahamians", - capitalEnglishName = "Nassau", - areaKM2 = "13880", - population = 393244, - currencyCode = "BSD", - currencyName = "Bahamian Dollar", - currencySymbol = "$", - cctld = "bs", - flagEmoji = "🇧🇸", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "BT", - alpha3 = "BTN", - englishName = "Bhutan", - demonym = "Bhutanese", - capitalEnglishName = "Thimphu", - areaKM2 = "38394", - population = 771608, - currencyCode = "BTN", - currencyName = "Bhutanese Ngultrum", - currencySymbol = "Nu.", - cctld = "bt", - flagEmoji = "🇧🇹", - phoneCode = 975 - ), - CountryInfo( - alpha2 = "BV", - alpha3 = "BVT", - englishName = "Bouvet Island", - demonym = "Bouvet Islanders", - capitalEnglishName = "-", - areaKM2 = "49", - population = 0, - currencyCode = "NOK", - currencyName = "Norwegian Kroner", - currencySymbol = "kr", - cctld = "bv", - flagEmoji = "🇧🇻", - phoneCode = 47 - ), - CountryInfo( - alpha2 = "BW", - alpha3 = "BWA", - englishName = "Botswana", - demonym = "Motswana", - capitalEnglishName = "Gaborone", - areaKM2 = "581730", - population = 2351627, - currencyCode = "BWP", - currencyName = "Botswana Pula", - currencySymbol = "P", - cctld = "bw", - flagEmoji = "🇧🇼", - phoneCode = 267 - ), - CountryInfo( - alpha2 = "BY", - alpha3 = "BLR", - englishName = "Belarus", - demonym = "Belarusians", - capitalEnglishName = "Minsk", - areaKM2 = "207600", - population = 9449323, - currencyCode = "BYR", - currencyName = "Belarusian Ruble", - currencySymbol = "Br", - cctld = "by", - flagEmoji = "🇧🇾", - phoneCode = 375 - ), - CountryInfo( - alpha2 = "BZ", - alpha3 = "BLZ", - englishName = "Belize", - demonym = "Belizeans", - capitalEnglishName = "Belmopan", - areaKM2 = "22966", - population = 397628, - currencyCode = "BZD", - currencyName = "Belize Dollar", - currencySymbol = "$", - cctld = "bz", - flagEmoji = "🇧🇿", - phoneCode = 501 - ), - CountryInfo( - alpha2 = "CA", - alpha3 = "CAN", - englishName = "Canada", - demonym = "Canadians", - capitalEnglishName = "Ottawa", - areaKM2 = "9984670", - population = 37742154, - currencyCode = "CAD", - currencyName = "Canadian Dollar", - currencySymbol = "$", - cctld = "ca", - flagEmoji = "🇨🇦", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "CC", - alpha3 = "CCK", - englishName = "Cocos (Keeling) Islands", - demonym = "Cocos Islanders", - capitalEnglishName = "West Island", - areaKM2 = "14", - population = 555, - currencyCode = "AUD", - currencyName = "Australian Dollar", - currencySymbol = "$", - cctld = "cc", - flagEmoji = "🇨🇨", - phoneCode = 61 - ), - CountryInfo( - alpha2 = "CD", - alpha3 = "COD", - englishName = "Congo (Democratic Republic of the)", - demonym = "Congolese", - capitalEnglishName = "Kinshasa", - areaKM2 = "2344858", - population = 89561403, - currencyCode = "CDF", - currencyName = "Congolese Franc", - currencySymbol = "FCFA", - cctld = "cd", - flagEmoji = "🇨🇩", - phoneCode = 243 - ), - CountryInfo( - alpha2 = "CF", - alpha3 = "CAF", - englishName = "Central African Republic", - demonym = "Central Africans", - capitalEnglishName = "Bangui", - areaKM2 = "622984", - population = 4829767, - currencyCode = "XAF", - currencyName = "Cfa Franc Beac", - currencySymbol = "FCFA", - cctld = "cf", - flagEmoji = "🇨🇫", - phoneCode = 236 - ), - CountryInfo( - alpha2 = "CG", - alpha3 = "COG", - englishName = "Congo", - demonym = "Congolese", - capitalEnglishName = "Brazzaville", - areaKM2 = "342000", - population = 5518087, - currencyCode = "XAF", - currencyName = "Cfa Franc Beac", - currencySymbol = "FCFA", - cctld = "cg", - flagEmoji = "🇨🇬", - phoneCode = 242 - ), - CountryInfo( - alpha2 = "CH", - alpha3 = "CHE", - englishName = "Switzerland", - demonym = "Swiss", - capitalEnglishName = "Bern", - areaKM2 = "41277", - population = 8654622, - currencyCode = "CHF", - currencyName = "Swiss Franc", - currencySymbol = "Fr.", - cctld = "ch", - flagEmoji = "🇨🇭", - phoneCode = 41 - ), - CountryInfo( - alpha2 = "CI", - alpha3 = "CIV", - englishName = "Cote d'Ivoire", - demonym = "Ivorians", - capitalEnglishName = "Yamoussoukro", - areaKM2 = "322463", - population = 26378274, - currencyCode = "XOF", - currencyName = "Cfa Franc Bceao", - currencySymbol = "CFA", - cctld = "ci", - flagEmoji = "🇨🇮", - phoneCode = 225 - ), - CountryInfo( - alpha2 = "CK", - alpha3 = "COK", - englishName = "Cook Islands", - demonym = "Cook Islanders", - capitalEnglishName = "Avarua", - areaKM2 = "236", - population = 17564, - currencyCode = "NZD", - currencyName = "New Zealand Dollar", - currencySymbol = "$", - cctld = "ck", - flagEmoji = "🇨🇰", - phoneCode = 682 - ), - CountryInfo( - alpha2 = "CL", - alpha3 = "CHL", - englishName = "Chile", - demonym = "Chileans", - capitalEnglishName = "Santiago", - areaKM2 = "756102", - population = 19116201, - currencyCode = "CLP", - currencyName = "Chilean Peso", - currencySymbol = "$", - cctld = "cl", - flagEmoji = "🇨🇱", - phoneCode = 56 - ), - CountryInfo( - alpha2 = "CM", - alpha3 = "CMR", - englishName = "Cameroon", - demonym = "Cameroonians", - capitalEnglishName = "Yaounde", - areaKM2 = "475440", - population = 26545863, - currencyCode = "XAF", - currencyName = "Cfa Franc Beac", - currencySymbol = "FCFA", - cctld = "cm", - flagEmoji = "🇨🇲", - phoneCode = 237 - ), - CountryInfo( - alpha2 = "CN", - alpha3 = "CHN", - englishName = "China", - demonym = "Chinese", - capitalEnglishName = "Beijing", - areaKM2 = "9596961", - population = 1439323776, - currencyCode = "CNY", - currencyName = "Chinese Yuan Renminbi", - currencySymbol = "¥", - cctld = "cn", - flagEmoji = "🇨🇳", - phoneCode = 86 - ), - CountryInfo( - alpha2 = "CO", - alpha3 = "COL", - englishName = "Colombia", - demonym = "Colombians", - capitalEnglishName = "Bogota", - areaKM2 = "1138910", - population = 50882891, - currencyCode = "COP", - currencyName = "Colombian Peso", - currencySymbol = "$", - cctld = "co", - flagEmoji = "🇨🇴", - phoneCode = 57 - ), - CountryInfo( - alpha2 = "CR", - alpha3 = "CRI", - englishName = "Costa Rica", - demonym = "Costa Ricans", - capitalEnglishName = "San Jose", - areaKM2 = "51100", - population = 5094118, - currencyCode = "CRC", - currencyName = "Costa Rican Colon", - currencySymbol = "₡", - cctld = "cr", - flagEmoji = "🇨🇷", - phoneCode = 506 - ), - CountryInfo( - alpha2 = "CU", - alpha3 = "CUB", - englishName = "Cuba", - demonym = "Cubans", - capitalEnglishName = "Havana", - areaKM2 = "110860", - population = 11326616, - currencyCode = "CUC", - currencyName = "Cuban Convertible Peso", - currencySymbol = "$", - cctld = "cu", - flagEmoji = "🇨🇺", - phoneCode = 53 - ), - CountryInfo( - alpha2 = "CV", - alpha3 = "CPV", - englishName = "Cabo Verde", - demonym = "Cabo Verdeans", - capitalEnglishName = "Praia", - areaKM2 = "4033", - population = 555987, - currencyCode = "CVE", - currencyName = "Cape Verde Escudo", - currencySymbol = "$", - cctld = "cv", - flagEmoji = "🇨🇻", - phoneCode = 238 - ), - CountryInfo( - alpha2 = "CW", - alpha3 = "CUW", - englishName = "Curaçao", - demonym = "Curacaoans", - capitalEnglishName = "Willemstad", - areaKM2 = "444", - population = 164093, - currencyCode = "ANG", - currencyName = "Nl Antillian Guilder", - currencySymbol = "ƒ", - cctld = "cw", - flagEmoji = "🇨🇼", - phoneCode = 599 - ), - CountryInfo( - alpha2 = "CX", - alpha3 = "CXR", - englishName = "Christmas Island", - demonym = "Christmas Islanders", - capitalEnglishName = "Flying Fish Cove", - areaKM2 = "135", - population = 1955, - currencyCode = "AUD", - currencyName = "Australian Dollar", - currencySymbol = "$", - cctld = "cx", - flagEmoji = "🇨🇽", - phoneCode = 61 - ), - CountryInfo( - alpha2 = "CY", - alpha3 = "CYP", - englishName = "Cyprus", - demonym = "Cypriots", - capitalEnglishName = "Nicosia", - areaKM2 = "9251", - population = 1207359, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "cy", - flagEmoji = "🇨🇾", - phoneCode = 357 - ), - CountryInfo( - alpha2 = "CZ", - alpha3 = "CZE", - englishName = "Czechia", - demonym = "Czechs", - capitalEnglishName = "Prague", - areaKM2 = "78867", - population = 10708981, - currencyCode = "CZK", - currencyName = "Czech Koruna", - currencySymbol = "Kč", - cctld = "cz", - flagEmoji = "🇨🇿", - phoneCode = 420 - ), - CountryInfo( - alpha2 = "DE", - alpha3 = "DEU", - englishName = "Germany", - demonym = "Germans", - capitalEnglishName = "Berlin", - areaKM2 = "357022", - population = 83783942, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "de", - flagEmoji = "🇩🇪", - phoneCode = 49 - ), - CountryInfo( - alpha2 = "DJ", - alpha3 = "DJI", - englishName = "Djibouti", - demonym = "Djiboutians", - capitalEnglishName = "Djibouti", - areaKM2 = "23200", - population = 988000, - currencyCode = "DJF", - currencyName = "Djiboutian Franc", - currencySymbol = "Fdj", - cctld = "dj", - flagEmoji = "🇩🇯", - phoneCode = 253 - ), - CountryInfo( - alpha2 = "DK", - alpha3 = "DNK", - englishName = "Denmark", - demonym = "Danes", - capitalEnglishName = "Copenhagen", - areaKM2 = "43094", - population = 5792202, - currencyCode = "DKK", - currencyName = "Danish Krone", - currencySymbol = "kr.", - cctld = "dk", - flagEmoji = "🇩🇰", - phoneCode = 45 - ), - CountryInfo( - alpha2 = "DM", - alpha3 = "DMA", - englishName = "Dominica", - demonym = "Dominicans", - capitalEnglishName = "Roseau", - areaKM2 = "751", - population = 71986, - currencyCode = "XCD", - currencyName = "East Caribbean Dollar", - currencySymbol = "$", - cctld = "dm", - flagEmoji = "🇩🇲", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "DO", - alpha3 = "DOM", - englishName = "Dominican Republic", - demonym = "Dominicans", - capitalEnglishName = "Santo Domingo", - areaKM2 = "48670", - population = 10847910, - currencyCode = "DOP", - currencyName = "Dominican Peso", - currencySymbol = "$", - cctld = "do", - flagEmoji = "🇩🇴", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "DZ", - alpha3 = "DZA", - englishName = "Algeria", - demonym = "Algerians", - capitalEnglishName = "Algiers", - areaKM2 = "2381741", - population = 43851044, - currencyCode = "DZD", - currencyName = "Algerian Dinar", - currencySymbol = "DA", - cctld = "dz", - flagEmoji = "🇩🇿", - phoneCode = 213 - ), - CountryInfo( - alpha2 = "EC", - alpha3 = "ECU", - englishName = "Ecuador", - demonym = "Ecuadorians", - capitalEnglishName = "Quito", - areaKM2 = "283561", - population = 17643054, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "ec", - flagEmoji = "🇪🇨", - phoneCode = 593 - ), - CountryInfo( - alpha2 = "EE", - alpha3 = "EST", - englishName = "Estonia", - demonym = "Estonians", - capitalEnglishName = "Tallinn", - areaKM2 = "45228", - population = 1326535, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "ee", - flagEmoji = "🇪🇪", - phoneCode = 372 - ), - CountryInfo( - alpha2 = "EG", - alpha3 = "EGY", - englishName = "Egypt", - demonym = "Egyptians", - capitalEnglishName = "Cairo", - areaKM2 = "1001450", - population = 102334404, - currencyCode = "EGP", - currencyName = "Egyptian Pound", - currencySymbol = "E£", - cctld = "eg", - flagEmoji = "🇪🇬", - phoneCode = 20 - ), - CountryInfo( - alpha2 = "EH", - alpha3 = "ESH", - englishName = "Western Sahara", - demonym = "Sahrawis", - capitalEnglishName = "Laayoune / El Aaiun", - areaKM2 = "266000", - population = 597339, - currencyCode = "MAD", - currencyName = "Moroccan Dirham", - currencySymbol = "DH", - cctld = "eh", - flagEmoji = "🇪🇭", - phoneCode = 212 - ), - CountryInfo( - alpha2 = "ER", - alpha3 = "ERI", - englishName = "Eritrea", - demonym = "Eritreans", - capitalEnglishName = "Asmara", - areaKM2 = "117600", - population = 3546421, - currencyCode = "ERN", - currencyName = "Eritrean Nakfa", - currencySymbol = "Nkf", - cctld = "er", - flagEmoji = "🇪🇷", - phoneCode = 291 - ), - CountryInfo( - alpha2 = "ES", - alpha3 = "ESP", - englishName = "Spain", - demonym = "Spaniards", - capitalEnglishName = "Madrid", - areaKM2 = "505370", - population = 46754778, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "es", - flagEmoji = "🇪🇸", - phoneCode = 34 - ), - CountryInfo( - alpha2 = "ET", - alpha3 = "ETH", - englishName = "Ethiopia", - demonym = "Ethiopians", - capitalEnglishName = "Addis Ababa", - areaKM2 = "1104300", - population = 114963588, - currencyCode = "ETB", - currencyName = "Ethiopian Birr", - currencySymbol = "Br", - cctld = "et", - flagEmoji = "🇪🇹", - phoneCode = 251 - ), - CountryInfo( - alpha2 = "FI", - alpha3 = "FIN", - englishName = "Finland", - demonym = "Finns", - capitalEnglishName = "Helsinki", - areaKM2 = "338145", - population = 5540720, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "fi", - flagEmoji = "🇫🇮", - phoneCode = 358 - ), - CountryInfo( - alpha2 = "FJ", - alpha3 = "FJI", - englishName = "Fiji", - demonym = "Fijians", - capitalEnglishName = "Suva", - areaKM2 = "18274", - population = 896445, - currencyCode = "FJD", - currencyName = "Fijian Dollar", - currencySymbol = "$", - cctld = "fj", - flagEmoji = "🇫🇯", - phoneCode = 679 - ), - CountryInfo( - alpha2 = "FK", - alpha3 = "FLK", - englishName = "Falkland Islands (Malvinas)", - demonym = "Falkland Islanders", - capitalEnglishName = "Stanley", - areaKM2 = "12173", - population = 3480, - currencyCode = "FKP", - currencyName = "Falkland Islands Pound", - currencySymbol = "£", - cctld = "fk", - flagEmoji = "🇫🇰", - phoneCode = 500 - ), - CountryInfo( - alpha2 = "FM", - alpha3 = "FSM", - englishName = "Micronesia (Federated States of)", - demonym = "Micronesians", - capitalEnglishName = "Palikir", - areaKM2 = "702", - population = 548914, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "fm", - flagEmoji = "🇫🇲", - phoneCode = 691 - ), - CountryInfo( - alpha2 = "FO", - alpha3 = "FRO", - englishName = "Faroe Islands", - demonym = "Faroese", - capitalEnglishName = "Torshavn", - areaKM2 = "1393", - population = 48863, - currencyCode = "DKK", - currencyName = "Danish Krone", - currencySymbol = "kr", - cctld = "fo", - flagEmoji = "🇫🇴", - phoneCode = 298 - ), - CountryInfo( - alpha2 = "FR", - alpha3 = "FRA", - englishName = "France", - demonym = "French", - capitalEnglishName = "Paris", - areaKM2 = "643801", - population = 65273511, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "fr", - flagEmoji = "🇫🇷", - phoneCode = 33 - ), - CountryInfo( - alpha2 = "GA", - alpha3 = "GAB", - englishName = "Gabon", - demonym = "Gabonese", - capitalEnglishName = "Libreville", - areaKM2 = "267667", - population = 2225734, - currencyCode = "XAF", - currencyName = "Cfa Franc Beac", - currencySymbol = "FCFA", - cctld = "ga", - flagEmoji = "🇬🇦", - phoneCode = 241 - ), - CountryInfo( - alpha2 = "GB", - alpha3 = "GBR", - englishName = "United Kingdom of Great Britain and Northern Ireland", - demonym = "British", - capitalEnglishName = "London", - areaKM2 = "243610", - population = 67886011, - currencyCode = "GBP", - currencyName = "British Pound", - currencySymbol = "£", - cctld = "gb", - flagEmoji = "🇬🇧", - phoneCode = 44 - ), - CountryInfo( - alpha2 = "GD", - alpha3 = "GRD", - englishName = "Grenada", - demonym = "Grenadians", - capitalEnglishName = "Saint George's", - areaKM2 = "344", - population = 112523, - currencyCode = "XCD", - currencyName = "East Caribbean Dollar", - currencySymbol = "$", - cctld = "gd", - flagEmoji = "🇬🇩", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "GE", - alpha3 = "GEO", - englishName = "Georgia", - demonym = "Georgians", - capitalEnglishName = "Tbilisi", - areaKM2 = "69700", - population = 3989167, - currencyCode = "GEL", - currencyName = "Georgian Lari", - currencySymbol = "₾", - cctld = "ge", - flagEmoji = "🇬🇪", - phoneCode = 995 - ), - CountryInfo( - alpha2 = "GF", - alpha3 = "GUF", - englishName = "French Guiana", - demonym = "French Guianese", - capitalEnglishName = "Cayenne", - areaKM2 = "86504", - population = 298682, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "gf", - flagEmoji = "🇬🇫", - phoneCode = 594 - ), - CountryInfo( - alpha2 = "GG", - alpha3 = "GGY", - englishName = "Guernsey", - demonym = "Channel Islanders", - capitalEnglishName = "Saint Peter Port", - areaKM2 = "78", - population = 63155, - currencyCode = "GBP", - currencyName = "Pound Sterling", - currencySymbol = "£", - cctld = "gg", - flagEmoji = "🇬🇬", - phoneCode = 44 - ), - CountryInfo( - alpha2 = "GH", - alpha3 = "GHA", - englishName = "Ghana", - demonym = "Ghanaians", - capitalEnglishName = "Accra", - areaKM2 = "238533", - population = 31072940, - currencyCode = "GHS", - currencyName = "Ghanaian New Cedi", - currencySymbol = "GH₵", - cctld = "gh", - flagEmoji = "🇬🇭", - phoneCode = 233 - ), - CountryInfo( - alpha2 = "GI", - alpha3 = "GIB", - englishName = "Gibraltar", - demonym = "Gibraltarians", - capitalEnglishName = "Gibraltar", - areaKM2 = "6", - population = 33691, - currencyCode = "GIP", - currencyName = "Gibraltar Pound", - currencySymbol = "£", - cctld = "gi", - flagEmoji = "🇬🇮", - phoneCode = 350 - ), - CountryInfo( - alpha2 = "GL", - alpha3 = "GRL", - englishName = "Greenland", - demonym = "Greenlanders", - capitalEnglishName = "Nuuk", - areaKM2 = "2166086", - population = 56770, - currencyCode = "DKK", - currencyName = "Danish Krone", - currencySymbol = "kr.", - cctld = "gl", - flagEmoji = "🇬🇱", - phoneCode = 299 - ), - CountryInfo( - alpha2 = "GM", - alpha3 = "GMB", - englishName = "Gambia", - demonym = "Gambians", - capitalEnglishName = "Banjul", - areaKM2 = "11295", - population = 2416668, - currencyCode = "GMD", - currencyName = "Gambian Dalasi", - currencySymbol = "D", - cctld = "gm", - flagEmoji = "🇬🇲", - phoneCode = 220 - ), - CountryInfo( - alpha2 = "GN", - alpha3 = "GIN", - englishName = "Guinea", - demonym = "Guineans", - capitalEnglishName = "Conakry", - areaKM2 = "245857", - population = 13132795, - currencyCode = "GNF", - currencyName = "Guinean Franc", - currencySymbol = "FG", - cctld = "gn", - flagEmoji = "🇬🇳", - phoneCode = 224 - ), - CountryInfo( - alpha2 = "GP", - alpha3 = "GLP", - englishName = "Guadeloupe", - demonym = "Guadeloupians", - capitalEnglishName = "Basse-terre", - areaKM2 = "1630", - population = 400124, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "gp", - flagEmoji = "🇬🇵", - phoneCode = 590 - ), - CountryInfo( - alpha2 = "GQ", - alpha3 = "GNQ", - englishName = "Equatorial Guinea", - demonym = "Equatorial Guineans", - capitalEnglishName = "Malabo", - areaKM2 = "28051", - population = 1402985, - currencyCode = "XAF", - currencyName = "Cfa Franc Beac", - currencySymbol = "FCFA", - cctld = "gq", - flagEmoji = "🇬🇶", - phoneCode = 240 - ), - CountryInfo( - alpha2 = "GR", - alpha3 = "GRC", - englishName = "Greece", - demonym = "Greeks", - capitalEnglishName = "Athens", - areaKM2 = "131957", - population = 10423054, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "gr", - flagEmoji = "🇬🇷", - phoneCode = 30 - ), - CountryInfo( - alpha2 = "GS", - alpha3 = "SGS", - englishName = "South Georgia and the South Sandwich Islands", - demonym = "South Georgian or South Sandwich Islander", - capitalEnglishName = "Grytviken", - areaKM2 = "3903", - population = 0, - currencyCode = "GBP", - currencyName = "Pound Sterling", - currencySymbol = "£", - cctld = "gs", - flagEmoji = "🇬🇸", - phoneCode = 500 - ), - CountryInfo( - alpha2 = "GT", - alpha3 = "GTM", - englishName = "Guatemala", - demonym = "Guatemalans", - capitalEnglishName = "Guatemala City", - areaKM2 = "108889", - population = 17915568, - currencyCode = "GTQ", - currencyName = "Guatemalan Quetzal", - currencySymbol = "Q", - cctld = "gt", - flagEmoji = "🇬🇹", - phoneCode = 502 - ), - CountryInfo( - alpha2 = "GU", - alpha3 = "GUM", - englishName = "Guam", - demonym = "Guamanians", - capitalEnglishName = "Hagatna", - areaKM2 = "544", - population = 168775, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "gu", - flagEmoji = "🇬🇺", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "GW", - alpha3 = "GNB", - englishName = "Guinea-Bissau", - demonym = "Bissau-Guineans", - capitalEnglishName = "Bissau", - areaKM2 = "36125", - population = 1968001, - currencyCode = "XOF", - currencyName = "Cfa Franc Bceao", - currencySymbol = "CFA", - cctld = "gw", - flagEmoji = "🇬🇼", - phoneCode = 245 - ), - CountryInfo( - alpha2 = "GY", - alpha3 = "GUY", - englishName = "Guyana", - demonym = "Guyanese", - capitalEnglishName = "Georgetown", - areaKM2 = "214969", - population = 786552, - currencyCode = "GYD", - currencyName = "Guyanese Dollar", - currencySymbol = "$", - cctld = "gy", - flagEmoji = "🇬🇾", - phoneCode = 592 - ), - CountryInfo( - alpha2 = "HK", - alpha3 = "HKG", - englishName = "Hong Kong", - demonym = "Hong Kongese", - capitalEnglishName = "-", - areaKM2 = "1104", - population = 7496981, - currencyCode = "HKD", - currencyName = "Hong Kong Dollar", - currencySymbol = "$", - cctld = "hk", - flagEmoji = "🇭🇰", - phoneCode = 852 - ), - CountryInfo( - alpha2 = "HM", - alpha3 = "HMD", - englishName = "Heard Island and McDonald Islands", - demonym = "Heard Islanders or McDonald Islanders", - capitalEnglishName = "-", - areaKM2 = "412", - population = 0, - currencyCode = "AUD", - currencyName = "Australian Dollar", - currencySymbol = "$", - cctld = "hm", - flagEmoji = "🇭🇲", - phoneCode = 672 - ), - CountryInfo( - alpha2 = "HN", - alpha3 = "HND", - englishName = "Honduras", - demonym = "Hondurans", - capitalEnglishName = "Tegucigalpa", - areaKM2 = "112090", - population = 9904607, - currencyCode = "HNL", - currencyName = "Honduran Lempira", - currencySymbol = "L", - cctld = "hn", - flagEmoji = "🇭🇳", - phoneCode = 504 - ), - CountryInfo( - alpha2 = "HR", - alpha3 = "HRV", - englishName = "Croatia", - demonym = "Croatians", - capitalEnglishName = "Zagreb", - areaKM2 = "56594", - population = 4105267, - currencyCode = "HRK", - currencyName = "Croatian Kuna", - currencySymbol = "kn", - cctld = "hr", - flagEmoji = "🇭🇷", - phoneCode = 385 - ), - CountryInfo( - alpha2 = "HT", - alpha3 = "HTI", - englishName = "Haiti", - demonym = "Haitians", - capitalEnglishName = "Port-au-prince", - areaKM2 = "27750", - population = 11402528, - currencyCode = "HTG", - currencyName = "Haitian Gourde", - currencySymbol = "G", - cctld = "ht", - flagEmoji = "🇭🇹", - phoneCode = 509 - ), - CountryInfo( - alpha2 = "HU", - alpha3 = "HUN", - englishName = "Hungary", - demonym = "Hungarians", - capitalEnglishName = "Budapest", - areaKM2 = "93028", - population = 9660351, - currencyCode = "HUF", - currencyName = "Hungarian Forint", - currencySymbol = "Ft", - cctld = "hu", - flagEmoji = "🇭🇺", - phoneCode = 36 - ), - CountryInfo( - alpha2 = "ID", - alpha3 = "IDN", - englishName = "Indonesia", - demonym = "Indonesians", - capitalEnglishName = "Jakarta", - areaKM2 = "1904569", - population = 273523615, - currencyCode = "IDR", - currencyName = "Indonesian Rupiah", - currencySymbol = "Rp", - cctld = "id", - flagEmoji = "🇮🇩", - phoneCode = 62 - ), - CountryInfo( - alpha2 = "IE", - alpha3 = "IRL", - englishName = "Ireland", - demonym = "Irish", - capitalEnglishName = "Dublin", - areaKM2 = "70273", - population = 4937786, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "ie", - flagEmoji = "🇮🇪", - phoneCode = 353 - ), - CountryInfo( - alpha2 = "IL", - alpha3 = "ISR", - englishName = "Israel", - demonym = "Israelis", - capitalEnglishName = "Jerusalem", - areaKM2 = "20770", - population = 8655535, - currencyCode = "ILS", - currencyName = "Israeli New Shekel", - currencySymbol = "₪", - cctld = "il", - flagEmoji = "🇮🇱", - phoneCode = 972 - ), - CountryInfo( - alpha2 = "IM", - alpha3 = "IMN", - englishName = "Isle of Man", - demonym = "Manx", - capitalEnglishName = "Douglas", - areaKM2 = "572", - population = 85033, - currencyCode = "GBP", - currencyName = "British Pound", - currencySymbol = "£", - cctld = "im", - flagEmoji = "🇮🇲", - phoneCode = 44 - ), - CountryInfo( - alpha2 = "IN", - alpha3 = "IND", - englishName = "India", - demonym = "Indians", - capitalEnglishName = "New Delhi", - areaKM2 = "3287263", - population = 1380004385, - currencyCode = "INR", - currencyName = "Indian Rupee", - currencySymbol = "₹", - cctld = "in", - flagEmoji = "🇮🇳", - phoneCode = 91 - ), - CountryInfo( - alpha2 = "IO", - alpha3 = "IOT", - englishName = "British Indian Ocean Territory", - demonym = "British", - capitalEnglishName = "Diego Garcia", - areaKM2 = "54400", - population = 3000, - currencyCode = "GBP", - currencyName = "British Pound", - currencySymbol = "£", - cctld = "io", - flagEmoji = "🇮🇴", - phoneCode = 246 - ), - CountryInfo( - alpha2 = "IQ", - alpha3 = "IRQ", - englishName = "Iraq", - demonym = "Iraqis", - capitalEnglishName = "Baghdad", - areaKM2 = "438317", - population = 40222493, - currencyCode = "IQD", - currencyName = "Iraqi Dinar", - currencySymbol = "د.ع", - cctld = "iq", - flagEmoji = "🇮🇶", - phoneCode = 964 - ), - CountryInfo( - alpha2 = "IR", - alpha3 = "IRN", - englishName = "Iran (Islamic Republic of)", - demonym = "Iranians", - capitalEnglishName = "Tehran", - areaKM2 = "1648195", - population = 83992949, - currencyCode = "IRR", - currencyName = "Iranian Rial", - currencySymbol = "﷼", - cctld = "ir", - flagEmoji = "🇮🇷", - phoneCode = 98 - ), - CountryInfo( - alpha2 = "IS", - alpha3 = "ISL", - englishName = "Iceland", - demonym = "Icelanders", - capitalEnglishName = "Reykjavik", - areaKM2 = "103000", - population = 341243, - currencyCode = "ISK", - currencyName = "Iceland Krona", - currencySymbol = "kr", - cctld = "is", - flagEmoji = "🇮🇸", - phoneCode = 354 - ), - CountryInfo( - alpha2 = "IT", - alpha3 = "ITA", - englishName = "Italy", - demonym = "Italians", - capitalEnglishName = "Roma", - areaKM2 = "301340", - population = 60461826, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "it", - flagEmoji = "🇮🇹", - phoneCode = 39 - ), - CountryInfo( - alpha2 = "JE", - alpha3 = "JEY", - englishName = "Jersey", - demonym = "Channel Islanders", - capitalEnglishName = "Saint Helier", - areaKM2 = "116", - population = 107800, - currencyCode = "GBP", - currencyName = "British Pound", - currencySymbol = "£", - cctld = "je", - flagEmoji = "🇯🇪", - phoneCode = 44 - ), - CountryInfo( - alpha2 = "JM", - alpha3 = "JAM", - englishName = "Jamaica", - demonym = "Jamaicans", - capitalEnglishName = "Kingston", - areaKM2 = "10991", - population = 2961167, - currencyCode = "JMD", - currencyName = "Jamaican Dollar", - currencySymbol = "$", - cctld = "jm", - flagEmoji = "🇯🇲", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "JO", - alpha3 = "JOR", - englishName = "Jordan", - demonym = "Jordanians", - capitalEnglishName = "Amman", - areaKM2 = "89342", - population = 10203134, - currencyCode = "JOD", - currencyName = "Jordanian Dinar", - currencySymbol = "د.أ", - cctld = "jo", - flagEmoji = "🇯🇴", - phoneCode = 962 - ), - CountryInfo( - alpha2 = "JP", - alpha3 = "JPN", - englishName = "Japan", - demonym = "Japanese", - capitalEnglishName = "Tokyo", - areaKM2 = "377915", - population = 126476461, - currencyCode = "JPY", - currencyName = "Japanese Yen", - currencySymbol = "¥", - cctld = "jp", - flagEmoji = "🇯🇵", - phoneCode = 81 - ), - CountryInfo( - alpha2 = "KE", - alpha3 = "KEN", - englishName = "Kenya", - demonym = "Kenyans", - capitalEnglishName = "Nairobi", - areaKM2 = "580367", - population = 53771296, - currencyCode = "KES", - currencyName = "Kenyan Shilling", - currencySymbol = "KSh", - cctld = "ke", - flagEmoji = "🇰🇪", - phoneCode = 254 - ), - CountryInfo( - alpha2 = "KG", - alpha3 = "KGZ", - englishName = "Kyrgyzstan", - demonym = "Kyrgyzstanis", - capitalEnglishName = "Bishkek", - areaKM2 = "199951", - population = 6524195, - currencyCode = "KGS", - currencyName = "Kyrgyzstani Som", - currencySymbol = "Лв", - cctld = "kg", - flagEmoji = "🇰🇬", - phoneCode = 996 - ), - CountryInfo( - alpha2 = "KH", - alpha3 = "KHM", - englishName = "Cambodia", - demonym = "Cambodians", - capitalEnglishName = "Phnom Penh", - areaKM2 = "181035", - population = 16718965, - currencyCode = "KHR", - currencyName = "Cambodian Riel", - currencySymbol = "៛", - cctld = "kh", - flagEmoji = "🇰🇭", - phoneCode = 855 - ), - CountryInfo( - alpha2 = "KI", - alpha3 = "KIR", - englishName = "Kiribati", - demonym = "I-Kiribati", - capitalEnglishName = "Tarawa", - areaKM2 = "811", - population = 119449, - currencyCode = "AUD", - currencyName = "Australian Dollar", - currencySymbol = "$", - cctld = "ki", - flagEmoji = "🇰🇮", - phoneCode = 686 - ), - CountryInfo( - alpha2 = "KM", - alpha3 = "COM", - englishName = "Comoros", - demonym = "Comorans", - capitalEnglishName = "Moroni", - areaKM2 = "2235", - population = 869601, - currencyCode = "KMF", - currencyName = "Comoro Franc", - currencySymbol = "CF", - cctld = "km", - flagEmoji = "🇰🇲", - phoneCode = 269 - ), - CountryInfo( - alpha2 = "KN", - alpha3 = "KNA", - englishName = "Saint Kitts and Nevis", - demonym = "Kittitians or Nevisians", - capitalEnglishName = "Basseterre", - areaKM2 = "261", - population = 53199, - currencyCode = "XCD", - currencyName = "East Caribbean Dollar", - currencySymbol = "$", - cctld = "kn", - flagEmoji = "🇰🇳", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "KP", - alpha3 = "PRK", - englishName = "Korea (Democratic People's Republic of)", - demonym = "Koreans", - capitalEnglishName = "Pyongyang", - areaKM2 = "120538", - population = 25778816, - currencyCode = "KPW", - currencyName = "North Korean Won", - currencySymbol = "₩", - cctld = "kp", - flagEmoji = "🇰🇵", - phoneCode = 850 - ), - CountryInfo( - alpha2 = "KR", - alpha3 = "KOR", - englishName = "Korea (Republic of)", - demonym = "Koreans", - capitalEnglishName = "Seoul", - areaKM2 = "99720", - population = 51269185, - currencyCode = "KRW", - currencyName = "South-korean Won", - currencySymbol = "₩", - cctld = "kr", - flagEmoji = "🇰🇷", - phoneCode = 82 - ), - CountryInfo( - alpha2 = "KW", - alpha3 = "KWT", - englishName = "Kuwait", - demonym = "Kuwaitis", - capitalEnglishName = "Kuwait", - areaKM2 = "17818", - population = 4270571, - currencyCode = "KWD", - currencyName = "Kuwaiti Dinar", - currencySymbol = "KD", - cctld = "kw", - flagEmoji = "🇰🇼", - phoneCode = 965 - ), - CountryInfo( - alpha2 = "KY", - alpha3 = "CYM", - englishName = "Cayman Islands", - demonym = "Caymanians", - capitalEnglishName = "George Town", - areaKM2 = "264", - population = 65722, - currencyCode = "KYD", - currencyName = "Cayman Islands Dollar", - currencySymbol = "$", - cctld = "ky", - flagEmoji = "🇰🇾", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "KZ", - alpha3 = "KAZ", - englishName = "Kazakhstan", - demonym = "Kazakhstanis", - capitalEnglishName = "Astana", - areaKM2 = "2724900", - population = 18776707, - currencyCode = "KZT", - currencyName = "Kazakhstani Tenge", - currencySymbol = "₸", - cctld = "kz", - flagEmoji = "🇰🇿", - phoneCode = 7 - ), - CountryInfo( - alpha2 = "LA", - alpha3 = "LAO", - englishName = "Lao People's Democratic Republic", - demonym = "Laos", - capitalEnglishName = "Vientiane", - areaKM2 = "236800", - population = 7275560, - currencyCode = "LAK", - currencyName = "Lao Kip", - currencySymbol = "₭", - cctld = "la", - flagEmoji = "🇱🇦", - phoneCode = 856 - ), - CountryInfo( - alpha2 = "LB", - alpha3 = "LBN", - englishName = "Lebanon", - demonym = "Lebanese", - capitalEnglishName = "Beirut", - areaKM2 = "10400", - population = 6825445, - currencyCode = "LBP", - currencyName = "Lebanese Pound", - currencySymbol = "LL", - cctld = "lb", - flagEmoji = "🇱🇧", - phoneCode = 961 - ), - CountryInfo( - alpha2 = "LC", - alpha3 = "LCA", - englishName = "Saint Lucia", - demonym = "Saint Lucians", - capitalEnglishName = "Castries", - areaKM2 = "616", - population = 183627, - currencyCode = "XCD", - currencyName = "East Caribbean Dollar", - currencySymbol = "$", - cctld = "lc", - flagEmoji = "🇱🇨", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "LI", - alpha3 = "LIE", - englishName = "Liechtenstein", - demonym = "Liechtensteiners", - capitalEnglishName = "Vaduz", - areaKM2 = "160", - population = 38128, - currencyCode = "CHF", - currencyName = "Swiss Franc", - currencySymbol = "Fr.", - cctld = "li", - flagEmoji = "🇱🇮", - phoneCode = 423 - ), - CountryInfo( - alpha2 = "LK", - alpha3 = "LKA", - englishName = "Sri Lanka", - demonym = "Sri Lankans", - capitalEnglishName = "Sri Jayewardenepura Kotte", - areaKM2 = "65610", - population = 21413249, - currencyCode = "LKR", - currencyName = "Sri Lanka Rupee", - currencySymbol = "රු", - cctld = "lk", - flagEmoji = "🇱🇰", - phoneCode = 94 - ), - CountryInfo( - alpha2 = "LR", - alpha3 = "LBR", - englishName = "Liberia", - demonym = "Liberians", - capitalEnglishName = "Monrovia", - areaKM2 = "111369", - population = 5057681, - currencyCode = "LRD", - currencyName = "Liberian Dollar", - currencySymbol = "$", - cctld = "lr", - flagEmoji = "🇱🇷", - phoneCode = 231 - ), - CountryInfo( - alpha2 = "LS", - alpha3 = "LSO", - englishName = "Lesotho", - demonym = "Basotho", - capitalEnglishName = "Maseru", - areaKM2 = "30355", - population = 2142249, - currencyCode = "LSL", - currencyName = "Lesotho Loti", - currencySymbol = "M", - cctld = "ls", - flagEmoji = "🇱🇸", - phoneCode = 266 - ), - CountryInfo( - alpha2 = "LT", - alpha3 = "LTU", - englishName = "Lithuania", - demonym = "Lithuanians", - capitalEnglishName = "Vilnius", - areaKM2 = "65300", - population = 2722289, - currencyCode = "LTL", - currencyName = "Lithuanian Litas", - currencySymbol = "Lt", - cctld = "lt", - flagEmoji = "🇱🇹", - phoneCode = 370 - ), - CountryInfo( - alpha2 = "LU", - alpha3 = "LUX", - englishName = "Luxembourg", - demonym = "Luxembourgers", - capitalEnglishName = "Luxembourg", - areaKM2 = "2586", - population = 625978, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "lu", - flagEmoji = "🇱🇺", - phoneCode = 352 - ), - CountryInfo( - alpha2 = "LV", - alpha3 = "LVA", - englishName = "Latvia", - demonym = "Latvians", - capitalEnglishName = "Riga", - areaKM2 = "64589", - population = 1886198, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "lv", - flagEmoji = "🇱🇻", - phoneCode = 371 - ), - CountryInfo( - alpha2 = "LY", - alpha3 = "LBY", - englishName = "Libya", - demonym = "Libyans", - capitalEnglishName = "Tripoli", - areaKM2 = "1759540", - population = 6871292, - currencyCode = "LYD", - currencyName = "Libyan Dinar", - currencySymbol = "LD", - cctld = "ly", - flagEmoji = "🇱🇾", - phoneCode = 218 - ), - CountryInfo( - alpha2 = "MA", - alpha3 = "MAR", - englishName = "Morocco", - demonym = "Moroccans", - capitalEnglishName = "Rabat", - areaKM2 = "446550", - population = 36910560, - currencyCode = "MAD", - currencyName = "Moroccan Dirham", - currencySymbol = "DH", - cctld = "ma", - flagEmoji = "🇲🇦", - phoneCode = 212 - ), - CountryInfo( - alpha2 = "MC", - alpha3 = "MCO", - englishName = "Monaco", - demonym = "Monacans", - capitalEnglishName = "Monaco", - areaKM2 = "2", - population = 39242, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "mc", - flagEmoji = "🇲🇨", - phoneCode = 377 - ), - CountryInfo( - alpha2 = "MD", - alpha3 = "MDA", - englishName = "Moldova (Republic of)", - demonym = "Moldovans", - capitalEnglishName = "Chisinau", - areaKM2 = "33851", - population = 4033963, - currencyCode = "MDL", - currencyName = "Moldovan Leu", - currencySymbol = "L", - cctld = "md", - flagEmoji = "🇲🇩", - phoneCode = 373 - ), - CountryInfo( - alpha2 = "ME", - alpha3 = "MNE", - englishName = "Montenegro", - demonym = "Montenegrins", - capitalEnglishName = "Podgorica", - areaKM2 = "13812", - population = 628066, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "me", - flagEmoji = "🇲🇪", - phoneCode = 382 - ), - CountryInfo( - alpha2 = "MF", - alpha3 = "MAF", - englishName = "Saint Martin (French Part)", - demonym = "Saint-Martinois", - capitalEnglishName = "Marigot", - areaKM2 = "54", - population = 38666, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "gp", - flagEmoji = "🇲🇫", - phoneCode = 590 - ), - CountryInfo( - alpha2 = "MG", - alpha3 = "MDG", - englishName = "Madagascar", - demonym = "Malagasy", - capitalEnglishName = "Antananarivo", - areaKM2 = "587041", - population = 27691018, - currencyCode = "MGA", - currencyName = "Malagasy Ariary", - currencySymbol = "Ar", - cctld = "mg", - flagEmoji = "🇲🇬", - phoneCode = 261 - ), - CountryInfo( - alpha2 = "MH", - alpha3 = "MHL", - englishName = "Marshall Islands", - demonym = "Marshallese", - capitalEnglishName = "Majuro", - areaKM2 = "181", - population = 59190, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "mh", - flagEmoji = "🇲🇭", - phoneCode = 692 - ), - CountryInfo( - alpha2 = "MK", - alpha3 = "MKD", - englishName = "North Macedonia", - demonym = "Macedonians", - capitalEnglishName = "Skopje", - areaKM2 = "25713", - population = 2083374, - currencyCode = "MKD", - currencyName = "Macedonian Denar", - currencySymbol = "den", - cctld = "mk", - flagEmoji = "🇲🇰", - phoneCode = 389 - ), - CountryInfo( - alpha2 = "ML", - alpha3 = "MLI", - englishName = "Mali", - demonym = "Malians", - capitalEnglishName = "Bamako", - areaKM2 = "1240192", - population = 20250833, - currencyCode = "XOF", - currencyName = "Cfa Franc Bceao", - currencySymbol = "CFA", - cctld = "ml", - flagEmoji = "🇲🇱", - phoneCode = 223 - ), - CountryInfo( - alpha2 = "MM", - alpha3 = "MMR", - englishName = "Myanmar", - demonym = "Burmese", - capitalEnglishName = "Pyinmana", - areaKM2 = "676578", - population = 54409800, - currencyCode = "MMK", - currencyName = "Myanmar Kyat", - currencySymbol = "K", - cctld = "mm", - flagEmoji = "🇲🇲", - phoneCode = 95 - ), - CountryInfo( - alpha2 = "MN", - alpha3 = "MNG", - englishName = "Mongolia", - demonym = "Mongolians", - capitalEnglishName = "Ulaanbaatar", - areaKM2 = "1564116", - population = 3278290, - currencyCode = "MNT", - currencyName = "Mongolian Tugrik", - currencySymbol = "₮", - cctld = "mn", - flagEmoji = "🇲🇳", - phoneCode = 976 - ), - CountryInfo( - alpha2 = "MO", - alpha3 = "MAC", - englishName = "Macao", - demonym = "Macanese", - capitalEnglishName = "-", - areaKM2 = "31.3", - population = 649335, - currencyCode = "HKD", - currencyName = "Hong Kong Dollar", - currencySymbol = "$", - cctld = "mo", - flagEmoji = "🇲🇴", - phoneCode = 853 - ), - CountryInfo( - alpha2 = "MP", - alpha3 = "MNP", - englishName = "Northern Mariana Islands", - demonym = "Northern Marianans", - capitalEnglishName = "Saipan", - areaKM2 = "464", - population = 57559, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "mp", - flagEmoji = "🇲🇵", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "MQ", - alpha3 = "MTQ", - englishName = "Martinique", - demonym = "Martiniquais", - capitalEnglishName = "Fort-de-france", - areaKM2 = "1128", - population = 375265, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "mq", - flagEmoji = "🇲🇶", - phoneCode = 596 - ), - CountryInfo( - alpha2 = "MR", - alpha3 = "MRT", - englishName = "Mauritania", - demonym = "Mauritanians", - capitalEnglishName = "Nouakchott", - areaKM2 = "1030700", - population = 4649658, - currencyCode = "MRO", - currencyName = "Mauritanian Ouguiya", - currencySymbol = "UM", - cctld = "mr", - flagEmoji = "🇲🇷", - phoneCode = 222 - ), - CountryInfo( - alpha2 = "MS", - alpha3 = "MSR", - englishName = "Montserrat", - demonym = "Montserratians", - capitalEnglishName = "Plymouth", - areaKM2 = "102", - population = 4992, - currencyCode = "XCD", - currencyName = "East Caribbean Dollar", - currencySymbol = "$", - cctld = "ms", - flagEmoji = "🇲🇸", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "MT", - alpha3 = "MLT", - englishName = "Malta", - demonym = "Maltese", - capitalEnglishName = "Valletta", - areaKM2 = "316", - population = 441543, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "mt", - flagEmoji = "🇲🇹", - phoneCode = 356 - ), - CountryInfo( - alpha2 = "MU", - alpha3 = "MUS", - englishName = "Mauritius", - demonym = "Mauritians", - capitalEnglishName = "Port Louis", - areaKM2 = "2040", - population = 1271768, - currencyCode = "MUR", - currencyName = "Mauritian Rupee", - currencySymbol = "₨", - cctld = "mu", - flagEmoji = "🇲🇺", - phoneCode = 230 - ), - CountryInfo( - alpha2 = "MV", - alpha3 = "MDV", - englishName = "Maldives", - demonym = "Maldivians", - capitalEnglishName = "Male", - areaKM2 = "298", - population = 540544, - currencyCode = "MVR", - currencyName = "Maldivian Rufiyaa", - currencySymbol = "Rf", - cctld = "mv", - flagEmoji = "🇲🇻", - phoneCode = 960 - ), - CountryInfo( - alpha2 = "MW", - alpha3 = "MWI", - englishName = "Malawi", - demonym = "Malawians", - capitalEnglishName = "Lilongwe", - areaKM2 = "118484", - population = 19129952, - currencyCode = "MWK", - currencyName = "Malawian Kwacha", - currencySymbol = "K", - cctld = "mw", - flagEmoji = "🇲🇼", - phoneCode = 265 - ), - CountryInfo( - alpha2 = "MX", - alpha3 = "MEX", - englishName = "Mexico", - demonym = "Mexicans", - capitalEnglishName = "Mexico City", - areaKM2 = "1964375", - population = 128932753, - currencyCode = "MXN", - currencyName = "Mexican Peso", - currencySymbol = "$", - cctld = "mx", - flagEmoji = "🇲🇽", - phoneCode = 52 - ), - CountryInfo( - alpha2 = "MY", - alpha3 = "MYS", - englishName = "Malaysia", - demonym = "Malaysians", - capitalEnglishName = "Kuala Lumpur", - areaKM2 = "329847", - population = 32365999, - currencyCode = "MYR", - currencyName = "Malaysian Ringgit", - currencySymbol = "RM", - cctld = "my", - flagEmoji = "🇲🇾", - phoneCode = 60 - ), - CountryInfo( - alpha2 = "MZ", - alpha3 = "MOZ", - englishName = "Mozambique", - demonym = "Mozambicans", - capitalEnglishName = "Maputo", - areaKM2 = "799380", - population = 31255435, - currencyCode = "MZN", - currencyName = "Mozambican Metical", - currencySymbol = "MT", - cctld = "mz", - flagEmoji = "🇲🇿", - phoneCode = 258 - ), - CountryInfo( - alpha2 = "NA", - alpha3 = "NAM", - englishName = "Namibia", - demonym = "Namibians", - capitalEnglishName = "Windhoek", - areaKM2 = "824292", - population = 2540905, - currencyCode = "NAD", - currencyName = "Namibian Dollar", - currencySymbol = "$", - cctld = "na", - flagEmoji = "🇳🇦", - phoneCode = 264 - ), - CountryInfo( - alpha2 = "NC", - alpha3 = "NCL", - englishName = "New Caledonia", - demonym = "New Caledonians", - capitalEnglishName = "Noumea", - areaKM2 = "18575", - population = 285498, - currencyCode = "XPF", - currencyName = "Cfp Franc", - currencySymbol = "₣", - cctld = "nc", - flagEmoji = "🇳🇨", - phoneCode = 687 - ), - CountryInfo( - alpha2 = "NE", - alpha3 = "NER", - englishName = "Niger", - demonym = "Nigeriens", - capitalEnglishName = "Niamey", - areaKM2 = "1186408", - population = 24206644, - currencyCode = "NZD", - currencyName = "New Zealand Dollar", - currencySymbol = "$", - cctld = "ne", - flagEmoji = "🇳🇪", - phoneCode = 227 - ), - CountryInfo( - alpha2 = "NF", - alpha3 = "NFK", - englishName = "Norfolk Island", - demonym = "Norfolk Islanders", - capitalEnglishName = "Kingston", - areaKM2 = "36", - population = 1735, - currencyCode = "AUD", - currencyName = "Australian Dollar", - currencySymbol = "$", - cctld = "nf", - flagEmoji = "🇳🇫", - phoneCode = 672 - ), - CountryInfo( - alpha2 = "NG", - alpha3 = "NGA", - englishName = "Nigeria", - demonym = "Nigerians", - capitalEnglishName = "Abuja", - areaKM2 = "923768", - population = 206139589, - currencyCode = "NGN", - currencyName = "Nigerian Naira", - currencySymbol = "₦", - cctld = "ng", - flagEmoji = "🇳🇬", - phoneCode = 234 - ), - CountryInfo( - alpha2 = "NI", - alpha3 = "NIC", - englishName = "Nicaragua", - demonym = "Nicaraguans", - capitalEnglishName = "Managua", - areaKM2 = "130370", - population = 6624554, - currencyCode = "NIO", - currencyName = "Nicaraguan CÓrdoba", - currencySymbol = "C$", - cctld = "ni", - flagEmoji = "🇳🇮", - phoneCode = 505 - ), - CountryInfo( - alpha2 = "NL", - alpha3 = "NLD", - englishName = "Netherlands", - demonym = "Netherlanders", - capitalEnglishName = "Amsterdam", - areaKM2 = "41543", - population = 17134872, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "nl", - flagEmoji = "🇳🇱", - phoneCode = 31 - ), - CountryInfo( - alpha2 = "NO", - alpha3 = "NOR", - englishName = "Norway", - demonym = "Norwegians", - capitalEnglishName = "Oslo", - areaKM2 = "323802", - population = 5421241, - currencyCode = "NOK", - currencyName = "Norwegian Kroner", - currencySymbol = "kr", - cctld = "no", - flagEmoji = "🇳🇴", - phoneCode = 47 - ), - CountryInfo( - alpha2 = "NP", - alpha3 = "NPL", - englishName = "Nepal", - demonym = "Nepalese", - capitalEnglishName = "Kathmandu", - areaKM2 = "147181", - population = 29136808, - currencyCode = "NPR", - currencyName = "Nepalese Rupee", - currencySymbol = "रू", - cctld = "np", - flagEmoji = "🇳🇵", - phoneCode = 977 - ), - CountryInfo( - alpha2 = "NR", - alpha3 = "NRU", - englishName = "Nauru", - demonym = "Nauruans", - capitalEnglishName = "Yaren", - areaKM2 = "21", - population = 10824, - currencyCode = "AUD", - currencyName = "Australian Dollar", - currencySymbol = "$", - cctld = "nr", - flagEmoji = "🇳🇷", - phoneCode = 674 - ), - CountryInfo( - alpha2 = "NU", - alpha3 = "NIU", - englishName = "Niue", - demonym = "Niueans", - capitalEnglishName = "Alofi", - areaKM2 = "260", - population = 1626, - currencyCode = "NZD", - currencyName = "New Zealand Dollar", - currencySymbol = "$", - cctld = "nu", - flagEmoji = "🇳🇺", - phoneCode = 683 - ), - CountryInfo( - alpha2 = "NZ", - alpha3 = "NZL", - englishName = "New Zealand", - demonym = "New Zealanders", - capitalEnglishName = "Wellington", - areaKM2 = "267710", - population = 4822233, - currencyCode = "NZD", - currencyName = "New Zealand Dollar", - currencySymbol = "$", - cctld = "nz", - flagEmoji = "🇳🇿", - phoneCode = 64 - ), - CountryInfo( - alpha2 = "OM", - alpha3 = "OMN", - englishName = "Oman", - demonym = "Omanis", - capitalEnglishName = "Muscat", - areaKM2 = "309500", - population = 5106626, - currencyCode = "OMR", - currencyName = "Omani Rial", - currencySymbol = "ر.ع.", - cctld = "om", - flagEmoji = "🇴🇲", - phoneCode = 968 - ), - CountryInfo( - alpha2 = "PA", - alpha3 = "PAN", - englishName = "Panama", - demonym = "Panamanians", - capitalEnglishName = "Panama", - areaKM2 = "75420", - population = 4314767, - currencyCode = "PAB", - currencyName = "Panamanian Balboa", - currencySymbol = "B/.", - cctld = "pa", - flagEmoji = "🇵🇦", - phoneCode = 507 - ), - CountryInfo( - alpha2 = "PE", - alpha3 = "PER", - englishName = "Peru", - demonym = "Peruvians", - capitalEnglishName = "Lima", - areaKM2 = "1285216", - population = 32971854, - currencyCode = "PEN", - currencyName = "Peruvian Nuevo Sol", - currencySymbol = "S/", - cctld = "pe", - flagEmoji = "🇵🇪", - phoneCode = 51 - ), - CountryInfo( - alpha2 = "PF", - alpha3 = "PYF", - englishName = "French Polynesia", - demonym = "French Polynesians", - capitalEnglishName = "Papeete", - areaKM2 = "4167", - population = 280908, - currencyCode = "XPF", - currencyName = "Cfp Franc", - currencySymbol = "₣", - cctld = "pf", - flagEmoji = "🇵🇫", - phoneCode = 689 - ), - CountryInfo( - alpha2 = "PG", - alpha3 = "PNG", - englishName = "Papua New Guinea", - demonym = "Papua New Guineans", - capitalEnglishName = "Port Moresby", - areaKM2 = "462840", - population = 8947024, - currencyCode = "PGK", - currencyName = "Papua New Guinean Kina", - currencySymbol = "K", - cctld = "pg", - flagEmoji = "🇵🇬", - phoneCode = 675 - ), - CountryInfo( - alpha2 = "PH", - alpha3 = "PHL", - englishName = "Philippines", - demonym = "Filipinos", - capitalEnglishName = "Manila", - areaKM2 = "300000", - population = 109581078, - currencyCode = "PHP", - currencyName = "Philippine Peso", - currencySymbol = "₱", - cctld = "ph", - flagEmoji = "🇵🇭", - phoneCode = 63 - ), - CountryInfo( - alpha2 = "PK", - alpha3 = "PAK", - englishName = "Pakistan", - demonym = "Pakistanis", - capitalEnglishName = "Islamabad", - areaKM2 = "796095", - population = 220892340, - currencyCode = "PKR", - currencyName = "Pakistan Rupee", - currencySymbol = "₨", - cctld = "pk", - flagEmoji = "🇵🇰", - phoneCode = 92 - ), - CountryInfo( - alpha2 = "PL", - alpha3 = "POL", - englishName = "Poland", - demonym = "Poles", - capitalEnglishName = "Warsaw", - areaKM2 = "312685", - population = 37846611, - currencyCode = "PLN", - currencyName = "Polish Zloty", - currencySymbol = "zł", - cctld = "pl", - flagEmoji = "🇵🇱", - phoneCode = 48 - ), - CountryInfo( - alpha2 = "PM", - alpha3 = "SPM", - englishName = "Saint Pierre and Miquelon", - demonym = "Saint-Pierrais or Miquelonnais", - capitalEnglishName = "Saint-pierre", - areaKM2 = "242", - population = 5794, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "pm", - flagEmoji = "🇵🇲", - phoneCode = 508 - ), - CountryInfo( - alpha2 = "PN", - alpha3 = "PCN", - englishName = "Pitcairn", - demonym = "Pitcairn Islanders", - capitalEnglishName = "Adamstown", - areaKM2 = "47", - population = 50, - currencyCode = "NZD", - currencyName = "New Zealand Dollar", - currencySymbol = "$", - cctld = "pn", - flagEmoji = "🇵🇳", - phoneCode = 870 - ), - CountryInfo( - alpha2 = "PR", - alpha3 = "PRI", - englishName = "Puerto Rico", - demonym = "Puerto Ricans", - capitalEnglishName = "San Juan", - areaKM2 = "13790", - population = 2860853, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "pr", - flagEmoji = "🇵🇷", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "PS", - alpha3 = "PSE", - englishName = "Palestine, State of", - demonym = "Palestinians", - capitalEnglishName = "-", - areaKM2 = "5860", - population = 5101414, - currencyCode = "ILS", - currencyName = "Israeli New Shekel", - currencySymbol = "₪", - cctld = "ps", - flagEmoji = "🇵🇸", - phoneCode = 970 - ), - CountryInfo( - alpha2 = "PT", - alpha3 = "PRT", - englishName = "Portugal", - demonym = "Portuguese", - capitalEnglishName = "Lisbon", - areaKM2 = "92090", - population = 10196709, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "pt", - flagEmoji = "🇵🇹", - phoneCode = 351 - ), - CountryInfo( - alpha2 = "PW", - alpha3 = "PLW", - englishName = "Palau", - demonym = "Palauans", - capitalEnglishName = "Melekeok - Palau State Capital", - areaKM2 = "459", - population = 18094, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "pw", - flagEmoji = "🇵🇼", - phoneCode = 680 - ), - CountryInfo( - alpha2 = "PY", - alpha3 = "PRY", - englishName = "Paraguay", - demonym = "Paraguayans", - capitalEnglishName = "Asuncion", - areaKM2 = "406752", - population = 7132538, - currencyCode = "PYG", - currencyName = "Paraguayan GuaranÍ", - currencySymbol = "₲", - cctld = "py", - flagEmoji = "🇵🇾", - phoneCode = 595 - ), - CountryInfo( - alpha2 = "QA", - alpha3 = "QAT", - englishName = "Qatar", - demonym = "Qataris", - capitalEnglishName = "Doha", - areaKM2 = "11586", - population = 2881053, - currencyCode = "QAR", - currencyName = "Qatari Riyal", - currencySymbol = "QR", - cctld = "qa", - flagEmoji = "🇶🇦", - phoneCode = 974 - ), - CountryInfo( - alpha2 = "RE", - alpha3 = "REU", - englishName = "Reunion", - demonym = "Réunionese", - capitalEnglishName = "Saint-denis", - areaKM2 = "2512", - population = 895312, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "re", - flagEmoji = "🇷🇪", - phoneCode = 262 - ), - CountryInfo( - alpha2 = "RO", - alpha3 = "ROU", - englishName = "Romania", - demonym = "Romanians", - capitalEnglishName = "Bucharest", - areaKM2 = "238391", - population = 19237691, - currencyCode = "RON", - currencyName = "Romanian New Lei", - currencySymbol = "RON", - cctld = "ro", - flagEmoji = "🇷🇴", - phoneCode = 40 - ), - CountryInfo( - alpha2 = "RS", - alpha3 = "SRB", - englishName = "Serbia", - demonym = "Serbians", - capitalEnglishName = "Belgrade", - areaKM2 = "77474", - population = 8737371, - currencyCode = "RSD", - currencyName = "Serbian Dinar", - currencySymbol = "din", - cctld = "rs", - flagEmoji = "🇷🇸", - phoneCode = 381 - ), - CountryInfo( - alpha2 = "RU", - alpha3 = "RUS", - englishName = "Russian Federation", - demonym = "Russians", - capitalEnglishName = "Moscow", - areaKM2 = "17098242", - population = 145934462, - currencyCode = "RUB", - currencyName = "Russian Rouble", - currencySymbol = "₽", - cctld = "ru", - flagEmoji = "🇷🇺", - phoneCode = 7 - ), - CountryInfo( - alpha2 = "RW", - alpha3 = "RWA", - englishName = "Rwanda", - demonym = "Rwandans", - capitalEnglishName = "Kigali", - areaKM2 = "26338", - population = 12952218, - currencyCode = "RWF", - currencyName = "Rwandan Franc", - currencySymbol = "FRw", - cctld = "rw", - flagEmoji = "🇷🇼", - phoneCode = 250 - ), - CountryInfo( - alpha2 = "SA", - alpha3 = "SAU", - englishName = "Saudi Arabia", - demonym = "Saudis", - capitalEnglishName = "Riyadh", - areaKM2 = "2149690", - population = 34813871, - currencyCode = "SAR", - currencyName = "Saudi Riyal", - currencySymbol = "SR", - cctld = "sa", - flagEmoji = "🇸🇦", - phoneCode = 966 - ), - CountryInfo( - alpha2 = "SB", - alpha3 = "SLB", - englishName = "Solomon Islands", - demonym = "Solomon Islanders", - capitalEnglishName = "Honiara", - areaKM2 = "28896", - population = 686884, - currencyCode = "SBD", - currencyName = "Solomon Islands Dollar", - currencySymbol = "$", - cctld = "sb", - flagEmoji = "🇸🇧", - phoneCode = 677 - ), - CountryInfo( - alpha2 = "SC", - alpha3 = "SYC", - englishName = "Seychelles", - demonym = "Seychellois", - capitalEnglishName = "Victoria", - areaKM2 = "455", - population = 98347, - currencyCode = "SCR", - currencyName = "Seychelles Rupee", - currencySymbol = "SR", - cctld = "sc", - flagEmoji = "🇸🇨", - phoneCode = 248 - ), - CountryInfo( - alpha2 = "SD", - alpha3 = "SDN", - englishName = "Sudan", - demonym = "Sudanese", - capitalEnglishName = "Khartoum", - areaKM2 = "1861484", - population = 43849260, - currencyCode = "SDG", - currencyName = "Sudanese Pound", - currencySymbol = "SD", - cctld = "sd", - flagEmoji = "🇸🇩", - phoneCode = 249 - ), - CountryInfo( - alpha2 = "SE", - alpha3 = "SWE", - englishName = "Sweden", - demonym = "Swedes", - capitalEnglishName = "Stockholm", - areaKM2 = "450295", - population = 10099265, - currencyCode = "SEK", - currencyName = "Swedish Krona", - currencySymbol = "kr", - cctld = "se", - flagEmoji = "🇸🇪", - phoneCode = 46 - ), - CountryInfo( - alpha2 = "SG", - alpha3 = "SGP", - englishName = "Singapore", - demonym = "Singaporeans", - capitalEnglishName = "Singapore", - areaKM2 = "697", - population = 5850342, - currencyCode = "SGD", - currencyName = "Singapore Dollar", - currencySymbol = "$", - cctld = "sg", - flagEmoji = "🇸🇬", - phoneCode = 65 - ), - CountryInfo( - alpha2 = "SH", - alpha3 = "SHN", - englishName = "Saint Helena, Ascension and Tristan da Cunha", - demonym = "Saint Helenians", - capitalEnglishName = "Jamestown", - areaKM2 = "122", - population = 6077, - currencyCode = "SHP", - currencyName = "Saint Helena Pound", - currencySymbol = "£", - cctld = "sh", - flagEmoji = "🇸🇭", - phoneCode = 290 - ), - CountryInfo( - alpha2 = "SI", - alpha3 = "SVN", - englishName = "Slovenia", - demonym = "Slovenes", - capitalEnglishName = "Ljubljana", - areaKM2 = "20273", - population = 2078938, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "si", - flagEmoji = "🇸🇮", - phoneCode = 386 - ), - CountryInfo( - alpha2 = "SJ", - alpha3 = "SJM", - englishName = "Svalbard and Jan Mayen", - demonym = "Slovakians", - capitalEnglishName = "Longyearbyen", - areaKM2 = "62045", - population = 2926, - currencyCode = "NOK", - currencyName = "Norwegian Krone", - currencySymbol = "kr", - cctld = "sj", - flagEmoji = "🇸🇯", - phoneCode = 47 - ), - CountryInfo( - alpha2 = "SK", - alpha3 = "SVK", - englishName = "Slovakia", - demonym = "Sierra Leoneans", - capitalEnglishName = "Bratislava", - areaKM2 = "49035", - population = 5459642, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "sk", - flagEmoji = "🇸🇰", - phoneCode = 421 - ), - CountryInfo( - alpha2 = "SL", - alpha3 = "SLE", - englishName = "Sierra Leone", - demonym = "Sammarinese", - capitalEnglishName = "Freetown", - areaKM2 = "71740", - population = 7976983, - currencyCode = "SLL", - currencyName = "Sierra Leonean Leone", - currencySymbol = "Le", - cctld = "sl", - flagEmoji = "🇸🇱", - phoneCode = 232 - ), - CountryInfo( - alpha2 = "SM", - alpha3 = "SMR", - englishName = "San Marino", - demonym = "Sammarinese", - capitalEnglishName = "San Marino", - areaKM2 = "61", - population = 33931, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "sm", - flagEmoji = "🇸🇲", - phoneCode = 378 - ), - CountryInfo( - alpha2 = "SN", - alpha3 = "SEN", - englishName = "Senegal", - demonym = "Somalis", - capitalEnglishName = "Dakar", - areaKM2 = "196722", - population = 16743927, - currencyCode = "XOF", - currencyName = "Cfa Franc Bceao", - currencySymbol = "CFA", - cctld = "sn", - flagEmoji = "🇸🇳", - phoneCode = 221 - ), - CountryInfo( - alpha2 = "SO", - alpha3 = "SOM", - englishName = "Somalia", - demonym = "Somalilanders", - capitalEnglishName = "Mogadishu", - areaKM2 = "637657", - population = 15893222, - currencyCode = "SOS", - currencyName = "Somali Shilling", - currencySymbol = "Sh.So.", - cctld = "so", - flagEmoji = "🇸🇴", - phoneCode = 252 - ), - CountryInfo( - alpha2 = "SR", - alpha3 = "SUR", - englishName = "Suriname", - demonym = "Surinamers", - capitalEnglishName = "Paramaribo", - areaKM2 = "163820", - population = 586632, - currencyCode = "SRD", - currencyName = "Surinamese Dollar", - currencySymbol = "$", - cctld = "sr", - flagEmoji = "🇸🇷", - phoneCode = 597 - ), - CountryInfo( - alpha2 = "SS", - alpha3 = "SSD", - englishName = "South Sudan", - demonym = "South Sudanese", - capitalEnglishName = "Juba", - areaKM2 = "644329", - population = 11193725, - currencyCode = "SSP", - currencyName = "South Sudanese Pound", - currencySymbol = "SD", - cctld = "ss", - flagEmoji = "🇸🇸", - phoneCode = 211 - ), - CountryInfo( - alpha2 = "ST", - alpha3 = "STP", - englishName = "Sao Tome and Principe", - demonym = "Sao Tomeans", - capitalEnglishName = "Sao Tome", - areaKM2 = "964", - population = 219159, - currencyCode = "STD", - currencyName = "Droba", - currencySymbol = "Db", - cctld = "st", - flagEmoji = "🇸🇹", - phoneCode = 239 - ), - CountryInfo( - alpha2 = "SV", - alpha3 = "SLV", - englishName = "El Salvador", - demonym = "Salvadorans", - capitalEnglishName = "San Salvador", - areaKM2 = "21041", - population = 6486205, - currencyCode = "NOK", - currencyName = "Norwegian Kroner", - currencySymbol = "kr", - cctld = "sv", - flagEmoji = "🇸🇻", - phoneCode = 503 - ), - CountryInfo( - alpha2 = "SX", - alpha3 = "SXM", - englishName = "Sint Maarten (Dutch Part)", - demonym = "Sint Maartener", - capitalEnglishName = "Philipsburg", - areaKM2 = "34", - population = 42876, - currencyCode = "ANG", - currencyName = "Nl Antillian Guilder", - currencySymbol = "ƒ", - cctld = "sx", - flagEmoji = "🇸🇽", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "SY", - alpha3 = "SYR", - englishName = "Syrian Arab Republic", - demonym = "Syrians", - capitalEnglishName = "Damascus", - areaKM2 = "185180", - population = 17500658, - currencyCode = "SYP", - currencyName = "Syrian Pound", - currencySymbol = "LS", - cctld = "sy", - flagEmoji = "🇸🇾", - phoneCode = 963 - ), - CountryInfo( - alpha2 = "SZ", - alpha3 = "SWZ", - englishName = "Eswatini", - demonym = "Swazis", - capitalEnglishName = "Mbabane", - areaKM2 = "17364", - population = 1160164, - currencyCode = "SZL", - currencyName = "Swazi Lilangeni", - currencySymbol = "L", - cctld = "sz", - flagEmoji = "🇸🇿", - phoneCode = 268 - ), - CountryInfo( - alpha2 = "TC", - alpha3 = "TCA", - englishName = "Turks and Caicos Islands", - demonym = "Turks and Caicos Islanders", - capitalEnglishName = "Cockburn Town", - areaKM2 = "948", - population = 38717, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "tc", - flagEmoji = "🇹🇨", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "TD", - alpha3 = "TCD", - englishName = "Chad", - demonym = "Chadians", - capitalEnglishName = "N'djamena", - areaKM2 = "1284000", - population = 16425864, - currencyCode = "XAF", - currencyName = "Cfa Franc Beac", - currencySymbol = "FCFA", - cctld = "td", - flagEmoji = "🇹🇩", - phoneCode = 235 - ), - CountryInfo( - alpha2 = "TF", - alpha3 = "ATF", - englishName = "French Southern Territories", - demonym = "French", - capitalEnglishName = "Port-aux-francais", - areaKM2 = "439781", - population = 140, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "tf", - flagEmoji = "🇹🇫", - phoneCode = 262 - ), - CountryInfo( - alpha2 = "TG", - alpha3 = "TGO", - englishName = "Togo", - demonym = "Togolese", - capitalEnglishName = "Lome", - areaKM2 = "56785", - population = 8278724, - currencyCode = "XOF", - currencyName = "Cfa Franc Bceao", - currencySymbol = "CFA", - cctld = "tg", - flagEmoji = "🇹🇬", - phoneCode = 228 - ), - CountryInfo( - alpha2 = "TH", - alpha3 = "THA", - englishName = "Thailand", - demonym = "Thai", - capitalEnglishName = "Bangkok", - areaKM2 = "513120", - population = 69799978, - currencyCode = "THB", - currencyName = "Thai Baht", - currencySymbol = "฿", - cctld = "th", - flagEmoji = "🇹🇭", - phoneCode = 66 - ), - CountryInfo( - alpha2 = "TJ", - alpha3 = "TJK", - englishName = "Tajikistan", - demonym = "Tajikistanis", - capitalEnglishName = "Dushanbe", - areaKM2 = "143100", - population = 9537645, - currencyCode = "TJS", - currencyName = "Tajikistani Somoni", - currencySymbol = "ЅM", - cctld = "tj", - flagEmoji = "🇹🇯", - phoneCode = 992 - ), - CountryInfo( - alpha2 = "TK", - alpha3 = "TKL", - englishName = "Tokelau", - demonym = "Tokelauans", - capitalEnglishName = "-", - areaKM2 = "12", - population = 1357, - currencyCode = "NZD", - currencyName = "New Zealand Dollar", - currencySymbol = "$", - cctld = "tk", - flagEmoji = "🇹🇰", - phoneCode = 690 - ), - CountryInfo( - alpha2 = "TL", - alpha3 = "TLS", - englishName = "Timor-Leste", - demonym = "Timorese", - capitalEnglishName = "Dili", - areaKM2 = "14874", - population = 1318445, - currencyCode = "NZD", - currencyName = "New Zealand Dollar", - currencySymbol = "$", - cctld = "tl", - flagEmoji = "🇹🇱", - phoneCode = 670 - ), - CountryInfo( - alpha2 = "TM", - alpha3 = "TKM", - englishName = "Turkmenistan", - demonym = "Turkmens", - capitalEnglishName = "Ashgabat", - areaKM2 = "488100", - population = 6031200, - currencyCode = "TMT", - currencyName = "Turkmenistani Manat", - currencySymbol = "T", - cctld = "tm", - flagEmoji = "🇹🇲", - phoneCode = 993 - ), - CountryInfo( - alpha2 = "TN", - alpha3 = "TUN", - englishName = "Tunisia", - demonym = "Tunisians", - capitalEnglishName = "Tunis", - areaKM2 = "163610", - population = 11818619, - currencyCode = "TND", - currencyName = "Tunisian Dinar", - currencySymbol = "DT", - cctld = "tn", - flagEmoji = "🇹🇳", - phoneCode = 216 - ), - CountryInfo( - alpha2 = "TO", - alpha3 = "TON", - englishName = "Tonga", - demonym = "Tongans", - capitalEnglishName = "Nuku'alofa", - areaKM2 = "747", - population = 105695, - currencyCode = "TOP", - currencyName = "Tongan Pa'anga", - currencySymbol = "T$", - cctld = "to", - flagEmoji = "🇹🇴", - phoneCode = 676 - ), - CountryInfo( - alpha2 = "TR", - alpha3 = "TUR", - englishName = "Turkey", - demonym = "Turks", - capitalEnglishName = "Ankara", - areaKM2 = "783562", - population = 84339067, - currencyCode = "TRY", - currencyName = "Turkish Lira", - currencySymbol = "₺", - cctld = "tr", - flagEmoji = "🇹🇷", - phoneCode = 90 - ), - CountryInfo( - alpha2 = "TT", - alpha3 = "TTO", - englishName = "Trinidad and Tobago", - demonym = "Trinidadians or Tobagonians", - capitalEnglishName = "Port of Spain", - areaKM2 = "5128", - population = 1399488, - currencyCode = "TTD", - currencyName = "Trinidad/tobago Dollar", - currencySymbol = "$", - cctld = "tt", - flagEmoji = "🇹🇹", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "TV", - alpha3 = "TUV", - englishName = "Tuvalu", - demonym = "Tuvaluans", - capitalEnglishName = "Funafuti", - areaKM2 = "26", - population = 11792, - currencyCode = "AUD", - currencyName = "Australian Dollar", - currencySymbol = "$", - cctld = "tv", - flagEmoji = "🇹🇻", - phoneCode = 688 - ), - CountryInfo( - alpha2 = "TW", - alpha3 = "TWN", - englishName = "Taiwan (Province of China)", - demonym = "Taiwanese", - capitalEnglishName = "Taipei", - areaKM2 = "35980", - population = 23816775, - currencyCode = "TWD", - currencyName = "Taiwan Dollar", - currencySymbol = "NT$", - cctld = "tw", - flagEmoji = "🇹🇼", - phoneCode = 886 - ), - CountryInfo( - alpha2 = "TZ", - alpha3 = "TZA", - englishName = "Tanzania, United Republic of", - demonym = "Tanzanians", - capitalEnglishName = "Dodoma", - areaKM2 = "947300", - population = 59734218, - currencyCode = "TZS", - currencyName = "Tanzanian Shilling", - currencySymbol = "TSh", - cctld = "tz", - flagEmoji = "🇹🇿", - phoneCode = 255 - ), - CountryInfo( - alpha2 = "UA", - alpha3 = "UKR", - englishName = "Ukraine", - demonym = "Ukrainians", - capitalEnglishName = "Kiev", - areaKM2 = "603550", - population = 43733762, - currencyCode = "UAH", - currencyName = "Ukrainian Hryvnia", - currencySymbol = "₴", - cctld = "ua", - flagEmoji = "🇺🇦", - phoneCode = 380 - ), - CountryInfo( - alpha2 = "UG", - alpha3 = "UGA", - englishName = "Uganda", - demonym = "Ugandans", - capitalEnglishName = "Kampala", - areaKM2 = "241038", - population = 45741007, - currencyCode = "UGX", - currencyName = "Ugandan Shilling", - currencySymbol = "USh", - cctld = "ug", - flagEmoji = "🇺🇬", - phoneCode = 256 - ), - CountryInfo( - alpha2 = "UM", - alpha3 = "UMI", - englishName = "United States Minor Outlying Islands", - demonym = "‎American Islander", - capitalEnglishName = "-", - areaKM2 = "34.2", - population = 300, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "um", - flagEmoji = "🇺🇲", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "US", - alpha3 = "USA", - englishName = "United States of America", - demonym = "Americans", - capitalEnglishName = "Washington, D.C.", - areaKM2 = "9826675", - population = 331002651, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "us", - flagEmoji = "🇺🇸", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "UY", - alpha3 = "URY", - englishName = "Uruguay", - demonym = "Uruguayans", - capitalEnglishName = "Montevideo", - areaKM2 = "176215", - population = 3473730, - currencyCode = "UYI", - currencyName = "Uruguay Peso En Unidades Indexadas", - currencySymbol = "$", - cctld = "uy", - flagEmoji = "🇺🇾", - phoneCode = 598 - ), - CountryInfo( - alpha2 = "UZ", - alpha3 = "UZB", - englishName = "Uzbekistan", - demonym = "Uzbekistanis", - capitalEnglishName = "Tashkent", - areaKM2 = "447400", - population = 33469203, - currencyCode = "UZS", - currencyName = "Uzbekistan Som", - currencySymbol = "som", - cctld = "uz", - flagEmoji = "🇺🇿", - phoneCode = 998 - ), - CountryInfo( - alpha2 = "VA", - alpha3 = "VAT", - englishName = "Holy See", - demonym = "Vatican citizens", - capitalEnglishName = "Vatican City", - areaKM2 = "0.44", - population = 801, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "va", - flagEmoji = "🇻🇦", - phoneCode = 379 - ), - CountryInfo( - alpha2 = "VC", - alpha3 = "VCT", - englishName = "Saint Vincent and the Grenadines", - demonym = "Saint Vincentians", - capitalEnglishName = "Kingstown", - areaKM2 = "389", - population = 110940, - currencyCode = "XCD", - currencyName = "East Caribbean Dollar", - currencySymbol = "$", - cctld = "vc", - flagEmoji = "🇻🇨", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "VE", - alpha3 = "VEN", - englishName = "Venezuela (Bolivarian Republic of)", - demonym = "Venezuelans", - capitalEnglishName = "Caracas", - areaKM2 = "912050", - population = 28435940, - currencyCode = "VEF", - currencyName = "Venezuelan Bolivar Fuerte", - currencySymbol = "Bs.S.", - cctld = "ve", - flagEmoji = "🇻🇪", - phoneCode = 58 - ), - CountryInfo( - alpha2 = "VG", - alpha3 = "VGB", - englishName = "Virgin Islands (British)", - demonym = "British Virgin Islanders", - capitalEnglishName = "Road Town", - areaKM2 = "151", - population = 30231, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "vg", - flagEmoji = "🇻🇬", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "VI", - alpha3 = "VIR", - englishName = "Virgin Islands (U.S.)", - demonym = "U.S. Virgin Islanders", - capitalEnglishName = "Charlotte Amalie", - areaKM2 = "1910", - population = 104425, - currencyCode = "USD", - currencyName = "United States Dollar", - currencySymbol = "$", - cctld = "vi", - flagEmoji = "🇻🇮", - phoneCode = 1 - ), - CountryInfo( - alpha2 = "VN", - alpha3 = "VNM", - englishName = "Viet Nam", - demonym = "Vietnamese", - capitalEnglishName = "Ha Noi", - areaKM2 = "331210", - population = 97338579, - currencyCode = "VND", - currencyName = "Vietnamese Dong", - currencySymbol = "₫", - cctld = "vn", - flagEmoji = "🇻🇳", - phoneCode = 84 - ), - CountryInfo( - alpha2 = "VU", - alpha3 = "VUT", - englishName = "Vanuatu", - demonym = "Ni-Vanuatu", - capitalEnglishName = "Port-vila", - areaKM2 = "12189", - population = 307145, - currencyCode = "VUV", - currencyName = "Vanuatu Vatu", - currencySymbol = "VT", - cctld = "vu", - flagEmoji = "🇻🇺", - phoneCode = 678 - ), - CountryInfo( - alpha2 = "WF", - alpha3 = "WLF", - englishName = "Wallis and Futuna", - demonym = "Wallisians or Futunans", - capitalEnglishName = "Mata'utu", - areaKM2 = "142", - population = 11239, - currencyCode = "XPF", - currencyName = "Cfp Franc", - currencySymbol = "₣", - cctld = "wf", - flagEmoji = "🇼🇫", - phoneCode = 681 - ), - CountryInfo( - alpha2 = "WS", - alpha3 = "WSM", - englishName = "Samoa", - demonym = "Samoans", - capitalEnglishName = "Apia", - areaKM2 = "2831", - population = 198414, - currencyCode = "WST", - currencyName = "Samoan Tala", - currencySymbol = "WS$", - cctld = "ws", - flagEmoji = "🇼🇸", - phoneCode = 685 - ), - CountryInfo( - alpha2 = "XK", - alpha3 = "XKX", - englishName = "Kosovo", - demonym = "Kosovar", - capitalEnglishName = "Pristina", - areaKM2 = "10887", - population = 1873160, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "al", - flagEmoji = "🇽🇰", - phoneCode = 383 - ), - CountryInfo( - alpha2 = "YE", - alpha3 = "YEM", - englishName = "Yemen", - demonym = "Yemenis", - capitalEnglishName = "Sanaa", - areaKM2 = "527968", - population = 29825964, - currencyCode = "YER", - currencyName = "Yemeni Rial", - currencySymbol = "﷼", - cctld = "ye", - flagEmoji = "🇾🇪", - phoneCode = 967 - ), - CountryInfo( - alpha2 = "YT", - alpha3 = "MYT", - englishName = "Mayotte", - demonym = "Mahorans", - capitalEnglishName = "Mamoudzou", - areaKM2 = "374", - population = 272815, - currencyCode = "EUR", - currencyName = "Euro", - currencySymbol = "€", - cctld = "yt", - flagEmoji = "🇾🇹", - phoneCode = 262 - ), - CountryInfo( - alpha2 = "ZA", - alpha3 = "ZAF", - englishName = "South Africa", - demonym = "South Africans", - capitalEnglishName = "Cape Town", - areaKM2 = "1219090", - population = 59308690, - currencyCode = "ZAR", - currencyName = "South African Rand", - currencySymbol = "R", - cctld = "za", - flagEmoji = "🇿🇦", - phoneCode = 27 - ), - CountryInfo( - alpha2 = "ZM", - alpha3 = "ZMB", - englishName = "Zambia", - demonym = "Zambians", - capitalEnglishName = "Lusaka", - areaKM2 = "752618", - population = 18383955, - currencyCode = "ZMW", - currencyName = "Zambian Kwacha", - currencySymbol = "K", - cctld = "zm", - flagEmoji = "🇿🇲", - phoneCode = 260 - ), - CountryInfo( - alpha2 = "ZW", - alpha3 = "ZWE", - englishName = "Zimbabwe", - demonym = "Zimbabweans", - capitalEnglishName = "Harare", - areaKM2 = "390757", - population = 14862924, - currencyCode = "ZWD", - currencyName = "Zimbabwe Dollar", - currencySymbol = "$", - cctld = "zw", - flagEmoji = "🇿🇼", - phoneCode = 263 +internal val countryInfoList = + listOf( + CountryInfo( + alpha2 = "AD", + alpha3 = "AND", + englishName = "Andorra", + demonym = "Andorrans", + capitalEnglishName = "Andorra la Vella", + areaKM2 = "468", + population = 77265, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "ad", + flagEmoji = "🇦🇩", + phoneCode = 376, + ), + CountryInfo( + alpha2 = "AE", + alpha3 = "ARE", + englishName = "United Arab Emirates", + demonym = "Emirians", + capitalEnglishName = "Abu Dhabi", + areaKM2 = "83600", + population = 9890402, + currencyCode = "AED", + currencyName = "United Arab Emirates Dirham", + currencySymbol = "د.إ", + cctld = "ae", + flagEmoji = "🇦🇪", + phoneCode = 971, + ), + CountryInfo( + alpha2 = "AF", + alpha3 = "AFG", + englishName = "Afghanistan", + demonym = "Afghans", + capitalEnglishName = "Kabul", + areaKM2 = "652230", + population = 38928346, + currencyCode = "AFN", + currencyName = "Afghan Afghani", + currencySymbol = "؋", + cctld = "af", + flagEmoji = "🇦🇫", + phoneCode = 93, + ), + CountryInfo( + alpha2 = "AG", + alpha3 = "ATG", + englishName = "Antigua and Barbuda", + demonym = "Antiguans or Barbudans", + capitalEnglishName = "Saint John's", + areaKM2 = "442", + population = 97929, + currencyCode = "XCD", + currencyName = "East Caribbean Dollar", + currencySymbol = "$", + cctld = "ag", + flagEmoji = "🇦🇬", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "AI", + alpha3 = "AIA", + englishName = "Anguilla", + demonym = "Anguillans", + capitalEnglishName = "The Valley", + areaKM2 = "91", + population = 15003, + currencyCode = "XCD", + currencyName = "East Caribbean Dollar", + currencySymbol = "$", + cctld = "ai", + flagEmoji = "🇦🇮", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "AL", + alpha3 = "ALB", + englishName = "Albania", + demonym = "Albanians", + capitalEnglishName = "Tirana", + areaKM2 = "28748", + population = 2877797, + currencyCode = "ALL", + currencyName = "Albanian Lek", + currencySymbol = "L", + cctld = "al", + flagEmoji = "🇦🇱", + phoneCode = 355, + ), + CountryInfo( + alpha2 = "AM", + alpha3 = "ARM", + englishName = "Armenia", + demonym = "Armenians", + capitalEnglishName = "Yerevan", + areaKM2 = "29743", + population = 2963243, + currencyCode = "AMD", + currencyName = "Armenian Dram", + currencySymbol = "֏", + cctld = "am", + flagEmoji = "🇦🇲", + phoneCode = 374, + ), + CountryInfo( + alpha2 = "AO", + alpha3 = "AGO", + englishName = "Angola", + demonym = "Angolans", + capitalEnglishName = "Luanda", + areaKM2 = "1246700", + population = 32866272, + currencyCode = "AOA", + currencyName = "Angolan Kwanza", + currencySymbol = "Kz", + cctld = "ao", + flagEmoji = "🇦🇴", + phoneCode = 244, + ), + CountryInfo( + alpha2 = "AQ", + alpha3 = "ATA", + englishName = "Antarctica", + demonym = "Antarctic residents", + capitalEnglishName = "-", + areaKM2 = "14000000", + population = 0, + currencyCode = "", + currencyName = "", + currencySymbol = "", + cctld = "aq", + flagEmoji = "🇦🇶", + phoneCode = 672, + ), + CountryInfo( + alpha2 = "AR", + alpha3 = "ARG", + englishName = "Argentina", + demonym = "Argentines", + capitalEnglishName = "Buenos Aires", + areaKM2 = "2780400", + population = 45195774, + currencyCode = "ARS", + currencyName = "Argentine Peso", + currencySymbol = "$", + cctld = "ar", + flagEmoji = "🇦🇷", + phoneCode = 54, + ), + CountryInfo( + alpha2 = "AS", + alpha3 = "ASM", + englishName = "American Samoa", + demonym = "American Samoans", + capitalEnglishName = "Pago Pago", + areaKM2 = "199", + population = 55191, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "as", + flagEmoji = "🇦🇸", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "AT", + alpha3 = "AUT", + englishName = "Austria", + demonym = "Austrians", + capitalEnglishName = "Vienna", + areaKM2 = "83871", + population = 9006398, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "at", + flagEmoji = "🇦🇹", + phoneCode = 43, + ), + CountryInfo( + alpha2 = "AU", + alpha3 = "AUS", + englishName = "Australia", + demonym = "Australians", + capitalEnglishName = "Canberra", + areaKM2 = "7741220", + population = 25499884, + currencyCode = "AUD", + currencyName = "Australian Dollar", + currencySymbol = "$", + cctld = "au", + flagEmoji = "🇦🇺", + phoneCode = 61, + ), + CountryInfo( + alpha2 = "AW", + alpha3 = "ABW", + englishName = "Aruba", + demonym = "Arubans", + capitalEnglishName = "Oranjestad", + areaKM2 = "180", + population = 106766, + currencyCode = "AWG", + currencyName = "Aruban Florin", + currencySymbol = "Afl", + cctld = "aw", + flagEmoji = "🇦🇼", + phoneCode = 297, + ), + CountryInfo( + alpha2 = "AX", + alpha3 = "ALA", + englishName = "Aland Islands", + demonym = "Aland Islanders", + capitalEnglishName = "Mariehamn", + areaKM2 = "1552", + population = 30144, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "ax", + flagEmoji = "🇦🇽", + phoneCode = 358, + ), + CountryInfo( + alpha2 = "AZ", + alpha3 = "AZE", + englishName = "Azerbaijan", + demonym = "Azerbaijanis", + capitalEnglishName = "Baku", + areaKM2 = "86600", + population = 10139177, + currencyCode = "AZN", + currencyName = "Azerbaijani Manat", + currencySymbol = "₼", + cctld = "az", + flagEmoji = "🇦🇿", + phoneCode = 994, + ), + CountryInfo( + alpha2 = "BA", + alpha3 = "BIH", + englishName = "Bosnia and Herzegovina", + demonym = "Bosnians or Herzegovinians", + capitalEnglishName = "Sarajevo", + areaKM2 = "51197", + population = 3280819, + currencyCode = "BAM", + currencyName = "Bosnia And Herzegovina Convertible Mark", + currencySymbol = "KM", + cctld = "ba", + flagEmoji = "🇧🇦", + phoneCode = 387, + ), + CountryInfo( + alpha2 = "BB", + alpha3 = "BRB", + englishName = "Barbados", + demonym = "Barbadians", + capitalEnglishName = "Bridgetown", + areaKM2 = "430", + population = 287375, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "bb", + flagEmoji = "🇧🇧", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "BD", + alpha3 = "BGD", + englishName = "Bangladesh", + demonym = "Bangladeshis", + capitalEnglishName = "Dhaka", + areaKM2 = "143998", + population = 164689383, + currencyCode = "BDT", + currencyName = "Bangladeshi Taka", + currencySymbol = "৳", + cctld = "bd", + flagEmoji = "🇧🇩", + phoneCode = 880, + ), + CountryInfo( + alpha2 = "BE", + alpha3 = "BEL", + englishName = "Belgium", + demonym = "Belgians", + capitalEnglishName = "Brussels", + areaKM2 = "30528", + population = 11589623, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "be", + flagEmoji = "🇧🇪", + phoneCode = 32, + ), + CountryInfo( + alpha2 = "BF", + alpha3 = "BFA", + englishName = "Burkina Faso", + demonym = "Burkinabe", + capitalEnglishName = "Ouagadougou", + areaKM2 = "274200", + population = 20903273, + currencyCode = "XOF", + currencyName = "Cfa Franc Bceao", + currencySymbol = "CFA", + cctld = "bf", + flagEmoji = "🇧🇫", + phoneCode = 226, + ), + CountryInfo( + alpha2 = "BG", + alpha3 = "BGR", + englishName = "Bulgaria", + demonym = "Bulgarians", + capitalEnglishName = "Sofia", + areaKM2 = "110879", + population = 6948445, + currencyCode = "BGN", + currencyName = "Bulgarian Lev", + currencySymbol = "лв", + cctld = "bg", + flagEmoji = "🇧🇬", + phoneCode = 359, + ), + CountryInfo( + alpha2 = "BH", + alpha3 = "BHR", + englishName = "Bahrain", + demonym = "Bahrainis", + capitalEnglishName = "Manama", + areaKM2 = "760", + population = 1701575, + currencyCode = "BHD", + currencyName = "Bahraini Dinar", + currencySymbol = "BD", + cctld = "bh", + flagEmoji = "🇧🇭", + phoneCode = 973, + ), + CountryInfo( + alpha2 = "BI", + alpha3 = "BDI", + englishName = "Burundi", + demonym = "Burundians", + capitalEnglishName = "Bujumbura", + areaKM2 = "27830", + population = 11890784, + currencyCode = "BIF", + currencyName = "Burundian Franc", + currencySymbol = "FBu", + cctld = "bi", + flagEmoji = "🇧🇮", + phoneCode = 257, + ), + CountryInfo( + alpha2 = "BJ", + alpha3 = "BEN", + englishName = "Benin", + demonym = "Beninese", + capitalEnglishName = "Porto-Novo", + areaKM2 = "112622", + population = 12123200, + currencyCode = "XOF", + currencyName = "Cfa Franc Bceao", + currencySymbol = "CFA", + cctld = "bj", + flagEmoji = "🇧🇯", + phoneCode = 229, + ), + CountryInfo( + alpha2 = "BL", + alpha3 = "BLM", + englishName = "Saint Barthelemy", + demonym = "Barthelemois", + capitalEnglishName = "Gustavia", + areaKM2 = "21", + population = 9877, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "gp", + flagEmoji = "🇧🇱", + phoneCode = 590, + ), + CountryInfo( + alpha2 = "BM", + alpha3 = "BMU", + englishName = "Bermuda", + demonym = "Bermudians", + capitalEnglishName = "Hamilton", + areaKM2 = "54", + population = 62278, + currencyCode = "BMD", + currencyName = "Bermudian Dollar", + currencySymbol = "$", + cctld = "bm", + flagEmoji = "🇧🇲", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "BN", + alpha3 = "BRN", + englishName = "Brunei Darussalam", + demonym = "Bruneians", + capitalEnglishName = "Bandar Seri Begawan", + areaKM2 = "5765", + population = 437479, + currencyCode = "SGD", + currencyName = "Brunei Dollar", + currencySymbol = "$", + cctld = "bn", + flagEmoji = "🇧🇳", + phoneCode = 673, + ), + CountryInfo( + alpha2 = "BO", + alpha3 = "BOL", + englishName = "Bolivia (Plurinational State of)", + demonym = "Bolivians", + capitalEnglishName = "Sucre", + areaKM2 = "1098581", + population = 11673021, + currencyCode = "BOB", + currencyName = "Boliviano", + currencySymbol = "Bs", + cctld = "bo", + flagEmoji = "🇧🇴", + phoneCode = 591, + ), + CountryInfo( + alpha2 = "BQ", + alpha3 = "BES", + englishName = "Bonaire, Sint Eustatius and Saba", + demonym = "Bonaire Dutch", + capitalEnglishName = "Kralendijk", + areaKM2 = "328", + population = 26223, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "bq", + flagEmoji = "🇧🇶", + phoneCode = 599, + ), + CountryInfo( + alpha2 = "BR", + alpha3 = "BRA", + englishName = "Brazil", + demonym = "Brazilians", + capitalEnglishName = "Brasilia", + areaKM2 = "8514877", + population = 212559417, + currencyCode = "BRL", + currencyName = "Brazilian Real", + currencySymbol = "Cz$", + cctld = "br", + flagEmoji = "🇧🇷", + phoneCode = 55, + ), + CountryInfo( + alpha2 = "BS", + alpha3 = "BHS", + englishName = "Bahamas", + demonym = "Bahamians", + capitalEnglishName = "Nassau", + areaKM2 = "13880", + population = 393244, + currencyCode = "BSD", + currencyName = "Bahamian Dollar", + currencySymbol = "$", + cctld = "bs", + flagEmoji = "🇧🇸", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "BT", + alpha3 = "BTN", + englishName = "Bhutan", + demonym = "Bhutanese", + capitalEnglishName = "Thimphu", + areaKM2 = "38394", + population = 771608, + currencyCode = "BTN", + currencyName = "Bhutanese Ngultrum", + currencySymbol = "Nu.", + cctld = "bt", + flagEmoji = "🇧🇹", + phoneCode = 975, + ), + CountryInfo( + alpha2 = "BV", + alpha3 = "BVT", + englishName = "Bouvet Island", + demonym = "Bouvet Islanders", + capitalEnglishName = "-", + areaKM2 = "49", + population = 0, + currencyCode = "NOK", + currencyName = "Norwegian Kroner", + currencySymbol = "kr", + cctld = "bv", + flagEmoji = "🇧🇻", + phoneCode = 47, + ), + CountryInfo( + alpha2 = "BW", + alpha3 = "BWA", + englishName = "Botswana", + demonym = "Motswana", + capitalEnglishName = "Gaborone", + areaKM2 = "581730", + population = 2351627, + currencyCode = "BWP", + currencyName = "Botswana Pula", + currencySymbol = "P", + cctld = "bw", + flagEmoji = "🇧🇼", + phoneCode = 267, + ), + CountryInfo( + alpha2 = "BY", + alpha3 = "BLR", + englishName = "Belarus", + demonym = "Belarusians", + capitalEnglishName = "Minsk", + areaKM2 = "207600", + population = 9449323, + currencyCode = "BYR", + currencyName = "Belarusian Ruble", + currencySymbol = "Br", + cctld = "by", + flagEmoji = "🇧🇾", + phoneCode = 375, + ), + CountryInfo( + alpha2 = "BZ", + alpha3 = "BLZ", + englishName = "Belize", + demonym = "Belizeans", + capitalEnglishName = "Belmopan", + areaKM2 = "22966", + population = 397628, + currencyCode = "BZD", + currencyName = "Belize Dollar", + currencySymbol = "$", + cctld = "bz", + flagEmoji = "🇧🇿", + phoneCode = 501, + ), + CountryInfo( + alpha2 = "CA", + alpha3 = "CAN", + englishName = "Canada", + demonym = "Canadians", + capitalEnglishName = "Ottawa", + areaKM2 = "9984670", + population = 37742154, + currencyCode = "CAD", + currencyName = "Canadian Dollar", + currencySymbol = "$", + cctld = "ca", + flagEmoji = "🇨🇦", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "CC", + alpha3 = "CCK", + englishName = "Cocos (Keeling) Islands", + demonym = "Cocos Islanders", + capitalEnglishName = "West Island", + areaKM2 = "14", + population = 555, + currencyCode = "AUD", + currencyName = "Australian Dollar", + currencySymbol = "$", + cctld = "cc", + flagEmoji = "🇨🇨", + phoneCode = 61, + ), + CountryInfo( + alpha2 = "CD", + alpha3 = "COD", + englishName = "Congo (Democratic Republic of the)", + demonym = "Congolese", + capitalEnglishName = "Kinshasa", + areaKM2 = "2344858", + population = 89561403, + currencyCode = "CDF", + currencyName = "Congolese Franc", + currencySymbol = "FCFA", + cctld = "cd", + flagEmoji = "🇨🇩", + phoneCode = 243, + ), + CountryInfo( + alpha2 = "CF", + alpha3 = "CAF", + englishName = "Central African Republic", + demonym = "Central Africans", + capitalEnglishName = "Bangui", + areaKM2 = "622984", + population = 4829767, + currencyCode = "XAF", + currencyName = "Cfa Franc Beac", + currencySymbol = "FCFA", + cctld = "cf", + flagEmoji = "🇨🇫", + phoneCode = 236, + ), + CountryInfo( + alpha2 = "CG", + alpha3 = "COG", + englishName = "Congo", + demonym = "Congolese", + capitalEnglishName = "Brazzaville", + areaKM2 = "342000", + population = 5518087, + currencyCode = "XAF", + currencyName = "Cfa Franc Beac", + currencySymbol = "FCFA", + cctld = "cg", + flagEmoji = "🇨🇬", + phoneCode = 242, + ), + CountryInfo( + alpha2 = "CH", + alpha3 = "CHE", + englishName = "Switzerland", + demonym = "Swiss", + capitalEnglishName = "Bern", + areaKM2 = "41277", + population = 8654622, + currencyCode = "CHF", + currencyName = "Swiss Franc", + currencySymbol = "Fr.", + cctld = "ch", + flagEmoji = "🇨🇭", + phoneCode = 41, + ), + CountryInfo( + alpha2 = "CI", + alpha3 = "CIV", + englishName = "Cote d'Ivoire", + demonym = "Ivorians", + capitalEnglishName = "Yamoussoukro", + areaKM2 = "322463", + population = 26378274, + currencyCode = "XOF", + currencyName = "Cfa Franc Bceao", + currencySymbol = "CFA", + cctld = "ci", + flagEmoji = "🇨🇮", + phoneCode = 225, + ), + CountryInfo( + alpha2 = "CK", + alpha3 = "COK", + englishName = "Cook Islands", + demonym = "Cook Islanders", + capitalEnglishName = "Avarua", + areaKM2 = "236", + population = 17564, + currencyCode = "NZD", + currencyName = "New Zealand Dollar", + currencySymbol = "$", + cctld = "ck", + flagEmoji = "🇨🇰", + phoneCode = 682, + ), + CountryInfo( + alpha2 = "CL", + alpha3 = "CHL", + englishName = "Chile", + demonym = "Chileans", + capitalEnglishName = "Santiago", + areaKM2 = "756102", + population = 19116201, + currencyCode = "CLP", + currencyName = "Chilean Peso", + currencySymbol = "$", + cctld = "cl", + flagEmoji = "🇨🇱", + phoneCode = 56, + ), + CountryInfo( + alpha2 = "CM", + alpha3 = "CMR", + englishName = "Cameroon", + demonym = "Cameroonians", + capitalEnglishName = "Yaounde", + areaKM2 = "475440", + population = 26545863, + currencyCode = "XAF", + currencyName = "Cfa Franc Beac", + currencySymbol = "FCFA", + cctld = "cm", + flagEmoji = "🇨🇲", + phoneCode = 237, + ), + CountryInfo( + alpha2 = "CN", + alpha3 = "CHN", + englishName = "China", + demonym = "Chinese", + capitalEnglishName = "Beijing", + areaKM2 = "9596961", + population = 1439323776, + currencyCode = "CNY", + currencyName = "Chinese Yuan Renminbi", + currencySymbol = "¥", + cctld = "cn", + flagEmoji = "🇨🇳", + phoneCode = 86, + ), + CountryInfo( + alpha2 = "CO", + alpha3 = "COL", + englishName = "Colombia", + demonym = "Colombians", + capitalEnglishName = "Bogota", + areaKM2 = "1138910", + population = 50882891, + currencyCode = "COP", + currencyName = "Colombian Peso", + currencySymbol = "$", + cctld = "co", + flagEmoji = "🇨🇴", + phoneCode = 57, + ), + CountryInfo( + alpha2 = "CR", + alpha3 = "CRI", + englishName = "Costa Rica", + demonym = "Costa Ricans", + capitalEnglishName = "San Jose", + areaKM2 = "51100", + population = 5094118, + currencyCode = "CRC", + currencyName = "Costa Rican Colon", + currencySymbol = "₡", + cctld = "cr", + flagEmoji = "🇨🇷", + phoneCode = 506, + ), + CountryInfo( + alpha2 = "CU", + alpha3 = "CUB", + englishName = "Cuba", + demonym = "Cubans", + capitalEnglishName = "Havana", + areaKM2 = "110860", + population = 11326616, + currencyCode = "CUC", + currencyName = "Cuban Convertible Peso", + currencySymbol = "$", + cctld = "cu", + flagEmoji = "🇨🇺", + phoneCode = 53, + ), + CountryInfo( + alpha2 = "CV", + alpha3 = "CPV", + englishName = "Cabo Verde", + demonym = "Cabo Verdeans", + capitalEnglishName = "Praia", + areaKM2 = "4033", + population = 555987, + currencyCode = "CVE", + currencyName = "Cape Verde Escudo", + currencySymbol = "$", + cctld = "cv", + flagEmoji = "🇨🇻", + phoneCode = 238, + ), + CountryInfo( + alpha2 = "CW", + alpha3 = "CUW", + englishName = "Curaçao", + demonym = "Curacaoans", + capitalEnglishName = "Willemstad", + areaKM2 = "444", + population = 164093, + currencyCode = "ANG", + currencyName = "Nl Antillian Guilder", + currencySymbol = "ƒ", + cctld = "cw", + flagEmoji = "🇨🇼", + phoneCode = 599, + ), + CountryInfo( + alpha2 = "CX", + alpha3 = "CXR", + englishName = "Christmas Island", + demonym = "Christmas Islanders", + capitalEnglishName = "Flying Fish Cove", + areaKM2 = "135", + population = 1955, + currencyCode = "AUD", + currencyName = "Australian Dollar", + currencySymbol = "$", + cctld = "cx", + flagEmoji = "🇨🇽", + phoneCode = 61, + ), + CountryInfo( + alpha2 = "CY", + alpha3 = "CYP", + englishName = "Cyprus", + demonym = "Cypriots", + capitalEnglishName = "Nicosia", + areaKM2 = "9251", + population = 1207359, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "cy", + flagEmoji = "🇨🇾", + phoneCode = 357, + ), + CountryInfo( + alpha2 = "CZ", + alpha3 = "CZE", + englishName = "Czechia", + demonym = "Czechs", + capitalEnglishName = "Prague", + areaKM2 = "78867", + population = 10708981, + currencyCode = "CZK", + currencyName = "Czech Koruna", + currencySymbol = "Kč", + cctld = "cz", + flagEmoji = "🇨🇿", + phoneCode = 420, + ), + CountryInfo( + alpha2 = "DE", + alpha3 = "DEU", + englishName = "Germany", + demonym = "Germans", + capitalEnglishName = "Berlin", + areaKM2 = "357022", + population = 83783942, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "de", + flagEmoji = "🇩🇪", + phoneCode = 49, + ), + CountryInfo( + alpha2 = "DJ", + alpha3 = "DJI", + englishName = "Djibouti", + demonym = "Djiboutians", + capitalEnglishName = "Djibouti", + areaKM2 = "23200", + population = 988000, + currencyCode = "DJF", + currencyName = "Djiboutian Franc", + currencySymbol = "Fdj", + cctld = "dj", + flagEmoji = "🇩🇯", + phoneCode = 253, + ), + CountryInfo( + alpha2 = "DK", + alpha3 = "DNK", + englishName = "Denmark", + demonym = "Danes", + capitalEnglishName = "Copenhagen", + areaKM2 = "43094", + population = 5792202, + currencyCode = "DKK", + currencyName = "Danish Krone", + currencySymbol = "kr.", + cctld = "dk", + flagEmoji = "🇩🇰", + phoneCode = 45, + ), + CountryInfo( + alpha2 = "DM", + alpha3 = "DMA", + englishName = "Dominica", + demonym = "Dominicans", + capitalEnglishName = "Roseau", + areaKM2 = "751", + population = 71986, + currencyCode = "XCD", + currencyName = "East Caribbean Dollar", + currencySymbol = "$", + cctld = "dm", + flagEmoji = "🇩🇲", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "DO", + alpha3 = "DOM", + englishName = "Dominican Republic", + demonym = "Dominicans", + capitalEnglishName = "Santo Domingo", + areaKM2 = "48670", + population = 10847910, + currencyCode = "DOP", + currencyName = "Dominican Peso", + currencySymbol = "$", + cctld = "do", + flagEmoji = "🇩🇴", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "DZ", + alpha3 = "DZA", + englishName = "Algeria", + demonym = "Algerians", + capitalEnglishName = "Algiers", + areaKM2 = "2381741", + population = 43851044, + currencyCode = "DZD", + currencyName = "Algerian Dinar", + currencySymbol = "DA", + cctld = "dz", + flagEmoji = "🇩🇿", + phoneCode = 213, + ), + CountryInfo( + alpha2 = "EC", + alpha3 = "ECU", + englishName = "Ecuador", + demonym = "Ecuadorians", + capitalEnglishName = "Quito", + areaKM2 = "283561", + population = 17643054, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "ec", + flagEmoji = "🇪🇨", + phoneCode = 593, + ), + CountryInfo( + alpha2 = "EE", + alpha3 = "EST", + englishName = "Estonia", + demonym = "Estonians", + capitalEnglishName = "Tallinn", + areaKM2 = "45228", + population = 1326535, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "ee", + flagEmoji = "🇪🇪", + phoneCode = 372, + ), + CountryInfo( + alpha2 = "EG", + alpha3 = "EGY", + englishName = "Egypt", + demonym = "Egyptians", + capitalEnglishName = "Cairo", + areaKM2 = "1001450", + population = 102334404, + currencyCode = "EGP", + currencyName = "Egyptian Pound", + currencySymbol = "E£", + cctld = "eg", + flagEmoji = "🇪🇬", + phoneCode = 20, + ), + CountryInfo( + alpha2 = "EH", + alpha3 = "ESH", + englishName = "Western Sahara", + demonym = "Sahrawis", + capitalEnglishName = "Laayoune / El Aaiun", + areaKM2 = "266000", + population = 597339, + currencyCode = "MAD", + currencyName = "Moroccan Dirham", + currencySymbol = "DH", + cctld = "eh", + flagEmoji = "🇪🇭", + phoneCode = 212, + ), + CountryInfo( + alpha2 = "ER", + alpha3 = "ERI", + englishName = "Eritrea", + demonym = "Eritreans", + capitalEnglishName = "Asmara", + areaKM2 = "117600", + population = 3546421, + currencyCode = "ERN", + currencyName = "Eritrean Nakfa", + currencySymbol = "Nkf", + cctld = "er", + flagEmoji = "🇪🇷", + phoneCode = 291, + ), + CountryInfo( + alpha2 = "ES", + alpha3 = "ESP", + englishName = "Spain", + demonym = "Spaniards", + capitalEnglishName = "Madrid", + areaKM2 = "505370", + population = 46754778, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "es", + flagEmoji = "🇪🇸", + phoneCode = 34, + ), + CountryInfo( + alpha2 = "ET", + alpha3 = "ETH", + englishName = "Ethiopia", + demonym = "Ethiopians", + capitalEnglishName = "Addis Ababa", + areaKM2 = "1104300", + population = 114963588, + currencyCode = "ETB", + currencyName = "Ethiopian Birr", + currencySymbol = "Br", + cctld = "et", + flagEmoji = "🇪🇹", + phoneCode = 251, + ), + CountryInfo( + alpha2 = "FI", + alpha3 = "FIN", + englishName = "Finland", + demonym = "Finns", + capitalEnglishName = "Helsinki", + areaKM2 = "338145", + population = 5540720, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "fi", + flagEmoji = "🇫🇮", + phoneCode = 358, + ), + CountryInfo( + alpha2 = "FJ", + alpha3 = "FJI", + englishName = "Fiji", + demonym = "Fijians", + capitalEnglishName = "Suva", + areaKM2 = "18274", + population = 896445, + currencyCode = "FJD", + currencyName = "Fijian Dollar", + currencySymbol = "$", + cctld = "fj", + flagEmoji = "🇫🇯", + phoneCode = 679, + ), + CountryInfo( + alpha2 = "FK", + alpha3 = "FLK", + englishName = "Falkland Islands (Malvinas)", + demonym = "Falkland Islanders", + capitalEnglishName = "Stanley", + areaKM2 = "12173", + population = 3480, + currencyCode = "FKP", + currencyName = "Falkland Islands Pound", + currencySymbol = "£", + cctld = "fk", + flagEmoji = "🇫🇰", + phoneCode = 500, + ), + CountryInfo( + alpha2 = "FM", + alpha3 = "FSM", + englishName = "Micronesia (Federated States of)", + demonym = "Micronesians", + capitalEnglishName = "Palikir", + areaKM2 = "702", + population = 548914, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "fm", + flagEmoji = "🇫🇲", + phoneCode = 691, + ), + CountryInfo( + alpha2 = "FO", + alpha3 = "FRO", + englishName = "Faroe Islands", + demonym = "Faroese", + capitalEnglishName = "Torshavn", + areaKM2 = "1393", + population = 48863, + currencyCode = "DKK", + currencyName = "Danish Krone", + currencySymbol = "kr", + cctld = "fo", + flagEmoji = "🇫🇴", + phoneCode = 298, + ), + CountryInfo( + alpha2 = "FR", + alpha3 = "FRA", + englishName = "France", + demonym = "French", + capitalEnglishName = "Paris", + areaKM2 = "643801", + population = 65273511, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "fr", + flagEmoji = "🇫🇷", + phoneCode = 33, + ), + CountryInfo( + alpha2 = "GA", + alpha3 = "GAB", + englishName = "Gabon", + demonym = "Gabonese", + capitalEnglishName = "Libreville", + areaKM2 = "267667", + population = 2225734, + currencyCode = "XAF", + currencyName = "Cfa Franc Beac", + currencySymbol = "FCFA", + cctld = "ga", + flagEmoji = "🇬🇦", + phoneCode = 241, + ), + CountryInfo( + alpha2 = "GB", + alpha3 = "GBR", + englishName = "United Kingdom of Great Britain and Northern Ireland", + demonym = "British", + capitalEnglishName = "London", + areaKM2 = "243610", + population = 67886011, + currencyCode = "GBP", + currencyName = "British Pound", + currencySymbol = "£", + cctld = "gb", + flagEmoji = "🇬🇧", + phoneCode = 44, + ), + CountryInfo( + alpha2 = "GD", + alpha3 = "GRD", + englishName = "Grenada", + demonym = "Grenadians", + capitalEnglishName = "Saint George's", + areaKM2 = "344", + population = 112523, + currencyCode = "XCD", + currencyName = "East Caribbean Dollar", + currencySymbol = "$", + cctld = "gd", + flagEmoji = "🇬🇩", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "GE", + alpha3 = "GEO", + englishName = "Georgia", + demonym = "Georgians", + capitalEnglishName = "Tbilisi", + areaKM2 = "69700", + population = 3989167, + currencyCode = "GEL", + currencyName = "Georgian Lari", + currencySymbol = "₾", + cctld = "ge", + flagEmoji = "🇬🇪", + phoneCode = 995, + ), + CountryInfo( + alpha2 = "GF", + alpha3 = "GUF", + englishName = "French Guiana", + demonym = "French Guianese", + capitalEnglishName = "Cayenne", + areaKM2 = "86504", + population = 298682, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "gf", + flagEmoji = "🇬🇫", + phoneCode = 594, + ), + CountryInfo( + alpha2 = "GG", + alpha3 = "GGY", + englishName = "Guernsey", + demonym = "Channel Islanders", + capitalEnglishName = "Saint Peter Port", + areaKM2 = "78", + population = 63155, + currencyCode = "GBP", + currencyName = "Pound Sterling", + currencySymbol = "£", + cctld = "gg", + flagEmoji = "🇬🇬", + phoneCode = 44, + ), + CountryInfo( + alpha2 = "GH", + alpha3 = "GHA", + englishName = "Ghana", + demonym = "Ghanaians", + capitalEnglishName = "Accra", + areaKM2 = "238533", + population = 31072940, + currencyCode = "GHS", + currencyName = "Ghanaian New Cedi", + currencySymbol = "GH₵", + cctld = "gh", + flagEmoji = "🇬🇭", + phoneCode = 233, + ), + CountryInfo( + alpha2 = "GI", + alpha3 = "GIB", + englishName = "Gibraltar", + demonym = "Gibraltarians", + capitalEnglishName = "Gibraltar", + areaKM2 = "6", + population = 33691, + currencyCode = "GIP", + currencyName = "Gibraltar Pound", + currencySymbol = "£", + cctld = "gi", + flagEmoji = "🇬🇮", + phoneCode = 350, + ), + CountryInfo( + alpha2 = "GL", + alpha3 = "GRL", + englishName = "Greenland", + demonym = "Greenlanders", + capitalEnglishName = "Nuuk", + areaKM2 = "2166086", + population = 56770, + currencyCode = "DKK", + currencyName = "Danish Krone", + currencySymbol = "kr.", + cctld = "gl", + flagEmoji = "🇬🇱", + phoneCode = 299, + ), + CountryInfo( + alpha2 = "GM", + alpha3 = "GMB", + englishName = "Gambia", + demonym = "Gambians", + capitalEnglishName = "Banjul", + areaKM2 = "11295", + population = 2416668, + currencyCode = "GMD", + currencyName = "Gambian Dalasi", + currencySymbol = "D", + cctld = "gm", + flagEmoji = "🇬🇲", + phoneCode = 220, + ), + CountryInfo( + alpha2 = "GN", + alpha3 = "GIN", + englishName = "Guinea", + demonym = "Guineans", + capitalEnglishName = "Conakry", + areaKM2 = "245857", + population = 13132795, + currencyCode = "GNF", + currencyName = "Guinean Franc", + currencySymbol = "FG", + cctld = "gn", + flagEmoji = "🇬🇳", + phoneCode = 224, + ), + CountryInfo( + alpha2 = "GP", + alpha3 = "GLP", + englishName = "Guadeloupe", + demonym = "Guadeloupians", + capitalEnglishName = "Basse-terre", + areaKM2 = "1630", + population = 400124, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "gp", + flagEmoji = "🇬🇵", + phoneCode = 590, + ), + CountryInfo( + alpha2 = "GQ", + alpha3 = "GNQ", + englishName = "Equatorial Guinea", + demonym = "Equatorial Guineans", + capitalEnglishName = "Malabo", + areaKM2 = "28051", + population = 1402985, + currencyCode = "XAF", + currencyName = "Cfa Franc Beac", + currencySymbol = "FCFA", + cctld = "gq", + flagEmoji = "🇬🇶", + phoneCode = 240, + ), + CountryInfo( + alpha2 = "GR", + alpha3 = "GRC", + englishName = "Greece", + demonym = "Greeks", + capitalEnglishName = "Athens", + areaKM2 = "131957", + population = 10423054, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "gr", + flagEmoji = "🇬🇷", + phoneCode = 30, + ), + CountryInfo( + alpha2 = "GS", + alpha3 = "SGS", + englishName = "South Georgia and the South Sandwich Islands", + demonym = "South Georgian or South Sandwich Islander", + capitalEnglishName = "Grytviken", + areaKM2 = "3903", + population = 0, + currencyCode = "GBP", + currencyName = "Pound Sterling", + currencySymbol = "£", + cctld = "gs", + flagEmoji = "🇬🇸", + phoneCode = 500, + ), + CountryInfo( + alpha2 = "GT", + alpha3 = "GTM", + englishName = "Guatemala", + demonym = "Guatemalans", + capitalEnglishName = "Guatemala City", + areaKM2 = "108889", + population = 17915568, + currencyCode = "GTQ", + currencyName = "Guatemalan Quetzal", + currencySymbol = "Q", + cctld = "gt", + flagEmoji = "🇬🇹", + phoneCode = 502, + ), + CountryInfo( + alpha2 = "GU", + alpha3 = "GUM", + englishName = "Guam", + demonym = "Guamanians", + capitalEnglishName = "Hagatna", + areaKM2 = "544", + population = 168775, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "gu", + flagEmoji = "🇬🇺", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "GW", + alpha3 = "GNB", + englishName = "Guinea-Bissau", + demonym = "Bissau-Guineans", + capitalEnglishName = "Bissau", + areaKM2 = "36125", + population = 1968001, + currencyCode = "XOF", + currencyName = "Cfa Franc Bceao", + currencySymbol = "CFA", + cctld = "gw", + flagEmoji = "🇬🇼", + phoneCode = 245, + ), + CountryInfo( + alpha2 = "GY", + alpha3 = "GUY", + englishName = "Guyana", + demonym = "Guyanese", + capitalEnglishName = "Georgetown", + areaKM2 = "214969", + population = 786552, + currencyCode = "GYD", + currencyName = "Guyanese Dollar", + currencySymbol = "$", + cctld = "gy", + flagEmoji = "🇬🇾", + phoneCode = 592, + ), + CountryInfo( + alpha2 = "HK", + alpha3 = "HKG", + englishName = "Hong Kong", + demonym = "Hong Kongese", + capitalEnglishName = "-", + areaKM2 = "1104", + population = 7496981, + currencyCode = "HKD", + currencyName = "Hong Kong Dollar", + currencySymbol = "$", + cctld = "hk", + flagEmoji = "🇭🇰", + phoneCode = 852, + ), + CountryInfo( + alpha2 = "HM", + alpha3 = "HMD", + englishName = "Heard Island and McDonald Islands", + demonym = "Heard Islanders or McDonald Islanders", + capitalEnglishName = "-", + areaKM2 = "412", + population = 0, + currencyCode = "AUD", + currencyName = "Australian Dollar", + currencySymbol = "$", + cctld = "hm", + flagEmoji = "🇭🇲", + phoneCode = 672, + ), + CountryInfo( + alpha2 = "HN", + alpha3 = "HND", + englishName = "Honduras", + demonym = "Hondurans", + capitalEnglishName = "Tegucigalpa", + areaKM2 = "112090", + population = 9904607, + currencyCode = "HNL", + currencyName = "Honduran Lempira", + currencySymbol = "L", + cctld = "hn", + flagEmoji = "🇭🇳", + phoneCode = 504, + ), + CountryInfo( + alpha2 = "HR", + alpha3 = "HRV", + englishName = "Croatia", + demonym = "Croatians", + capitalEnglishName = "Zagreb", + areaKM2 = "56594", + population = 4105267, + currencyCode = "HRK", + currencyName = "Croatian Kuna", + currencySymbol = "kn", + cctld = "hr", + flagEmoji = "🇭🇷", + phoneCode = 385, + ), + CountryInfo( + alpha2 = "HT", + alpha3 = "HTI", + englishName = "Haiti", + demonym = "Haitians", + capitalEnglishName = "Port-au-prince", + areaKM2 = "27750", + population = 11402528, + currencyCode = "HTG", + currencyName = "Haitian Gourde", + currencySymbol = "G", + cctld = "ht", + flagEmoji = "🇭🇹", + phoneCode = 509, + ), + CountryInfo( + alpha2 = "HU", + alpha3 = "HUN", + englishName = "Hungary", + demonym = "Hungarians", + capitalEnglishName = "Budapest", + areaKM2 = "93028", + population = 9660351, + currencyCode = "HUF", + currencyName = "Hungarian Forint", + currencySymbol = "Ft", + cctld = "hu", + flagEmoji = "🇭🇺", + phoneCode = 36, + ), + CountryInfo( + alpha2 = "ID", + alpha3 = "IDN", + englishName = "Indonesia", + demonym = "Indonesians", + capitalEnglishName = "Jakarta", + areaKM2 = "1904569", + population = 273523615, + currencyCode = "IDR", + currencyName = "Indonesian Rupiah", + currencySymbol = "Rp", + cctld = "id", + flagEmoji = "🇮🇩", + phoneCode = 62, + ), + CountryInfo( + alpha2 = "IE", + alpha3 = "IRL", + englishName = "Ireland", + demonym = "Irish", + capitalEnglishName = "Dublin", + areaKM2 = "70273", + population = 4937786, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "ie", + flagEmoji = "🇮🇪", + phoneCode = 353, + ), + CountryInfo( + alpha2 = "IL", + alpha3 = "ISR", + englishName = "Israel", + demonym = "Israelis", + capitalEnglishName = "Jerusalem", + areaKM2 = "20770", + population = 8655535, + currencyCode = "ILS", + currencyName = "Israeli New Shekel", + currencySymbol = "₪", + cctld = "il", + flagEmoji = "🇮🇱", + phoneCode = 972, + ), + CountryInfo( + alpha2 = "IM", + alpha3 = "IMN", + englishName = "Isle of Man", + demonym = "Manx", + capitalEnglishName = "Douglas", + areaKM2 = "572", + population = 85033, + currencyCode = "GBP", + currencyName = "British Pound", + currencySymbol = "£", + cctld = "im", + flagEmoji = "🇮🇲", + phoneCode = 44, + ), + CountryInfo( + alpha2 = "IN", + alpha3 = "IND", + englishName = "India", + demonym = "Indians", + capitalEnglishName = "New Delhi", + areaKM2 = "3287263", + population = 1380004385, + currencyCode = "INR", + currencyName = "Indian Rupee", + currencySymbol = "₹", + cctld = "in", + flagEmoji = "🇮🇳", + phoneCode = 91, + ), + CountryInfo( + alpha2 = "IO", + alpha3 = "IOT", + englishName = "British Indian Ocean Territory", + demonym = "British", + capitalEnglishName = "Diego Garcia", + areaKM2 = "54400", + population = 3000, + currencyCode = "GBP", + currencyName = "British Pound", + currencySymbol = "£", + cctld = "io", + flagEmoji = "🇮🇴", + phoneCode = 246, + ), + CountryInfo( + alpha2 = "IQ", + alpha3 = "IRQ", + englishName = "Iraq", + demonym = "Iraqis", + capitalEnglishName = "Baghdad", + areaKM2 = "438317", + population = 40222493, + currencyCode = "IQD", + currencyName = "Iraqi Dinar", + currencySymbol = "د.ع", + cctld = "iq", + flagEmoji = "🇮🇶", + phoneCode = 964, + ), + CountryInfo( + alpha2 = "IR", + alpha3 = "IRN", + englishName = "Iran (Islamic Republic of)", + demonym = "Iranians", + capitalEnglishName = "Tehran", + areaKM2 = "1648195", + population = 83992949, + currencyCode = "IRR", + currencyName = "Iranian Rial", + currencySymbol = "﷼", + cctld = "ir", + flagEmoji = "🇮🇷", + phoneCode = 98, + ), + CountryInfo( + alpha2 = "IS", + alpha3 = "ISL", + englishName = "Iceland", + demonym = "Icelanders", + capitalEnglishName = "Reykjavik", + areaKM2 = "103000", + population = 341243, + currencyCode = "ISK", + currencyName = "Iceland Krona", + currencySymbol = "kr", + cctld = "is", + flagEmoji = "🇮🇸", + phoneCode = 354, + ), + CountryInfo( + alpha2 = "IT", + alpha3 = "ITA", + englishName = "Italy", + demonym = "Italians", + capitalEnglishName = "Roma", + areaKM2 = "301340", + population = 60461826, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "it", + flagEmoji = "🇮🇹", + phoneCode = 39, + ), + CountryInfo( + alpha2 = "JE", + alpha3 = "JEY", + englishName = "Jersey", + demonym = "Channel Islanders", + capitalEnglishName = "Saint Helier", + areaKM2 = "116", + population = 107800, + currencyCode = "GBP", + currencyName = "British Pound", + currencySymbol = "£", + cctld = "je", + flagEmoji = "🇯🇪", + phoneCode = 44, + ), + CountryInfo( + alpha2 = "JM", + alpha3 = "JAM", + englishName = "Jamaica", + demonym = "Jamaicans", + capitalEnglishName = "Kingston", + areaKM2 = "10991", + population = 2961167, + currencyCode = "JMD", + currencyName = "Jamaican Dollar", + currencySymbol = "$", + cctld = "jm", + flagEmoji = "🇯🇲", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "JO", + alpha3 = "JOR", + englishName = "Jordan", + demonym = "Jordanians", + capitalEnglishName = "Amman", + areaKM2 = "89342", + population = 10203134, + currencyCode = "JOD", + currencyName = "Jordanian Dinar", + currencySymbol = "د.أ", + cctld = "jo", + flagEmoji = "🇯🇴", + phoneCode = 962, + ), + CountryInfo( + alpha2 = "JP", + alpha3 = "JPN", + englishName = "Japan", + demonym = "Japanese", + capitalEnglishName = "Tokyo", + areaKM2 = "377915", + population = 126476461, + currencyCode = "JPY", + currencyName = "Japanese Yen", + currencySymbol = "¥", + cctld = "jp", + flagEmoji = "🇯🇵", + phoneCode = 81, + ), + CountryInfo( + alpha2 = "KE", + alpha3 = "KEN", + englishName = "Kenya", + demonym = "Kenyans", + capitalEnglishName = "Nairobi", + areaKM2 = "580367", + population = 53771296, + currencyCode = "KES", + currencyName = "Kenyan Shilling", + currencySymbol = "KSh", + cctld = "ke", + flagEmoji = "🇰🇪", + phoneCode = 254, + ), + CountryInfo( + alpha2 = "KG", + alpha3 = "KGZ", + englishName = "Kyrgyzstan", + demonym = "Kyrgyzstanis", + capitalEnglishName = "Bishkek", + areaKM2 = "199951", + population = 6524195, + currencyCode = "KGS", + currencyName = "Kyrgyzstani Som", + currencySymbol = "Лв", + cctld = "kg", + flagEmoji = "🇰🇬", + phoneCode = 996, + ), + CountryInfo( + alpha2 = "KH", + alpha3 = "KHM", + englishName = "Cambodia", + demonym = "Cambodians", + capitalEnglishName = "Phnom Penh", + areaKM2 = "181035", + population = 16718965, + currencyCode = "KHR", + currencyName = "Cambodian Riel", + currencySymbol = "៛", + cctld = "kh", + flagEmoji = "🇰🇭", + phoneCode = 855, + ), + CountryInfo( + alpha2 = "KI", + alpha3 = "KIR", + englishName = "Kiribati", + demonym = "I-Kiribati", + capitalEnglishName = "Tarawa", + areaKM2 = "811", + population = 119449, + currencyCode = "AUD", + currencyName = "Australian Dollar", + currencySymbol = "$", + cctld = "ki", + flagEmoji = "🇰🇮", + phoneCode = 686, + ), + CountryInfo( + alpha2 = "KM", + alpha3 = "COM", + englishName = "Comoros", + demonym = "Comorans", + capitalEnglishName = "Moroni", + areaKM2 = "2235", + population = 869601, + currencyCode = "KMF", + currencyName = "Comoro Franc", + currencySymbol = "CF", + cctld = "km", + flagEmoji = "🇰🇲", + phoneCode = 269, + ), + CountryInfo( + alpha2 = "KN", + alpha3 = "KNA", + englishName = "Saint Kitts and Nevis", + demonym = "Kittitians or Nevisians", + capitalEnglishName = "Basseterre", + areaKM2 = "261", + population = 53199, + currencyCode = "XCD", + currencyName = "East Caribbean Dollar", + currencySymbol = "$", + cctld = "kn", + flagEmoji = "🇰🇳", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "KP", + alpha3 = "PRK", + englishName = "Korea (Democratic People's Republic of)", + demonym = "Koreans", + capitalEnglishName = "Pyongyang", + areaKM2 = "120538", + population = 25778816, + currencyCode = "KPW", + currencyName = "North Korean Won", + currencySymbol = "₩", + cctld = "kp", + flagEmoji = "🇰🇵", + phoneCode = 850, + ), + CountryInfo( + alpha2 = "KR", + alpha3 = "KOR", + englishName = "Korea (Republic of)", + demonym = "Koreans", + capitalEnglishName = "Seoul", + areaKM2 = "99720", + population = 51269185, + currencyCode = "KRW", + currencyName = "South-korean Won", + currencySymbol = "₩", + cctld = "kr", + flagEmoji = "🇰🇷", + phoneCode = 82, + ), + CountryInfo( + alpha2 = "KW", + alpha3 = "KWT", + englishName = "Kuwait", + demonym = "Kuwaitis", + capitalEnglishName = "Kuwait", + areaKM2 = "17818", + population = 4270571, + currencyCode = "KWD", + currencyName = "Kuwaiti Dinar", + currencySymbol = "KD", + cctld = "kw", + flagEmoji = "🇰🇼", + phoneCode = 965, + ), + CountryInfo( + alpha2 = "KY", + alpha3 = "CYM", + englishName = "Cayman Islands", + demonym = "Caymanians", + capitalEnglishName = "George Town", + areaKM2 = "264", + population = 65722, + currencyCode = "KYD", + currencyName = "Cayman Islands Dollar", + currencySymbol = "$", + cctld = "ky", + flagEmoji = "🇰🇾", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "KZ", + alpha3 = "KAZ", + englishName = "Kazakhstan", + demonym = "Kazakhstanis", + capitalEnglishName = "Astana", + areaKM2 = "2724900", + population = 18776707, + currencyCode = "KZT", + currencyName = "Kazakhstani Tenge", + currencySymbol = "₸", + cctld = "kz", + flagEmoji = "🇰🇿", + phoneCode = 7, + ), + CountryInfo( + alpha2 = "LA", + alpha3 = "LAO", + englishName = "Lao People's Democratic Republic", + demonym = "Laos", + capitalEnglishName = "Vientiane", + areaKM2 = "236800", + population = 7275560, + currencyCode = "LAK", + currencyName = "Lao Kip", + currencySymbol = "₭", + cctld = "la", + flagEmoji = "🇱🇦", + phoneCode = 856, + ), + CountryInfo( + alpha2 = "LB", + alpha3 = "LBN", + englishName = "Lebanon", + demonym = "Lebanese", + capitalEnglishName = "Beirut", + areaKM2 = "10400", + population = 6825445, + currencyCode = "LBP", + currencyName = "Lebanese Pound", + currencySymbol = "LL", + cctld = "lb", + flagEmoji = "🇱🇧", + phoneCode = 961, + ), + CountryInfo( + alpha2 = "LC", + alpha3 = "LCA", + englishName = "Saint Lucia", + demonym = "Saint Lucians", + capitalEnglishName = "Castries", + areaKM2 = "616", + population = 183627, + currencyCode = "XCD", + currencyName = "East Caribbean Dollar", + currencySymbol = "$", + cctld = "lc", + flagEmoji = "🇱🇨", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "LI", + alpha3 = "LIE", + englishName = "Liechtenstein", + demonym = "Liechtensteiners", + capitalEnglishName = "Vaduz", + areaKM2 = "160", + population = 38128, + currencyCode = "CHF", + currencyName = "Swiss Franc", + currencySymbol = "Fr.", + cctld = "li", + flagEmoji = "🇱🇮", + phoneCode = 423, + ), + CountryInfo( + alpha2 = "LK", + alpha3 = "LKA", + englishName = "Sri Lanka", + demonym = "Sri Lankans", + capitalEnglishName = "Sri Jayewardenepura Kotte", + areaKM2 = "65610", + population = 21413249, + currencyCode = "LKR", + currencyName = "Sri Lanka Rupee", + currencySymbol = "රු", + cctld = "lk", + flagEmoji = "🇱🇰", + phoneCode = 94, + ), + CountryInfo( + alpha2 = "LR", + alpha3 = "LBR", + englishName = "Liberia", + demonym = "Liberians", + capitalEnglishName = "Monrovia", + areaKM2 = "111369", + population = 5057681, + currencyCode = "LRD", + currencyName = "Liberian Dollar", + currencySymbol = "$", + cctld = "lr", + flagEmoji = "🇱🇷", + phoneCode = 231, + ), + CountryInfo( + alpha2 = "LS", + alpha3 = "LSO", + englishName = "Lesotho", + demonym = "Basotho", + capitalEnglishName = "Maseru", + areaKM2 = "30355", + population = 2142249, + currencyCode = "LSL", + currencyName = "Lesotho Loti", + currencySymbol = "M", + cctld = "ls", + flagEmoji = "🇱🇸", + phoneCode = 266, + ), + CountryInfo( + alpha2 = "LT", + alpha3 = "LTU", + englishName = "Lithuania", + demonym = "Lithuanians", + capitalEnglishName = "Vilnius", + areaKM2 = "65300", + population = 2722289, + currencyCode = "LTL", + currencyName = "Lithuanian Litas", + currencySymbol = "Lt", + cctld = "lt", + flagEmoji = "🇱🇹", + phoneCode = 370, + ), + CountryInfo( + alpha2 = "LU", + alpha3 = "LUX", + englishName = "Luxembourg", + demonym = "Luxembourgers", + capitalEnglishName = "Luxembourg", + areaKM2 = "2586", + population = 625978, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "lu", + flagEmoji = "🇱🇺", + phoneCode = 352, + ), + CountryInfo( + alpha2 = "LV", + alpha3 = "LVA", + englishName = "Latvia", + demonym = "Latvians", + capitalEnglishName = "Riga", + areaKM2 = "64589", + population = 1886198, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "lv", + flagEmoji = "🇱🇻", + phoneCode = 371, + ), + CountryInfo( + alpha2 = "LY", + alpha3 = "LBY", + englishName = "Libya", + demonym = "Libyans", + capitalEnglishName = "Tripoli", + areaKM2 = "1759540", + population = 6871292, + currencyCode = "LYD", + currencyName = "Libyan Dinar", + currencySymbol = "LD", + cctld = "ly", + flagEmoji = "🇱🇾", + phoneCode = 218, + ), + CountryInfo( + alpha2 = "MA", + alpha3 = "MAR", + englishName = "Morocco", + demonym = "Moroccans", + capitalEnglishName = "Rabat", + areaKM2 = "446550", + population = 36910560, + currencyCode = "MAD", + currencyName = "Moroccan Dirham", + currencySymbol = "DH", + cctld = "ma", + flagEmoji = "🇲🇦", + phoneCode = 212, + ), + CountryInfo( + alpha2 = "MC", + alpha3 = "MCO", + englishName = "Monaco", + demonym = "Monacans", + capitalEnglishName = "Monaco", + areaKM2 = "2", + population = 39242, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "mc", + flagEmoji = "🇲🇨", + phoneCode = 377, + ), + CountryInfo( + alpha2 = "MD", + alpha3 = "MDA", + englishName = "Moldova (Republic of)", + demonym = "Moldovans", + capitalEnglishName = "Chisinau", + areaKM2 = "33851", + population = 4033963, + currencyCode = "MDL", + currencyName = "Moldovan Leu", + currencySymbol = "L", + cctld = "md", + flagEmoji = "🇲🇩", + phoneCode = 373, + ), + CountryInfo( + alpha2 = "ME", + alpha3 = "MNE", + englishName = "Montenegro", + demonym = "Montenegrins", + capitalEnglishName = "Podgorica", + areaKM2 = "13812", + population = 628066, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "me", + flagEmoji = "🇲🇪", + phoneCode = 382, + ), + CountryInfo( + alpha2 = "MF", + alpha3 = "MAF", + englishName = "Saint Martin (French Part)", + demonym = "Saint-Martinois", + capitalEnglishName = "Marigot", + areaKM2 = "54", + population = 38666, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "gp", + flagEmoji = "🇲🇫", + phoneCode = 590, + ), + CountryInfo( + alpha2 = "MG", + alpha3 = "MDG", + englishName = "Madagascar", + demonym = "Malagasy", + capitalEnglishName = "Antananarivo", + areaKM2 = "587041", + population = 27691018, + currencyCode = "MGA", + currencyName = "Malagasy Ariary", + currencySymbol = "Ar", + cctld = "mg", + flagEmoji = "🇲🇬", + phoneCode = 261, + ), + CountryInfo( + alpha2 = "MH", + alpha3 = "MHL", + englishName = "Marshall Islands", + demonym = "Marshallese", + capitalEnglishName = "Majuro", + areaKM2 = "181", + population = 59190, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "mh", + flagEmoji = "🇲🇭", + phoneCode = 692, + ), + CountryInfo( + alpha2 = "MK", + alpha3 = "MKD", + englishName = "North Macedonia", + demonym = "Macedonians", + capitalEnglishName = "Skopje", + areaKM2 = "25713", + population = 2083374, + currencyCode = "MKD", + currencyName = "Macedonian Denar", + currencySymbol = "den", + cctld = "mk", + flagEmoji = "🇲🇰", + phoneCode = 389, + ), + CountryInfo( + alpha2 = "ML", + alpha3 = "MLI", + englishName = "Mali", + demonym = "Malians", + capitalEnglishName = "Bamako", + areaKM2 = "1240192", + population = 20250833, + currencyCode = "XOF", + currencyName = "Cfa Franc Bceao", + currencySymbol = "CFA", + cctld = "ml", + flagEmoji = "🇲🇱", + phoneCode = 223, + ), + CountryInfo( + alpha2 = "MM", + alpha3 = "MMR", + englishName = "Myanmar", + demonym = "Burmese", + capitalEnglishName = "Pyinmana", + areaKM2 = "676578", + population = 54409800, + currencyCode = "MMK", + currencyName = "Myanmar Kyat", + currencySymbol = "K", + cctld = "mm", + flagEmoji = "🇲🇲", + phoneCode = 95, + ), + CountryInfo( + alpha2 = "MN", + alpha3 = "MNG", + englishName = "Mongolia", + demonym = "Mongolians", + capitalEnglishName = "Ulaanbaatar", + areaKM2 = "1564116", + population = 3278290, + currencyCode = "MNT", + currencyName = "Mongolian Tugrik", + currencySymbol = "₮", + cctld = "mn", + flagEmoji = "🇲🇳", + phoneCode = 976, + ), + CountryInfo( + alpha2 = "MO", + alpha3 = "MAC", + englishName = "Macao", + demonym = "Macanese", + capitalEnglishName = "-", + areaKM2 = "31.3", + population = 649335, + currencyCode = "HKD", + currencyName = "Hong Kong Dollar", + currencySymbol = "$", + cctld = "mo", + flagEmoji = "🇲🇴", + phoneCode = 853, + ), + CountryInfo( + alpha2 = "MP", + alpha3 = "MNP", + englishName = "Northern Mariana Islands", + demonym = "Northern Marianans", + capitalEnglishName = "Saipan", + areaKM2 = "464", + population = 57559, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "mp", + flagEmoji = "🇲🇵", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "MQ", + alpha3 = "MTQ", + englishName = "Martinique", + demonym = "Martiniquais", + capitalEnglishName = "Fort-de-france", + areaKM2 = "1128", + population = 375265, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "mq", + flagEmoji = "🇲🇶", + phoneCode = 596, + ), + CountryInfo( + alpha2 = "MR", + alpha3 = "MRT", + englishName = "Mauritania", + demonym = "Mauritanians", + capitalEnglishName = "Nouakchott", + areaKM2 = "1030700", + population = 4649658, + currencyCode = "MRO", + currencyName = "Mauritanian Ouguiya", + currencySymbol = "UM", + cctld = "mr", + flagEmoji = "🇲🇷", + phoneCode = 222, + ), + CountryInfo( + alpha2 = "MS", + alpha3 = "MSR", + englishName = "Montserrat", + demonym = "Montserratians", + capitalEnglishName = "Plymouth", + areaKM2 = "102", + population = 4992, + currencyCode = "XCD", + currencyName = "East Caribbean Dollar", + currencySymbol = "$", + cctld = "ms", + flagEmoji = "🇲🇸", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "MT", + alpha3 = "MLT", + englishName = "Malta", + demonym = "Maltese", + capitalEnglishName = "Valletta", + areaKM2 = "316", + population = 441543, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "mt", + flagEmoji = "🇲🇹", + phoneCode = 356, + ), + CountryInfo( + alpha2 = "MU", + alpha3 = "MUS", + englishName = "Mauritius", + demonym = "Mauritians", + capitalEnglishName = "Port Louis", + areaKM2 = "2040", + population = 1271768, + currencyCode = "MUR", + currencyName = "Mauritian Rupee", + currencySymbol = "₨", + cctld = "mu", + flagEmoji = "🇲🇺", + phoneCode = 230, + ), + CountryInfo( + alpha2 = "MV", + alpha3 = "MDV", + englishName = "Maldives", + demonym = "Maldivians", + capitalEnglishName = "Male", + areaKM2 = "298", + population = 540544, + currencyCode = "MVR", + currencyName = "Maldivian Rufiyaa", + currencySymbol = "Rf", + cctld = "mv", + flagEmoji = "🇲🇻", + phoneCode = 960, + ), + CountryInfo( + alpha2 = "MW", + alpha3 = "MWI", + englishName = "Malawi", + demonym = "Malawians", + capitalEnglishName = "Lilongwe", + areaKM2 = "118484", + population = 19129952, + currencyCode = "MWK", + currencyName = "Malawian Kwacha", + currencySymbol = "K", + cctld = "mw", + flagEmoji = "🇲🇼", + phoneCode = 265, + ), + CountryInfo( + alpha2 = "MX", + alpha3 = "MEX", + englishName = "Mexico", + demonym = "Mexicans", + capitalEnglishName = "Mexico City", + areaKM2 = "1964375", + population = 128932753, + currencyCode = "MXN", + currencyName = "Mexican Peso", + currencySymbol = "$", + cctld = "mx", + flagEmoji = "🇲🇽", + phoneCode = 52, + ), + CountryInfo( + alpha2 = "MY", + alpha3 = "MYS", + englishName = "Malaysia", + demonym = "Malaysians", + capitalEnglishName = "Kuala Lumpur", + areaKM2 = "329847", + population = 32365999, + currencyCode = "MYR", + currencyName = "Malaysian Ringgit", + currencySymbol = "RM", + cctld = "my", + flagEmoji = "🇲🇾", + phoneCode = 60, + ), + CountryInfo( + alpha2 = "MZ", + alpha3 = "MOZ", + englishName = "Mozambique", + demonym = "Mozambicans", + capitalEnglishName = "Maputo", + areaKM2 = "799380", + population = 31255435, + currencyCode = "MZN", + currencyName = "Mozambican Metical", + currencySymbol = "MT", + cctld = "mz", + flagEmoji = "🇲🇿", + phoneCode = 258, + ), + CountryInfo( + alpha2 = "NA", + alpha3 = "NAM", + englishName = "Namibia", + demonym = "Namibians", + capitalEnglishName = "Windhoek", + areaKM2 = "824292", + population = 2540905, + currencyCode = "NAD", + currencyName = "Namibian Dollar", + currencySymbol = "$", + cctld = "na", + flagEmoji = "🇳🇦", + phoneCode = 264, + ), + CountryInfo( + alpha2 = "NC", + alpha3 = "NCL", + englishName = "New Caledonia", + demonym = "New Caledonians", + capitalEnglishName = "Noumea", + areaKM2 = "18575", + population = 285498, + currencyCode = "XPF", + currencyName = "Cfp Franc", + currencySymbol = "₣", + cctld = "nc", + flagEmoji = "🇳🇨", + phoneCode = 687, + ), + CountryInfo( + alpha2 = "NE", + alpha3 = "NER", + englishName = "Niger", + demonym = "Nigeriens", + capitalEnglishName = "Niamey", + areaKM2 = "1186408", + population = 24206644, + currencyCode = "NZD", + currencyName = "New Zealand Dollar", + currencySymbol = "$", + cctld = "ne", + flagEmoji = "🇳🇪", + phoneCode = 227, + ), + CountryInfo( + alpha2 = "NF", + alpha3 = "NFK", + englishName = "Norfolk Island", + demonym = "Norfolk Islanders", + capitalEnglishName = "Kingston", + areaKM2 = "36", + population = 1735, + currencyCode = "AUD", + currencyName = "Australian Dollar", + currencySymbol = "$", + cctld = "nf", + flagEmoji = "🇳🇫", + phoneCode = 672, + ), + CountryInfo( + alpha2 = "NG", + alpha3 = "NGA", + englishName = "Nigeria", + demonym = "Nigerians", + capitalEnglishName = "Abuja", + areaKM2 = "923768", + population = 206139589, + currencyCode = "NGN", + currencyName = "Nigerian Naira", + currencySymbol = "₦", + cctld = "ng", + flagEmoji = "🇳🇬", + phoneCode = 234, + ), + CountryInfo( + alpha2 = "NI", + alpha3 = "NIC", + englishName = "Nicaragua", + demonym = "Nicaraguans", + capitalEnglishName = "Managua", + areaKM2 = "130370", + population = 6624554, + currencyCode = "NIO", + currencyName = "Nicaraguan CÓrdoba", + currencySymbol = "C$", + cctld = "ni", + flagEmoji = "🇳🇮", + phoneCode = 505, + ), + CountryInfo( + alpha2 = "NL", + alpha3 = "NLD", + englishName = "Netherlands", + demonym = "Netherlanders", + capitalEnglishName = "Amsterdam", + areaKM2 = "41543", + population = 17134872, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "nl", + flagEmoji = "🇳🇱", + phoneCode = 31, + ), + CountryInfo( + alpha2 = "NO", + alpha3 = "NOR", + englishName = "Norway", + demonym = "Norwegians", + capitalEnglishName = "Oslo", + areaKM2 = "323802", + population = 5421241, + currencyCode = "NOK", + currencyName = "Norwegian Kroner", + currencySymbol = "kr", + cctld = "no", + flagEmoji = "🇳🇴", + phoneCode = 47, + ), + CountryInfo( + alpha2 = "NP", + alpha3 = "NPL", + englishName = "Nepal", + demonym = "Nepalese", + capitalEnglishName = "Kathmandu", + areaKM2 = "147181", + population = 29136808, + currencyCode = "NPR", + currencyName = "Nepalese Rupee", + currencySymbol = "रू", + cctld = "np", + flagEmoji = "🇳🇵", + phoneCode = 977, + ), + CountryInfo( + alpha2 = "NR", + alpha3 = "NRU", + englishName = "Nauru", + demonym = "Nauruans", + capitalEnglishName = "Yaren", + areaKM2 = "21", + population = 10824, + currencyCode = "AUD", + currencyName = "Australian Dollar", + currencySymbol = "$", + cctld = "nr", + flagEmoji = "🇳🇷", + phoneCode = 674, + ), + CountryInfo( + alpha2 = "NU", + alpha3 = "NIU", + englishName = "Niue", + demonym = "Niueans", + capitalEnglishName = "Alofi", + areaKM2 = "260", + population = 1626, + currencyCode = "NZD", + currencyName = "New Zealand Dollar", + currencySymbol = "$", + cctld = "nu", + flagEmoji = "🇳🇺", + phoneCode = 683, + ), + CountryInfo( + alpha2 = "NZ", + alpha3 = "NZL", + englishName = "New Zealand", + demonym = "New Zealanders", + capitalEnglishName = "Wellington", + areaKM2 = "267710", + population = 4822233, + currencyCode = "NZD", + currencyName = "New Zealand Dollar", + currencySymbol = "$", + cctld = "nz", + flagEmoji = "🇳🇿", + phoneCode = 64, + ), + CountryInfo( + alpha2 = "OM", + alpha3 = "OMN", + englishName = "Oman", + demonym = "Omanis", + capitalEnglishName = "Muscat", + areaKM2 = "309500", + population = 5106626, + currencyCode = "OMR", + currencyName = "Omani Rial", + currencySymbol = "ر.ع.", + cctld = "om", + flagEmoji = "🇴🇲", + phoneCode = 968, + ), + CountryInfo( + alpha2 = "PA", + alpha3 = "PAN", + englishName = "Panama", + demonym = "Panamanians", + capitalEnglishName = "Panama", + areaKM2 = "75420", + population = 4314767, + currencyCode = "PAB", + currencyName = "Panamanian Balboa", + currencySymbol = "B/.", + cctld = "pa", + flagEmoji = "🇵🇦", + phoneCode = 507, + ), + CountryInfo( + alpha2 = "PE", + alpha3 = "PER", + englishName = "Peru", + demonym = "Peruvians", + capitalEnglishName = "Lima", + areaKM2 = "1285216", + population = 32971854, + currencyCode = "PEN", + currencyName = "Peruvian Nuevo Sol", + currencySymbol = "S/", + cctld = "pe", + flagEmoji = "🇵🇪", + phoneCode = 51, + ), + CountryInfo( + alpha2 = "PF", + alpha3 = "PYF", + englishName = "French Polynesia", + demonym = "French Polynesians", + capitalEnglishName = "Papeete", + areaKM2 = "4167", + population = 280908, + currencyCode = "XPF", + currencyName = "Cfp Franc", + currencySymbol = "₣", + cctld = "pf", + flagEmoji = "🇵🇫", + phoneCode = 689, + ), + CountryInfo( + alpha2 = "PG", + alpha3 = "PNG", + englishName = "Papua New Guinea", + demonym = "Papua New Guineans", + capitalEnglishName = "Port Moresby", + areaKM2 = "462840", + population = 8947024, + currencyCode = "PGK", + currencyName = "Papua New Guinean Kina", + currencySymbol = "K", + cctld = "pg", + flagEmoji = "🇵🇬", + phoneCode = 675, + ), + CountryInfo( + alpha2 = "PH", + alpha3 = "PHL", + englishName = "Philippines", + demonym = "Filipinos", + capitalEnglishName = "Manila", + areaKM2 = "300000", + population = 109581078, + currencyCode = "PHP", + currencyName = "Philippine Peso", + currencySymbol = "₱", + cctld = "ph", + flagEmoji = "🇵🇭", + phoneCode = 63, + ), + CountryInfo( + alpha2 = "PK", + alpha3 = "PAK", + englishName = "Pakistan", + demonym = "Pakistanis", + capitalEnglishName = "Islamabad", + areaKM2 = "796095", + population = 220892340, + currencyCode = "PKR", + currencyName = "Pakistan Rupee", + currencySymbol = "₨", + cctld = "pk", + flagEmoji = "🇵🇰", + phoneCode = 92, + ), + CountryInfo( + alpha2 = "PL", + alpha3 = "POL", + englishName = "Poland", + demonym = "Poles", + capitalEnglishName = "Warsaw", + areaKM2 = "312685", + population = 37846611, + currencyCode = "PLN", + currencyName = "Polish Zloty", + currencySymbol = "zł", + cctld = "pl", + flagEmoji = "🇵🇱", + phoneCode = 48, + ), + CountryInfo( + alpha2 = "PM", + alpha3 = "SPM", + englishName = "Saint Pierre and Miquelon", + demonym = "Saint-Pierrais or Miquelonnais", + capitalEnglishName = "Saint-pierre", + areaKM2 = "242", + population = 5794, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "pm", + flagEmoji = "🇵🇲", + phoneCode = 508, + ), + CountryInfo( + alpha2 = "PN", + alpha3 = "PCN", + englishName = "Pitcairn", + demonym = "Pitcairn Islanders", + capitalEnglishName = "Adamstown", + areaKM2 = "47", + population = 50, + currencyCode = "NZD", + currencyName = "New Zealand Dollar", + currencySymbol = "$", + cctld = "pn", + flagEmoji = "🇵🇳", + phoneCode = 870, + ), + CountryInfo( + alpha2 = "PR", + alpha3 = "PRI", + englishName = "Puerto Rico", + demonym = "Puerto Ricans", + capitalEnglishName = "San Juan", + areaKM2 = "13790", + population = 2860853, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "pr", + flagEmoji = "🇵🇷", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "PS", + alpha3 = "PSE", + englishName = "Palestine, State of", + demonym = "Palestinians", + capitalEnglishName = "-", + areaKM2 = "5860", + population = 5101414, + currencyCode = "ILS", + currencyName = "Israeli New Shekel", + currencySymbol = "₪", + cctld = "ps", + flagEmoji = "🇵🇸", + phoneCode = 970, + ), + CountryInfo( + alpha2 = "PT", + alpha3 = "PRT", + englishName = "Portugal", + demonym = "Portuguese", + capitalEnglishName = "Lisbon", + areaKM2 = "92090", + population = 10196709, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "pt", + flagEmoji = "🇵🇹", + phoneCode = 351, + ), + CountryInfo( + alpha2 = "PW", + alpha3 = "PLW", + englishName = "Palau", + demonym = "Palauans", + capitalEnglishName = "Melekeok - Palau State Capital", + areaKM2 = "459", + population = 18094, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "pw", + flagEmoji = "🇵🇼", + phoneCode = 680, + ), + CountryInfo( + alpha2 = "PY", + alpha3 = "PRY", + englishName = "Paraguay", + demonym = "Paraguayans", + capitalEnglishName = "Asuncion", + areaKM2 = "406752", + population = 7132538, + currencyCode = "PYG", + currencyName = "Paraguayan GuaranÍ", + currencySymbol = "₲", + cctld = "py", + flagEmoji = "🇵🇾", + phoneCode = 595, + ), + CountryInfo( + alpha2 = "QA", + alpha3 = "QAT", + englishName = "Qatar", + demonym = "Qataris", + capitalEnglishName = "Doha", + areaKM2 = "11586", + population = 2881053, + currencyCode = "QAR", + currencyName = "Qatari Riyal", + currencySymbol = "QR", + cctld = "qa", + flagEmoji = "🇶🇦", + phoneCode = 974, + ), + CountryInfo( + alpha2 = "RE", + alpha3 = "REU", + englishName = "Reunion", + demonym = "Réunionese", + capitalEnglishName = "Saint-denis", + areaKM2 = "2512", + population = 895312, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "re", + flagEmoji = "🇷🇪", + phoneCode = 262, + ), + CountryInfo( + alpha2 = "RO", + alpha3 = "ROU", + englishName = "Romania", + demonym = "Romanians", + capitalEnglishName = "Bucharest", + areaKM2 = "238391", + population = 19237691, + currencyCode = "RON", + currencyName = "Romanian New Lei", + currencySymbol = "RON", + cctld = "ro", + flagEmoji = "🇷🇴", + phoneCode = 40, + ), + CountryInfo( + alpha2 = "RS", + alpha3 = "SRB", + englishName = "Serbia", + demonym = "Serbians", + capitalEnglishName = "Belgrade", + areaKM2 = "77474", + population = 8737371, + currencyCode = "RSD", + currencyName = "Serbian Dinar", + currencySymbol = "din", + cctld = "rs", + flagEmoji = "🇷🇸", + phoneCode = 381, + ), + CountryInfo( + alpha2 = "RU", + alpha3 = "RUS", + englishName = "Russian Federation", + demonym = "Russians", + capitalEnglishName = "Moscow", + areaKM2 = "17098242", + population = 145934462, + currencyCode = "RUB", + currencyName = "Russian Rouble", + currencySymbol = "₽", + cctld = "ru", + flagEmoji = "🇷🇺", + phoneCode = 7, + ), + CountryInfo( + alpha2 = "RW", + alpha3 = "RWA", + englishName = "Rwanda", + demonym = "Rwandans", + capitalEnglishName = "Kigali", + areaKM2 = "26338", + population = 12952218, + currencyCode = "RWF", + currencyName = "Rwandan Franc", + currencySymbol = "FRw", + cctld = "rw", + flagEmoji = "🇷🇼", + phoneCode = 250, + ), + CountryInfo( + alpha2 = "SA", + alpha3 = "SAU", + englishName = "Saudi Arabia", + demonym = "Saudis", + capitalEnglishName = "Riyadh", + areaKM2 = "2149690", + population = 34813871, + currencyCode = "SAR", + currencyName = "Saudi Riyal", + currencySymbol = "SR", + cctld = "sa", + flagEmoji = "🇸🇦", + phoneCode = 966, + ), + CountryInfo( + alpha2 = "SB", + alpha3 = "SLB", + englishName = "Solomon Islands", + demonym = "Solomon Islanders", + capitalEnglishName = "Honiara", + areaKM2 = "28896", + population = 686884, + currencyCode = "SBD", + currencyName = "Solomon Islands Dollar", + currencySymbol = "$", + cctld = "sb", + flagEmoji = "🇸🇧", + phoneCode = 677, + ), + CountryInfo( + alpha2 = "SC", + alpha3 = "SYC", + englishName = "Seychelles", + demonym = "Seychellois", + capitalEnglishName = "Victoria", + areaKM2 = "455", + population = 98347, + currencyCode = "SCR", + currencyName = "Seychelles Rupee", + currencySymbol = "SR", + cctld = "sc", + flagEmoji = "🇸🇨", + phoneCode = 248, + ), + CountryInfo( + alpha2 = "SD", + alpha3 = "SDN", + englishName = "Sudan", + demonym = "Sudanese", + capitalEnglishName = "Khartoum", + areaKM2 = "1861484", + population = 43849260, + currencyCode = "SDG", + currencyName = "Sudanese Pound", + currencySymbol = "SD", + cctld = "sd", + flagEmoji = "🇸🇩", + phoneCode = 249, + ), + CountryInfo( + alpha2 = "SE", + alpha3 = "SWE", + englishName = "Sweden", + demonym = "Swedes", + capitalEnglishName = "Stockholm", + areaKM2 = "450295", + population = 10099265, + currencyCode = "SEK", + currencyName = "Swedish Krona", + currencySymbol = "kr", + cctld = "se", + flagEmoji = "🇸🇪", + phoneCode = 46, + ), + CountryInfo( + alpha2 = "SG", + alpha3 = "SGP", + englishName = "Singapore", + demonym = "Singaporeans", + capitalEnglishName = "Singapore", + areaKM2 = "697", + population = 5850342, + currencyCode = "SGD", + currencyName = "Singapore Dollar", + currencySymbol = "$", + cctld = "sg", + flagEmoji = "🇸🇬", + phoneCode = 65, + ), + CountryInfo( + alpha2 = "SH", + alpha3 = "SHN", + englishName = "Saint Helena, Ascension and Tristan da Cunha", + demonym = "Saint Helenians", + capitalEnglishName = "Jamestown", + areaKM2 = "122", + population = 6077, + currencyCode = "SHP", + currencyName = "Saint Helena Pound", + currencySymbol = "£", + cctld = "sh", + flagEmoji = "🇸🇭", + phoneCode = 290, + ), + CountryInfo( + alpha2 = "SI", + alpha3 = "SVN", + englishName = "Slovenia", + demonym = "Slovenes", + capitalEnglishName = "Ljubljana", + areaKM2 = "20273", + population = 2078938, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "si", + flagEmoji = "🇸🇮", + phoneCode = 386, + ), + CountryInfo( + alpha2 = "SJ", + alpha3 = "SJM", + englishName = "Svalbard and Jan Mayen", + demonym = "Slovakians", + capitalEnglishName = "Longyearbyen", + areaKM2 = "62045", + population = 2926, + currencyCode = "NOK", + currencyName = "Norwegian Krone", + currencySymbol = "kr", + cctld = "sj", + flagEmoji = "🇸🇯", + phoneCode = 47, + ), + CountryInfo( + alpha2 = "SK", + alpha3 = "SVK", + englishName = "Slovakia", + demonym = "Sierra Leoneans", + capitalEnglishName = "Bratislava", + areaKM2 = "49035", + population = 5459642, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "sk", + flagEmoji = "🇸🇰", + phoneCode = 421, + ), + CountryInfo( + alpha2 = "SL", + alpha3 = "SLE", + englishName = "Sierra Leone", + demonym = "Sammarinese", + capitalEnglishName = "Freetown", + areaKM2 = "71740", + population = 7976983, + currencyCode = "SLL", + currencyName = "Sierra Leonean Leone", + currencySymbol = "Le", + cctld = "sl", + flagEmoji = "🇸🇱", + phoneCode = 232, + ), + CountryInfo( + alpha2 = "SM", + alpha3 = "SMR", + englishName = "San Marino", + demonym = "Sammarinese", + capitalEnglishName = "San Marino", + areaKM2 = "61", + population = 33931, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "sm", + flagEmoji = "🇸🇲", + phoneCode = 378, + ), + CountryInfo( + alpha2 = "SN", + alpha3 = "SEN", + englishName = "Senegal", + demonym = "Somalis", + capitalEnglishName = "Dakar", + areaKM2 = "196722", + population = 16743927, + currencyCode = "XOF", + currencyName = "Cfa Franc Bceao", + currencySymbol = "CFA", + cctld = "sn", + flagEmoji = "🇸🇳", + phoneCode = 221, + ), + CountryInfo( + alpha2 = "SO", + alpha3 = "SOM", + englishName = "Somalia", + demonym = "Somalilanders", + capitalEnglishName = "Mogadishu", + areaKM2 = "637657", + population = 15893222, + currencyCode = "SOS", + currencyName = "Somali Shilling", + currencySymbol = "Sh.So.", + cctld = "so", + flagEmoji = "🇸🇴", + phoneCode = 252, + ), + CountryInfo( + alpha2 = "SR", + alpha3 = "SUR", + englishName = "Suriname", + demonym = "Surinamers", + capitalEnglishName = "Paramaribo", + areaKM2 = "163820", + population = 586632, + currencyCode = "SRD", + currencyName = "Surinamese Dollar", + currencySymbol = "$", + cctld = "sr", + flagEmoji = "🇸🇷", + phoneCode = 597, + ), + CountryInfo( + alpha2 = "SS", + alpha3 = "SSD", + englishName = "South Sudan", + demonym = "South Sudanese", + capitalEnglishName = "Juba", + areaKM2 = "644329", + population = 11193725, + currencyCode = "SSP", + currencyName = "South Sudanese Pound", + currencySymbol = "SD", + cctld = "ss", + flagEmoji = "🇸🇸", + phoneCode = 211, + ), + CountryInfo( + alpha2 = "ST", + alpha3 = "STP", + englishName = "Sao Tome and Principe", + demonym = "Sao Tomeans", + capitalEnglishName = "Sao Tome", + areaKM2 = "964", + population = 219159, + currencyCode = "STD", + currencyName = "Droba", + currencySymbol = "Db", + cctld = "st", + flagEmoji = "🇸🇹", + phoneCode = 239, + ), + CountryInfo( + alpha2 = "SV", + alpha3 = "SLV", + englishName = "El Salvador", + demonym = "Salvadorans", + capitalEnglishName = "San Salvador", + areaKM2 = "21041", + population = 6486205, + currencyCode = "NOK", + currencyName = "Norwegian Kroner", + currencySymbol = "kr", + cctld = "sv", + flagEmoji = "🇸🇻", + phoneCode = 503, + ), + CountryInfo( + alpha2 = "SX", + alpha3 = "SXM", + englishName = "Sint Maarten (Dutch Part)", + demonym = "Sint Maartener", + capitalEnglishName = "Philipsburg", + areaKM2 = "34", + population = 42876, + currencyCode = "ANG", + currencyName = "Nl Antillian Guilder", + currencySymbol = "ƒ", + cctld = "sx", + flagEmoji = "🇸🇽", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "SY", + alpha3 = "SYR", + englishName = "Syrian Arab Republic", + demonym = "Syrians", + capitalEnglishName = "Damascus", + areaKM2 = "185180", + population = 17500658, + currencyCode = "SYP", + currencyName = "Syrian Pound", + currencySymbol = "LS", + cctld = "sy", + flagEmoji = "🇸🇾", + phoneCode = 963, + ), + CountryInfo( + alpha2 = "SZ", + alpha3 = "SWZ", + englishName = "Eswatini", + demonym = "Swazis", + capitalEnglishName = "Mbabane", + areaKM2 = "17364", + population = 1160164, + currencyCode = "SZL", + currencyName = "Swazi Lilangeni", + currencySymbol = "L", + cctld = "sz", + flagEmoji = "🇸🇿", + phoneCode = 268, + ), + CountryInfo( + alpha2 = "TC", + alpha3 = "TCA", + englishName = "Turks and Caicos Islands", + demonym = "Turks and Caicos Islanders", + capitalEnglishName = "Cockburn Town", + areaKM2 = "948", + population = 38717, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "tc", + flagEmoji = "🇹🇨", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "TD", + alpha3 = "TCD", + englishName = "Chad", + demonym = "Chadians", + capitalEnglishName = "N'djamena", + areaKM2 = "1284000", + population = 16425864, + currencyCode = "XAF", + currencyName = "Cfa Franc Beac", + currencySymbol = "FCFA", + cctld = "td", + flagEmoji = "🇹🇩", + phoneCode = 235, + ), + CountryInfo( + alpha2 = "TF", + alpha3 = "ATF", + englishName = "French Southern Territories", + demonym = "French", + capitalEnglishName = "Port-aux-francais", + areaKM2 = "439781", + population = 140, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "tf", + flagEmoji = "🇹🇫", + phoneCode = 262, + ), + CountryInfo( + alpha2 = "TG", + alpha3 = "TGO", + englishName = "Togo", + demonym = "Togolese", + capitalEnglishName = "Lome", + areaKM2 = "56785", + population = 8278724, + currencyCode = "XOF", + currencyName = "Cfa Franc Bceao", + currencySymbol = "CFA", + cctld = "tg", + flagEmoji = "🇹🇬", + phoneCode = 228, + ), + CountryInfo( + alpha2 = "TH", + alpha3 = "THA", + englishName = "Thailand", + demonym = "Thai", + capitalEnglishName = "Bangkok", + areaKM2 = "513120", + population = 69799978, + currencyCode = "THB", + currencyName = "Thai Baht", + currencySymbol = "฿", + cctld = "th", + flagEmoji = "🇹🇭", + phoneCode = 66, + ), + CountryInfo( + alpha2 = "TJ", + alpha3 = "TJK", + englishName = "Tajikistan", + demonym = "Tajikistanis", + capitalEnglishName = "Dushanbe", + areaKM2 = "143100", + population = 9537645, + currencyCode = "TJS", + currencyName = "Tajikistani Somoni", + currencySymbol = "ЅM", + cctld = "tj", + flagEmoji = "🇹🇯", + phoneCode = 992, + ), + CountryInfo( + alpha2 = "TK", + alpha3 = "TKL", + englishName = "Tokelau", + demonym = "Tokelauans", + capitalEnglishName = "-", + areaKM2 = "12", + population = 1357, + currencyCode = "NZD", + currencyName = "New Zealand Dollar", + currencySymbol = "$", + cctld = "tk", + flagEmoji = "🇹🇰", + phoneCode = 690, + ), + CountryInfo( + alpha2 = "TL", + alpha3 = "TLS", + englishName = "Timor-Leste", + demonym = "Timorese", + capitalEnglishName = "Dili", + areaKM2 = "14874", + population = 1318445, + currencyCode = "NZD", + currencyName = "New Zealand Dollar", + currencySymbol = "$", + cctld = "tl", + flagEmoji = "🇹🇱", + phoneCode = 670, + ), + CountryInfo( + alpha2 = "TM", + alpha3 = "TKM", + englishName = "Turkmenistan", + demonym = "Turkmens", + capitalEnglishName = "Ashgabat", + areaKM2 = "488100", + population = 6031200, + currencyCode = "TMT", + currencyName = "Turkmenistani Manat", + currencySymbol = "T", + cctld = "tm", + flagEmoji = "🇹🇲", + phoneCode = 993, + ), + CountryInfo( + alpha2 = "TN", + alpha3 = "TUN", + englishName = "Tunisia", + demonym = "Tunisians", + capitalEnglishName = "Tunis", + areaKM2 = "163610", + population = 11818619, + currencyCode = "TND", + currencyName = "Tunisian Dinar", + currencySymbol = "DT", + cctld = "tn", + flagEmoji = "🇹🇳", + phoneCode = 216, + ), + CountryInfo( + alpha2 = "TO", + alpha3 = "TON", + englishName = "Tonga", + demonym = "Tongans", + capitalEnglishName = "Nuku'alofa", + areaKM2 = "747", + population = 105695, + currencyCode = "TOP", + currencyName = "Tongan Pa'anga", + currencySymbol = "T$", + cctld = "to", + flagEmoji = "🇹🇴", + phoneCode = 676, + ), + CountryInfo( + alpha2 = "TR", + alpha3 = "TUR", + englishName = "Turkey", + demonym = "Turks", + capitalEnglishName = "Ankara", + areaKM2 = "783562", + population = 84339067, + currencyCode = "TRY", + currencyName = "Turkish Lira", + currencySymbol = "₺", + cctld = "tr", + flagEmoji = "🇹🇷", + phoneCode = 90, + ), + CountryInfo( + alpha2 = "TT", + alpha3 = "TTO", + englishName = "Trinidad and Tobago", + demonym = "Trinidadians or Tobagonians", + capitalEnglishName = "Port of Spain", + areaKM2 = "5128", + population = 1399488, + currencyCode = "TTD", + currencyName = "Trinidad/tobago Dollar", + currencySymbol = "$", + cctld = "tt", + flagEmoji = "🇹🇹", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "TV", + alpha3 = "TUV", + englishName = "Tuvalu", + demonym = "Tuvaluans", + capitalEnglishName = "Funafuti", + areaKM2 = "26", + population = 11792, + currencyCode = "AUD", + currencyName = "Australian Dollar", + currencySymbol = "$", + cctld = "tv", + flagEmoji = "🇹🇻", + phoneCode = 688, + ), + CountryInfo( + alpha2 = "TW", + alpha3 = "TWN", + englishName = "Taiwan (Province of China)", + demonym = "Taiwanese", + capitalEnglishName = "Taipei", + areaKM2 = "35980", + population = 23816775, + currencyCode = "TWD", + currencyName = "Taiwan Dollar", + currencySymbol = "NT$", + cctld = "tw", + flagEmoji = "🇹🇼", + phoneCode = 886, + ), + CountryInfo( + alpha2 = "TZ", + alpha3 = "TZA", + englishName = "Tanzania, United Republic of", + demonym = "Tanzanians", + capitalEnglishName = "Dodoma", + areaKM2 = "947300", + population = 59734218, + currencyCode = "TZS", + currencyName = "Tanzanian Shilling", + currencySymbol = "TSh", + cctld = "tz", + flagEmoji = "🇹🇿", + phoneCode = 255, + ), + CountryInfo( + alpha2 = "UA", + alpha3 = "UKR", + englishName = "Ukraine", + demonym = "Ukrainians", + capitalEnglishName = "Kiev", + areaKM2 = "603550", + population = 43733762, + currencyCode = "UAH", + currencyName = "Ukrainian Hryvnia", + currencySymbol = "₴", + cctld = "ua", + flagEmoji = "🇺🇦", + phoneCode = 380, + ), + CountryInfo( + alpha2 = "UG", + alpha3 = "UGA", + englishName = "Uganda", + demonym = "Ugandans", + capitalEnglishName = "Kampala", + areaKM2 = "241038", + population = 45741007, + currencyCode = "UGX", + currencyName = "Ugandan Shilling", + currencySymbol = "USh", + cctld = "ug", + flagEmoji = "🇺🇬", + phoneCode = 256, + ), + CountryInfo( + alpha2 = "UM", + alpha3 = "UMI", + englishName = "United States Minor Outlying Islands", + demonym = "‎American Islander", + capitalEnglishName = "-", + areaKM2 = "34.2", + population = 300, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "um", + flagEmoji = "🇺🇲", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "US", + alpha3 = "USA", + englishName = "United States of America", + demonym = "Americans", + capitalEnglishName = "Washington, D.C.", + areaKM2 = "9826675", + population = 331002651, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "us", + flagEmoji = "🇺🇸", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "UY", + alpha3 = "URY", + englishName = "Uruguay", + demonym = "Uruguayans", + capitalEnglishName = "Montevideo", + areaKM2 = "176215", + population = 3473730, + currencyCode = "UYI", + currencyName = "Uruguay Peso En Unidades Indexadas", + currencySymbol = "$", + cctld = "uy", + flagEmoji = "🇺🇾", + phoneCode = 598, + ), + CountryInfo( + alpha2 = "UZ", + alpha3 = "UZB", + englishName = "Uzbekistan", + demonym = "Uzbekistanis", + capitalEnglishName = "Tashkent", + areaKM2 = "447400", + population = 33469203, + currencyCode = "UZS", + currencyName = "Uzbekistan Som", + currencySymbol = "som", + cctld = "uz", + flagEmoji = "🇺🇿", + phoneCode = 998, + ), + CountryInfo( + alpha2 = "VA", + alpha3 = "VAT", + englishName = "Holy See", + demonym = "Vatican citizens", + capitalEnglishName = "Vatican City", + areaKM2 = "0.44", + population = 801, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "va", + flagEmoji = "🇻🇦", + phoneCode = 379, + ), + CountryInfo( + alpha2 = "VC", + alpha3 = "VCT", + englishName = "Saint Vincent and the Grenadines", + demonym = "Saint Vincentians", + capitalEnglishName = "Kingstown", + areaKM2 = "389", + population = 110940, + currencyCode = "XCD", + currencyName = "East Caribbean Dollar", + currencySymbol = "$", + cctld = "vc", + flagEmoji = "🇻🇨", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "VE", + alpha3 = "VEN", + englishName = "Venezuela (Bolivarian Republic of)", + demonym = "Venezuelans", + capitalEnglishName = "Caracas", + areaKM2 = "912050", + population = 28435940, + currencyCode = "VEF", + currencyName = "Venezuelan Bolivar Fuerte", + currencySymbol = "Bs.S.", + cctld = "ve", + flagEmoji = "🇻🇪", + phoneCode = 58, + ), + CountryInfo( + alpha2 = "VG", + alpha3 = "VGB", + englishName = "Virgin Islands (British)", + demonym = "British Virgin Islanders", + capitalEnglishName = "Road Town", + areaKM2 = "151", + population = 30231, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "vg", + flagEmoji = "🇻🇬", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "VI", + alpha3 = "VIR", + englishName = "Virgin Islands (U.S.)", + demonym = "U.S. Virgin Islanders", + capitalEnglishName = "Charlotte Amalie", + areaKM2 = "1910", + population = 104425, + currencyCode = "USD", + currencyName = "United States Dollar", + currencySymbol = "$", + cctld = "vi", + flagEmoji = "🇻🇮", + phoneCode = 1, + ), + CountryInfo( + alpha2 = "VN", + alpha3 = "VNM", + englishName = "Viet Nam", + demonym = "Vietnamese", + capitalEnglishName = "Ha Noi", + areaKM2 = "331210", + population = 97338579, + currencyCode = "VND", + currencyName = "Vietnamese Dong", + currencySymbol = "₫", + cctld = "vn", + flagEmoji = "🇻🇳", + phoneCode = 84, + ), + CountryInfo( + alpha2 = "VU", + alpha3 = "VUT", + englishName = "Vanuatu", + demonym = "Ni-Vanuatu", + capitalEnglishName = "Port-vila", + areaKM2 = "12189", + population = 307145, + currencyCode = "VUV", + currencyName = "Vanuatu Vatu", + currencySymbol = "VT", + cctld = "vu", + flagEmoji = "🇻🇺", + phoneCode = 678, + ), + CountryInfo( + alpha2 = "WF", + alpha3 = "WLF", + englishName = "Wallis and Futuna", + demonym = "Wallisians or Futunans", + capitalEnglishName = "Mata'utu", + areaKM2 = "142", + population = 11239, + currencyCode = "XPF", + currencyName = "Cfp Franc", + currencySymbol = "₣", + cctld = "wf", + flagEmoji = "🇼🇫", + phoneCode = 681, + ), + CountryInfo( + alpha2 = "WS", + alpha3 = "WSM", + englishName = "Samoa", + demonym = "Samoans", + capitalEnglishName = "Apia", + areaKM2 = "2831", + population = 198414, + currencyCode = "WST", + currencyName = "Samoan Tala", + currencySymbol = "WS$", + cctld = "ws", + flagEmoji = "🇼🇸", + phoneCode = 685, + ), + CountryInfo( + alpha2 = "XK", + alpha3 = "XKX", + englishName = "Kosovo", + demonym = "Kosovar", + capitalEnglishName = "Pristina", + areaKM2 = "10887", + population = 1873160, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "al", + flagEmoji = "🇽🇰", + phoneCode = 383, + ), + CountryInfo( + alpha2 = "YE", + alpha3 = "YEM", + englishName = "Yemen", + demonym = "Yemenis", + capitalEnglishName = "Sanaa", + areaKM2 = "527968", + population = 29825964, + currencyCode = "YER", + currencyName = "Yemeni Rial", + currencySymbol = "﷼", + cctld = "ye", + flagEmoji = "🇾🇪", + phoneCode = 967, + ), + CountryInfo( + alpha2 = "YT", + alpha3 = "MYT", + englishName = "Mayotte", + demonym = "Mahorans", + capitalEnglishName = "Mamoudzou", + areaKM2 = "374", + population = 272815, + currencyCode = "EUR", + currencyName = "Euro", + currencySymbol = "€", + cctld = "yt", + flagEmoji = "🇾🇹", + phoneCode = 262, + ), + CountryInfo( + alpha2 = "ZA", + alpha3 = "ZAF", + englishName = "South Africa", + demonym = "South Africans", + capitalEnglishName = "Cape Town", + areaKM2 = "1219090", + population = 59308690, + currencyCode = "ZAR", + currencyName = "South African Rand", + currencySymbol = "R", + cctld = "za", + flagEmoji = "🇿🇦", + phoneCode = 27, + ), + CountryInfo( + alpha2 = "ZM", + alpha3 = "ZMB", + englishName = "Zambia", + demonym = "Zambians", + capitalEnglishName = "Lusaka", + areaKM2 = "752618", + population = 18383955, + currencyCode = "ZMW", + currencyName = "Zambian Kwacha", + currencySymbol = "K", + cctld = "zm", + flagEmoji = "🇿🇲", + phoneCode = 260, + ), + CountryInfo( + alpha2 = "ZW", + alpha3 = "ZWE", + englishName = "Zimbabwe", + demonym = "Zimbabweans", + capitalEnglishName = "Harare", + areaKM2 = "390757", + population = 14862924, + currencyCode = "ZWD", + currencyName = "Zimbabwe Dollar", + currencySymbol = "$", + cctld = "zw", + flagEmoji = "🇿🇼", + phoneCode = 263, + ), ) -) diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/models/alpha2Collection.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/models/alpha2Collection.kt deleted file mode 100644 index 25d5831..0000000 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/models/alpha2Collection.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.hbb20.countrypicker.models - -val allCountryAlpha2List = countryInfoList.map { it.alpha2 } \ No newline at end of file diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CPRecyclerViewExtensions.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CPRecyclerViewExtensions.kt index 312af22..9a39a8e 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CPRecyclerViewExtensions.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CPRecyclerViewExtensions.kt @@ -13,11 +13,12 @@ import com.hbb20.countrypicker.models.CPCountry import com.hbb20.countrypicker.models.CPDataStore val defaultDataStoreModifier = null + fun RecyclerView.loadCountries( - customMasterCountries: String = CPDataStoreGenerator.defaultMasterCountries, - customExcludedCountries: String = CPDataStoreGenerator.defaultExcludedCountries, - countryFileReader: CountryFileReading = CPDataStoreGenerator.defaultCountryFileReader, - useCache: Boolean = CPDataStoreGenerator.defaultUseCache, + customMasterCountries: String = CPDataStoreGenerator.DEFAULT_MASTER_COUNTRIES, + customExcludedCountries: String = CPDataStoreGenerator.DEFAULT_EXCLUDED_COUNTRIES, + countryFileReader: CountryFileReading = CPDataStoreGenerator.DEFAULT_FILE_READER, + useCache: Boolean = CPDataStoreGenerator.DEFAULT_USE_CACHE, customDataStoreModifier: ((CPDataStore) -> (Unit))? = defaultDataStoreModifier, preferredCountryCodes: String? = CPListConfig.defaultCPListPreferredCountryCodes, filterQueryEditText: EditText? = null, @@ -25,16 +26,17 @@ fun RecyclerView.loadCountries( primaryTextGenerator: ((CPCountry) -> String) = CPRowConfig.defaultPrimaryTextGenerator, secondaryTextGenerator: ((CPCountry) -> String)? = CPRowConfig.defaultSecondaryTextGenerator, highlightedTextGenerator: ((CPCountry) -> String)? = CPRowConfig.defaultHighlightedTextGenerator, - onCountryClickListener: ((CPCountry) -> Unit) + onCountryClickListener: ((CPCountry) -> Unit), ) { onMethodBegin("loadCountries") - val cpDataStore = CPDataStoreGenerator.generate( - context, - customMasterCountries, - customExcludedCountries, - countryFileReader, - useCache - ) + val cpDataStore = + CPDataStoreGenerator.generate( + context, + customMasterCountries, + customExcludedCountries, + countryFileReader, + useCache, + ) customDataStoreModifier?.invoke(cpDataStore) @@ -46,7 +48,7 @@ fun RecyclerView.loadCountries( highlightedTextGenerator, preferredCountryCodes, filterQueryEditText, - onCountryClickListener + onCountryClickListener, ) logMethodEnd("loadCountries") @@ -60,14 +62,15 @@ fun RecyclerView.loadCountriesUsingDataStore( highlightedTextGenerator: ((CPCountry) -> String)? = CPRowConfig.defaultHighlightedTextGenerator, preferredCountryCodes: String? = CPListConfig.defaultCPListPreferredCountryCodes, filterQueryEditText: EditText? = null, - onCountryClickListener: ((CPCountry) -> Unit) + onCountryClickListener: ((CPCountry) -> Unit), ) { - val cpCountryRowConfig = CPRowConfig( - cpFlagProvider = cpFlagProvider, - primaryTextGenerator = primaryTextGenerator, - secondaryTextGenerator = secondaryTextGenerator, - highlightedTextGenerator = highlightedTextGenerator - ) + val cpCountryRowConfig = + CPRowConfig( + cpFlagProvider = cpFlagProvider, + primaryTextGenerator = primaryTextGenerator, + secondaryTextGenerator = secondaryTextGenerator, + highlightedTextGenerator = highlightedTextGenerator, + ) val cpListConfig = CPListConfig(preferredCountryCodes = preferredCountryCodes) @@ -76,7 +79,7 @@ fun RecyclerView.loadCountriesUsingDataStore( cpCountryRowConfig, cpListConfig, filterQueryEditText, - onCountryClickListener + onCountryClickListener, ) } @@ -85,15 +88,14 @@ fun RecyclerView.loadCountriesUsingDataStoreAndConfig( cpRowConfig: CPRowConfig, cpListConfig: CPListConfig, filterQueryEditText: EditText? = null, - onCountryClickListener: (CPCountry) -> Unit + onCountryClickListener: (CPCountry) -> Unit, ) { - val cpRecyclerViewHelper = CPRecyclerViewHelper( cpDataStore = cpDataStore, onCountryClickListener = onCountryClickListener, cpRowConfig = cpRowConfig, - cpListConfig = cpListConfig + cpListConfig = cpListConfig, ) cpRecyclerViewHelper.attachRecyclerView(this) diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CPRecyclerViewHelper.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CPRecyclerViewHelper.kt index 6df71a4..ffd6a3b 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CPRecyclerViewHelper.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CPRecyclerViewHelper.kt @@ -13,25 +13,27 @@ class CPRecyclerViewHelper( private val cpDataStore: CPDataStore, cpListConfig: CPListConfig = CPListConfig(), private val cpRowConfig: CPRowConfig = CPRowConfig(), - onCountryClickListener: ((CPCountry) -> Unit) + onCountryClickListener: ((CPCountry) -> Unit), ) { private val additionalSearchTerm = mutableMapOf() - var allPreferredCountries = extractPreferredCountries( - cpDataStore.countryList, - cpListConfig.preferredCountryCodes - ) + var allPreferredCountries = + extractPreferredCountries( + cpDataStore.countryList, + cpListConfig.preferredCountryCodes, + ) private set val epoxyController by lazy { CountryListController() } - val controllerData = CountryListControllerData( - allPreferredCountries, - cpDataStore.countryList, - onCountryClickListener, - cpRowConfig, - cpDataStore - ) + val controllerData = + CountryListControllerData( + allPreferredCountries, + cpDataStore.countryList, + onCountryClickListener, + cpRowConfig, + cpDataStore, + ) fun attachFilterQueryEditText(queryEditText: EditText?) { queryEditText?.doOnTextChanged { query, _, _, _ -> @@ -59,16 +61,17 @@ class CPRecyclerViewHelper( private fun extractPreferredCountries( countries: List, - preferredCountryCodes: String? = "" + preferredCountryCodes: String? = "", ): List { val result = mutableListOf() preferredCountryCodes?.split(",")?.map { it.trim() }?.mapNotNull { alphaCode -> - val country = when (alphaCode.length) { - 2 -> countries.find { cpCountry -> cpCountry.alpha2.equals(alphaCode, true) } - 3 -> countries.find { cpCountry -> cpCountry.alpha3.equals(alphaCode, true) } - else -> null - } + val country = + when (alphaCode.length) { + 2 -> countries.find { cpCountry -> cpCountry.alpha2.equals(alphaCode, true) } + 3 -> countries.find { cpCountry -> cpCountry.alpha3.equals(alphaCode, true) } + else -> null + } country?.let { result.add(it) } } @@ -77,7 +80,7 @@ class CPRecyclerViewHelper( private fun List.filterCountries( filterQuery: String, - cpRowConfig: CPRowConfig + cpRowConfig: CPRowConfig, ): List { if (filterQuery.isBlank()) return this @@ -91,16 +94,15 @@ class CPRecyclerViewHelper( } cpCountry.alpha2.startsWith(filterQuery, true) || - cpCountry.alpha3.startsWith(filterQuery, true) || - firstCharsOfWords.contains(filterQuery, true) || - cpRowConfig.primaryTextGenerator(cpCountry).contains(filterQuery, true) || - cpRowConfig.secondaryTextGenerator?.invoke(cpCountry) - ?.contains(filterQuery, true) + cpCountry.alpha3.startsWith(filterQuery, true) || + firstCharsOfWords.contains(filterQuery, true) || + cpRowConfig.primaryTextGenerator(cpCountry).contains(filterQuery, true) || + cpRowConfig.secondaryTextGenerator?.invoke(cpCountry) + ?.contains(filterQuery, true) ?: false || - cpRowConfig.highlightedTextGenerator?.invoke(cpCountry) - ?.contains(filterQuery, true) + cpRowConfig.highlightedTextGenerator?.invoke(cpCountry) + ?.contains(filterQuery, true) ?: false - } } } diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CountryListController.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CountryListController.kt index 5b2e523..4c68aca 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CountryListController.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CountryListController.kt @@ -10,15 +10,12 @@ data class CountryListControllerData( var allCountries: List, val onCountryClickListener: ((CPCountry) -> Unit), val cpRowConfig: CPRowConfig, - val cpDataStore: CPDataStore + val cpDataStore: CPDataStore, ) class CountryListController : - TypedEpoxyController() { - - override fun buildModels( - data: CountryListControllerData - ) { + TypedEpoxyController() { + override fun buildModels(data: CountryListControllerData) { data.apply { preferredCountries.forEach { country -> countryRow { diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CountryRow.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CountryRow.kt index 64e8d7d..9923af8 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CountryRow.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/CountryRow.kt @@ -18,112 +18,119 @@ import com.hbb20.countrypicker.flagprovider.DefaultEmojiFlagProvider import com.hbb20.countrypicker.models.CPCountry @ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT) -internal class CountryRow @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0 -) : FrameLayout(context, attrs, defStyleAttr) { - enum class FlagView { NONE, EMOJI, IMAGE } - - private var binding: CpCountryRowBinding - - init { - inflate(context, R.layout.cp_country_row, this) - binding = CpCountryRowBinding.bind(this.findViewById(R.id.countryRow)) - } +internal class CountryRow + @JvmOverloads + constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + ) : FrameLayout(context, attrs, defStyleAttr) { + enum class FlagView { NONE, EMOJI, IMAGE } + + private var binding: CpCountryRowBinding + + init { + inflate(context, R.layout.cp_country_row, this) + binding = CpCountryRowBinding.bind(this.findViewById(R.id.countryRow)) + } - lateinit var country: CPCountry - @ModelProp set + lateinit var country: CPCountry + @ModelProp set - var rowConfig = CPRowConfig() - @ModelProp set + var rowConfig = CPRowConfig() + @ModelProp set - @CallbackProp - fun clickListener(clickListener: ((CPCountry) -> Unit)?) { - setOnClickListener { clickListener?.invoke(country) } - } + @CallbackProp + fun clickListener(clickListener: ((CPCountry) -> Unit)?) { + setOnClickListener { clickListener?.invoke(country) } + } - override fun setOnClickListener(l: OnClickListener?) { - binding.countryRow.setOnClickListener(l) - } + override fun setOnClickListener(l: OnClickListener?) { + binding.countryRow.setOnClickListener(l) + } - @AfterPropsSet - fun updateViews() { - binding.tvPrimaryText.text = rowConfig.primaryTextGenerator.invoke(country) - setSecondaryText(rowConfig.secondaryTextGenerator?.invoke(country)) - setHighlightedInfo() - applyFlag() + @AfterPropsSet + fun updateViews() { + binding.tvPrimaryText.text = rowConfig.primaryTextGenerator.invoke(country) + setSecondaryText(rowConfig.secondaryTextGenerator?.invoke(country)) + setHighlightedInfo() + applyFlag() - // apply config - applyTextSize() - } + // apply config + applyTextSize() + } - private fun setSecondaryText(secondaryText: String?) { - if (secondaryText == null) { - binding.tvSecondaryText.visibility = View.GONE - } else { - binding.tvSecondaryText.visibility = View.VISIBLE - binding.tvSecondaryText.text = secondaryText + private fun setSecondaryText(secondaryText: String?) { + if (secondaryText == null) { + binding.tvSecondaryText.visibility = View.GONE + } else { + binding.tvSecondaryText.visibility = View.VISIBLE + binding.tvSecondaryText.text = secondaryText + } } - } - private fun setHighlightedInfo() { - val highlightedText = rowConfig.highlightedTextGenerator?.invoke(country) - if (highlightedText != null) { - binding.tvHighlightedInfo.visibility = View.VISIBLE - binding.tvHighlightedInfo.text = highlightedText - } else { - binding.tvHighlightedInfo.visibility = View.GONE + private fun setHighlightedInfo() { + val highlightedText = rowConfig.highlightedTextGenerator?.invoke(country) + if (highlightedText != null) { + binding.tvHighlightedInfo.visibility = View.VISIBLE + binding.tvHighlightedInfo.text = highlightedText + } else { + binding.tvHighlightedInfo.visibility = View.GONE + } } - } - private fun applyFlag() { - val flagProvider = rowConfig.cpFlagProvider - if (flagProvider != null) { - when (flagProvider) { - is DefaultEmojiFlagProvider -> { - showFlag(FlagView.EMOJI) - val flagEmoji = - if (flagProvider.useEmojiCompat) { - EmojiCompat.get().process(country.flagEmoji) - } else { - country.flagEmoji - } - binding.tvEmojiFlag.text = flagEmoji - } - is CPFlagImageProvider -> { - showFlag(FlagView.IMAGE) - binding.imgFlag.setImageResource(flagProvider.getFlag(country.alpha2)) + private fun applyFlag() { + val flagProvider = rowConfig.cpFlagProvider + if (flagProvider != null) { + when (flagProvider) { + is DefaultEmojiFlagProvider -> { + showFlag(FlagView.EMOJI) + val flagEmoji = + if (flagProvider.useEmojiCompat) { + EmojiCompat.get().process(country.flagEmoji) + } else { + country.flagEmoji + } + binding.tvEmojiFlag.text = flagEmoji + } + is CPFlagImageProvider -> { + showFlag(FlagView.IMAGE) + binding.imgFlag.setImageResource(flagProvider.getFlag(country.alpha2)) + } } + } else { + showFlag(FlagView.NONE) } - } else { - showFlag(FlagView.NONE) } - } - private fun showFlag(flagView: FlagView) { - val viewToShow = when (flagView) { - FlagView.NONE -> null - FlagView.EMOJI -> binding.tvEmojiFlag - FlagView.IMAGE -> binding.imgFlag - } + private fun showFlag(flagView: FlagView) { + val viewToShow = + when (flagView) { + FlagView.NONE -> null + FlagView.EMOJI -> binding.tvEmojiFlag + FlagView.IMAGE -> binding.imgFlag + } - if (viewToShow != null) { - for (view in setOf(binding.imgFlag, binding.tvEmojiFlag)) { - if (view == viewToShow) { - view.visibility = View.VISIBLE - } else { - view.visibility = View.GONE + if (viewToShow != null) { + for (view in setOf(binding.imgFlag, binding.tvEmojiFlag)) { + if (view == viewToShow) { + view.visibility = View.VISIBLE + } else { + view.visibility = View.GONE + } } + } else { + binding.flagHolder.visibility = View.GONE } - } else { - binding.flagHolder.visibility = View.GONE } - } - private fun applyTextSize() { - val emojiSize: Float = - if (rowConfig.secondaryTextGenerator == null) binding.tvPrimaryText.textSize else binding.tvPrimaryText.textSize * 1.3f - binding.tvEmojiFlag.setTextSize(TypedValue.COMPLEX_UNIT_PX, emojiSize) + private fun applyTextSize() { + val emojiSize: Float = + if (rowConfig.secondaryTextGenerator == null) { + binding.tvPrimaryText.textSize + } else { + binding.tvPrimaryText.textSize * 1.3f + } + binding.tvEmojiFlag.setTextSize(TypedValue.COMPLEX_UNIT_PX, emojiSize) + } } -} diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/DividerRow.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/DividerRow.kt index f1cf5f6..570a4e0 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/DividerRow.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/DividerRow.kt @@ -7,13 +7,14 @@ import com.airbnb.epoxy.ModelView import com.hbb20.countrypicker.R @ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT) -class DividerRow @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0 -) : ConstraintLayout(context, attrs, defStyleAttr) { - - init { - inflate(context, R.layout.cp_divider_row, this) +class DividerRow + @JvmOverloads + constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + ) : ConstraintLayout(context, attrs, defStyleAttr) { + init { + inflate(context, R.layout.cp_divider_row, this) + } } -} diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/NoMatchRow.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/NoMatchRow.kt index 4ff8995..f5cfdf0 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/NoMatchRow.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/recyclerview/NoMatchRow.kt @@ -10,23 +10,25 @@ import com.hbb20.countrypicker.R import com.hbb20.countrypicker.databinding.CpNoMatchRowBinding @ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT) -class NoMatchRow @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0 -) : FrameLayout(context, attrs, defStyleAttr) { - private var binding: CpNoMatchRowBinding +class NoMatchRow + @JvmOverloads + constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + ) : FrameLayout(context, attrs, defStyleAttr) { + private var binding: CpNoMatchRowBinding - init { - inflate(context, R.layout.cp_no_match_row, this) - binding = CpNoMatchRowBinding.bind(this.findViewById(R.id.rowHolder)) - } + init { + inflate(context, R.layout.cp_no_match_row, this) + binding = CpNoMatchRowBinding.bind(this.findViewById(R.id.rowHolder)) + } - lateinit var noMatchAckText: String - @ModelProp set + lateinit var noMatchAckText: String + @ModelProp set - @AfterPropsSet - fun updateViews() { - binding.tvMsg.text = noMatchAckText + @AfterPropsSet + fun updateViews() { + binding.tvMsg.text = noMatchAckText + } } -} diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/view/CPViewExtension.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/view/CPViewExtension.kt index 0bcc175..5b84047 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/view/CPViewExtension.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/view/CPViewExtension.kt @@ -13,10 +13,10 @@ import com.hbb20.countrypicker.models.CPDataStore import com.hbb20.countrypicker.recyclerview.defaultDataStoreModifier fun Context.prepareCustomCountryPickerView( - customMasterCountries: String = CPDataStoreGenerator.defaultMasterCountries, - customExcludedCountries: String = CPDataStoreGenerator.defaultExcludedCountries, - countryFileReader: CountryFileReading = CPDataStoreGenerator.defaultCountryFileReader, - useCache: Boolean = CPDataStoreGenerator.defaultUseCache, + customMasterCountries: String = CPDataStoreGenerator.DEFAULT_MASTER_COUNTRIES, + customExcludedCountries: String = CPDataStoreGenerator.DEFAULT_EXCLUDED_COUNTRIES, + countryFileReader: CountryFileReading = CPDataStoreGenerator.DEFAULT_FILE_READER, + useCache: Boolean = CPDataStoreGenerator.DEFAULT_USE_CACHE, customDataStoreModifier: ((CPDataStore) -> (Unit))? = defaultDataStoreModifier, containerViewGroup: ViewGroup, tvSelectedCountryInfo: TextView, @@ -30,47 +30,51 @@ fun Context.prepareCustomCountryPickerView( highlightedTextGenerator: ((CPCountry) -> String)? = CPRowConfig.defaultHighlightedTextGenerator, preferredCountryCodes: String? = null, dialogViewIds: CPDialogViewIds = CPDialogConfig.defaultCPDialogViewIds, - allowSearch: Boolean = CPDialogConfig.defaultCPDialogAllowSearch, - allowClearSelection: Boolean = CPDialogConfig.defaultCPDialogAllowClearSelection, - showTitle: Boolean = CPDialogConfig.defaultCPDialogDefaultShowTitle, - showFullScreen: Boolean = CPDialogConfig.defaultCPDialogShowFullScreen, - onCountryChangedListener: ((CPCountry?) -> Unit)? = null + allowSearch: Boolean = CPDialogConfig.DEFAULT_CP_DIALOG_ALLOW_SEARCH, + allowClearSelection: Boolean = CPDialogConfig.DEFAULT_CP_DIALOG_ALLOW_CLEAR_SELECTION, + showTitle: Boolean = CPDialogConfig.DEFAULT_CP_DIALOG_SHOW_TITLE, + showFullScreen: Boolean = CPDialogConfig.DEFAULT_CP_DIALOG_SHOW_FULL_SCREEN, + onCountryChangedListener: ((CPCountry?) -> Unit)? = null, ): CPViewHelper { - - val cpDataStore = CPDataStoreGenerator.generate( - context = this, - customMasterCountries = customMasterCountries, - customExcludedCountries = customExcludedCountries, - countryFileReader = countryFileReader, - useCache = useCache - ) + val cpDataStore = + CPDataStoreGenerator.generate( + context = this, + customMasterCountries = customMasterCountries, + customExcludedCountries = customExcludedCountries, + countryFileReader = countryFileReader, + useCache = useCache, + ) customDataStoreModifier?.invoke(cpDataStore) - val cpDialogConfig = CPDialogConfig( - dialogViewIds = dialogViewIds, - allowSearch = allowSearch, - allowClearSelection = allowClearSelection, - showTitle = showTitle, - showFullScreen = showFullScreen - ) + val cpDialogConfig = + CPDialogConfig( + dialogViewIds = dialogViewIds, + allowSearch = allowSearch, + allowClearSelection = allowClearSelection, + showTitle = showTitle, + showFullScreen = showFullScreen, + ) - val cpCountryRowConfig = CPRowConfig( - cpFlagProvider = cpFlagProvider, - primaryTextGenerator = primaryTextGenerator, - secondaryTextGenerator = secondaryTextGenerator, - highlightedTextGenerator = highlightedTextGenerator - ) + val cpCountryRowConfig = + CPRowConfig( + cpFlagProvider = cpFlagProvider, + primaryTextGenerator = primaryTextGenerator, + secondaryTextGenerator = secondaryTextGenerator, + highlightedTextGenerator = highlightedTextGenerator, + ) - val cpListConfig = CPListConfig( - preferredCountryCodes = preferredCountryCodes - ) + val cpListConfig = + CPListConfig( + preferredCountryCodes = preferredCountryCodes, + ) - val cpViewConfig = CPViewConfig( - initialSelection = initialSelection, - viewTextGenerator = selectedCountryInfoTextGenerator, - cpFlagProvider = cpFlagProvider - ) + val cpViewConfig = + CPViewConfig( + initialSelection = initialSelection, + viewTextGenerator = selectedCountryInfoTextGenerator, + cpFlagProvider = cpFlagProvider, + ) val helper = CPViewHelper( @@ -79,7 +83,7 @@ fun Context.prepareCustomCountryPickerView( cpViewConfig = cpViewConfig, cpDialogConfig = cpDialogConfig, cpListConfig = cpListConfig, - cpRowConfig = cpCountryRowConfig + cpRowConfig = cpCountryRowConfig, ) helper.onCountryChangedListener = onCountryChangedListener @@ -88,7 +92,7 @@ fun Context.prepareCustomCountryPickerView( container = containerViewGroup, tvCountryInfo = tvSelectedCountryInfo, tvEmojiFlag = tvSelectedCountryEmojiFlag, - imgFlag = imgSelectedCountryFlag + imgFlag = imgSelectedCountryFlag, ) return helper diff --git a/countrypicker/src/main/java/com/hbb20/countrypicker/view/CPViewHelper.kt b/countrypicker/src/main/java/com/hbb20/countrypicker/view/CPViewHelper.kt index cbb215d..b520cd8 100644 --- a/countrypicker/src/main/java/com/hbb20/countrypicker/view/CPViewHelper.kt +++ b/countrypicker/src/main/java/com/hbb20/countrypicker/view/CPViewHelper.kt @@ -29,7 +29,7 @@ class CPViewHelper( val cpDialogConfig: CPDialogConfig = CPDialogConfig(), val cpListConfig: CPListConfig = CPListConfig(), val cpRowConfig: CPRowConfig = CPRowConfig(cpFlagProvider = cpViewConfig.cpFlagProvider), - val isInEditMode: Boolean = false + val isInEditMode: Boolean = false, ) { private val _selectedCountry = MutableLiveData().apply { value = null } val selectedCountry: LiveData = _selectedCountry @@ -45,17 +45,17 @@ class CPViewHelper( setInitialCountry(cpViewConfig.initialSelection) } - fun setInitialCountry( - initialSelection: CPViewConfig.InitialSelection - ) { + fun setInitialCountry(initialSelection: CPViewConfig.InitialSelection) { when (initialSelection) { CPViewConfig.InitialSelection.EmptySelection -> clearSelection() - is CPViewConfig.InitialSelection.AutoDetectCountry -> setAutoDetectedCountry( - initialSelection.autoDetectSources - ) - is CPViewConfig.InitialSelection.SpecificCountry -> setCountryForAlphaCode( - initialSelection.countryCode - ) + is CPViewConfig.InitialSelection.AutoDetectCountry -> + setAutoDetectedCountry( + initialSelection.autoDetectSources, + ) + is CPViewConfig.InitialSelection.SpecificCountry -> + setCountryForAlphaCode( + initialSelection.countryCode, + ) } } @@ -63,9 +63,10 @@ class CPViewHelper( * CountryCode can be alpha2 or alpha3 code */ fun setCountryForAlphaCode(countryCode: String?) { - val country = cpDataStore.countryList.firstOrNull { - it.alpha2.equals(countryCode, true) || it.alpha3.equals(countryCode, true) - } + val country = + cpDataStore.countryList.firstOrNull { + it.alpha2.equals(countryCode, true) || it.alpha3.equals(countryCode, true) + } setCountry(country) } @@ -73,21 +74,26 @@ class CPViewHelper( setCountry(null) } - fun setAutoDetectedCountry(countryDetectSources: List = CPViewConfig.defaultCountryDetectorSources) { + fun setAutoDetectedCountry( + countryDetectSources: List = CPViewConfig.defaultCountryDetectorSources, + ) { val detectedAlpha2 = if (isInEditMode) "US" else countryDetector.detectCountry(countryDetectSources) - val detectedCountry = cpDataStore.countryList.firstOrNull { - it.alpha2.lowercase(Locale.ROOT) == detectedAlpha2?.lowercase( - Locale.ROOT - ) - } + val detectedCountry = + cpDataStore.countryList.firstOrNull { + it.alpha2.lowercase(Locale.ROOT) == + detectedAlpha2?.lowercase( + Locale.ROOT, + ) + } setCountry(detectedCountry) } fun launchDialog() { - val dialogHelper = CPDialogHelper(cpDataStore, cpDialogConfig, cpListConfig, cpRowConfig) { - setCountry(it) - } + val dialogHelper = + CPDialogHelper(cpDataStore, cpDialogConfig, cpListConfig, cpRowConfig) { + setCountry(it) + } dialogHelper.createDialog(context).show() } @@ -95,7 +101,7 @@ class CPViewHelper( container: ViewGroup, tvCountryInfo: TextView, tvEmojiFlag: TextView? = null, - imgFlag: ImageView? = null + imgFlag: ImageView? = null, ) { this.viewComponentGroup = ViewComponentGroup(container, tvCountryInfo, tvEmojiFlag, imgFlag) @@ -114,18 +120,23 @@ class CPViewHelper( viewComponentGroup?.apply { // text tvCountryInfo.text = - if (selectedCountry != null) cpViewConfig.viewTextGenerator(selectedCountry) else cpDataStore.messageGroup.selectionPlaceholderText + if (selectedCountry != null) { + cpViewConfig.viewTextGenerator(selectedCountry) + } else { + cpDataStore.messageGroup.selectionPlaceholderText + } val flagProvider = cpViewConfig.cpFlagProvider imgFlag?.isVisible = flagProvider is CPFlagImageProvider tvEmojiFlag?.isVisible = flagProvider is DefaultEmojiFlagProvider if (flagProvider is DefaultEmojiFlagProvider) { - val flagEmoji = when { - flagProvider.useEmojiCompat -> - EmojiCompat.get() - .process(selectedCountry?.flagEmoji ?: " ") - else -> selectedCountry?.flagEmoji ?: " " - } + val flagEmoji = + when { + flagProvider.useEmojiCompat -> + EmojiCompat.get() + .process(selectedCountry?.flagEmoji ?: " ") + else -> selectedCountry?.flagEmoji ?: " " + } tvEmojiFlag?.setText(flagEmoji) ?: kotlin.run { Timber.e("No tvEmojiFlag provided to load emoji flag") } @@ -150,6 +161,6 @@ class CPViewHelper( val container: ViewGroup, val tvCountryInfo: TextView, val tvEmojiFlag: TextView? = null, - val imgFlag: ImageView? = null + val imgFlag: ImageView? = null, ) } diff --git a/countrypicker/src/test/java/com/hbb20/CPDataStoreGeneratorTest.kt b/countrypicker/src/test/java/com/hbb20/CPDataStoreGeneratorTest.kt index 5eed1fc..22995d5 100644 --- a/countrypicker/src/test/java/com/hbb20/CPDataStoreGeneratorTest.kt +++ b/countrypicker/src/test/java/com/hbb20/CPDataStoreGeneratorTest.kt @@ -11,7 +11,6 @@ import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) class CPDataStoreGeneratorTest { - private val context: Context = ApplicationProvider.getApplicationContext() @Test @@ -27,7 +26,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customMasterCountries = "AU,TG,ZA", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertTrue(dataStore.countryList.any { it.alpha2 == "AU" }) @@ -42,7 +41,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customMasterCountries = "LKA,GHA,AFG", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertTrue(dataStore.countryList.any { it.alpha3 == "LKA" }) assertTrue(dataStore.countryList.any { it.alpha3 == "GHA" }) @@ -56,7 +55,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customMasterCountries = "AU,TG,ZA,LKA,GHA,AFG", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertTrue(dataStore.countryList.any { it.alpha3 == "LKA" }) assertTrue(dataStore.countryList.any { it.alpha3 == "GHA" }) @@ -73,7 +72,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customMasterCountries = "LKA,GHA,AFG,QQQ", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertTrue(dataStore.countryList.none { it.alpha3 == "QQQ" }) assertTrue(dataStore.countryList.any { it.alpha3 == "LKA" }) @@ -88,7 +87,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customMasterCountries = "AU,TG,QQ,ZA", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertTrue(dataStore.countryList.none { it.alpha2 == "QQ" }) assertTrue(dataStore.countryList.any { it.alpha2 == "AU" }) @@ -103,7 +102,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customMasterCountries = "AU,TG,DD,ZA,LKA,GHA,AFG,QQQ", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertTrue(dataStore.countryList.none { it.alpha2 == "DD" }) assertTrue(dataStore.countryList.none { it.alpha3 == "QQQ" }) @@ -122,7 +121,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customMasterCountries = "", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertEquals(10, dataStore.countryList.size) } @@ -133,7 +132,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customMasterCountries = "QQ,DDD,ANYThing", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertEquals(10, dataStore.countryList.size) } @@ -144,7 +143,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customExcludedCountries = "AU,TG,ZA", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertTrue(dataStore.countryList.none { it.alpha2 == "AU" }) assertTrue(dataStore.countryList.none { it.alpha2 == "TG" }) @@ -158,7 +157,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customExcludedCountries = "LKA,GHA,AFG", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertTrue(dataStore.countryList.none { it.alpha3 == "LKA" }) assertTrue(dataStore.countryList.none { it.alpha3 == "GHA" }) @@ -172,7 +171,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customExcludedCountries = "AU,TG,ZA,LKA,GHA,AFG", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertTrue(dataStore.countryList.none { it.alpha3 == "LKA" }) assertTrue(dataStore.countryList.none { it.alpha3 == "GHA" }) @@ -189,7 +188,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customExcludedCountries = "LKA,GHA,AFG,QQQ", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertTrue(dataStore.countryList.none { it.alpha3 == "LKA" }) assertTrue(dataStore.countryList.none { it.alpha3 == "GHA" }) @@ -203,7 +202,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customExcludedCountries = "AU,TG,QQ,ZA", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertTrue(dataStore.countryList.none { it.alpha2 == "AU" }) assertTrue(dataStore.countryList.none { it.alpha2 == "TG" }) @@ -217,7 +216,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customExcludedCountries = "AU,TG,DD,ZA,LKA,GHA,AFG,QQQ", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertTrue(dataStore.countryList.none { it.alpha3 == "LKA" }) assertTrue(dataStore.countryList.none { it.alpha3 == "GHA" }) @@ -234,7 +233,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customExcludedCountries = " ", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertEquals(10, dataStore.countryList.size) } @@ -245,7 +244,7 @@ class CPDataStoreGeneratorTest { CPDataStoreGenerator.generate( context, customExcludedCountries = "QQ,DDD,ANYThing", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) assertEquals(10, dataStore.countryList.size) } @@ -257,7 +256,7 @@ class CPDataStoreGeneratorTest { context, customMasterCountries = "AU,TG,DD,ZA,LKA,GHA,AFG,QQQ", customExcludedCountries = "AUS,ZA,IN,QQ,DDD,ANYThing", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) // master list: AU/AUS,TG,ZA,LKA,GHA,AFG // after excluded: TG,LKA,GHA,AFG @@ -271,7 +270,7 @@ class CPDataStoreGeneratorTest { context, customMasterCountries = "AU,TG,DD,ZA,LKA,GHA,AFG", customExcludedCountries = "AUS,TG,AU,ZA,LKA,GHA,AFG,QQQ", - countryFileReader = MockCountryFileReader + countryFileReader = MockCountryFileReader, ) // master list: AU,TG,ZA,LKA,GHA,AFG assertEquals(6, dataStore.countryList.size) diff --git a/countrypicker/src/test/java/com/hbb20/CPRecyclerViewHelperTest.kt b/countrypicker/src/test/java/com/hbb20/CPRecyclerViewHelperTest.kt index 74bce40..305154a 100644 --- a/countrypicker/src/test/java/com/hbb20/CPRecyclerViewHelperTest.kt +++ b/countrypicker/src/test/java/com/hbb20/CPRecyclerViewHelperTest.kt @@ -14,74 +14,78 @@ import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) class CPRecyclerViewHelperTest { - private val context = mockk {} private val dataStore = CPDataStoreGenerator.generate(context, countryFileReader = MockCountryFileReader) @Test fun preferredCountriesWorkWithAlpha2() { - - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - cpListConfig = CPListConfig(preferredCountryCodes = "IN,AU"), - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + cpListConfig = CPListConfig(preferredCountryCodes = "IN,AU"), + onCountryClickListener = mockk(), + ) assertEquals("IN", helper.allPreferredCountries[0].alpha2) assertEquals("AU", helper.allPreferredCountries[1].alpha2) } @Test fun trimCodeBeforePreferred() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - cpListConfig = CPListConfig(preferredCountryCodes = "IN ,AU"), - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + cpListConfig = CPListConfig(preferredCountryCodes = "IN ,AU"), + onCountryClickListener = mockk(), + ) assertEquals("IN", helper.allPreferredCountries[0].alpha2) assertEquals("AU", helper.allPreferredCountries[1].alpha2) } @Test fun preferredCountriesWorkWithAlpha3() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - cpListConfig = CPListConfig(preferredCountryCodes = "IND,AUS"), - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + cpListConfig = CPListConfig(preferredCountryCodes = "IND,AUS"), + onCountryClickListener = mockk(), + ) assertEquals("IN", helper.allPreferredCountries[0].alpha2) assertEquals("AU", helper.allPreferredCountries[1].alpha2) } @Test fun preferredCountriesWorkWithAlpha2and3() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - cpListConfig = CPListConfig(preferredCountryCodes = "IN,AUS"), - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + cpListConfig = CPListConfig(preferredCountryCodes = "IN,AUS"), + onCountryClickListener = mockk(), + ) assertEquals("IN", helper.allPreferredCountries[0].alpha2) assertEquals("AU", helper.allPreferredCountries[1].alpha2) } @Test fun invalidCodesAvoidedSafely() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - cpListConfig = CPListConfig(preferredCountryCodes = "XX,IN,YYY,21dksaj,AUS"), - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + cpListConfig = CPListConfig(preferredCountryCodes = "XX,IN,YYY,21dksaj,AUS"), + onCountryClickListener = mockk(), + ) assertEquals("IN", helper.allPreferredCountries[0].alpha2) assertEquals("AU", helper.allPreferredCountries[1].alpha2) } @Test fun duplicateCodesAreRemoved() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - cpListConfig = CPListConfig(preferredCountryCodes = "IN,AUS,IN"), - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + cpListConfig = CPListConfig(preferredCountryCodes = "IN,AUS,IN"), + onCountryClickListener = mockk(), + ) assertEquals("IN", helper.allPreferredCountries[0].alpha2) assertEquals("AU", helper.allPreferredCountries[1].alpha2) @@ -90,11 +94,12 @@ class CPRecyclerViewHelperTest { @Test fun duplicateCountriesAreRemoved() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - cpListConfig = CPListConfig(preferredCountryCodes = "IN,AUS,IND"), - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + cpListConfig = CPListConfig(preferredCountryCodes = "IN,AUS,IND"), + onCountryClickListener = mockk(), + ) assertEquals("IN", helper.allPreferredCountries[0].alpha2) assertEquals("AU", helper.allPreferredCountries[1].alpha2) @@ -103,10 +108,11 @@ class CPRecyclerViewHelperTest { @Test fun `filter for name`() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + onCountryClickListener = mockk(), + ) helper.updateDataForQuery("United States") assertEquals("US", helper.controllerData.allCountries[0].alpha2) @@ -115,10 +121,11 @@ class CPRecyclerViewHelperTest { @Test fun `filter for part of name`() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + onCountryClickListener = mockk(), + ) helper.updateDataForQuery("United") assertEquals("US", helper.controllerData.allCountries[0].alpha2) @@ -127,10 +134,11 @@ class CPRecyclerViewHelperTest { @Test fun `filter for english name`() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + onCountryClickListener = mockk(), + ) helper.updateDataForQuery("United States") assertEquals("US", helper.controllerData.allCountries[0].alpha2) @@ -139,10 +147,11 @@ class CPRecyclerViewHelperTest { @Test fun `filter for part of english name`() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + onCountryClickListener = mockk(), + ) helper.updateDataForQuery("nited") assertEquals("US", helper.controllerData.allCountries[0].alpha2) @@ -151,11 +160,12 @@ class CPRecyclerViewHelperTest { @Test fun `filter for alpha3 code`() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - cpRowConfig = CPRowConfig(highlightedTextGenerator = { it.alpha3 }), - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + cpRowConfig = CPRowConfig(highlightedTextGenerator = { it.alpha3 }), + onCountryClickListener = mockk(), + ) helper.updateDataForQuery("LKA") assertEquals("LK", helper.controllerData.allCountries[0].alpha2) assertEquals(1, helper.controllerData.allCountries.size) @@ -163,11 +173,12 @@ class CPRecyclerViewHelperTest { @Test fun `filter for alpha2 code`() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - cpRowConfig = CPRowConfig(highlightedTextGenerator = { it.alpha2 }), - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + cpRowConfig = CPRowConfig(highlightedTextGenerator = { it.alpha2 }), + onCountryClickListener = mockk(), + ) helper.updateDataForQuery("LK") assertEquals("LK", helper.controllerData.allCountries[0].alpha2) assertEquals(1, helper.controllerData.allCountries.size) @@ -175,11 +186,12 @@ class CPRecyclerViewHelperTest { @Test fun `filter for phone code`() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - cpRowConfig = CPRowConfig(highlightedTextGenerator = { it.phoneCode.toString() }), - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + cpRowConfig = CPRowConfig(highlightedTextGenerator = { it.phoneCode.toString() }), + onCountryClickListener = mockk(), + ) helper.updateDataForQuery("94") assertEquals("LK", helper.controllerData.allCountries[0].alpha2) assertEquals(1, helper.controllerData.allCountries.size) @@ -187,11 +199,12 @@ class CPRecyclerViewHelperTest { @Test fun `filter for partial phone code`() { - val helper = CPRecyclerViewHelper( - cpDataStore = dataStore, - cpRowConfig = CPRowConfig(highlightedTextGenerator = { it.phoneCode.toString() }), - onCountryClickListener = mockk() - ) + val helper = + CPRecyclerViewHelper( + cpDataStore = dataStore, + cpRowConfig = CPRowConfig(highlightedTextGenerator = { it.phoneCode.toString() }), + onCountryClickListener = mockk(), + ) helper.updateDataForQuery("9") assertTrue(helper.controllerData.allCountries.any { it.alpha2 == "AF" }) diff --git a/countrypicker/src/test/java/com/hbb20/MockCountryFileReader.kt b/countrypicker/src/test/java/com/hbb20/MockCountryFileReader.kt index 19180aa..fff34bd 100644 --- a/countrypicker/src/test/java/com/hbb20/MockCountryFileReader.kt +++ b/countrypicker/src/test/java/com/hbb20/MockCountryFileReader.kt @@ -5,8 +5,7 @@ import com.hbb20.countrypicker.datagenerator.CountryFileReading import com.hbb20.countrypicker.models.CPDataStore object MockCountryFileReader : - CountryFileReading { - + CountryFileReading { override fun readMasterDataFromFiles(context: Context): CPDataStore { return getSampleDataStore() } diff --git a/countrypicker/src/test/java/com/hbb20/SampleDataStore.kt b/countrypicker/src/test/java/com/hbb20/SampleDataStore.kt index 785ec08..b1afc09 100644 --- a/countrypicker/src/test/java/com/hbb20/SampleDataStore.kt +++ b/countrypicker/src/test/java/com/hbb20/SampleDataStore.kt @@ -20,8 +20,8 @@ fun getSampleDataStore(): CPDataStore { currencyName = "Afghan Afghani", currencySymbol = "؋", cctld = "af", - flagEmoji = "\uD83C\uDDE6\uD83C\uDDEB" - ) + flagEmoji = "\uD83C\uDDE6\uD83C\uDDEB", + ), ) masterCountryList.add( @@ -39,8 +39,8 @@ fun getSampleDataStore(): CPDataStore { currencyName = "Australian Dollar", currencySymbol = "$", cctld = "au", - flagEmoji = "\uD83C\uDDE6\uD83C\uDDFA" - ) + flagEmoji = "\uD83C\uDDE6\uD83C\uDDFA", + ), ) masterCountryList.add( CPCountry( @@ -57,8 +57,8 @@ fun getSampleDataStore(): CPDataStore { currencyName = "Ghanaian New Cedi", currencySymbol = "GH₵", cctld = "gh", - flagEmoji = "\uD83C\uDDEC\uD83C\uDDED" - ) + flagEmoji = "\uD83C\uDDEC\uD83C\uDDED", + ), ) masterCountryList.add( CPCountry( @@ -75,8 +75,8 @@ fun getSampleDataStore(): CPDataStore { currencyName = "Indian Rupee", currencySymbol = "₹", cctld = "in", - flagEmoji = "\uD83C\uDDEE\uD83C\uDDF3" - ) + flagEmoji = "\uD83C\uDDEE\uD83C\uDDF3", + ), ) masterCountryList.add( CPCountry( @@ -93,8 +93,8 @@ fun getSampleDataStore(): CPDataStore { currencyName = "Sri Lanka Rupee", currencySymbol = "රු", cctld = "lk", - flagEmoji = "\uD83C\uDDF1\uD83C\uDDF0" - ) + flagEmoji = "\uD83C\uDDF1\uD83C\uDDF0", + ), ) masterCountryList.add( CPCountry( @@ -111,8 +111,8 @@ fun getSampleDataStore(): CPDataStore { currencyName = "Russian Rouble", currencySymbol = "\u20BD", cctld = "ru", - flagEmoji = "\uD83C\uDDF7\uD83C\uDDFA" - ) + flagEmoji = "\uD83C\uDDF7\uD83C\uDDFA", + ), ) masterCountryList.add( CPCountry( @@ -129,8 +129,8 @@ fun getSampleDataStore(): CPDataStore { currencyName = "Cfa Franc Bceao", currencySymbol = "CFA", cctld = "tg", - flagEmoji = "\uD83C\uDDF9\uD83C\uDDEC" - ) + flagEmoji = "\uD83C\uDDF9\uD83C\uDDEC", + ), ) masterCountryList.add( CPCountry( @@ -147,8 +147,8 @@ fun getSampleDataStore(): CPDataStore { currencyName = "United States Dollar", currencySymbol = "$", cctld = "us", - flagEmoji = "\uD83C\uDDFA\uD83C\uDDF8" - ) + flagEmoji = "\uD83C\uDDFA\uD83C\uDDF8", + ), ) masterCountryList.add( CPCountry( @@ -165,8 +165,8 @@ fun getSampleDataStore(): CPDataStore { currencyName = "South African Rand", currencySymbol = "R", cctld = "za", - flagEmoji = "\uD83C\uDDFF\uD83C\uDDE6" - ) + flagEmoji = "\uD83C\uDDFF\uD83C\uDDE6", + ), ) masterCountryList.add( CPCountry( @@ -183,8 +183,8 @@ fun getSampleDataStore(): CPDataStore { currencyName = "Zimbabwe Dollar", currencySymbol = "$", cctld = "zw", - flagEmoji = "\uD83C\uDDFF\uD83C\uDDFC" - ) + flagEmoji = "\uD83C\uDDFF\uD83C\uDDFC", + ), ) return CPDataStore( masterCountryList, @@ -192,7 +192,7 @@ fun getSampleDataStore(): CPDataStore { "No matching result found", "Search...", "Select a country", - "Country" - ) + "Country", + ), ) } diff --git a/countrypicker/src/test/java/com/hbb20/countrypicker/config/CPDialogConfigTest.kt b/countrypicker/src/test/java/com/hbb20/countrypicker/config/CPDialogConfigTest.kt index bdd5982..56ab402 100644 --- a/countrypicker/src/test/java/com/hbb20/countrypicker/config/CPDialogConfigTest.kt +++ b/countrypicker/src/test/java/com/hbb20/countrypicker/config/CPDialogConfigTest.kt @@ -7,7 +7,6 @@ import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) class CPDialogConfigTest { - @Test fun `when resize mode is auto and full screen is false, wrap mode is applied`() { val config = CPDialogConfig(showFullScreen = false, sizeMode = SizeMode.Auto) @@ -31,4 +30,4 @@ class CPDialogConfigTest { val config = CPDialogConfig(showFullScreen = false, sizeMode = SizeMode.Unchanged) assertEquals(SizeMode.Unchanged, config.getApplicableResizeMode()) } -} \ No newline at end of file +} diff --git a/countrypicker/src/test/java/com/hbb20/countrypicker/helper/CountryPickerDialogAttrReaderKtTest.kt b/countrypicker/src/test/java/com/hbb20/countrypicker/helper/CountryPickerDialogAttrReaderKtTest.kt index 848b17b..964971a 100644 --- a/countrypicker/src/test/java/com/hbb20/countrypicker/helper/CountryPickerDialogAttrReaderKtTest.kt +++ b/countrypicker/src/test/java/com/hbb20/countrypicker/helper/CountryPickerDialogAttrReaderKtTest.kt @@ -12,12 +12,12 @@ import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) class CountryPickerDialogAttrReaderKtTest { - @Test fun `allow search = false set in config`() { - val attr: TypedArray = mockk(relaxed = true) { - every { getBoolean(CountryPickerView_cpDialog_allowSearch, any()) } returns false - } + val attr: TypedArray = + mockk(relaxed = true) { + every { getBoolean(CountryPickerView_cpDialog_allowSearch, any()) } returns false + } val dialogConfig = readDialogConfigFromAttrs(attr) assertFalse("Should be false because attribute is set to false", dialogConfig.allowSearch) @@ -25,9 +25,10 @@ class CountryPickerDialogAttrReaderKtTest { @Test fun `allow search = true set in config`() { - val attr: TypedArray = mockk(relaxed = true) { - every { getBoolean(CountryPickerView_cpDialog_allowSearch, any()) } returns true - } + val attr: TypedArray = + mockk(relaxed = true) { + every { getBoolean(CountryPickerView_cpDialog_allowSearch, any()) } returns true + } val dialogConfig = readDialogConfigFromAttrs(attr) assertTrue("Should be true because attribute is set to true", dialogConfig.allowSearch) @@ -35,40 +36,43 @@ class CountryPickerDialogAttrReaderKtTest { @Test fun `allow clear selection = false set in config`() { - val attr: TypedArray = mockk(relaxed = true) { - every { - getBoolean( - CountryPickerView_cpDialog_allowClearSelection, - any() - ) - } returns false - } + val attr: TypedArray = + mockk(relaxed = true) { + every { + getBoolean( + CountryPickerView_cpDialog_allowClearSelection, + any(), + ) + } returns false + } val dialogConfig = readDialogConfigFromAttrs(attr) assertFalse( "Should be false because attribute is set to false", - dialogConfig.allowClearSelection + dialogConfig.allowClearSelection, ) } @Test fun `allow clear selection = true set in config`() { - val attr: TypedArray = mockk(relaxed = true) { - every { getBoolean(CountryPickerView_cpDialog_allowClearSelection, any()) } returns true - } + val attr: TypedArray = + mockk(relaxed = true) { + every { getBoolean(CountryPickerView_cpDialog_allowClearSelection, any()) } returns true + } val dialogConfig = readDialogConfigFromAttrs(attr) assertTrue( "Should be true because attribute is set to true", - dialogConfig.allowClearSelection + dialogConfig.allowClearSelection, ) } @Test fun `show title = false set in config`() { - val attr: TypedArray = mockk(relaxed = true) { - every { getBoolean(CountryPickerView_cpDialog_showTitle, any()) } returns false - } + val attr: TypedArray = + mockk(relaxed = true) { + every { getBoolean(CountryPickerView_cpDialog_showTitle, any()) } returns false + } val dialogConfig = readDialogConfigFromAttrs(attr) assertFalse("Should be false because attribute is set to false", dialogConfig.showTitle) @@ -76,9 +80,10 @@ class CountryPickerDialogAttrReaderKtTest { @Test fun `show title = true set in config`() { - val attr: TypedArray = mockk(relaxed = true) { - every { getBoolean(CountryPickerView_cpDialog_showTitle, any()) } returns true - } + val attr: TypedArray = + mockk(relaxed = true) { + every { getBoolean(CountryPickerView_cpDialog_showTitle, any()) } returns true + } val dialogConfig = readDialogConfigFromAttrs(attr) assertTrue("Should be true because attribute is set to true", dialogConfig.showTitle) @@ -86,22 +91,24 @@ class CountryPickerDialogAttrReaderKtTest { @Test fun `show fullscreen = false set in config`() { - val attr: TypedArray = mockk(relaxed = true) { - every { getBoolean(CountryPickerView_cpDialog_showFullScreen, any()) } returns false - } + val attr: TypedArray = + mockk(relaxed = true) { + every { getBoolean(CountryPickerView_cpDialog_showFullScreen, any()) } returns false + } val dialogConfig = readDialogConfigFromAttrs(attr) assertFalse( "Should be false because attribute is set to false", - dialogConfig.showFullScreen + dialogConfig.showFullScreen, ) } @Test fun `show fullscreen = true set in config`() { - val attr: TypedArray = mockk(relaxed = true) { - every { getBoolean(CountryPickerView_cpDialog_showFullScreen, any()) } returns true - } + val attr: TypedArray = + mockk(relaxed = true) { + every { getBoolean(CountryPickerView_cpDialog_showFullScreen, any()) } returns true + } val dialogConfig = readDialogConfigFromAttrs(attr) assertTrue("Should be true because attribute is set to true", dialogConfig.showFullScreen) diff --git a/countrypicker/src/test/java/com/hbb20/countrypicker/helper/CountryPickerListAttrReaderKtTest.kt b/countrypicker/src/test/java/com/hbb20/countrypicker/helper/CountryPickerListAttrReaderKtTest.kt index 24863bf..62dc63e 100644 --- a/countrypicker/src/test/java/com/hbb20/countrypicker/helper/CountryPickerListAttrReaderKtTest.kt +++ b/countrypicker/src/test/java/com/hbb20/countrypicker/helper/CountryPickerListAttrReaderKtTest.kt @@ -8,12 +8,12 @@ import junit.framework.Assert.assertEquals import org.junit.Test class CountryPickerListAttrReaderKtTest { - @Test fun `preferred countries attr is set in config`() { - val attr: TypedArray = mockk(relaxed = true) { - every { getString(R.styleable.CountryPickerView_cpList_preferredCountryCodes) } returns "IN,US" - } + val attr: TypedArray = + mockk(relaxed = true) { + every { getString(R.styleable.CountryPickerView_cpList_preferredCountryCodes) } returns "IN,US" + } val listConfig = readListConfigFromAttrs(attr) assertEquals("Must match the attribute value", "IN,US", listConfig.preferredCountryCodes) diff --git a/flagpack1/build.gradle.kts b/flagpack1/build.gradle.kts index f359b23..b2e738a 100644 --- a/flagpack1/build.gradle.kts +++ b/flagpack1/build.gradle.kts @@ -15,12 +15,12 @@ android { viewBinding = true } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = BuildData.appJavaVersion + targetCompatibility = BuildData.appJavaVersion } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8.toString() + jvmTarget = BuildData.appJavaVersion.toString() } testOptions { diff --git a/flagpack1/src/main/java/com/hbb20/contrypicker/flagpack1/FlagPack1.kt b/flagpack1/src/main/java/com/hbb20/contrypicker/flagpack1/FlagPack1.kt index ea8952a..f9588b6 100644 --- a/flagpack1/src/main/java/com/hbb20/contrypicker/flagpack1/FlagPack1.kt +++ b/flagpack1/src/main/java/com/hbb20/contrypicker/flagpack1/FlagPack1.kt @@ -2,252 +2,263 @@ package com.hbb20.contrypicker.flagpack1 object FlagPack1 { val missingFlagPlaceHolder: Int = R.drawable.flag_transparent - val alpha2ToFlag = mapOf( - "ad" to R.drawable.flag_andorra, - "ae" to R.drawable.flag_uae, - "af" to R.drawable.flag_afghanistan, - "ag" to R.drawable.flag_antigua_and_barbuda, - "ai" to R.drawable.flag_anguilla, - "al" to R.drawable.flag_albania, - "am" to R.drawable.flag_armenia, - "ao" to R.drawable.flag_angola, - "aq" to R.drawable.flag_antarctica, - "ar" to R.drawable.flag_argentina, - "as" to R.drawable.flag_american_samoa, - "at" to R.drawable.flag_austria, - "au" to R.drawable.flag_australia, - "aw" to R.drawable.flag_aruba, - "ax" to R.drawable.flag_aland, - "az" to R.drawable.flag_azerbaijan, - "ba" to R.drawable.flag_bosnia, - "bb" to R.drawable.flag_barbados, - "bd" to R.drawable.flag_bangladesh, - "be" to R.drawable.flag_belgium, - "bf" to R.drawable.flag_burkina_faso, - "bg" to R.drawable.flag_bulgaria, - "bh" to R.drawable.flag_bahrain, - "bi" to R.drawable.flag_burundi, - "bj" to R.drawable.flag_benin, - "bl" to R.drawable.flag_saint_barthelemy, // custom, - "bm" to R.drawable.flag_bermuda, - "bn" to R.drawable.flag_brunei, - "bo" to R.drawable.flag_bolivia, - "br" to R.drawable.flag_brazil, - "bs" to R.drawable.flag_bahamas, - "bt" to R.drawable.flag_bhutan, - "bw" to R.drawable.flag_botswana, - "by" to R.drawable.flag_belarus, - "bz" to R.drawable.flag_belize, - "ca" to R.drawable.flag_canada, - "cc" to R.drawable.flag_cocos, // custom, - "cd" to R.drawable.flag_democratic_republic_of_the_congo, - "cf" to R.drawable.flag_central_african_republic, - "cg" to R.drawable.flag_republic_of_the_congo, - "ch" to R.drawable.flag_switzerland, - "ci" to R.drawable.flag_cote_divoire, - "ck" to R.drawable.flag_cook_islands, - "cl" to R.drawable.flag_chile, - "cm" to R.drawable.flag_cameroon, - "cn" to R.drawable.flag_china, - "co" to R.drawable.flag_colombia, - "cr" to R.drawable.flag_costa_rica, - "cu" to R.drawable.flag_cuba, - "cv" to R.drawable.flag_cape_verde, - "cw" to R.drawable.flag_curacao, - "cx" to R.drawable.flag_christmas_island, - "cy" to R.drawable.flag_cyprus, - "cz" to R.drawable.flag_czech_republic, - "de" to R.drawable.flag_germany, - "dj" to R.drawable.flag_djibouti, - "dk" to R.drawable.flag_denmark, - "dm" to R.drawable.flag_dominica, - "do" to R.drawable.flag_dominican_republic, - "dz" to R.drawable.flag_algeria, - "ec" to R.drawable.flag_ecuador, - "ee" to R.drawable.flag_estonia, - "eg" to R.drawable.flag_egypt, - "er" to R.drawable.flag_eritrea, - "es" to R.drawable.flag_spain, - "et" to R.drawable.flag_ethiopia, - "fi" to R.drawable.flag_finland, - "fj" to R.drawable.flag_fiji, - "fk" to R.drawable.flag_falkland_islands, - "fm" to R.drawable.flag_micronesia, - "fo" to R.drawable.flag_faroe_islands, - "fr" to R.drawable.flag_france, - "ga" to R.drawable.flag_gabon, - "gb" to R.drawable.flag_united_kingdom, - "gd" to R.drawable.flag_grenada, - "ge" to R.drawable.flag_georgia, - "gf" to R.drawable.flag_guyane, - "gg" to R.drawable.flag_guernsey, - "gh" to R.drawable.flag_ghana, - "gi" to R.drawable.flag_gibraltar, - "gl" to R.drawable.flag_greenland, - "gm" to R.drawable.flag_gambia, - "gn" to R.drawable.flag_guinea, - "gp" to R.drawable.flag_guadeloupe, - "gq" to R.drawable.flag_equatorial_guinea, - "gr" to R.drawable.flag_greece, - "gt" to R.drawable.flag_guatemala, - "gu" to R.drawable.flag_guam, - "gw" to R.drawable.flag_guinea_bissau, - "gy" to R.drawable.flag_guyana, - "hk" to R.drawable.flag_hong_kong, - "hn" to R.drawable.flag_honduras, - "hr" to R.drawable.flag_croatia, - "ht" to R.drawable.flag_haiti, - "hu" to R.drawable.flag_hungary, - "id" to R.drawable.flag_indonesia, - "ie" to R.drawable.flag_ireland, - "il" to R.drawable.flag_israel, - "im" to R.drawable.flag_isleof_man, // custom, - "is" to R.drawable.flag_iceland, - "in" to R.drawable.flag_india, - "io" to R.drawable.flag_british_indian_ocean_territory, - "iq" to R.drawable.flag_iraq_new, - "ir" to R.drawable.flag_iran, - "it" to R.drawable.flag_italy, - "je" to R.drawable.flag_jersey, - "jm" to R.drawable.flag_jamaica, - "jo" to R.drawable.flag_jordan, - "jp" to R.drawable.flag_japan, - "ke" to R.drawable.flag_kenya, - "kg" to R.drawable.flag_kyrgyzstan, - "kh" to R.drawable.flag_cambodia, - "ki" to R.drawable.flag_kiribati, - "km" to R.drawable.flag_comoros, - "kn" to R.drawable.flag_saint_kitts_and_nevis, - "kp" to R.drawable.flag_north_korea, - "kr" to R.drawable.flag_south_korea, - "kw" to R.drawable.flag_kuwait, - "ky" to R.drawable.flag_cayman_islands, - "kz" to R.drawable.flag_kazakhstan, - "la" to R.drawable.flag_laos, - "lb" to R.drawable.flag_lebanon, - "lc" to R.drawable.flag_saint_lucia, - "li" to R.drawable.flag_liechtenstein, - "lk" to R.drawable.flag_sri_lanka, - "lr" to R.drawable.flag_liberia, - "ls" to R.drawable.flag_lesotho, - "lt" to R.drawable.flag_lithuania, - "lu" to R.drawable.flag_luxembourg, - "lv" to R.drawable.flag_latvia, - "ly" to R.drawable.flag_libya, - "ma" to R.drawable.flag_morocco, - "mc" to R.drawable.flag_monaco, - "md" to R.drawable.flag_moldova, - "me" to R.drawable.flag_of_montenegro, // custom, - "mf" to R.drawable.flag_saint_martin, - "mg" to R.drawable.flag_madagascar, - "mh" to R.drawable.flag_marshall_islands, - "mk" to R.drawable.flag_macedonia, - "ml" to R.drawable.flag_mali, - "mm" to R.drawable.flag_myanmar, - "mn" to R.drawable.flag_mongolia, - "mo" to R.drawable.flag_macao, - "mp" to R.drawable.flag_northern_mariana_islands, - "mq" to R.drawable.flag_martinique, - "mr" to R.drawable.flag_mauritania, - "ms" to R.drawable.flag_montserrat, - "mt" to R.drawable.flag_malta, - "mu" to R.drawable.flag_mauritius, - "mv" to R.drawable.flag_maldives, - "mw" to R.drawable.flag_malawi, - "mx" to R.drawable.flag_mexico, - "my" to R.drawable.flag_malaysia, - "mz" to R.drawable.flag_mozambique, - "na" to R.drawable.flag_namibia, - "nc" to R.drawable.flag_new_caledonia, // custom, - "ne" to R.drawable.flag_niger, - "nf" to R.drawable.flag_norfolk_island, - "ng" to R.drawable.flag_nigeria, - "ni" to R.drawable.flag_nicaragua, - "nl" to R.drawable.flag_netherlands, - "no" to R.drawable.flag_norway, - "np" to R.drawable.flag_nepal, - "nr" to R.drawable.flag_nauru, - "nu" to R.drawable.flag_niue, - "nz" to R.drawable.flag_new_zealand, - "om" to R.drawable.flag_oman, - "pa" to R.drawable.flag_panama, - "pe" to R.drawable.flag_peru, - "pf" to R.drawable.flag_french_polynesia, - "pg" to R.drawable.flag_papua_new_guinea, - "ph" to R.drawable.flag_philippines, - "pk" to R.drawable.flag_pakistan, - "pl" to R.drawable.flag_poland, - "pm" to R.drawable.flag_saint_pierre, - "pn" to R.drawable.flag_pitcairn_islands, - "pr" to R.drawable.flag_puerto_rico, - "ps" to R.drawable.flag_palestine, - "pt" to R.drawable.flag_portugal, - "pw" to R.drawable.flag_palau, - "py" to R.drawable.flag_paraguay, - "qa" to R.drawable.flag_qatar, - "re" to R.drawable.flag_martinique, // no exact flag found, - "ro" to R.drawable.flag_romania, - "rs" to R.drawable.flag_serbia, // custom, - "ru" to R.drawable.flag_russian_federation, - "rw" to R.drawable.flag_rwanda, - "sa" to R.drawable.flag_saudi_arabia, - "sb" to R.drawable.flag_soloman_islands, - "sc" to R.drawable.flag_seychelles, - "sd" to R.drawable.flag_sudan, - "se" to R.drawable.flag_sweden, - "sg" to R.drawable.flag_singapore, - "sh" to R.drawable.flag_saint_helena, // custom, - "si" to R.drawable.flag_slovenia, - "sk" to R.drawable.flag_slovakia, - "sl" to R.drawable.flag_sierra_leone, - "sm" to R.drawable.flag_san_marino, - "sn" to R.drawable.flag_senegal, - "so" to R.drawable.flag_somalia, - "sr" to R.drawable.flag_suriname, - "ss" to R.drawable.flag_south_sudan, - "st" to R.drawable.flag_sao_tome_and_principe, - "sv" to R.drawable.flag_el_salvador, - "sx" to R.drawable.flag_sint_maarten, - "sy" to R.drawable.flag_syria, - "sz" to R.drawable.flag_swaziland, - "tc" to R.drawable.flag_turks_and_caicos_islands, - "td" to R.drawable.flag_chad, - "tg" to R.drawable.flag_togo, - "th" to R.drawable.flag_thailand, - "tj" to R.drawable.flag_tajikistan, - "tk" to R.drawable.flag_tokelau, // custom, - "tl" to R.drawable.flag_timor_leste, - "tm" to R.drawable.flag_turkmenistan, - "tn" to R.drawable.flag_tunisia, - "to" to R.drawable.flag_tonga, - "tr" to R.drawable.flag_turkey, - "tt" to R.drawable.flag_trinidad_and_tobago, - "tv" to R.drawable.flag_tuvalu, - "tw" to R.drawable.flag_taiwan, - "tz" to R.drawable.flag_tanzania, - "ua" to R.drawable.flag_ukraine, - "ug" to R.drawable.flag_uganda, - "us" to R.drawable.flag_united_states_of_america, - "uy" to R.drawable.flag_uruguay, - "uz" to R.drawable.flag_uzbekistan, - "va" to R.drawable.flag_vatican_city, - "vc" to R.drawable.flag_saint_vicent_and_the_grenadines, - "ve" to R.drawable.flag_venezuela, - "vg" to R.drawable.flag_british_virgin_islands, - "vi" to R.drawable.flag_us_virgin_islands, - "vn" to R.drawable.flag_vietnam, - "vu" to R.drawable.flag_vanuatu, - "wf" to R.drawable.flag_wallis_and_futuna, - "ws" to R.drawable.flag_samoa, - "xk" to R.drawable.flag_kosovo, - "ye" to R.drawable.flag_yemen, - "yt" to R.drawable.flag_martinique, // no exact flag found, - "za" to R.drawable.flag_south_africa, - "zm" to R.drawable.flag_zambia, - "zw" to R.drawable.flag_zimbabwe, - "bq" to R.drawable.flag_bq, - "tf" to R.drawable.flag_tf, - "gs" to R.drawable.flag_gs, - "eh" to R.drawable.flag_eh, - ) -} \ No newline at end of file + val alpha2ToFlag = + mapOf( + "ad" to R.drawable.flag_andorra, + "ae" to R.drawable.flag_uae, + "af" to R.drawable.flag_afghanistan, + "ag" to R.drawable.flag_antigua_and_barbuda, + "ai" to R.drawable.flag_anguilla, + "al" to R.drawable.flag_albania, + "am" to R.drawable.flag_armenia, + "ao" to R.drawable.flag_angola, + "aq" to R.drawable.flag_antarctica, + "ar" to R.drawable.flag_argentina, + "as" to R.drawable.flag_american_samoa, + "at" to R.drawable.flag_austria, + "au" to R.drawable.flag_australia, + "aw" to R.drawable.flag_aruba, + "ax" to R.drawable.flag_aland, + "az" to R.drawable.flag_azerbaijan, + "ba" to R.drawable.flag_bosnia, + "bb" to R.drawable.flag_barbados, + "bd" to R.drawable.flag_bangladesh, + "be" to R.drawable.flag_belgium, + "bf" to R.drawable.flag_burkina_faso, + "bg" to R.drawable.flag_bulgaria, + "bh" to R.drawable.flag_bahrain, + "bi" to R.drawable.flag_burundi, + "bj" to R.drawable.flag_benin, + "bl" to R.drawable.flag_saint_barthelemy, + // custom 👆🏽 + "bm" to R.drawable.flag_bermuda, + "bn" to R.drawable.flag_brunei, + "bo" to R.drawable.flag_bolivia, + "br" to R.drawable.flag_brazil, + "bs" to R.drawable.flag_bahamas, + "bt" to R.drawable.flag_bhutan, + "bw" to R.drawable.flag_botswana, + "by" to R.drawable.flag_belarus, + "bz" to R.drawable.flag_belize, + "ca" to R.drawable.flag_canada, + "cc" to R.drawable.flag_cocos, + // custom 👆🏽 + "cd" to R.drawable.flag_democratic_republic_of_the_congo, + "cf" to R.drawable.flag_central_african_republic, + "cg" to R.drawable.flag_republic_of_the_congo, + "ch" to R.drawable.flag_switzerland, + "ci" to R.drawable.flag_cote_divoire, + "ck" to R.drawable.flag_cook_islands, + "cl" to R.drawable.flag_chile, + "cm" to R.drawable.flag_cameroon, + "cn" to R.drawable.flag_china, + "co" to R.drawable.flag_colombia, + "cr" to R.drawable.flag_costa_rica, + "cu" to R.drawable.flag_cuba, + "cv" to R.drawable.flag_cape_verde, + "cw" to R.drawable.flag_curacao, + "cx" to R.drawable.flag_christmas_island, + "cy" to R.drawable.flag_cyprus, + "cz" to R.drawable.flag_czech_republic, + "de" to R.drawable.flag_germany, + "dj" to R.drawable.flag_djibouti, + "dk" to R.drawable.flag_denmark, + "dm" to R.drawable.flag_dominica, + "do" to R.drawable.flag_dominican_republic, + "dz" to R.drawable.flag_algeria, + "ec" to R.drawable.flag_ecuador, + "ee" to R.drawable.flag_estonia, + "eg" to R.drawable.flag_egypt, + "er" to R.drawable.flag_eritrea, + "es" to R.drawable.flag_spain, + "et" to R.drawable.flag_ethiopia, + "fi" to R.drawable.flag_finland, + "fj" to R.drawable.flag_fiji, + "fk" to R.drawable.flag_falkland_islands, + "fm" to R.drawable.flag_micronesia, + "fo" to R.drawable.flag_faroe_islands, + "fr" to R.drawable.flag_france, + "ga" to R.drawable.flag_gabon, + "gb" to R.drawable.flag_united_kingdom, + "gd" to R.drawable.flag_grenada, + "ge" to R.drawable.flag_georgia, + "gf" to R.drawable.flag_guyane, + "gg" to R.drawable.flag_guernsey, + "gh" to R.drawable.flag_ghana, + "gi" to R.drawable.flag_gibraltar, + "gl" to R.drawable.flag_greenland, + "gm" to R.drawable.flag_gambia, + "gn" to R.drawable.flag_guinea, + "gp" to R.drawable.flag_guadeloupe, + "gq" to R.drawable.flag_equatorial_guinea, + "gr" to R.drawable.flag_greece, + "gt" to R.drawable.flag_guatemala, + "gu" to R.drawable.flag_guam, + "gw" to R.drawable.flag_guinea_bissau, + "gy" to R.drawable.flag_guyana, + "hk" to R.drawable.flag_hong_kong, + "hn" to R.drawable.flag_honduras, + "hr" to R.drawable.flag_croatia, + "ht" to R.drawable.flag_haiti, + "hu" to R.drawable.flag_hungary, + "id" to R.drawable.flag_indonesia, + "ie" to R.drawable.flag_ireland, + "il" to R.drawable.flag_israel, + "im" to R.drawable.flag_isleof_man, + // custom 👆🏽 + "is" to R.drawable.flag_iceland, + "in" to R.drawable.flag_india, + "io" to R.drawable.flag_british_indian_ocean_territory, + "iq" to R.drawable.flag_iraq_new, + "ir" to R.drawable.flag_iran, + "it" to R.drawable.flag_italy, + "je" to R.drawable.flag_jersey, + "jm" to R.drawable.flag_jamaica, + "jo" to R.drawable.flag_jordan, + "jp" to R.drawable.flag_japan, + "ke" to R.drawable.flag_kenya, + "kg" to R.drawable.flag_kyrgyzstan, + "kh" to R.drawable.flag_cambodia, + "ki" to R.drawable.flag_kiribati, + "km" to R.drawable.flag_comoros, + "kn" to R.drawable.flag_saint_kitts_and_nevis, + "kp" to R.drawable.flag_north_korea, + "kr" to R.drawable.flag_south_korea, + "kw" to R.drawable.flag_kuwait, + "ky" to R.drawable.flag_cayman_islands, + "kz" to R.drawable.flag_kazakhstan, + "la" to R.drawable.flag_laos, + "lb" to R.drawable.flag_lebanon, + "lc" to R.drawable.flag_saint_lucia, + "li" to R.drawable.flag_liechtenstein, + "lk" to R.drawable.flag_sri_lanka, + "lr" to R.drawable.flag_liberia, + "ls" to R.drawable.flag_lesotho, + "lt" to R.drawable.flag_lithuania, + "lu" to R.drawable.flag_luxembourg, + "lv" to R.drawable.flag_latvia, + "ly" to R.drawable.flag_libya, + "ma" to R.drawable.flag_morocco, + "mc" to R.drawable.flag_monaco, + "md" to R.drawable.flag_moldova, + "me" to R.drawable.flag_of_montenegro, + // custom 👆🏽 + "mf" to R.drawable.flag_saint_martin, + "mg" to R.drawable.flag_madagascar, + "mh" to R.drawable.flag_marshall_islands, + "mk" to R.drawable.flag_macedonia, + "ml" to R.drawable.flag_mali, + "mm" to R.drawable.flag_myanmar, + "mn" to R.drawable.flag_mongolia, + "mo" to R.drawable.flag_macao, + "mp" to R.drawable.flag_northern_mariana_islands, + "mq" to R.drawable.flag_martinique, + "mr" to R.drawable.flag_mauritania, + "ms" to R.drawable.flag_montserrat, + "mt" to R.drawable.flag_malta, + "mu" to R.drawable.flag_mauritius, + "mv" to R.drawable.flag_maldives, + "mw" to R.drawable.flag_malawi, + "mx" to R.drawable.flag_mexico, + "my" to R.drawable.flag_malaysia, + "mz" to R.drawable.flag_mozambique, + "na" to R.drawable.flag_namibia, + "nc" to R.drawable.flag_new_caledonia, + // custom 👆🏽 + "ne" to R.drawable.flag_niger, + "nf" to R.drawable.flag_norfolk_island, + "ng" to R.drawable.flag_nigeria, + "ni" to R.drawable.flag_nicaragua, + "nl" to R.drawable.flag_netherlands, + "no" to R.drawable.flag_norway, + "np" to R.drawable.flag_nepal, + "nr" to R.drawable.flag_nauru, + "nu" to R.drawable.flag_niue, + "nz" to R.drawable.flag_new_zealand, + "om" to R.drawable.flag_oman, + "pa" to R.drawable.flag_panama, + "pe" to R.drawable.flag_peru, + "pf" to R.drawable.flag_french_polynesia, + "pg" to R.drawable.flag_papua_new_guinea, + "ph" to R.drawable.flag_philippines, + "pk" to R.drawable.flag_pakistan, + "pl" to R.drawable.flag_poland, + "pm" to R.drawable.flag_saint_pierre, + "pn" to R.drawable.flag_pitcairn_islands, + "pr" to R.drawable.flag_puerto_rico, + "ps" to R.drawable.flag_palestine, + "pt" to R.drawable.flag_portugal, + "pw" to R.drawable.flag_palau, + "py" to R.drawable.flag_paraguay, + "qa" to R.drawable.flag_qatar, + "re" to R.drawable.flag_martinique, + // no exact flag found 👆🏽 + "ro" to R.drawable.flag_romania, + "rs" to R.drawable.flag_serbia, + // custom 👆🏽 + "ru" to R.drawable.flag_russian_federation, + "rw" to R.drawable.flag_rwanda, + "sa" to R.drawable.flag_saudi_arabia, + "sb" to R.drawable.flag_soloman_islands, + "sc" to R.drawable.flag_seychelles, + "sd" to R.drawable.flag_sudan, + "se" to R.drawable.flag_sweden, + "sg" to R.drawable.flag_singapore, + "sh" to R.drawable.flag_saint_helena, + // custom 👆🏽 + "si" to R.drawable.flag_slovenia, + "sk" to R.drawable.flag_slovakia, + "sl" to R.drawable.flag_sierra_leone, + "sm" to R.drawable.flag_san_marino, + "sn" to R.drawable.flag_senegal, + "so" to R.drawable.flag_somalia, + "sr" to R.drawable.flag_suriname, + "ss" to R.drawable.flag_south_sudan, + "st" to R.drawable.flag_sao_tome_and_principe, + "sv" to R.drawable.flag_el_salvador, + "sx" to R.drawable.flag_sint_maarten, + "sy" to R.drawable.flag_syria, + "sz" to R.drawable.flag_swaziland, + "tc" to R.drawable.flag_turks_and_caicos_islands, + "td" to R.drawable.flag_chad, + "tg" to R.drawable.flag_togo, + "th" to R.drawable.flag_thailand, + "tj" to R.drawable.flag_tajikistan, + "tk" to R.drawable.flag_tokelau, + // custom 👆🏽 + "tl" to R.drawable.flag_timor_leste, + "tm" to R.drawable.flag_turkmenistan, + "tn" to R.drawable.flag_tunisia, + "to" to R.drawable.flag_tonga, + "tr" to R.drawable.flag_turkey, + "tt" to R.drawable.flag_trinidad_and_tobago, + "tv" to R.drawable.flag_tuvalu, + "tw" to R.drawable.flag_taiwan, + "tz" to R.drawable.flag_tanzania, + "ua" to R.drawable.flag_ukraine, + "ug" to R.drawable.flag_uganda, + "us" to R.drawable.flag_united_states_of_america, + "uy" to R.drawable.flag_uruguay, + "uz" to R.drawable.flag_uzbekistan, + "va" to R.drawable.flag_vatican_city, + "vc" to R.drawable.flag_saint_vicent_and_the_grenadines, + "ve" to R.drawable.flag_venezuela, + "vg" to R.drawable.flag_british_virgin_islands, + "vi" to R.drawable.flag_us_virgin_islands, + "vn" to R.drawable.flag_vietnam, + "vu" to R.drawable.flag_vanuatu, + "wf" to R.drawable.flag_wallis_and_futuna, + "ws" to R.drawable.flag_samoa, + "xk" to R.drawable.flag_kosovo, + "ye" to R.drawable.flag_yemen, + "yt" to R.drawable.flag_martinique, + // no exact flag found 👆🏽 + "za" to R.drawable.flag_south_africa, + "zm" to R.drawable.flag_zambia, + "zw" to R.drawable.flag_zimbabwe, + "bq" to R.drawable.flag_bq, + "tf" to R.drawable.flag_tf, + "gs" to R.drawable.flag_gs, + "eh" to R.drawable.flag_eh, + ) +} diff --git a/flagpack1/src/test/java/com/hbb20/contrypicker/flagpack1/ExampleUnitTest.kt b/flagpack1/src/test/java/com/hbb20/contrypicker/flagpack1/ExampleUnitTest.kt index 4332879..e14dbff 100644 --- a/flagpack1/src/test/java/com/hbb20/contrypicker/flagpack1/ExampleUnitTest.kt +++ b/flagpack1/src/test/java/com/hbb20/contrypicker/flagpack1/ExampleUnitTest.kt @@ -13,4 +13,4 @@ class ExampleUnitTest { fun addition_isCorrect() { assertEquals(4, 2 + 2) } -} \ No newline at end of file +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 48b4b44..ea17ea2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Sat Sep 09 15:42:56 EDT 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 6468b10656dd697d8bd4588facea9a5f23154cc1 Mon Sep 17 00:00:00 2001 From: hbb20 Date: Sat, 30 Dec 2023 14:56:00 -0700 Subject: [PATCH 09/10] add title --- .../androidcountrypicker/compose/ComposeDemoActivity.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt b/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt index 3966138..59cc1e3 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt @@ -34,6 +34,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.google.android.material.shape.MarkerEdgeTreatment import com.hbb20.androidcountrypicker.R import com.hbb20.androidcountrypicker.compose.theme.DemoTheme import com.hbb20.contrypicker.flagpack1.FlagPack1 @@ -57,11 +58,8 @@ class ComposeDemoActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background, ) { - val (countryCode, setCountryCode) = remember { mutableStateOf("In") } Column(modifier = Modifier.verticalScroll(rememberScrollState())) { - CountryPicker(alpha2Code = countryCode) { - setCountryCode(it?.alpha2) - } + Text(text = "Jetpack Compose", style = MaterialTheme.typography.h5, color = MaterialTheme.colors.onSurface, modifier = Modifier.padding(16.dp)) OutOfBox() AutoDetectedInitialCountry() UseFlagPack() From 6f4a38eab43da4db46ed36fbbadbd8c218a93971 Mon Sep 17 00:00:00 2001 From: hbb20 Date: Sat, 30 Dec 2023 15:36:43 -0700 Subject: [PATCH 10/10] ktlint --- .../androidcountrypicker/compose/ComposeDemoActivity.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt b/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt index 59cc1e3..47364f6 100644 --- a/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt +++ b/app/src/main/java/com/hbb20/androidcountrypicker/compose/ComposeDemoActivity.kt @@ -34,7 +34,6 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.google.android.material.shape.MarkerEdgeTreatment import com.hbb20.androidcountrypicker.R import com.hbb20.androidcountrypicker.compose.theme.DemoTheme import com.hbb20.contrypicker.flagpack1.FlagPack1 @@ -59,7 +58,12 @@ class ComposeDemoActivity : ComponentActivity() { color = MaterialTheme.colors.background, ) { Column(modifier = Modifier.verticalScroll(rememberScrollState())) { - Text(text = "Jetpack Compose", style = MaterialTheme.typography.h5, color = MaterialTheme.colors.onSurface, modifier = Modifier.padding(16.dp)) + Text( + text = "Jetpack Compose", + style = MaterialTheme.typography.h5, + color = MaterialTheme.colors.onSurface, + modifier = Modifier.padding(16.dp), + ) OutOfBox() AutoDetectedInitialCountry() UseFlagPack()