icerockdev / moko-widgets

Multiplatform UI DSL with screen management in common code for mobile (android & ios) Kotlin Multiplatform development
https://moko.icerock.dev
Apache License 2.0
387 stars 32 forks source link

Support of android autofill services #249

Open Alex009 opened 4 years ago

Alex009 commented 4 years ago

Now android try to suggest correct autofill type, but fails and show invalid autofill hints. To fix it required some autofill support. For now particall solution is: common:

enum class AutoFillType {
    EMAIL,
    PHONE,
    PHONE_CURRENT,
    FULL_NAME,
    FIRST_NAME,
    LAST_NAME,
    MIDDLE_NAME,
    USERNAME,
    PASSWORD,
    NEW_PASSWORD,
    NEW_USERNAME,
    BIRTHDAY_FULL
}

expect fun InputType.withAutoFill(autoFillType: AutoFillType): InputType

android:

actual fun InputType.withAutoFill(autoFillType: AutoFillType): InputType {
    val decoratedInputType = this
    return object : InputType {
        override fun applyTo(editText: EditText) {
            decoratedInputType.applyTo(editText)

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                autoFillType.applyTo(editText)
            }
        }
    }
}

@RequiresApi(Build.VERSION_CODES.O)
private fun AutoFillType.applyTo(editText: EditText) {
    val hints: Array<String> = when (this) {
        AutoFillType.EMAIL -> arrayOf(HintConstants.AUTOFILL_HINT_EMAIL_ADDRESS)
        AutoFillType.PHONE -> arrayOf(HintConstants.AUTOFILL_HINT_PHONE_NUMBER)
        AutoFillType.PHONE_CURRENT -> arrayOf(HintConstants.AUTOFILL_HINT_PHONE_NUMBER_DEVICE)
        AutoFillType.FULL_NAME -> arrayOf(HintConstants.AUTOFILL_HINT_PERSON_NAME)
        AutoFillType.FIRST_NAME -> arrayOf(HintConstants.AUTOFILL_HINT_PERSON_NAME_GIVEN)
        AutoFillType.PASSWORD -> arrayOf(HintConstants.AUTOFILL_HINT_PASSWORD)
        AutoFillType.LAST_NAME -> arrayOf(HintConstants.AUTOFILL_HINT_PERSON_NAME_FAMILY)
        AutoFillType.MIDDLE_NAME -> arrayOf(HintConstants.AUTOFILL_HINT_PERSON_NAME_MIDDLE)
        AutoFillType.USERNAME -> arrayOf(HintConstants.AUTOFILL_HINT_USERNAME)
        AutoFillType.NEW_PASSWORD -> arrayOf(HintConstants.AUTOFILL_HINT_NEW_PASSWORD)
        AutoFillType.NEW_USERNAME -> arrayOf(HintConstants.AUTOFILL_HINT_NEW_USERNAME)
        AutoFillType.BIRTHDAY_FULL -> arrayOf(HintConstants.AUTOFILL_HINT_BIRTH_DATE_FULL)
    }
    @Suppress("SpreadOperator")
    editText.setAutofillHints(*hints)
    editText.importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_YES
}

ios:

actual fun InputType.withAutoFill(autoFillType: AutoFillType): InputType {
    return this
}

usage is simple:

input(
    size = WidgetSize.Const(SizeSpec.MatchConstraint, SizeSpec.WrapContent),
    id = Ids.PhoneInput,
    label = const(strings.phone),
    field = viewModel.phoneField,
    inputType = InputType.customPhone().withAutoFill(AutoFillType.PHONE_CURRENT)
)