react-native-nitro-country-picker 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/LICENSE +20 -0
  2. package/NitroCountryPicker.podspec +37 -0
  3. package/README.md +164 -0
  4. package/android/CMakeLists.txt +24 -0
  5. package/android/build.gradle +149 -0
  6. package/android/gradle.properties +5 -0
  7. package/android/src/main/AndroidManifest.xml +8 -0
  8. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  9. package/android/src/main/java/com/margelo/nitro/nitrocountrypicker/CountryPickerActivity.kt +95 -0
  10. package/android/src/main/java/com/margelo/nitro/nitrocountrypicker/NitroCountryPicker.kt +132 -0
  11. package/android/src/main/java/com/margelo/nitro/nitrocountrypicker/NitroCountryPickerPackage.kt +36 -0
  12. package/ios/NitroCountryPicker.swift +94 -0
  13. package/lib/module/NitroCountryPicker.nitro.js +4 -0
  14. package/lib/module/NitroCountryPicker.nitro.js.map +1 -0
  15. package/lib/module/index.js +11 -0
  16. package/lib/module/index.js.map +1 -0
  17. package/lib/module/package.json +1 -0
  18. package/lib/typescript/package.json +1 -0
  19. package/lib/typescript/src/NitroCountryPicker.nitro.d.ts +17 -0
  20. package/lib/typescript/src/NitroCountryPicker.nitro.d.ts.map +1 -0
  21. package/lib/typescript/src/index.d.ts +4 -0
  22. package/lib/typescript/src/index.d.ts.map +1 -0
  23. package/nitro.json +23 -0
  24. package/nitrogen/generated/android/c++/JHybridNitroCountryPickerSpec.cpp +83 -0
  25. package/nitrogen/generated/android/c++/JHybridNitroCountryPickerSpec.hpp +64 -0
  26. package/nitrogen/generated/android/c++/JIPickedCountry.hpp +65 -0
  27. package/nitrogen/generated/android/c++/JPickCountryOptions.hpp +58 -0
  28. package/nitrogen/generated/android/c++/JVariant_NullType_IPickedCountry.cpp +26 -0
  29. package/nitrogen/generated/android/c++/JVariant_NullType_IPickedCountry.hpp +72 -0
  30. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrocountrypicker/HybridNitroCountryPickerSpec.kt +60 -0
  31. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrocountrypicker/IPickedCountry.kt +44 -0
  32. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrocountrypicker/PickCountryOptions.kt +38 -0
  33. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrocountrypicker/Variant_NullType_IPickedCountry.kt +53 -0
  34. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrocountrypicker/nitrocountrypickerOnLoad.kt +35 -0
  35. package/nitrogen/generated/android/nitrocountrypicker+autolinking.cmake +82 -0
  36. package/nitrogen/generated/android/nitrocountrypicker+autolinking.gradle +27 -0
  37. package/nitrogen/generated/android/nitrocountrypickerOnLoad.cpp +54 -0
  38. package/nitrogen/generated/android/nitrocountrypickerOnLoad.hpp +34 -0
  39. package/nitrogen/generated/ios/NitroCountryPicker+autolinking.rb +60 -0
  40. package/nitrogen/generated/ios/NitroCountryPicker-Swift-Cxx-Bridge.cpp +49 -0
  41. package/nitrogen/generated/ios/NitroCountryPicker-Swift-Cxx-Bridge.hpp +188 -0
  42. package/nitrogen/generated/ios/NitroCountryPicker-Swift-Cxx-Umbrella.hpp +54 -0
  43. package/nitrogen/generated/ios/NitroCountryPickerAutolinking.mm +33 -0
  44. package/nitrogen/generated/ios/NitroCountryPickerAutolinking.swift +26 -0
  45. package/nitrogen/generated/ios/c++/HybridNitroCountryPickerSpecSwift.cpp +11 -0
  46. package/nitrogen/generated/ios/c++/HybridNitroCountryPickerSpecSwift.hpp +99 -0
  47. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
  48. package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__IPickedCountry_.swift +58 -0
  49. package/nitrogen/generated/ios/swift/HybridNitroCountryPickerSpec.swift +56 -0
  50. package/nitrogen/generated/ios/swift/HybridNitroCountryPickerSpec_cxx.swift +171 -0
  51. package/nitrogen/generated/ios/swift/IPickedCountry.swift +39 -0
  52. package/nitrogen/generated/ios/swift/PickCountryOptions.swift +42 -0
  53. package/nitrogen/generated/ios/swift/Variant_NullType_IPickedCountry.swift +18 -0
  54. package/nitrogen/generated/shared/c++/HybridNitroCountryPickerSpec.cpp +22 -0
  55. package/nitrogen/generated/shared/c++/HybridNitroCountryPickerSpec.hpp +71 -0
  56. package/nitrogen/generated/shared/c++/IPickedCountry.hpp +91 -0
  57. package/nitrogen/generated/shared/c++/PickCountryOptions.hpp +84 -0
  58. package/package.json +175 -0
  59. package/src/NitroCountryPicker.nitro.ts +20 -0
  60. package/src/index.tsx +19 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Quan Pham
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
@@ -0,0 +1,37 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "NitroCountryPicker"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => min_ios_version_supported }
14
+ s.source = { :git => "https://github.com/Doko-Demo-Doa/react-native-nitro-country-picker.git", :tag => "#{s.version}" }
15
+
16
+
17
+ s.source_files = [
18
+ "ios/**/*.{swift}",
19
+ "ios/**/*.{m,mm}",
20
+ "cpp/**/*.{hpp,cpp}",
21
+ ]
22
+
23
+ s.dependency 'React-jsi'
24
+ s.dependency 'React-callinvoker'
25
+ s.dependency 'CountryPickerAKS'
26
+
27
+ load 'nitrogen/generated/ios/NitroCountryPicker+autolinking.rb'
28
+ add_nitrogen_files(s)
29
+
30
+ # Ensure generated shared C++ headers are exported to Pods/Headers/Public.
31
+ current_public_headers = Array(s.attributes_hash['public_header_files'])
32
+ s.public_header_files = current_public_headers + [
33
+ 'nitrogen/generated/shared/c++/*.hpp',
34
+ ]
35
+
36
+ install_modules_dependencies(s)
37
+ end
package/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # react-native-nitro-country-picker
2
+
3
+ A native country picker for React Native, powered by Nitro Modules.
4
+
5
+ This library provides a single async API that opens a native picker and returns structured country data.
6
+
7
+ - Android native implementation: [CountryCodePickerCompose](https://github.com/ahmmedrejowan/CountryCodePickerCompose)
8
+ - iOS native implementation: [CountryPickerAKS](https://github.com/aksamitsah/CountryPickerAKS)
9
+
10
+ ## Features
11
+
12
+ - Native picker UI on both iOS and Android
13
+ - Promise-based API: `pickCountry(options?)`
14
+ - Typed result object with `name`, `dialCode`, and `code`
15
+ - `null` result when user dismisses without selection
16
+ - Last selection cache via `getLastPickedCountry()`
17
+ - Optional picker title input: `headerTitle` (currently applied on Android)
18
+
19
+ ## Requirements
20
+
21
+ | Platform | Minimum |
22
+ | -------- | ------- |
23
+ | iOS | 15.1+ |
24
+ | Android | API 24+ |
25
+
26
+ > Note: This package depends on [react-native-nitro-modules](https://nitro.margelo.com/).
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ npm install react-native-nitro-country-picker react-native-nitro-modules
32
+ ```
33
+
34
+ or
35
+
36
+ ```bash
37
+ yarn add react-native-nitro-country-picker react-native-nitro-modules
38
+ ```
39
+
40
+ ### iOS setup
41
+
42
+ ```bash
43
+ cd ios && pod install
44
+ ```
45
+
46
+ ## Usage
47
+
48
+ ```tsx
49
+ import { pickCountry } from 'react-native-nitro-country-picker';
50
+
51
+ const country = await pickCountry();
52
+ ```
53
+
54
+ ### With options
55
+
56
+ ```tsx
57
+ import { pickCountry } from 'react-native-nitro-country-picker';
58
+
59
+ const country = await pickCountry({
60
+ headerTitle: 'Select your country',
61
+ });
62
+ ```
63
+
64
+ ## Returned Data Examples
65
+
66
+ ### 1) Handle selected vs dismissed
67
+
68
+ ```tsx
69
+ import { pickCountry } from 'react-native-nitro-country-picker';
70
+
71
+ const picked = await pickCountry();
72
+
73
+ if (picked) {
74
+ console.log('Country name:', picked.name);
75
+ console.log('Dial code:', picked.dialCode);
76
+ console.log('ISO code:', picked.code);
77
+ } else {
78
+ console.log('Picker dismissed without selection');
79
+ }
80
+ ```
81
+
82
+ ### 2) Build display text from returned data
83
+
84
+ ```tsx
85
+ import { pickCountry } from 'react-native-nitro-country-picker';
86
+
87
+ const picked = await pickCountry();
88
+ const label = picked
89
+ ? `${picked.name} (${picked.dialCode}, ${picked.code})`
90
+ : 'No country selected';
91
+
92
+ console.log(label);
93
+ ```
94
+
95
+ ### 3) Read last picked country
96
+
97
+ ```tsx
98
+ import {
99
+ getLastPickedCountry,
100
+ pickCountry,
101
+ } from 'react-native-nitro-country-picker';
102
+
103
+ await pickCountry();
104
+
105
+ const last = getLastPickedCountry();
106
+ if (last) {
107
+ console.log('Last picked:', last.name, last.dialCode, last.code);
108
+ }
109
+ ```
110
+
111
+ ## API
112
+
113
+ ### `pickCountry(options?) => Promise<IPickedCountry | null>`
114
+
115
+ Opens the native picker and resolves with:
116
+
117
+ - `IPickedCountry` when user selects a country
118
+ - `null` when user dismisses/cancels
119
+
120
+ Options:
121
+
122
+ - `headerTitle?: string`
123
+
124
+ ### `getLastPickedCountry() => IPickedCountry | null`
125
+
126
+ Returns the most recent selected country for the current app runtime session.
127
+
128
+ ## Type Shapes
129
+
130
+ ```ts
131
+ type IPickedCountry = {
132
+ name: string;
133
+ dialCode: string;
134
+ code: string;
135
+ };
136
+
137
+ type PickCountryOptions = {
138
+ headerTitle?: string;
139
+ };
140
+ ```
141
+
142
+ ## Example App
143
+
144
+ To run the included example app:
145
+
146
+ ```bash
147
+ cd example
148
+ yarn install
149
+ yarn ios
150
+ # or
151
+ yarn android
152
+ ```
153
+
154
+ ## Contributing
155
+
156
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development workflow and contribution guidelines.
157
+
158
+ ## License
159
+
160
+ MIT
161
+
162
+ ---
163
+
164
+ Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
@@ -0,0 +1,24 @@
1
+ project(nitrocountrypicker)
2
+ cmake_minimum_required(VERSION 3.9.0)
3
+
4
+ set(PACKAGE_NAME nitrocountrypicker)
5
+ set(CMAKE_VERBOSE_MAKEFILE ON)
6
+ set(CMAKE_CXX_STANDARD 20)
7
+
8
+ # Define C++ library and add all sources
9
+ add_library(${PACKAGE_NAME} SHARED src/main/cpp/cpp-adapter.cpp)
10
+
11
+ # Add Nitrogen specs :)
12
+ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/nitrocountrypicker+autolinking.cmake)
13
+
14
+ # Set up local includes
15
+ include_directories("src/main/cpp" "../cpp")
16
+
17
+ find_library(LOG_LIB log)
18
+
19
+ # Link all libraries together
20
+ target_link_libraries(
21
+ ${PACKAGE_NAME}
22
+ ${LOG_LIB}
23
+ android # <-- Android core
24
+ )
@@ -0,0 +1,149 @@
1
+ buildscript {
2
+ ext.getExtOrDefault = {name ->
3
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['NitroCountryPicker_' + name]
4
+ }
5
+
6
+ repositories {
7
+ google()
8
+ mavenCentral()
9
+ maven { url 'https://jitpack.io' }
10
+ }
11
+
12
+ dependencies {
13
+ classpath "com.android.tools.build:gradle:8.7.2"
14
+ // noinspection DifferentKotlinGradleVersion
15
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
16
+ classpath "org.jetbrains.kotlin:compose-compiler-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
17
+ }
18
+ }
19
+
20
+ def reactNativeArchitectures() {
21
+ def value = rootProject.getProperties().get("reactNativeArchitectures")
22
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
23
+ }
24
+
25
+ apply plugin: "com.android.library"
26
+ apply plugin: "kotlin-android"
27
+ apply plugin: "org.jetbrains.kotlin.plugin.compose"
28
+ apply from: '../nitrogen/generated/android/nitrocountrypicker+autolinking.gradle'
29
+
30
+ apply plugin: "com.facebook.react"
31
+
32
+ def getExtOrIntegerDefault(name) {
33
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["NitroCountryPicker_" + name]).toInteger()
34
+ }
35
+
36
+ android {
37
+ namespace "com.margelo.nitro.nitrocountrypicker"
38
+
39
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
40
+
41
+ defaultConfig {
42
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
43
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
44
+
45
+ externalNativeBuild {
46
+ cmake {
47
+ cppFlags "-frtti -fexceptions -Wall -fstack-protector-all"
48
+ arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
49
+ abiFilters (*reactNativeArchitectures())
50
+
51
+ buildTypes {
52
+ debug {
53
+ cppFlags "-O1 -g"
54
+ }
55
+ release {
56
+ cppFlags "-O2"
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ externalNativeBuild {
64
+ cmake {
65
+ path "CMakeLists.txt"
66
+ }
67
+ }
68
+
69
+ packagingOptions {
70
+ excludes = [
71
+ "META-INF",
72
+ "META-INF/**",
73
+ "**/libc++_shared.so",
74
+ "**/libfbjni.so",
75
+ "**/libjsi.so",
76
+ "**/libfolly_json.so",
77
+ "**/libfolly_runtime.so",
78
+ "**/libglog.so",
79
+ "**/libhermes.so",
80
+ "**/libhermes-executor-debug.so",
81
+ "**/libhermes_executor.so",
82
+ "**/libreactnative.so",
83
+ "**/libreactnativejni.so",
84
+ "**/libturbomodulejsijni.so",
85
+ "**/libreact_nativemodule_core.so",
86
+ "**/libjscexecutor.so"
87
+ ]
88
+ }
89
+
90
+ buildFeatures {
91
+ buildConfig true
92
+ prefab true
93
+ compose true
94
+ }
95
+
96
+ buildTypes {
97
+ release {
98
+ minifyEnabled false
99
+ }
100
+ }
101
+
102
+ lintOptions {
103
+ disable "GradleCompatible"
104
+ }
105
+
106
+ compileOptions {
107
+ sourceCompatibility JavaVersion.VERSION_17
108
+ targetCompatibility JavaVersion.VERSION_17
109
+ }
110
+
111
+ kotlinOptions {
112
+ jvmTarget = "17"
113
+ }
114
+
115
+ sourceSets {
116
+ main {
117
+ java.srcDirs += [
118
+ "generated/java",
119
+ "generated/jni"
120
+ ]
121
+ }
122
+ }
123
+ }
124
+
125
+ repositories {
126
+ mavenCentral()
127
+ maven { url 'https://jitpack.io' }
128
+ google()
129
+ }
130
+
131
+ def kotlin_version = getExtOrDefault("kotlinVersion")
132
+ def appcompat_version = "1.7.1"
133
+ def compose_bom_version = "2024.12.01"
134
+ def activity_compose_version = "1.13.0"
135
+
136
+ dependencies {
137
+ implementation "com.facebook.react:react-android"
138
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
139
+ implementation project(":react-native-nitro-modules")
140
+
141
+ implementation "com.rejowan:ccpc:1.0.1"
142
+ implementation platform("androidx.compose:compose-bom:$compose_bom_version")
143
+ implementation "androidx.activity:activity-compose:$activity_compose_version"
144
+ implementation "androidx.compose.ui:ui"
145
+ implementation "androidx.compose.runtime:runtime"
146
+ implementation "androidx.compose.material3:material3"
147
+ implementation "androidx.appcompat:appcompat:$appcompat_version"
148
+ implementation "com.google.android.material:material:1.12.0"
149
+ }
@@ -0,0 +1,5 @@
1
+ NitroCountryPicker_kotlinVersion=2.0.21
2
+ NitroCountryPicker_minSdkVersion=24
3
+ NitroCountryPicker_targetSdkVersion=34
4
+ NitroCountryPicker_compileSdkVersion=36
5
+ NitroCountryPicker_ndkVersion=27.1.12297006
@@ -0,0 +1,8 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <application>
3
+ <activity
4
+ android:name=".CountryPickerActivity"
5
+ android:exported="false"
6
+ android:theme="@android:style/Theme.Translucent.NoTitleBar" />
7
+ </application>
8
+ </manifest>
@@ -0,0 +1,6 @@
1
+ #include <jni.h>
2
+ #include "nitrocountrypickerOnLoad.hpp"
3
+
4
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
5
+ return margelo::nitro::nitrocountrypicker::initialize(vm);
6
+ }
@@ -0,0 +1,95 @@
1
+ package com.margelo.nitro.nitrocountrypicker
2
+
3
+ import android.app.Activity
4
+ import android.content.Intent
5
+ import android.os.Bundle
6
+ import android.widget.Toast
7
+ import androidx.activity.ComponentActivity
8
+ import androidx.activity.compose.setContent
9
+ import androidx.compose.material3.MaterialTheme
10
+ import androidx.compose.runtime.getValue
11
+ import androidx.compose.runtime.mutableStateOf
12
+ import androidx.compose.runtime.remember
13
+ import androidx.compose.runtime.setValue
14
+ import com.rejowan.ccpc.CCPUtils
15
+ import com.rejowan.ccpc.Country
16
+ import com.rejowan.ccpc.CountryPickerDialog
17
+ import com.rejowan.ccpc.PickerCustomization
18
+
19
+ class CountryPickerActivity : ComponentActivity() {
20
+ companion object {
21
+ const val EXTRA_HEADER_TITLE = "com.margelo.nitro.nitrocountrypicker.HEADER_TITLE"
22
+ private const val EXTRA_RESULT_NAME = "com.margelo.nitro.nitrocountrypicker.RESULT_NAME"
23
+ private const val EXTRA_RESULT_DIAL_CODE = "com.margelo.nitro.nitrocountrypicker.RESULT_DIAL_CODE"
24
+ private const val EXTRA_RESULT_CODE = "com.margelo.nitro.nitrocountrypicker.RESULT_CODE"
25
+
26
+ fun intentResultToPickedCountry(resultCode: Int, data: Intent?): IPickedCountry? {
27
+ if (resultCode != Activity.RESULT_OK || data == null) {
28
+ return null
29
+ }
30
+
31
+ val name = data.getStringExtra(EXTRA_RESULT_NAME) ?: return null
32
+ val dialCode = data.getStringExtra(EXTRA_RESULT_DIAL_CODE) ?: return null
33
+ val code = data.getStringExtra(EXTRA_RESULT_CODE) ?: return null
34
+ return IPickedCountry(name = name, dialCode = dialCode, code = code)
35
+ }
36
+ }
37
+
38
+ private var hasCompletedPick = false
39
+
40
+ override fun onCreate(savedInstanceState: Bundle?) {
41
+ super.onCreate(savedInstanceState)
42
+ val headerTitle = intent.getStringExtra(EXTRA_HEADER_TITLE)?.trim()?.takeIf { it.isNotEmpty() }
43
+ val pickerCustomization = if (headerTitle == null) {
44
+ PickerCustomization()
45
+ } else {
46
+ PickerCustomization(headerTitleText = headerTitle)
47
+ }
48
+
49
+ setContent {
50
+ MaterialTheme {
51
+ var selectedCountry by remember {
52
+ mutableStateOf(
53
+ CCPUtils.getCountryAutomatically(this@CountryPickerActivity)
54
+ ?: Country.UnitedStates
55
+ )
56
+ }
57
+
58
+ CountryPickerDialog(
59
+ onDismissRequest = {
60
+ hasCompletedPick = true
61
+ setResult(Activity.RESULT_CANCELED)
62
+ finish()
63
+ },
64
+ onItemClicked = { country ->
65
+ selectedCountry = country
66
+ hasCompletedPick = true
67
+ val resultIntent = Intent().apply {
68
+ putExtra(EXTRA_RESULT_NAME, country.countryName)
69
+ putExtra(EXTRA_RESULT_DIAL_CODE, country.countryCode)
70
+ putExtra(EXTRA_RESULT_CODE, country.countryIso)
71
+ }
72
+ setResult(Activity.RESULT_OK, resultIntent)
73
+ Toast.makeText(
74
+ this@CountryPickerActivity,
75
+ country.countryName,
76
+ Toast.LENGTH_SHORT
77
+ ).show()
78
+ finish()
79
+ },
80
+ listOfCountry = Country.getAllCountries(),
81
+ selectedCountry = selectedCountry,
82
+ pickerCustomization = pickerCustomization
83
+ )
84
+ }
85
+ }
86
+ }
87
+
88
+ override fun onDestroy() {
89
+ super.onDestroy()
90
+ if (!hasCompletedPick) {
91
+ setResult(Activity.RESULT_CANCELED)
92
+ hasCompletedPick = true
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,132 @@
1
+ package com.margelo.nitro.nitrocountrypicker
2
+
3
+ import android.content.Intent
4
+ import androidx.activity.ComponentActivity
5
+ import androidx.activity.result.ActivityResultLauncher
6
+ import androidx.activity.result.contract.ActivityResultContracts
7
+ import com.facebook.proguard.annotations.DoNotStrip
8
+ import com.facebook.react.bridge.UiThreadUtil
9
+ import com.margelo.nitro.NitroModules
10
+ import com.margelo.nitro.core.NullType
11
+ import com.margelo.nitro.core.Promise
12
+ import java.util.concurrent.atomic.AtomicInteger
13
+
14
+
15
+ @DoNotStrip
16
+ class NitroCountryPicker : HybridNitroCountryPickerSpec() {
17
+ companion object {
18
+ const val NAME = "NitroCountryPicker"
19
+
20
+ @Volatile
21
+ private var lastPickedCountry: IPickedCountry? = null
22
+
23
+ @Volatile
24
+ private var pendingPickPromise: Promise<Variant_NullType_IPickedCountry>? = null
25
+
26
+ private val launcherCounter = AtomicInteger(0)
27
+
28
+ private fun setLastPickedCountry(country: IPickedCountry) {
29
+ lastPickedCountry = country
30
+ }
31
+
32
+ @Synchronized
33
+ private fun resolvePendingPick(country: IPickedCountry?) {
34
+ val promise = pendingPickPromise ?: return
35
+ pendingPickPromise = null
36
+ val result = if (country == null) {
37
+ Variant_NullType_IPickedCountry.create(NullType.NULL)
38
+ } else {
39
+ Variant_NullType_IPickedCountry.create(country)
40
+ }
41
+ promise.resolve(result)
42
+ }
43
+
44
+ @Synchronized
45
+ private fun setPendingPickPromise(promise: Promise<Variant_NullType_IPickedCountry>): Boolean {
46
+ if (pendingPickPromise != null) {
47
+ return false
48
+ }
49
+ pendingPickPromise = promise
50
+ return true
51
+ }
52
+
53
+ @Synchronized
54
+ private fun rejectPendingPick(error: Throwable) {
55
+ val promise = pendingPickPromise ?: return
56
+ pendingPickPromise = null
57
+ promise.reject(error)
58
+ }
59
+
60
+ private fun nextLauncherKey(): String {
61
+ return "NitroCountryPicker#${launcherCounter.incrementAndGet()}"
62
+ }
63
+ }
64
+
65
+ override fun pickCountry(options: PickCountryOptions?): Promise<Variant_NullType_IPickedCountry> {
66
+ val activity = NitroModules.applicationContext?.currentActivity
67
+ ?: return Promise.rejected<Variant_NullType_IPickedCountry>(
68
+ IllegalStateException("No current Activity available to present country picker.")
69
+ )
70
+ val componentActivity = activity as? ComponentActivity
71
+ ?: return Promise.rejected<Variant_NullType_IPickedCountry>(
72
+ IllegalStateException("Current Activity must be a ComponentActivity to register for activity results.")
73
+ )
74
+
75
+ val promise = Promise<Variant_NullType_IPickedCountry>()
76
+ val accepted = setPendingPickPromise(promise)
77
+ if (!accepted) {
78
+ return Promise.rejected<Variant_NullType_IPickedCountry>(
79
+ IllegalStateException("Country picker is already open.")
80
+ )
81
+ }
82
+
83
+ UiThreadUtil.runOnUiThread {
84
+ var launcher: ActivityResultLauncher<Intent>? = null
85
+ try {
86
+ val intent = Intent(activity, CountryPickerActivity::class.java)
87
+ val headerTitle = options?.headerTitle?.trim()?.takeIf { it.isNotEmpty() }
88
+ if (headerTitle != null) {
89
+ intent.putExtra(CountryPickerActivity.EXTRA_HEADER_TITLE, headerTitle)
90
+ }
91
+
92
+ launcher = componentActivity.activityResultRegistry.register(
93
+ nextLauncherKey(),
94
+ ActivityResultContracts.StartActivityForResult()
95
+ ) { result ->
96
+ try {
97
+ val picked = CountryPickerActivity.intentResultToPickedCountry(result.resultCode, result.data)
98
+ if (picked != null) {
99
+ setLastPickedCountry(picked)
100
+ }
101
+ resolvePendingPick(picked)
102
+ } catch (error: Throwable) {
103
+ rejectPendingPick(error)
104
+ } finally {
105
+ launcher?.unregister()
106
+ launcher = null
107
+ }
108
+ }
109
+
110
+ launcher?.launch(intent)
111
+ } catch (error: Throwable) {
112
+ try {
113
+ launcher?.unregister()
114
+ } catch (_: Throwable) {
115
+ // Ignore cleanup errors while handling the original failure.
116
+ }
117
+ rejectPendingPick(error)
118
+ }
119
+ }
120
+
121
+ return promise
122
+ }
123
+
124
+ override fun getLastPickedCountry(): Variant_NullType_IPickedCountry {
125
+ val picked = lastPickedCountry
126
+ return if (picked == null) {
127
+ Variant_NullType_IPickedCountry.create(NullType.NULL)
128
+ } else {
129
+ Variant_NullType_IPickedCountry.create(picked)
130
+ }
131
+ }
132
+ }
@@ -0,0 +1,36 @@
1
+ package com.margelo.nitro.nitrocountrypicker
2
+
3
+ import android.util.Log
4
+ import com.facebook.react.BaseReactPackage
5
+ import com.facebook.react.bridge.NativeModule
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.module.model.ReactModuleInfo
8
+ import com.facebook.react.module.model.ReactModuleInfoProvider
9
+
10
+ class NitroCountryPickerPackage : BaseReactPackage() {
11
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
12
+ return null
13
+ }
14
+
15
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
16
+ return ReactModuleInfoProvider {
17
+ val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
18
+ moduleInfos[NitroCountryPicker.NAME] = ReactModuleInfo(
19
+ NitroCountryPicker.NAME,
20
+ NitroCountryPicker.NAME,
21
+ false,
22
+ needsEagerInit = true,
23
+ isCxxModule = false,
24
+ isTurboModule = true
25
+ )
26
+ moduleInfos
27
+ }
28
+ }
29
+
30
+ companion object {
31
+ init {
32
+ System.loadLibrary("nitrocountrypicker")
33
+ Log.d(NitroCountryPicker.NAME, "Hello from init")
34
+ }
35
+ }
36
+ }