Skip to content

[iOS] Default camera presenter breaks touch handling when launched from a Compose Multiplatform 1.11+ Dialog #638

Description

@PierreVieira

Environment

  • FileKit 0.15.0 (filekit-dialogs-compose)
  • Compose Multiplatform 1.11.1, Kotlin 2.4.10
  • iOS 17, physical iPhone 15

Summary

Follow-up to #618 (whose two titled problems were fixed by #619 and released in 0.15.0). The remaining problem, previously only discussed in the comments there: the default camera presenter breaks touch handling app-wide when the picker is launched from a Compose Multiplatform 1.11+ Dialog/Popup.

Since CMP 1.11.0-alpha02, Compose dialogs and popups are hosted in a dedicated UIWindow placed above modal view controllers (JetBrains/compose-multiplatform-core#2270, CMP-9772). When no custom presenter is supplied, openCameraPicker presents the in-process fullscreen UIImagePickerController from topMostViewController() — i.e. in the app's main window, underneath the Compose dialog window.

What happens

Launch the camera from a composable hosted inside a Compose Dialog (in our case, a Navigation 3 dialog-scene entry), take a photo or cancel. After the picker dismissal, every subsequent tap shows the press indication (ripple) but never completes a click — the whole app becomes unresponsive to clicks until process restart. The gallery path is unaffected because PHPickerViewController is out-of-process and doesn't fight the dialog window.

The deliver-after-dismissal fix from #619 is necessary but not sufficient: the corruption comes from the presentation itself happening below the dialog window, not from the result ordering.

Confirmed workaround

Presenting the camera from a dedicated app-managed transparent UIWindow (made key above UIWindowLevelAlert, restored afterwards) via FileKitOpenCameraSettings(presenter = ...) fully resolves the interaction issue on device. This matches the JetBrains-recommended pattern for presenting native modals alongside CMP 1.11 dialog windows.

Proposal

When FileKitOpenCameraSettings.presenter is null, host the camera presentation in a FileKit-managed dedicated window instead of topMostViewController(): create a transparent UIWindow on the active scene, make it key and visible, present the picker from its root view controller, and on completion (result, cancel or failure) hide the window and restore the previous key window. Apps passing an explicit presenter keep the current behavior.

I have a working implementation of this and will open a PR shortly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions