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

[feat] [dialog] How to determine whether to open photos picker or files picker on iOS #1596

Open
winjeysong opened this issue Jul 30, 2024 · 12 comments
Labels
plugin: dialog question Further information is requested

Comments

@winjeysong
Copy link

using open imported from @tauri-apps/plugin-dialog will open files picker on iOS 17.5 simulator.
Is there a way to determine whether to open photos picker or files picker? I just want to open photos picker by open.

tauri-plugin-dialog: 2.0.0-beta.11

@winjeysong winjeysong changed the title plugin-dialog: How to determine whether to open photos picker or files picker on iOS [feat] [dialog] How to determine whether to open photos picker or files picker on iOS Jul 30, 2024
@FabianLars FabianLars added question Further information is requested plugin: dialog labels Jul 30, 2024
@FabianLars
Copy link
Member

Considering we have the opposite behavior in #1578 i have to admit that this is quite confusing to me. Anyway, just wrote this to link to 1578 so that when someone works one of those issues the other one will be looked at & resolved as well.

Thanks for the report.

@ecmel
Copy link

ecmel commented Aug 1, 2024

From my testing the following opens the file dialog:

await open({ filters: [{ extensions: ["pdf", "txt"], name: "Documents" }]});

but interestingly the following opens photo chooser:

await open({ filters: [{ extensions: ["pdf"], name: "Documents" }]});

Checking the source code, open method can show multiple dialogs depending on the parsing of the filters attribute so both issues are valid. Parsing logic should be fixed.

@bjbk
Copy link

bjbk commented Aug 6, 2024

Confirmed. Adding the second extension to the extensions array opens the Files app. However, for some reason the target files are greyed out and not selectable.

file = await open({
        multiple: false,
        directory: false,
        filters: [{ name: 'CSV', extensions: ['txt', 'csv'] }]
      })

@bjbk
Copy link

bjbk commented Aug 6, 2024

I wonder if this may be of use:

PLEASE USE CAUTION WITH THE CODE BELOW, I am not a Swift developer. I was looking to see what could be the issue with parsing the code and so asked Claude AI. I realize that asking AI may be bad form, but sometimes it proves to be useful.

The code is using kUTTagClassMIMEType to create the UTI, but it's passing in the file extension. Instead, should it use kUTTagClassFilenameExtension?

import MobileCoreServices
import Photos
import PhotosUI
import SwiftRs
import Tauri
import UIKit
import WebKit

// ... (previous code remains the same)

class DialogPlugin: Plugin {
  var filePickerController: FilePickerController!
  var pendingInvoke: Invoke? = nil
  var pendingInvokeArgs: FilePickerOptions? = nil

  override init() {
    super.init()
    filePickerController = FilePickerController(self)
  }

  @objc public func showFilePicker(_ invoke: Invoke) throws {
    let args = try invoke.parseArgs(FilePickerOptions.self)

    let parsedTypes = parseFiltersOption(args.filters ?? [])

    pendingInvoke = invoke
    pendingInvokeArgs = args

    DispatchQueue.main.async {
      if #available(iOS 14, *) {
        var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
        configuration.selectionLimit = (args.multiple ?? false) ? 0 : 1
        
        if !parsedTypes.isEmpty {
          configuration.filter = self.createPHPickerFilter(from: parsedTypes)
        }

        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self.filePickerController
        picker.modalPresentationStyle = .fullScreen
        self.presentViewController(picker)
      } else {
        let picker = UIDocumentPickerViewController(documentTypes: parsedTypes, in: .import)
        picker.delegate = self.filePickerController
        picker.allowsMultipleSelection = args.multiple ?? false
        picker.modalPresentationStyle = .fullScreen
        self.presentViewController(picker)
      }
    }
  }

  private func parseFiltersOption(_ filters: [Filter]) -> [String] {
    var parsedTypes: [String] = []
    for filter in filters {
      for ext in filter.extensions ?? [] {
        if let utType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext as CFString, nil)?.takeRetainedValue() as String? {
          parsedTypes.append(utType)
        } else {
          // If we can't get a UTI for the extension, add a wildcard UTI
          parsedTypes.append("public.item")
        }
      }
    }
    // If no valid types were found, allow all file types
    return parsedTypes.isEmpty ? ["public.item"] : parsedTypes
  }

  @available(iOS 14, *)
  private func createPHPickerFilter(from parsedTypes: [String]) -> PHPickerFilter? {
    let filters = parsedTypes.compactMap { UTType($0) }.map { PHPickerFilter.any(of: [$0]) }
    return filters.isEmpty ? nil : PHPickerFilter.any(of: filters)
  }

  private func presentViewController(_ viewControllerToPresent: UIViewController) {
    self.manager.viewController?.present(viewControllerToPresent, animated: true, completion: nil)
  }

  // ... (rest of the code remains the same)
}

@winjeysong
Copy link
Author

winjeysong commented Aug 7, 2024

Thank you, guys

@ecmel
Copy link

ecmel commented Aug 7, 2024

Screenshot 2024-08-07 at 11 51 07 File chooser on a iOS webview asks for chooser type so I think it is best to have different commands/options for choosing the kind of the dialog.

@bjbk
Copy link

bjbk commented Aug 13, 2024

No change when upgrading to RC
tauri-plugin-dialog = "2.0.0-rc.0"
"@tauri-apps/plugin-dialog": "2.0.0-rc.0"

file = await open({
        multiple: false,
        directory: false,
        filters: [{ name: 'CSV', extensions: ['txt', 'csv'] }]
      })

Dialog comes up but files cannot be selected. (iOS simulator)
image

@bjbk
Copy link

bjbk commented Sep 29, 2024

Thanks for all the hard work on getting Tauri 2 ready for release. Has this issue been resolved yet? Or is my use of the API incorrect?

@bjbk
Copy link

bjbk commented Oct 6, 2024

Same issue with 2.0.1
Has there been any updates to the API or config? Do I need to explicitly set permissions on the Simulator device?

@aramrw
Copy link

aramrw commented Oct 20, 2024

I would like to select files such as folders with the files app as well... does anyone have an idea or has done it before?

@rtiagom
Copy link

rtiagom commented Oct 27, 2024

Same problem on iOS.

@rtiagom
Copy link

rtiagom commented Oct 27, 2024

For me it worked once I set different file types in the extension. This is caused by a bug in the plugin logic.

    extensions: ["image/jpeg", "text/csv"],

Simply setting ["text/csv"] does not work. If the types are not different, it also does not work, such as with ["text/csv", "text/plain"].

@FabianLars This issue is not really a question but a bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugin: dialog question Further information is requested
Projects
None yet
Development

No branches or pull requests

6 participants