From 3b0012a033755e8544e2c541fb543b56ef90221f Mon Sep 17 00:00:00 2001 From: abdosaidbassuony Date: Fri, 25 Apr 2025 22:06:31 +0300 Subject: [PATCH 1/2] Add phone module --- phoneNumber/build.gradle.kts | 122 ++++++++++++++++++ .../kmm/base/BaseClassForTest.android.kt | 6 + .../kmm/phoneNumber/di/PhoneNumberModule.kt | 11 ++ .../phoneNumberManger/IPhoneNumberManager.kt | 25 ++++ .../phoneNumberManger/PhoneNumberManager.kt | 79 ++++++++++++ .../metacto/kmm/base/BaseClassForTest.ios.kt | 6 + settings.gradle.kts | 3 +- 7 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 phoneNumber/build.gradle.kts create mode 100644 phoneNumber/src/androidMain/kotlin/com/metacto/kmm/base/BaseClassForTest.android.kt create mode 100644 phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/di/PhoneNumberModule.kt create mode 100644 phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/phoneNumberManger/IPhoneNumberManager.kt create mode 100644 phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/phoneNumberManger/PhoneNumberManager.kt create mode 100644 phoneNumber/src/iosMain/kotlin/com/metacto/kmm/base/BaseClassForTest.ios.kt diff --git a/phoneNumber/build.gradle.kts b/phoneNumber/build.gradle.kts new file mode 100644 index 00000000..7c614160 --- /dev/null +++ b/phoneNumber/build.gradle.kts @@ -0,0 +1,122 @@ +import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties +import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework +import org.jetbrains.kotlin.konan.properties.Properties +import java.io.FileInputStream +import java.io.FileOutputStream + +plugins { + id(Plugins.ANDROID_LIBRARY_PLUGIN) + kotlin(Plugins.MULTIPLATFORM_PLUGIN) + id(Plugins.MAVEN_PUBLISH) + id(Plugins.SIGNING) +} + +val versionProperties = Properties().apply { + load(FileInputStream(File(rootProject.rootDir, Constants.VERSIONS_PROPERTIES))) +} + +val currentVersion = versionProperties.getProperty(Constants.PUBLISH_VERSION) as String +val libName = "phoneNumber" + +version = currentVersion +group = Constants.GROUP_ID + +kotlin { + androidTarget { + compilations.all { + kotlinOptions { + jvmTarget = Versions.JVM.toString() + } + } + publishLibraryVariants("debug", "release") + } + + val xcf = XCFramework() + listOf( + iosX64(), + iosArm64(), + iosSimulatorArm64() + ).forEach { + it.binaries.framework(libName) { + baseName = libName + xcf.add(this) + isStatic = true + } + } + + metadata { + compilations.matching { it.name == "iosMain" }.all { + compileTaskProvider.configure { enabled = false } + } + } + + sourceSets { + commonMain.dependencies { + // Koin + api(Dependencies.Koin.CORE) + + // Phone Number + api(Dependencies.LIB_PHONE_NUMBER) + + } + + androidMain.dependencies { + // ANDROID ANDROID DEPENDENCIES + } + + iosMain.dependencies { + // IOS DEPENDENCIES + } + } + + task("testClasses") +} + +android { + namespace = "com.metacto.kmm.base" + compileSdk = Configs.COMPILE_SDK_VERSION + sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") + defaultConfig { + minSdk = Configs.MIN_SDK_VERSION + consumerProguardFiles("consumer-rules.pro") + } + compileOptions { + sourceCompatibility = Versions.JVM + targetCompatibility = Versions.JVM + } +} + +publishing { + repositories { + val localProperties = gradleLocalProperties(rootDir, providers) + var publishUserRepo = localProperties.getProperty(Constants.PUBLISH_REPO_USER) + var publishTokenRepo = localProperties.getProperty(Constants.PUBLISH_REPO_TOKEN) + + if (publishUserRepo.isNullOrEmpty()) { + publishUserRepo = "" + localProperties.setProperty(Constants.PUBLISH_REPO_USER, publishUserRepo) + } + + if (publishTokenRepo.isNullOrEmpty()) { + publishTokenRepo = "" + localProperties.setProperty(Constants.PUBLISH_REPO_TOKEN, publishTokenRepo) + } + + if (publishUserRepo.isEmpty() || publishTokenRepo.isEmpty()) { + localProperties.store( + FileOutputStream(File(rootDir, Constants.LOCAL_PROPERTIES)), null + ) + } + + repositories { + maven(Constants.MAVEN_URL) { + name = Constants.PUBLISH_MAVEN_REPO_NAME + credentials { + username = publishUserRepo + password = publishTokenRepo + } + } + } + } +} + diff --git a/phoneNumber/src/androidMain/kotlin/com/metacto/kmm/base/BaseClassForTest.android.kt b/phoneNumber/src/androidMain/kotlin/com/metacto/kmm/base/BaseClassForTest.android.kt new file mode 100644 index 00000000..34a2d081 --- /dev/null +++ b/phoneNumber/src/androidMain/kotlin/com/metacto/kmm/base/BaseClassForTest.android.kt @@ -0,0 +1,6 @@ +package com.metacto.kmm.base + +actual class BaseClassForTest { + actual fun test() { + } +} \ No newline at end of file diff --git a/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/di/PhoneNumberModule.kt b/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/di/PhoneNumberModule.kt new file mode 100644 index 00000000..b6b2c31a --- /dev/null +++ b/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/di/PhoneNumberModule.kt @@ -0,0 +1,11 @@ +package com.metacto.kmm.phoneNumber.di + +import com.metacto.core.utils.phoneNumber.IPhoneNumberManager +import com.metacto.kmm.phoneNumber.phoneNumberManger.PhoneNumberManager +import org.koin.dsl.module + +val phoneNumberModule = module { + single { + PhoneNumberManager(get()) + } +} \ No newline at end of file diff --git a/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/phoneNumberManger/IPhoneNumberManager.kt b/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/phoneNumberManger/IPhoneNumberManager.kt new file mode 100644 index 00000000..754c3b5f --- /dev/null +++ b/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/phoneNumberManger/IPhoneNumberManager.kt @@ -0,0 +1,25 @@ +package com.metacto.core.utils.phoneNumber + +val Class = IPhoneNumberManager::class + +interface IPhoneNumberManager { + fun getValidPhoneNumber( + number: String, + countryCode: String? + ): String? + + fun getFormattedPhoneNumber( + number: String, + countryCode: String? + ): String? + + fun getE164FormattedPhoneNumber( + number: String, + countryCode: String? + ): String? + + fun isValidPhoneNumber( + number: String, + countryCode: String? + ): Boolean +} \ No newline at end of file diff --git a/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/phoneNumberManger/PhoneNumberManager.kt b/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/phoneNumberManger/PhoneNumberManager.kt new file mode 100644 index 00000000..9436f88d --- /dev/null +++ b/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/phoneNumberManger/PhoneNumberManager.kt @@ -0,0 +1,79 @@ +package com.metacto.kmm.phoneNumber.phoneNumberManger +import com.metacto.core.utils.phoneNumber.IPhoneNumberManager +import io.michaelrocks.libphonenumber.kotlin.PhoneNumberUtil +import io.michaelrocks.libphonenumber.kotlin.Phonenumber + +class PhoneNumberManager( + private val phoneNumberUtil: PhoneNumberUtil +) : IPhoneNumberManager { + + override fun getValidPhoneNumber( + number: String, + countryCode: String? + ): String? { + val regex = Regex("[^+0-9]") + + // Remove all non-numeric characters except + + val updatedNumber = regex.replace(number, "").replace(" ", "") + // create phone number util instance + + // parse the updated number without country code and check if it's valid + val internationalPhoneNumber = parsePhoneNumber(updatedNumber, countryCode) + // if valid, format it to international format + if (internationalPhoneNumber != null) { + // return the formatted number + return phoneNumberUtil.format( + internationalPhoneNumber, + PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL + ) + } else { + // if not valid, try to parse it with US country code + val usPhoneNumber = parsePhoneNumber(updatedNumber, countryCode) + // if valid, format it to international format + if (usPhoneNumber != null) { + // return the formatted number + return phoneNumberUtil.format( + usPhoneNumber, + PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL + ) + } + } + + // if not valid, return null + return null + } + + override fun getFormattedPhoneNumber(number: String, countryCode: String?): String? { + val phoneNumber = parsePhoneNumber(number, countryCode) ?: return null + return phoneNumberUtil.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL) + } + + override fun getE164FormattedPhoneNumber(number: String, countryCode: String?): String? { + val phoneNumber = parsePhoneNumber(number, countryCode) ?: return null + return phoneNumberUtil.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164) + } + + override fun isValidPhoneNumber(number: String, countryCode: String?): Boolean { + val phoneNumber = parsePhoneNumber(number, countryCode) ?: return false + return phoneNumberUtil.isValidNumber(phoneNumber) + } + + private fun parsePhoneNumber( + number: String, + countryCode: String? + ): Phonenumber.PhoneNumber? { + try { + val phoneNumber = phoneNumberUtil.parse(number, countryCode) + val phoneNumberType = phoneNumberUtil.getNumberType(phoneNumber) + val isValidPhoneType = + phoneNumberType == PhoneNumberUtil.PhoneNumberType.MOBILE || phoneNumberType == PhoneNumberUtil.PhoneNumberType.FIXED_LINE_OR_MOBILE + return if (isValidPhoneType) { + phoneNumber + } else { + null + } + } catch (_: Exception) { + } + return null + } +} \ No newline at end of file diff --git a/phoneNumber/src/iosMain/kotlin/com/metacto/kmm/base/BaseClassForTest.ios.kt b/phoneNumber/src/iosMain/kotlin/com/metacto/kmm/base/BaseClassForTest.ios.kt new file mode 100644 index 00000000..34a2d081 --- /dev/null +++ b/phoneNumber/src/iosMain/kotlin/com/metacto/kmm/base/BaseClassForTest.ios.kt @@ -0,0 +1,6 @@ +package com.metacto.kmm.base + +actual class BaseClassForTest { + actual fun test() { + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index a8ba79ff..0285c923 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,4 +3,5 @@ include(":sampleAppShared") include(":coreapp") include(":androidApp") include(":baseModule") -include(":notifications") \ No newline at end of file +include(":notifications") +include(":phoneNumber") \ No newline at end of file From 0d3e4cff0b6aecc6ea47d3af2e76c6cb50de2e8e Mon Sep 17 00:00:00 2001 From: abdosaidbassuony Date: Sat, 26 Apr 2025 01:47:42 +0300 Subject: [PATCH 2/2] reformat file --- .../com/metacto/kmm/phoneNumber/di/PhoneNumberModule.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/di/PhoneNumberModule.kt b/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/di/PhoneNumberModule.kt index b6b2c31a..81eb2cff 100644 --- a/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/di/PhoneNumberModule.kt +++ b/phoneNumber/src/commonMain/kotlin/com/metacto/kmm/phoneNumber/di/PhoneNumberModule.kt @@ -5,7 +5,7 @@ import com.metacto.kmm.phoneNumber.phoneNumberManger.PhoneNumberManager import org.koin.dsl.module val phoneNumberModule = module { - single { - PhoneNumberManager(get()) - } + single { + PhoneNumberManager(get()) + } } \ No newline at end of file