diff --git a/README.md b/README.md
index 6ce78fd0..4d8d8b75 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
# BasicTools
+
[]
(https://jitpack.io/#esasby/basic-tools)
diff --git a/accesscontainer/build.gradle b/accesscontainer/build.gradle
index 71000eee..e42cb5e2 100644
--- a/accesscontainer/build.gradle
+++ b/accesscontainer/build.gradle
@@ -1,64 +1,38 @@
apply plugin: 'com.android.library'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
+apply plugin: 'org.jetbrains.kotlin.android'
apply plugin: 'maven-publish'
+apply from: '../properties.gradle'
-// Because the components are created only during the afterEvaluate phase, you must
-// configure your publications using the afterEvaluate() lifecycle method.
-afterEvaluate {
- task sourceJar(type: Jar) {
- from android.sourceSets.main.java.srcDirs
- classifier "sources"
- }
- publishing {
- publications {
- // Creates a Maven publication called "release".
- release(MavenPublication) {
- // Applies the component for the release build variant.
- from components.release
-
- // You can then customize attributes of the publication as shown below.
- groupId = 'by.esas.tools'
- artifactId = 'accesscontainer'
- version = "$accesscontainer_lib_version"
- }
- // Creates a Maven publication called “debug”.
- /*debug(MavenPublication) {
- // Applies the component for the debug build variant.
- from components.debug
-
- groupId = 'com.example.MyLibrary'
- artifactId = 'final-debug'
- version = '1.0'
- }*/
-
- }
- repositories {
- maven {
- // change to point to your repo, e.g. http://my.org/repo
- url = 'https://github.com/PManenok/BasicTools'
- /*credentials {
- username PManenok
- password BlackCurrant$25
- }*/
- }
- }
- }
-}
android {
- compileSdkVersion 30
+ namespace = "${package_name}.${project.name}"
+
+ compileSdkVersion compile_sdk_version
defaultConfig {
- minSdkVersion 16
+ minSdkVersion min_sdk_version
}
}
dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "androidx.appcompat:appcompat:$appcompat_version"
implementation "androidx.core:core-ktx:$corektx_version"
//Module
- implementation project(path: ':logger')
+ api project(path: ':logger')
+}
+
+afterEvaluate {
+ publishing {
+ publications {
+ // Creates a Maven publication called "release".
+ release(MavenPublication) {
+ from components.release
+ groupId = "${package_name}"
+ artifactId = "${project.name}"
+ version = "$accesscontainer_lib_version"
+ }
+ }
+ }
}
diff --git a/accesscontainer/src/main/AndroidManifest.xml b/accesscontainer/src/main/AndroidManifest.xml
deleted file mode 100644
index 79149913..00000000
--- a/accesscontainer/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/ContainerRequest.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/ContainerRequest.kt
index 5fbf1835..53877294 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/ContainerRequest.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/ContainerRequest.kt
@@ -7,8 +7,8 @@ package by.esas.tools.accesscontainer
import by.esas.tools.logger.BaseErrorModel
+class ContainerRequest {
-class ContainerRequest, M : BaseErrorModel> {
private var onComplete: ((T) -> Unit)? = null
private var onError: ((M) -> Unit)? = null
private var onCancel: (() -> Unit)? = null
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/IRefreshContainer.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/IRefreshContainer.kt
index 0bfc71a2..634f1dea 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/IRefreshContainer.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/IRefreshContainer.kt
@@ -6,45 +6,43 @@
package by.esas.tools.accesscontainer
import androidx.fragment.app.FragmentActivity
-import androidx.fragment.app.FragmentManager
import by.esas.tools.accesscontainer.entity.Token
import by.esas.tools.accesscontainer.support.IContainerCancellationCallback
import by.esas.tools.logger.BaseErrorModel
-interface IRefreshContainer, M : BaseErrorModel> {
+interface IRefreshContainer {
+
fun setToken(token: Token)
fun getToken(): String
fun getRefresh(): String
fun setCancellationCallback(callback: IContainerCancellationCallback)
fun setActivity(activity: FragmentActivity)
- fun setParams(manager: FragmentManager)
fun setForgotPasswordAction(enable: Boolean, forgotPasswordAction: () -> Unit)
/**
* This function can refresh token without secret key
* Access token would be refreshed anyway
**/
- fun refresh(onComplete: (String?) -> Unit, onError: (BaseErrorModel) -> Unit, onCancel: () -> Unit)
+ fun refresh(onComplete: (String?) -> Unit, onError: (M) -> Unit, onCancel: () -> Unit)
/**
* This function would always invoke dialogs with secrets if it can, because it checks if user can access secret
* can refresh token or not
* @see refreshExplicitly
**/
- fun checkAccess(refreshExplicitly: Boolean = false, response: ContainerRequest.() -> Unit)
+ fun checkAccess(refreshExplicitly: Boolean = false, response: ContainerRequest.() -> Unit)
/**
* This function can save refresh token, it invokes only encryption dialogs
* Should be used only when no secret exist, because it will override old secrets
**/
- fun saveRefresh(refreshToken: String, response: ContainerRequest.() -> Unit)
+ fun saveRefresh(refreshToken: String, response: ContainerRequest.() -> Unit)
/**
- * This function can save refresh token, it invokes only encryption dialogs
- * Should be used only when no secret exist, because it will override old secrets
+ * This function return secret after PIN or Biometric decryption success
**/
- fun getSecret(response: ContainerRequest.() -> Unit)
+ fun getSecret(response: ContainerRequest.() -> Unit)
fun setUserId(userId: String)
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/Refresher.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/Refresher.kt
index 37edf965..848bff17 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/Refresher.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/Refresher.kt
@@ -7,7 +7,6 @@ package by.esas.tools.accesscontainer
import android.provider.Settings
import androidx.fragment.app.FragmentActivity
-import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
@@ -15,6 +14,9 @@ import by.esas.tools.accesscontainer.dialog.BiometricUserInfo
import by.esas.tools.accesscontainer.dialog.DialogProvider
import by.esas.tools.accesscontainer.dialog.IBaseDialog
import by.esas.tools.accesscontainer.dialog.IBiometric
+import by.esas.tools.accesscontainer.dialog.setters.MenuResultHandler
+import by.esas.tools.accesscontainer.dialog.setters.PasswordResultHandler
+import by.esas.tools.accesscontainer.dialog.setters.PinResultHandler
import by.esas.tools.accesscontainer.entity.AuthType
import by.esas.tools.accesscontainer.entity.RefreshResult
import by.esas.tools.accesscontainer.entity.Token
@@ -26,20 +28,25 @@ import by.esas.tools.accesscontainer.support.ITypeManager
import by.esas.tools.accesscontainer.support.supporter.Supporter
import by.esas.tools.logger.BaseErrorModel
import by.esas.tools.logger.ILogger
+import by.esas.tools.logger.ILogger.Companion.CATEGORY_ERROR
import java.lang.ref.WeakReference
import javax.crypto.Cipher
import javax.crypto.SecretKey
-open class Refresher, M : BaseErrorModel>(
- protected val logger: ILogger,
- protected val executor: IContainerExecutor,
+open class Refresher(
+ protected val logger: ILogger,
+ protected val executor: IContainerExecutor,
protected val typeManager: ITypeManager,
protected val userInfo: BiometricUserInfo,
- protected val mapper: IErrorMapper,
+ protected val mapper: IErrorMapper,
protected val dialogProvider: DialogProvider,
- protected val supporter: Supporter
-) : IRefreshContainer {
+ protected val supporter: Supporter
+) : IRefreshContainer {
+
val TAG: String = Refresher::class.java.simpleName
+
+ /*region Params*/
+
protected var accessToken: String = ""
protected var refreshToken: String = ""
@@ -47,21 +54,21 @@ open class Refresher, M : BaseErrorModel>(
protected val defaultCancellationCallback: IContainerCancellationCallback = object :
IContainerCancellationCallback {
override fun onCancel() {
- logger.log("defaultCancellationCallback onCancel does nothing")
+ logger.logInfo("defaultCancellationCallback onCancel does nothing")
//does nothing. should be set before refresh usage
}
}
protected var containerCancellationCallback: IContainerCancellationCallback =
defaultCancellationCallback // cancellation callback invoke if UC callback not set?
- protected var fragmentManager: WeakReference =
- WeakReference(null) // fragment manager for simple dialogs
+ /*protected var fragmentManager: WeakReference =
+ WeakReference(null) // fragment manager for simple dialogs*/
protected var activity: WeakReference = WeakReference(null) // activity for biometric dialog
- protected var result: ContainerRequest =
- ContainerRequest() // result instance which will get result when it is finished
- protected var secretResult: ContainerRequest =
- ContainerRequest() // result instance which will get result when it is finished
+ protected var result: ContainerRequest =
+ ContainerRequest() // result instance which will get result when it is finished
+ protected var secretResult: ContainerRequest =
+ ContainerRequest() // result instance which will get result when it is finished
protected var userIdValue: String = "" // user ID sets from getSecrets or with setUserId method
protected var isBiometricAvailable: Boolean = false // shows if biometric is available
@@ -82,26 +89,30 @@ open class Refresher, M : BaseErrorModel>(
protected val types: MutableSet = mutableSetOf()// shows which secret types user has
- protected var refresherErrorStatusToCheck: E? = null
+ protected var refresherErrorStatusToCheck: String? = null
protected var checkRefreshError: Boolean = false
protected var useExtraCheck: Boolean = false
- protected var extraRefreshCheck: (BaseErrorModel) -> Unit = {}
+ protected var extraRefreshCheck: (BaseErrorModel) -> Unit = {}
+
+ /*endregion Params*/
init {
logger.setTag(TAG)
}
+ /*region ############################# Base functionality ##########################################*/
+
override fun setUserId(userId: String) {
this.userIdValue = userId
}
override fun getToken(): String {
- logger.log("getToken()")
+ logger.logOrder("getToken()")
return accessToken
}
override fun setToken(token: Token) {
- logger.log("setToken() refreshToken isNullOrBlank = ${token.refreshToken.isNullOrBlank()}")
+ logger.logOrder("setToken() refreshToken isNullOrBlank = ${token.refreshToken.isNullOrBlank()}")
accessToken = token.accessToken
refreshToken = token.refreshToken ?: ""
}
@@ -114,57 +125,57 @@ open class Refresher, M : BaseErrorModel>(
* Запуск запроса на восстановление маркера доступа с последующим обновлением
* данных контейнера и выполнением переданного блока кода
*/
- override fun refresh(onComplete: (String?) -> Unit, onError: (BaseErrorModel) -> Unit, onCancel: () -> Unit) {
- logger.log("refresh")
+ override fun refresh(onComplete: (String?) -> Unit, onError: (M) -> Unit, onCancel: () -> Unit) {
+ logger.logOrder("refresh")
this.refreshExplicitly = true
- result = ContainerRequest()
+ result = ContainerRequest()
.apply {
onComplete { tokenResponse ->
- logger.log("refresh result.onComplete token != null = ${tokenResponse.token != null}")
+ logger.logOrder("refresh result.onComplete token != null = ${tokenResponse.token != null}")
tokenResponse.token?.let { setToken(it) }
onComplete(tokenResponse.token?.accessToken)
}
onError {
- logger.log("refresh result.onError")
+ logger.logOrder("refresh result.onError")
logger.logError(it)
onError(it)
}
onCancel {
- logger.log("refresh result.onCancel")
+ logger.logOrder("refresh result.onCancel")
onCancel()
}
}
- logger.log("refresh needCheck = false")
+ logger.logDebug("refresh needCheck = false")
needCheck = false
needSecret = false
if (refreshToken.isNotEmpty()) {
- logger.log("refresh refreshToken isNotEmpty")
+ logger.logDebug("refresh refreshToken isNotEmpty")
refreshAccess(refreshToken)
} else {
- logger.log("refresh refreshToken isEmpty")
+ logger.logDebug("refresh refreshToken isEmpty")
userIdValue = userInfo.getCurrentUser()
- logger.log("refresh userId = $userIdValue")
+ logger.logUserInfo("refresh userId = $userIdValue")
getSecrets()
}
}
override fun onCancel() {
- logger.log("onCancel")
+ logger.logOrder("onCancel")
containerCancellationCallback.onCancel()
}
- override fun checkAccess(refreshExplicitly: Boolean, response: ContainerRequest.() -> Unit) {
- logger.log("checkAccess refreshExplicitly = $refreshExplicitly")
+ override fun checkAccess(refreshExplicitly: Boolean, response: ContainerRequest.() -> Unit) {
+ logger.logOrder("checkAccess refreshExplicitly = $refreshExplicitly")
this.refreshExplicitly = refreshExplicitly
- val result = ContainerRequest().apply(response)
+ val result = ContainerRequest().apply(response)
- this.result = ContainerRequest()
+ this.result = ContainerRequest()
.apply {
onComplete { tokenResponse ->
- logger.log("checkAccess result.onComplete hasAccess = ${tokenResponse.hasAccess}")
+ logger.logOrder("checkAccess result.onComplete hasAccess = ${tokenResponse.hasAccess}")
if (tokenResponse.hasAccess) {
- logger.log("checkAccess result.onComplete token != null = ${tokenResponse.token != null}")
+ logger.logDebug("checkAccess result.onComplete token != null = ${tokenResponse.token != null}")
tokenResponse.token?.let { token ->
setToken(token)
}
@@ -172,52 +183,53 @@ open class Refresher, M : BaseErrorModel>(
} else result()
}
onError {
- logger.log("checkAccess result.onError")
+ logger.logOrder("checkAccess result.onError")
logger.logError(it)
result(it)
}
onCancel {
- logger.log("checkAccess result.onCancel")
+ logger.logOrder("checkAccess result.onCancel")
result()
}
}
- logger.log("checkAccess needCheck = true")
+ logger.logDebug("checkAccess needCheck = true needSecret = false")
needCheck = true
needSecret = false
userIdValue = userInfo.getCurrentUser()
- logger.log("checkAccess userId = $userIdValue")
+ logger.logUserInfo("checkAccess userId = $userIdValue")
getSecrets()
}
- override fun getSecret(response: ContainerRequest.() -> Unit) {
- logger.log("getSecret")
- val result = ContainerRequest().apply(response)
+ override fun getSecret(response: ContainerRequest.() -> Unit) {
+ logger.logOrder("getSecret")
+ val result = ContainerRequest().apply(response)
this.secretResult = result
- logger.log("getSecret needSecret = true, needCheck = false")
+ logger.logDebug("getSecret needSecret = true, needCheck = false")
needSecret = true
needCheck = false
userIdValue = userInfo.getCurrentUser()
- logger.log("getSecret userId = $userIdValue")
+ logger.logUserInfo("getSecret userId = $userIdValue")
getSecrets()
}
- override fun saveRefresh(refreshToken: String, response: ContainerRequest.() -> Unit) {
- val result = ContainerRequest().apply(response)
+ override fun saveRefresh(refreshToken: String, response: ContainerRequest.() -> Unit) {
+ val result = ContainerRequest().apply(response)
- this.result = ContainerRequest()
+ this.result = ContainerRequest()
.apply {
onComplete { tokenResponse ->
- logger.log("saveRefresh result.onComplete")
+ logger.logOrder("saveRefresh result.onComplete")
+ this@Refresher.refreshToken = tokenResponse.token?.refreshToken ?: ""
result(accessToken)
}
onError {
- logger.log("saveRefresh result.onError")
+ logger.logOrder("saveRefresh result.onError")
logger.logError(it)
result(it)
}
onCancel {
- logger.log("saveRefresh result.onCancel")
+ logger.logOrder("saveRefresh result.onCancel")
result()
}
}
@@ -229,19 +241,66 @@ open class Refresher, M : BaseErrorModel>(
}
}
- /*############################ Simple refresh token #########################################*/
+ override fun clearAccess() {
+ logger.logOrder("clearAccess")
+ accessToken = ""
+ refreshToken = ""
+ executor.unsubscribe()
+ }
+
+ override fun clear() {
+ logger.logOrder("clear")
+ clearAccess()
+ containerCancellationCallback = defaultCancellationCallback
+ result = ContainerRequest()
+ userIdValue = ""
+ isBiometricAvailable = false
+ needCheck = false
+ refreshExplicitly = false
+ types.clear()
+ //presentType = AuthType.NONE
+ stateIsPaused = false
+ lastAction = {}
+ currentDialog?.dismiss()
+ currentDialog = null
+ currentBiometricDialog?.cancelAuthentication()
+ currentBiometricDialog = null
+ dialogProvider.menuDialog.clear(activity.get())
+ dialogProvider.pinDialog.clear(activity.get())
+ dialogProvider.passwordDialog.clear(activity.get())
+ dialogProvider.biom.clear()
+ activity.clear()
+ forgotPasswordActionEnable = false
+ forgotPasswordAction = {}
+ }
+
+ open fun setCheckRefreshError(
+ check: Boolean = false,
+ errorStatus: String? = null,
+ useExtraCheck: Boolean = false,
+ extraCheck: (BaseErrorModel) -> Unit = {}
+ ) {
+ checkRefreshError = check
+ refresherErrorStatusToCheck = errorStatus
+ this.useExtraCheck = useExtraCheck
+ extraRefreshCheck = extraCheck
+ }
+
+ /*endregion ########################### Base functionality #########################################*/
+
+ /*region ############################ Simple refresh token #########################################*/
protected open fun refreshAccess(refreshToken: String) {
- logger.log("refreshAccess")
+ logger.logOrder("refreshAccess")
executor.refreshAccessUC(refreshToken) {
onComplete { token ->
- logger.log("refreshAccess onComplete it != null ${token != null}")
+ logger.logOrder("refreshAccess onComplete it != null ${token != null}")
if (token != null) {
result(RefreshResult(token = token))
}
}
onError { error ->
- logger.log("refreshAccess onError error = $error")
+ logger.logOrder("refreshAccess onError error = $error")
if (checkRefreshError) {
checkRefreshError(error)
} else {
@@ -252,6 +311,7 @@ open class Refresher, M : BaseErrorModel>(
}
protected open fun checkRefreshError(error: M) {
+ logger.logOrder("checkRefreshError")
if (useExtraCheck) {
extraRefreshCheck(error)
} else {
@@ -263,105 +323,128 @@ open class Refresher, M : BaseErrorModel>(
}
}
- /*############################# Simple refresh token END ####################################*/
+ /*endregion ############################# Simple refresh token END ####################################*/
- /*############################# Refresh token with dialogs ##################################*/
+ /*region ############################# Refresh token with dialogs ##################################*/
protected open fun getSecrets() {
- logger.log("getSecrets")
+ logger.logOrder("getSecrets")
types.clear()
executor.getSecretsUC {
onComplete {
- logger.log("getSecrets onComplete types not empty = ${it.isNotEmpty()}")
+ logger.logOrder("getSecrets onComplete types not empty = ${it.isNotEmpty()}")
if (it.isNotEmpty()) {
doWhenHasSecrets(it)
} else {
if (needSecret)
- secretResult(supporter.util.createErrorModel(0, ErrorStatusEnum.HAS_NO_SECRETS.name))
+ secretResult(mapper(0, ErrorStatusEnum.HAS_NO_SECRETS.name))
else
showPasswordDialog()
}
}
onError { throwable ->
- logger.log("getSecrets onError")
+ logger.logOrder("getSecrets onError")
result(throwable)
}
}
}
+ protected fun showDialogForType(type: AuthType) {
+ when (type) {
+ AuthType.PIN_AUTH -> {
+ showDecryptPinDialog()
+ }
+ AuthType.BIOMETRIC_AUTH -> {
+ showDecryptBiometricDialog()
+ }
+ AuthType.NONE -> {
+ showPasswordDialog()
+ }
+ }
+ }
+
protected open fun doWhenHasSecrets(list: List) {
+ types.clear()
types.addAll(list)
- logger.log("getSecrets onComplete onlyOnePresent = ${list.size == 1}")
+ logger.logOrder("getSecrets onComplete onlyOnePresent = ${list.size == 1}")
val preferred = typeManager.getPreferredType()
- logger.log("getSecrets onComplete preferred = $preferred")
- if (preferred == AuthType.NONE || types.contains(preferred)) {
- when (preferred) {
- AuthType.PIN_AUTH -> {
- showDecryptPinDialog()
- }
- AuthType.BIOMETRIC_AUTH -> {
- showDecryptBiometricDialog()
- }
- AuthType.NONE -> {
- if (needSecret) {
- secretResult(
- supporter.util.createErrorModel(0, ErrorStatusEnum.HAS_NO_SECRETS.name)
- )
- } else {
- showPasswordDialog()
- }
- }
+ logger.logDebug("getSecrets onComplete preferred = $preferred")
+
+ if (!needSecret) {
+ //needSecret != true
+ if (preferred == AuthType.NONE || list.contains(preferred)) {
+ showDialogForType(preferred)
+ } else if (list.size > 1 || !list.contains(AuthType.NONE)) {
+ //FIX
+ //keep in mind that list can not be empty
+ showAuthDialog(isDecrypting = true)
+ } else {
+ showDialogForType(list[0])
}
} else {
- showAuthDialog(isDecrypting = true)
+ //needSecret == true
+ if (preferred != AuthType.NONE && list.contains(preferred)) {
+ //preferred is not NONE and List contains preferred
+ showDialogForType(preferred)
+ } else {
+ //preferred is NONE or list does not contain preferred
+ val filtered = list.filter { it != AuthType.NONE }
+ if (filtered.isEmpty()) {
+ secretResult(mapper(0, ErrorStatusEnum.HAS_NO_SECRETS.name))
+ } else if (filtered.size == 1) {
+ showDialogForType(filtered[0])
+ } else {
+ showAuthDialog(isDecrypting = true)
+ }
+ }
}
}
-/*############################# Refresh token with dialogs END ##############################*/
+ /*endregion ############################# Refresh token with dialogs END ##############################*/
-/*############################# Check access with dialogs ###################################*/
+ /*region ############################# Check access with dialogs ###################################*/
protected open fun checkSecret(pinKey: SecretKey? = null, cipher: Cipher? = null) {
- logger.log("checkSecret pinKey!=null ${pinKey != null}, cipher!=null ${cipher != null}")
+ logger.logOrder("checkSecret pinKey!=null ${pinKey != null}, cipher!=null ${cipher != null}")
executor.checkSecretUC(pinKey, cipher) {
onComplete {
- logger.log("checkSecret onComplete ${it.first}")
+ logger.logOrder("checkSecret onComplete ${it.first}")
if (it.first) {
when {
needSecret -> secretResult(it.second)
refreshExplicitly -> {
- logger.log("checkSecret onComplete refreshToken != null")
+ logger.logDebug("checkSecret onComplete refreshToken != null")
refreshWithSecret(it.second)
}
else -> {
- logger.log("checkSecret onComplete return")
+ logger.logDebug("checkSecret onComplete return")
result(RefreshResult())
}
}
} else {
- logger.log("checkSecret onComplete failed check return error SECRET_CHECK_NOT_MATCH")
- val error = supporter.util.createErrorModel(0, ErrorStatusEnum.SECRET_CHECK_NOT_MATCH.name)
+ logger.logDebug("checkSecret onComplete failed check return error SECRET_CHECK_NOT_MATCH")
+ val error = mapper(0, ErrorStatusEnum.SECRET_CHECK_NOT_MATCH.name)
if (needSecret) secretResult(error)
else result(error)
}
}
onError { error ->
- logger.log("checkSecret onError")
+ logger.logOrder("checkSecret onError")
result(error)
}
}
}
protected open fun refreshWithSecret(secret: String) {
- logger.log("refreshWithSecret")
+ logger.logOrder("refreshWithSecret")
executor.refreshWithSecretUC(secret) {
onComplete { token ->
- logger.log("refreshWithSecret onComplete")
+ logger.logOrder("refreshWithSecret onComplete")
result(RefreshResult(token))
}
onError { error ->
- logger.log("refreshWithSecret onError")
+ logger.logOrder("refreshWithSecret onError")
if (checkRefreshError) {
checkRefreshError(error)
} else {
@@ -371,17 +454,17 @@ open class Refresher, M : BaseErrorModel>(
}
}
-/*############################## Check access with dialogs END ##############################*/
+ /*endregion ############################## Check access with dialogs END ##############################*/
- /*############################### Authentication with password ##############################*/
+ /*region ############################### Authentication with password ##############################*/
protected open fun authenticate(password: String, recreate: Boolean, noSecrets: Boolean) {
- logger.log("authenticate password not blank = ${password.isNotBlank()}; recreate = $recreate; noSecrets = $noSecrets")
+ logger.logOrder("authenticate password not blank = ${password.isNotBlank()}; recreate = $recreate; noSecrets = $noSecrets")
if (password.isNotBlank()) {
executor.authorizationInSystemUC(password) {
onComplete { token ->
- logger.log("authenticate onComplete it.refreshToken != null ${token.refreshToken != null}")
+ logger.logOrder("authenticate onComplete it.refreshToken != null ${token.refreshToken != null}")
if (token.refreshToken != null) {
- logger.log("authenticate onComplete isBiometricAvailable $isBiometricAvailable")
+ logger.logDebug("authenticate onComplete isBiometricAvailable $isBiometricAvailable")
if (recreate) {
if (isBiometricAvailable) {
@@ -393,187 +476,207 @@ open class Refresher, M : BaseErrorModel>(
result(RefreshResult(token))
}
} else {
- logger.log("authenticate onComplete return")
+ logger.logDebug("authenticate onComplete return")
result(RefreshResult(token))
}
}
onError { error ->
- logger.log("authenticate onError")
+ logger.logOrder("authenticate onError")
result(error)
}
}
} else {
- logger.log("authenticate showPasswordDialog")
+ logger.logDebug("authenticate showPasswordDialog")
showPasswordDialog(noSecrets)
}
}
protected open fun putSecrets(token: Token, cipher: Cipher? = null, pinKey: SecretKey? = null) {
- logger.log("putSecrets pinKey!=null ${pinKey != null}, cipher!=null ${cipher != null}")
+ logger.logOrder("putSecrets pinKey!=null ${pinKey != null}, cipher!=null ${cipher != null}")
executor.createSecretUC(token.refreshToken!!, cipher, pinKey) {
onComplete {
- logger.log("putSecrets onComplete return")
+ logger.logOrder("putSecrets onComplete return")
result(RefreshResult(token))
}
onError {
- logger.log("putSecrets onError return")
+ logger.logOrder("putSecrets onError return")
logger.showMessage("Secret was not saved") //todo show message secret was not create
result(RefreshResult(token))
}
}
}
-/*############################## Authentication with password END ###########################*/
+ /*endregion ############################## Authentication with password END ###########################*/
-/*############################### Dialogs ###################################################*/
+ /*############################### Dialogs ###################################################*/
+
+ /*region ############################### Menu dialog ##############################################*/
protected open fun showAuthDialog(isDecrypting: Boolean, token: Token? = null) {
- logger.log("showAuthDialog isDecrypting ${isDecrypting}, token!=null = ${token != null}")
+ logger.logOrder("showAuthDialog isDecrypting ${isDecrypting}, token!=null = ${token != null}")
dialogProvider.menuDialog.let { dialog ->
dialog.createDialog()
- dialog.setStateActions({ e ->
- logger.log("showAuthDialog onError ${e.message}")
- if (needSecret) secretResult(mapper(e))
- else result(mapper(e))
- }, { afterOk ->
- logger.log("showAuthDialog onDismiss afterOk=${afterOk}")
- if (!afterOk) {
- if (needSecret) secretResult()
- else result()
- }
- })
- dialog.isDecrypting(isDecrypting)
- dialog.showPassword(!needSecret)
- dialog.setCallBacks({
- logger.log("showAuthDialog onPinClick")
- if (isDecrypting) showDecryptPinDialog()
- else token?.let { showEncryptPinDialog(token) }
- }, {
- logger.log("showAuthDialog onBiometricClick")
- if (isDecrypting) showDecryptBiometricDialog()
- else token?.let { showEncryptBiometricDialog(token) }
- }, {
- logger.log("showAuthDialog onPasswordClick")
- showPasswordDialog()
- })
-
- val titleRes: Int = if (isDecrypting) -1 else supporter.resProvider.provideEncryptTitle()
- dialog.setTitle(titleRes)
+ //setup menu dialog parameters
+ val showPin: Boolean
+ val showBiom: Boolean
if (isDecrypting) {
- dialog.setPinPresent(types.contains(AuthType.PIN_AUTH))
- dialog.setBiometricPresent(types.contains(AuthType.BIOMETRIC_AUTH))
+ showPin = types.contains(AuthType.PIN_AUTH)
+ showBiom = types.contains(AuthType.BIOMETRIC_AUTH)
} else {
- dialog.setPinPresent(true)
- dialog.setBiometricPresent(isBiometricAvailable)
+ showPin = true
+ showBiom = isBiometricAvailable
}
+ dialog.setupParameterBundle(
+ isDecrypting = isDecrypting,
+ showPassword = !needSecret,
+ showPin = showPin,
+ showBiom = showBiom
+ )
+
+ //setup menu dialog result handler
+ dialog.setupResultHandler(provideMenuResultHandler(isDecrypting, token))
+
+ val titleRes: Int = if (isDecrypting) -1 else supporter.resProvider.provideEncryptTitle()
+ dialog.setTitle(titleRes)
showDialog(dialog.getDialog(), "OperatorAuthDialog")
}
}
- /*######################## PIN ##########################*/
+ protected open fun provideMenuResultHandler(
+ decrypting: Boolean,
+ accessToken: Token?
+ ): MenuResultHandler {
+ return object : MenuResultHandler(decrypting, accessToken) {
+ override fun onCancel() {
+ logger.logOrder("showAuthDialog onCancel")
+ if (needSecret) secretResult()
+ else result()
+ }
+
+ override fun onPinClick() {
+ logger.logOrder("showAuthDialog onPinClick")
+ if (this.decrypting) showDecryptPinDialog()
+ else this.accessToken?.let { showEncryptPinDialog(it) }
+ }
+
+ override fun onPasswordClick() {
+ logger.logOrder("showAuthDialog onPasswordClick")
+ showPasswordDialog()
+ }
+
+ override fun onBiomClick() {
+ if (this.decrypting) showDecryptBiometricDialog()
+ else this.accessToken?.let { showEncryptBiometricDialog(it) }
+ }
+ }
+ }
+
+ /*endregion ############################### Menu dialog ##############################################*/
+
+ /*region ######################## PIN ##########################*/
+
protected open fun showDecryptPinDialog() {
- logger.log("showDecryptPinDialog")
+ logger.logOrder("showDecryptPinDialog")
dialogProvider.pinDialog.let { dialog ->
dialog.createDialog()
- dialog.setStateActions({ e ->
- logger.log("showDecryptPinDialog onError ${e.message}")
- if (needSecret) secretResult(mapper(e))
- else result(mapper(e))
- }, { afterOk ->
- logger.log("showDecryptPinDialog onDismiss afterOk=$afterOk")
- if (!afterOk) {
- if (needSecret) secretResult()
- else result()
- }
- })
- dialog.setCallbacks({ pin ->
- logger.log("showDecryptPinDialog onPinComplete needCheck=$needCheck")
- val pinKey = supporter.util.generatePin(
- pin, userIdValue,
- Settings.Secure.getString(activity.get()?.contentResolver, Settings.Secure.ANDROID_ID)
- )
- typeManager.putPreferredType(AuthType.PIN_AUTH)
- //if (needCheck) {
- checkSecret(pinKey = pinKey)
- /*} else {
- refreshWithSecret(pinKey = pinKey)
- }*/
- }, {
- logger.log("showDecryptPinDialog onPinCanceled showAuthDialog(isDecrypting = true)")
- showAuthDialog(isDecrypting = true)
- })
+ val cancelId = supporter.resProvider.provideAlterCancelStr()
+ val hasAnother = if (needSecret) types.size > 1 else true
+ dialog.setupParameterBundle(cancelId, cancelId, false, hasAnother)
+
+ dialog.setupResultHandler(provideDecryptingPinHandler())
- logger.log("showDecryptPinDialog needCheck=$needCheck")
+ logger.logDebug("showDecryptPinDialog needCheck=$needCheck")
if (needCheck)
dialog.setTitle(supporter.resProvider.provideAccessConfirmStr())
else
dialog.setTitle(supporter.resProvider.provideAccessStr())
- val cancelId = supporter.resProvider.provideAlterCancelStr()
- dialog.setCancelTitle(cancelId)
- dialog.setCancellable(false)
- if (needSecret) dialog.setHasAnother(types.size > 1)
- else dialog.setHasAnother(true)
showDialog(dialog.getDialog(), "OperatorPinDecryptDialog")
}
}
protected open fun showEncryptPinDialog(token: Token) {
- logger.log("showEncryptPinDialog")
+ logger.logOrder("showEncryptPinDialog")
dialogProvider.pinDialog.let { dialog ->
dialog.createDialog()
- dialog.setStateActions({ e ->
- logger.log("showDecryptPinDialog onError ${e.message}")
- result(mapper(e))
- }, { afterOk ->
- logger.log("showEncryptPinDialog onDismiss afterOk=$afterOk")
- if (!afterOk) {
- result(
- RefreshResult(
- token
- )
- )
- }
- })
- dialog.setCallbacks({ pin ->
- logger.log("showEncryptPinDialog onPinComplete preferredType=PIN_AUTH")
+
+ logger.logDebug("showEncryptPinDialog isBiometricAvailable=$isBiometricAvailable")
+ val cancelId = if (isBiometricAvailable) supporter.resProvider.provideAlterCancelStr() else -1
+ dialog.setupParameterBundle(cancelId, cancelId, false, isBiometricAvailable)
+
+ dialog.setupResultHandler(provideEncryptingPinHandler(token))
+
+ dialog.setTitle(supporter.resProvider.provideEncryptTitle())
+ showDialog(dialog.getDialog(), "OperatorPinEncryptDialog")
+ }
+ }
+
+ protected open fun provideDecryptingPinHandler(): PinResultHandler {
+ return object : PinResultHandler(null) {
+ override fun onCancel() {
+ if (needSecret) secretResult()
+ else result()
+ }
+
+ override fun onAnotherClicked() {
+ logger.logOrder("showDecryptPinDialog onPinCanceled showAuthDialog(isDecrypting = true)")
+ showAuthDialog(isDecrypting = true)
+ }
+
+ override fun onComplete(pin: String) {
+ logger.logOrder("showDecryptPinDialog onPinComplete needCheck=$needCheck")
val pinKey = supporter.util.generatePin(
pin, userIdValue,
Settings.Secure.getString(activity.get()?.contentResolver, Settings.Secure.ANDROID_ID)
)
typeManager.putPreferredType(AuthType.PIN_AUTH)
- putSecrets(token = token, pinKey = pinKey)
- }, {
- logger.log("showEncryptPinDialog onPinCanceled showAuthDialog(isDecrypting = false)")
- showAuthDialog(isDecrypting = false, token = token)
- })
+ checkSecret(pinKey = pinKey)
+ }
+ }
+ }
- dialog.setTitle(supporter.resProvider.provideEncryptTitle())
- logger.log("showEncryptPinDialog isBiometricAvailable=$isBiometricAvailable")
- val cancelId = if (isBiometricAvailable) supporter.resProvider.provideAlterCancelStr() else -1
- dialog.setCancelTitle(cancelId)
- dialog.setCancellable(false)
- showDialog(dialog.getDialog(), "OperatorPinEncryptDialog")
+ protected open fun provideEncryptingPinHandler(token: Token): PinResultHandler {
+ return object : PinResultHandler(token) {
+ override fun onCancel() {
+ result(RefreshResult(this.token))
+ }
+
+ override fun onAnotherClicked() {
+ logger.logOrder("showEncryptPinDialog onPinCanceled showAuthDialog(isDecrypting = false)")
+ showAuthDialog(isDecrypting = false, token = this.token)
+ }
+
+ override fun onComplete(pin: String) {
+ logger.logOrder("showEncryptPinDialog onPinComplete preferredType=PIN_AUTH")
+ val pinKey = supporter.util.generatePin(
+ pin, userIdValue,
+ Settings.Secure.getString(activity.get()?.contentResolver, Settings.Secure.ANDROID_ID)
+ )
+ typeManager.putPreferredType(AuthType.PIN_AUTH)
+ this.token?.let { putSecrets(token = it, pinKey = pinKey) }
+ }
}
}
-/*######################## PIN END #####################*/
+ /*endregion######################## PIN END #####################*/
-/*###################### Biometric ######################*/
+ /*region ###################### Biometric ######################*/
protected open fun showDecryptBiometricDialog() {
- logger.log("showDecryptBiometricDialog")
+ logger.logOrder("showDecryptBiometricDialog")
dialogProvider.biom.let { dialog ->
activity.get()?.let { context ->
- logger.log("showDecryptBiometricDialog activity let")
+ logger.logDebug("showDecryptBiometricDialog activity let")
dialog.onAuthenticationCallback({ isCancelled, errString ->
+ logger.logOrder("Decrypt biometric dialog onAuthenticationCallback onError")
+ logger.logDebug("onError isCancelled=$isCancelled errString=$errString")
context.runOnUiThread {
if (isCancelled) {//Операция с отпечатком отменена. on pause
- logger.log("$errString isPaused = $stateIsPaused")
+ logger.logDebug("$errString isPaused = $stateIsPaused")
if (!stateIsPaused) { // somehow dialog set error_canceled after resume if it was unblocked not with finger
- logger.log("Show decrypt biometric dialog again")
+ logger.logDebug("Show decrypt biometric dialog again")
showDecryptBiometricDialog()
} else {
- logger.log("Set last action to show decrypt biometric dialog")
+ logger.logDebug("Set last action to show decrypt biometric dialog")
lastAction = { showDecryptBiometricDialog() }
}
} else {
@@ -586,9 +689,9 @@ open class Refresher, M : BaseErrorModel>(
}
}
}, { cipher ->
- logger.log("DecryptBiometricDialog preferredType BIOMETRIC_AUTH")
+ logger.logOrder("DecryptBiometricDialog preferredType BIOMETRIC_AUTH")
typeManager.putPreferredType(AuthType.BIOMETRIC_AUTH)
- logger.log("DecryptBiometricDialog needCheck $needCheck")
+ logger.logDebug("DecryptBiometricDialog needCheck $needCheck")
//if (needCheck) {
checkSecret(cipher = cipher)
/*} else {
@@ -596,7 +699,7 @@ open class Refresher, M : BaseErrorModel>(
}*/
})
- logger.log("showDecryptBiometricDialog needCheck=$needCheck")
+ logger.logDebug("showDecryptBiometricDialog needCheck=$needCheck")
dialog.create(context, userInfo)
val title: String = supporter.resProvider.getString(
@@ -614,16 +717,16 @@ open class Refresher, M : BaseErrorModel>(
dialog.setInfo(title = title, negativeText = negativeText)
lastAction = {
- logger.log("showDecryptBiometricDialog lastAction DECRYPT_MODE")
+ logger.logOrder("showDecryptBiometricDialog lastAction DECRYPT_MODE")
try {
currentBiometricDialog = dialog.authenticate(isDecrypt = true)
} catch (e: Exception) {
- logger.log("showDecryptBiometricDialog catch exception")
+ logger.logOrder("showDecryptBiometricDialog catch exception")
logger.logError(e)
deleteBiometricType()
}
}
- logger.log("showDecryptBiometricDialog stateIsPaused=$stateIsPaused")
+ logger.logDebug("showDecryptBiometricDialog stateIsPaused=$stateIsPaused")
if (!stateIsPaused) {
lastAction.invoke()
lastAction = {}
@@ -633,23 +736,25 @@ open class Refresher, M : BaseErrorModel>(
}
protected open fun showEncryptBiometricDialog(token: Token) {
- logger.log("showEncryptBiometricDialog")
+ logger.logOrder("showEncryptBiometricDialog")
dialogProvider.biom.let { dialog ->
activity.get()?.let { context ->
- logger.log("showDecryptBiometricDialog activity let")
+ logger.logOrder("showDecryptBiometricDialog activity let")
dialog.onAuthenticationCallback({ isCancelled, errString ->
+ logger.logOrder("Encrypt biometric dialog onAuthenticationCallback onError")
+ logger.logDebug("onError isCancelled=$isCancelled errString=$errString")
context.runOnUiThread {
if (isCancelled) {//Операция с отпечатком отменена. on pause
- logger.log("showEncryptBiometricDialog ERROR_CANCELED")
+ logger.logDebug("showEncryptBiometricDialog ERROR_CANCELED")
lastAction = { showEncryptBiometricDialog(token) }
} else {
- logger.log("showEncryptBiometricDialog showAuthDialog(isDecrypting = false,token)")
+ logger.logDebug("showEncryptBiometricDialog showAuthDialog(isDecrypting = false,token)")
showAuthDialog(isDecrypting = false, token = token)
}
}
}, { cipher ->
- logger.log("EncryptBiometricDialog Success preferredType BIOMETRIC_AUTH")
+ logger.logOrder("EncryptBiometricDialog Success preferredType BIOMETRIC_AUTH")
typeManager.putPreferredType(AuthType.BIOMETRIC_AUTH)
putSecrets(token = token, cipher = cipher)
})
@@ -659,13 +764,13 @@ open class Refresher, M : BaseErrorModel>(
val title: String = supporter.resProvider.getString(supporter.resProvider.provideEncryptTitle())
val negativeText = supporter.resProvider.getString(supporter.resProvider.provideAlterCancelStr())
dialog.setInfo(title, negativeText)
- logger.log("showEncryptBiometricDialog stateIsPaused=$stateIsPaused")
+ logger.logDebug("showEncryptBiometricDialog stateIsPaused=$stateIsPaused")
lastAction = {
- logger.log("showEncryptBiometricDialog lastAction ENCRYPT_MODE")
+ logger.logOrder("showEncryptBiometricDialog lastAction ENCRYPT_MODE")
try {
currentBiometricDialog = dialog.authenticate(isDecrypt = false)
} catch (e: Exception) {
- logger.log("showEncryptBiometricDialog catch exception")
+ logger.logOrder("showEncryptBiometricDialog catch exception")
logger.logError(e)
isBiometricAvailable = false
showEncryptPinDialog(token)
@@ -679,74 +784,72 @@ open class Refresher, M : BaseErrorModel>(
}
}
-/*#################### Biometric END ####################*/
-
+/*endregion #################### Biometric END ####################*/
-/*##################### Password ########################*/
+ /*region ##################### Password ########################*/
protected open fun showPasswordDialog(noSecrets: Boolean = false) {
- logger.log("showPasswordDialog")
+ logger.logOrder("showPasswordDialog")
dialogProvider.passwordDialog.let { dialog ->
dialog.createDialog()
- dialog.setStateActions({ e: Exception ->
- logger.log("showPasswordDialog onError ${e.message}")
- result(mapper(e))
- }, { afterOk: Boolean ->
- logger.log("showPasswordDialog onDismiss afterOk=$afterOk, types not empty=${types.isNotEmpty()}")
- if (!afterOk) {
- if (!noSecrets && types.isNotEmpty()) {
- showAuthDialog(isDecrypting = true)
- } else {
- result()
- }
- }
- /*if (!afterOk && types.isNotEmpty()) {
- showAuthDialog(isDecrypting = true)
- } else if (!afterOk && types.isEmpty()) {
- result()
- }*/
- })
- logger.log("showPasswordDialog types not empty=${types.isNotEmpty()}")
- if (!noSecrets && types.isNotEmpty()) {
- dialog.setCancelTitle(supporter.resProvider.provideAlterCancelStr())
- dialog.setShowRecreateAuth(true)
- }
- logger.log("showPasswordDialog forgotPasswordActionEnable=$forgotPasswordActionEnable")
- dialog.setForgotPassword(forgotPasswordActionEnable)
- logger.log("showPasswordDialog needCheck=$needCheck")
+ logger.logDebug("showPasswordDialog types not empty=${types.isNotEmpty()}")
+ logger.logDebug("showPasswordDialog forgotPasswordActionEnable=$forgotPasswordActionEnable")
+ dialog.setupParameterBundle(
+ cancelBtnRes = supporter.resProvider.provideCancelStr(),
+ anotherBtnRes = supporter.resProvider.provideAlterCancelStr(),
+ isCancellable = true,
+ showAnother = !noSecrets && types.isNotEmpty(),
+ forgotPasswordActionEnable = forgotPasswordActionEnable
+ )
+ dialog.setupResultHandler(providePasswordHandler(noSecrets))
+
+ logger.logDebug("showPasswordDialog needCheck=$needCheck")
if (needCheck)
dialog.setTitle(supporter.resProvider.provideAccessConfirmStr())
else
dialog.setTitle(supporter.resProvider.provideAccessStr())
- dialog.setCallbacks({ password: String, recreate: Boolean ->
- logger.log("showPasswordDialog onPasswordComplete")
- authenticate(password, recreate, noSecrets)
- }, {
- logger.log("showPasswordDialog onPasswordForgot forgotPasswordActionEnable=$forgotPasswordActionEnable")
- if (forgotPasswordActionEnable)
- forgotPasswordAction()
- })
showDialog(dialog.getDialog(), "PasswordDialog")
}
}
+ protected open fun providePasswordHandler(noSecrets: Boolean): PasswordResultHandler =
+ object : PasswordResultHandler(noSecrets) {
+ override fun onCancel() {
+ result()
+ }
-/*##################### Password END ####################*/
+ override fun onComplete(password: String, recreate: Boolean) {
+ logger.logOrder("showPasswordDialog onPasswordComplete")
+ authenticate(password, recreate, this.noSecrets)
+ }
-/*################################## Dialogs END ############################################*/
+ override fun onForgotClicked() {
+ logger.logOrder("showPasswordDialog onPasswordForgot forgotPasswordActionEnable=$forgotPasswordActionEnable")
+ if (forgotPasswordActionEnable)
+ forgotPasswordAction()
+ }
-/*################################## Common #################################################*/
+ override fun onAnotherClicked() {
+ showAuthDialog(isDecrypting = true)
+ }
+ }
+
+ /*endregion ##################### Password END ####################*/
+
+ /*################################## Dialogs END ############################################*/
+
+ /*region ################################## Common #################################################*/
protected open fun showDialog(dialog: IBaseDialog, tag: String) {
- logger.log("showDialog $tag stateIsPaused=$stateIsPaused")
+ logger.logOrder("showDialog $tag stateIsPaused=$stateIsPaused")
lastAction = {
- logger.log("showDialog lastAction invoke")
- val manager = fragmentManager.get()
+ logger.logOrder("showDialog lastAction invoke")
+ //val manager = fragmentManager.get()
val context = activity.get()
- logger.log("showDialog lastAction fragmentManager != null ${manager != null} context != null ${context != null}")
+ logger.logDebug("showDialog lastAction fragmentManager != null {manager != null} context != null ${context != null}")
currentDialog = dialog
- dialog.show(manager, context, tag)
+ dialog.show(context, tag)
}
if (!stateIsPaused) {
lastAction.invoke()
@@ -755,132 +858,76 @@ open class Refresher, M : BaseErrorModel>(
}
protected open fun deleteBiometricType() {
- logger.log("deleteBiometricType BIOMETRIC_AUTH")
+ logger.logOrder("deleteBiometricType BIOMETRIC_AUTH")
executor.deleteSecretTypeUC(AuthType.BIOMETRIC_AUTH) {
onComplete {
- logger.log("deleteBiometricType $it")
+ logger.logOrder("deleteBiometricType $it")
if (it) {
types.remove(AuthType.BIOMETRIC_AUTH)
if (types.isEmpty()) {
val presentType = AuthType.NONE
- logger.log("deleteBiometricType containsSecrets = false presentType=NONE")
+ logger.logDebug("deleteBiometricType containsSecrets = false presentType=NONE")
showPasswordDialog()
} else {
val presentType = types.firstOrNull() ?: AuthType.NONE
typeManager.putPreferredType(presentType)
- logger.log("deleteBiometricType presentType=$presentType")
+ logger.logDebug("deleteBiometricType presentType=$presentType")
showAuthDialog(isDecrypting = true)
}
}
}
onError {
logger.logError(it)
- logger.log("deleteBiometricType showAuthDialog(isDecrypting = true)")
+ logger.logOrder("deleteBiometricType showAuthDialog(isDecrypting = true)")
showAuthDialog(isDecrypting = true)
}
}
}
-/*#################################### Common END ###########################################*/
+ /*endregion #################################### Common END ###########################################*/
-/*############################## Settings ###################################################*/
+ /*region ############################## Settings ###################################################*/
/**
* Установка Activity необходимая для работы диалогов
*
* @param activity FragmentActivity
*/
override fun setActivity(activity: FragmentActivity) {
- logger.log("setActivity")
+ logger.logOrder("setActivity")
this.activity = WeakReference(activity)
activity.lifecycle.addObserver(object : LifecycleObserver {
+ //FIX
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun doAfterResume() {
- logger.log("activity LifecycleObserver doAfterResume")
+ logger.logOrder("activity LifecycleObserver doAfterResume")
stateIsPaused = false
lastAction.invoke()
lastAction = {}
}
+ //FIX
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun doAfterPause() {
- logger.log("activity LifecycleObserver doAfterPause")
+ logger.logOrder("activity LifecycleObserver doAfterPause")
stateIsPaused = true
}
})
isBiometricAvailable =
supporter.util.checkBiometricSupport(activity.applicationContext) { tag: String, msg: String ->
- logger.log(tag, msg)
+ logger.logCategory(CATEGORY_ERROR, tag, msg)
}
- logger.log("setActivity isBiometricAvailable=$isBiometricAvailable")
+ logger.logDebug("setActivity isBiometricAvailable=$isBiometricAvailable")
}
override fun setForgotPasswordAction(enable: Boolean, forgotPasswordAction: () -> Unit) {
- logger.log("setForgotPasswordAction enable=$enable")
+ logger.logOrder("setForgotPasswordAction enable=$enable")
this.forgotPasswordActionEnable = enable
this.forgotPasswordAction = if (enable) forgotPasswordAction else ({})
}
- /**
- * Установка Params необходимая для работы диалогов
- *
- * @param root ViewGroup
- * @param manager FragmentManager
- */
- override fun setParams(manager: FragmentManager) {
- logger.log("setParams")
- fragmentManager = WeakReference(manager)
- }
-
override fun setCancellationCallback(callback: IContainerCancellationCallback) {
- logger.log("setCancellationCallback")
+ logger.logOrder("setCancellationCallback")
containerCancellationCallback = callback
}
-/*############################## Settings END ###############################################*/
-
- override fun clearAccess() {
- logger.log("clearAccess")
- accessToken = ""
- refreshToken = ""
- executor.unsubscribe()
- }
-
- override fun clear() {
- logger.log("clear")
- clearAccess()
- activity.clear()
- fragmentManager.clear()
- containerCancellationCallback = defaultCancellationCallback
- result = ContainerRequest()
- userIdValue = ""
- isBiometricAvailable = false
- needCheck = false
- refreshExplicitly = false
- types.clear()
- //presentType = AuthType.NONE
- stateIsPaused = false
- lastAction = {}
- currentDialog?.dismiss()
- currentDialog = null
- currentBiometricDialog?.cancelAuthentication()
- currentBiometricDialog = null
- dialogProvider.menuDialog.clear()
- dialogProvider.pinDialog.clear()
- dialogProvider.passwordDialog.clear()
- dialogProvider.biom.clear()
- forgotPasswordActionEnable = false
- forgotPasswordAction = {}
- }
-
- open fun setCheckRefreshError(
- check: Boolean = false,
- errorStatus: E? = null,
- useExtraCheck: Boolean = false,
- extraCheck: (BaseErrorModel) -> Unit = {}
- ) {
- checkRefreshError = check
- refresherErrorStatusToCheck = errorStatus
- this.useExtraCheck = useExtraCheck
- extraRefreshCheck = extraCheck
- }
-
+ /*endregion ############################## Settings END ###############################################*/
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/BiometricUserInfo.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/BiometricUserInfo.kt
index 11cd9304..812329ef 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/BiometricUserInfo.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/BiometricUserInfo.kt
@@ -6,7 +6,8 @@
package by.esas.tools.accesscontainer.dialog
interface BiometricUserInfo {
- fun getCurrentUser(): String
- fun setCurrentUserIv(iv: ByteArray)
- fun getCurrentUserIv(): ByteArray
- }
\ No newline at end of file
+
+ fun getCurrentUser(): String
+ fun setCurrentUserIv(iv: ByteArray)
+ fun getCurrentUserIv(): ByteArray
+}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/DialogProvider.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/DialogProvider.kt
index 0defd58c..b95abec4 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/DialogProvider.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/DialogProvider.kt
@@ -5,21 +5,23 @@
package by.esas.tools.accesscontainer.dialog
+import androidx.fragment.app.FragmentActivity
import by.esas.tools.accesscontainer.dialog.setters.MenuDialogSetter
import by.esas.tools.accesscontainer.dialog.setters.SetBiometricDialog
import by.esas.tools.accesscontainer.dialog.setters.SetPasswordDialog
import by.esas.tools.accesscontainer.dialog.setters.SetPinDialog
abstract class DialogProvider {
+
abstract val passwordDialog: SetPasswordDialog
abstract val menuDialog: MenuDialogSetter
abstract val pinDialog: SetPinDialog
abstract val biom: SetBiometricDialog
- fun clear() {
- passwordDialog.clear()
- menuDialog.clear()
- pinDialog.clear()
+ fun clear(context: FragmentActivity?) {
+ passwordDialog.clear(context)
+ menuDialog.clear(context)
+ pinDialog.clear(context)
biom.clear()
}
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/IBaseDialog.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/IBaseDialog.kt
index 91488fa5..21a83cae 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/IBaseDialog.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/IBaseDialog.kt
@@ -5,10 +5,12 @@
package by.esas.tools.accesscontainer.dialog
-import android.content.Context
-import androidx.fragment.app.FragmentManager
+import androidx.fragment.app.FragmentActivity
+import androidx.fragment.app.FragmentResultListener
interface IBaseDialog {
+
fun dismiss()
- fun show(manager: FragmentManager?, context: Context?, tag: String)
+ fun show(context: FragmentActivity?, tag: String)
+ fun provideResultListener(tag: String): FragmentResultListener
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/IBiometric.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/IBiometric.kt
index 83e50153..2c5c47c1 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/IBiometric.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/IBiometric.kt
@@ -6,6 +6,7 @@
package by.esas.tools.accesscontainer.dialog
interface IBiometric {
+
fun cancelAuthentication()
//fun authenticate(isDecrypt: Boolean, title: String, negativeText: String): IBiometric?
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/IDialogSetter.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/IDialogSetter.kt
index 2a6c2604..e3589ce4 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/IDialogSetter.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/IDialogSetter.kt
@@ -5,14 +5,13 @@
package by.esas.tools.accesscontainer.dialog.setters
+import androidx.fragment.app.FragmentActivity
import by.esas.tools.accesscontainer.dialog.IBaseDialog
interface IDialogSetter {
+
fun createDialog()
fun getDialog(): IBaseDialog
- fun setStateActions(error: (Exception) -> Unit, dismiss: (Boolean) -> Unit)
-
fun setTitle(titleRes: Int)
-
- fun clear()
+ fun clear(context: FragmentActivity?)
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/MenuDialogSetter.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/MenuDialogSetter.kt
index c2abf5ed..81c04c6d 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/MenuDialogSetter.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/MenuDialogSetter.kt
@@ -5,11 +5,8 @@
package by.esas.tools.accesscontainer.dialog.setters
-interface MenuDialogSetter :
- IDialogSetter {
- fun isDecrypting(decrypting: Boolean)
- fun setCallBacks(pin: () -> Unit?, biom: () -> Unit?, password: () -> Unit?)
- fun showPassword(value: Boolean)
- fun setPinPresent(present: Boolean)
- fun setBiometricPresent(present: Boolean)
+interface MenuDialogSetter : IDialogSetter {
+
+ fun setupParameterBundle(isDecrypting: Boolean, showPassword: Boolean, showPin: Boolean, showBiom: Boolean)
+ fun setupResultHandler(handler: MenuResultHandler)
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/MenuResultHandler.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/MenuResultHandler.kt
new file mode 100644
index 00000000..070246fe
--- /dev/null
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/MenuResultHandler.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2022 Electronic Systems And Services Ltd.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package by.esas.tools.accesscontainer.dialog.setters
+
+import by.esas.tools.accesscontainer.entity.Token
+
+abstract class MenuResultHandler(
+ protected val decrypting: Boolean,
+ protected val accessToken: Token?
+) {
+
+ abstract fun onCancel()
+ abstract fun onPinClick()
+ abstract fun onPasswordClick()
+ abstract fun onBiomClick()
+}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/PasswordResultHandler.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/PasswordResultHandler.kt
new file mode 100644
index 00000000..fb21ac88
--- /dev/null
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/PasswordResultHandler.kt
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2022 Electronic Systems And Services Ltd.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package by.esas.tools.accesscontainer.dialog.setters
+
+abstract class PasswordResultHandler(protected var noSecrets: Boolean) {
+
+ abstract fun onCancel()
+ abstract fun onComplete(password: String, recreate: Boolean = false)
+ abstract fun onForgotClicked()
+ abstract fun onAnotherClicked()
+}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/PinResultHandler.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/PinResultHandler.kt
new file mode 100644
index 00000000..949268df
--- /dev/null
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/PinResultHandler.kt
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2022 Electronic Systems And Services Ltd.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package by.esas.tools.accesscontainer.dialog.setters
+
+import by.esas.tools.accesscontainer.entity.Token
+
+abstract class PinResultHandler(protected val token: Token?) {
+
+ abstract fun onCancel()
+ abstract fun onAnotherClicked()
+ abstract fun onComplete(pin: String)
+}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/SetBiometricDialog.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/SetBiometricDialog.kt
index f0337883..d933a09c 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/SetBiometricDialog.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/SetBiometricDialog.kt
@@ -11,6 +11,7 @@ import by.esas.tools.accesscontainer.dialog.IBiometric
import javax.crypto.Cipher
interface SetBiometricDialog {
+
fun onAuthenticationCallback(onError: (Boolean, String) -> Unit, onSuccess: (Cipher?) -> Unit)
fun create(activity: FragmentActivity, userInfo: BiometricUserInfo)
fun setInfo(title: String, negativeText: String)
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/SetPasswordDialog.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/SetPasswordDialog.kt
index f264d63a..6b810e15 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/SetPasswordDialog.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/SetPasswordDialog.kt
@@ -5,11 +5,15 @@
package by.esas.tools.accesscontainer.dialog.setters
-interface SetPasswordDialog :
- IDialogSetter {
- fun setCancelTitle(cancelBtnRes: Int)
- fun setShowRecreateAuth(recreate: Boolean)
- fun setForgotPassword(forgotPasswordActionEnable: Boolean)
+interface SetPasswordDialog : IDialogSetter {
- fun setCallbacks(complete: (String, Boolean) -> Unit, forgot: () -> Unit)
+ fun setupParameterBundle(
+ cancelBtnRes: Int,
+ anotherBtnRes: Int,
+ isCancellable: Boolean,
+ showAnother: Boolean,
+ forgotPasswordActionEnable: Boolean
+ )
+
+ fun setupResultHandler(handler: PasswordResultHandler)
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/SetPinDialog.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/SetPinDialog.kt
index 53df78d7..939cc730 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/SetPinDialog.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/dialog/setters/SetPinDialog.kt
@@ -5,10 +5,14 @@
package by.esas.tools.accesscontainer.dialog.setters
-interface SetPinDialog :
- IDialogSetter {
- fun setCallbacks(complete: (String) -> Unit, cancel: () -> Unit)
- fun setCancelTitle(cancelRes: Int)
- fun setCancellable(value: Boolean)
- fun setHasAnother(value: Boolean)
+interface SetPinDialog : IDialogSetter {
+
+ fun setupParameterBundle(
+ cancelBtnRes: Int,
+ anotherBtnRes: Int,
+ cancellable: Boolean,
+ hasAnother: Boolean
+ )
+
+ fun setupResultHandler(handler: PinResultHandler)
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/error/IErrorMapper.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/error/IErrorMapper.kt
index 3128e333..f395a873 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/error/IErrorMapper.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/error/IErrorMapper.kt
@@ -7,10 +7,16 @@ package by.esas.tools.accesscontainer.error
import by.esas.tools.logger.BaseErrorModel
-interface IErrorMapper, M : BaseErrorModel> {
+interface IErrorMapper {
+
fun mapError(e: Exception): M
+ fun createErrorModel(code: Int, enumName: String): M
operator fun invoke(e: Exception): M {
return mapError(e)
}
+
+ operator fun invoke(code: Int, enumName: String): M {
+ return createErrorModel(code, enumName)
+ }
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/IContainerCancellationCallback.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/IContainerCancellationCallback.kt
index ccf7fd2e..586605ef 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/IContainerCancellationCallback.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/IContainerCancellationCallback.kt
@@ -6,5 +6,6 @@
package by.esas.tools.accesscontainer.support
interface IContainerCancellationCallback {
+
fun onCancel()
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/IContainerExecutor.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/IContainerExecutor.kt
index e3c4f558..2f39b9e3 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/IContainerExecutor.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/IContainerExecutor.kt
@@ -12,24 +12,38 @@ import by.esas.tools.logger.BaseErrorModel
import javax.crypto.Cipher
import javax.crypto.SecretKey
-interface IContainerExecutor, M : BaseErrorModel> {
- fun refreshAccessUC(refreshToken: String, block: ContainerRequest.() -> Unit)
+interface IContainerExecutor {
- fun getSecretsUC(block: ContainerRequest, E, M>.() -> Unit)
+ fun refreshAccessUC(refreshToken: String, block: ContainerRequest.() -> Unit)
- fun refreshWithSecretUC(pinKey: SecretKey? = null, cipher: Cipher? = null, block: ContainerRequest.() -> Unit)
+ fun getSecretsUC(block: ContainerRequest, M>.() -> Unit)
- fun checkSecretUC(pinKey: SecretKey? = null, cipher: Cipher? = null, block: ContainerRequest, E, M>.() -> Unit)
+ fun refreshWithSecretUC(
+ pinKey: SecretKey? = null,
+ cipher: Cipher? = null,
+ block: ContainerRequest.() -> Unit
+ )
- fun refreshWithSecretUC(secret: String, block: ContainerRequest.() -> Unit)
+ fun checkSecretUC(
+ pinKey: SecretKey? = null,
+ cipher: Cipher? = null,
+ block: ContainerRequest, M>.() -> Unit
+ )
- fun authorizationInSystemUC(password: String, block: ContainerRequest.() -> Unit)
+ fun refreshWithSecretUC(secret: String, block: ContainerRequest.() -> Unit)
- fun createSecretUC(token: String, cipher: Cipher? = null, pinKey: SecretKey? = null, block: ContainerRequest.() -> Unit)
+ fun authorizationInSystemUC(password: String, block: ContainerRequest.() -> Unit)
- fun deleteSecretTypeUC(type: AuthType, block: ContainerRequest.() -> Unit)
+ fun createSecretUC(
+ refreshToken: String,
+ cipher: Cipher? = null,
+ pinKey: SecretKey? = null,
+ block: ContainerRequest.() -> Unit
+ )
- fun deleteSecretsUC(block: ContainerRequest.() -> Unit)
+ fun deleteSecretTypeUC(type: AuthType, block: ContainerRequest.() -> Unit)
+
+ fun deleteSecretsUC(block: ContainerRequest.() -> Unit)
fun unsubscribe()
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/IContainerLogger.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/IContainerLogger.kt
index c0060863..a1a9fe86 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/IContainerLogger.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/IContainerLogger.kt
@@ -8,6 +8,7 @@ package by.esas.tools.accesscontainer.support
import android.widget.Toast
interface IContainerLogger {
+
fun setTag(tag: String)
fun log(msg: String)
fun log(res: Int)
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/ITypeManager.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/ITypeManager.kt
index e28c30ae..c820fd4f 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/ITypeManager.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/ITypeManager.kt
@@ -8,6 +8,7 @@ package by.esas.tools.accesscontainer.support
import by.esas.tools.accesscontainer.entity.AuthType
interface ITypeManager {
+
fun getPreferredType(): AuthType
fun putPreferredType(type: AuthType)
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/supporter/IUtil.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/supporter/IUtil.kt
index 2b44a013..011be144 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/supporter/IUtil.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/supporter/IUtil.kt
@@ -6,11 +6,10 @@
package by.esas.tools.accesscontainer.support.supporter
import android.content.Context
-import by.esas.tools.logger.BaseErrorModel
import javax.crypto.SecretKey
-interface IUtil, M : BaseErrorModel> {
- fun createErrorModel(code: Int, enumName: String): M
+interface IUtil {
+
fun generatePin(pin: String, userId: String, androidId: String): SecretKey?
fun checkBiometricSupport(context: Context?, logging: (String, String) -> Unit): Boolean
}
\ No newline at end of file
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/supporter/ResourceStrProvider.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/supporter/ResourceStrProvider.kt
index ab09eac4..229f7117 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/supporter/ResourceStrProvider.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/supporter/ResourceStrProvider.kt
@@ -9,6 +9,7 @@ import android.content.Context
import androidx.annotation.StringRes
interface ResourceStrProvider {
+
fun requireContext(): Context
fun getString(@StringRes resId: Int): String
fun provideAlterCancelStr(): Int
diff --git a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/supporter/Supporter.kt b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/supporter/Supporter.kt
index 11b61b32..b8d8b0c2 100644
--- a/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/supporter/Supporter.kt
+++ b/accesscontainer/src/main/java/by/esas/tools/accesscontainer/support/supporter/Supporter.kt
@@ -5,9 +5,7 @@
package by.esas.tools.accesscontainer.support.supporter
-import by.esas.tools.logger.BaseErrorModel
-
-class Supporter, M : BaseErrorModel>(
+class Supporter(
val resProvider: ResourceStrProvider,
- val util: IUtil
+ val util: IUtil
)
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index b5676761..215c6f5b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,11 +1,12 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
+apply plugin: 'androidx.navigation.safeargs.kotlin'
+apply from: '../properties.gradle'
android {
- compileSdkVersion 30
- buildToolsVersion "30.0.1"
+ compileSdkVersion compile_sdk_version
+ buildToolsVersion "30.0.3"
buildFeatures {
dataBinding = true
@@ -19,8 +20,9 @@ android {
}
defaultConfig {
applicationId "by.esas.tools"
- minSdkVersion 16
- targetSdkVersion 30
+ minSdkVersion min_sdk_version
+ targetSdkVersion compile_sdk_version
+ multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -31,25 +33,48 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
-
}
dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation "androidx.multidex:multidex:$multidex_version"
+
+ // Kotlin
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
+ //App
implementation "androidx.appcompat:appcompat:$appcompat_version"
implementation "androidx.core:core-ktx:$corektx_version"
+ implementation "androidx.biometric:biometric:$biometric_version"
// Data binding
kapt "com.android.databinding:compiler:$databinding_version"
+ // Moshi
+ implementation "com.squareup.moshi:moshi:$moshi_version"
+ //implementation "com.squareup.moshi:moshi-adapters:$moshi_version"
+ implementation "com.squareup.moshi:moshi-kotlin:$moshi_version"
+ //kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
+
+ // Network
+ implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
+ implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
+
+ // Room
+ api "androidx.room:room-runtime:$room_version"
+ kapt "androidx.room:room-compiler:$room_version"
+ implementation "androidx.room:room-ktx:$room_version"
+
// Dagger 2
- implementation "com.google.dagger:dagger:$dagger2_version"
- implementation "com.google.dagger:dagger-android:$dagger2_version"
- implementation "com.google.dagger:dagger-android-support:$dagger2_version"
+ //REMEMBER dagger is applied with api so it will be available in app module
+ //implementation "com.google.dagger:dagger:$dagger2_version"
+ //implementation "com.google.dagger:dagger-android:$dagger2_version"
+ //implementation "com.google.dagger:dagger-android-support:$dagger2_version"
kapt "com.google.dagger:dagger-compiler:$dagger2_version"
kapt "com.google.dagger:dagger-android-processor:$dagger2_version"
+ implementation project(path: ':baseui')
implementation project(path: ':basedaggerui')
implementation project(path: ':domain')
implementation project(path: ':dialog')
@@ -57,4 +82,12 @@ dependencies {
implementation project(path: ':inputfieldview')
implementation project(path: ':pinview')
implementation project(path: ':timeparser')
+ implementation project(path: ':numpad')
+ implementation project(path: ':util')
+ implementation project(path: ':listheader')
+ implementation project(path: ':customswitch')
+ implementation project(path: ':topbarview')
+ implementation project(path: ':cardline')
+ implementation project(path: ':biometric_decryption')
+ implementation project(path: ':accesscontainer')
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index cdd7e882..6e959c06 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,6 +2,13 @@
+
+
+
+
+
-
+
diff --git a/app/src/main/java/by/esas/tools/AddInvoiceViewModel.kt b/app/src/main/java/by/esas/tools/AddInvoiceViewModel.kt
deleted file mode 100644
index 219e0f21..00000000
--- a/app/src/main/java/by/esas/tools/AddInvoiceViewModel.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package by.esas.tools
-
-import androidx.lifecycle.SavedStateHandle
-import by.esas.tools.basedaggerui.inject.factory.AssistedSavedStateViewModelFactory
-import by.esas.tools.error_mapper.AppErrorMapper
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-
-class AddInvoiceViewModel @AssistedInject constructor(
- @Assisted private val savedStateHandle: SavedStateHandle,
- private val mapper: AppErrorMapper
-) : AppVM() {
- override val TAG: String = AddInvoiceViewModel::class.java.simpleName
-
- @AssistedFactory
- interface Factory : AssistedSavedStateViewModelFactory {
- override fun create(savedStateHandle: SavedStateHandle): AddInvoiceViewModel // may be ommited prior kotlin 1.3.60 or after PR #121 in AssistedInject lib
- }
-
- override fun onChangeLanguage() {
-
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/App.kt b/app/src/main/java/by/esas/tools/App.kt
index 473debb1..98c00f6d 100644
--- a/app/src/main/java/by/esas/tools/App.kt
+++ b/app/src/main/java/by/esas/tools/App.kt
@@ -2,12 +2,15 @@ package by.esas.tools
import android.content.Context
import androidx.appcompat.app.AppCompatDelegate
+import androidx.multidex.MultiDex
+import by.esas.tools.app_data.AppSharedPrefs
import by.esas.tools.inject.component.DaggerAppComponent
-import by.esas.tools.util.LocaleManager
+import by.esas.tools.util.configs.SettingsManager
import dagger.android.AndroidInjector
import dagger.android.DaggerApplication
class App : DaggerApplication() {
+
override fun applicationInjector(): AndroidInjector {
return DaggerAppComponent
.builder()
@@ -16,6 +19,7 @@ class App : DaggerApplication() {
}
companion object {
+
lateinit var instance: App
lateinit var appContext: Context
}
@@ -42,8 +46,10 @@ class App : DaggerApplication() {
}
override fun attachBaseContext(base: Context?) {
- super.attachBaseContext(base?.let { return@let LocaleManager.setLocale(base, getLocale(base).language) })
- //MultiDex.install(this)
+ super.attachBaseContext(base?.let {
+ val prefs = AppSharedPrefs(base)
+ return@let SettingsManager.updateSettings(base, prefs.getLanguage(), prefs.getTheme())
+ })
+ MultiDex.install(this)
}
-
}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/AppActivity.kt b/app/src/main/java/by/esas/tools/AppActivity.kt
deleted file mode 100644
index 048e109e..00000000
--- a/app/src/main/java/by/esas/tools/AppActivity.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-package by.esas.tools
-
-import androidx.databinding.ViewDataBinding
-import by.esas.tools.basedaggerui.simple.SimpleActivity
-import by.esas.tools.error_mapper.AppErrorStatusEnum
-import by.esas.tools.logger.ErrorModel
-import by.esas.tools.logger.handler.ErrorHandler
-
-abstract class AppActivity : SimpleActivity() {
-
- override fun provideErrorHandler(): ErrorHandler {
- return object : ErrorHandler() {
- override fun getErrorMessage(error: ErrorModel): String {
- TODO("Not yet implemented")
- }
-
- override fun getErrorMessage(e: Throwable): String {
- TODO("Not yet implemented")
- }
-
- override fun mapError(e: Throwable): ErrorModel {
- TODO("Not yet implemented")
- }
-
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/AppVM.kt b/app/src/main/java/by/esas/tools/AppVM.kt
deleted file mode 100644
index 8603753b..00000000
--- a/app/src/main/java/by/esas/tools/AppVM.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package by.esas.tools
-
-import by.esas.tools.basedaggerui.simple.SimpleViewModel
-import by.esas.tools.error_mapper.AppErrorStatusEnum
-import by.esas.tools.logger.ErrorModel
-
-abstract class AppVM : SimpleViewModel() {
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/DataBinding.kt b/app/src/main/java/by/esas/tools/DataBinding.kt
index fcf6ed19..0c53ff54 100644
--- a/app/src/main/java/by/esas/tools/DataBinding.kt
+++ b/app/src/main/java/by/esas/tools/DataBinding.kt
@@ -1,34 +1,80 @@
package by.esas.tools
-import android.text.Editable
-import android.text.TextWatcher
import android.view.View
+import androidx.core.content.ContextCompat
import androidx.databinding.BindingAdapter
-import androidx.databinding.InverseBindingAdapter
-import androidx.databinding.InverseBindingListener
-import by.esas.tools.fields.RohabInputField
+import by.esas.tools.entity.TestStatusEnum
+import by.esas.tools.topbarview.TopbarView
+import com.google.android.material.textview.MaterialTextView
@BindingAdapter("visibilityGone")
fun setVisibilityOrGone(view: View, isVisible: Boolean) {
view.visibility = if (isVisible) View.VISIBLE else View.GONE
}
-@BindingAdapter("android:textAttrChanged")
-fun setListeners(view: RohabInputField, attrChange: InverseBindingListener) {
- view.inputText?.addTextChangedListener(object : TextWatcher {
- override fun afterTextChanged(s: Editable?) {
- attrChange.onChange()
- }
+@BindingAdapter("barTitleText")
+fun setBarTitle(view: TopbarView, text: String?) {
+ view.setTitle(text)
+}
- override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
- }
+@BindingAdapter("buttonsClickable")
+fun setButtonsEnabled(view: TopbarView, value: Boolean) {
+ view.setButtonsEnabled(value)
+}
- override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
- }
- })
+@BindingAdapter("onEndActionClick")
+fun setBarEndActionClick(view: TopbarView, listener: View.OnClickListener) {
+ view.setEndActionListener(listener)
+}
+
+@BindingAdapter("onStartActionClick")
+fun setBarStartActionClick(view: TopbarView, listener: View.OnClickListener) {
+ view.setStartActionListener(listener)
+}
+
+@BindingAdapter("barShowNavIcon")
+fun setBarNavIconVisibility(view: TopbarView, value: Boolean) {
+ view.setNavIconVisibility(value)
}
-@InverseBindingAdapter(attribute = "android:text")
-fun getText(view: RohabInputField): String {
- return view.getText()
+@BindingAdapter("barShowActionIcon")
+fun setBarActionIconVisibility(view: TopbarView, value: Boolean) {
+ view.setActionIconVisibility(value)
+}
+
+@BindingAdapter("barShowDivider")
+fun setBarDividerVisibility(view: TopbarView, value: Boolean) {
+ view.setDividerVisibility(value)
+}
+
+@BindingAdapter("caseTestStatus")
+fun setInvoiceStatus(view: MaterialTextView, state: TestStatusEnum) {
+ val bgRes: Int
+ val textColorRes: Int
+ val textRes: Int
+ when (state) {
+ TestStatusEnum.CHECKED -> {
+ bgRes = R.drawable.bg_case_status_checked
+ textColorRes = R.color.green_dark
+ textRes = R.string.case_status_checked
+ }
+ TestStatusEnum.IN_PROCESS -> {
+ bgRes = R.drawable.bg_case_status_in_process
+ textColorRes = R.color.blue
+ textRes = R.string.case_status_in_process
+ }
+ TestStatusEnum.FAILED -> {
+ bgRes = R.drawable.bg_case_status_failed
+ textColorRes = R.color.red
+ textRes = R.string.case_status_failed
+ }
+ else -> {
+ bgRes = R.drawable.bg_case_status_unchecked
+ textColorRes = R.color.gray_dark
+ textRes = R.string.case_status_unchecked
+ }
+ }
+ view.setBackgroundResource(bgRes)
+ view.setText(textRes)
+ view.setTextColor(ContextCompat.getColor(view.context, textColorRes))
}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/MainActivity.kt b/app/src/main/java/by/esas/tools/MainActivity.kt
deleted file mode 100644
index 4de496b0..00000000
--- a/app/src/main/java/by/esas/tools/MainActivity.kt
+++ /dev/null
@@ -1,179 +0,0 @@
-package by.esas.tools
-
-import android.content.Context
-import android.graphics.Color
-import android.os.Build
-import android.os.Bundle
-import android.view.View
-import android.view.WindowInsetsController
-import androidx.core.view.ViewCompat
-import androidx.core.view.updatePadding
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.ViewModelProvider
-import by.esas.tools.checker.Checker
-import by.esas.tools.checker.IRequestFocusHandler
-import by.esas.tools.checker.checks.LengthCheck
-import by.esas.tools.checking.AppChecker
-import by.esas.tools.checking.FieldChecking
-import by.esas.tools.databinding.ActivityMainBinding
-import by.esas.tools.error_mapper.AppErrorMapper
-import by.esas.tools.error_mapper.AppErrorStatusEnum
-import by.esas.tools.logger.BaseErrorModel
-import by.esas.tools.logger.ILogger
-import by.esas.tools.logger.LoggerImpl
-import by.esas.tools.usecase.GetDefaultCardUseCase
-import by.esas.tools.util.LanguageSetter
-import by.esas.tools.util.hideSystemUIR
-import com.squareup.moshi.Moshi
-import kotlinx.coroutines.Dispatchers
-
-open class MainActivity : AppActivity() {
- override val TAG: String = "MainActivity"
- override var logger: ILogger = LoggerImpl()
- override fun provideViewModel(): MainVM {
- return ViewModelProvider(this, viewModelFactory.provideFactory()).get(MainVM::class.java)
- }
-
- override fun provideLayoutId(): Int {
- return R.layout.activity_main
- }
-
- override fun provideVariableInd(): Int {
- return BR.viewModel
- }
-
- override fun provideLifecycleOwner(): LifecycleOwner {
- return this
- }
-
- override fun provideSetter(): LanguageSetter {
- return object : LanguageSetter {
- override fun getDefaultLanguage(): String {
- return "en"
- }
-
- override fun getLanguage(): String {
- return "en"
- }
-
- override fun setLanguage(lang: String) {
-
- }
- }
- }
-
- override fun getAppContext(): Context {
- return App.appContext
- }
-
- override fun setAppContext(context: Context) {
- App.appContext = context
- }
-
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
- val statusBar = insets.getSystemWindowInsetTop()
- val navigationBar = insets.getSystemWindowInsetBottom()
- binding.root.updatePadding(top = statusBar)
- return@setOnApplyWindowInsetsListener insets
- }
- /*viewModel.update = {
- binding.fMainAddInvoiceAdditionalContainer.invalidate()
- }*/
-
- binding.fMainSetErrorPin.setOnClickListener {
- doCheck()
- if (!binding.aMainText3.getText().equals("12345678")) {
- binding.aMainText3.setError("Some error")
- } else {
- binding.aMainText3.setError("")
- }
- }
- }
-
- fun doCheck() {
- AppChecker()
- .setShowError(true)
- .setListener(object : Checker.CheckListener {})
- .validate(
- listOf(
- FieldChecking(binding.aMainText4, true)
- .setRequestFocusHandler(object : IRequestFocusHandler {
- override fun handleRequestFocus() {
- binding.aMainText4.visibility = View.VISIBLE
- binding.aMainText4.requestFocus()
- //scroll to position
- }
- })
- .addCheck(LengthCheck(0, 4))
- )
- )
- }
- /*val field = findViewById(R.id.a_main_text2)
- field.setInputPrefix("1")*/
- /*val spinner = findViewById(R.id.a_main_service_spinner)
- spinner.adapter.clear()
- (spinner.adapter as ArrayAdapter).addAll(listOf("1", "2", "3"))
- spinner.adapter.notifyDataSetChanged()
- val currentText = "1"
- spinner.setText(currentText)*/
- /*viewModel.addToObservable(viewModel.mainText, Observer {
- AppChecker()
- .setShowError(true)
- .setListener(object : Checker.CheckListener {})
- .validate(listOf(FieldChecking(field, true).addCheck(LengthCheck(0, 4))))
- })*/
-
-
- override fun setFullScreen() {
- //WindowCompat.setDecorFitsSystemWindows(window, false)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- window.setDecorFitsSystemWindows(false)
- window.insetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- window.apply {
- //clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
- //addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- decorView.systemUiVisibility =
- (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
- } else {
- decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)
- }
- statusBarColor = Color.TRANSPARENT
- }
-
- }
- }
-
- fun testError() {
- val uc = GetDefaultCardUseCase(
- AppErrorMapper(Moshi.Builder().build(), LoggerImpl()),
- Dispatchers.Main
- )
- uc.execute {
- onComplete {
-
- }
- onError {
- it.statusEnum
- }
- onCancel {
-
- }
- }
- val model = BaseErrorModel(0, AppErrorStatusEnum.APP_UNPREDICTED_ERROR)
- model.statusEnum
- }
-
- override fun hideSystemUI() {
- logger.logInfo("hideSystemUI")
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- hideSystemUIR(this)
- } else hideSystemUIApp(this)
- }
-
-
-}
diff --git a/app/src/main/java/by/esas/tools/MainVM.kt b/app/src/main/java/by/esas/tools/MainVM.kt
deleted file mode 100644
index 977fde95..00000000
--- a/app/src/main/java/by/esas/tools/MainVM.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-package by.esas.tools
-
-import androidx.databinding.Observable
-import androidx.databinding.ObservableBoolean
-import androidx.databinding.ObservableField
-import androidx.lifecycle.MutableLiveData
-import javax.inject.Inject
-
-class MainVM @Inject constructor() : AppVM() {
- override val TAG: String = "MainVM"
- var update: () -> Unit = {}
-
- override fun onChangeLanguage() {
-
- }
-
- fun setUp() {
- serviceName.addOnPropertyChangedCallback(
- object : Observable.OnPropertyChangedCallback() {
- override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
- mainText.postValue(serviceName.get() ?: "")
- }
- }
- )
- }
-
- val serviceName = ObservableField("")
- val showAdditional = ObservableBoolean(false)
- val mainText = MutableLiveData().apply { postValue("") }
-
- val password = MutableLiveData("")
-
- fun onAdditionalClick() {
- showAdditional.set(!showAdditional.get())
- update()
- }
-}
-
diff --git a/app/src/main/java/by/esas/tools/Utils.kt b/app/src/main/java/by/esas/tools/Utils.kt
deleted file mode 100644
index f44f90fb..00000000
--- a/app/src/main/java/by/esas/tools/Utils.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package by.esas.tools
-
-import android.app.Activity
-import android.content.Context
-import android.view.View
-import java.util.*
-
-fun getLocale(context: Context): Locale {
- return Locale.getDefault()
-}
-
-/* Standard */
-fun hideSystemUIApp(activity: Activity?) {
- // Enables regular immersive mode.
- // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
- // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- if (activity != null) {
- activity.window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- // Set the content to appear under the system bars so that the
- // content doesn't resize when the system bars hide and show.
- or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- //or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- // Hide the nav bar and status bar
- or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- /*or View.SYSTEM_UI_FLAG_FULLSCREEN*/)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_data/AppSharedPrefs.kt b/app/src/main/java/by/esas/tools/app_data/AppSharedPrefs.kt
new file mode 100644
index 00000000..4dde7fd9
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_data/AppSharedPrefs.kt
@@ -0,0 +1,40 @@
+package by.esas.tools.app_data
+
+import android.content.Context
+import android.content.SharedPreferences
+import by.esas.tools.util.configs.UiModeType
+
+class AppSharedPrefs(val context: Context) {
+
+ private val sharedPrefs: SharedPreferences
+
+ companion object {
+
+ private const val CURRENT_LANGUAGE = "klangkopl"
+ private const val CURRENT_THEME = "pjuthemred"
+ private const val SHARED_PREFS_NAME = "basic_tools_pref"
+ }
+
+ init {
+ sharedPrefs = context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE)
+ }
+
+ fun setLanguage(lang: String) {
+ sharedPrefs.edit().putString(CURRENT_LANGUAGE, lang).apply()
+ }
+
+ fun getLanguage(): String {
+ return sharedPrefs.getString(CURRENT_LANGUAGE, "en") ?: "en"
+ }
+
+ fun setTheme(theme: UiModeType) {
+ sharedPrefs.edit().putString(CURRENT_THEME, theme.name).apply()
+ }
+
+ fun getTheme(): UiModeType {
+ val currentTheme = sharedPrefs.getString(CURRENT_THEME, "") ?: ""
+ return if (currentTheme.isNotBlank()) {
+ UiModeType.valueOf(currentTheme)
+ } else UiModeType.SYSTEM
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_data/Cases.kt b/app/src/main/java/by/esas/tools/app_data/Cases.kt
new file mode 100644
index 00000000..bc648297
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_data/Cases.kt
@@ -0,0 +1,198 @@
+package by.esas.tools.app_data
+
+import by.esas.tools.App
+import by.esas.tools.R
+import by.esas.tools.entity.CaseInfo
+import by.esas.tools.entity.Modules
+
+object Cases {
+
+ private val cases = arrayListOf()
+
+ fun getAll(): List {
+ cases.clear()
+ addCaseItem(
+ R.id.loggerFragment,
+ R.string.case_label_logger,
+ listOf(Modules.LOGGER)
+ )
+ addCaseItem(
+ R.id.timeparserFragment,
+ R.string.case_label_timeparser,
+ listOf(Modules.TIMEPARSER)
+ )
+ addCaseItem(
+ R.id.biometricDecryptionFragment,
+ R.string.case_label_biometric_decryption,
+ listOf(Modules.BIOMETRIC_DECRYPTION)
+ )
+ addCaseItem(
+ R.id.domainCaseFragment,
+ R.string.case_label_domain,
+ listOf(Modules.DOMAIN)
+ )
+ addCaseItem(
+ R.id.baseuiThemeFragment,
+ R.string.case_label_baseui_theme,
+ listOf(Modules.BASE_UI)
+ )
+ addCaseItem(
+ R.id.baseuiFunctionalityFragment,
+ R.string.case_label_baseui,
+ listOf(Modules.BASE_UI)
+ )
+ addCaseItem(
+ R.id.baseuiNavigationFragment,
+ R.string.case_label_baseui_navigation,
+ listOf(Modules.BASE_UI)
+ )
+ addCaseItem(
+ R.id.bottomDialogFragment,
+ R.string.case_label_bottom_dialog,
+ listOf(Modules.DIALOG, Modules.INPUTFIELD_VIEW)
+ )
+ addCaseItem(
+ R.id.dynamicMessageDialogFragment,
+ R.string.case_label_dynamic_message_dialog,
+ listOf(Modules.DIALOG)
+ )
+ addCaseItem(
+ R.id.inputfieldViewFragment,
+ R.string.case_label_inputfield_view,
+ listOf(Modules.INPUTFIELD_VIEW)
+ )
+ addCaseItem(
+ R.id.inputfieldViewStartIconFragment,
+ R.string.case_label_inputfield_view_start_icon,
+ listOf(Modules.INPUTFIELD_VIEW)
+ )
+ addCaseItem(
+ R.id.inputfieldViewEndIconFragment,
+ R.string.case_label_inputfield_view_end_icon,
+ listOf(Modules.INPUTFIELD_VIEW)
+ )
+ addCaseItem(
+ R.id.checkerFragment,
+ R.string.case_label_checker,
+ listOf(Modules.CHECKER, Modules.INPUTFIELD_VIEW)
+ )
+ addCaseItem(
+ R.id.pinViewFragment,
+ R.string.case_label_pin_view,
+ listOf(Modules.PIN_VIEW)
+ )
+ addCaseItem(
+ R.id.dynamicPinViewFragment,
+ R.string.case_label_dynamic_pin_view,
+ listOf(Modules.PIN_VIEW)
+ )
+ addCaseItem(
+ R.id.savedStateFragment,
+ R.string.case_label_saved_state,
+ listOf(Modules.BASE_DAGGER_UI, Modules.BASE_UI)
+ )
+ addCaseItem(
+ R.id.numpadImageFragment,
+ R.string.case_label_numpad_image,
+ listOf(Modules.NUMPAD)
+ )
+ addCaseItem(
+ R.id.numpadTextFragment,
+ R.string.case_label_numpad_text,
+ listOf(Modules.NUMPAD)
+ )
+ addCaseItem(
+ R.id.utilKeyboardFragment,
+ R.string.case_label_util_keyboard,
+ listOf(Modules.UTIL)
+ )
+ addCaseItem(
+ R.id.utilUtilsFragment,
+ R.string.case_label_utils,
+ listOf(Modules.UTIL)
+ )
+ addCaseItem(
+ R.id.utilSwitchManagerFragment,
+ R.string.case_label_switch_manager,
+ listOf(Modules.UTIL, Modules.CUSTOMSWITCH)
+ )
+ addCaseItem(
+ R.id.customSwitchFragment,
+ R.string.case_label_custom_switch,
+ listOf(Modules.CUSTOMSWITCH)
+ )
+ addCaseItem(
+ R.id.customSwitchProgramFragment,
+ R.string.case_label_dynamic_custom_switch,
+ listOf(Modules.CUSTOMSWITCH),
+ )
+ addCaseItem(
+ R.id.listheaderFragment,
+ R.string.case_label_listheader,
+ listOf(Modules.LISTHEADER, Modules.CUSTOMSWITCH)
+ )
+ addCaseItem(
+ R.id.dynamicListheaderFragment,
+ R.string.case_label_dynamic_listheader,
+ listOf(Modules.LISTHEADER)
+ )
+ addCaseItem(
+ R.id.topbarFragment,
+ R.string.case_label_topbar_view,
+ listOf(Modules.TOPBAR_VIEW)
+ )
+ addCaseItem(
+ R.id.cardlineFragment,
+ R.string.case_label_cardline,
+ listOf(Modules.CARDLINE)
+ )
+ addCaseItem(
+ R.id.dynamicCardlineFragment,
+ R.string.case_label_dynamic_cardline,
+ listOf(Modules.CARDLINE)
+ )
+ addCaseItem(
+ R.id.recyclerFragment,
+ R.string.case_label_recycler_base,
+ listOf(Modules.RECYCLER)
+ )
+ addCaseItem(
+ R.id.stickyCaseFragment,
+ R.string.case_label_recycler_sticky,
+ listOf(Modules.RECYCLER)
+ )
+ addCaseItem(
+ R.id.simpleRecyclerFragment,
+ R.string.case_label_recycler_simple,
+ listOf(Modules.RECYCLER)
+ )
+ addCaseItem(
+ R.id.customRecyclerFragment,
+ R.string.case_label_recycler_custom,
+ listOf(Modules.RECYCLER)
+ )
+ addCaseItem(
+ R.id.accessContainerFragment,
+ R.string.case_label_access_container,
+ listOf(
+ Modules.ACCESS_CONTAINER,
+ Modules.LISTHEADER,
+ Modules.INPUTFIELD_VIEW,
+ Modules.NUMPAD,
+ Modules.DIALOG
+ )
+ )
+
+ return cases
+ }
+
+ //REMEMBER to add some static mapping to set static ID's for cases
+ private fun addCaseItem(
+ id: Int,
+ name: Int,
+ modulesList: List
+ ) {
+ val caseName = App.appContext.getString(name)
+ cases.add(CaseInfo(id, caseName, modulesList))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_data/db/AppDataBase.kt b/app/src/main/java/by/esas/tools/app_data/db/AppDataBase.kt
new file mode 100644
index 00000000..f97b534c
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_data/db/AppDataBase.kt
@@ -0,0 +1,31 @@
+package by.esas.tools.app_data.db
+
+import android.content.Context
+import androidx.room.Database
+import androidx.room.Room
+import androidx.room.RoomDatabase
+import androidx.room.TypeConverters
+import by.esas.tools.app_data.db.converter.CaseStatusConverter
+import by.esas.tools.app_data.db.dao.CaseStatusDao
+import by.esas.tools.entity.CaseStatus
+
+@Database(entities = [CaseStatus::class], version = 1)
+
+@TypeConverters(CaseStatusConverter::class)
+abstract class AppDataBase : RoomDatabase() {
+
+ companion object {
+
+ private const val DATABASE_NAME = "ABL_DATABASE"
+
+ fun getInstance(context: Context): AppDataBase {
+ return Room.databaseBuilder(
+ context,
+ AppDataBase::class.java,
+ DATABASE_NAME
+ ).build()
+ }
+ }
+
+ abstract fun getCaseStatusDao(): CaseStatusDao
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_data/db/converter/CaseStatusConverter.kt b/app/src/main/java/by/esas/tools/app_data/db/converter/CaseStatusConverter.kt
new file mode 100644
index 00000000..15f4ea26
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_data/db/converter/CaseStatusConverter.kt
@@ -0,0 +1,13 @@
+package by.esas.tools.app_data.db.converter
+
+import androidx.room.TypeConverter
+import by.esas.tools.entity.TestStatusEnum
+
+class CaseStatusConverter {
+
+ @TypeConverter
+ fun toTestStatusEnum(value: String) = enumValueOf(value)
+
+ @TypeConverter
+ fun fromTestStatusEnum(value: TestStatusEnum) = value.name
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_data/db/dao/CaseStatusDao.kt b/app/src/main/java/by/esas/tools/app_data/db/dao/CaseStatusDao.kt
new file mode 100644
index 00000000..d36701cf
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_data/db/dao/CaseStatusDao.kt
@@ -0,0 +1,27 @@
+package by.esas.tools.app_data.db.dao
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import by.esas.tools.entity.CaseStatus
+import by.esas.tools.entity.TestStatusEnum
+
+@Dao
+interface CaseStatusDao {
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ fun insert(caseStatus: CaseStatus)
+
+ @Query("UPDATE caseStatusTable SET case_status=:status WHERE case_id = :id")
+ fun update(id: Int, status: TestStatusEnum)
+
+ @Query("SELECT * FROM caseStatusTable")
+ fun getAll(): List
+
+ @Query("SELECT * FROM caseStatusTable WHERE case_id = :id")
+ fun getById(id: Int): CaseStatus
+
+ @Query("DELETE FROM caseStatusTable")
+ fun deleteAll()
+}
diff --git a/app/src/main/java/by/esas/tools/app_domain/error_mapper/AppErrorMapper.kt b/app/src/main/java/by/esas/tools/app_domain/error_mapper/AppErrorMapper.kt
new file mode 100644
index 00000000..aac0a4b4
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_domain/error_mapper/AppErrorMapper.kt
@@ -0,0 +1,22 @@
+package by.esas.tools.app_domain.error_mapper
+
+import by.esas.tools.domain.mapper.BaseErrorMapper
+import by.esas.tools.logger.ILogger
+import by.esas.tools.utils.logger.ErrorModel
+import com.squareup.moshi.Moshi
+
+class AppErrorMapper(moshi: Moshi, logger: ILogger) :
+ BaseErrorMapper(moshi, logger) {
+
+ override fun mapBaseException(errorText: String?): String {
+ return AppErrorStatusEnum.APP_UNPREDICTED_ERROR.name
+ }
+
+ override fun createModel(code: Int, status: String): ErrorModel {
+ return ErrorModel(code, AppErrorStatusEnum.getAppErrorStatusEnum(status))
+ }
+
+ override fun mapHttpStatus(httpEnumString: String): String {
+ return AppErrorStatusEnum.APP_UNPREDICTED_ERROR.name
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/error_mapper/AppErrorStatusEnum.kt b/app/src/main/java/by/esas/tools/app_domain/error_mapper/AppErrorStatusEnum.kt
similarity index 62%
rename from app/src/main/java/by/esas/tools/error_mapper/AppErrorStatusEnum.kt
rename to app/src/main/java/by/esas/tools/app_domain/error_mapper/AppErrorStatusEnum.kt
index e4992595..90ab3b3c 100644
--- a/app/src/main/java/by/esas/tools/error_mapper/AppErrorStatusEnum.kt
+++ b/app/src/main/java/by/esas/tools/app_domain/error_mapper/AppErrorStatusEnum.kt
@@ -1,4 +1,6 @@
-package by.esas.tools.error_mapper
+package by.esas.tools.app_domain.error_mapper
+
+import by.esas.tools.accesscontainer.error.ErrorStatusEnum
enum class AppErrorStatusEnum {
OK,
@@ -21,19 +23,15 @@ enum class AppErrorStatusEnum {
//App
APP_UNPREDICTED_ERROR,
- APP_INVOICE_NOT_ADDED,
- APP_INVOICE_NOT_CHANGED,
- APP_INVOICE_NOT_FOUND,
- APP_INVOICE_QR_NOT_FOUND,
APP_DATE_IN_UNEXPECTED_FORMAT,
+ APP_ILLEGAL_PATTERN_CHARACTER,
APP_NO_ACCESS_TOKEN,
- APP_INVOICE_ID_NOT_SET,
- APP_INVOICE_NOT_SET,
APP_CONTEXT_PARAMETERS_EMPTY,
APP_USER_HAS_NO_SECRETS,
//Decryption
+ BIOMETRIC_UNAVAILABLE,
SECRET_CHECK_NOT_MATCH,
DECRYPTION_FAILED,
APP_REFRESH_TOKEN_DECRYPTION_FAILED,
@@ -74,10 +72,27 @@ enum class AppErrorStatusEnum {
API_DELETE_PHONE_ERROR,
API_PHONE_NUMBER_NOT_CONFIRMED,
API_PHONE_ALREADY_SET,
- API_CODE_INVALID_OR_EXPIRED,
+ API_CODE_INVALID_OR_EXPIRED;
+
+ companion object {
+
+ fun getAppErrorStatusEnum(value: String): AppErrorStatusEnum {
+ return try {
+ valueOf(value)
+ } catch (e: IllegalArgumentException) {
+ mapToAppErrorStatus(value)
+ }
+ }
- EPOS_INVOICE_NUMBER_TAKEN,
- SERVICE_INFO_NOT_FOUND,
- CURRENCY_INFO_NOT_FOUND,
- INVOICES_GET_NOT_FOUND
+ private fun mapToAppErrorStatus(value: String): AppErrorStatusEnum {
+ return try {
+ when (ErrorStatusEnum.valueOf(value)) {
+ ErrorStatusEnum.HAS_NO_SECRETS -> APP_USER_HAS_NO_SECRETS
+ ErrorStatusEnum.SECRET_CHECK_NOT_MATCH -> SECRET_CHECK_NOT_MATCH
+ }
+ } catch (e: IllegalArgumentException) {
+ UNKNOWN_ERROR
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_domain/usecase/AddCaseStatusUseCase.kt b/app/src/main/java/by/esas/tools/app_domain/usecase/AddCaseStatusUseCase.kt
new file mode 100644
index 00000000..63d64ad7
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_domain/usecase/AddCaseStatusUseCase.kt
@@ -0,0 +1,24 @@
+package by.esas.tools.app_domain.usecase
+
+import by.esas.tools.app_data.db.dao.CaseStatusDao
+import by.esas.tools.app_domain.error_mapper.AppErrorMapper
+import by.esas.tools.entity.CaseStatus
+import by.esas.tools.entity.TestStatusEnum
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+
+class AddCaseStatusUseCase @Inject constructor(
+ errorUtil: AppErrorMapper,
+ foregroundContext: CoroutineContext,
+ private val dao: CaseStatusDao
+) : BaseUseCase(errorUtil, foregroundContext) {
+
+ override val TAG: String = GetCaseItemsUseCase::class.java.simpleName
+
+ var caseId = -1
+ var caseStatus = TestStatusEnum.UNCHECKED
+
+ override suspend fun executeOnBackground() {
+ dao.insert(CaseStatus(caseId, caseStatus))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_domain/usecase/BaseUseCase.kt b/app/src/main/java/by/esas/tools/app_domain/usecase/BaseUseCase.kt
new file mode 100644
index 00000000..5c06378c
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_domain/usecase/BaseUseCase.kt
@@ -0,0 +1,31 @@
+package by.esas.tools.app_domain.usecase
+
+import by.esas.tools.app_domain.error_mapper.AppErrorMapper
+import by.esas.tools.domain.usecase.IRefresh
+import by.esas.tools.domain.usecase.UseCase
+import by.esas.tools.utils.logger.ErrorModel
+import kotlinx.coroutines.Dispatchers
+import kotlin.coroutines.CoroutineContext
+
+abstract class BaseUseCase(errorUtil: AppErrorMapper, refresher: IRefresh?) :
+ UseCase(errorUtil, refresher) {
+
+ constructor(
+ errorUtil: AppErrorMapper,
+ foregroundContext: CoroutineContext,
+ backgroundContext: CoroutineContext = Dispatchers.IO
+ ) : this(errorUtil, null) {
+ this.foregroundContext = foregroundContext
+ this.backgroundContext = backgroundContext
+ }
+
+ constructor(
+ errorUtil: AppErrorMapper,
+ refresher: IRefresh,
+ foregroundContext: CoroutineContext,
+ backgroundContext: CoroutineContext = Dispatchers.IO
+ ) : this(errorUtil, refresher) {
+ this.foregroundContext = foregroundContext
+ this.backgroundContext = backgroundContext
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_domain/usecase/ClearAllSavedTestStatusesUseCase.kt b/app/src/main/java/by/esas/tools/app_domain/usecase/ClearAllSavedTestStatusesUseCase.kt
new file mode 100644
index 00000000..86adbb96
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_domain/usecase/ClearAllSavedTestStatusesUseCase.kt
@@ -0,0 +1,19 @@
+package by.esas.tools.app_domain.usecase
+
+import by.esas.tools.app_data.db.dao.CaseStatusDao
+import by.esas.tools.app_domain.error_mapper.AppErrorMapper
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+
+class ClearAllSavedTestStatusesUseCase @Inject constructor(
+ errorUtil: AppErrorMapper,
+ foregroundContext: CoroutineContext,
+ private val dao: CaseStatusDao
+) : BaseUseCase(errorUtil, foregroundContext) {
+
+ override val TAG: String = GetCaseItemsUseCase::class.java.simpleName
+
+ override suspend fun executeOnBackground() {
+ dao.deleteAll()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_domain/usecase/FilterCaseUseCase.kt b/app/src/main/java/by/esas/tools/app_domain/usecase/FilterCaseUseCase.kt
new file mode 100644
index 00000000..15f8f275
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_domain/usecase/FilterCaseUseCase.kt
@@ -0,0 +1,29 @@
+package by.esas.tools.app_domain.usecase
+
+import by.esas.tools.app_domain.error_mapper.AppErrorMapper
+import by.esas.tools.entity.CaseItemInfo
+import by.esas.tools.entity.TestStatusEnum
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+
+class FilterCaseUseCase @Inject constructor(
+ errorUtil: AppErrorMapper,
+ foregroundContext: CoroutineContext
+) : BaseUseCase>(errorUtil, foregroundContext) {
+
+ override val TAG = FilterCaseUseCase::class.java.simpleName
+
+ var modules = listOf()
+ var statuses = listOf()
+ var caseItems = listOf()
+
+ override suspend fun executeOnBackground(): List {
+ var filteredList = caseItems
+ if (statuses.isNotEmpty())
+ filteredList = filteredList.filter { it.status in statuses }
+ if (modules.isNotEmpty())
+ filteredList = filteredList.filter { it.modules.intersect(modules.toSet()).isNotEmpty() }
+
+ return filteredList
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_domain/usecase/GetCaseItemsUseCase.kt b/app/src/main/java/by/esas/tools/app_domain/usecase/GetCaseItemsUseCase.kt
new file mode 100644
index 00000000..e67d9c24
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_domain/usecase/GetCaseItemsUseCase.kt
@@ -0,0 +1,33 @@
+package by.esas.tools.app_domain.usecase
+
+import by.esas.tools.app_data.Cases
+import by.esas.tools.app_data.db.dao.CaseStatusDao
+import by.esas.tools.app_domain.error_mapper.AppErrorMapper
+import by.esas.tools.entity.CaseItemInfo
+import by.esas.tools.entity.TestStatusEnum
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+
+class GetCaseItemsUseCase @Inject constructor(
+ errorUtil: AppErrorMapper,
+ foregroundContext: CoroutineContext,
+ private val dao: CaseStatusDao
+) : BaseUseCase>(errorUtil, foregroundContext) {
+
+ override val TAG: String = GetCaseItemsUseCase::class.java.simpleName
+
+ override suspend fun executeOnBackground(): List {
+ val cases = Cases.getAll()
+ val savedCaseStatuses = dao.getAll()
+ val caseItemsList = cases.map { caseInfo ->
+ CaseItemInfo(
+ caseInfo.id,
+ caseInfo.name,
+ caseInfo.modules,
+ savedCaseStatuses.find { it.caseId == caseInfo.id }?.status ?: TestStatusEnum.UNCHECKED
+ )
+ }
+
+ return caseItemsList
+ }
+}
diff --git a/app/src/main/java/by/esas/tools/usecase/GetDefaultCardUseCase.kt b/app/src/main/java/by/esas/tools/app_domain/usecase/GetDefaultCardUseCase.kt
similarity index 59%
rename from app/src/main/java/by/esas/tools/usecase/GetDefaultCardUseCase.kt
rename to app/src/main/java/by/esas/tools/app_domain/usecase/GetDefaultCardUseCase.kt
index 48c42283..56d7f686 100644
--- a/app/src/main/java/by/esas/tools/usecase/GetDefaultCardUseCase.kt
+++ b/app/src/main/java/by/esas/tools/app_domain/usecase/GetDefaultCardUseCase.kt
@@ -1,17 +1,21 @@
-package by.esas.tools.usecase
+package by.esas.tools.app_domain.usecase
-import by.esas.tools.error_mapper.AppErrorMapper
+import by.esas.tools.app_domain.error_mapper.AppErrorMapper
import by.esas.tools.domain.exception.BaseException
import by.esas.tools.domain.exception.BaseStatusEnum
+import kotlinx.coroutines.delay
+import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
-class GetDefaultCardUseCase constructor(
+class GetDefaultCardUseCase @Inject constructor(
errorUtil: AppErrorMapper,
foregroundContext: CoroutineContext
-) : BaseUseCase(errorUtil, null) {
+) : BaseUseCase(errorUtil, foregroundContext) {
+
override val TAG: String = GetDefaultCardUseCase::class.java.simpleName
override suspend fun executeOnBackground(): String {
+ delay(1000L)
throw BaseException(BaseStatusEnum.UNKNOWN_ERROR)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_domain/usecase/GetSavedCaseStatusUseCase.kt b/app/src/main/java/by/esas/tools/app_domain/usecase/GetSavedCaseStatusUseCase.kt
new file mode 100644
index 00000000..ec333079
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_domain/usecase/GetSavedCaseStatusUseCase.kt
@@ -0,0 +1,23 @@
+package by.esas.tools.app_domain.usecase
+
+import by.esas.tools.app_data.db.dao.CaseStatusDao
+import by.esas.tools.app_domain.error_mapper.AppErrorMapper
+import by.esas.tools.entity.CaseStatus
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+
+class GetSavedCaseStatusUseCase @Inject constructor(
+ errorUtil: AppErrorMapper,
+ foregroundContext: CoroutineContext,
+ private val dao: CaseStatusDao
+) : BaseUseCase(errorUtil, foregroundContext) {
+
+ override val TAG: String = GetCaseItemsUseCase::class.java.simpleName
+
+ var caseId = -1
+
+ override suspend fun executeOnBackground(): CaseStatus {
+
+ return dao.getById(caseId)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_domain/usecase/PlayRandomUseCase.kt b/app/src/main/java/by/esas/tools/app_domain/usecase/PlayRandomUseCase.kt
new file mode 100644
index 00000000..57415f3c
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_domain/usecase/PlayRandomUseCase.kt
@@ -0,0 +1,28 @@
+package by.esas.tools.app_domain.usecase
+
+import by.esas.tools.App
+import by.esas.tools.R
+import by.esas.tools.app_domain.error_mapper.AppErrorMapper
+import by.esas.tools.domain.exception.BaseException
+import by.esas.tools.domain.exception.BaseStatusEnum
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlin.random.Random
+
+class PlayRandomUseCase @Inject constructor(
+ errorUtil: AppErrorMapper,
+ foregroundContext: CoroutineContext
+) : BaseUseCase(errorUtil, foregroundContext) {
+
+ override val TAG = PlayRandomUseCase::class.java.simpleName
+
+ var rangeNumbers = 0
+ var number = 0
+
+ override suspend fun executeOnBackground(): String {
+ if (number == Random.nextInt(0, rangeNumbers + 1)) {
+ return App.appContext.getString(R.string.domain_case_congratulations)
+ } else
+ throw BaseException(BaseStatusEnum.UNKNOWN_ERROR)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/app_domain/usecase/SearchCaseUseCase.kt b/app/src/main/java/by/esas/tools/app_domain/usecase/SearchCaseUseCase.kt
new file mode 100644
index 00000000..2fd3708c
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/app_domain/usecase/SearchCaseUseCase.kt
@@ -0,0 +1,43 @@
+package by.esas.tools.app_domain.usecase
+
+import by.esas.tools.app_domain.error_mapper.AppErrorMapper
+import by.esas.tools.entity.CaseItemInfo
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+
+class SearchCaseUseCase @Inject constructor(
+ errorUtil: AppErrorMapper,
+ foregroundContext: CoroutineContext
+) : BaseUseCase>(errorUtil, foregroundContext) {
+
+ override val TAG: String = SearchCaseUseCase::class.java.simpleName
+
+ var caseItems = listOf()
+ var search = ""
+
+ override suspend fun executeOnBackground(): List {
+ return if (search != "") {
+ var filteredList = caseItems
+ val searchList = splitSearch(search)
+ for (i in searchList) {
+ filteredList = filteredList.filter { item ->
+ item.name.contains(i, true) || doSearchByModules(item, i)
+ }
+ }
+ filteredList
+ } else {
+ caseItems
+ }
+ }
+
+ private fun splitSearch(search: String): List {
+ return search.split(";").mapNotNull { result -> result.trim().takeIf { it.isNotBlank() } }
+ }
+
+ private fun doSearchByModules(case: CaseItemInfo, search: String): Boolean {
+ val module = case.modules.find { module ->
+ module == search
+ }
+ return module != null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/base/AppActivity.kt b/app/src/main/java/by/esas/tools/base/AppActivity.kt
new file mode 100644
index 00000000..c330de16
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/base/AppActivity.kt
@@ -0,0 +1,130 @@
+package by.esas.tools.base
+
+import android.content.Context
+import android.os.Bundle
+import android.view.View
+import androidx.databinding.ViewDataBinding
+import by.esas.tools.App
+import by.esas.tools.BR
+import by.esas.tools.R
+import by.esas.tools.app_data.AppSharedPrefs
+import by.esas.tools.basedaggerui.factory.InjectingViewModelFactory
+import by.esas.tools.baseui.standard.StandardActivity
+import by.esas.tools.logger.ILogger
+import by.esas.tools.logger.handler.ErrorHandler
+import by.esas.tools.util.TAGk
+import by.esas.tools.util.configs.SettingsProvider
+import by.esas.tools.util.configs.UiModeType
+import by.esas.tools.utils.logger.ErrorModel
+import by.esas.tools.utils.logger.LoggerImpl
+import dagger.android.AndroidInjection
+import dagger.android.AndroidInjector
+import dagger.android.DispatchingAndroidInjector
+import dagger.android.HasAndroidInjector
+import java.util.*
+import javax.inject.Inject
+
+/**
+ * To use HasAndroidInjector with Activity do not forget to add
+ * AndroidInjection.inject(this)
+ * in the fun onCreate(savedInstanceState: Bundle?)
+ *
+ * To use HasAndroidInjector with Fragment do not forget to add
+ * override fun onAttach(context: Context) {
+ * AndroidSupportInjection.inject(this)
+ * super.onAttach(context)
+ * }
+ */
+abstract class AppActivity
+ : StandardActivity(),
+ HasAndroidInjector {
+
+ @Inject
+ lateinit var viewModelFactory: InjectingViewModelFactory
+
+ @Inject
+ lateinit var androidInjector: DispatchingAndroidInjector
+
+ override fun androidInjector(): AndroidInjector? {
+ return androidInjector
+ }
+
+ override var logger: ILogger = LoggerImpl()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ AndroidInjection.inject(this)
+ super.onCreate(savedInstanceState)
+ }
+
+ override fun provideSwitchableViews(): List {
+ return emptyList()
+ }
+
+ override fun provideErrorHandler(): ErrorHandler {
+ logger.logOrder("provideErrorHandler")
+ return object : ErrorHandler() {
+
+ override fun getErrorMessage(error: ErrorModel): String {
+ return error.statusEnum
+ }
+
+ override fun getErrorMessage(e: Throwable): String {
+ return e.message ?: resources.getString(R.string.test_error)
+ }
+
+ override fun mapError(e: Throwable): ErrorModel {
+ return viewModel.provideMapper().mapErrorException(this.TAGk, e)
+ }
+ }
+ }
+
+ override fun provideVariableInd(): Int {
+ return BR.viewModel
+ }
+
+ override fun provideSetter(): SettingsProvider {
+ return object : SettingsProvider {
+ var prefs: AppSharedPrefs = AppSharedPrefs(App.instance)
+
+ override fun getDefaultLanguage(): String {
+ return "en"
+ }
+
+ override fun getLanguage(): String {
+ return prefs.getLanguage()
+ }
+
+ override fun setLanguage(lang: String) {
+ prefs.setLanguage(lang)
+ }
+
+ override fun getDefaultMode(): UiModeType {
+ return UiModeType.SYSTEM
+ }
+
+ override fun getMode(): UiModeType {
+ return prefs.getTheme()
+ }
+
+ override fun setMode(uiMode: UiModeType) {
+ prefs.setTheme(uiMode)
+ }
+ }
+ }
+
+ override fun getAppContext(): Context {
+ return App.appContext
+ }
+
+ override fun setAppContext(context: Context) {
+ App.appContext = context
+ }
+
+ /**
+ * @see IHandlePopBackArguments
+ * */
+ override fun handlePopBackArguments(arguments: Bundle?) {
+ if (arguments != null)
+ intent.putExtras(arguments)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/base/AppFragment.kt b/app/src/main/java/by/esas/tools/base/AppFragment.kt
new file mode 100644
index 00000000..6b2d2136
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/base/AppFragment.kt
@@ -0,0 +1,85 @@
+package by.esas.tools.base
+
+import android.content.Context
+import android.view.View
+import androidx.databinding.ViewDataBinding
+import by.esas.tools.App
+import by.esas.tools.BR
+import by.esas.tools.R
+import by.esas.tools.basedaggerui.factory.InjectingViewModelFactory
+import by.esas.tools.baseui.standard.StandardFragment
+import by.esas.tools.checker.Checker
+import by.esas.tools.checker.Checking
+import by.esas.tools.logger.BaseLoggerImpl
+import by.esas.tools.logger.ILogger
+import by.esas.tools.logger.handler.ErrorHandler
+import by.esas.tools.util.TAGk
+import by.esas.tools.utils.logger.ErrorModel
+import dagger.android.AndroidInjector
+import dagger.android.DispatchingAndroidInjector
+import dagger.android.HasAndroidInjector
+import dagger.android.support.AndroidSupportInjection
+import javax.inject.Inject
+
+abstract class AppFragment :
+ StandardFragment(),
+ HasAndroidInjector {
+
+ @Inject
+ lateinit var viewModelFactory: InjectingViewModelFactory
+
+ @Inject
+ lateinit var androidInjector: DispatchingAndroidInjector
+
+ override fun androidInjector(): AndroidInjector? {
+ return androidInjector
+ }
+
+ override var logger: ILogger<*> = BaseLoggerImpl(context = provideAppContext())
+
+ override fun provideAppContext(): Context {
+ return App.appContext
+ }
+
+ override fun provideVariableInd(): Int {
+ return BR.viewModel
+ }
+
+ override fun provideErrorHandler(): ErrorHandler {
+ logger.logOrder("provideErrorHandler")
+ return object : ErrorHandler() {
+
+ override fun getErrorMessage(error: ErrorModel): String {
+ return error.statusEnum
+ }
+
+ override fun getErrorMessage(e: Throwable): String {
+ return e.message ?: resources.getString(R.string.test_error)
+ }
+
+ override fun mapError(e: Throwable): ErrorModel {
+ return viewModel.provideMapper().mapErrorException(this.TAGk, e)
+ }
+ }
+ }
+
+ override fun provideChecks(): List {
+ logger.logOrder("provideChecks")
+ return emptyList()
+ }
+
+ override fun provideChecker(): Checker? {
+ logger.logOrder("provideChecker")
+ return null
+ }
+
+ override fun provideSwitchableViews(): List {
+ logger.logOrder("provideSwitchableViews")
+ return emptyList()
+ }
+
+ override fun onAttach(context: Context) {
+ AndroidSupportInjection.inject(this)
+ super.onAttach(context)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/base/AppVM.kt b/app/src/main/java/by/esas/tools/base/AppVM.kt
new file mode 100644
index 00000000..6bb3f6a4
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/base/AppVM.kt
@@ -0,0 +1,21 @@
+package by.esas.tools.base
+
+import by.esas.tools.app_domain.error_mapper.AppErrorMapper
+import by.esas.tools.baseui.standard.StandardViewModel
+import by.esas.tools.logger.IErrorMapper
+import by.esas.tools.logger.ILogger
+import by.esas.tools.utils.logger.ErrorModel
+import by.esas.tools.utils.logger.LoggerImpl
+import javax.inject.Inject
+
+abstract class AppVM : StandardViewModel() {
+
+ @Inject
+ lateinit var mapper: AppErrorMapper
+
+ override var logger: ILogger<*> = LoggerImpl()
+
+ override fun provideMapper(): IErrorMapper {
+ return mapper
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/dialog/CustomBottomDialog.kt b/app/src/main/java/by/esas/tools/dialog/CustomBottomDialog.kt
new file mode 100644
index 00000000..05f0ac64
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/dialog/CustomBottomDialog.kt
@@ -0,0 +1,91 @@
+package by.esas.tools.dialog
+
+import android.os.Bundle
+import android.view.View
+import android.widget.Button
+import by.esas.tools.R
+import by.esas.tools.checker.Checker
+import by.esas.tools.checker.Checking
+import by.esas.tools.checker.checks.LengthCheck
+import by.esas.tools.databinding.DfCustomBottomBinding
+import by.esas.tools.util.SwitchManager
+import by.esas.tools.utils.checking.AppChecker
+import by.esas.tools.utils.checking.FieldChecking
+
+class CustomBottomDialog : BindingBottomDialogFragment() {
+
+ companion object {
+
+ const val BOTTOM_DIALOG_CHECK_RESULT = "BOTTOM_DIALOG_CHECK_RESULT"
+ }
+
+ override fun provideLayoutId(): Int {
+ return R.layout.df_custom_bottom
+ }
+
+ override var switcher: SwitchManager = object : SwitchManager() {
+ override fun enableView(view: View): Boolean {
+ return if (view is Button) {
+ view.isEnabled = true
+ true
+ } else {
+ super.enableView(view)
+ }
+ }
+
+ override fun disableView(view: View): Boolean {
+ return if (view is Button) {
+ view.isEnabled = false
+ true
+ } else {
+ super.disableView(view)
+ }
+ }
+ }
+
+ override fun provideSwitchableList(): List {
+ return listOf(binding.dfCustomBottomSendButton, binding.dfCustomBottomInputField)
+ }
+
+ override fun provideValidationList(): List {
+ return listOf(
+ FieldChecking(binding.dfCustomBottomInputField).addCheck(
+ LengthCheck(
+ 1, 20,
+ resources.getString(R.string.validation_text_in_range, 1, 20)
+ )
+ )
+ )
+ }
+
+ override fun provideVariableId(): Int {
+ return BR.handler
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ binding.dfCustomBottomSwitcher.setOnCheckedChangeListener { _, isChecked ->
+ when (isChecked) {
+ true -> enableControls()
+ false -> disableControls()
+ }
+ }
+
+ binding.dfCustomBottomSendButton.setOnClickListener {
+ disableControls()
+ AppChecker().setListener(object : Checker.CheckListener {
+ override fun onFailed() {
+ enableControls()
+ }
+
+ override fun onSuccess() {
+ enableControls()
+ resultBundle.putString(Config.DIALOG_USER_ACTION, Config.DISMISS_DIALOG)
+ resultBundle.putString(BOTTOM_DIALOG_CHECK_RESULT, binding.dfCustomBottomInputField.getText())
+ dismiss()
+ }
+ }).validate(provideValidationList())
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/dialog/GetPasswordDialog.kt b/app/src/main/java/by/esas/tools/dialog/GetPasswordDialog.kt
deleted file mode 100644
index f7130a6b..00000000
--- a/app/src/main/java/by/esas/tools/dialog/GetPasswordDialog.kt
+++ /dev/null
@@ -1,136 +0,0 @@
-package by.esas.tools.dialog
-
-import android.os.Bundle
-import android.view.View
-import android.widget.EditText
-import androidx.databinding.ObservableBoolean
-import androidx.databinding.ObservableField
-import by.esas.tools.BR
-import by.esas.tools.R
-import by.esas.tools.checker.Checking
-import by.esas.tools.databinding.DfPasswordBinding
-import by.esas.tools.domain.exception.BaseException
-import by.esas.tools.domain.exception.BaseStatusEnum
-import kotlinx.android.synthetic.main.df_password.*
-
-class GetPasswordDialog : BindingDialogFragment() {
- override val TAG: String = GetPasswordDialog::class.java.simpleName
-
- /* override fun provideLogger(): LoggerImpl {
- return LoggerImpl(TAG)
- }*/
-
- override fun provideLayoutId(): Int {
- return R.layout.df_password
- }
-
- override fun provideSwitchableList(): List {
- return emptyList()//listOf(df_password_layout.inputText)
- }
-
- override fun provideValidationList(): List {
- return emptyList()/*listOf(
- BaseChecking(df_password_layout.inputLayout)
- .addCheck(NotEmptyCheck("Can't be empty"))
- )*/
- }
-
- override fun provideProgressBar(): View? {
- return null
- }
-
- fun setPasswordCallback(callback: PasswordCallback) {
- this.callback = callback
- }
-
- fun setShowRecreateAuth(value: Boolean) {
- showRecreateView = value
- }
-
- val showForgotPassword = ObservableBoolean(false)
- val showRecreateCheck = ObservableBoolean(false)
- val isChecked = ObservableBoolean(false)
- val password = ObservableField("12345678")
-
- private var showRecreateView: Boolean = false
- private var callback: PasswordCallback? = null
- private var titleRes: Int = -1
- private var forgotPasswordEnable: Boolean = false
- private var cancelTitleRes: Int = -1
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- isCancelable = false
- //setHeader(view.findViewById(R.id.df_password_title), view.context.getString(titleRes))
- showRecreateCheck.set(showRecreateView)
- showForgotPassword.set(forgotPasswordEnable)
- binding.dfPasswordCancelBtn.setText(cancelTitleRes)
- }
-
- fun onCancelClick() {
- afterOk = false
- dismiss()
- }
-
- fun onContinueClick() {
- validatePassword()
- }
-
- fun onForgotPasswordClick() {
- afterOk = true
- callback?.onPasswordForgot()
- dismiss()
- }
-
- private fun validatePassword() {
- /*disableControls()
- Validator.with(App.appContext).setListener(object : Validator.OnValidateListener {
- override fun onValidateFailed() {
- enableControls()
- }
-
- override fun onValidateSuccess(values: List) {
- callback?.onPasswordComplete(
- df_password_layout.inputText.text.toString(),
- isChecked.get()
- )
- afterOk = true
- enableControls()
- dismiss()
- }
- }).validate(*validationList.toTypedArray())*/
- }
-
- override fun disableControls() {
- super.disableControls()
- df_password_continue_btn.isClickable = false
- df_password_cancel_btn.isClickable = false
- }
-
- override fun enableControls() {
- super.enableControls()
- df_password_continue_btn.isClickable = true
- df_password_cancel_btn.isClickable = true
- }
-
- fun setForgotPassword(enable: Boolean) {
- forgotPasswordEnable = enable
- }
-
- fun setTitle(resId: Int) {
- //titleRes = if (resId == -1) R.string.dialog_password_title else resId
- }
-
- fun setCancelTitle(resId: Int) {
- //cancelTitleRes = if (resId == -1) R.string.dialog_cancel_btn else resId
- }
-
- interface PasswordCallback {
- fun onPasswordComplete(password: String, recreate: Boolean)
- fun onPasswordForgot()
- }
-
- override fun provideVariableId(): Int {
- return BR.handler
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/dialog/SearchFilterDialog.kt b/app/src/main/java/by/esas/tools/dialog/SearchFilterDialog.kt
new file mode 100644
index 00000000..68eae8df
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/dialog/SearchFilterDialog.kt
@@ -0,0 +1,168 @@
+package by.esas.tools.dialog
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.CheckBox
+import by.esas.tools.App
+import by.esas.tools.R
+import by.esas.tools.checker.Checking
+import by.esas.tools.databinding.DfSearchFilterBinding
+import by.esas.tools.entity.Modules
+import by.esas.tools.topbarview.ITopbarHandler
+
+private const val SELECTED_MODULES_KEY = "SELECTED_MODULES_KEY"
+private const val SELECTED_STATUSES_KEY = "SELECTED_STATUSES_KEY"
+
+class SearchFilterDialog : BindingDialogFragment() {
+
+ companion object {
+
+ const val ACTION_SELECT_FILTER_MODULES = "ACTION_SELECT_FILTER_MODULES"
+ const val ACTION_SELECT_FILTER_STATUSES = "ACTION_SELECT_FILTER_STATUSES"
+ const val FILTER_DIALOG_KEY = "FILTER_DIALOG_KEY"
+ }
+
+ private var moduleBoxes = listOf>()
+ private var statusBoxes = listOf>()
+
+ private var selectedModules = arrayListOf()
+ private var selectedStatuses = arrayListOf()
+
+ init {
+ isCancelable = true
+ }
+
+ override fun provideLayoutId() = R.layout.df_search_filter
+
+ override fun provideSwitchableList(): List = emptyList()
+
+ override fun provideValidationList(): List = emptyList()
+
+ override fun provideVariableId() = BR.handler
+
+ override fun styleSettings() {
+ setStyle(STYLE_NO_FRAME, R.style.AppTheme)
+ }
+
+ override fun onStart() {
+ super.onStart()
+
+ dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ super.onCreateView(inflater, container, savedInstanceState)
+
+ statusBoxes = listOf(
+ Pair(binding.dfFilterStatusChecked, App.appContext.getString(R.string.case_status_checked)),
+ Pair(binding.dfFilterStatusUnchecked, App.appContext.getString(R.string.case_status_unchecked)),
+ Pair(binding.dfFilterStatusFailed, App.appContext.getString(R.string.case_status_failed)),
+ Pair(binding.dfFilterStatusInProgress, App.appContext.getString(R.string.case_status_in_process))
+ )
+ moduleBoxes = listOf(
+ Pair(binding.dfFilterModuleAccesscontainer, Modules.ACCESS_CONTAINER),
+ Pair(binding.dfFilterModuleBasedaggerui, Modules.BASE_DAGGER_UI),
+ Pair(binding.dfFilterModuleBaseui, Modules.BASE_UI),
+ Pair(binding.dfFilterModuleBiometricDecryption, Modules.BIOMETRIC_DECRYPTION),
+ Pair(binding.dfFilterModuleCardline, Modules.CARDLINE),
+ Pair(binding.dfFilterModuleChecker, Modules.CHECKER),
+ Pair(binding.dfFilterModuleCustomswitch, Modules.CUSTOMSWITCH),
+ Pair(binding.dfFilterModuleDialog, Modules.DIALOG),
+ Pair(binding.dfFilterModuleDimenUtil, Modules.DIMEN_UTIL),
+ Pair(binding.dfFilterModuleDomain, Modules.DOMAIN),
+ Pair(binding.dfFilterModuleInputfieldview, Modules.INPUTFIELD_VIEW),
+ Pair(binding.dfFilterModuleListheader, Modules.LISTHEADER),
+ Pair(binding.dfFilterModuleLogger, Modules.LOGGER),
+ Pair(binding.dfFilterModuleNumpad, Modules.NUMPAD),
+ Pair(binding.dfFilterModulePinview, Modules.PIN_VIEW),
+ Pair(binding.dfFilterModuleRecycler, Modules.RECYCLER),
+ Pair(binding.dfFilterModuleTimeparser, Modules.TIMEPARSER),
+ Pair(binding.dfFilterModuleTopbarview, Modules.TOPBAR_VIEW),
+ Pair(binding.dfFilterModuleUtil, Modules.UTIL)
+ )
+
+ setSelectedStatuses()
+ setSelectedModules()
+
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ binding.dfFilterTopbar.setupHandler(object : ITopbarHandler {
+ override fun onActionClick() {
+ resultBundle.putString(Config.DIALOG_USER_ACTION, Config.DISMISS_DIALOG)
+ resultBundle.putStringArray(ACTION_SELECT_FILTER_STATUSES, emptyArray())
+ resultBundle.putStringArray(ACTION_SELECT_FILTER_MODULES, emptyArray())
+
+ this@SearchFilterDialog.dismiss()
+ }
+
+ override fun onNavigationClick() {
+ this@SearchFilterDialog.dismiss()
+ }
+ })
+
+ binding.dfFilterShowResultBtn.setOnClickListener {
+ resultBundle.putString(Config.DIALOG_USER_ACTION, Config.DISMISS_DIALOG)
+ resultBundle.putStringArray(ACTION_SELECT_FILTER_STATUSES, getSelectedStatuses().toTypedArray())
+ resultBundle.putStringArray(ACTION_SELECT_FILTER_MODULES, getSelectedModules().toTypedArray())
+
+ this@SearchFilterDialog.dismiss()
+ }
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+
+ outState.putStringArrayList(SELECTED_STATUSES_KEY, selectedStatuses)
+ outState.putStringArrayList(SELECTED_MODULES_KEY, selectedModules)
+ }
+
+ override fun onViewStateRestored(savedInstanceState: Bundle?) {
+ super.onViewStateRestored(savedInstanceState)
+
+ selectedStatuses = savedInstanceState?.getStringArrayList(SELECTED_STATUSES_KEY) ?: arrayListOf()
+ selectedModules = savedInstanceState?.getStringArrayList(SELECTED_MODULES_KEY) ?: arrayListOf()
+ setSelectedStatuses()
+ setSelectedModules()
+ }
+
+ fun setSelectedItems(statuses: List, modules: List) {
+ selectedStatuses.clear()
+ selectedStatuses.addAll(statuses)
+
+ selectedModules.clear()
+ selectedModules.addAll(modules)
+ }
+
+ private fun setSelectedStatuses() {
+ selectedStatuses.forEach {
+ when (it) {
+ App.appContext.getString(R.string.case_status_checked) -> binding.dfFilterStatusChecked.isChecked = true
+ App.appContext.getString(R.string.case_status_in_process) -> binding.dfFilterStatusInProgress.isChecked =
+ true
+ App.appContext.getString(R.string.case_status_failed) -> binding.dfFilterStatusFailed.isChecked = true
+ App.appContext.getString(R.string.case_status_unchecked) -> binding.dfFilterStatusUnchecked.isChecked =
+ true
+ }
+ }
+ }
+
+ private fun setSelectedModules() {
+ selectedModules.forEach { selectedModule ->
+ moduleBoxes.find { it.second == selectedModule }?.first?.isChecked = true
+ }
+ }
+
+ private fun getSelectedStatuses() = statusBoxes.filter { it.first.isChecked }.map { it.second }
+
+ private fun getSelectedModules() = moduleBoxes.filter { it.first.isChecked }.map { it.second }
+}
diff --git a/app/src/main/java/by/esas/tools/entity/CaseInfo.kt b/app/src/main/java/by/esas/tools/entity/CaseInfo.kt
new file mode 100644
index 00000000..e217b5a4
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/entity/CaseInfo.kt
@@ -0,0 +1,7 @@
+package by.esas.tools.entity
+
+data class CaseInfo(
+ val id: Int,
+ val name: String,
+ val modules: List
+)
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/entity/CaseItemInfo.kt b/app/src/main/java/by/esas/tools/entity/CaseItemInfo.kt
new file mode 100644
index 00000000..87c8e828
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/entity/CaseItemInfo.kt
@@ -0,0 +1,24 @@
+package by.esas.tools.entity
+
+import by.esas.tools.recycler.ICheckDiff
+
+data class CaseItemInfo(
+ val id: Int,
+ val name: String,
+ val modules: List,
+ val status: TestStatusEnum
+) : ICheckDiff {
+
+ override fun checkIfSameItem(item: CaseItemInfo): Boolean {
+ return id == item.id
+ }
+
+ override fun checkIfSameContent(item: CaseItemInfo): Boolean {
+ if (id != item.id) return false
+ else if (name != item.name) return false
+ else if (modules.size != item.modules.size || !modules.containsAll(item.modules)) return false
+ else if (status != item.status) return false
+
+ return true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/entity/CaseStatus.kt b/app/src/main/java/by/esas/tools/entity/CaseStatus.kt
new file mode 100644
index 00000000..190faa56
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/entity/CaseStatus.kt
@@ -0,0 +1,15 @@
+package by.esas.tools.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity(tableName = "caseStatusTable")
+data class CaseStatus(
+ @PrimaryKey
+ @ColumnInfo(name = "case_id")
+ val caseId: Int,
+
+ @ColumnInfo(name = "case_status")
+ var status: TestStatusEnum
+)
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/entity/LogItem.kt b/app/src/main/java/by/esas/tools/entity/LogItem.kt
new file mode 100644
index 00000000..e98d56a9
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/entity/LogItem.kt
@@ -0,0 +1,7 @@
+package by.esas.tools.entity
+
+data class LogItem(
+ val tag: String = "",
+ val category: String = "",
+ val message: String
+)
diff --git a/app/src/main/java/by/esas/tools/entity/Modules.kt b/app/src/main/java/by/esas/tools/entity/Modules.kt
new file mode 100644
index 00000000..95048d59
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/entity/Modules.kt
@@ -0,0 +1,24 @@
+package by.esas.tools.entity
+
+object Modules {
+
+ const val ACCESS_CONTAINER = "accesscontainer"
+ const val BASE_DAGGER_UI = "basedaggerui"
+ const val BASE_UI = "baseui"
+ const val BIOMETRIC_DECRYPTION = "biometric_decryption"
+ const val CARDLINE = "cardline"
+ const val CHECKER = "checker"
+ const val CUSTOMSWITCH = "customswitch"
+ const val DIALOG = "dialog"
+ const val DIMEN_UTIL = "dimen_util"
+ const val DOMAIN = "domain"
+ const val INPUTFIELD_VIEW = "inputfieldview"
+ const val LISTHEADER = "listheader"
+ const val LOGGER = "logger"
+ const val NUMPAD = "numpad"
+ const val PIN_VIEW = "pinview"
+ const val RECYCLER = "recycler"
+ const val TIMEPARSER = "timeparser"
+ const val TOPBAR_VIEW = "topbarview"
+ const val UTIL = "util"
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/entity/NumpadTextIconEntity.kt b/app/src/main/java/by/esas/tools/entity/NumpadTextIconEntity.kt
new file mode 100644
index 00000000..a1324b6e
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/entity/NumpadTextIconEntity.kt
@@ -0,0 +1,7 @@
+package by.esas.tools.entity
+
+data class NumpadTextIconEntity(
+ val iconSize: Int,
+ val numTextSize: Int,
+ val imageSize: Int
+)
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/entity/TestStatusEnum.kt b/app/src/main/java/by/esas/tools/entity/TestStatusEnum.kt
new file mode 100644
index 00000000..6e6c074f
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/entity/TestStatusEnum.kt
@@ -0,0 +1,8 @@
+package by.esas.tools.entity
+
+enum class TestStatusEnum {
+ CHECKED,
+ UNCHECKED,
+ IN_PROCESS,
+ FAILED
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/error_mapper/AppErrorMapper.kt b/app/src/main/java/by/esas/tools/error_mapper/AppErrorMapper.kt
deleted file mode 100644
index 44b10a60..00000000
--- a/app/src/main/java/by/esas/tools/error_mapper/AppErrorMapper.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-package by.esas.tools.error_mapper
-
-import by.esas.tools.domain.exception.BaseStatusEnum
-import by.esas.tools.domain.mapper.BaseErrorMapper
-import by.esas.tools.logger.ErrorModel
-import by.esas.tools.logger.ILogger
-import com.squareup.moshi.Moshi
-import retrofit2.HttpException
-
-class AppErrorMapper(moshi: Moshi, logger: ILogger) :
- BaseErrorMapper(moshi, logger) {
- override fun mapBaseException(errorText: String?): AppErrorStatusEnum {
- return AppErrorStatusEnum.APP_UNPREDICTED_ERROR
- }
-
- override fun mapBaseStatus(enum: BaseStatusEnum): AppErrorStatusEnum {
- return AppErrorStatusEnum.APP_UNPREDICTED_ERROR
- }
-
- override fun mapErrorException(tag: String, throwable: Throwable?): ErrorModel {
- val model = super.mapErrorException(tag, throwable)
- return ErrorModel(model.code, model.statusEnum)
- }
-
- override fun getHttpError(throwable: HttpException): ErrorModel {
- val model = super.getHttpError(throwable)
- return ErrorModel(model.code, model.statusEnum)
- }
-
- override fun createModel(code: Int, status: AppErrorStatusEnum): ErrorModel {
- return ErrorModel(code, status)
- }
-
- override fun mapHttpStatus(httpEnumString: String): AppErrorStatusEnum {
- return AppErrorStatusEnum.APP_UNPREDICTED_ERROR
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/fields/RohabInputField.kt b/app/src/main/java/by/esas/tools/fields/RohabInputField.kt
deleted file mode 100644
index f695c177..00000000
--- a/app/src/main/java/by/esas/tools/fields/RohabInputField.kt
+++ /dev/null
@@ -1,105 +0,0 @@
-package by.esas.tools.fields
-
-import android.content.Context
-import android.util.AttributeSet
-import androidx.core.text.BidiFormatter
-import by.esas.tools.R
-import by.esas.tools.getLocale
-import by.esas.tools.inputfieldview.InputFieldView
-
-class RohabInputField : InputFieldView {
- override val TAG: String = RohabInputField::class.java.simpleName
- //val logger: ILogger = LoggerImpl()
-
- override val defaultLabelType: Int = LABEL_TYPE_ON_TOP
- private var formattedText: String = ""
-
- constructor(context: Context) : super(context)
- constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
- initAttrs(attrs)
- }
-
- constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int)
- : super(context, attrs, defStyleAttr) {
- initAttrs(attrs)
- }
-
- /* @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
- constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int)
- : super(context, attrs, defStyleAttr, defStyleRes) {
- initAttrs(attrs)
- }*/
-
- init {
- //logger.setTag(TAG)
- }
-
- /* Initialize attributes from XML file */
- private fun initAttrs(attrs: AttributeSet?) {
- val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RohabInputField)
- // Label
- val label = typedArray.getString(R.styleable.RohabInputField_inputLabel) ?: ""
- // Hint
- formattedText = typedArray.getString(R.styleable.RohabInputField_inputHintFormattedText) ?: ""
-
- typedArray.recycle()
-
- labelText?.text = ""
- if (formattedText.isNotBlank()) {
- setInputLabel(label, formattedText)
- } else setInputLabel(label)
- }
-
- fun setInputLabel(text: String, formattedText: String) {
- val formatter: BidiFormatter = BidiFormatter.getInstance()
- val hintTxt = String.format(text, formatter.unicodeWrap(formattedText))
- setInputLabel(hintTxt)
- }
-
- fun setInputLabel(text: String, formattedId: Int) {
- val formatter: BidiFormatter = BidiFormatter.getInstance()
- val formattedText = if (formattedId != -1) context.resources.getString(formattedId) else ""
- val hintTxt = String.format(text, formatter.unicodeWrap(formattedText))
- setInputLabel(hintTxt)
- }
-
- override fun setInputLabel(text: String?) {
- if ((labelText?.text?.toString() ?: "") != text && !text.isNullOrBlank()) {
- /*if (!isInEditMode)
- logger.log("Is RTL direction ${resources.getBoolean(R.bool.is_rtl_direction)}")*/
- var hint = text ?: ""
- hint = if (hint.contains("(") && hint.contains(")")) {
- val beforeBrace = text.substringBefore("(")
- val afterFirstBrace = text.substringAfter("(")
- val betweenBraces = afterFirstBrace.substringBefore(")")
- val afterSecondBrace = afterFirstBrace.substringAfter(")", "")
- val builder = StringBuilder("")
- builder.append(beforeBrace.toUpperCase(getLocale(context))).append("(")
- .append(betweenBraces).append(")").append(
- afterSecondBrace.toUpperCase(
- getLocale(
- context
- )
- )
- )
- builder.toString()
- } else hint.toUpperCase(getLocale(context))
- labelText?.text = hint//HtmlCompat.fromHtml(hint,HtmlCompat.FROM_HTML_MODE_LEGACY)
- } else hideLabel()
- }
-
- fun setInputLabel(textId: Int, formattedText: String) {
- val text = if (textId != -1) context.resources.getString(textId) else ""
- val formatter: BidiFormatter = BidiFormatter.getInstance()
- val hintTxt = String.format(text, formatter.unicodeWrap(formattedText))
- setInputLabel(hintTxt)
- }
-
- fun setInputLabel(textId: Int, formattedId: Int) {
- val text = if (textId != -1) context.resources.getString(textId) else ""
- val formattedText = if (formattedId != -1) context.resources.getString(formattedId) else ""
- val formatter: BidiFormatter = BidiFormatter.getInstance()
- val hintTxt = String.format(text, formatter.unicodeWrap(formattedText))
- setInputLabel(hintTxt)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/inject/builder/ActivityBuilder.kt b/app/src/main/java/by/esas/tools/inject/builder/ActivityBuilder.kt
index f4926c8c..e9c9dc2c 100644
--- a/app/src/main/java/by/esas/tools/inject/builder/ActivityBuilder.kt
+++ b/app/src/main/java/by/esas/tools/inject/builder/ActivityBuilder.kt
@@ -1,12 +1,12 @@
package by.esas.tools.inject.builder
-import by.esas.tools.MainActivity
+import by.esas.tools.screens.MainActivity
import dagger.Module
import dagger.android.ContributesAndroidInjector
-
@Module
abstract class ActivityBuilder {
+
@ContributesAndroidInjector(modules = [FragmentBuilder::class])
abstract fun bindMainActivity(): MainActivity
}
diff --git a/app/src/main/java/by/esas/tools/inject/builder/FragmentBuilder.kt b/app/src/main/java/by/esas/tools/inject/builder/FragmentBuilder.kt
index 41ef6aa7..f6a6111d 100644
--- a/app/src/main/java/by/esas/tools/inject/builder/FragmentBuilder.kt
+++ b/app/src/main/java/by/esas/tools/inject/builder/FragmentBuilder.kt
@@ -1,11 +1,148 @@
package by.esas.tools.inject.builder
+import by.esas.tools.screens.access_container.AccessContainerFragment
+import by.esas.tools.screens.baseui.navigation.BaseUINavigationFragment
+import by.esas.tools.screens.baseui.navigation.BaseUINavigationSecondFragment
+import by.esas.tools.screens.baseui.other.BaseUIFunctionalityFragment
+import by.esas.tools.screens.baseui.ui.BaseUIThemeFragment
+import by.esas.tools.screens.biometric.BiometricDecryptionFragment
+import by.esas.tools.screens.cardline.CardlineFragment
+import by.esas.tools.screens.cardline.dynamic.DynamicCardlineFragment
+import by.esas.tools.screens.checker.CheckerInputFieldFragment
+import by.esas.tools.screens.custom_switch.CustomSwitchFragment
+import by.esas.tools.screens.custom_switch.program.CustomSwitchProgramFragment
+import by.esas.tools.screens.dialog.DynamicMessageDialogFragment
+import by.esas.tools.screens.dialog.bottom_dialog.BottomDialogFragment
+import by.esas.tools.screens.domain.DomainCaseFragment
+import by.esas.tools.screens.inputfield_view.end_icon.InputfieldViewEndIconFragment
+import by.esas.tools.screens.inputfield_view.input_field.InputfieldViewFragment
+import by.esas.tools.screens.inputfield_view.start_icon.InputfieldViewStartIconFragment
+import by.esas.tools.screens.listheader.ListheaderFragment
+import by.esas.tools.screens.listheader.dynamic.DynamicListheaderFragment
+import by.esas.tools.screens.logger.LoggerFragment
+import by.esas.tools.screens.menu.MenuFragment
+import by.esas.tools.screens.numpad.NumpadImageFragment
+import by.esas.tools.screens.numpad.numpad_text.NumpadTextFragment
+import by.esas.tools.screens.pin_view.PinViewFragment
+import by.esas.tools.screens.pin_view.dynamic.DynamicPinViewFragment
+import by.esas.tools.screens.recycler.base.RecyclerFragment
+import by.esas.tools.screens.recycler.custom.CustomRecyclerFragment
+import by.esas.tools.screens.recycler.simple.SimpleRecyclerFragment
+import by.esas.tools.screens.recycler.sticky_case.StickyCaseFragment
+import by.esas.tools.screens.saved_state_vm.SavedStateFragment
+import by.esas.tools.screens.timeparser.TimeParserFragment
+import by.esas.tools.screens.topbar.TopbarFragment
+import by.esas.tools.screens.util.UtilKeyboardFragment
+import by.esas.tools.screens.util.switchManager.UtilSwitchManagerFragment
+import by.esas.tools.screens.util.utils.UtilsFragment
import dagger.Module
+import dagger.android.ContributesAndroidInjector
@Module
abstract class FragmentBuilder {
- /* @ContributesAndroidInjector
- abstract fun bindLoadingFragment(): LoadingFragment*/
+ @ContributesAndroidInjector
+ abstract fun bindMenuFragment(): MenuFragment
+ @ContributesAndroidInjector
+ abstract fun bindPinViewFragment(): PinViewFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindDynamicPinViewFragment(): DynamicPinViewFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindSavedStateFragment(): SavedStateFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindNumpadImageFragment(): NumpadImageFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindUtilKeyboardFragment(): UtilKeyboardFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindUtilsFragment(): UtilsFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindUtilSwitchManagerFragment(): UtilSwitchManagerFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindListheaderFragment(): ListheaderFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindDynamicListheaderFragment(): DynamicListheaderFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindCustomSwitchFragment(): CustomSwitchFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindCustomSwitchProgramFragment(): CustomSwitchProgramFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindTopbarFragment(): TopbarFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindCardlineFragment(): CardlineFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindDynamicCardlineFragment(): DynamicCardlineFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindDynamicMessageDialogFragment(): DynamicMessageDialogFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindBottomDialogFragment(): BottomDialogFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindInputfieldViewFragment(): InputfieldViewFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindInputfieldViewEndIconFragment(): InputfieldViewEndIconFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindInputfieldViewStartIconFragment(): InputfieldViewStartIconFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindNumpadTextFragment(): NumpadTextFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindBaseUINavigationFragment(): BaseUINavigationFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindBaseUINavigationSecondFragment(): BaseUINavigationSecondFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindBaseUIFunctionalityFragment(): BaseUIFunctionalityFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindBaseUIThemeFragment(): BaseUIThemeFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindDomainCaseFragment(): DomainCaseFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindRecyclerFragment(): RecyclerFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindStickyCaseFragment(): StickyCaseFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindSimpleRecyclerFragment(): SimpleRecyclerFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindCustomRecyclerFragment(): CustomRecyclerFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindCheckerInputFieldFragment(): CheckerInputFieldFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindBiometricDecryptionFragment(): BiometricDecryptionFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindTimeParserFragment(): TimeParserFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindLoggerFragment(): LoggerFragment
+
+ @ContributesAndroidInjector
+ abstract fun bindAccessContainerFragment(): AccessContainerFragment
}
diff --git a/app/src/main/java/by/esas/tools/inject/builder/RepositoryBuilder.kt b/app/src/main/java/by/esas/tools/inject/builder/RepositoryBuilder.kt
index 63bea2e3..1005dbd1 100644
--- a/app/src/main/java/by/esas/tools/inject/builder/RepositoryBuilder.kt
+++ b/app/src/main/java/by/esas/tools/inject/builder/RepositoryBuilder.kt
@@ -1,13 +1,11 @@
package by.esas.tools.inject.builder
-import dagger.Binds
import dagger.Module
-
@Module
abstract class RepositoryBuilder {
- /* @Binds
- abstract fun bindsAppRepository(repository: AppRepository): IAppRepository*/
+ /* @Binds
+ abstract fun bindsAppRepository(repository: AppRepository): IAppRepository*/
}
diff --git a/app/src/main/java/by/esas/tools/inject/builder/ViewModelBuilder.kt b/app/src/main/java/by/esas/tools/inject/builder/ViewModelBuilder.kt
index 1d082a76..d37fbaec 100644
--- a/app/src/main/java/by/esas/tools/inject/builder/ViewModelBuilder.kt
+++ b/app/src/main/java/by/esas/tools/inject/builder/ViewModelBuilder.kt
@@ -1,15 +1,48 @@
package by.esas.tools.inject.builder
import androidx.lifecycle.ViewModel
-import by.esas.tools.AddInvoiceViewModel
-import by.esas.tools.basedaggerui.inject.qualifier.ViewModelKey
-import by.esas.tools.MainVM
-import by.esas.tools.basedaggerui.inject.factory.AssistedSavedStateViewModelFactory
+import by.esas.tools.basedaggerui.factory.AssistedSavedStateViewModelFactory
+import by.esas.tools.basedaggerui.qualifier.ViewModelKey
+import by.esas.tools.screens.MainVM
+import by.esas.tools.screens.access_container.AccessContainerVM
+import by.esas.tools.screens.baseui.navigation.BaseUINavigationSecondVM
+import by.esas.tools.screens.baseui.navigation.BaseUINavigationVM
+import by.esas.tools.screens.baseui.other.BaseUIFunctionalityVM
+import by.esas.tools.screens.baseui.ui.BaseUIThemeVM
+import by.esas.tools.screens.biometric.BiometricDecryptionVM
+import by.esas.tools.screens.cardline.CardlineVM
+import by.esas.tools.screens.cardline.dynamic.DynamicCardlineVM
+import by.esas.tools.screens.checker.CheckerInputFieldVM
+import by.esas.tools.screens.custom_switch.CustomSwitchVM
+import by.esas.tools.screens.custom_switch.program.CustomSwitchProgramVM
+import by.esas.tools.screens.dialog.DynamicMessageDialogVM
+import by.esas.tools.screens.dialog.bottom_dialog.BottomDialogVM
+import by.esas.tools.screens.domain.DomainCaseVM
+import by.esas.tools.screens.inputfield_view.end_icon.InputfieldViewEndIconVM
+import by.esas.tools.screens.inputfield_view.input_field.InputfieldViewVM
+import by.esas.tools.screens.inputfield_view.start_icon.InputfieldViewStartIconVM
+import by.esas.tools.screens.listheader.ListheaderVM
+import by.esas.tools.screens.listheader.dynamic.DynamicListheaderVM
+import by.esas.tools.screens.logger.LoggerVM
+import by.esas.tools.screens.menu.MenuVM
+import by.esas.tools.screens.numpad.NumpadImageVM
+import by.esas.tools.screens.numpad.numpad_text.NumpadTextVM
+import by.esas.tools.screens.pin_view.PinViewVM
+import by.esas.tools.screens.pin_view.dynamic.DynamicPinViewVM
+import by.esas.tools.screens.recycler.base.RecyclerVM
+import by.esas.tools.screens.recycler.custom.CustomRecyclerVM
+import by.esas.tools.screens.recycler.simple.SimpleRecyclerVM
+import by.esas.tools.screens.recycler.sticky_case.StickyCaseVM
+import by.esas.tools.screens.saved_state_vm.SavedStateVM
+import by.esas.tools.screens.timeparser.TimeParserVM
+import by.esas.tools.screens.topbar.TopbarVM
+import by.esas.tools.screens.util.UtilKeyboardVM
+import by.esas.tools.screens.util.switchManager.UtilSwitchManagerVM
+import by.esas.tools.screens.util.utils.UtilsVM
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
-
@Module
abstract class ViewModelBuilder {
@@ -20,6 +53,176 @@ abstract class ViewModelBuilder {
@Binds
@IntoMap
- @ViewModelKey(AddInvoiceViewModel::class)
- abstract fun bindVMFactory(f: AddInvoiceViewModel.Factory): AssistedSavedStateViewModelFactory
+ @ViewModelKey(MenuVM::class)
+ abstract fun bindMenuViewModel(menuViewModel: MenuVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(PinViewVM::class)
+ abstract fun bindPinViewVM(pinViewVM: PinViewVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(DynamicPinViewVM::class)
+ abstract fun bindDynamicPinViewVM(dynamicPinViewVM: DynamicPinViewVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(NumpadImageVM::class)
+ abstract fun bindNumpadImageVM(numpadImageVM: NumpadImageVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(UtilKeyboardVM::class)
+ abstract fun bindUtilKeyboardVM(utilKeyboardVM: UtilKeyboardVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(UtilsVM::class)
+ abstract fun bindUtilsVM(utilsVM: UtilsVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(UtilSwitchManagerVM::class)
+ abstract fun bindUtilSwitchManagerVM(utilSwitchManagerVM: UtilSwitchManagerVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(ListheaderVM::class)
+ abstract fun bindListheaderVM(listheaderVM: ListheaderVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(DynamicListheaderVM::class)
+ abstract fun bindDynamicListheaderVM(dynamicListheaderVM: DynamicListheaderVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(CustomSwitchVM::class)
+ abstract fun bindCustomSwitchVM(customSwitchVM: CustomSwitchVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(CustomSwitchProgramVM::class)
+ abstract fun bindCustomSwitchProgramVM(customSwitchProgramVM: CustomSwitchProgramVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(TopbarVM::class)
+ abstract fun bindTopbarVM(topbarVM: TopbarVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(CardlineVM::class)
+ abstract fun bindCardlineVM(cardlineVM: CardlineVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(DynamicCardlineVM::class)
+ abstract fun bindDynamicCardlineVM(dynamicCardlineVM: DynamicCardlineVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(DynamicMessageDialogVM::class)
+ abstract fun bindDynamicMessageDialogVM(dynamicMessageDialogVM: DynamicMessageDialogVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(BottomDialogVM::class)
+ abstract fun bindBottomDialogVM(bottomDialogVM: BottomDialogVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(InputfieldViewEndIconVM::class)
+ abstract fun bindInputfieldViewEndIconVM(inputfieldViewEndIconVM: InputfieldViewEndIconVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(InputfieldViewVM::class)
+ abstract fun bindInputfieldViewVM(inputfieldViewVM: InputfieldViewVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(InputfieldViewStartIconVM::class)
+ abstract fun bindInputfieldViewStartIconVM(inputfieldViewStartIconVM: InputfieldViewStartIconVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(NumpadTextVM::class)
+ abstract fun bindNumpadTextVM(numpadTextVM: NumpadTextVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(BaseUINavigationSecondVM::class)
+ abstract fun bindBaseUINavigationSecondVM(baseUINavigationSecondVM: BaseUINavigationSecondVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(BaseUINavigationVM::class)
+ abstract fun bindBaseUINavigationVM(baseUINavigationVM: BaseUINavigationVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(BaseUIFunctionalityVM::class)
+ abstract fun bindBaseUIFunctionalityVM(baseUIFunctionalityVM: BaseUIFunctionalityVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(BaseUIThemeVM::class)
+ abstract fun bindBaseUIThemeVM(baseUIThemeVM: BaseUIThemeVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(DomainCaseVM::class)
+ abstract fun bindDomainCaseVM(domainCaseVM: DomainCaseVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(CheckerInputFieldVM::class)
+ abstract fun bindCheckerInputFieldVM(сheckerInputFieldVM: CheckerInputFieldVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(BiometricDecryptionVM::class)
+ abstract fun bindBiometricDecryptionVM(biometricDecryptionVM: BiometricDecryptionVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(SavedStateVM::class)
+ abstract fun bindVMFactory(f: SavedStateVM.Factory): AssistedSavedStateViewModelFactory
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(RecyclerVM::class)
+ abstract fun bindRecyclerVM(viewModel: RecyclerVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(StickyCaseVM::class)
+ abstract fun bindStickyCaseVM(viewModel: StickyCaseVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(SimpleRecyclerVM::class)
+ abstract fun bindSimpleRecyclerVM(viewModel: SimpleRecyclerVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(CustomRecyclerVM::class)
+ abstract fun bindCustomRecyclerVM(viewModel: CustomRecyclerVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(TimeParserVM::class)
+ abstract fun bindTimeParserVM(viewModel: TimeParserVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(LoggerVM::class)
+ abstract fun bindLoggerVM(viewModel: LoggerVM): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(AccessContainerVM::class)
+ abstract fun bindAccessContainerVM(viewModel: AccessContainerVM): ViewModel
}
diff --git a/app/src/main/java/by/esas/tools/inject/builder/ViewModelFactoryBuilder.kt b/app/src/main/java/by/esas/tools/inject/builder/ViewModelFactoryBuilder.kt
index faa1bf15..5416dc8f 100644
--- a/app/src/main/java/by/esas/tools/inject/builder/ViewModelFactoryBuilder.kt
+++ b/app/src/main/java/by/esas/tools/inject/builder/ViewModelFactoryBuilder.kt
@@ -1,11 +1,10 @@
package by.esas.tools.inject.builder
import androidx.lifecycle.ViewModelProvider
-import by.esas.tools.basedaggerui.inject.factory.ViewModelFactory
+import by.esas.tools.basedaggerui.factory.ViewModelFactory
import dagger.Binds
import dagger.Module
-
@Module(
includes = [
(RepositoryBuilder::class),
diff --git a/app/src/main/java/by/esas/tools/inject/component/AppComponent.kt b/app/src/main/java/by/esas/tools/inject/component/AppComponent.kt
index c4310db2..5058ef7c 100644
--- a/app/src/main/java/by/esas/tools/inject/component/AppComponent.kt
+++ b/app/src/main/java/by/esas/tools/inject/component/AppComponent.kt
@@ -11,7 +11,6 @@ import dagger.android.AndroidInjector
import dagger.android.support.AndroidSupportInjectionModule
import javax.inject.Singleton
-
@Singleton
@Component(
modules = [
@@ -26,6 +25,7 @@ interface AppComponent : AndroidInjector {
@Suppress("UNCHECKED_CAST")
@Component.Builder
interface Builder {
+
@BindsInstance
fun application(application: Application): Builder
diff --git a/app/src/main/java/by/esas/tools/inject/module/ContextModule.kt b/app/src/main/java/by/esas/tools/inject/module/ContextModule.kt
index 9d26f589..3e2ab9b3 100644
--- a/app/src/main/java/by/esas/tools/inject/module/ContextModule.kt
+++ b/app/src/main/java/by/esas/tools/inject/module/ContextModule.kt
@@ -2,12 +2,11 @@ package by.esas.tools.inject.module
import android.app.Application
import android.content.Context
-import by.esas.tools.error_mapper.AppErrorMapper
-import by.esas.tools.error_mapper.AppErrorStatusEnum
+import by.esas.tools.app_domain.error_mapper.AppErrorMapper
import by.esas.tools.inject.builder.ViewModelFactoryBuilder
-import by.esas.tools.logger.ErrorModel
import by.esas.tools.logger.ILogger
-import by.esas.tools.logger.LoggerImpl
+import by.esas.tools.utils.logger.ErrorModel
+import by.esas.tools.utils.logger.LoggerImpl
import com.squareup.moshi.Moshi
import dagger.Module
import dagger.Provides
@@ -15,7 +14,6 @@ import kotlinx.coroutines.Dispatchers
import javax.inject.Singleton
import kotlin.coroutines.CoroutineContext
-
@Module(
includes = [
ViewModelFactoryBuilder::class
@@ -35,12 +33,12 @@ class ContextModule {
@Provides
@Singleton
- fun provideCrashlyticsMapper(moshi: Moshi, logger: ILogger): AppErrorMapper {
+ fun provideErrorMapper(moshi: Moshi, logger: ILogger): AppErrorMapper {
return AppErrorMapper(moshi, logger)
}
@Provides
- fun provideLogger(): ILogger {
+ fun provideLogger(): ILogger {
return LoggerImpl().apply { setTag("LoggerImpl") }
}
}
diff --git a/app/src/main/java/by/esas/tools/inject/module/NetworkModule.kt b/app/src/main/java/by/esas/tools/inject/module/NetworkModule.kt
index f2730c2a..9c363eed 100644
--- a/app/src/main/java/by/esas/tools/inject/module/NetworkModule.kt
+++ b/app/src/main/java/by/esas/tools/inject/module/NetworkModule.kt
@@ -1,43 +1,16 @@
package by.esas.tools.inject.module
import android.content.Context
+import by.esas.tools.app_data.db.AppDataBase
+import by.esas.tools.app_data.db.dao.CaseStatusDao
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import dagger.Module
import dagger.Provides
-import okhttp3.OkHttpClient
-import retrofit2.Retrofit
-import java.util.concurrent.TimeUnit
import javax.inject.Singleton
@Module
class NetworkModule {
- /* @Provides
- @Singleton
- fun providesRetrofit(
- moshiConverterFactory: MoshiConverterFactory,
- okHttpClient: OkHttpClient
- ): Retrofit.Builder {
- return Retrofit.Builder()
- .addConverterFactory(moshiConverterFactory)
- .addCallAdapterFactory(CoroutineCallAdapterFactory())
- .client(okHttpClient)
- }
-
- @Provides
- @Singleton
- fun providesOkHttpClient(logger: ILogger): OkHttpClient {
- val client = OkHttpClient.Builder()
- // .cache(cache)
- .connectTimeout(30, TimeUnit.SECONDS)
- .writeTimeout(30, TimeUnit.SECONDS)
- .readTimeout(30, TimeUnit.SECONDS)
- val interceptor = HttpLoggingInterceptor()
- interceptor.level = HttpLoggingInterceptor.Level.BODY
- client.addNetworkInterceptor(interceptor)
- val tlsSupportingClient = enableTls12On(client = client, logger = logger)
- return tlsSupportingClient.build()
- }*/
@Provides
@Singleton
@@ -47,6 +20,43 @@ class NetworkModule {
.build()
}
+ /*############ Data Base ############*/
+
+ @Singleton
+ @Provides
+ fun provideAppDataBase(context: Context): AppDataBase = AppDataBase.getInstance(context)
+
+ @Singleton
+ @Provides
+ fun provideCaseStatusDao(appDataBase: AppDataBase): CaseStatusDao = appDataBase.getCaseStatusDao()
+
+ /* @Provides
+ @Singleton
+ fun providesRetrofit(
+ moshiConverterFactory: MoshiConverterFactory,
+ okHttpClient: OkHttpClient
+ ): Retrofit.Builder {
+ return Retrofit.Builder()
+ .addConverterFactory(moshiConverterFactory)
+ .addCallAdapterFactory(CoroutineCallAdapterFactory())
+ .client(okHttpClient)
+ }
+
+ @Provides
+ @Singleton
+ fun providesOkHttpClient(logger: ILogger): OkHttpClient {
+ val client = OkHttpClient.Builder()
+ // .cache(cache)
+ .connectTimeout(30, TimeUnit.SECONDS)
+ .writeTimeout(30, TimeUnit.SECONDS)
+ .readTimeout(30, TimeUnit.SECONDS)
+ val interceptor = HttpLoggingInterceptor()
+ interceptor.level = HttpLoggingInterceptor.Level.BODY
+ client.addNetworkInterceptor(interceptor)
+ val tlsSupportingClient = enableTls12On(client = client, logger = logger)
+ return tlsSupportingClient.build()
+ }*/
+
/*@Provides
@Singleton
fun providesMoshiConverterFactory(moshi: Moshi): MoshiConverterFactory {
@@ -58,12 +68,10 @@ class NetworkModule {
fun provideSharedPrefs(context: Context): AppSharedPrefs {
return AppSharedPrefs(context)
}*/
-
-
}
- /* @Provides
- @Singleton
- fun providesTrustManagerFactory(context: Context): TrustManagerFactory {
- return createTrustManager(context)
- }*/
\ No newline at end of file
+/* @Provides
+ @Singleton
+ fun providesTrustManagerFactory(context: Context): TrustManagerFactory {
+ return createTrustManager(context)
+ }*/
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/logger/ErrorModel.kt b/app/src/main/java/by/esas/tools/logger/ErrorModel.kt
deleted file mode 100644
index ad2a1212..00000000
--- a/app/src/main/java/by/esas/tools/logger/ErrorModel.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package by.esas.tools.logger
-
-import by.esas.tools.error_mapper.AppErrorStatusEnum
-
-class ErrorModel(code: Int, statusEnum: AppErrorStatusEnum) : BaseErrorModel(code, statusEnum)
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/logger/LoggerImpl.kt b/app/src/main/java/by/esas/tools/logger/LoggerImpl.kt
deleted file mode 100644
index ff72a731..00000000
--- a/app/src/main/java/by/esas/tools/logger/LoggerImpl.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package by.esas.tools.logger
-
-import android.util.Log
-import by.esas.tools.error_mapper.AppErrorStatusEnum
-
-class LoggerImpl : ILogger {
- var baseTag: String = "LoggerImpl"
- override fun setTag(tag: String) {
- this.baseTag = tag
- }
-
- override fun showMessage(msg: String, length: Int) {
-
- }
-
- override fun showMessage(msgRes: Int, length: Int) {
-
- }
-
- override fun logLocally(msg: String) {
- Log.w(baseTag, msg)
- }
-
- override fun log(msg: String) {
- Log.w(baseTag, msg)
- }
-
- override fun log(tag: String, msg: String, level: Int) {
- Log.w(baseTag, msg)
- }
-
- override fun logError(throwable: Throwable) {
- Log.e(baseTag, throwable.message, throwable)
- }
-
- override fun logError(msg: String) {
- Log.e(baseTag, msg)
- }
-
- override fun logInfo(msg: String) {
- Log.i(baseTag, msg)
- }
-
- override fun sendLogs(msg: String) {
-
- }
-
- override fun logError(error: ErrorModel) {
- Log.e(baseTag, error.statusEnum.name)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/screens/MainActivity.kt b/app/src/main/java/by/esas/tools/screens/MainActivity.kt
new file mode 100644
index 00000000..9d9ee168
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/screens/MainActivity.kt
@@ -0,0 +1,167 @@
+package by.esas.tools.screens
+
+import android.os.Bundle
+import android.view.Gravity
+import android.view.MotionEvent
+import android.widget.PopupMenu
+import androidx.core.os.bundleOf
+import androidx.fragment.app.FragmentResultListener
+import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.NavController
+import androidx.navigation.Navigation
+import by.esas.tools.R
+import by.esas.tools.base.AppActivity
+import by.esas.tools.baseui.Config.ERROR_MESSAGE_DIALOG
+import by.esas.tools.databinding.ActivityMainBinding
+import by.esas.tools.dialog.MessageDialog
+import by.esas.tools.logger.Action
+import by.esas.tools.screens.menu.MenuFragment
+import by.esas.tools.topbarview.ITopbarHandler
+
+/**
+ * To use HasAndroidInjector with Activity do not forget to add
+ * AndroidInjection.inject(this)
+ * in the fun onCreate(savedInstanceState: Bundle?)
+ *
+ * To use HasAndroidInjector with Fragment do not forget to add
+ * override fun onAttach(context: Context) {
+ * AndroidSupportInjection.inject(this)
+ * super.onAttach(context)
+ * }
+ */
+class MainActivity : AppActivity() {
+
+ companion object {
+
+ const val NEED_TO_UPDATE_MENU: String = "NEED_TO_UPDATE_MENU"
+ const val NEED_TO_UPDATE_CURRENT_CASE: String = "NEED_TO_UPDATE_CURRENT_CASE"
+ const val CURRENT_CASE_ID: String = "CURRENT_CASE_ID"
+ }
+
+ lateinit var navController: NavController
+ lateinit var popupMenu: PopupMenu
+ private var topDestination = R.id.menuFragment
+
+ override fun provideViewModel(): MainVM {
+ return ViewModelProvider(this, viewModelFactory.provideFactory()).get(MainVM::class.java)
+ }
+
+ override fun provideLayoutId(): Int {
+ return R.layout.activity_main
+ }
+
+ override fun provideRequestKeys(): List {
+ return listOf(ERROR_MESSAGE_DIALOG, MainVM.CASE_STATUS_DIALOG, MainVM.CLEAR_CASES_TEST_DATA_DIALOG)
+ }
+
+ override fun provideFragmentResultListener(requestKey: String): FragmentResultListener? {
+ return when (requestKey) {
+ //REMEMBER we can register result listener for CLEAR_CASES_TEST_DATA_DIALOG
+ // in MenuFragment so it will receive the result right away
+ MainVM.CASE_STATUS_DIALOG -> {
+ FragmentResultListener { key, result ->
+ val actionName = result.getString(by.esas.tools.dialog.Config.DIALOG_USER_ACTION)
+ result.putString(MainVM.DIALOG_KEY, key)
+ if (!actionName.isNullOrBlank()) {
+ viewModel.handleAction(Action(actionName, result))
+ } else {
+ viewModel.enableControls()
+ }
+ }
+ }
+ MainVM.CLEAR_CASES_TEST_DATA_DIALOG -> {
+ FragmentResultListener { _, result ->
+ val actionName = result.getString(by.esas.tools.dialog.Config.DIALOG_USER_ACTION)
+ if (actionName == MessageDialog.USER_ACTION_POSITIVE_CLICKED)
+ supportFragmentManager.setFragmentResult(
+ MenuFragment.MENU_UPDATE,
+ bundleOf(Pair(MenuFragment.MENU_UPDATE, MenuFragment.MENU_UPDATE_KEY_CLEAR))
+ )
+ }
+ }
+ else -> {
+ super.provideFragmentResultListener(requestKey)
+ }
+ }
+ }
+
+ override fun handleAction(action: Action): Boolean {
+ when (action.name) {
+ NEED_TO_UPDATE_MENU -> {
+ val bundle = Bundle()
+ bundle.putBoolean(NEED_TO_UPDATE_MENU, true)
+ intent.putExtras(bundle)
+ }
+ NEED_TO_UPDATE_CURRENT_CASE -> {
+ val newId = action.parameters?.getInt(CURRENT_CASE_ID) ?: -1
+ viewModel.currentCaseId = newId
+ }
+ else -> return super.handleAction(action)
+ }
+ return true
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setupNavigation()
+ setupSettingsMenu()
+
+ binding.aMainTopBar.setupHandler(object : ITopbarHandler {
+ override fun onNavigationClick() {
+ onBackPressed()
+ }
+
+ override fun onActionClick() {
+ navController.currentDestination?.let {
+ if (it.id == topDestination)
+ popupMenu.show()
+ else
+ viewModel.openCaseStatusDialog(it.label.toString())
+ }
+ }
+ })
+ }
+
+ override fun setupObservers() {
+ super.setupObservers()
+
+ viewModel.updateMenuLive.observe(this) {
+ handleAction(Action(NEED_TO_UPDATE_MENU))
+ }
+ }
+
+ override fun handleTouchOutOfInputField(event: MotionEvent) {
+ if (event.action == MotionEvent.ACTION_DOWN && navController.currentDestination?.id != R.id.utilKeyboardFragment) {
+ super.handleTouchOutOfInputField(event)
+ }
+ }
+
+ private fun setupNavigation() {
+ navController = Navigation.findNavController(this, R.id.a_main_nav_host_fragment)
+ navController.addOnDestinationChangedListener { _, destination, _ ->
+ if (destination.id == topDestination) viewModel.currentCaseId = -1
+ viewModel.hasBackBtn.set(destination.id != topDestination)
+ viewModel.hasSettingsBtn.set(destination.id == topDestination)
+ viewModel.title.set(destination.label.toString())
+ binding.aMainTopBar.setEndActionViewVisibility(viewModel.currentCaseId != -1)
+ }
+ }
+
+ private fun setupSettingsMenu() {
+ popupMenu = PopupMenu(this, binding.aMainTopBar, Gravity.END)
+ popupMenu.inflate(R.menu.settings_menu)
+ popupMenu.setOnMenuItemClickListener { menuItem ->
+ return@setOnMenuItemClickListener when (menuItem.itemId) {
+ R.id.menuUiSettings -> {
+ navController.navigate(R.id.baseuiThemeFragment)
+ true
+ }
+ R.id.menuUpdateTest -> {
+ viewModel.openClearCasesTestDataDialog()
+ true
+ }
+ else -> false
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/by/esas/tools/screens/MainVM.kt b/app/src/main/java/by/esas/tools/screens/MainVM.kt
new file mode 100644
index 00000000..f710ad61
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/screens/MainVM.kt
@@ -0,0 +1,99 @@
+package by.esas.tools.screens
+
+import android.os.Bundle
+import androidx.databinding.ObservableBoolean
+import androidx.databinding.ObservableField
+import androidx.lifecycle.MutableLiveData
+import by.esas.tools.App
+import by.esas.tools.R
+import by.esas.tools.app_domain.usecase.AddCaseStatusUseCase
+import by.esas.tools.base.AppVM
+import by.esas.tools.dialog.MessageDialog
+import by.esas.tools.entity.TestStatusEnum
+import by.esas.tools.logger.Action
+import javax.inject.Inject
+
+class MainVM @Inject constructor(
+ private val addCaseStatus: AddCaseStatusUseCase
+) : AppVM() {
+
+ companion object {
+
+ const val CASE_STATUS_DIALOG = "CASE_STATUS_DIALOG"
+ const val CLEAR_CASES_TEST_DATA_DIALOG = "CLEAR_CASES_TEST_DATA_DIALOG"
+ const val DIALOG_KEY = "DIALOG_KEY"
+ }
+
+ override fun handleAction(action: Action?): Boolean {
+ val dialogKey = action?.parameters?.getString(DIALOG_KEY)
+ val actionName = action?.name
+ if (dialogKey == CASE_STATUS_DIALOG && actionName == MessageDialog.USER_ACTION_ITEM_PICKED) {
+ getStatusAndUpdate(action.parameters)
+ } else
+ return super.handleAction(action)
+
+ return true
+ }
+
+ val updateMenuLive = MutableLiveData()
+
+ val hasBackBtn = ObservableBoolean(false)
+ val hasSettingsBtn = ObservableBoolean(true)
+ val title = ObservableField(App.appContext.resources.getString(R.string.menu))
+ var currentCaseId = -1
+
+ fun openCaseStatusDialog(caseLabel: String) {
+ val dialog = MessageDialog()
+ dialog.setRequestKey(CASE_STATUS_DIALOG)
+ dialog.setNegativeButton(R.string.cancel)
+ dialog.setTitle(R.string.case_status_dialog_title)
+ dialog.setMessage(
+ App.appContext.getString(R.string.case_status_dialog_message)
+ .format(caseLabel)
+ )
+ dialog.setItems(
+ listOf(
+ makeItemInfo(TestStatusEnum.CHECKED, R.string.case_status_checked),
+ makeItemInfo(TestStatusEnum.FAILED, R.string.case_status_failed),
+ makeItemInfo(TestStatusEnum.IN_PROCESS, R.string.case_status_in_process),
+ makeItemInfo(TestStatusEnum.UNCHECKED, R.string.case_status_unchecked)
+ )
+ )
+
+ showDialog(dialog)
+ }
+
+ fun openClearCasesTestDataDialog() {
+ val dialog = MessageDialog()
+ dialog.setRequestKey(CLEAR_CASES_TEST_DATA_DIALOG)
+ dialog.setPositiveButton(R.string.clear)
+ dialog.setNegativeButton(R.string.cancel)
+ dialog.setTitle(R.string.case_clear_all_dialog_title)
+ dialog.setMessage(R.string.case_clear_all_dialog_message)
+
+ showDialog(dialog)
+ }
+
+ private fun makeItemInfo(status: TestStatusEnum, resId: Int): MessageDialog.ItemInfo {
+ return MessageDialog.ItemInfo(status.name, App.appContext.getString(resId))
+ }
+
+ private fun getStatusAndUpdate(parameters: Bundle?) {
+ val code = parameters?.getString(MessageDialog.ITEM_CODE) ?: ""
+ val status = try {
+ TestStatusEnum.valueOf(code)
+ } catch (e: IllegalArgumentException) {
+ TestStatusEnum.UNCHECKED
+ }
+ //REMEMBER to execute usecase only in case that status is new to this case
+ addCaseStatus.caseId = currentCaseId
+ addCaseStatus.caseStatus = status
+ addCaseStatus.execute {
+ onComplete {
+ logger.showMessage(R.string.case_status_is_changed)
+ updateMenuLive.postValue(true)
+ }
+ onError { handleError(it) }
+ }
+ }
+}
diff --git a/app/src/main/java/by/esas/tools/screens/access_container/AccessContainerFragment.kt b/app/src/main/java/by/esas/tools/screens/access_container/AccessContainerFragment.kt
new file mode 100644
index 00000000..2ade41fc
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/screens/access_container/AccessContainerFragment.kt
@@ -0,0 +1,97 @@
+package by.esas.tools.screens.access_container
+
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.FragmentResultListener
+import androidx.lifecycle.ViewModelProvider
+import by.esas.tools.R
+import by.esas.tools.accesscontainer.entity.AuthType
+import by.esas.tools.accesscontainer.entity.Token
+import by.esas.tools.base.AppFragment
+import by.esas.tools.biometric_decryption.checkBiometricSupport
+import by.esas.tools.databinding.FMainRefresherBinding
+import by.esas.tools.dialog.MessageDialog
+import by.esas.tools.getErrorMessage
+import by.esas.tools.logger.ILogger
+import by.esas.tools.logger.handler.ErrorHandler
+import by.esas.tools.util.TAGk
+import by.esas.tools.utils.logger.ErrorModel
+
+class AccessContainerFragment : AppFragment() {
+
+ companion object {
+
+ const val PREFERRED_TYPE_PICKER: String = "PREFERRED_TYPE_PICKER"
+ val DEFAULT_TOKEN: Token = Token("accessToken", "refreshToken")
+ }
+
+ override val fragmentDestinationId = R.id.accessContainerFragment
+
+ override fun provideLayoutId(): Int = R.layout.f_main_refresher
+
+ override fun provideViewModel(): AccessContainerVM {
+ return ViewModelProvider(
+ this,
+ viewModelFactory.provideFactory()
+ ).get(AccessContainerVM::class.java)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ viewModel.initialize()
+ viewModel.isBiometricAvailable.value =
+ activity?.applicationContext?.let {
+ checkBiometricSupport(it) { tag: String, msg: String ->
+ logger.logCategory(ILogger.CATEGORY_ERROR, tag, msg)
+ }
+ } ?: false
+
+ viewModel.refresher.setActivity(requireActivity())
+ viewModel.refresher.setUserId(viewModel.user)
+ viewModel.currentToken.value = DEFAULT_TOKEN.accessToken
+ viewModel.currentRefresh.value = DEFAULT_TOKEN.refreshToken
+ viewModel.provider.setToken(DEFAULT_TOKEN)
+ viewModel.refresher.setToken(DEFAULT_TOKEN)
+ }
+
+ override fun provideRequestKeys(): List {
+ return super.provideRequestKeys().plus(listOf(PREFERRED_TYPE_PICKER))
+ }
+
+ override fun provideFragmentResultListener(requestKey: String): FragmentResultListener? {
+ return if (requestKey == PREFERRED_TYPE_PICKER) {
+ FragmentResultListener { key, result ->
+ val actionName = result.getString(by.esas.tools.dialog.Config.DIALOG_USER_ACTION)
+ if (actionName == MessageDialog.USER_ACTION_ITEM_PICKED) {
+ val name = result.getString(MessageDialog.ITEM_NAME)
+ val code = result.getString(MessageDialog.ITEM_CODE) ?: AuthType.NONE.name
+ viewModel.preferredTypeText.value = name
+ viewModel.preferredType = AuthType.valueOf(code)
+ viewModel.enableControls()
+ } else {
+ viewModel.enableControls()
+ }
+ }
+ } else {
+ super.provideFragmentResultListener(requestKey)
+ }
+ }
+
+ override fun provideErrorHandler(): ErrorHandler {
+ logger.logInfo("provideErrorHandler")
+ return object : ErrorHandler() {
+
+ override fun getErrorMessage(error: ErrorModel): String {
+ return getErrorMessage(error.getStatusAsEnum(), null)
+ }
+
+ override fun getErrorMessage(e: Throwable): String {
+ return getErrorMessage(mapError(e))
+ }
+
+ override fun mapError(e: Throwable): ErrorModel {
+ return viewModel.provideMapper().mapErrorException(this.TAGk, e)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/screens/access_container/AccessContainerVM.kt b/app/src/main/java/by/esas/tools/screens/access_container/AccessContainerVM.kt
new file mode 100644
index 00000000..41df7c4e
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/screens/access_container/AccessContainerVM.kt
@@ -0,0 +1,230 @@
+package by.esas.tools.screens.access_container
+
+import androidx.lifecycle.MutableLiveData
+import by.esas.tools.App
+import by.esas.tools.R
+import by.esas.tools.accesscontainer.dialog.BiometricUserInfo
+import by.esas.tools.accesscontainer.entity.AuthType
+import by.esas.tools.accesscontainer.entity.Token
+import by.esas.tools.accesscontainer.support.ITypeManager
+import by.esas.tools.base.AppVM
+import by.esas.tools.dialog.MessageDialog
+import by.esas.tools.screens.access_container.utility.Container
+import by.esas.tools.screens.access_container.utility.Executor
+import by.esas.tools.screens.access_container.utility.SecretProvider
+import by.esas.tools.util.TAGk
+import by.esas.tools.utils.logger.LoggerImpl
+import javax.inject.Inject
+
+class AccessContainerVM @Inject constructor() : AppVM() {
+
+ init {
+ logger.setTag(AccessContainerVM::class.TAGk)
+ }
+
+ lateinit var refresher: Container
+ lateinit var provider: SecretProvider
+ var user: String = "user"
+ var preferredType: AuthType = AuthType.PIN_AUTH
+ val authTypes = listOf(AuthType.NONE, AuthType.PIN_AUTH, AuthType.BIOMETRIC_AUTH)
+
+ val preferredTypeText = MutableLiveData(getAuthTypeText(preferredType))
+ val currentToken = MutableLiveData("")
+ val currentRefresh = MutableLiveData("")
+ val correctPassword = MutableLiveData("12345678")
+ val pinAvailable = MutableLiveData(false)
+ val biomAvailable = MutableLiveData(false)
+ val refreshExplicitly = MutableLiveData(false)
+ val isBiometricAvailable = MutableLiveData(false)
+ val noToken = MutableLiveData(false)
+
+ val errorOnRefreshWithToken = MutableLiveData(false)
+ val errorOnGetSecrets = MutableLiveData(false)
+ val errorOnRefresh = MutableLiveData(false)
+ val errorOnRefreshWithSecret = MutableLiveData(false)
+ val errorOnCheckSecret = MutableLiveData(false)
+ val errorOnCreateSecret = MutableLiveData(false)
+
+ private var userIv: ByteArray = ByteArray(16)
+ private val containerLogger = LoggerImpl()
+
+ fun getAuthTypeText(type: AuthType): String {
+ val resId = when (type) {
+ AuthType.PIN_AUTH -> R.string.label_pin
+ AuthType.BIOMETRIC_AUTH -> R.string.label_biom
+ AuthType.NONE -> R.string.label_password
+ }
+ return App.appContext.getString(resId)
+ }
+
+ fun initialize() {
+ val executor = Executor(LoggerImpl())
+ provider = executor.provider
+ containerLogger.setTag("Container")
+ refresher = Container.getInstance(
+ logger = containerLogger,
+ appMapper = mapper,
+ executor = executor,
+ typeManager = provideTypeManager(),
+ userInfo = provideUserInfo()
+ )
+ }
+
+ fun onPickPreferredType() {
+ disableControls()
+ val dialog: MessageDialog = MessageDialog()
+ dialog.setRequestKey(AccessContainerFragment.PREFERRED_TYPE_PICKER)
+ dialog.setTitle(R.string.refresher_preferred_lable)
+ dialog.setItems(authTypes.map { MessageDialog.ItemInfo(it.name, getAuthTypeText(it)) })
+ dialog.isCancelable = true
+ showDialog(dialog)
+ }
+
+ fun onRefreshAccess() {
+ disableControls()
+ updateProvider()
+ refresher.refresh({
+ currentToken.value = it
+ currentRefresh.value = refresher.getRefresh()
+ showMessage("Refresh access result: $it")
+ enableControls()
+ }, {
+ handleError(it)
+ }, {
+ showMessage("Refresh access cancelled")
+ enableControls()
+ })
+ }
+
+ fun onCheckAccess() {
+ disableControls()
+ updateProvider()
+ refresher.checkAccess(refreshExplicitly.value ?: false) {
+ onComplete {
+ currentToken.value = it
+ currentRefresh.value = refresher.getRefresh()
+ showMessage("Check access result: $it")
+ enableControls()
+ }
+ onError {
+ handleError(it)
+ }
+ onCancel {
+ showMessage("Check access cancelled")
+ enableControls()
+ }
+ onCancellation {
+ handleError(it)
+ }
+ }
+ }
+
+ fun onGetSecret() {
+ disableControls()
+ updateProvider()
+ refresher.getSecret {
+ onComplete {
+ showMessage("Get secret result: $it")
+ enableControls()
+ }
+ onError {
+ handleError(it)
+ }
+ onCancel {
+ showMessage("Get secret cancelled")
+ enableControls()
+ }
+ onCancellation {
+ handleError(it)
+ }
+ }
+ }
+
+ fun onSaveRefresh() {
+ disableControls()
+ updateProvider()
+ refresher.saveRefresh("newRefresh") {
+ onComplete {
+ currentToken.value = it
+ currentRefresh.value = refresher.getRefresh()
+ showMessage("Save refresh token \"newRefresh\" result: $it")
+ enableControls()
+ }
+ onError {
+ handleError(it)
+ }
+ onCancel {
+ showMessage("Save refresh token cancelled")
+ enableControls()
+ }
+ onCancellation {
+ handleError(it)
+ }
+ }
+ }
+
+ private fun updateProvider() {
+ if (noToken.value == true) {
+ refresher.setToken(Token(currentToken.value ?: "", ""))
+ currentRefresh.value = ""
+ } else if (refresher.getRefresh().isBlank()) {
+ val token = provider.getCurrentToken()
+ refresher.setToken(token)
+ currentToken.value = token.accessToken
+ currentRefresh.value = token.refreshToken
+ }
+
+ val list = mutableListOf()
+ if (pinAvailable.value == true) {
+ list.add(AuthType.PIN_AUTH)
+ }
+ if (biomAvailable.value == true) {
+ list.add(AuthType.BIOMETRIC_AUTH)
+ }
+ provider.authTypes = list
+ provider.correctPassword = correctPassword.value.orEmpty()
+ provider.errorOnRefreshWithToken = errorOnRefreshWithToken.value ?: false
+ provider.errorOnGetSecrets = errorOnGetSecrets.value ?: false
+ provider.errorOnRefresh = errorOnRefresh.value ?: false
+ provider.errorOnRefreshWithSecret = errorOnRefreshWithSecret.value ?: false
+ provider.errorOnCheckSecret = errorOnCheckSecret.value ?: false
+ provider.errorOnCreateSecret = errorOnCreateSecret.value ?: false
+ }
+
+ private fun provideTypeManager(): ITypeManager {
+ return object : ITypeManager {
+ override fun getPreferredType(): AuthType {
+ // this way we can check refresher's behavior when there is not appropriate preferred type
+ return preferredType
+ }
+
+ override fun putPreferredType(type: AuthType) {
+ preferredTypeText.value = getAuthTypeText(type)
+ preferredType = type
+ }
+ }
+ }
+
+ private fun provideUserInfo(): BiometricUserInfo {
+ return object : BiometricUserInfo {
+ override fun getCurrentUser(): String {
+ return user
+ }
+
+ override fun setCurrentUserIv(iv: ByteArray) {
+ userIv = iv
+ }
+
+ override fun getCurrentUserIv(): ByteArray {
+ return userIv
+ }
+ }
+ }
+
+ private fun showMessage(msg: String) {
+ val dialog: MessageDialog = MessageDialog()
+ dialog.setMessage(msg)
+ dialog.isCancelable = true
+ showDialog(dialog)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/screens/access_container/dialog/PasswordDialog.kt b/app/src/main/java/by/esas/tools/screens/access_container/dialog/PasswordDialog.kt
new file mode 100644
index 00000000..7f3558b0
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/screens/access_container/dialog/PasswordDialog.kt
@@ -0,0 +1,159 @@
+package by.esas.tools.screens.access_container.dialog
+
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import androidx.databinding.ObservableBoolean
+import androidx.databinding.ObservableField
+import by.esas.tools.BR
+import by.esas.tools.R
+import by.esas.tools.checker.Checker
+import by.esas.tools.checker.Checking
+import by.esas.tools.databinding.DfPasswordBinding
+import by.esas.tools.dialog.BindingDialogFragment
+import by.esas.tools.dialog.Config
+import by.esas.tools.utils.checking.AppChecker
+
+class PasswordDialog : BindingDialogFragment() {
+
+ companion object {
+
+ const val USER_ACTION_PASSWORD_COMPLETED: String = "USER_ACTION_PASSWORD_COMPLETED"
+ const val RESULT_PASSWORD: String = "RESULT_PASSWORD"
+ const val USER_ACTION_ANOTHER_CLICKED: String = "USER_ACTION_ANOTHER_CLICKED"
+ const val USER_ACTION_FORGOT_CLICKED: String = "USER_ACTION_FORGOT_CLICKED"
+ }
+
+ override fun provideLayoutId(): Int {
+ return R.layout.df_password
+ }
+
+ override fun provideSwitchableList(): List {
+ return emptyList()
+ }
+
+ override fun provideValidationList(): List {
+ return emptyList()
+ }
+
+ override fun provideVariableId(): Int {
+ return BR.handler
+ }
+
+ val showForgotPassword = ObservableBoolean(false)
+ val showAnotherBtn = ObservableBoolean(false)
+ val btnEnabled = ObservableBoolean(false)
+ val password = ObservableField("")
+
+ private var titleRes: Int = R.string.label_password
+ private var showForgot: Boolean = false
+ private var showAnother: Boolean = false
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ outState.putBoolean("btnEnabled", btnEnabled.get())
+ outState.putString("password", password.get())
+ outState.putBoolean("showForgot", showForgot)
+ outState.putBoolean("showAnother", showAnother)
+ outState.putInt("titleRes", titleRes)
+ }
+
+ override fun onViewStateRestored(savedInstanceState: Bundle?) {
+ super.onViewStateRestored(savedInstanceState)
+ if (savedInstanceState != null) {
+ btnEnabled.set(savedInstanceState.getBoolean("btnEnabled", true))
+ showForgot = (savedInstanceState.getBoolean("showForgot", false))
+ showAnother = (savedInstanceState.getBoolean("showAnother", false))
+ password.set(savedInstanceState.getString("password", "") ?: "")
+ titleRes = (savedInstanceState.getInt("titleRes", R.string.label_password))
+ updateScreen()
+ }
+ }
+
+ override fun styleSettings() {
+ setStyle(STYLE_NO_FRAME, 0)
+ }
+
+ override fun layoutSettings() {
+ dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ updateScreen()
+ enableControls()
+ }
+
+ fun updateScreen() {
+ binding.dfPasswordTopBarTitle.setText(titleRes)
+
+ showAnotherBtn.set(showAnother)
+ showForgotPassword.set(showForgot)
+ }
+
+ fun onBackClick() {
+ disableControls()
+ resultBundle.clear()
+ resultBundle.putString(Config.DIALOG_USER_ACTION, Config.CANCEL_DIALOG)
+ dismiss()
+ }
+
+ fun onAnotherClick() {
+ disableControls()
+ resultBundle.clear()
+ resultBundle.putString(Config.DIALOG_USER_ACTION, USER_ACTION_ANOTHER_CLICKED)
+ dismiss()
+ enableControls()
+ }
+
+ fun onPasswordClick() {
+ disableControls()
+ validatePassword()
+ }
+
+ fun onForgotClick() {
+ disableControls()
+ resultBundle.clear()
+ resultBundle.putString(Config.DIALOG_USER_ACTION, USER_ACTION_FORGOT_CLICKED)
+ dismiss()
+ enableControls()
+ }
+
+ private fun validatePassword() {
+ AppChecker().setListener(object : Checker.CheckListener {
+ override fun onFailed() {
+ enableControls()
+ }
+
+ override fun onSuccess() {
+ resultBundle.clear()
+ resultBundle.putString(Config.DIALOG_USER_ACTION, USER_ACTION_PASSWORD_COMPLETED)
+ resultBundle.putString(RESULT_PASSWORD, password.get() ?: "")
+ dismiss()
+ enableControls()
+ }
+ }).validate(provideValidationList())
+ }
+
+ override fun disableControls() {
+ super.disableControls()
+ btnEnabled.set(false)
+ }
+
+ override fun enableControls() {
+ super.enableControls()
+ btnEnabled.set(true)
+ }
+
+ fun showAnotherMethod(show: Boolean) {
+ showAnother = show
+ }
+
+ fun setForgotPassword(enable: Boolean) {
+ showForgot = enable
+ }
+
+ fun setTitle(resId: Int) {
+ titleRes = if (resId == -1) R.string.label_password else resId
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/screens/access_container/dialog/PinDialog.kt b/app/src/main/java/by/esas/tools/screens/access_container/dialog/PinDialog.kt
new file mode 100644
index 00000000..46a7f931
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/screens/access_container/dialog/PinDialog.kt
@@ -0,0 +1,230 @@
+package by.esas.tools.screens.access_container.dialog
+
+import android.os.Bundle
+import android.view.View
+import android.widget.Toast
+import androidx.databinding.ObservableBoolean
+import androidx.databinding.ObservableField
+import by.esas.tools.App
+import by.esas.tools.BR
+import by.esas.tools.R
+import by.esas.tools.checker.Checking
+import by.esas.tools.databinding.DfPinBinding
+import by.esas.tools.dialog.BindingDialogFragment
+import by.esas.tools.dialog.Config
+import by.esas.tools.numpad.INumPadHandler
+import com.google.android.material.textfield.TextInputEditText
+
+class PinDialog : BindingDialogFragment() {
+
+ override val TAG: String = PinDialog::class.java.simpleName
+
+ companion object {
+
+ const val USER_ACTION_PIN_COMPLETED: String = "USER_ACTION_PIN_COMPLETED"
+ const val RESULT_PIN: String = "RESULT_PIN"
+ const val USER_ACTION_ANOTHER_CLICKED: String = "USER_ACTION_ANOTHER_CLICKED"
+ }
+
+ override fun provideLayoutId(): Int {
+ return R.layout.df_pin
+ }
+
+ override fun provideVariableId(): Int {
+ return BR.handler
+ }
+
+ override fun provideSwitchableList(): List {
+ return emptyList()
+ }
+
+ override fun provideValidationList(): List {
+ return emptyList()
+ }
+
+ private val builder: StringBuilder = StringBuilder()
+
+ private var compare: String = ""
+ private var titleRes: Int = R.string.dialog_pin_title
+ private var confirmBtnTextRes: Int = R.string.dialog_pin_create_btn
+ val btnEnabled = ObservableBoolean(true)
+ val confirmBtnEnable = ObservableBoolean(false)
+ val showPinError = ObservableBoolean(false)
+ val showAnotherBtn = ObservableBoolean(false)
+ val showConfirmBtn = ObservableBoolean(false)
+ val confirmBtnText = ObservableField("")
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ outState.putBoolean("btnEnabled", btnEnabled.get())
+ outState.putBoolean("showAnotherBtn", showAnotherBtn.get())
+ outState.putBoolean("showConfirmBtn", showConfirmBtn.get())
+ outState.putBoolean("showPinError", showPinError.get())
+ outState.putString("old", compare)
+ outState.putString("builder", builder.toString())
+ outState.putInt("titleRes", titleRes)
+ outState.putInt("confirmBtnTextRes", confirmBtnTextRes)
+ }
+
+ override fun onViewStateRestored(savedInstanceState: Bundle?) {
+ super.onViewStateRestored(savedInstanceState)
+ if (savedInstanceState != null) {
+ btnEnabled.set(savedInstanceState.getBoolean("btnEnabled", true))
+ showAnotherBtn.set(savedInstanceState.getBoolean("showAnotherBtn", false))
+ showConfirmBtn.set(savedInstanceState.getBoolean("showConfirmBtn", false))
+ showPinError.set(savedInstanceState.getBoolean("showPinError", false))
+ compare = savedInstanceState.getString("old", "") ?: ""
+ builder.clear()
+ builder.append(savedInstanceState.getString("builder", "") ?: "")
+ titleRes = (savedInstanceState.getInt("titleRes", R.string.dialog_pin_title))
+ confirmBtnTextRes = (savedInstanceState.getInt("confirmBtnTextRes", R.string.dialog_pin_create_btn))
+ updateScreen()
+ }
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ enableControls()
+ builder.clear()
+
+ binding.dfPinNumPad.setNumpadHandler(object : INumPadHandler {
+ override fun onNumClick(num: Int) {
+ showPinError.set(false)
+ if (btnEnabled.get()) {
+ disableControls()
+ if (builder.length < 5) {
+ addPin(num)
+ } else if (builder.length < 6) {
+ addLastPin(num)
+ } else {
+ enableControls()
+ }
+ }
+ }
+
+ private fun addPin(num: Int) {
+ binding.dfPinView.fillPin()
+ builder.append(num)
+ enableControls()
+ }
+
+ private fun addLastPin(num: Int) {
+ binding.dfPinView.fillPin()
+ builder.append(num)
+ if (!showConfirmBtn.get()) {
+ binding.dfPinView.postOnAnimationDelayed({
+ logger.logInfo(builder.length.toString())
+ resultBundle.clear()
+ resultBundle.putString(Config.DIALOG_USER_ACTION, USER_ACTION_PIN_COMPLETED)
+ resultBundle.putString(RESULT_PIN, builder.toString())
+ builder.clear()
+ binding.dfPinView.clearPins()
+ dismiss()
+ enableControls()
+ }, 300L)
+ } else {
+ if (compare.isNotBlank() && compare != builder.toString()) {
+ showPinError.set(true)
+ }
+ enableControls()
+ }
+ }
+
+ override fun onRightIconClick() {
+ disableControls()
+ showPinError.set(false)
+ if (builder.isNotEmpty()) {
+ val length = if (builder.length <= 1) 0 else builder.length - 1
+ builder.setLength(length)
+ binding.dfPinView.unFillPin()
+ }
+ enableControls()
+ }
+ })
+ /*restoreBtn?.setOnLongClickListener {
+ return@setOnLongClickListener if (btnEnabled.get()) {
+ disableControls()
+ showPinError.set(false)
+ builder.clear()
+ binding.dfPinView.clearPins()
+ enableControls()
+ true
+ } else
+ false
+ }*/
+ updateScreen()
+ }
+
+ private fun updateScreen() {
+ binding.dfPinTopBarTitle.setText(titleRes)
+ binding.dfPinView.setPin(builder.length)
+ confirmBtnText.set(App.appContext.getString(confirmBtnTextRes))
+ }
+
+ fun onBackClick() {
+ disableControls()
+ //full = false
+ builder.clear()
+ binding.dfPinView.clearPins()
+ resultBundle.clear()
+ resultBundle.putString(Config.DIALOG_USER_ACTION, Config.CANCEL_DIALOG)
+ dismiss()
+ }
+
+ fun onAnotherClick() {
+ disableControls()
+ //full = false
+ builder.clear()
+ binding.dfPinView.clearPins()
+ resultBundle.clear()
+ resultBundle.putString(Config.DIALOG_USER_ACTION, USER_ACTION_ANOTHER_CLICKED)
+ dismiss()
+ enableControls()
+ }
+
+ fun onConfirmClick() {
+ disableControls()
+ if (compare.isNotBlank() && compare != builder.toString()) {
+ Toast.makeText(requireContext(), R.string.error_app_not_equal, Toast.LENGTH_SHORT).show()
+ enableControls()
+ } else {
+ resultBundle.clear()
+ resultBundle.putString(Config.DIALOG_USER_ACTION, USER_ACTION_PIN_COMPLETED)
+ resultBundle.putString(RESULT_PIN, builder.toString())
+ builder.clear()
+ binding.dfPinView.clearPins()
+ dismiss()
+ enableControls()
+ }
+ }
+
+ override fun disableControls() {
+ btnEnabled.set(false)
+ confirmBtnEnable.set(false)
+ binding.dfPinNumPad.disableNumpadView()
+ super.disableControls()
+ }
+
+ override fun enableControls() {
+ btnEnabled.set(true)
+ confirmBtnEnable.set(builder.length == 6)
+ binding.dfPinNumPad.enableNumpadView()
+ super.enableControls()
+ }
+
+ fun setTitle(resId: Int) {
+ titleRes = if (resId == -1) R.string.dialog_pin_title else resId
+ }
+
+ fun setConfirmBtn(showBtn: Boolean, textResId: Int = -1, compare: String = "") {
+ this.compare = compare
+ confirmBtnTextRes = if (textResId == -1) R.string.common_continue_button else textResId
+ showConfirmBtn.set(showBtn)
+ if (showBtn) showAnotherBtn.set(false)
+ }
+
+ fun setHasAnother(value: Boolean) {
+ showAnotherBtn.set(value)
+ if (value) showConfirmBtn.set(false)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/screens/access_container/utility/Container.kt b/app/src/main/java/by/esas/tools/screens/access_container/utility/Container.kt
new file mode 100644
index 00000000..b8e5aad5
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/screens/access_container/utility/Container.kt
@@ -0,0 +1,81 @@
+package by.esas.tools.screens.access_container.utility
+
+import android.content.Context
+import by.esas.tools.accesscontainer.Refresher
+import by.esas.tools.accesscontainer.dialog.BiometricUserInfo
+import by.esas.tools.accesscontainer.dialog.DialogProvider
+import by.esas.tools.accesscontainer.error.IErrorMapper
+import by.esas.tools.accesscontainer.support.IContainerExecutor
+import by.esas.tools.accesscontainer.support.ITypeManager
+import by.esas.tools.accesscontainer.support.supporter.IUtil
+import by.esas.tools.accesscontainer.support.supporter.Supporter
+import by.esas.tools.app_domain.error_mapper.AppErrorMapper
+import by.esas.tools.logger.ILogger
+import by.esas.tools.util.TAGk
+import by.esas.tools.utils.logger.ErrorModel
+import javax.crypto.SecretKey
+
+class Container(
+ logger: ILogger,
+ executor: IContainerExecutor,
+ typeManager: ITypeManager,
+ userInfo: BiometricUserInfo,
+ mapper: IErrorMapper,
+ dialogProvider: DialogProvider,
+ supporter: Supporter
+) : Refresher(logger, executor, typeManager, userInfo, mapper, dialogProvider, supporter) {
+
+ companion object {
+
+ fun getInstance(
+ logger: ILogger,
+ executor: IContainerExecutor,
+ appMapper: AppErrorMapper,
+ typeManager: ITypeManager,
+ userInfo: BiometricUserInfo
+ ): Container {
+ val errorMapper = object : IErrorMapper {
+ private val mapper = appMapper
+ override fun mapError(e: Exception): ErrorModel {
+ return mapper.mapErrorException(TAGk, e)
+ }
+
+ override fun createErrorModel(code: Int, enumName: String): ErrorModel {
+ return mapper.createModel(code, enumName)
+ }
+ }
+
+ return Container(
+ logger = logger,
+ executor = executor,
+ typeManager = typeManager,
+ userInfo = userInfo,
+ mapper = errorMapper,
+ dialogProvider = DialogProviderImpl(logger),
+ supporter = Supporter(ResProviderImpl(), provideUtil())
+ )
+ }
+
+ private fun provideUtil(): IUtil {
+ return object : IUtil {
+
+ override fun generatePin(pin: String, userId: String, androidId: String): SecretKey? {
+ return by.esas.tools.biometric_decryption.generatePin(pin, userId, androidId)
+ }
+
+ override fun checkBiometricSupport(
+ context: Context?,
+ logging: (String, String) -> Unit
+ ): Boolean {
+ return context?.let {
+ by.esas.tools.biometric_decryption.checkBiometricSupport(
+ context,
+ logging
+ )
+ }
+ ?: false
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/screens/access_container/utility/DialogProviderImpl.kt b/app/src/main/java/by/esas/tools/screens/access_container/utility/DialogProviderImpl.kt
new file mode 100644
index 00000000..742ef63a
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/screens/access_container/utility/DialogProviderImpl.kt
@@ -0,0 +1,425 @@
+package by.esas.tools.screens.access_container.utility
+
+import android.view.View
+import androidx.biometric.BiometricPrompt
+import androidx.fragment.app.FragmentActivity
+import androidx.fragment.app.FragmentResultListener
+import by.esas.tools.App
+import by.esas.tools.R
+import by.esas.tools.accesscontainer.dialog.BiometricUserInfo
+import by.esas.tools.accesscontainer.dialog.DialogProvider
+import by.esas.tools.accesscontainer.dialog.IBaseDialog
+import by.esas.tools.accesscontainer.dialog.IBiometric
+import by.esas.tools.accesscontainer.dialog.setters.MenuDialogSetter
+import by.esas.tools.accesscontainer.dialog.setters.MenuResultHandler
+import by.esas.tools.accesscontainer.dialog.setters.PasswordResultHandler
+import by.esas.tools.accesscontainer.dialog.setters.PinResultHandler
+import by.esas.tools.accesscontainer.dialog.setters.SetBiometricDialog
+import by.esas.tools.accesscontainer.dialog.setters.SetPasswordDialog
+import by.esas.tools.accesscontainer.dialog.setters.SetPinDialog
+import by.esas.tools.accesscontainer.entity.AuthType
+import by.esas.tools.biometric_decryption.Biometric
+import by.esas.tools.dialog.BaseDialogFragment
+import by.esas.tools.dialog.Config
+import by.esas.tools.dialog.Config.CANCEL_DIALOG
+import by.esas.tools.dialog.MessageDialog
+import by.esas.tools.dialog.MessageDialog.Companion.ITEM_CODE
+import by.esas.tools.dialog.MessageDialog.Companion.USER_ACTION_ITEM_PICKED
+import by.esas.tools.logger.ILogger
+import by.esas.tools.screens.access_container.dialog.PasswordDialog
+import by.esas.tools.screens.access_container.dialog.PinDialog
+import by.esas.tools.utils.logger.ErrorModel
+import javax.crypto.Cipher
+
+class DialogProviderImpl(val logger: ILogger) : DialogProvider() {
+
+ override val passwordDialog: SetPasswordDialog = providePasswordDialog()
+ override val menuDialog: MenuDialogSetter = provideMenuDialog()
+ override val pinDialog: SetPinDialog = providePinDialog()
+ override val biom: SetBiometricDialog = provideBiomDialog()
+
+ private fun show(
+ context: FragmentActivity?,
+ tag: String,
+ instance: BaseDialogFragment?,
+ resultListener: FragmentResultListener
+ ) {
+ logger.logOrder("IBaseDialog $tag show instance != null ${instance != null}")
+ if (context != null) {
+ instance?.setRequestKey(tag)
+
+ context.supportFragmentManager.clearFragmentResultListener(tag)
+ context.supportFragmentManager.setFragmentResultListener(tag, context, resultListener)
+
+ try {
+ instance?.show(context.supportFragmentManager, tag)
+ } catch (e: java.lang.IllegalStateException) {
+ context.supportFragmentManager.clearFragmentResultListener(tag)
+ logger.logError("IBaseDialog $tag IllegalStateException while dialog show")
+ }
+ }
+ }
+
+ private fun provideMenuDialog(): MenuDialogSetter {
+ var dialog: MessageDialog? = null
+
+ return object : MenuDialogSetter {
+ val list = mutableListOf>()
+ var menuHandler: MenuResultHandler? = null
+
+ override fun createDialog() {
+ logger.logOrder("MenuDialogSetter createDialog dialog!=null = ${dialog != null}")
+ dialog?.dismiss()
+ dialog = null
+ dialog = MessageDialog(false)
+ dialog?.isCancelable = false
+ }
+
+ override fun setupParameterBundle(
+ isDecrypting: Boolean,
+ showPassword: Boolean,
+ showPin: Boolean,
+ showBiom: Boolean
+ ) {
+ logger.logOrder("MenuDialogSetter setupParameterBundle isDecrypting=$isDecrypting, showPassword=$showPassword, showPin=$showPin, showBiom=$showBiom")
+ list.clear()
+ if (isDecrypting && showPassword)
+ list.add(Pair(App.appContext.getString(R.string.label_password), AuthType.NONE))
+ if (showPin)
+ list.add(Pair(App.appContext.getString(R.string.label_pin), AuthType.PIN_AUTH))
+ if (showBiom)
+ list.add(Pair(App.appContext.getString(R.string.label_biom), AuthType.BIOMETRIC_AUTH))
+ dialog?.setItems(
+ list = list.map { MessageDialog.ItemInfo(it.second.name, it.first) },
+ alignment = View.TEXT_ALIGNMENT_CENTER
+ )
+ }
+
+ override fun setupResultHandler(handler: MenuResultHandler) {
+ logger.logOrder("MenuDialogSetter setupResultHandler")
+ this.menuHandler = handler
+ }
+
+ override fun setTitle(titleRes: Int) {
+ logger.logOrder("MenuDialogSetter setTitle dialog!=null = ${dialog != null}")
+ dialog?.setTitle(titleRes)
+ }
+
+ override fun getDialog(): IBaseDialog {
+ logger.logOrder("MenuDialogSetter getDialog dialog != null = ${dialog != null}")
+ return object : IBaseDialog {
+ var dialogInst: BaseDialogFragment? = dialog
+
+ override fun dismiss() {
+ logger.logOrder("IBaseDialog MessageDialog dismiss dialogInst != null = ${dialogInst != null}")
+ try {
+ dialogInst?.dismiss()
+ dialogInst = null
+ } catch (e: IllegalStateException) {
+ logger.logError(e)
+ }
+ }
+
+ override fun show(context: FragmentActivity?, tag: String) {
+ val listener = provideResultListener(tag)
+ show(context, tag, dialogInst, listener)
+ }
+
+ override fun provideResultListener(tag: String): FragmentResultListener {
+ return FragmentResultListener { requestKey, result ->
+ if (requestKey == tag) {
+ val userAction = result.getString(Config.DIALOG_USER_ACTION)
+ logger.logOrder("IBaseDialog $tag requestKey $requestKey userAction $userAction")
+ if (userAction == CANCEL_DIALOG) {
+ menuHandler?.onCancel()
+ } else if (userAction == USER_ACTION_ITEM_PICKED) {
+ val itemCode = result.getString(ITEM_CODE) ?: ""
+ val type: AuthType = try {
+ AuthType.valueOf(itemCode)
+ } catch (e: IllegalArgumentException) {
+ AuthType.NONE
+ }
+ when (type) {
+ AuthType.BIOMETRIC_AUTH -> menuHandler?.onBiomClick()
+ AuthType.PIN_AUTH -> menuHandler?.onPinClick()
+ AuthType.NONE -> menuHandler?.onPasswordClick()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override fun clear(context: FragmentActivity?) {
+ logger.logOrder("MenuDialogSetter clear dialog!=null = ${dialog != null}")
+ dialog?.getRequestKey()?.let { context?.supportFragmentManager?.clearFragmentResultListener(it) }
+ dialog?.dismiss()
+ dialog = null
+ }
+ }
+ }
+
+ private fun providePasswordDialog(): SetPasswordDialog {
+ return object : SetPasswordDialog {
+ var dialog: PasswordDialog? = null
+ var resultHandler: PasswordResultHandler? = null
+
+ override fun setupParameterBundle(
+ cancelBtnRes: Int,
+ anotherBtnRes: Int,
+ isCancellable: Boolean,
+ showAnother: Boolean,
+ forgotPasswordActionEnable: Boolean
+ ) {
+ logger.logOrder("GetPasswordDialog setupParameterBundle")
+ dialog?.isCancelable = isCancellable
+ dialog?.showAnotherMethod(showAnother)
+ dialog?.setForgotPassword(forgotPasswordActionEnable)
+ }
+
+ override fun setupResultHandler(handler: PasswordResultHandler) {
+ logger.logOrder("GetPasswordDialog setupResultHandler")
+ this.resultHandler = handler
+ }
+
+ override fun setTitle(titleRes: Int) {
+ logger.logOrder("GetPasswordDialog setTitle dialog!=null = ${dialog != null}")
+ dialog?.setTitle(titleRes)
+ }
+
+ override fun createDialog() {
+ logger.logOrder("GetPasswordDialog createDialog dialog!=null = ${dialog != null}")
+ dialog?.dismiss()
+ dialog = null
+ dialog = PasswordDialog()
+ }
+
+ override fun getDialog(): IBaseDialog {
+ logger.logOrder("GetPasswordDialog getDialog dialog != null = ${dialog != null}")
+ return object : IBaseDialog {
+ var dialogInst: BaseDialogFragment? = dialog
+ override fun dismiss() {
+ logger.logOrder("IBaseDialog PasswordDialog dismiss dialogInst != null = ${dialogInst != null}")
+ try {
+ dialogInst?.dismiss()
+ dialogInst = null
+ } catch (e: IllegalStateException) {
+ logger.logError(e)
+ }
+ }
+
+ override fun show(context: FragmentActivity?, tag: String) {
+ val listener = provideResultListener(tag)
+ show(context, tag, dialogInst, listener)
+ }
+
+ override fun provideResultListener(tag: String): FragmentResultListener {
+ return FragmentResultListener { requestKey, result ->
+ if (requestKey == tag) {
+ val userAction = result.getString(Config.DIALOG_USER_ACTION)
+ logger.logOrder("IBaseDialog $tag requestKey $requestKey userAction $userAction")
+ when (userAction) {
+ CANCEL_DIALOG -> {
+ resultHandler?.onCancel()
+ }
+ PasswordDialog.USER_ACTION_ANOTHER_CLICKED -> {
+ resultHandler?.onAnotherClicked()
+ }
+ PasswordDialog.USER_ACTION_PASSWORD_COMPLETED -> {
+ val password = result.getString(PasswordDialog.RESULT_PASSWORD)
+ resultHandler?.onComplete(password ?: "")
+ }
+ PasswordDialog.USER_ACTION_FORGOT_CLICKED -> {
+ resultHandler?.onForgotClicked()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override fun clear(context: FragmentActivity?) {
+ logger.logOrder("GetPasswordDialog clear dialog!=null = ${dialog != null}")
+ dialog?.getRequestKey()?.let { context?.supportFragmentManager?.clearFragmentResultListener(it) }
+ dialog?.dismiss()
+ dialog = null
+ }
+ }
+ }
+
+ private fun providePinDialog(): SetPinDialog {
+ return object : SetPinDialog {
+ var dialog: PinDialog? = null
+ var resultHandler: PinResultHandler? = null
+
+ override fun createDialog() {
+ logger.logOrder("SetPinDialog createDialog dialog!=null = ${dialog != null}")
+ dialog?.dismiss()
+ dialog = null
+ dialog = PinDialog()
+ }
+
+ override fun setTitle(titleRes: Int) {
+ logger.logOrder("SetPinDialog setTitle dialog!=null = ${dialog != null}")
+ dialog?.setTitle(titleRes)
+ }
+
+ override fun setupParameterBundle(
+ cancelBtnRes: Int,
+ anotherBtnRes: Int,
+ cancellable: Boolean,
+ hasAnother: Boolean
+ ) {
+ logger.logOrder("SetPinDialog dialog!=null = ${dialog != null}")
+ logger.logInfo("SetPinDialog setCancellable $cancellable")
+ dialog?.isCancelable = cancellable
+ logger.logInfo("SetPinDialog hasAnother $hasAnother")
+ dialog?.setHasAnother(hasAnother)
+ }
+
+ override fun setupResultHandler(handler: PinResultHandler) {
+ this.resultHandler = handler
+ }
+
+ override fun getDialog(): IBaseDialog {
+ logger.logOrder("SetPinDialog getDialog dialog != null = ${dialog != null}")
+ return object : IBaseDialog {
+ var dialogInst: BaseDialogFragment? = dialog
+ override fun dismiss() {
+ logger.logOrder("IBaseDialog PinDialog dismiss dialogInst != null = ${dialogInst != null}")
+ try {
+ dialogInst?.dismiss()
+ dialogInst = null
+ } catch (e: IllegalStateException) {
+ logger.logError(e)
+ }
+ }
+
+ override fun show(context: FragmentActivity?, tag: String) {
+ val listener = provideResultListener(tag)
+ show(context, tag, dialogInst, listener)
+ }
+
+ override fun provideResultListener(tag: String): FragmentResultListener {
+ return FragmentResultListener { requestKey, result ->
+ if (requestKey == tag) {
+ val userAction = result.getString(Config.DIALOG_USER_ACTION)
+ logger.logOrder("IBaseDialog $tag requestKey $requestKey userAction $userAction")
+ when (userAction) {
+ CANCEL_DIALOG -> {
+ resultHandler?.onCancel()
+ }
+ PinDialog.USER_ACTION_ANOTHER_CLICKED -> {
+ resultHandler?.onAnotherClicked()
+ }
+ PinDialog.USER_ACTION_PIN_COMPLETED -> {
+ val pin = result.getString(PinDialog.RESULT_PIN)
+ resultHandler?.onComplete(pin ?: "")
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override fun clear(context: FragmentActivity?) {
+ logger.logOrder("GetPasswordDialog clear dialog!=null = ${dialog != null}")
+ dialog?.getRequestKey()?.let { context?.supportFragmentManager?.clearFragmentResultListener(it) }
+ dialog?.dismiss()
+ dialog = null
+ }
+ }
+ }
+
+ private fun provideBiomDialog(): SetBiometricDialog {
+ return object : SetBiometricDialog {
+ var biometricCallback: BiometricPrompt.AuthenticationCallback? = null
+ var builder: Biometric? = null
+ var prompt: BiometricPrompt.PromptInfo? = null
+ var dialog: BiometricPrompt? = null
+
+ override fun onAuthenticationCallback(onError: (Boolean, String) -> Unit, onSuccess: (Cipher?) -> Unit) {
+ logger.logOrder("SetBiometricDialog onAuthenticationCallback")
+ biometricCallback = object : BiometricPrompt.AuthenticationCallback() {
+ override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
+ super.onAuthenticationError(errorCode, errString)
+ logger.logOrder("SetBiometricDialog authentication Error")
+ onError(errorCode == BiometricPrompt.ERROR_CANCELED, errString.toString())
+ }
+
+ override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
+ super.onAuthenticationSucceeded(result)
+ logger.logOrder("SetBiometricDialog authentication Succeeded")
+ onSuccess(result.cryptoObject?.cipher)
+ }
+
+ override fun onAuthenticationFailed() {
+ super.onAuthenticationFailed()
+ logger.logOrder("SetBiometricDialog authentication Failed")
+ }
+ }
+ logger.logOrder("SetBiometricDialog biometricCallback!=null = ${biometricCallback != null}")
+ }
+
+ override fun create(activity: FragmentActivity, userInfo: BiometricUserInfo) {
+ logger.logOrder("SetBiometricDialog create")
+ val info = object : Biometric.BiometricUserInfo {
+ override fun getCurrentUser(): String {
+ return userInfo.getCurrentUser()
+ }
+
+ override fun setCurrentUserIv(iv: ByteArray) {
+ userInfo.setCurrentUserIv(iv)
+ }
+
+ override fun getCurrentUserIv(): ByteArray {
+ return userInfo.getCurrentUserIv()
+ }
+ }
+ builder = biometricCallback?.let { callback ->
+ logger.logOrder("SetBiometricDialog builder update")
+ Biometric(activity, callback, info)
+ }
+ logger.logOrder("SetBiometricDialog builder!=null = ${builder != null}")
+ }
+
+ override fun setInfo(title: String, negativeText: String) {
+ logger.logOrder("SetBiometricDialog setInfo")
+ prompt = builder?.createInfo(title, negativeText)
+ logger.logOrder("SetBiometricDialog prompt!=null = ${prompt != null}")
+ }
+
+ override fun authenticate(isDecrypt: Boolean): IBiometric? {
+ logger.logOrder("SetBiometricDialog authenticate isDecrypt = $isDecrypt")
+ prompt?.let { info ->
+ logger.logOrder("SetBiometricDialog authenticate prompt let")
+ dialog = builder?.authenticate(
+ if (isDecrypt) Biometric.DialogMode.DECRYPT_MODE else Biometric.DialogMode.ENCRYPT_MODE,
+ info
+ )
+ }
+ logger.logOrder("SetBiometricDialog authenticate return IBiometric")
+ return object : IBiometric {
+ private var dialogInst: BiometricPrompt? = dialog
+ override fun cancelAuthentication() {
+ logger.logOrder("IBiometric cancelAuthentication dialogInst!=null ${dialogInst != null}")
+ dialogInst?.cancelAuthentication()
+ dialogInst = null
+ }
+ }
+ }
+
+ override fun clear() {
+ logger.logOrder("SetBiometricDialog clear")
+ biometricCallback = null
+ builder = null
+ prompt = null
+ dialog?.cancelAuthentication()
+ dialog = null
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/by/esas/tools/screens/access_container/utility/Executor.kt b/app/src/main/java/by/esas/tools/screens/access_container/utility/Executor.kt
new file mode 100644
index 00000000..25f1635e
--- /dev/null
+++ b/app/src/main/java/by/esas/tools/screens/access_container/utility/Executor.kt
@@ -0,0 +1,162 @@
+package by.esas.tools.screens.access_container.utility
+
+import by.esas.tools.accesscontainer.ContainerRequest
+import by.esas.tools.accesscontainer.entity.AuthType
+import by.esas.tools.accesscontainer.entity.Token
+import by.esas.tools.accesscontainer.support.IContainerExecutor
+import by.esas.tools.app_domain.error_mapper.AppErrorStatusEnum
+import by.esas.tools.logger.ILogger
+import by.esas.tools.utils.logger.ErrorModel
+import javax.crypto.Cipher
+import javax.crypto.SecretKey
+
+class Executor(
+ private val logger: ILogger
+) : IContainerExecutor {
+
+ val TAG: String = Executor::class.java.simpleName
+
+ var provider: SecretProvider = SecretProvider()
+
+ init {
+ logger.setTag(TAG)
+ }
+
+ override fun refreshAccessUC(
+ refreshToken: String,
+ block: ContainerRequest.() -> Unit
+ ) {
+ logger.logOrder("refreshAccessUC")
+
+ val response = ContainerRequest().apply { block() }
+ provider.refreshToken().let {
+ if (it.type == Result.SUCCESS_RESULT) {
+ response(it.result)
+ } else {
+ response(ErrorModel(0, AppErrorStatusEnum.ACCESS_DENIED))
+ }
+ }
+ }
+
+ override fun getSecretsUC(block: ContainerRequest, ErrorModel>.() -> Unit) {
+ logger.logOrder("getSecretsUC")
+
+ val response = ContainerRequest, ErrorModel>().apply { block() }
+ provider.getSecrets().let {
+ if (it.type == Result.SUCCESS_RESULT) {
+ response(it.result!!)
+ } else {
+ response(ErrorModel(0, AppErrorStatusEnum.APP_USER_HAS_NO_SECRETS))
+ }
+ }
+ }
+
+ override fun refreshWithSecretUC(
+ pinKey: SecretKey?,
+ cipher: Cipher?,
+ block: ContainerRequest.() -> Unit
+ ) {
+ logger.logOrder("refreshWithSecretUC pinKey!=null = ${pinKey != null}, cipher!=null = ${cipher != null}")
+
+ val response = ContainerRequest().apply { block() }
+ provider.refreshWithSecret().let {
+ if (it.type == Result.SUCCESS_RESULT) {
+ response(it.result!!)
+ } else {
+ val status =
+ if (pinKey != null) AppErrorStatusEnum.APP_PIN_DECRYPTION_FAILED
+ else AppErrorStatusEnum.APP_BIOMETRIC_DECRYPTION_FAILED
+ response(ErrorModel(0, status))
+ }
+ }
+ }
+
+ override fun checkSecretUC(
+ pinKey: SecretKey?,
+ cipher: Cipher?,
+ block: ContainerRequest, ErrorModel>.() -> Unit
+ ) {
+ logger.logOrder("checkSecretUC pinKey!=null = ${pinKey != null}, cipher!=null = ${cipher != null}")
+
+ val response = ContainerRequest