Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS: File picker cannot be opened in another sheet #164

Open
davidsoukup opened this issue Dec 4, 2024 · 5 comments
Open

iOS: File picker cannot be opened in another sheet #164

davidsoukup opened this issue Dec 4, 2024 · 5 comments

Comments

@davidsoukup
Copy link

davidsoukup commented Dec 4, 2024

I'm trying to implement a file picker for iOS.

I have implemented the file picker function in the View model:

open class SelectFileViewModel: BaseViewModel<SelectFileContract.Event, SelectFileContract.State, SelectFileContract.Effect>() {

    override suspend fun handleEvent(event: SelectFileContract.Event) {
        when (event) {
            is SelectFileContract.Event.SelectDocument -> selectDocument(event.document)
        }
    }
    
        override fun createInitialState(): PepFormContract.State = PepFormContract.State.initialState
    
    private suspend fun selectDocument(document: Document) {
        val files = FileKit.pickFile(
            type = PickerType.File(
                extensions = listOf("pdf", "png", "jpg", "jpeg", "heic")
            ),
            title = null,
            mode = PickerMode.Multiple(5),
        )

        files?.let {
            setState { copy(requiredDocuments = requiredDocuments + (document to files)) }
        }
    }
}

Then, I have this component in iOS.

PepFormFileUpload( onSelect: { viewModel.setEvent(event: PepFormContractEventSelectDocument(document: document)) }, requiredDocument: requiredDocument, selectedFiles: viewModel.state.requiredDocuments[requiredDocument] as? [Filekit_corePlatformFile] )

Selecting files works, but when calling SelectDocument in another sheet, this error occurs:

Attempt to present <UIDocumentPickerViewController: 0x10192ce00> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x10202aa00> (from <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x10202aa00>) which is already presenting <_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x10985a800>.

iOS 18.1 & Xcode 16.0

@vinceglb
Copy link
Owner

vinceglb commented Dec 9, 2024

Hi @davidsoukup! Thanks for submitting this issue!

Could you share a project that reproduces it? It would be easier for me to replicate your behavior.

@davidsoukup
Copy link
Author

davidsoukup commented Dec 10, 2024

It can be easily replicated in sample project, there is code for iOSApp in sample directory to replicate the issue.

import SwiftUI
import KMPObservableViewModelSwiftUI
import SamplePickerKt

struct ContentView: View {
    @StateViewModel
    var viewModel = MainViewModel(platformSettings: nil)
    
    @State private var sheetIsPresented: Bool = false
    
    var body: some View {
        let uiState = viewModel.uiState.value as? MainUiState
        
        // Convert Set to Array
        let files = Array(uiState?.files ?? [])
        
        VStack {
            Button("ShowSheet") {
                sheetIsPresented.toggle()
            }
            .sheet(isPresented: $sheetIsPresented, content: {
                Button("Multiple file picker, only png") {
                    viewModel.pickFiles()
                }
            })
        
            if uiState?.loading == true {
                ProgressView()
            }
            
            Text("Directory: \(String(describing: uiState?.directory?.path))")
            
            List(files, id: \.nsUrl) { file in
                Text(file.name)
                    .onTapGesture { viewModel.saveFile(file: file) }
            }
        }
        .padding()
    }
}

vinceglb added a commit that referenced this issue Dec 11, 2024
Related to #164

Fix the file picker function to work correctly when called in another sheet without causing a presentation error.

* **ContentView.swift**
  - Update the `sheet` modifier to dismiss any currently presented view controller before presenting the picker.
  - Add a check to ensure the picker is not presented on a view controller that is already presenting another view controller.

* **FileKit.ios.kt**
  - Update the `callPicker` function to dismiss any currently presented view controller before presenting the picker.
  - Add a check to ensure the picker is not presented on a view controller that is already presenting another view controller.

---

For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/vinceglb/FileKit/issues/164?shareId=XXXX-XXXX-XXXX-XXXX).
@vinceglb
Copy link
Owner

Thanks for your sample code. I found that it's not possible to display multiple view controllers at the same time. A common solution is to dismiss the currently active view controller and display the document picker after that.

Here is the result from the PR #170 implementing the changes:

CleanShot.2024-12-11.at.12.54.08.mp4

Does it solve your issue? Is it a problem that it dismisses the first sheet?

@vinceglb
Copy link
Owner

@theHonzic, what is the best way to manage this case? I'm open to any suggestion!

@davidsoukup
Copy link
Author

davidsoukup commented Dec 11, 2024

@vinceglb Thanks for the quick iteration, unfortunately this won't help our case. We have a flow in sheet that requires files to be uploaded in one of the steps, closing the original sheet is not an option for us.

I will leave this issue open for now and try to find a solution during this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants