From 24b380fff06b0c3147a976c7c0f6057e83ec8d1a Mon Sep 17 00:00:00 2001 From: Alemoore Date: Wed, 2 Mar 2022 15:44:15 +0300 Subject: [PATCH 01/13] use interface in RxViewModel --- .../src/main/java/ru/touchin/lifecycle/viewmodel/RxViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lifecycle-rx/src/main/java/ru/touchin/lifecycle/viewmodel/RxViewModel.kt b/lifecycle-rx/src/main/java/ru/touchin/lifecycle/viewmodel/RxViewModel.kt index 74b8f67..5919bdf 100644 --- a/lifecycle-rx/src/main/java/ru/touchin/lifecycle/viewmodel/RxViewModel.kt +++ b/lifecycle-rx/src/main/java/ru/touchin/lifecycle/viewmodel/RxViewModel.kt @@ -8,7 +8,7 @@ import androidx.annotation.CallSuper */ open class RxViewModel( private val destroyable: BaseDestroyable = BaseDestroyable(), - private val liveDataDispatcher: BaseLiveDataDispatcher = BaseLiveDataDispatcher(destroyable) + private val liveDataDispatcher: LiveDataDispatcher = BaseLiveDataDispatcher(destroyable) ) : ViewModel(), Destroyable by destroyable, LiveDataDispatcher by liveDataDispatcher { @CallSuper From 7ed7a25bfeca2944d7fc09caaedf2047eac4ad34 Mon Sep 17 00:00:00 2001 From: Alemoore Date: Wed, 2 Mar 2022 15:46:55 +0300 Subject: [PATCH 02/13] add TestableLiveDataDispatcher without android classes --- .../viewmodel/TestableLiveDataDispatcher.kt | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 lifecycle-rx/src/main/java/ru/touchin/lifecycle/viewmodel/TestableLiveDataDispatcher.kt diff --git a/lifecycle-rx/src/main/java/ru/touchin/lifecycle/viewmodel/TestableLiveDataDispatcher.kt b/lifecycle-rx/src/main/java/ru/touchin/lifecycle/viewmodel/TestableLiveDataDispatcher.kt new file mode 100644 index 0000000..c7ea674 --- /dev/null +++ b/lifecycle-rx/src/main/java/ru/touchin/lifecycle/viewmodel/TestableLiveDataDispatcher.kt @@ -0,0 +1,49 @@ +package ru.touchin.lifecycle.viewmodel + +import androidx.lifecycle.MutableLiveData +import io.reactivex.Completable +import io.reactivex.Flowable +import io.reactivex.Maybe +import io.reactivex.Observable +import io.reactivex.Single +import io.reactivex.disposables.Disposable +import ru.touchin.lifecycle.event.ContentEvent +import ru.touchin.lifecycle.event.Event + +class TestableLiveDataDispatcher( + private val destroyable: BaseDestroyable = BaseDestroyable() +) : LiveDataDispatcher, Destroyable by destroyable { + + override fun Flowable.dispatchTo(liveData: MutableLiveData>): Disposable { + return untilDestroy( + { data -> liveData.value = ContentEvent.Success(data) }, + { throwable -> liveData.value = ContentEvent.Error(throwable, liveData.value?.data) }, + { liveData.value = ContentEvent.Complete(liveData.value?.data) }) + } + + override fun Observable.dispatchTo(liveData: MutableLiveData>): Disposable { + return untilDestroy( + { data -> liveData.value = ContentEvent.Success(data) }, + { throwable -> liveData.value = ContentEvent.Error(throwable, liveData.value?.data) }, + { liveData.value = ContentEvent.Complete(liveData.value?.data) }) + } + + override fun Single.dispatchTo(liveData: MutableLiveData>): Disposable { + return untilDestroy( + { data -> liveData.value = ContentEvent.Success(data) }, + { throwable -> liveData.value = ContentEvent.Error(throwable, liveData.value?.data) }) + } + + override fun Maybe.dispatchTo(liveData: MutableLiveData>): Disposable { + return untilDestroy( + { data -> liveData.value = ContentEvent.Success(data) }, + { throwable -> liveData.value = ContentEvent.Error(throwable, liveData.value?.data) }, + { liveData.value = ContentEvent.Complete(liveData.value?.data) }) + } + + override fun Completable.dispatchTo(liveData: MutableLiveData): Disposable { + return untilDestroy( + { liveData.value = Event.Complete }, + { throwable -> liveData.value = Event.Error(throwable) }) + } +} From 9a728a9e57ffa270a77a2b5f1ad2880af61b2ec5 Mon Sep 17 00:00:00 2001 From: Rinat Nurmukhametov Date: Tue, 15 Mar 2022 11:46:24 +0300 Subject: [PATCH 03/13] create captcha module with checking --- recaptcha/.gitignore | 1 + recaptcha/README.md | 12 ++++ recaptcha/build.gradle | 50 ++++++++++++++++ recaptcha/src/main/AndroidManifest.xml | 6 ++ .../touchin/recaptcha/RecaptchaController.kt | 60 +++++++++++++++++++ .../ru/touchin/recaptcha/ServicesUtils.kt | 19 ++++++ 6 files changed, 148 insertions(+) create mode 100644 recaptcha/.gitignore create mode 100644 recaptcha/README.md create mode 100644 recaptcha/build.gradle create mode 100644 recaptcha/src/main/AndroidManifest.xml create mode 100644 recaptcha/src/main/java/ru/touchin/recaptcha/RecaptchaController.kt create mode 100644 recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt diff --git a/recaptcha/.gitignore b/recaptcha/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/recaptcha/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/recaptcha/README.md b/recaptcha/README.md new file mode 100644 index 0000000..ca78bde --- /dev/null +++ b/recaptcha/README.md @@ -0,0 +1,12 @@ +recaptcha +===== + +Модуль содержит класс `RecaptchaController` - служит для проверки используемого сервиса (Huawei или Google) и показа диалога с каптчёй + +Для использования модуля нужно добавить json файл с сервисами в корневую папку проекта + +### Конструктор +`googleRecaptchaKey` - ключ для google recaptcha +`huaweiAppId` - `id` приложения для huawei captcha +`onNewTokenReceived` - callback на успешную проверку каптчи +`processThrowable` - callback на ошибку проверки каптчи diff --git a/recaptcha/build.gradle b/recaptcha/build.gradle new file mode 100644 index 0000000..42c941e --- /dev/null +++ b/recaptcha/build.gradle @@ -0,0 +1,50 @@ +apply from: "../android-configs/lib-config.gradle" +apply plugin: 'com.huawei.agconnect' + +dependencies { + implementation project(':kotlin-extensions') + implementation "androidx.core:core" + implementation "androidx.annotation:annotation" + implementation "com.google.android.material:material" + implementation "com.google.android.gms:play-services-safetynet" + implementation "com.google.android.gms:play-services-base" + implementation "com.huawei.hms:safetydetect" + + constraints { + implementation("androidx.core:core") { + version { + require '1.0.0' + } + } + + implementation("androidx.annotation:annotation") { + version { + require '1.1.0' + } + } + + implementation("com.google.android.gms:play-services-safetynet") { + version { + require '17.0.0' + } + } + + implementation("com.google.android.gms:play-services-base") { + version { + require '18.0.1' + } + } + + implementation("com.huawei.hms:safetydetect") { + version { + require '4.0.3.300' + } + } + + implementation("com.google.android.material:material") { + version { + require '1.2.0-rc01' + } + } + } +} diff --git a/recaptcha/src/main/AndroidManifest.xml b/recaptcha/src/main/AndroidManifest.xml new file mode 100644 index 0000000..17ef42a --- /dev/null +++ b/recaptcha/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/RecaptchaController.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/RecaptchaController.kt new file mode 100644 index 0000000..d3720ee --- /dev/null +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/RecaptchaController.kt @@ -0,0 +1,60 @@ +package ru.touchin.recaptcha + +import android.app.Activity +import com.google.android.gms.safetynet.SafetyNet +import com.huawei.hms.support.api.safetydetect.SafetyDetect +import ru.touchin.recaptcha.ServicesUtils.checkGooglePlayServices +import ru.touchin.recaptcha.ServicesUtils.checkHuaweiServices + +class RecaptchaController( + private val activity: Activity, + private val googleRecaptchaKey: String? = null, + private val huaweiAppId: String? = null, + private val onNewTokenReceived: (String) -> Unit, + private val processThrowable: (Throwable) -> Unit +) { + + fun showRecaptchaAlert() { + when { + checkHuaweiServices(activity) -> showHuaweiCaptcha() + checkGooglePlayServices(activity) -> showGoogleCaptcha() + } + } + + private fun showGoogleCaptcha() { + if (googleRecaptchaKey != null) { + SafetyNet.getClient(activity) + .verifyWithRecaptcha(googleRecaptchaKey) + .addOnSuccessListener(activity) { response -> + onServiceTokenResponse(response?.tokenResult) + } + .addOnFailureListener(activity, processThrowable) + } + } + + private fun showHuaweiCaptcha() { + if (huaweiAppId != null) { + val huaweiSafetyDetectClient = SafetyDetect.getClient(activity) + huaweiSafetyDetectClient.initUserDetect() + .addOnSuccessListener { + huaweiSafetyDetectClient.userDetection(huaweiAppId) + .addOnSuccessListener { response -> + onServiceTokenResponse(response?.responseToken) + } + .addOnFailureListener(activity, processThrowable) + } + .addOnFailureListener(activity, processThrowable) + } + } + + private fun onServiceTokenResponse(newToken: String?) { + if (!newToken.isNullOrBlank()) { + onNewTokenReceived.invoke(newToken) + } else { + processThrowable.invoke(EmptyCaptchaTokenException()) + } + } + +} + +class EmptyCaptchaTokenException : Throwable("Captcha token is empty") diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt new file mode 100644 index 0000000..502a731 --- /dev/null +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt @@ -0,0 +1,19 @@ +package ru.touchin.recaptcha + +import android.content.Context +import com.google.android.gms.common.ConnectionResult +import com.google.android.gms.common.GoogleApiAvailability +import com.huawei.hms.api.HuaweiApiAvailability + +//TODO: in the future move to a module with services +object ServicesUtils { + + fun checkHuaweiServices(context: Context): Boolean = + HuaweiApiAvailability.getInstance() + .isHuaweiMobileNoticeAvailable(context) == ConnectionResult.SUCCESS + + fun checkGooglePlayServices(context: Context): Boolean = + GoogleApiAvailability.getInstance() + .isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS + +} From d9e891c83840891dd7759a2a4858fe5e78e78290 Mon Sep 17 00:00:00 2001 From: rinstance <30986957+rinstance@users.noreply.github.com> Date: Tue, 15 Mar 2022 11:48:11 +0300 Subject: [PATCH 04/13] change README --- recaptcha/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/recaptcha/README.md b/recaptcha/README.md index ca78bde..f2a26cb 100644 --- a/recaptcha/README.md +++ b/recaptcha/README.md @@ -6,7 +6,7 @@ recaptcha Для использования модуля нужно добавить json файл с сервисами в корневую папку проекта ### Конструктор -`googleRecaptchaKey` - ключ для google recaptcha -`huaweiAppId` - `id` приложения для huawei captcha -`onNewTokenReceived` - callback на успешную проверку каптчи -`processThrowable` - callback на ошибку проверки каптчи +* `googleRecaptchaKey` - ключ для google recaptcha +* `huaweiAppId` - `id` приложения для huawei captcha +* `onNewTokenReceived` - callback на успешную проверку каптчи +* `processThrowable` - callback на ошибку проверки каптчи From 8d70d2dad18c8bf26c1629aae10d61a10b94eaab Mon Sep 17 00:00:00 2001 From: Rinat Nurmukhametov Date: Wed, 16 Mar 2022 16:56:04 +0300 Subject: [PATCH 05/13] refactor manager + utils --- recaptcha/build.gradle | 9 +-- .../ru/touchin/recaptcha/CaptchaClient.kt | 24 ++++++++ .../ru/touchin/recaptcha/CaptchaManager.kt | 24 ++++++++ .../touchin/recaptcha/GoogleCaptchaClient.kt | 20 +++++++ .../touchin/recaptcha/HuaweiCaptchaClient.kt | 24 ++++++++ .../touchin/recaptcha/RecaptchaController.kt | 60 ------------------- .../ru/touchin/recaptcha/ServicesUtils.kt | 16 ++++- 7 files changed, 106 insertions(+), 71 deletions(-) create mode 100644 recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaClient.kt create mode 100644 recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt create mode 100644 recaptcha/src/main/java/ru/touchin/recaptcha/GoogleCaptchaClient.kt create mode 100644 recaptcha/src/main/java/ru/touchin/recaptcha/HuaweiCaptchaClient.kt delete mode 100644 recaptcha/src/main/java/ru/touchin/recaptcha/RecaptchaController.kt diff --git a/recaptcha/build.gradle b/recaptcha/build.gradle index 42c941e..7f748b6 100644 --- a/recaptcha/build.gradle +++ b/recaptcha/build.gradle @@ -5,7 +5,6 @@ dependencies { implementation project(':kotlin-extensions') implementation "androidx.core:core" implementation "androidx.annotation:annotation" - implementation "com.google.android.material:material" implementation "com.google.android.gms:play-services-safetynet" implementation "com.google.android.gms:play-services-base" implementation "com.huawei.hms:safetydetect" @@ -25,7 +24,7 @@ dependencies { implementation("com.google.android.gms:play-services-safetynet") { version { - require '17.0.0' + require '18.0.1' } } @@ -40,11 +39,5 @@ dependencies { require '4.0.3.300' } } - - implementation("com.google.android.material:material") { - version { - require '1.2.0-rc01' - } - } } } diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaClient.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaClient.kt new file mode 100644 index 0000000..207a6ef --- /dev/null +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaClient.kt @@ -0,0 +1,24 @@ +package ru.touchin.recaptcha + +import android.app.Activity + +abstract class CaptchaClient( + private val onNewTokenReceived: (String) -> Unit = {}, + private val processThrowable: (Throwable) -> Unit = {} +) { + + abstract fun showCaptcha(activity: Activity, captchaKey: String) + + protected fun onServiceTokenResponse(newToken: String?) { + if (!newToken.isNullOrBlank()) { + onNewTokenReceived.invoke(newToken) + } else { + processThrowable.invoke(EmptyCaptchaTokenException()) + } + } + +} + +class EmptyCaptchaKeyException : Throwable("Captcha key is empty") + +class EmptyCaptchaTokenException : Throwable("Captcha token is empty") diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt new file mode 100644 index 0000000..8aa9d15 --- /dev/null +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt @@ -0,0 +1,24 @@ +package ru.touchin.recaptcha + +import android.app.Activity + +class CaptchaManager( + onNewTokenReceived: (String) -> Unit, + private val processThrowable: (Throwable) -> Unit +) { + + private val clientsMap = mapOf( + MobileService.GOOGLE_SERVICE to GoogleCaptchaClient(onNewTokenReceived, processThrowable), + MobileService.HUAWEI_SERVICE to HuaweiCaptchaClient(onNewTokenReceived, processThrowable) + ) + + fun showRecaptchaAlert(activity: Activity, captchaKey: String) { + if (captchaKey.isBlank()) { + processThrowable.invoke(EmptyCaptchaKeyException()) + } else { + val service = ServicesUtils().getCurrentService(activity) + clientsMap[service]?.showCaptcha(activity, captchaKey) + } + } + +} diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/GoogleCaptchaClient.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/GoogleCaptchaClient.kt new file mode 100644 index 0000000..b25bd34 --- /dev/null +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/GoogleCaptchaClient.kt @@ -0,0 +1,20 @@ +package ru.touchin.recaptcha + +import android.app.Activity +import com.google.android.gms.safetynet.SafetyNet + +class GoogleCaptchaClient( + onNewTokenReceived: (String) -> Unit, + private val processThrowable: (Throwable) -> Unit +) : CaptchaClient(onNewTokenReceived, processThrowable) { + + override fun showCaptcha(activity: Activity, captchaKey: String) { + SafetyNet.getClient(activity) + .verifyWithRecaptcha(captchaKey) + .addOnSuccessListener(activity) { response -> + onServiceTokenResponse(response?.tokenResult) + } + .addOnFailureListener(activity, processThrowable) + } + +} diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/HuaweiCaptchaClient.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/HuaweiCaptchaClient.kt new file mode 100644 index 0000000..6e860ca --- /dev/null +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/HuaweiCaptchaClient.kt @@ -0,0 +1,24 @@ +package ru.touchin.recaptcha + +import android.app.Activity +import com.huawei.hms.support.api.safetydetect.SafetyDetect + +class HuaweiCaptchaClient( + onNewTokenReceived: (String) -> Unit, + private val processThrowable: (Throwable) -> Unit +) : CaptchaClient(onNewTokenReceived, processThrowable) { + + override fun showCaptcha(activity: Activity, captchaKey: String) { + val huaweiSafetyDetectClient = SafetyDetect.getClient(activity) + huaweiSafetyDetectClient.initUserDetect() + .addOnSuccessListener { + huaweiSafetyDetectClient.userDetection(captchaKey) + .addOnSuccessListener { response -> + onServiceTokenResponse(response?.responseToken) + } + .addOnFailureListener(activity, processThrowable) + } + .addOnFailureListener(activity, processThrowable) + } + +} diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/RecaptchaController.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/RecaptchaController.kt deleted file mode 100644 index d3720ee..0000000 --- a/recaptcha/src/main/java/ru/touchin/recaptcha/RecaptchaController.kt +++ /dev/null @@ -1,60 +0,0 @@ -package ru.touchin.recaptcha - -import android.app.Activity -import com.google.android.gms.safetynet.SafetyNet -import com.huawei.hms.support.api.safetydetect.SafetyDetect -import ru.touchin.recaptcha.ServicesUtils.checkGooglePlayServices -import ru.touchin.recaptcha.ServicesUtils.checkHuaweiServices - -class RecaptchaController( - private val activity: Activity, - private val googleRecaptchaKey: String? = null, - private val huaweiAppId: String? = null, - private val onNewTokenReceived: (String) -> Unit, - private val processThrowable: (Throwable) -> Unit -) { - - fun showRecaptchaAlert() { - when { - checkHuaweiServices(activity) -> showHuaweiCaptcha() - checkGooglePlayServices(activity) -> showGoogleCaptcha() - } - } - - private fun showGoogleCaptcha() { - if (googleRecaptchaKey != null) { - SafetyNet.getClient(activity) - .verifyWithRecaptcha(googleRecaptchaKey) - .addOnSuccessListener(activity) { response -> - onServiceTokenResponse(response?.tokenResult) - } - .addOnFailureListener(activity, processThrowable) - } - } - - private fun showHuaweiCaptcha() { - if (huaweiAppId != null) { - val huaweiSafetyDetectClient = SafetyDetect.getClient(activity) - huaweiSafetyDetectClient.initUserDetect() - .addOnSuccessListener { - huaweiSafetyDetectClient.userDetection(huaweiAppId) - .addOnSuccessListener { response -> - onServiceTokenResponse(response?.responseToken) - } - .addOnFailureListener(activity, processThrowable) - } - .addOnFailureListener(activity, processThrowable) - } - } - - private fun onServiceTokenResponse(newToken: String?) { - if (!newToken.isNullOrBlank()) { - onNewTokenReceived.invoke(newToken) - } else { - processThrowable.invoke(EmptyCaptchaTokenException()) - } - } - -} - -class EmptyCaptchaTokenException : Throwable("Captcha token is empty") diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt index 502a731..e2c24e1 100644 --- a/recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt @@ -6,14 +6,24 @@ import com.google.android.gms.common.GoogleApiAvailability import com.huawei.hms.api.HuaweiApiAvailability //TODO: in the future move to a module with services -object ServicesUtils { +class ServicesUtils { - fun checkHuaweiServices(context: Context): Boolean = + fun getCurrentService(context: Context): MobileService = when { + checkHuaweiServices(context) -> MobileService.HUAWEI_SERVICE + checkGooglePlayServices(context) -> MobileService.GOOGLE_SERVICE + else -> MobileService.GOOGLE_SERVICE + } + + private fun checkHuaweiServices(context: Context): Boolean = HuaweiApiAvailability.getInstance() .isHuaweiMobileNoticeAvailable(context) == ConnectionResult.SUCCESS - fun checkGooglePlayServices(context: Context): Boolean = + private fun checkGooglePlayServices(context: Context): Boolean = GoogleApiAvailability.getInstance() .isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS } + +enum class MobileService { + HUAWEI_SERVICE, GOOGLE_SERVICE +} From d201cfb36fa44b4dac3d1673b3086e6b98444b93 Mon Sep 17 00:00:00 2001 From: Rinat Nurmukhametov Date: Wed, 16 Mar 2022 17:01:32 +0300 Subject: [PATCH 06/13] change README --- recaptcha/README.md | 6 ------ .../src/main/java/ru/touchin/recaptcha/CaptchaManager.kt | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/recaptcha/README.md b/recaptcha/README.md index f2a26cb..a9b84b7 100644 --- a/recaptcha/README.md +++ b/recaptcha/README.md @@ -4,9 +4,3 @@ recaptcha Модуль содержит класс `RecaptchaController` - служит для проверки используемого сервиса (Huawei или Google) и показа диалога с каптчёй Для использования модуля нужно добавить json файл с сервисами в корневую папку проекта - -### Конструктор -* `googleRecaptchaKey` - ключ для google recaptcha -* `huaweiAppId` - `id` приложения для huawei captcha -* `onNewTokenReceived` - callback на успешную проверку каптчи -* `processThrowable` - callback на ошибку проверки каптчи diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt index 8aa9d15..ebf7744 100644 --- a/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt @@ -2,6 +2,11 @@ package ru.touchin.recaptcha import android.app.Activity +/** + * onNewTokenReceived - callback на успешную проверку каптчи + * processThrowable - callback на ошибку проверки каптчи + */ + class CaptchaManager( onNewTokenReceived: (String) -> Unit, private val processThrowable: (Throwable) -> Unit From ccb3f1c4e1d6e2060d1663f294e892cf3f8ff2bc Mon Sep 17 00:00:00 2001 From: Rinat Nurmukhametov Date: Wed, 16 Mar 2022 18:31:01 +0300 Subject: [PATCH 07/13] create services module --- client-services/.gitignore | 1 + client-services/build.gradle | 35 +++++++++++++++++++ client-services/src/main/AndroidManifest.xml | 6 ++++ .../touchin/client_services/MobileService.kt | 5 +++ .../touchin/client_services}/ServicesUtils.kt | 7 +--- recaptcha/build.gradle | 3 +- .../ru/touchin/recaptcha/CaptchaManager.kt | 2 ++ 7 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 client-services/.gitignore create mode 100644 client-services/build.gradle create mode 100644 client-services/src/main/AndroidManifest.xml create mode 100644 client-services/src/main/java/ru/touchin/client_services/MobileService.kt rename {recaptcha/src/main/java/ru/touchin/recaptcha => client-services/src/main/java/ru/touchin/client_services}/ServicesUtils.kt (85%) diff --git a/client-services/.gitignore b/client-services/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/client-services/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/client-services/build.gradle b/client-services/build.gradle new file mode 100644 index 0000000..c55e87e --- /dev/null +++ b/client-services/build.gradle @@ -0,0 +1,35 @@ +apply from: "../android-configs/lib-config.gradle" +apply plugin: 'com.huawei.agconnect' + +dependencies { + implementation "androidx.core:core" + implementation "androidx.annotation:annotation" + implementation "com.google.android.gms:play-services-base" + implementation "com.huawei.hms:safetydetect" + + constraints { + implementation("androidx.core:core") { + version { + require '1.0.0' + } + } + + implementation("androidx.annotation:annotation") { + version { + require '1.1.0' + } + } + + implementation("com.google.android.gms:play-services-base") { + version { + require '18.0.1' + } + } + + implementation("com.huawei.hms:safetydetect") { + version { + require '4.0.3.300' + } + } + } +} diff --git a/client-services/src/main/AndroidManifest.xml b/client-services/src/main/AndroidManifest.xml new file mode 100644 index 0000000..4390a88 --- /dev/null +++ b/client-services/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/client-services/src/main/java/ru/touchin/client_services/MobileService.kt b/client-services/src/main/java/ru/touchin/client_services/MobileService.kt new file mode 100644 index 0000000..6514e3a --- /dev/null +++ b/client-services/src/main/java/ru/touchin/client_services/MobileService.kt @@ -0,0 +1,5 @@ +package ru.touchin.client_services + +enum class MobileService { + HUAWEI_SERVICE, GOOGLE_SERVICE +} diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt b/client-services/src/main/java/ru/touchin/client_services/ServicesUtils.kt similarity index 85% rename from recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt rename to client-services/src/main/java/ru/touchin/client_services/ServicesUtils.kt index e2c24e1..a4566d9 100644 --- a/recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt +++ b/client-services/src/main/java/ru/touchin/client_services/ServicesUtils.kt @@ -1,11 +1,10 @@ -package ru.touchin.recaptcha +package ru.touchin.client_services import android.content.Context import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GoogleApiAvailability import com.huawei.hms.api.HuaweiApiAvailability -//TODO: in the future move to a module with services class ServicesUtils { fun getCurrentService(context: Context): MobileService = when { @@ -23,7 +22,3 @@ class ServicesUtils { .isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS } - -enum class MobileService { - HUAWEI_SERVICE, GOOGLE_SERVICE -} diff --git a/recaptcha/build.gradle b/recaptcha/build.gradle index 7f748b6..51b4418 100644 --- a/recaptcha/build.gradle +++ b/recaptcha/build.gradle @@ -2,7 +2,8 @@ apply from: "../android-configs/lib-config.gradle" apply plugin: 'com.huawei.agconnect' dependencies { - implementation project(':kotlin-extensions') + implementation project(':client-services') + implementation "androidx.core:core" implementation "androidx.annotation:annotation" implementation "com.google.android.gms:play-services-safetynet" diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt index ebf7744..2fd00ee 100644 --- a/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt @@ -1,6 +1,8 @@ package ru.touchin.recaptcha import android.app.Activity +import ru.touchin.client_services.MobileService +import ru.touchin.client_services.ServicesUtils /** * onNewTokenReceived - callback на успешную проверку каптчи From 3681f5c92d84aae67850d224d5e497822b53a15e Mon Sep 17 00:00:00 2001 From: Rinat Nurmukhametov Date: Thu, 17 Mar 2022 12:02:27 +0300 Subject: [PATCH 08/13] change documentation + gradle deps --- client-services/build.gradle | 6 ++-- .../touchin/client_services/ServicesUtils.kt | 4 +++ recaptcha/README.md | 30 +++++++++++++++++-- .../ru/touchin/recaptcha/CaptchaManager.kt | 9 ++++-- .../touchin/recaptcha/HuaweiCaptchaClient.kt | 1 + 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/client-services/build.gradle b/client-services/build.gradle index c55e87e..6799856 100644 --- a/client-services/build.gradle +++ b/client-services/build.gradle @@ -5,7 +5,7 @@ dependencies { implementation "androidx.core:core" implementation "androidx.annotation:annotation" implementation "com.google.android.gms:play-services-base" - implementation "com.huawei.hms:safetydetect" + implementation "com.huawei.hms:base" constraints { implementation("androidx.core:core") { @@ -26,9 +26,9 @@ dependencies { } } - implementation("com.huawei.hms:safetydetect") { + implementation("com.huawei.hms:base") { version { - require '4.0.3.300' + require '6.3.0.303' } } } diff --git a/client-services/src/main/java/ru/touchin/client_services/ServicesUtils.kt b/client-services/src/main/java/ru/touchin/client_services/ServicesUtils.kt index a4566d9..121b736 100644 --- a/client-services/src/main/java/ru/touchin/client_services/ServicesUtils.kt +++ b/client-services/src/main/java/ru/touchin/client_services/ServicesUtils.kt @@ -5,6 +5,10 @@ import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GoogleApiAvailability import com.huawei.hms.api.HuaweiApiAvailability +/** + * A class with utils for interacting with Google, Huawei, etc. services + */ + class ServicesUtils { fun getCurrentService(context: Context): MobileService = when { diff --git a/recaptcha/README.md b/recaptcha/README.md index a9b84b7..a437d99 100644 --- a/recaptcha/README.md +++ b/recaptcha/README.md @@ -1,6 +1,32 @@ recaptcha ===== -Модуль содержит класс `RecaptchaController` - служит для проверки используемого сервиса (Huawei или Google) и показа диалога с каптчёй +### Общее описание -Для использования модуля нужно добавить json файл с сервисами в корневую папку проекта +Модуль содержит класс `CaptchaManager` - служит для проверки используемого сервиса (Huawei или Google) и показа диалога с каптчёй +В конструктуре `CaptchaManager` принимает два callback`а: +`onNewTokenReceived` - успешная проверка, возвращает токен +`processThrowable` - ошибка, возвращает `Throwable` + +### Требования + +Для использования модуля нужно добавить json файл с сервисами в корневую папку проекта: +Для Google - google-services.json +Для Huawei - agconnect-services.json + +### Пример + +Во `Fragment` + +```kotlin +val manager = CaptchaManager(onNewTokenReceived = { token -> + viewModel.sendRequest(token) + }, processThrowable = { error -> + showError(error) + }) + +manager.showRecaptchaAlert( + activity = activity, + captchaKey = "6Lc2heYeAAAAAHqe3mp0ylUnvXSY4lYfbRCwsVz_" +) +``` diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt index 2fd00ee..2e5145b 100644 --- a/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/CaptchaManager.kt @@ -5,12 +5,15 @@ import ru.touchin.client_services.MobileService import ru.touchin.client_services.ServicesUtils /** - * onNewTokenReceived - callback на успешную проверку каптчи - * processThrowable - callback на ошибку проверки каптчи + * A class for displaying a dialog with a captcha + * with a check on the current service of the application + * + * @param onNewTokenReceived - callback for a successful captcha check, return token + * @param processThrowable - callback for a captcha check error, return throwable */ class CaptchaManager( - onNewTokenReceived: (String) -> Unit, + private val onNewTokenReceived: (String) -> Unit, private val processThrowable: (Throwable) -> Unit ) { diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/HuaweiCaptchaClient.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/HuaweiCaptchaClient.kt index 6e860ca..2dd8c20 100644 --- a/recaptcha/src/main/java/ru/touchin/recaptcha/HuaweiCaptchaClient.kt +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/HuaweiCaptchaClient.kt @@ -10,6 +10,7 @@ class HuaweiCaptchaClient( override fun showCaptcha(activity: Activity, captchaKey: String) { val huaweiSafetyDetectClient = SafetyDetect.getClient(activity) + huaweiSafetyDetectClient.initUserDetect() .addOnSuccessListener { huaweiSafetyDetectClient.userDetection(captchaKey) From 05f2adb849158848de8973e6ee90e7cea425e60c Mon Sep 17 00:00:00 2001 From: Rinat Nurmukhametov Date: Thu, 17 Mar 2022 12:14:23 +0300 Subject: [PATCH 09/13] fix for comments --- .../java/ru/touchin/client_services/ServicesUtils.kt | 2 +- recaptcha/README.md | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/client-services/src/main/java/ru/touchin/client_services/ServicesUtils.kt b/client-services/src/main/java/ru/touchin/client_services/ServicesUtils.kt index 121b736..1cc5b2a 100644 --- a/client-services/src/main/java/ru/touchin/client_services/ServicesUtils.kt +++ b/client-services/src/main/java/ru/touchin/client_services/ServicesUtils.kt @@ -6,7 +6,7 @@ import com.google.android.gms.common.GoogleApiAvailability import com.huawei.hms.api.HuaweiApiAvailability /** - * A class with utils for interacting with Google, Huawei, etc. services + * A class with utils for interacting with Google, Huawei services */ class ServicesUtils { diff --git a/recaptcha/README.md b/recaptcha/README.md index a437d99..69a7392 100644 --- a/recaptcha/README.md +++ b/recaptcha/README.md @@ -4,15 +4,16 @@ recaptcha ### Общее описание Модуль содержит класс `CaptchaManager` - служит для проверки используемого сервиса (Huawei или Google) и показа диалога с каптчёй -В конструктуре `CaptchaManager` принимает два callback`а: +В конструктуре `CaptchaManager` принимает два callback: `onNewTokenReceived` - успешная проверка, возвращает токен `processThrowable` - ошибка, возвращает `Throwable` ### Требования Для использования модуля нужно добавить json файл с сервисами в корневую папку проекта: -Для Google - google-services.json -Для Huawei - agconnect-services.json + +1. Для Google - google-services.json +2. Для Huawei - agconnect-services.json ### Пример @@ -27,6 +28,6 @@ val manager = CaptchaManager(onNewTokenReceived = { token -> manager.showRecaptchaAlert( activity = activity, - captchaKey = "6Lc2heYeAAAAAHqe3mp0ylUnvXSY4lYfbRCwsVz_" + captchaKey = BuildConfig.CAPTCHA_TOKEN ) ``` From 82e1cff525aa64dd2a2ff1218468ad40bdf55c25 Mon Sep 17 00:00:00 2001 From: Grigorii Date: Mon, 18 Apr 2022 11:51:21 +0300 Subject: [PATCH 10/13] Remove pretty-print dependency from mvi module --- mvi-arch/build.gradle | 2 -- .../ru/touchin/roboswag/mvi_arch/core/MviViewModel.kt | 6 +++--- .../roboswag/mvi_arch/mediator/LoggingMediator.kt | 9 ++------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/mvi-arch/build.gradle b/mvi-arch/build.gradle index 1532294..77b2a22 100644 --- a/mvi-arch/build.gradle +++ b/mvi-arch/build.gradle @@ -28,8 +28,6 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android") - implementation("com.tylerthrailkill.helpers:pretty-print:2.0.2") - def fragmentVersion = "1.2.1" def lifecycleVersion = "2.2.0" def coroutinesVersion = "1.3.7" diff --git a/mvi-arch/src/main/java/ru/touchin/roboswag/mvi_arch/core/MviViewModel.kt b/mvi-arch/src/main/java/ru/touchin/roboswag/mvi_arch/core/MviViewModel.kt index 8b4b170..ede36e5 100644 --- a/mvi-arch/src/main/java/ru/touchin/roboswag/mvi_arch/core/MviViewModel.kt +++ b/mvi-arch/src/main/java/ru/touchin/roboswag/mvi_arch/core/MviViewModel.kt @@ -9,8 +9,10 @@ import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.launch +import ru.touchin.mvi_arch.BuildConfig import ru.touchin.roboswag.mvi_arch.marker.ViewAction import ru.touchin.roboswag.mvi_arch.marker.ViewState +import ru.touchin.roboswag.mvi_arch.mediator.LoggingMediator import ru.touchin.roboswag.mvi_arch.mediator.MediatorStore /** @@ -40,9 +42,7 @@ abstract class MviViewModel Date: Fri, 15 Apr 2022 17:53:43 +0300 Subject: [PATCH 11/13] Create DateFormatUtils class for handling cases with DateTime format --- utils/build.gradle | 14 ++++++++ .../roboswag/core/utils/DateFormatUtils.kt | 32 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 utils/src/main/java/ru/touchin/roboswag/core/utils/DateFormatUtils.kt diff --git a/utils/build.gradle b/utils/build.gradle index fe6fd6a..954f81e 100644 --- a/utils/build.gradle +++ b/utils/build.gradle @@ -5,6 +5,8 @@ dependencies { implementation "androidx.core:core" implementation "androidx.annotation:annotation" implementation "com.google.android.material:material" + implementation "net.danlew:android.joda" + implementation "junit:junit" constraints { implementation("androidx.core:core") { @@ -24,5 +26,17 @@ dependencies { require '1.2.0-rc01' } } + + implementation("net.danlew:android.joda") { + version { + require '2.10.2' + } + } + + implementation("junit:junit") { + version { + require '4.13.2' + } + } } } diff --git a/utils/src/main/java/ru/touchin/roboswag/core/utils/DateFormatUtils.kt b/utils/src/main/java/ru/touchin/roboswag/core/utils/DateFormatUtils.kt new file mode 100644 index 0000000..9444416 --- /dev/null +++ b/utils/src/main/java/ru/touchin/roboswag/core/utils/DateFormatUtils.kt @@ -0,0 +1,32 @@ +package ru.touchin.roboswag.core.utils + +import org.joda.time.DateTime +import org.joda.time.format.DateTimeFormat + +/** + * Util object for handling some cases with DateTime e.g. parsing string to DateTime object + */ +object DateFormatUtils { + + enum class Format(val formatValue: String) { + DATE_TIME_FORMAT("yyyy-MM-dd'T'HH:mm:ss.SSSZZ"), + DATE_FORMAT("yyyy-MM-dd"), + TIME_FORMAT("HH:mm:ssZ") + } + + /** + * @return the result of parsed string value + * @param value is string value of date time in right format + * @param format is date time format for parsing string value. + * Default value is [Format.DATE_TIME_FORMAT] + * @param defaultValue is value returned in case of exception + */ + fun fromString( + value: String, + format: Format = Format.DATE_TIME_FORMAT, + defaultValue: DateTime? = null + ): DateTime? = runCatching { value.parse(format.formatValue) }.getOrDefault(defaultValue) + + private fun String.parse(format: String) = DateTimeFormat.forPattern(format).parseDateTime(this) + +} From a3241002c51800d60adb464119ef7de38f04335c Mon Sep 17 00:00:00 2001 From: Kirill Nayduik Date: Fri, 15 Apr 2022 18:22:23 +0300 Subject: [PATCH 12/13] Create DateFormatUtilsTest for testing DateFormatUtils --- utils/src/test/java/DateFormatUtilsTest.kt | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 utils/src/test/java/DateFormatUtilsTest.kt diff --git a/utils/src/test/java/DateFormatUtilsTest.kt b/utils/src/test/java/DateFormatUtilsTest.kt new file mode 100644 index 0000000..62b4290 --- /dev/null +++ b/utils/src/test/java/DateFormatUtilsTest.kt @@ -0,0 +1,34 @@ +import org.joda.time.DateTime +import org.joda.time.DateTimeZone +import org.joda.time.tz.UTCProvider +import org.junit.Assert +import org.junit.Test +import ru.touchin.roboswag.core.utils.DateFormatUtils + +class DateFormatUtilsTest { + + init { + DateTimeZone.setProvider(UTCProvider()) + } + + @Test + fun `Assert Date format parsing`() { + val dateTime = DateFormatUtils.fromString( + value = "2015-04-29", + format = DateFormatUtils.Format.DATE_FORMAT + ) + Assert.assertEquals(DateTime(2015, 4, 29, 0, 0, 0), dateTime) + } + + @Test + fun `Assert Date format parsing with default value`() { + val currentDateTime = DateTime.now() + + val dateTime = DateFormatUtils.fromString( + value = "2015-04-29", + format = DateFormatUtils.Format.DATE_TIME_FORMAT, + defaultValue = currentDateTime + ) + Assert.assertEquals(currentDateTime, dateTime) + } +} From 7a37fb20b74f4b9f4913ca5f052144af5305930a Mon Sep 17 00:00:00 2001 From: Kirill Nayduik Date: Mon, 18 Apr 2022 13:13:35 +0300 Subject: [PATCH 13/13] Add implementation of 'joda-time' for tests to avoid issue https://github.com/dlew/joda-time-android/issues/148 --- utils/build.gradle | 23 +++++++++++++++++----- utils/src/test/java/DateFormatUtilsTest.kt | 6 ------ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/utils/build.gradle b/utils/build.gradle index 954f81e..513c848 100644 --- a/utils/build.gradle +++ b/utils/build.gradle @@ -1,41 +1,54 @@ apply from: "../android-configs/lib-config.gradle" dependencies { + def coreVersion = '1.0.0' + def annotationVersion = '1.1.0' + def materialVersion = '1.2.0-rc01' + def jodaVersion = '2.10.2' + def junitVersion = '4.13.2' + implementation project(':kotlin-extensions') implementation "androidx.core:core" implementation "androidx.annotation:annotation" implementation "com.google.android.material:material" implementation "net.danlew:android.joda" implementation "junit:junit" + testImplementation "joda-time:joda-time" constraints { implementation("androidx.core:core") { version { - require '1.0.0' + require(coreVersion) } } implementation("androidx.annotation:annotation") { version { - require '1.1.0' + require(annotationVersion) } } implementation("com.google.android.material:material") { version { - require '1.2.0-rc01' + require(materialVersion) } } implementation("net.danlew:android.joda") { version { - require '2.10.2' + require(jodaVersion) + } + } + + testImplementation("joda-time:joda-time") { + version { + require(jodaVersion) } } implementation("junit:junit") { version { - require '4.13.2' + require(junitVersion) } } } diff --git a/utils/src/test/java/DateFormatUtilsTest.kt b/utils/src/test/java/DateFormatUtilsTest.kt index 62b4290..8036ede 100644 --- a/utils/src/test/java/DateFormatUtilsTest.kt +++ b/utils/src/test/java/DateFormatUtilsTest.kt @@ -1,16 +1,10 @@ import org.joda.time.DateTime -import org.joda.time.DateTimeZone -import org.joda.time.tz.UTCProvider import org.junit.Assert import org.junit.Test import ru.touchin.roboswag.core.utils.DateFormatUtils class DateFormatUtilsTest { - init { - DateTimeZone.setProvider(UTCProvider()) - } - @Test fun `Assert Date format parsing`() { val dateTime = DateFormatUtils.fromString(