@react-native-documents/picker 11.0.3 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/android/src/main/java/com/reactnativedocumentpicker/CopyDestination.kt +1 -2
  2. package/android/src/main/java/com/reactnativedocumentpicker/DocumentMetadataBuilder.kt +4 -3
  3. package/android/src/main/java/com/reactnativedocumentpicker/FileOperations.kt +2 -2
  4. package/android/src/main/java/com/reactnativedocumentpicker/IsKnownTypeImpl.kt +26 -28
  5. package/android/src/main/java/com/reactnativedocumentpicker/MetadataGetter.kt +69 -45
  6. package/android/src/main/java/com/reactnativedocumentpicker/PickOptions.kt +43 -23
  7. package/android/src/main/java/com/reactnativedocumentpicker/PromiseWrapper.kt +83 -0
  8. package/android/src/main/java/com/reactnativedocumentpicker/RNDocumentPickerModule.kt +7 -18
  9. package/ios/RNDocumentPicker.mm +19 -41
  10. package/ios/swift/DocPicker.swift +46 -28
  11. package/ios/swift/DocSaver.swift +18 -23
  12. package/ios/swift/DocumentMetadataBuilder.swift +1 -1
  13. package/ios/swift/FileOperations.swift +21 -19
  14. package/ios/swift/IsKnownTypeImpl.swift +16 -10
  15. package/ios/swift/LocalCopyResponse.swift +3 -5
  16. package/ios/swift/PickerBase.swift +31 -49
  17. package/ios/swift/PickerOptions.swift +53 -23
  18. package/ios/swift/PromiseWrapper.swift +71 -58
  19. package/ios/swift/SaverOptions.swift +39 -17
  20. package/jest/build/src/errors.js +2 -0
  21. package/lib/module/errors.js +3 -2
  22. package/lib/module/errors.js.map +1 -1
  23. package/lib/module/release.js +1 -1
  24. package/lib/typescript/src/errors.d.ts +6 -3
  25. package/lib/typescript/src/errors.d.ts.map +1 -1
  26. package/lib/typescript/src/release.d.ts +1 -1
  27. package/lib/typescript/src/saveDocuments.d.ts +1 -1
  28. package/lib/typescript/src/types.d.ts +3 -3
  29. package/package.json +3 -2
  30. package/react-native-document-picker.podspec +1 -0
  31. package/src/errors.ts +8 -4
  32. package/src/release.ts +1 -1
  33. package/src/saveDocuments.ts +1 -1
  34. package/src/types.ts +3 -3
  35. package/android/src/main/java/com/reactnativedocumentpicker/IntentFactory.kt +0 -36
  36. package/android/src/main/java/com/reactnativedocumentpicker/PromiseWrapper.java +0 -105
  37. package/ios/swift/PromiseSupport.swift +0 -2
@@ -1,61 +1,45 @@
1
1
  // LICENSE: see License.md in the package root
2
2
 
3
3
  import Foundation
4
+ import React
4
5
 
5
- class PromiseWrapper {
6
- private var promiseResolve: RNDPPromiseResolveBlock?
7
- private var promiseReject: RNDPPromiseRejectBlock?
8
- private var nameOfCallInProgress: String?
6
+ /// React Native promise blocks are safe to call from background queues, but they are not annotated
7
+ /// as `Sendable`. Wrap them so Swift 6 doesn't warn when captured by `@Sendable` closures
8
+ /// (e.g. `Task.detached`, GCD `DispatchQueue.async`).
9
+ struct ResolveCallback: @unchecked Sendable {
10
+ let resolve: RCTPromiseResolveBlock
11
+ }
9
12
 
10
- private let E_DOCUMENT_PICKER_CANCELED = "OPERATION_CANCELED"
11
- private let ASYNC_OP_IN_PROGRESS = "ASYNC_OP_IN_PROGRESS"
13
+ /// React Native promise blocks are safe to call from background queues, but they are not annotated
14
+ /// as `Sendable`. Wrap them so Swift 6 doesn't warn when captured by `@Sendable` closures
15
+ /// (e.g. `Task.detached`, GCD `DispatchQueue.async`).
16
+ struct RejectCallback: @unchecked Sendable {
17
+ let reject: RCTPromiseRejectBlock
18
+ }
12
19
 
13
- func setPromiseRejectingPrevious(_ resolve: @escaping RNDPPromiseResolveBlock,
14
- rejecter reject: @escaping RNDPPromiseRejectBlock,
15
- fromCallSite callsite: String) {
16
- if let previousReject = promiseReject {
17
- rejectPreviousPromiseBecauseNewOneIsInProgress(previousReject, requestedOperation: callsite)
18
- }
19
- promiseResolve = resolve
20
- promiseReject = reject
21
- nameOfCallInProgress = callsite
22
- }
20
+ /// Promise callbacks for React Native bridges.
21
+ ///
22
+ /// React Native promise blocks are safe to call from background queues, but they are not annotated
23
+ /// as `Sendable`. We wrap them so this value can be captured by `@Sendable` closures without
24
+ /// Swift 6 warnings.
25
+ struct PromiseCallbacks: @unchecked Sendable {
26
+ private let resolveCallback: ResolveCallback
27
+ private let rejectCallback: RejectCallback
23
28
 
24
- func trySetPromiseRejectingIncoming(_ resolve: @escaping RNDPPromiseResolveBlock,
25
- rejecter reject: @escaping RNDPPromiseRejectBlock,
26
- fromCallSite callsite: String) -> Bool {
27
- if promiseReject != nil {
28
- rejectNewPromiseBecauseOldOneIsInProgress(reject, requestedOperation: callsite)
29
- return false
30
- }
31
- promiseResolve = resolve
32
- promiseReject = reject
33
- nameOfCallInProgress = callsite
34
- return true
35
- }
29
+ private let E_DOCUMENT_PICKER_CANCELED = "OPERATION_CANCELED"
36
30
 
37
- func resolve(_ result: Any?) {
38
- guard let resolver = promiseResolve else {
39
- print("cannot resolve promise because it's null")
40
- return
41
- }
42
- resetMembers()
43
- resolver(result)
31
+ init(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
32
+ self.resolveCallback = ResolveCallback(resolve: resolve)
33
+ self.rejectCallback = RejectCallback(reject: reject)
44
34
  }
45
35
 
46
- func reject(_ message: String, withError error: NSError) {
47
- let errorCode = String(error.code)
48
- reject(message, withCode: errorCode, withError: error)
36
+ func resolve(_ result: Any?) {
37
+ resolveCallback.resolve(result)
49
38
  }
50
39
 
51
- func reject(_ message: String, withCode errorCode: String, withError error: NSError) {
52
- guard let rejecter = promiseReject else {
53
- print("cannot reject promise because it's null")
54
- return
55
- }
56
- let errorMessage = "RNDPPromiseWrapper: \(message), \(error.description)"
57
- resetMembers()
58
- rejecter(errorCode, errorMessage, error)
40
+ func reject(_ message: String, withCode code: String, withError error: NSError?) {
41
+ let errorMessage = "RNDocumentPicker: \(message)\(error.map { ", \($0.description)" } ?? "")"
42
+ rejectCallback.reject(code, errorMessage, error)
59
43
  }
60
44
 
61
45
  func rejectAsUserCancelledOperation() {
@@ -66,27 +50,56 @@ class PromiseWrapper {
66
50
  withCode: E_DOCUMENT_PICKER_CANCELED,
67
51
  withError: error)
68
52
  }
53
+ }
69
54
 
70
- private func resetMembers() {
71
- promiseResolve = nil
72
- promiseReject = nil
55
+ /// Promise lifecycle manager.
56
+ ///
57
+ /// **Lifecycle:** Stores the promise callbacks between the initial call and delegate callbacks.
58
+ /// Call `takeCallbacks()` to extract callbacks for async operations.
59
+ ///
60
+ /// **Usage:** Cancellation/dismissal settles the in-flight promise (on whatever queue calls it).
61
+ final class PromiseWrapper {
62
+ private var callbacks: PromiseCallbacks?
63
+ private var nameOfCallInProgress: String?
64
+
65
+ private let ASYNC_OP_IN_PROGRESS = "ASYNC_OP_IN_PROGRESS"
66
+
67
+ func trySetPromiseRejectingIncoming(_ resolve: @escaping RCTPromiseResolveBlock,
68
+ rejecter reject: @escaping RCTPromiseRejectBlock,
69
+ fromCallSite callsite: String = #function) -> Bool {
70
+ if callbacks != nil {
71
+ let newCallbacks = PromiseCallbacks(resolve: resolve, reject: reject)
72
+ rejectNewPromiseBecauseOldOneIsInProgress(newCallbacks, requestedOperation: callsite)
73
+ return false
74
+ }
75
+ callbacks = PromiseCallbacks(resolve: resolve, reject: reject)
76
+ nameOfCallInProgress = callsite
77
+ return true
78
+ }
79
+
80
+ /// Extract callbacks for async work (e.g. file I/O off the main thread).
81
+ /// After extraction, this wrapper is cleared and the callbacks are moved out.
82
+ func takeCallbacks(caller: String = #function) -> PromiseCallbacks? {
83
+ guard let cb = callbacks else {
84
+ NSLog("RNDocumentPicker: \(caller) called with no in-flight promise. Dropping result.")
85
+ return nil
86
+ }
87
+
88
+ callbacks = nil
73
89
  nameOfCallInProgress = nil
90
+ return cb
74
91
  }
75
92
 
76
- // TODO error messages
77
- private func rejectPreviousPromiseBecauseNewOneIsInProgress(_ reject: RNDPPromiseRejectBlock,
78
- requestedOperation callSiteName: String) {
79
- let msg = "Warning: previous promise did not settle and was overwritten. " +
80
- "You've called \"\(callSiteName)\" while \"\(nameOfCallInProgress ?? "")\" " +
81
- "was already in progress and has not completed yet."
82
- reject(ASYNC_OP_IN_PROGRESS, msg, nil)
93
+ func rejectAsUserCancelledOperation() {
94
+ takeCallbacks()?.rejectAsUserCancelledOperation()
83
95
  }
84
96
 
85
- private func rejectNewPromiseBecauseOldOneIsInProgress(_ reject: RNDPPromiseRejectBlock,
97
+ private func rejectNewPromiseBecauseOldOneIsInProgress(_ callbacks: PromiseCallbacks,
86
98
  requestedOperation callSiteName: String) {
87
99
  let msg = "Warning: previous promise did not settle and you attempted to overwrite it. " +
88
100
  "You've called \"\(callSiteName)\" while \"\(nameOfCallInProgress ?? "")\" " +
89
101
  "was already in progress and has not completed yet."
90
- reject(ASYNC_OP_IN_PROGRESS, msg, nil)
102
+ let error = NSError(domain: NSCocoaErrorDomain, code: 0, userInfo: [NSLocalizedDescriptionKey: msg])
103
+ callbacks.reject(msg, withCode: ASYNC_OP_IN_PROGRESS, withError: error)
91
104
  }
92
105
  }
@@ -3,28 +3,50 @@
3
3
  import Foundation
4
4
  import UIKit
5
5
  import UniformTypeIdentifiers
6
+ import React
6
7
 
7
- @objc public class SaverOptions: NSObject {
8
- let transitionStyle: UIModalTransitionStyle
9
- let presentationStyle: UIModalPresentationStyle
10
- let initialDirectoryUrl: URL?
8
+ public struct SaverOptions: Sendable {
9
+ var transitionStyle: UIModalTransitionStyle?
10
+ var presentationStyle: UIModalPresentationStyle?
11
+ var initialDirectoryUri: URL?
11
12
  let sourceUrls: [URL]
12
13
  let shouldShowFileExtensions: Bool
13
14
  let asCopy: Bool
14
-
15
- @objc public init(sourceUrlStrings: [String], asCopy: Bool, initialDirectoryUrl: String? = nil, shouldShowFileExtensions: Bool, transitionStyle: UIModalTransitionStyle = .coverVertical, presentationStyle: UIModalPresentationStyle = .fullScreen) {
16
- self.sourceUrls = sourceUrlStrings.map({ it in
17
- URL(string: it)!
18
- })
15
+
16
+ public init(dictionary: NSDictionary) {
17
+ let sourceUrlStrings = dictionary["sourceUris"] as? [String] ?? []
18
+ let asCopy = dictionary["copy"] as? Bool ?? false
19
+ let shouldShowFileExtensions = dictionary["showFileExtensions"] as? Bool ?? false
20
+
21
+ self.sourceUrls = sourceUrlStrings.compactMap { URL(string: $0) }
19
22
  self.asCopy = asCopy
20
- self.transitionStyle = transitionStyle
21
- self.presentationStyle = presentationStyle
22
- if let unwrappedUrl = initialDirectoryUrl, let url = URL(string: unwrappedUrl) {
23
- self.initialDirectoryUrl = url
24
- } else {
25
- self.initialDirectoryUrl = nil
26
- }
27
23
  self.shouldShowFileExtensions = shouldShowFileExtensions
24
+
25
+ if let transitionStyle = dictionary["transitionStyle"] as? String {
26
+ self.transitionStyle = RCTConvert.uiModalTransitionStyle(transitionStyle)
27
+ }
28
+ if let presentationStyle = dictionary["presentationStyle"] as? String {
29
+ self.presentationStyle = RCTConvert.uiModalPresentationStyle(presentationStyle)
30
+ }
31
+ if let initialDirectoryUri = dictionary["initialDirectoryUri"] as? String, let url = URL(string: initialDirectoryUri) {
32
+ self.initialDirectoryUri = url
33
+ }
28
34
  }
29
-
35
+
36
+ @MainActor
37
+ public func createDocumentPicker() -> UIDocumentPickerViewController {
38
+ let picker = UIDocumentPickerViewController(forExporting: sourceUrls, asCopy: asCopy)
39
+
40
+ if let presentationStyle = presentationStyle {
41
+ picker.modalPresentationStyle = presentationStyle
42
+ }
43
+ if let transitionStyle = transitionStyle {
44
+ picker.modalTransitionStyle = transitionStyle
45
+ }
46
+ picker.directoryURL = initialDirectoryUri
47
+ picker.shouldShowFileExtensions = shouldShowFileExtensions
48
+
49
+ return picker
50
+ }
51
+
30
52
  }
@@ -4,6 +4,7 @@ exports.isErrorWithCode = exports.errorCodes = void 0;
4
4
  const OPERATION_CANCELED = 'OPERATION_CANCELED';
5
5
  const IN_PROGRESS = 'ASYNC_OP_IN_PROGRESS';
6
6
  const UNABLE_TO_OPEN_FILE_TYPE = 'UNABLE_TO_OPEN_FILE_TYPE';
7
+ const NULL_PRESENTER = 'NULL_PRESENTER';
7
8
  /**
8
9
  * Error codes that can be returned by the module, and are available on the `code` property of the error.
9
10
  *
@@ -34,6 +35,7 @@ exports.errorCodes = Object.freeze({
34
35
  OPERATION_CANCELED,
35
36
  IN_PROGRESS,
36
37
  UNABLE_TO_OPEN_FILE_TYPE,
38
+ NULL_PRESENTER,
37
39
  });
38
40
  /**
39
41
  * TypeScript helper to check if an object has the `code` property.
@@ -3,6 +3,7 @@
3
3
  const OPERATION_CANCELED = 'OPERATION_CANCELED';
4
4
  const IN_PROGRESS = 'ASYNC_OP_IN_PROGRESS';
5
5
  const UNABLE_TO_OPEN_FILE_TYPE = 'UNABLE_TO_OPEN_FILE_TYPE';
6
+ const NULL_PRESENTER = 'NULL_PRESENTER';
6
7
 
7
8
  /**
8
9
  * Error codes that can be returned by the module, and are available on the `code` property of the error.
@@ -33,9 +34,9 @@ const UNABLE_TO_OPEN_FILE_TYPE = 'UNABLE_TO_OPEN_FILE_TYPE';
33
34
  export const errorCodes = Object.freeze({
34
35
  OPERATION_CANCELED,
35
36
  IN_PROGRESS,
36
- UNABLE_TO_OPEN_FILE_TYPE
37
+ UNABLE_TO_OPEN_FILE_TYPE,
38
+ NULL_PRESENTER
37
39
  });
38
-
39
40
  /**
40
41
  * TypeScript helper to check if an object has the `code` property.
41
42
  * This is used to avoid `as` casting when you access the `code` property on errors returned by the module.
@@ -1 +1 @@
1
- {"version":3,"names":["OPERATION_CANCELED","IN_PROGRESS","UNABLE_TO_OPEN_FILE_TYPE","errorCodes","Object","freeze","isErrorWithCode","error","isNewArchErrorIOS","Error"],"sourceRoot":"../../src","sources":["errors.ts"],"mappings":";;AAIA,MAAMA,kBAAkB,GAAG,oBAAoB;AAC/C,MAAMC,WAAW,GAAG,sBAAsB;AAC1C,MAAMC,wBAAwB,GAAG,0BAA0B;;AAE3D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,UAAU,GAAGC,MAAM,CAACC,MAAM,CAAC;EACtCL,kBAAkB;EAClBC,WAAW;EACXC;AACF,CAAC,CAAC;;AAEF;AACA;AACA;AACA;AACA,OAAO,MAAMI,eAAe,GAAIC,KAAU,IAAiC;EACzE;EACA,MAAMC,iBAAiB,GAAG,OAAOD,KAAK,KAAK,QAAQ,IAAIA,KAAK,IAAI,IAAI;EACpE,OAAO,CAACA,KAAK,YAAYE,KAAK,IAAID,iBAAiB,KAAK,MAAM,IAAID,KAAK;AACzE,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["OPERATION_CANCELED","IN_PROGRESS","UNABLE_TO_OPEN_FILE_TYPE","NULL_PRESENTER","errorCodes","Object","freeze","isErrorWithCode","error","isNewArchErrorIOS","Error"],"sourceRoot":"../../src","sources":["errors.ts"],"mappings":";;AAAA,MAAMA,kBAAkB,GAAG,oBAAoB;AAC/C,MAAMC,WAAW,GAAG,sBAAsB;AAC1C,MAAMC,wBAAwB,GAAG,0BAA0B;AAC3D,MAAMC,cAAc,GAAG,gBAAgB;;AAEvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,UAAU,GAAGC,MAAM,CAACC,MAAM,CAAC;EACtCN,kBAAkB;EAClBC,WAAW;EACXC,wBAAwB;EACxBC;AACF,CAAC,CAAC;AAQF;AACA;AACA;AACA;AACA,OAAO,MAAMI,eAAe,GAAIC,KAAU,IAAiC;EACzE;EACA,MAAMC,iBAAiB,GAAG,OAAOD,KAAK,KAAK,QAAQ,IAAIA,KAAK,IAAI,IAAI;EACpE,OAAO,CAACA,KAAK,YAAYE,KAAK,IAAID,iBAAiB,KAAK,MAAM,IAAID,KAAK;AACzE,CAAC","ignoreList":[]}
@@ -3,7 +3,7 @@
3
3
  import { NativeDocumentPicker } from "./spec/NativeDocumentPicker.js";
4
4
 
5
5
  /**
6
- * For each uri whose release was requested, the result will contain an object with the uri and a status.
6
+ * For each uri whose release was requested, the result contains an object with the uri and a status.
7
7
  * */
8
8
 
9
9
  /**
@@ -1,6 +1,3 @@
1
- export interface NativeModuleError extends Error {
2
- code: string;
3
- }
4
1
  /**
5
2
  * Error codes that can be returned by the module, and are available on the `code` property of the error.
6
3
  *
@@ -31,10 +28,16 @@ export declare const errorCodes: Readonly<{
31
28
  OPERATION_CANCELED: "OPERATION_CANCELED";
32
29
  IN_PROGRESS: "ASYNC_OP_IN_PROGRESS";
33
30
  UNABLE_TO_OPEN_FILE_TYPE: "UNABLE_TO_OPEN_FILE_TYPE";
31
+ NULL_PRESENTER: "NULL_PRESENTER";
34
32
  }>;
33
+ type ErrorCodes = (typeof errorCodes)[keyof typeof errorCodes];
34
+ export interface NativeModuleError extends Error {
35
+ code: ErrorCodes | (string & {});
36
+ }
35
37
  /**
36
38
  * TypeScript helper to check if an object has the `code` property.
37
39
  * This is used to avoid `as` casting when you access the `code` property on errors returned by the module.
38
40
  */
39
41
  export declare const isErrorWithCode: (error: any) => error is NativeModuleError;
42
+ export {};
40
43
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAkB,SAAQ,KAAK;IAC9C,IAAI,EAAE,MAAM,CAAA;CACb;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;KAyBK;AACL,eAAO,MAAM,UAAU;;;;EAIrB,CAAA;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,UAAW,GAAG,KAAG,KAAK,IAAI,iBAIrD,CAAA"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/errors.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;KAyBK;AACL,eAAO,MAAM,UAAU;;;;;EAKrB,CAAA;AAEF,KAAK,UAAU,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAA;AAE9D,MAAM,WAAW,iBAAkB,SAAQ,KAAK;IAC9C,IAAI,EAAE,UAAU,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;CACjC;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,UAAW,GAAG,KAAG,KAAK,IAAI,iBAIrD,CAAA"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * For each uri whose release was requested, the result will contain an object with the uri and a status.
2
+ * For each uri whose release was requested, the result contains an object with the uri and a status.
3
3
  * */
4
4
  export type ReleaseLongTermAccessResult = Array<{
5
5
  uri: string;
@@ -11,7 +11,7 @@ export type SaveDocumentsOptions = {
11
11
  sourceUris: string[];
12
12
  /**
13
13
  * Android-only: The MIME type of the file to be stored.
14
- * It is recommended to provide this value, otherwise the system will try to infer it from the sourceUri using ContentResolver.
14
+ * It is recommended to provide this value, otherwise the system tries to infer it from the sourceUri using ContentResolver.
15
15
  * */
16
16
  mimeType?: string;
17
17
  /**
@@ -21,7 +21,7 @@ export type VirtualFileMeta = {
21
21
  /**
22
22
  * The registered extension for the given MIME type. Note that some MIME types map to multiple extensions.
23
23
  *
24
- * This call will return the most common extension for the given MIME type.
24
+ * This call returns the most common extension for the given MIME type.
25
25
  *
26
26
  * Example: `pdf`
27
27
  */
@@ -62,7 +62,7 @@ export type DocumentPickerResponse = {
62
62
  * */
63
63
  size: number | null;
64
64
  /**
65
- * Android: whether the file is a virtual file (such as Google docs or sheets). Will be `null` on pre-Android 7.0 devices. On iOS, it's always `false`.
65
+ * Android: whether the file is a virtual file (such as Google docs or sheets). This is `null` on pre-Android 7.0 devices. On iOS, it's always `false`.
66
66
  * */
67
67
  isVirtual: boolean | null;
68
68
  /**
@@ -73,7 +73,7 @@ export type DocumentPickerResponse = {
73
73
  /**
74
74
  * Android: Some document providers on Android (especially those popular in Asia, it seems)
75
75
  * do not respect the request for limiting selectable file types.
76
- * `hasRequestedType` will be false if the user picked a file that does not have one of the requested types.
76
+ * `hasRequestedType` is false if the user picked a file that does not have one of the requested types.
77
77
  *
78
78
  * You need to do your own post-processing and display an error to the user if this is important to your app.
79
79
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-documents/picker",
3
- "version": "11.0.3",
3
+ "version": "12.0.0",
4
4
  "description": "A react native interface to access documents from dropbox, google drive, iCloud...",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -61,7 +61,8 @@
61
61
  },
62
62
  "homepage": "https://github.com/react-native-documents/document-picker#readme",
63
63
  "publishConfig": {
64
- "access": "public"
64
+ "access": "public",
65
+ "provenance": true
65
66
  },
66
67
  "devDependencies": {
67
68
  "@tsconfig/node18": "^18.2.4",
@@ -14,6 +14,7 @@ Pod::Spec.new do |s|
14
14
  s.source = { :git => "https://github.com/react-native-documents/sponsors-only.git", :tag => "v#{s.version}" }
15
15
 
16
16
  s.source_files = ["ios/**/*.{h,m,mm,swift}"]
17
+ s.swift_version = '6.0'
17
18
 
18
19
  # Swift/Objective-C compatibility
19
20
  s.pod_target_xcconfig = {
package/src/errors.ts CHANGED
@@ -1,10 +1,7 @@
1
- export interface NativeModuleError extends Error {
2
- code: string
3
- }
4
-
5
1
  const OPERATION_CANCELED = 'OPERATION_CANCELED'
6
2
  const IN_PROGRESS = 'ASYNC_OP_IN_PROGRESS'
7
3
  const UNABLE_TO_OPEN_FILE_TYPE = 'UNABLE_TO_OPEN_FILE_TYPE'
4
+ const NULL_PRESENTER = 'NULL_PRESENTER'
8
5
 
9
6
  /**
10
7
  * Error codes that can be returned by the module, and are available on the `code` property of the error.
@@ -36,8 +33,15 @@ export const errorCodes = Object.freeze({
36
33
  OPERATION_CANCELED,
37
34
  IN_PROGRESS,
38
35
  UNABLE_TO_OPEN_FILE_TYPE,
36
+ NULL_PRESENTER,
39
37
  })
40
38
 
39
+ type ErrorCodes = (typeof errorCodes)[keyof typeof errorCodes]
40
+
41
+ export interface NativeModuleError extends Error {
42
+ code: ErrorCodes | (string & {})
43
+ }
44
+
41
45
  /**
42
46
  * TypeScript helper to check if an object has the `code` property.
43
47
  * This is used to avoid `as` casting when you access the `code` property on errors returned by the module.
package/src/release.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { NativeDocumentPicker } from './spec/NativeDocumentPicker'
2
2
 
3
3
  /**
4
- * For each uri whose release was requested, the result will contain an object with the uri and a status.
4
+ * For each uri whose release was requested, the result contains an object with the uri and a status.
5
5
  * */
6
6
  export type ReleaseLongTermAccessResult = Array<
7
7
  | {
@@ -15,7 +15,7 @@ export type SaveDocumentsOptions = {
15
15
  sourceUris: string[]
16
16
  /**
17
17
  * Android-only: The MIME type of the file to be stored.
18
- * It is recommended to provide this value, otherwise the system will try to infer it from the sourceUri using ContentResolver.
18
+ * It is recommended to provide this value, otherwise the system tries to infer it from the sourceUri using ContentResolver.
19
19
  * */
20
20
  mimeType?: string
21
21
  /**
package/src/types.ts CHANGED
@@ -25,7 +25,7 @@ export type VirtualFileMeta = {
25
25
  /**
26
26
  * The registered extension for the given MIME type. Note that some MIME types map to multiple extensions.
27
27
  *
28
- * This call will return the most common extension for the given MIME type.
28
+ * This call returns the most common extension for the given MIME type.
29
29
  *
30
30
  * Example: `pdf`
31
31
  */
@@ -68,7 +68,7 @@ export type DocumentPickerResponse = {
68
68
  size: number | null
69
69
 
70
70
  /**
71
- * Android: whether the file is a virtual file (such as Google docs or sheets). Will be `null` on pre-Android 7.0 devices. On iOS, it's always `false`.
71
+ * Android: whether the file is a virtual file (such as Google docs or sheets). This is `null` on pre-Android 7.0 devices. On iOS, it's always `false`.
72
72
  * */
73
73
  isVirtual: boolean | null
74
74
  /**
@@ -80,7 +80,7 @@ export type DocumentPickerResponse = {
80
80
  /**
81
81
  * Android: Some document providers on Android (especially those popular in Asia, it seems)
82
82
  * do not respect the request for limiting selectable file types.
83
- * `hasRequestedType` will be false if the user picked a file that does not have one of the requested types.
83
+ * `hasRequestedType` is false if the user picked a file that does not have one of the requested types.
84
84
  *
85
85
  * You need to do your own post-processing and display an error to the user if this is important to your app.
86
86
  *
@@ -1,36 +0,0 @@
1
- package com.reactnativedocumentpicker
2
-
3
- import android.content.Intent
4
- import android.os.Build
5
- import android.provider.DocumentsContract
6
-
7
- object IntentFactory {
8
- fun getPickIntent(options: PickOptions): Intent {
9
- // TODO option for extra task on stack?
10
- // reminder - flags are for granting rights to others
11
-
12
- return Intent(options.action).apply {
13
- val types = options.mimeTypes
14
-
15
- type =
16
- if (types.size > 1) {
17
- putExtra(Intent.EXTRA_MIME_TYPES, types)
18
- options.intentFilterTypes
19
- } else {
20
- types[0]
21
- }
22
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
23
- options.initialDirectoryUrl != null
24
- ) {
25
- // only works for ACTION_OPEN_DOCUMENT
26
- // TODO must be URI
27
- putExtra(DocumentsContract.EXTRA_INITIAL_URI, options.initialDirectoryUrl)
28
- }
29
- if (!options.allowVirtualFiles) {
30
- addCategory(Intent.CATEGORY_OPENABLE)
31
- }
32
- putExtra(Intent.EXTRA_LOCAL_ONLY, options.localOnly)
33
- putExtra(Intent.EXTRA_ALLOW_MULTIPLE, options.multiple)
34
- }
35
- }
36
- }
@@ -1,105 +0,0 @@
1
- // LICENSE: see License.md in the package root
2
- package com.reactnativedocumentpicker;
3
-
4
- import android.util.Log;
5
-
6
- import androidx.annotation.NonNull;
7
-
8
- import com.facebook.react.bridge.Promise;
9
-
10
- public class PromiseWrapper {
11
-
12
- private Promise promise;
13
- private String nameOfCallInProgress;
14
- public static final String ASYNC_OP_IN_PROGRESS = "ASYNC_OP_IN_PROGRESS";
15
- public static final String E_DOCUMENT_PICKER_CANCELED = "OPERATION_CANCELED";
16
- private final String MODULE_NAME;
17
-
18
- public PromiseWrapper(String moduleName) {
19
- MODULE_NAME = moduleName;
20
- }
21
-
22
- public void setPromiseRejectingPrevious(Promise promise, @NonNull String fromCallsite) {
23
- Promise previousPromise = this.promise;
24
- if (previousPromise != null) {
25
- rejectPreviousPromiseBecauseNewOneIsInProgress(previousPromise, fromCallsite);
26
- }
27
- this.promise = promise;
28
- nameOfCallInProgress = fromCallsite;
29
- }
30
-
31
- public boolean trySetPromiseRejectingIncoming(Promise promise, @NonNull String fromCallsite) {
32
- Promise previousPromise = this.promise;
33
- if (previousPromise != null) {
34
- rejectNewPromiseBecauseOldOneIsInProgress(promise, fromCallsite);
35
- return false;
36
- }
37
- this.promise = promise;
38
- nameOfCallInProgress = fromCallsite;
39
- return true;
40
- }
41
-
42
- public void resolve(Object value) {
43
- Promise resolver = promise;
44
- if (resolver == null) {
45
- Log.e(MODULE_NAME, "cannot resolve promise because it's null");
46
- return;
47
- }
48
-
49
- resetMembers();
50
- resolver.resolve(value);
51
- }
52
-
53
- public void reject(@NonNull String code, Exception e) {
54
- String message = e.getLocalizedMessage() != null ? e.getLocalizedMessage() :
55
- e.getMessage() != null ? e.getMessage() : "unknown error";
56
-
57
- this.reject(code, message, e);
58
- }
59
-
60
- public void reject(Exception e) {
61
- String message = e.getLocalizedMessage() != null ? e.getLocalizedMessage() :
62
- e.getMessage() != null ? e.getMessage() : "unknown error";
63
-
64
- this.reject(nameOfCallInProgress, message, e);
65
- }
66
-
67
- public void rejectAsUserCancelledOperation() {
68
- this.reject(E_DOCUMENT_PICKER_CANCELED, "user canceled the document picker");
69
- }
70
-
71
- public void reject(@NonNull String code, @NonNull String message) {
72
- reject(code, message, null);
73
- }
74
- public void reject(@NonNull String code, @NonNull String message, Exception e) {
75
- Promise rejecter = promise;
76
- if (rejecter == null) {
77
- Log.e(MODULE_NAME, "cannot reject promise because it's null");
78
- return;
79
- }
80
-
81
- resetMembers();
82
- rejecter.reject(code, message, e);
83
- }
84
-
85
- public String getNameOfCallInProgress() {
86
- return nameOfCallInProgress;
87
- }
88
-
89
- private void resetMembers() {
90
- nameOfCallInProgress = null;
91
- promise = null;
92
- }
93
-
94
-
95
- private void rejectPreviousPromiseBecauseNewOneIsInProgress(Promise promise, String requestedOperation) {
96
- // TODO better message
97
- promise.reject(ASYNC_OP_IN_PROGRESS, "Warning: previous promise did not settle and was overwritten. " +
98
- "You've called \"" + requestedOperation + "\" while \"" + getNameOfCallInProgress() + "\" was already in progress and has not completed yet.");
99
- }
100
- private void rejectNewPromiseBecauseOldOneIsInProgress(Promise promise, String requestedOperation) {
101
- // TODO better message
102
- promise.reject(ASYNC_OP_IN_PROGRESS, "Warning: previous promise did not settle and you attempted to overwrite it. " +
103
- "You've called \"" + requestedOperation + "\" while \"" + getNameOfCallInProgress() + "\" was already in progress and has not completed yet.");
104
- }
105
- }
@@ -1,2 +0,0 @@
1
- public typealias RNDPPromiseResolveBlock = ((Any?) -> Void)
2
- public typealias RNDPPromiseRejectBlock = (String?, String?, Error?) -> Void