Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/file_selector/file_selector_macos/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.9.0+9

* Adds support for MIME types on macOS 11+.

## 0.9.0+8

* Updates pigeon for null value handling fixes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

import FlutterMacOS
import UniformTypeIdentifiers
import XCTest

@testable import file_selector_macos
Expand Down Expand Up @@ -160,7 +161,7 @@ class exampleTests: XCTestCase {
baseOptions: SavePanelOptions(
allowedFileTypes: AllowedTypes(
extensions: ["txt", "json"],
mimeTypes: [],
mimeTypes: ["text/html"],
utis: ["public.text", "public.image"])))
plugin.displayOpenPanel(options: options) { result in
switch result {
Expand All @@ -175,7 +176,62 @@ class exampleTests: XCTestCase {
wait(for: [called], timeout: 0.5)
XCTAssertNotNil(panelController.openPanel)
if let panel = panelController.openPanel {
if #available(macOS 11.0, *) {
XCTAssertTrue(panel.allowedContentTypes.contains(UTType.plainText))
XCTAssertTrue(panel.allowedContentTypes.contains(UTType.json))
XCTAssertTrue(panel.allowedContentTypes.contains(UTType.html))
XCTAssertTrue(panel.allowedContentTypes.contains(UTType.image))
} else {
// MIME type is not supported for the legacy codepath, but the rest should be set.
XCTAssertEqual(panel.allowedFileTypes, ["txt", "json", "public.text", "public.image"])
}
}
}

func testOpenWithFilterLegacy() throws {
let panelController = TestPanelController()
let plugin = FileSelectorPlugin(
viewProvider: TestViewProvider(),
panelController: panelController)
plugin.forceLegacyTypes = true

let returnPath = "/foo/bar"
panelController.openURLs = [URL(fileURLWithPath: returnPath)]

let called = XCTestExpectation()
let options = OpenPanelOptions(
allowsMultipleSelection: true,
canChooseDirectories: false,
canChooseFiles: true,
baseOptions: SavePanelOptions(
allowedFileTypes: AllowedTypes(
extensions: ["txt", "json"],
mimeTypes: ["text/html"],
utis: ["public.text", "public.image"])))
plugin.displayOpenPanel(options: options) { result in
switch result {
case .success(let paths):
XCTAssertEqual(paths[0], returnPath)
case .failure(let error):
XCTFail("\(error)")
}
called.fulfill()
}

wait(for: [called], timeout: 0.5)
XCTAssertNotNil(panelController.openPanel)
if let panel = panelController.openPanel {
// On the legacy path, the allowedFileTypes should be set directly.
XCTAssertEqual(panel.allowedFileTypes, ["txt", "json", "public.text", "public.image"])

// They should also be translated to corresponding allowed content types.
if #available(macOS 11.0, *) {
XCTAssertTrue(panel.allowedContentTypes.contains(UTType.plainText))
XCTAssertTrue(panel.allowedContentTypes.contains(UTType.json))
XCTAssertTrue(panel.allowedContentTypes.contains(UTType.image))
// MIME type is not supported for the legacy codepath.
XCTAssertFalse(panel.allowedContentTypes.contains(UTType.html))
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import Cocoa
import FlutterMacOS
import Foundation
import UniformTypeIdentifiers

/// Protocol for showing panels, allowing for depenedency injection in tests.
protocol PanelController {
Expand Down Expand Up @@ -48,6 +49,8 @@ public class FileSelectorPlugin: NSObject, FlutterPlugin, FileSelectorApi {
private let openDirectoryMethod = "getDirectoryPath"
private let saveMethod = "getSavePath"

var forceLegacyTypes = false

public static func register(with registrar: FlutterPluginRegistrar) {
let instance = FileSelectorPlugin(
viewProvider: DefaultViewProvider(registrar: registrar),
Expand Down Expand Up @@ -96,16 +99,31 @@ public class FileSelectorPlugin: NSObject, FlutterPlugin, FileSelectorApi {
}

if let acceptedTypes = options.allowedFileTypes {
var allowedTypes: [String] = []
// The array values are non-null by convention even though Pigeon can't currently express
// that via the types; see messages.dart.
allowedTypes.append(contentsOf: acceptedTypes.extensions.map({ $0! }))
allowedTypes.append(contentsOf: acceptedTypes.utis.map({ $0! }))
// TODO: Add support for mimeTypes in macOS 11+. See
// https://github.com/flutter/flutter/issues/117843

if !allowedTypes.isEmpty {
panel.allowedFileTypes = allowedTypes
if #available(macOS 11, *), !forceLegacyTypes {
var allowedTypes: [UTType] = []
// The array values are non-null by convention even though Pigeon can't currently express
// that via the types; see messages.dart.
allowedTypes.append(contentsOf: acceptedTypes.utis.compactMap({ UTType($0!) }))
allowedTypes.append(
contentsOf: acceptedTypes.extensions.flatMap({
UTType.types(tag: $0!, tagClass: UTTagClass.filenameExtension, conformingTo: nil)
}))
allowedTypes.append(
contentsOf: acceptedTypes.mimeTypes.flatMap({
UTType.types(tag: $0!, tagClass: UTTagClass.mimeType, conformingTo: nil)
}))
if !allowedTypes.isEmpty {
panel.allowedContentTypes = allowedTypes
}
} else {
var allowedTypes: [String] = []
// The array values are non-null by convention even though Pigeon can't currently express
// that via the types; see messages.dart.
allowedTypes.append(contentsOf: acceptedTypes.extensions.map({ $0! }))
allowedTypes.append(contentsOf: acceptedTypes.utis.map({ $0! }))
if !allowedTypes.isEmpty {
panel.allowedFileTypes = allowedTypes
}
}
}
}
Expand Down
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes to this file are just my running swift-format on it, which I hadn't done previously; we don't yet have enforcement of formatting for Swift in CI.

Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
// See also: https://pub.dev/packages/pigeon

import Foundation

#if os(iOS)
import Flutter
import Flutter
#elseif os(macOS)
import FlutterMacOS
import FlutterMacOS
#else
#error("Unsupported platform.")
#error("Unsupported platform.")
#endif

private func wrapResult(_ result: Any?) -> [Any?] {
Expand All @@ -22,13 +23,13 @@ private func wrapError(_ error: Any) -> [Any?] {
return [
flutterError.code,
flutterError.message,
flutterError.details
flutterError.details,
]
}
return [
"\(error)",
"\(type(of: error))",
"Stacktrace: \(Thread.callStackSymbols)"
"Stacktrace: \(Thread.callStackSymbols)",
]
}

Expand Down Expand Up @@ -140,14 +141,14 @@ struct OpenPanelOptions {
private class FileSelectorApiCodecReader: FlutterStandardReader {
override func readValue(ofType type: UInt8) -> Any? {
switch type {
case 128:
return AllowedTypes.fromList(self.readValue() as! [Any])
case 129:
return OpenPanelOptions.fromList(self.readValue() as! [Any])
case 130:
return SavePanelOptions.fromList(self.readValue() as! [Any])
default:
return super.readValue(ofType: type)
case 128:
return AllowedTypes.fromList(self.readValue() as! [Any])
case 129:
return OpenPanelOptions.fromList(self.readValue() as! [Any])
case 130:
return SavePanelOptions.fromList(self.readValue() as! [Any])
default:
return super.readValue(ofType: type)
}
}
}
Expand Down Expand Up @@ -189,11 +190,13 @@ protocol FileSelectorApi {
/// selected paths.
///
/// An empty list corresponds to a cancelled selection.
func displayOpenPanel(options: OpenPanelOptions, completion: @escaping (Result<[String?], Error>) -> Void)
func displayOpenPanel(
options: OpenPanelOptions, completion: @escaping (Result<[String?], Error>) -> Void)
/// Shows a save panel with the given [options], returning the selected path.
///
/// A null return corresponds to a cancelled save.
func displaySavePanel(options: SavePanelOptions, completion: @escaping (Result<String?, Error>) -> Void)
func displaySavePanel(
options: SavePanelOptions, completion: @escaping (Result<String?, Error>) -> Void)
}

/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
Expand All @@ -206,17 +209,19 @@ class FileSelectorApiSetup {
/// selected paths.
///
/// An empty list corresponds to a cancelled selection.
let displayOpenPanelChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.FileSelectorApi.displayOpenPanel", binaryMessenger: binaryMessenger, codec: codec)
let displayOpenPanelChannel = FlutterBasicMessageChannel(
name: "dev.flutter.pigeon.FileSelectorApi.displayOpenPanel", binaryMessenger: binaryMessenger,
codec: codec)
if let api = api {
displayOpenPanelChannel.setMessageHandler { message, reply in
let args = message as! [Any]
let optionsArg = args[0] as! OpenPanelOptions
api.displayOpenPanel(options: optionsArg) { result in
switch result {
case .success(let res):
reply(wrapResult(res))
case .failure(let error):
reply(wrapError(error))
case .success(let res):
reply(wrapResult(res))
case .failure(let error):
reply(wrapError(error))
}
}
}
Expand All @@ -226,17 +231,19 @@ class FileSelectorApiSetup {
/// Shows a save panel with the given [options], returning the selected path.
///
/// A null return corresponds to a cancelled save.
let displaySavePanelChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.FileSelectorApi.displaySavePanel", binaryMessenger: binaryMessenger, codec: codec)
let displaySavePanelChannel = FlutterBasicMessageChannel(
name: "dev.flutter.pigeon.FileSelectorApi.displaySavePanel", binaryMessenger: binaryMessenger,
codec: codec)
if let api = api {
displaySavePanelChannel.setMessageHandler { message, reply in
let args = message as! [Any]
let optionsArg = args[0] as! SavePanelOptions
api.displaySavePanel(options: optionsArg) { result in
switch result {
case .success(let res):
reply(wrapResult(res))
case .failure(let error):
reply(wrapError(error))
case .success(let res):
reply(wrapResult(res))
case .failure(let error):
reply(wrapError(error))
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/file_selector/file_selector_macos/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: file_selector_macos
description: macOS implementation of the file_selector plugin.
repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_macos
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22
version: 0.9.0+8
version: 0.9.0+9

environment:
sdk: ">=2.18.0 <4.0.0"
Expand Down