JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
15.57k stars 1.13k forks source link

iOS Keyboard Broken with `readOnly` will show/hide in loop #5088

Open chrisjenx opened 2 weeks ago

chrisjenx commented 2 weeks ago

Focus is not respected for readOnly textfields on iOS causing the second tap to cause an infinate loop of showing/hiding the keyboard, see video. On older versions, readonly won't show the keyboard. But it also will show then hide if trying to create a filter style drop down.

Looking at the errors looks like the textview get incorrectly recomposed or focus removed so iOS removes the keyboard:

-[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:]  perform input operation requires a valid sessionID. inputModality = Keyboard, inputOperation = <null selector>, customInfoType = UIEmojiSearchOperations

Affected platforms

Versions

To Reproduce

ExposedDropdownMenuBox(
            expanded = expanded,
            onExpandedChange = { expanded = it },
        ) {
            TextField(
                modifier = Modifier.fillMaxWidth(1f).menuAnchor(
                    type = MenuAnchorType.PrimaryNotEditable,
                ),
                readOnly = true,
            )
 /// etc
}

Watch the video closely, you tap once to show the drop down, then tap to close it, the next time you tap to reopen the same drop down it start going crazy.

Expected behavior Keyboard should not show, second click should hide the popup (as should scrolling etc)

https://github.com/JetBrains/compose-multiplatform/assets/1167793/158bd88b-7e19-421f-bf96-bc20dba002f8

Updated, tried 1.6.1x+ and broken on there too. Downgrading to 1.6.1 again...

MatkovIvan commented 2 weeks ago

Hm.. it should be there 🤔

I'll take a look, thanks for the report

chrisjenx commented 2 weeks ago

This also is slightly broken on 1.6.10/11, but no where near as janky as this. On 1.6.1x it will show the keyboard once but then not again, seems like on iOS it doens't know who should hold focus causing this back and forth.

chrisjenx commented 2 weeks ago

Broken on 1.6.1x so downgrading again...

chrisjenx commented 2 weeks ago

Hm.. it should be there 🤔

I'll take a look, thanks for the report

Note, you won't see this on an emulator, you need a physical device. As the emulators are faster/don't show keyboard on focus by default

chrisjenx commented 2 weeks ago

Well the more I test the more I realize dropdown with keyboard is just plain broken on iOS, basically the popup always steals the focus so the keyboard auto closes. All versions since 1.6.0 (as far back as I tested) will eventually throw:

-[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:]  perform input operation requires a valid sessionID. inputModality = Keyboard, inputOperation = <null selector>, customInfoType = UIEmojiSearchOperations

Remove the menuAnchor and starts showing keyboard again.

Seems like compose compiler will start writing the text view in a way where it aways will recompose the textfield causing the keyboard not to be able to focus.

This happens on 1.6.x on KT 1.9.23 forward

chrisjenx commented 2 weeks ago

Created a test project for you, this is actually broken on the emulator too. What is interesting is I'm pretty sure it works first time from a clean, then you start changing stuff and then it breaks. It could be completely unrelated to menuAnchor an a iOS compile compiler issue where it's incorrectly invalidating the text field. (Cleaning all caches doesn't fix it, so not sure that theory has any validity)

TestProj.zip

chrisjenx commented 2 weeks ago

Another random note that leads me to belive focus/recompose issue, if you comment out the ExposedDropdownMenu block, the Field will act correctly. It's like either the showing of the Menu popup or rendering causes a rerender of the whole DrowdownBox

MatkovIvan commented 2 weeks ago

For 1.6.x with an editable text field inside dropdown it was tracked in #4782 and already fixed. See my comment https://github.com/JetBrains/compose-multiplatform/issues/4782#issuecomment-2107195344 with explanation what was that.

For 1.7.0-alpha01 - I've checked in our samples and in your project and wasn't able to reproduce it. It works as expected in both editable and noneditable variants.

Since the shared project contains an issue with the EDITABLE field from 1.6 that was already resolved and the initial message was about NON editable fields from 1.7, I kindly ask you to provide a project with reproduction for future investigation - the code snippet from the first message works fine.


@ASalavei could you please check if it's related to your change about an edit menu?

chrisjenx commented 2 weeks ago

Updated to 1.7.x with the readOnly issue.

Tap Read only field for focus, then tap again, they keyboard starts going crazy

TestProj.zip

https://github.com/JetBrains/compose-multiplatform/assets/1167793/c1afb06d-1e83-41cf-8385-9da04c6f8f2d

ASalavei commented 2 weeks ago

@MatkovIvan , it looks like this line does the party: https://github.com/JetBrains/compose-multiplatform-core/blob/0ff7bcc245689fc6e3a7c5b2bf2cc46bca684280/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/platform/UIKitTextInputService.uikit.kt#L305 It definitely should be removed.

However, I can see the difference in keyboard appearing behavior. This sample behaves differently on iOS and Android. It looks like our FocusStackImpl does something wrong.

MatkovIvan commented 2 weeks ago

Thanks for investigation. This is from https://github.com/JetBrains/compose-multiplatform-core/pull/1269. Then, reassigning to @mazunin-v-jb

okushnikov commented 1 week ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.