Skip to content

Commit 212731b

Browse files
authored
feat: additional picker options (#31)
* init * chore
1 parent 674d19b commit 212731b

17 files changed

+526
-29
lines changed

example/tests/benchmark.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,10 @@ const styles = StyleSheet.create({
445445

446446
// tbd: playground
447447
setTimeout(async () => {
448-
const files = await showOpenFilePicker()
448+
const files = await showOpenFilePicker({
449+
startIn: 'desktop',
450+
types: [{ description: 'PDF files', accept: { 'text/plain': ['.txt'] } }],
451+
})
449452

450453
if (!files[0]) {
451454
console.log('No file')

packages/react-native-fast-io/ios/HybridFileSystem.swift

+40-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77

88
import Foundation
9+
import UniformTypeIdentifiers
910
import NitroModules
1011
import FastIOPrivate
1112

@@ -17,7 +18,7 @@ class HybridFileSystem : NSObject, UIDocumentPickerDelegate, HybridFileSystemSpe
1718
return HybridInputStream(stream: stream)
1819
}
1920

20-
func getFileMetadata(path: String) throws -> Metadata {
21+
func getMetadata(path: String) throws -> Metadata {
2122
let attributes = try FileManager.default.attributesOfItem(atPath: path)
2223
let fileURL = URL(fileURLWithPath: path)
2324

@@ -30,20 +31,56 @@ class HybridFileSystem : NSObject, UIDocumentPickerDelegate, HybridFileSystemSpe
3031
)
3132
}
3233

34+
func getWellKnownDirectoryPath(directory: WellKnownDirectory) throws -> String {
35+
let url = switch directory {
36+
case .desktop:
37+
FileManager.default.urls(for: .desktopDirectory, in: .userDomainMask).first
38+
case .documents:
39+
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
40+
case .downloads:
41+
FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first
42+
case .music:
43+
FileManager.default.urls(for: .musicDirectory, in: .userDomainMask).first
44+
case .pictures:
45+
FileManager.default.urls(for: .picturesDirectory, in: .userDomainMask).first
46+
case .videos:
47+
FileManager.default.urls(for: .moviesDirectory, in: .userDomainMask).first
48+
}
49+
50+
guard let url else {
51+
throw RuntimeError.error(withMessage: "Directory '\(directory)' is not available")
52+
}
53+
54+
return url.path
55+
}
56+
3357
private var filePicker: (promise: Promise<[String]>, vc: UIDocumentPickerViewController)?
34-
func showOpenFilePicker() throws -> Promise<[String]> {
58+
func showOpenFilePicker(options: NativeFilePickerOptions?) throws -> Promise<[String]> {
3559
if filePicker != nil {
3660
return Promise.rejected(withError: RuntimeError.error(withMessage: "File picker already open"))
3761
}
3862

3963
let promise = Promise<[String]>()
4064

4165
DispatchQueue.main.async {
66+
let utTypes: [UTType] = options?.extensions?
67+
.compactMap { ext in
68+
let cleanExt = ext.hasPrefix(".") ? String(ext.dropFirst()) : ext
69+
return UTType(filenameExtension: cleanExt)
70+
} ?? [.item]
71+
72+
4273
let documentPicker = UIDocumentPickerViewController(
43-
forOpeningContentTypes: [.item],
74+
forOpeningContentTypes: utTypes,
4475
asCopy: true
4576
)
4677
documentPicker.delegate = self
78+
79+
documentPicker.allowsMultipleSelection = options?.multiple ?? false
80+
81+
if let startIn = options?.startIn {
82+
documentPicker.directoryURL = URL(fileURLWithPath: startIn, isDirectory: true)
83+
}
4784

4885
guard let vc = RCTUtilsWrapper.getPresentedViewController() else {
4986
promise.reject(withError: RuntimeError.error(withMessage: "Cannot present file picker"))

packages/react-native-fast-io/nitrogen/generated/ios/FastIO-Swift-Cxx-Bridge.hpp

+40
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ namespace margelo::nitro::fastio { class HybridPassThroughStreamSpec; }
2626
namespace margelo::nitro::fastio { class HybridWebSocketManagerSpec; }
2727
// Forward declaration of `HybridWebSocketSpec` to properly resolve imports.
2828
namespace margelo::nitro::fastio { class HybridWebSocketSpec; }
29+
// Forward declaration of `NativeFilePickerOptions` to properly resolve imports.
30+
namespace margelo::nitro::fastio { struct NativeFilePickerOptions; }
2931

3032
// Forward declarations of Swift defined types
3133
// Forward declaration of `HybridFileSystemSpecCxx` to properly resolve imports.
@@ -51,12 +53,14 @@ namespace FastIO { class HybridWebSocketSpecCxx; }
5153
#include "HybridPassThroughStreamSpec.hpp"
5254
#include "HybridWebSocketManagerSpec.hpp"
5355
#include "HybridWebSocketSpec.hpp"
56+
#include "NativeFilePickerOptions.hpp"
5457
#include <NitroModules/ArrayBuffer.hpp>
5558
#include <NitroModules/ArrayBufferHolder.hpp>
5659
#include <NitroModules/PromiseHolder.hpp>
5760
#include <functional>
5861
#include <future>
5962
#include <memory>
63+
#include <optional>
6064
#include <string>
6165
#include <vector>
6266

@@ -94,6 +98,42 @@ namespace margelo::nitro::fastio::bridge::swift {
9498
return PromiseHolder<std::vector<std::string>>();
9599
}
96100

101+
// pragma MARK: std::optional<bool>
102+
/**
103+
* Specialized version of `std::optional<bool>`.
104+
*/
105+
using std__optional_bool_ = std::optional<bool>;
106+
inline std::optional<bool> create_std__optional_bool_(const bool& value) {
107+
return std::optional<bool>(value);
108+
}
109+
110+
// pragma MARK: std::optional<std::string>
111+
/**
112+
* Specialized version of `std::optional<std::string>`.
113+
*/
114+
using std__optional_std__string_ = std::optional<std::string>;
115+
inline std::optional<std::string> create_std__optional_std__string_(const std::string& value) {
116+
return std::optional<std::string>(value);
117+
}
118+
119+
// pragma MARK: std::optional<std::vector<std::string>>
120+
/**
121+
* Specialized version of `std::optional<std::vector<std::string>>`.
122+
*/
123+
using std__optional_std__vector_std__string__ = std::optional<std::vector<std::string>>;
124+
inline std::optional<std::vector<std::string>> create_std__optional_std__vector_std__string__(const std::vector<std::string>& value) {
125+
return std::optional<std::vector<std::string>>(value);
126+
}
127+
128+
// pragma MARK: std::optional<NativeFilePickerOptions>
129+
/**
130+
* Specialized version of `std::optional<NativeFilePickerOptions>`.
131+
*/
132+
using std__optional_NativeFilePickerOptions_ = std::optional<NativeFilePickerOptions>;
133+
inline std::optional<NativeFilePickerOptions> create_std__optional_NativeFilePickerOptions_(const NativeFilePickerOptions& value) {
134+
return std::optional<NativeFilePickerOptions>(value);
135+
}
136+
97137
// pragma MARK: std::shared_ptr<margelo::nitro::fastio::HybridFileSystemSpec>
98138
/**
99139
* Specialized version of `std::shared_ptr<margelo::nitro::fastio::HybridFileSystemSpec>`.

packages/react-native-fast-io/nitrogen/generated/ios/FastIO-Swift-Cxx-Umbrella.hpp

+7
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ namespace margelo::nitro::fastio { class HybridWebSocketManagerSpec; }
2626
namespace margelo::nitro::fastio { class HybridWebSocketSpec; }
2727
// Forward declaration of `Metadata` to properly resolve imports.
2828
namespace margelo::nitro::fastio { struct Metadata; }
29+
// Forward declaration of `NativeFilePickerOptions` to properly resolve imports.
30+
namespace margelo::nitro::fastio { struct NativeFilePickerOptions; }
2931
// Forward declaration of `RequestMethod` to properly resolve imports.
3032
namespace margelo::nitro::fastio { enum class RequestMethod; }
3133
// Forward declaration of `RequestOptions` to properly resolve imports.
3234
namespace margelo::nitro::fastio { struct RequestOptions; }
35+
// Forward declaration of `WellKnownDirectory` to properly resolve imports.
36+
namespace margelo::nitro::fastio { enum class WellKnownDirectory; }
3337

3438
// Include C++ defined types
3539
#include "HybridFileSystemSpec.hpp"
@@ -40,12 +44,15 @@ namespace margelo::nitro::fastio { struct RequestOptions; }
4044
#include "HybridWebSocketManagerSpec.hpp"
4145
#include "HybridWebSocketSpec.hpp"
4246
#include "Metadata.hpp"
47+
#include "NativeFilePickerOptions.hpp"
4348
#include "RequestMethod.hpp"
4449
#include "RequestOptions.hpp"
50+
#include "WellKnownDirectory.hpp"
4551
#include <NitroModules/ArrayBuffer.hpp>
4652
#include <functional>
4753
#include <future>
4854
#include <memory>
55+
#include <optional>
4956
#include <string>
5057
#include <vector>
5158

packages/react-native-fast-io/nitrogen/generated/ios/c++/HybridFileSystemSpecSwift.hpp

+15-4
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,21 @@ namespace FastIO { class HybridFileSystemSpecCxx; }
1616
namespace margelo::nitro::fastio { class HybridInputStreamSpec; }
1717
// Forward declaration of `Metadata` to properly resolve imports.
1818
namespace margelo::nitro::fastio { struct Metadata; }
19+
// Forward declaration of `WellKnownDirectory` to properly resolve imports.
20+
namespace margelo::nitro::fastio { enum class WellKnownDirectory; }
21+
// Forward declaration of `NativeFilePickerOptions` to properly resolve imports.
22+
namespace margelo::nitro::fastio { struct NativeFilePickerOptions; }
1923

2024
#include <memory>
2125
#include "HybridInputStreamSpec.hpp"
2226
#include <string>
2327
#include "Metadata.hpp"
28+
#include "WellKnownDirectory.hpp"
2429
#include <future>
2530
#include <vector>
2631
#include <NitroModules/PromiseHolder.hpp>
32+
#include <optional>
33+
#include "NativeFilePickerOptions.hpp"
2734

2835
#if __has_include(<NitroModules/HybridContext.hpp>)
2936
#include <NitroModules/HybridContext.hpp>
@@ -72,12 +79,16 @@ namespace margelo::nitro::fastio {
7279
auto __result = _swiftPart.createInputStream(path);
7380
return __result;
7481
}
75-
inline Metadata getFileMetadata(const std::string& path) override {
76-
auto __result = _swiftPart.getFileMetadata(path);
82+
inline Metadata getMetadata(const std::string& path) override {
83+
auto __result = _swiftPart.getMetadata(path);
7784
return __result;
7885
}
79-
inline std::future<std::vector<std::string>> showOpenFilePicker() override {
80-
auto __result = _swiftPart.showOpenFilePicker();
86+
inline std::string getWellKnownDirectoryPath(WellKnownDirectory directory) override {
87+
auto __result = _swiftPart.getWellKnownDirectoryPath(static_cast<int>(directory));
88+
return __result;
89+
}
90+
inline std::future<std::vector<std::string>> showOpenFilePicker(const std::optional<NativeFilePickerOptions>& options) override {
91+
auto __result = _swiftPart.showOpenFilePicker(options);
8192
return __result.getFuture();
8293
}
8394

packages/react-native-fast-io/nitrogen/generated/ios/swift/HybridFileSystemSpec.swift

+3-2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public protocol HybridFileSystemSpec: AnyObject, HybridObjectSpec {
3333

3434
// Methods
3535
func createInputStream(path: String) throws -> (any HybridInputStreamSpec)
36-
func getFileMetadata(path: String) throws -> Metadata
37-
func showOpenFilePicker() throws -> Promise<[String]>
36+
func getMetadata(path: String) throws -> Metadata
37+
func getWellKnownDirectoryPath(directory: WellKnownDirectory) throws -> String
38+
func showOpenFilePicker(options: NativeFilePickerOptions?) throws -> Promise<[String]>
3839
}

packages/react-native-fast-io/nitrogen/generated/ios/swift/HybridFileSystemSpecCxx.swift

+21-4
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,9 @@ public class HybridFileSystemSpecCxx {
114114
}
115115

116116
@inline(__always)
117-
public func getFileMetadata(path: std.string) -> Metadata {
117+
public func getMetadata(path: std.string) -> Metadata {
118118
do {
119-
let __result = try self.__implementation.getFileMetadata(path: String(path))
119+
let __result = try self.__implementation.getMetadata(path: String(path))
120120
return __result
121121
} catch {
122122
let __message = "\(error.localizedDescription)"
@@ -125,9 +125,26 @@ public class HybridFileSystemSpecCxx {
125125
}
126126

127127
@inline(__always)
128-
public func showOpenFilePicker() -> bridge.PromiseHolder_std__vector_std__string__ {
128+
public func getWellKnownDirectoryPath(directory: Int32) -> std.string {
129129
do {
130-
let __result = try self.__implementation.showOpenFilePicker()
130+
let __result = try self.__implementation.getWellKnownDirectoryPath(directory: margelo.nitro.fastio.WellKnownDirectory(rawValue: directory)!)
131+
return std.string(__result)
132+
} catch {
133+
let __message = "\(error.localizedDescription)"
134+
fatalError("Swift errors can currently not be propagated to C++! See https://github.com/swiftlang/swift/issues/75290 (Error: \(__message))")
135+
}
136+
}
137+
138+
@inline(__always)
139+
public func showOpenFilePicker(options: bridge.std__optional_NativeFilePickerOptions_) -> bridge.PromiseHolder_std__vector_std__string__ {
140+
do {
141+
let __result = try self.__implementation.showOpenFilePicker(options: { () -> NativeFilePickerOptions? in
142+
if let __unwrapped = options.value {
143+
return __unwrapped
144+
} else {
145+
return nil
146+
}
147+
}())
131148
return { () -> bridge.PromiseHolder_std__vector_std__string__ in
132149
let __promiseHolder = bridge.create_PromiseHolder_std__vector_std__string__()
133150
__result
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
///
2+
/// NativeFilePickerOptions.swift
3+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4+
/// https://github.com/mrousavy/nitro
5+
/// Copyright © 2024 Marc Rousavy @ Margelo
6+
///
7+
8+
import NitroModules
9+
10+
/**
11+
* Represents an instance of `NativeFilePickerOptions`, backed by a C++ struct.
12+
*/
13+
public typealias NativeFilePickerOptions = margelo.nitro.fastio.NativeFilePickerOptions
14+
15+
public extension NativeFilePickerOptions {
16+
private typealias bridge = margelo.nitro.fastio.bridge.swift
17+
18+
/**
19+
* Create a new instance of `NativeFilePickerOptions`.
20+
*/
21+
init(multiple: Bool?, startIn: String?, extensions: [String]?) {
22+
self.init({ () -> bridge.std__optional_bool_ in
23+
if let __unwrappedValue = multiple {
24+
return bridge.create_std__optional_bool_(__unwrappedValue)
25+
} else {
26+
return .init()
27+
}
28+
}(), { () -> bridge.std__optional_std__string_ in
29+
if let __unwrappedValue = startIn {
30+
return bridge.create_std__optional_std__string_(std.string(__unwrappedValue))
31+
} else {
32+
return .init()
33+
}
34+
}(), { () -> bridge.std__optional_std__vector_std__string__ in
35+
if let __unwrappedValue = extensions {
36+
return bridge.create_std__optional_std__vector_std__string__({ () -> bridge.std__vector_std__string_ in
37+
var __vector = bridge.create_std__vector_std__string_(__unwrappedValue.count)
38+
for __item in __unwrappedValue {
39+
__vector.push_back(std.string(__item))
40+
}
41+
return __vector
42+
}())
43+
} else {
44+
return .init()
45+
}
46+
}())
47+
}
48+
49+
var multiple: Bool? {
50+
@inline(__always)
51+
get {
52+
return self.__multiple.value
53+
}
54+
@inline(__always)
55+
set {
56+
self.__multiple = { () -> bridge.std__optional_bool_ in
57+
if let __unwrappedValue = newValue {
58+
return bridge.create_std__optional_bool_(__unwrappedValue)
59+
} else {
60+
return .init()
61+
}
62+
}()
63+
}
64+
}
65+
66+
var startIn: String? {
67+
@inline(__always)
68+
get {
69+
return { () -> String? in
70+
if let __unwrapped = self.__startIn.value {
71+
return String(__unwrapped)
72+
} else {
73+
return nil
74+
}
75+
}()
76+
}
77+
@inline(__always)
78+
set {
79+
self.__startIn = { () -> bridge.std__optional_std__string_ in
80+
if let __unwrappedValue = newValue {
81+
return bridge.create_std__optional_std__string_(std.string(__unwrappedValue))
82+
} else {
83+
return .init()
84+
}
85+
}()
86+
}
87+
}
88+
89+
var extensions: [String]? {
90+
@inline(__always)
91+
get {
92+
return { () -> [String]? in
93+
if let __unwrapped = self.__extensions.value {
94+
return __unwrapped.map({ __item in String(__item) })
95+
} else {
96+
return nil
97+
}
98+
}()
99+
}
100+
@inline(__always)
101+
set {
102+
self.__extensions = { () -> bridge.std__optional_std__vector_std__string__ in
103+
if let __unwrappedValue = newValue {
104+
return bridge.create_std__optional_std__vector_std__string__({ () -> bridge.std__vector_std__string_ in
105+
var __vector = bridge.create_std__vector_std__string_(__unwrappedValue.count)
106+
for __item in __unwrappedValue {
107+
__vector.push_back(std.string(__item))
108+
}
109+
return __vector
110+
}())
111+
} else {
112+
return .init()
113+
}
114+
}()
115+
}
116+
}
117+
}

0 commit comments

Comments
 (0)