Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 5 additions & 0 deletions packages/file_selector/file_selector_ios/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.5.3+4

* Improves compatibility with `UIScene`.
* Updates minimum supported SDK version to Flutter 3.38/Dart 3.10.

## 0.5.3+3

* Updates minimum supported version to iOS 13.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import Flutter
import XCTest

@testable import file_selector_ios
Expand All @@ -16,13 +17,21 @@ final class TestViewPresenter: ViewPresenter {
}
}

final class StubViewPresenterProvider: ViewPresenterProvider {
var viewPresenter: ViewPresenter?

init(viewPresenter: ViewPresenter?) {
self.viewPresenter = viewPresenter
}
}

class FileSelectorTests: XCTestCase {
func testPickerPresents() throws {
let plugin = FileSelectorPlugin()
let picker = UIDocumentPickerViewController(documentTypes: [], in: UIDocumentPickerMode.import)
let presenter = TestViewPresenter()
let plugin = FileSelectorPlugin(
viewPresenterProvider: StubViewPresenterProvider(viewPresenter: presenter))
let picker = UIDocumentPickerViewController(documentTypes: [], in: UIDocumentPickerMode.import)
plugin.documentPickerViewControllerOverride = picker
plugin.viewPresenterOverride = presenter

plugin.openFile(
config: FileSelectorConfig(utis: [], allowMultiSelection: false)
Expand All @@ -34,10 +43,10 @@ class FileSelectorTests: XCTestCase {
}

func testReturnsPickedFiles() throws {
let plugin = FileSelectorPlugin()
let plugin = FileSelectorPlugin(
viewPresenterProvider: StubViewPresenterProvider(viewPresenter: TestViewPresenter()))
let picker = UIDocumentPickerViewController(documentTypes: [], in: UIDocumentPickerMode.import)
plugin.documentPickerViewControllerOverride = picker
plugin.viewPresenterOverride = TestViewPresenter()
let completionWasCalled = expectation(description: "completion")

plugin.openFile(
Expand All @@ -60,10 +69,10 @@ class FileSelectorTests: XCTestCase {
}

func testCancellingPickerReturnsEmptyList() throws {
let plugin = FileSelectorPlugin()
let plugin = FileSelectorPlugin(
viewPresenterProvider: StubViewPresenterProvider(viewPresenter: TestViewPresenter()))
let picker = UIDocumentPickerViewController(documentTypes: [], in: UIDocumentPickerMode.import)
plugin.documentPickerViewControllerOverride = picker
plugin.viewPresenterOverride = TestViewPresenter()
let completionWasCalled = expectation(description: "completion")

plugin.openFile(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ publish_to: 'none'
version: 1.0.0

environment:
sdk: ^3.9.0
flutter: ">=3.35.0"
sdk: ^3.10.0
flutter: ">=3.38.0"

dependencies:
# The following adds the Cupertino Icons font to your application.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,19 @@ public class FileSelectorPlugin: NSObject, FlutterPlugin, FileSelectorApi {
var pendingCompletions: Set<PickerCompletionBridge> = []
/// Overridden document picker, for testing.
var documentPickerViewControllerOverride: UIDocumentPickerViewController?
/// Overridden view presenter, for testing.
var viewPresenterOverride: ViewPresenter?
/// The view controller provider, for showing the document picker.
let viewPresenterProvider: ViewPresenterProvider

public static func register(with registrar: FlutterPluginRegistrar) {
let instance = FileSelectorPlugin()
let instance = FileSelectorPlugin(
viewPresenterProvider: DefaultViewPresenterProvider(registrar: registrar))
FileSelectorApiSetup.setUp(binaryMessenger: registrar.messenger(), api: instance)
}

init(viewPresenterProvider: ViewPresenterProvider) {
self.viewPresenterProvider = viewPresenterProvider
}

func openFile(config: FileSelectorConfig, completion: @escaping (Result<[String], Error>) -> Void)
{
let completionBridge = PickerCompletionBridge(completion: completion, owner: self)
Expand All @@ -64,14 +69,12 @@ public class FileSelectorPlugin: NSObject, FlutterPlugin, FileSelectorApi {
documentPicker.allowsMultipleSelection = config.allowMultiSelection
documentPicker.delegate = completionBridge

let presenter =
self.viewPresenterOverride ?? UIApplication.shared.delegate?.window??.rootViewController
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We could keep this override structure instead of adding ViewPresenterProvider, but I thought it was cleaner to reduce test branching in production code.

if let presenter = presenter {
if let presenter = viewPresenterProvider.viewPresenter {
pendingCompletions.insert(completionBridge)
presenter.present(documentPicker, animated: true, completion: nil)
} else {
completion(
.failure(PigeonError(code: "error", message: "Missing root view controller.", details: nil))
.failure(PigeonError(code: "error", message: "No view controller available.", details: nil))
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import Flutter
import UIKit

/// Protocol for UIViewController methods relating to presenting a controller.
Expand All @@ -18,3 +19,26 @@ protocol ViewPresenter {

/// ViewPresenter is intentionally a direct passthroguh to UIViewController.
extension UIViewController: ViewPresenter {}

/// Protocol for FlutterPluginRegistrar method for accessing the view controller.
///
/// This is necessary because Swift doesn't allow for only partially implementing a protocol, so
/// a stub implementation of FlutterPluginRegistrar for tests would break any time something was
/// added to that protocol.
protocol ViewPresenterProvider {
/// Returns the view controller associated with the Flutter content.
var viewPresenter: ViewPresenter? { get }
}

/// Non-test implementation of ViewPresenterProvider that forwards to the plugin registrar.
final class DefaultViewPresenterProvider: ViewPresenterProvider {
private let registrar: FlutterPluginRegistrar

init(registrar: FlutterPluginRegistrar) {
self.registrar = registrar
}

var viewPresenter: ViewPresenter? {
registrar.viewController
}
}
6 changes: 3 additions & 3 deletions packages/file_selector/file_selector_ios/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ name: file_selector_ios
description: iOS implementation of the file_selector plugin.
repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_ios
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22
version: 0.5.3+3
version: 0.5.3+4

environment:
sdk: ^3.9.0
flutter: ">=3.35.0"
sdk: ^3.10.0
flutter: ">=3.38.0"

flutter:
plugin:
Expand Down