Hi there guys!! I would like to get your help. I h...
# android
k
Hi there guys!! I would like to get your help. I have an issue, how can i do to always put the pointer at the end?
not kotlin but kotlin colored 1
Copy code
class PhoneNumberVisualTransformation(
    countryCode: String
) : VisualTransformation {

    private val phoneNumberFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(countryCode)

    override fun filter(text: AnnotatedString): TransformedText {
        if (text.isEmpty()) {
            return TransformedText(AnnotatedString(EMPTY_STRING), OffsetMapping.Identity)
        }
        val transformation = reformat(text, Selection.getSelectionEnd(text))

        return TransformedText(
            AnnotatedString(transformation.formatted.orEmpty()),
            object : OffsetMapping {
                override fun originalToTransformed(offset: Int): Int {
                    return transformation.originalToTransformed[
                            offset.coerceIn(transformation.originalToTransformed.indices)
                    ]
                }

                override fun transformedToOriginal(offset: Int): Int {
                    return transformation.transformedToOriginal[
                            offset.coerceIn(transformation.transformedToOriginal.indices)
                    ]
                }
            }
        )
    }

    private fun reformat(s: CharSequence, cursor: Int): Transformation {
        phoneNumberFormatter.clear()

        val curIndex = cursor - ONE_INT
        var formatted: String? = null
        var lastNonSeparator = ZERO_INT.toChar()
        var hasCursor = false

        s.forEachIndexed { index, char ->
            if (PhoneNumberUtils.isNonSeparator(char)) {
                if (lastNonSeparator.code != ZERO_INT) {
                    formatted = getFormattedNumber(lastNonSeparator, hasCursor)
                    hasCursor = false
                }
                lastNonSeparator = char
            }
            if (index == curIndex) {
                hasCursor = true
            }
        }

        if (lastNonSeparator.code != ZERO_INT) {
            formatted = getFormattedNumber(lastNonSeparator, hasCursor)
        }
        val originalToTransformed = mutableListOf<Int>()
        val transformedToOriginal = mutableListOf<Int>()
        var specialCharsCount = 0
        formatted?.forEachIndexed { index, char ->
            if (!PhoneNumberUtils.isNonSeparator(char)) {
                specialCharsCount++
            } else {
                originalToTransformed.add(index)
            }
            transformedToOriginal.add(index - specialCharsCount)
        }
        originalToTransformed.add(originalToTransformed.maxOrNull()?.plus(ONE_INT) ?: ZERO_INT)
        transformedToOriginal.add(transformedToOriginal.maxOrNull()?.plus(ONE_INT) ?: ZERO_INT)
        return Transformation(formatted, originalToTransformed, transformedToOriginal)
    }

    private fun getFormattedNumber(lastNonSeparator: Char, hasCursor: Boolean): String? {
        return if (hasCursor) {
            phoneNumberFormatter.inputDigitAndRememberPosition(lastNonSeparator)
        } else {
            phoneNumberFormatter.inputDigit(lastNonSeparator)
        }
    }

    private data class Transformation(
        val formatted: String?,
        val originalToTransformed: List<Int>,
        val transformedToOriginal: List<Int>
    )
}
m
ChatGPT may help... To always put the pointer at the end, you can modify the
PhoneNumberVisualTransformation
class by adding an additional step after formatting the phone number. Here's the updated code:
Copy code
class PhoneNumberVisualTransformation(
    countryCode: String
) : VisualTransformation {

    private val phoneNumberFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(countryCode)

    override fun filter(text: AnnotatedString): TransformedText {
        if (text.isEmpty()) {
            return TransformedText(AnnotatedString(EMPTY_STRING), OffsetMapping.Identity)
        }
        val transformation = reformat(text, Selection.getSelectionEnd(text))

        return TransformedText(
            AnnotatedString(transformation.formatted.orEmpty()),
            object : OffsetMapping {
                override fun originalToTransformed(offset: Int): Int {
                    return transformation.originalToTransformed[
                            offset.coerceIn(transformation.originalToTransformed.indices)
                    ]
                }

                override fun transformedToOriginal(offset: Int): Int {
                    return transformation.transformedToOriginal[
                            offset.coerceIn(transformation.transformedToOriginal.indices)
                    ]
                }
            }
        )
    }

    private fun reformat(s: CharSequence, cursor: Int): Transformation {
        phoneNumberFormatter.clear()

        val curIndex = cursor - 1
        var formatted: String? = null
        var lastNonSeparator = '0'
        var hasCursor = false

        s.forEachIndexed { index, char ->
            if (PhoneNumberUtils.isNonSeparator(char)) {
                if (lastNonSeparator != '0') {
                    formatted = getFormattedNumber(lastNonSeparator, hasCursor)
                    hasCursor = false
                }
                lastNonSeparator = char
            }
            if (index == curIndex) {
                hasCursor = true
            }
        }

        if (lastNonSeparator != '0') {
            formatted = getFormattedNumber(lastNonSeparator, hasCursor)
        }
        val originalToTransformed = mutableListOf<Int>()
        val transformedToOriginal = mutableListOf<Int>()
        var specialCharsCount = 0
        formatted?.forEachIndexed { index, char ->
            if (!PhoneNumberUtils.isNonSeparator(char)) {
                specialCharsCount++
            } else {
                originalToTransformed.add(index)
            }
            transformedToOriginal.add(index - specialCharsCount)
        }
        originalToTransformed.add(originalToTransformed.maxOrNull()?.plus(1) ?: 0)
        transformedToOriginal.add(transformedToOriginal.maxOrNull()?.plus(1) ?: 0)

        // Always put the cursor at the end
        val cursorPosition = originalToTransformed.size - 1

        return Transformation(formatted, originalToTransformed, transformedToOriginal, cursorPosition)
    }

    private fun getFormattedNumber(lastNonSeparator: Char, hasCursor: Boolean): String? {
        return if (hasCursor) {
            phoneNumberFormatter.inputDigitAndRememberPosition(lastNonSeparator)
        } else {
            phoneNumberFormatter.inputDigit(lastNonSeparator)
        }
    }

    private data class Transformation(
        val formatted: String?,
        val originalToTransformed: List<Int>,
        val transformedToOriginal: List<Int>,
        val cursorPosition: Int
    )
}
In the
reformat
function, I added a
cursorPosition
variable to keep track of the position of the cursor. Then, at the end of the function, I included a
cursorPosition
field in the
Transformation
data class to store the calculated cursor position. In the
filter
function, after creating the
TransformedText
object, you can set the cursor position using the
cursorPosition
field:
Copy code
return TransformedText(
    AnnotatedString(transformation.formatted.orEmpty()),
    object :

 OffsetMapping {
        override fun originalToTransformed(offset: Int): Int {
            return transformation.originalToTransformed[offset.coerceIn(transformation.originalToTransformed.indices)]
        }

        override fun transformedToOriginal(offset: Int): Int {
            return transformation.transformedToOriginal[offset.coerceIn(transformation.transformedToOriginal.indices)]
        }
    },
    cursorPosition
)
With this modification, the cursor will always be positioned at the end of the text after reformatting.
k
it is not working in that way