@capgo/capacitor-file-picker 8.2.5 → 8.2.7

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.
package/README.md CHANGED
@@ -8,7 +8,6 @@ Let users pick files, images, videos and folders with the native pickers on iOS
8
8
  <p><b>Capgo</b>: push fixes to your Capacitor users in minutes, build signed iOS and Android apps without a Mac, and roll back in one click.</p>
9
9
  <h2><a href="https://capgo.app/register/?ref=plugin_file_picker">➡️ Get started for free</a></h2>
10
10
  <p>14-day unlimited free trial. No credit card required</p>
11
- <p><a href="https://capgo.app/consulting/?ref=plugin_file_picker">Missing a feature? We'll build the plugin for you 💪</a></p>
12
11
  </div>
13
12
 
14
13
  > 🤖 **Building with an AI coding agent?** Install [Capgo skills](https://capgo.app/skills/?ref=plugin_file_picker) so Claude Code, Codex, Cursor, Copilot, or Gemini CLI know how to install and use `@capgo/capacitor-file-picker` in your Capacitor app: `npx skills add Cap-go/capgo-skills`. Then ask your agent: *"Add @capgo/capacitor-file-picker to my Capacitor app and wire it up."* [Agent setup guides](https://capgo.app/agents/?ref=plugin_file_picker) · [Hosted MCP](https://capgo.app/docs/ai/mcp/?ref=plugin_file_picker)
@@ -153,6 +152,10 @@ pickImages(options?: PickMediaOptions | undefined) => Promise<PickFilesResult>
153
152
 
154
153
  Pick one or more images from the gallery.
155
154
  Android/iOS only.
155
+ On Android, `limit` is enforced by the system photo picker when available
156
+ (Android 13+, or Android 11-12 with the Google Play system photo picker extension).
157
+ Older Android versions may allow selecting more items than `limit`; results are
158
+ truncated to `limit` before they are returned.
156
159
 
157
160
  | Param | Type | Description |
158
161
  | ------------- | ------------------------------------------------------------- | ---------------------------- |
@@ -173,6 +176,10 @@ pickVideos(options?: PickMediaOptions | undefined) => Promise<PickFilesResult>
173
176
 
174
177
  Pick one or more videos from the gallery.
175
178
  Android/iOS only.
179
+ On Android, `limit` is enforced by the system photo picker when available
180
+ (Android 13+, or Android 11-12 with the Google Play system photo picker extension).
181
+ Older Android versions may allow selecting more items than `limit`; results are
182
+ truncated to `limit` before they are returned.
176
183
 
177
184
  | Param | Type | Description |
178
185
  | ------------- | ------------------------------------------------------------- | ---------------------------- |
@@ -391,12 +398,12 @@ Options for picking files.
391
398
 
392
399
  Options for picking media (images/videos).
393
400
 
394
- | Prop | Type | Description | Default |
395
- | --------------------- | -------------------- | ------------------------------------------------------------------------------------------- | ------------------ |
396
- | **`limit`** | <code>number</code> | Maximum number of files to pick. Set to 0 for unlimited (platform default). | <code>0</code> |
397
- | **`readData`** | <code>boolean</code> | Whether to read the file data as base64. Note: Reading large files may cause memory issues. | <code>false</code> |
398
- | **`skipTranscoding`** | <code>boolean</code> | iOS only: Skip transcoding of videos. | <code>false</code> |
399
- | **`ordered`** | <code>boolean</code> | iOS 15+ only: Show ordered selection badges. | <code>false</code> |
401
+ | Prop | Type | Description | Default |
402
+ | --------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
403
+ | **`limit`** | <code>number</code> | Maximum number of files to pick. Set to 0 for unlimited (platform default). On Android, when the system photo picker is available, the platform enforces this limit (capped by the device maximum). On older Android versions the picker may not enforce the limit; the plugin truncates the returned list to this value when needed. | <code>0</code> |
404
+ | **`readData`** | <code>boolean</code> | Whether to read the file data as base64. Note: Reading large files may cause memory issues. | <code>false</code> |
405
+ | **`skipTranscoding`** | <code>boolean</code> | iOS only: Skip transcoding of videos. | <code>false</code> |
406
+ | **`ordered`** | <code>boolean</code> | iOS 15+ only: Show ordered selection badges. | <code>false</code> |
400
407
 
401
408
 
402
409
  #### PickDirectoryResult
@@ -53,6 +53,8 @@ dependencies {
53
53
  implementation project(':capacitor-android')
54
54
  implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
55
55
  testImplementation "junit:junit:$junitVersion"
56
+ testImplementation "org.mockito:mockito-core:5.14.2"
57
+ testImplementation "org.robolectric:robolectric:4.16"
56
58
  androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
57
59
  androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
58
60
  }
@@ -2,6 +2,7 @@ package app.capgo.capacitor.filepicker;
2
2
 
3
3
  import android.Manifest;
4
4
  import android.app.Activity;
5
+ import android.content.ActivityNotFoundException;
5
6
  import android.content.ClipData;
6
7
  import android.content.Intent;
7
8
  import android.database.Cursor;
@@ -50,14 +51,30 @@ import org.json.JSONException;
50
51
  )
51
52
  public class CapgoFilePickerPlugin extends Plugin {
52
53
 
53
- private final String pluginVersion = "8.2.5";
54
- private boolean readData = false;
54
+ private final String pluginVersion = "8.2.7";
55
+
56
+ private PickerLaunchQueue pickerLaunchQueue;
57
+
58
+ @Override
59
+ public void load() {
60
+ super.load();
61
+ pickerLaunchQueue = new PickerLaunchQueue((runnable) -> bridge.executeOnMainThread(runnable), this::launchPickerActivity);
62
+ }
63
+
64
+ private boolean launchPickerActivity(PickerLaunchQueue.PendingPickerLaunch launch) {
65
+ try {
66
+ startActivityForResult(launch.call, launch.getIntent(), launch.callbackName);
67
+ return true;
68
+ } catch (ActivityNotFoundException e) {
69
+ launch.call.reject("Unable to open file picker", e);
70
+ return false;
71
+ }
72
+ }
55
73
 
56
74
  // MARK: - Pick Files
57
75
 
58
76
  @PluginMethod
59
77
  public void pickFiles(PluginCall call) {
60
- readData = call.getBoolean("readData", false);
61
78
  int limit = call.getInt("limit", 0);
62
79
 
63
80
  Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
@@ -86,53 +103,49 @@ public class CapgoFilePickerPlugin extends Plugin {
86
103
  intent.addCategory(Intent.CATEGORY_OPENABLE);
87
104
  intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, limit != 1);
88
105
 
89
- startActivityForResult(call, intent, "pickFilesResult");
106
+ enqueuePickerLaunch(call, intent, "pickFilesResult", false);
90
107
  }
91
108
 
92
109
  // MARK: - Pick Images
93
110
 
94
111
  @PluginMethod
95
112
  public void pickImages(PluginCall call) {
96
- readData = call.getBoolean("readData", false);
97
113
  int limit = call.getInt("limit", 0);
114
+ boolean photoPickerAvailable = MediaPickerIntents.isPhotoPickerAvailable();
115
+ boolean truncateResults = MediaPickerIntents.shouldTruncateResultsToLimit(photoPickerAvailable);
98
116
 
99
- Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
100
- intent.setType("image/*");
101
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, limit != 1);
102
-
103
- startActivityForResult(call, intent, "pickMediaResult");
117
+ Intent intent = MediaPickerIntents.buildPickImagesIntent(limit, photoPickerAvailable);
118
+ enqueuePickerLaunch(call, intent, "pickMediaResult", truncateResults);
104
119
  }
105
120
 
106
121
  // MARK: - Pick Videos
107
122
 
108
123
  @PluginMethod
109
124
  public void pickVideos(PluginCall call) {
110
- readData = call.getBoolean("readData", false);
111
125
  int limit = call.getInt("limit", 0);
126
+ boolean photoPickerAvailable = MediaPickerIntents.isPhotoPickerAvailable();
127
+ boolean truncateResults = MediaPickerIntents.shouldTruncateResultsToLimit(photoPickerAvailable);
112
128
 
113
- Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
114
- intent.setType("video/*");
115
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, limit != 1);
116
-
117
- startActivityForResult(call, intent, "pickMediaResult");
129
+ Intent intent = MediaPickerIntents.buildPickVideosIntent(limit, photoPickerAvailable);
130
+ enqueuePickerLaunch(call, intent, "pickMediaResult", truncateResults);
118
131
  }
119
132
 
120
133
  // MARK: - Pick Media
121
134
 
122
135
  @PluginMethod
123
136
  public void pickMedia(PluginCall call) {
124
- readData = call.getBoolean("readData", false);
125
137
  int limit = call.getInt("limit", 0);
126
138
 
127
139
  Intent intent;
128
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
140
+ boolean photoPickerAvailable = MediaPickerIntents.isPhotoPickerAvailable();
141
+ boolean truncateResults = false;
142
+ if (photoPickerAvailable) {
129
143
  intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
130
144
  intent.setType("*/*");
131
145
  intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] { "image/*", "video/*" });
132
- if (limit > 1) {
133
- intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, limit);
134
- }
146
+ MediaPickerIntents.applyPhotoPickerMaxLimit(intent, limit, MediaStore.getPickImagesMaxLimit());
135
147
  } else {
148
+ truncateResults = true;
136
149
  intent = new Intent(Intent.ACTION_GET_CONTENT);
137
150
  intent.setType("*/*");
138
151
  intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] { "image/*", "video/*" });
@@ -140,7 +153,7 @@ public class CapgoFilePickerPlugin extends Plugin {
140
153
  intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, limit != 1);
141
154
  }
142
155
 
143
- startActivityForResult(call, intent, "pickMediaResult");
156
+ enqueuePickerLaunch(call, intent, "pickMediaResult", truncateResults);
144
157
  }
145
158
 
146
159
  // MARK: - Pick Directory
@@ -150,7 +163,7 @@ public class CapgoFilePickerPlugin extends Plugin {
150
163
  Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
151
164
  intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
152
165
 
153
- startActivityForResult(call, intent, "pickDirectoryResult");
166
+ enqueuePickerLaunch(call, intent, "pickDirectoryResult", false);
154
167
  }
155
168
 
156
169
  // MARK: - Convert HEIC to JPEG
@@ -253,89 +266,123 @@ public class CapgoFilePickerPlugin extends Plugin {
253
266
 
254
267
  @ActivityCallback
255
268
  private void pickFilesResult(PluginCall call, ActivityResult result) {
256
- handleFilePickerResult(call, result);
269
+ handleFilePickerResult(call, result, false);
257
270
  }
258
271
 
259
272
  @ActivityCallback
260
273
  private void pickMediaResult(PluginCall call, ActivityResult result) {
261
- handleFilePickerResult(call, result);
274
+ handleFilePickerResult(call, result, truncateResultsForCall(call));
275
+ }
276
+
277
+ private boolean truncateResultsForCall(PluginCall call) {
278
+ return pickerLaunchQueue.isTruncateResultsForCall(call);
262
279
  }
263
280
 
264
- private void handleFilePickerResult(PluginCall call, ActivityResult result) {
281
+ private void handleFilePickerResult(PluginCall call, ActivityResult result, boolean truncateResultsToLimit) {
265
282
  if (call == null) {
283
+ completeActivePickerLaunch();
266
284
  return;
267
285
  }
268
286
 
269
- if (result.getResultCode() != Activity.RESULT_OK) {
270
- notifyListeners("pickerDismissed", new JSObject());
271
- JSObject ret = new JSObject();
272
- ret.put("files", new JSArray());
273
- call.resolve(ret);
274
- return;
275
- }
287
+ try {
288
+ if (result.getResultCode() != Activity.RESULT_OK) {
289
+ notifyListeners("pickerDismissed", new JSObject());
290
+ JSObject ret = new JSObject();
291
+ ret.put("files", new JSArray());
292
+ call.resolve(ret);
293
+ return;
294
+ }
276
295
 
277
- Intent data = result.getData();
278
- if (data == null) {
279
- JSObject ret = new JSObject();
280
- ret.put("files", new JSArray());
281
- call.resolve(ret);
282
- return;
283
- }
296
+ Intent data = result.getData();
297
+ if (data == null) {
298
+ JSObject ret = new JSObject();
299
+ ret.put("files", new JSArray());
300
+ call.resolve(ret);
301
+ return;
302
+ }
284
303
 
285
- List<Uri> uris = new ArrayList<>();
304
+ List<Uri> uris = new ArrayList<>();
286
305
 
287
- ClipData clipData = data.getClipData();
288
- if (clipData != null) {
289
- for (int i = 0; i < clipData.getItemCount(); i++) {
290
- uris.add(clipData.getItemAt(i).getUri());
306
+ ClipData clipData = data.getClipData();
307
+ if (clipData != null) {
308
+ for (int i = 0; i < clipData.getItemCount(); i++) {
309
+ uris.add(clipData.getItemAt(i).getUri());
310
+ }
311
+ } else if (data.getData() != null) {
312
+ uris.add(data.getData());
291
313
  }
292
- } else if (data.getData() != null) {
293
- uris.add(data.getData());
294
- }
295
314
 
296
- JSArray files = new JSArray();
297
- for (Uri uri : uris) {
298
- JSObject fileInfo = getFileInfo(uri);
299
- if (fileInfo != null) {
300
- files.put(fileInfo);
315
+ if (truncateResultsToLimit) {
316
+ int limit = call.getInt("limit", 0);
317
+ uris = MediaPickerIntents.truncateUris(uris, limit);
301
318
  }
302
- }
303
319
 
304
- JSObject ret = new JSObject();
305
- ret.put("files", files);
306
- call.resolve(ret);
320
+ boolean readData = call.getBoolean("readData", false);
321
+ JSArray files = new JSArray();
322
+ for (Uri uri : uris) {
323
+ JSObject fileInfo = getFileInfo(uri, readData);
324
+ if (fileInfo != null) {
325
+ files.put(fileInfo);
326
+ }
327
+ }
328
+
329
+ JSObject ret = new JSObject();
330
+ ret.put("files", files);
331
+ call.resolve(ret);
332
+ } finally {
333
+ completeActivePickerLaunch();
334
+ }
307
335
  }
308
336
 
309
337
  @ActivityCallback
310
338
  private void pickDirectoryResult(PluginCall call, ActivityResult result) {
311
339
  if (call == null) {
340
+ completeActivePickerLaunch();
312
341
  return;
313
342
  }
314
343
 
315
- if (result.getResultCode() != Activity.RESULT_OK) {
316
- notifyListeners("pickerDismissed", new JSObject());
317
- call.reject("User cancelled");
318
- return;
319
- }
344
+ try {
345
+ if (result.getResultCode() != Activity.RESULT_OK) {
346
+ notifyListeners("pickerDismissed", new JSObject());
347
+ call.reject("User cancelled");
348
+ return;
349
+ }
320
350
 
321
- Intent data = result.getData();
322
- if (data == null || data.getData() == null) {
323
- call.reject("No directory selected");
324
- return;
351
+ Intent data = result.getData();
352
+ if (data == null || data.getData() == null) {
353
+ call.reject("No directory selected");
354
+ return;
355
+ }
356
+
357
+ Uri uri = data.getData();
358
+ String path = getPathFromUri(uri);
359
+
360
+ JSObject ret = new JSObject();
361
+ ret.put("path", path != null ? path : uri.toString());
362
+ call.resolve(ret);
363
+ } finally {
364
+ completeActivePickerLaunch();
325
365
  }
366
+ }
326
367
 
327
- Uri uri = data.getData();
328
- String path = getPathFromUri(uri);
368
+ private void enqueuePickerLaunch(PluginCall call, Intent intent, String callbackName, boolean truncateResultsToLimit) {
369
+ PickerLaunchQueue.PendingPickerLaunch launch = new PickerLaunchQueue.PendingPickerLaunch(
370
+ call,
371
+ intent,
372
+ callbackName,
373
+ truncateResultsToLimit
374
+ );
375
+ pickerLaunchQueue.enqueue(launch);
376
+ }
329
377
 
330
- JSObject ret = new JSObject();
331
- ret.put("path", path != null ? path : uri.toString());
332
- call.resolve(ret);
378
+ private void completeActivePickerLaunch() {
379
+ pickerLaunchQueue.completeActive();
333
380
  }
334
381
 
335
382
  // MARK: - Helpers
336
383
 
337
384
  @Nullable
338
- private JSObject getFileInfo(Uri uri) {
385
+ private JSObject getFileInfo(Uri uri, boolean readData) {
339
386
  try {
340
387
  JSObject result = new JSObject();
341
388
 
@@ -415,7 +462,6 @@ public class CapgoFilePickerPlugin extends Plugin {
415
462
  }
416
463
  }
417
464
 
418
- // Read data if requested
419
465
  if (readData) {
420
466
  try (InputStream is = getContext().getContentResolver().openInputStream(uri)) {
421
467
  if (is != null) {
@@ -0,0 +1,87 @@
1
+ package app.capgo.capacitor.filepicker;
2
+
3
+ import android.content.Intent;
4
+ import android.net.Uri;
5
+ import android.os.Build;
6
+ import android.os.ext.SdkExtensions;
7
+ import android.provider.MediaStore;
8
+ import java.util.ArrayList;
9
+ import java.util.List;
10
+
11
+ /** Builds gallery picker intents and applies selection limits on Android. */
12
+ final class MediaPickerIntents {
13
+
14
+ private MediaPickerIntents() {}
15
+
16
+ static boolean isPhotoPickerAvailable() {
17
+ return isPhotoPickerAvailable(Build.VERSION.SDK_INT, getRExtensionVersion());
18
+ }
19
+
20
+ static boolean isPhotoPickerAvailable(int sdkInt, int rExtensionVersion) {
21
+ if (sdkInt >= Build.VERSION_CODES.TIRAMISU) {
22
+ return true;
23
+ }
24
+ if (sdkInt >= Build.VERSION_CODES.R) {
25
+ return rExtensionVersion >= 2;
26
+ }
27
+ return false;
28
+ }
29
+
30
+ private static int getRExtensionVersion() {
31
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
32
+ return SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R);
33
+ }
34
+ return 0;
35
+ }
36
+
37
+ static Intent buildPickImagesIntent(int limit, boolean photoPickerAvailable) {
38
+ return buildGalleryIntent("image/*", MediaStore.Images.Media.EXTERNAL_CONTENT_URI, limit, photoPickerAvailable);
39
+ }
40
+
41
+ static Intent buildPickVideosIntent(int limit, boolean photoPickerAvailable) {
42
+ return buildGalleryIntent("video/*", MediaStore.Video.Media.EXTERNAL_CONTENT_URI, limit, photoPickerAvailable);
43
+ }
44
+
45
+ static int resolvePhotoPickerMaxLimit(int limit, int pickImagesMaxLimit) {
46
+ if (limit <= 0) {
47
+ return pickImagesMaxLimit > 0 ? pickImagesMaxLimit : limit;
48
+ }
49
+ return pickImagesMaxLimit > 0 ? Math.min(limit, pickImagesMaxLimit) : limit;
50
+ }
51
+
52
+ static void applyPhotoPickerMaxLimit(Intent intent, int limit, int pickImagesMaxLimit) {
53
+ if (limit == 1) {
54
+ return;
55
+ }
56
+ intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, resolvePhotoPickerMaxLimit(limit, pickImagesMaxLimit));
57
+ }
58
+
59
+ static Intent buildGalleryIntent(String mimeType, Uri legacyPickUri, int limit, boolean photoPickerAvailable) {
60
+ return buildGalleryIntent(mimeType, legacyPickUri, limit, photoPickerAvailable, MediaStore.getPickImagesMaxLimit());
61
+ }
62
+
63
+ static Intent buildGalleryIntent(String mimeType, Uri legacyPickUri, int limit, boolean photoPickerAvailable, int pickImagesMaxLimit) {
64
+ if (photoPickerAvailable) {
65
+ Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
66
+ intent.setType(mimeType);
67
+ applyPhotoPickerMaxLimit(intent, limit, pickImagesMaxLimit);
68
+ return intent;
69
+ }
70
+
71
+ Intent intent = new Intent(Intent.ACTION_PICK, legacyPickUri);
72
+ intent.setType(mimeType);
73
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, limit != 1);
74
+ return intent;
75
+ }
76
+
77
+ static boolean shouldTruncateResultsToLimit(boolean photoPickerAvailable) {
78
+ return !photoPickerAvailable;
79
+ }
80
+
81
+ static List<Uri> truncateUris(List<Uri> uris, int limit) {
82
+ if (limit <= 0 || uris.size() <= limit) {
83
+ return uris;
84
+ }
85
+ return new ArrayList<>(uris.subList(0, limit));
86
+ }
87
+ }
@@ -0,0 +1,126 @@
1
+ package app.capgo.capacitor.filepicker;
2
+
3
+ import com.getcapacitor.PluginCall;
4
+ import java.util.ArrayDeque;
5
+ import java.util.Queue;
6
+
7
+ /**
8
+ * Serializes picker activity launches so only one Capacitor saved activity call is active.
9
+ * All queue mutations and launches run on the main thread.
10
+ */
11
+ final class PickerLaunchQueue {
12
+
13
+ static final class PendingPickerLaunch {
14
+
15
+ final PluginCall call;
16
+ final IntentHolder intent;
17
+ final String callbackName;
18
+ final boolean truncateResultsToLimit;
19
+
20
+ PendingPickerLaunch(PluginCall call, android.content.Intent intent, String callbackName, boolean truncateResultsToLimit) {
21
+ this.call = call;
22
+ this.intent = new IntentHolder(intent);
23
+ this.callbackName = callbackName;
24
+ this.truncateResultsToLimit = truncateResultsToLimit;
25
+ }
26
+
27
+ android.content.Intent getIntent() {
28
+ return intent.get();
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Holds a copy of the intent so queued launches are not affected if callers mutate the original.
34
+ */
35
+ private static final class IntentHolder {
36
+
37
+ private final android.content.Intent intent;
38
+
39
+ IntentHolder(android.content.Intent intent) {
40
+ this.intent = new android.content.Intent(intent);
41
+ }
42
+
43
+ android.content.Intent get() {
44
+ return intent;
45
+ }
46
+ }
47
+
48
+ interface MainThreadScheduler {
49
+ void run(Runnable runnable);
50
+ }
51
+
52
+ /**
53
+ * @return true when the activity was launched and the call is retained for the result callback
54
+ */
55
+ interface ActivityLauncher {
56
+ boolean launch(PendingPickerLaunch launch);
57
+ }
58
+
59
+ private final MainThreadScheduler mainThreadScheduler;
60
+ private final ActivityLauncher activityLauncher;
61
+ private final Queue<PendingPickerLaunch> pendingPickerLaunches = new ArrayDeque<>();
62
+ private PendingPickerLaunch activePickerLaunch;
63
+
64
+ PickerLaunchQueue(MainThreadScheduler mainThreadScheduler, ActivityLauncher activityLauncher) {
65
+ this.mainThreadScheduler = mainThreadScheduler;
66
+ this.activityLauncher = activityLauncher;
67
+ }
68
+
69
+ void enqueue(PendingPickerLaunch launch) {
70
+ mainThreadScheduler.run(() -> enqueueOnMainThread(launch));
71
+ }
72
+
73
+ void completeActive() {
74
+ mainThreadScheduler.run(this::completeActiveOnMainThread);
75
+ }
76
+
77
+ PendingPickerLaunch getActiveLaunch() {
78
+ return activePickerLaunch;
79
+ }
80
+
81
+ boolean isTruncateResultsForCall(PluginCall call) {
82
+ PendingPickerLaunch active = activePickerLaunch;
83
+ if (active != null && active.call == call) {
84
+ return active.truncateResultsToLimit;
85
+ }
86
+ return false;
87
+ }
88
+
89
+ private void enqueueOnMainThread(PendingPickerLaunch launch) {
90
+ if (activePickerLaunch != null) {
91
+ pendingPickerLaunches.add(launch);
92
+ return;
93
+ }
94
+ startPickerLaunch(launch);
95
+ }
96
+
97
+ private void completeActiveOnMainThread() {
98
+ activePickerLaunch = null;
99
+ startNextQueuedLaunch();
100
+ }
101
+
102
+ private void startNextQueuedLaunch() {
103
+ PendingPickerLaunch next = pendingPickerLaunches.poll();
104
+ if (next != null) {
105
+ startPickerLaunch(next);
106
+ }
107
+ }
108
+
109
+ private void startPickerLaunch(PendingPickerLaunch launch) {
110
+ boolean launched;
111
+ try {
112
+ launched = activityLauncher.launch(launch);
113
+ } catch (RuntimeException e) {
114
+ launch.call.reject("Unable to open file picker", e);
115
+ startNextQueuedLaunch();
116
+ return;
117
+ }
118
+
119
+ if (!launched) {
120
+ startNextQueuedLaunch();
121
+ return;
122
+ }
123
+
124
+ activePickerLaunch = launch;
125
+ }
126
+ }
package/dist/docs.json CHANGED
@@ -75,7 +75,7 @@
75
75
  "text": "```typescript\nconst result = await CapgoFilePicker.pickImages({\n limit: 10,\n readData: false\n});\nconsole.log('Picked images:', result.files);\n```"
76
76
  }
77
77
  ],
78
- "docs": "Pick one or more images from the gallery.\nAndroid/iOS only.",
78
+ "docs": "Pick one or more images from the gallery.\nAndroid/iOS only.\nOn Android, `limit` is enforced by the system photo picker when available\n(Android 13+, or Android 11-12 with the Google Play system photo picker extension).\nOlder Android versions may allow selecting more items than `limit`; results are\ntruncated to `limit` before they are returned.",
79
79
  "complexTypes": [
80
80
  "PickFilesResult",
81
81
  "PickMediaOptions"
@@ -111,7 +111,7 @@
111
111
  "text": "```typescript\nconst result = await CapgoFilePicker.pickVideos({\n limit: 3,\n skipTranscoding: true\n});\nconsole.log('Picked videos:', result.files);\n```"
112
112
  }
113
113
  ],
114
- "docs": "Pick one or more videos from the gallery.\nAndroid/iOS only.",
114
+ "docs": "Pick one or more videos from the gallery.\nAndroid/iOS only.\nOn Android, `limit` is enforced by the system photo picker when available\n(Android 13+, or Android 11-12 with the Google Play system photo picker extension).\nOlder Android versions may allow selecting more items than `limit`; results are\ntruncated to `limit` before they are returned.",
115
115
  "complexTypes": [
116
116
  "PickFilesResult",
117
117
  "PickMediaOptions"
@@ -557,7 +557,7 @@
557
557
  "name": "default"
558
558
  }
559
559
  ],
560
- "docs": "Maximum number of files to pick.\nSet to 0 for unlimited (platform default).",
560
+ "docs": "Maximum number of files to pick.\nSet to 0 for unlimited (platform default).\nOn Android, when the system photo picker is available, the platform enforces this\nlimit (capped by the device maximum). On older Android versions the picker may not\nenforce the limit; the plugin truncates the returned list to this value when needed.",
561
561
  "complexTypes": [],
562
562
  "type": "number | undefined"
563
563
  },
@@ -33,6 +33,9 @@ export interface PickMediaOptions {
33
33
  /**
34
34
  * Maximum number of files to pick.
35
35
  * Set to 0 for unlimited (platform default).
36
+ * On Android, when the system photo picker is available, the platform enforces this
37
+ * limit (capped by the device maximum). On older Android versions the picker may not
38
+ * enforce the limit; the plugin truncates the returned list to this value when needed.
36
39
  * @default 0
37
40
  */
38
41
  limit?: number;
@@ -195,6 +198,10 @@ export interface CapgoFilePickerPlugin {
195
198
  /**
196
199
  * Pick one or more images from the gallery.
197
200
  * Android/iOS only.
201
+ * On Android, `limit` is enforced by the system photo picker when available
202
+ * (Android 13+, or Android 11-12 with the Google Play system photo picker extension).
203
+ * Older Android versions may allow selecting more items than `limit`; results are
204
+ * truncated to `limit` before they are returned.
198
205
  *
199
206
  * @param options - Options for picking images
200
207
  * @returns Promise that resolves with the picked images
@@ -212,6 +219,10 @@ export interface CapgoFilePickerPlugin {
212
219
  /**
213
220
  * Pick one or more videos from the gallery.
214
221
  * Android/iOS only.
222
+ * On Android, `limit` is enforced by the system photo picker when available
223
+ * (Android 13+, or Android 11-12 with the Google Play system photo picker extension).
224
+ * Older Android versions may allow selecting more items than `limit`; results are
225
+ * truncated to `limit` before they are returned.
215
226
  *
216
227
  * @param options - Options for picking videos
217
228
  * @returns Promise that resolves with the picked videos
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n/**\n * Options for picking files.\n *\n * @since 8.0.0\n */\nexport interface PickFilesOptions {\n /**\n * List of accepted MIME types or file extensions.\n * On iOS, only MIME types are supported.\n * Examples: ['image/*'], ['application/pdf'], ['.pdf', '.doc']\n */\n types?: string[];\n /**\n * Maximum number of files to pick.\n * Set to 0 for unlimited (platform default).\n * @default 0\n */\n limit?: number;\n /**\n * Whether to read the file data as base64.\n * Note: Reading large files may cause memory issues.\n * @default false\n */\n readData?: boolean;\n}\n\n/**\n * Options for picking media (images/videos).\n *\n * @since 8.0.0\n */\nexport interface PickMediaOptions {\n /**\n * Maximum number of files to pick.\n * Set to 0 for unlimited (platform default).\n * @default 0\n */\n limit?: number;\n /**\n * Whether to read the file data as base64.\n * Note: Reading large files may cause memory issues.\n * @default false\n */\n readData?: boolean;\n /**\n * iOS only: Skip transcoding of videos.\n * @default false\n */\n skipTranscoding?: boolean;\n /**\n * iOS 15+ only: Show ordered selection badges.\n * @default false\n */\n ordered?: boolean;\n}\n\n/**\n * Options for converting HEIC to JPEG.\n *\n * @since 8.0.0\n */\nexport interface ConvertHeicToJpegOptions {\n /** The path to the HEIC file to convert */\n path: string;\n /**\n * The compression quality for JPEG (0.0 - 1.0).\n * @default 0.9\n */\n quality?: number;\n}\n\n/**\n * Result of HEIC to JPEG conversion.\n *\n * @since 8.0.0\n */\nexport interface ConvertHeicToJpegResult {\n /** The path to the converted JPEG file */\n path: string;\n}\n\n/**\n * Options for copying a file.\n *\n * @since 8.0.0\n */\nexport interface CopyFileOptions {\n /** Source file path */\n from: string;\n /** Destination file path */\n to: string;\n /**\n * Whether to overwrite if destination exists.\n * @default false\n */\n overwrite?: boolean;\n}\n\n/**\n * Represents a picked file.\n *\n * @since 8.0.0\n */\nexport interface PickedFile {\n /** The name of the file */\n name: string;\n /** The path to the file */\n path?: string;\n /** The MIME type of the file */\n mimeType: string;\n /** The size of the file in bytes */\n size: number;\n /**\n * The base64 encoded data of the file.\n * Only present if readData was true.\n */\n data?: string;\n /**\n * The Blob instance of the file.\n * Web only.\n */\n blob?: Blob;\n /** Width in pixels (images/videos only) */\n width?: number;\n /** Height in pixels (images/videos only) */\n height?: number;\n /** Duration in seconds (videos only) */\n duration?: number;\n /** Last modified timestamp in milliseconds */\n modifiedAt?: number;\n}\n\n/**\n * Result of picking files.\n *\n * @since 8.0.0\n */\nexport interface PickFilesResult {\n /** Array of picked files */\n files: PickedFile[];\n}\n\n/**\n * Result of picking a directory.\n *\n * @since 8.0.0\n */\nexport interface PickDirectoryResult {\n /** The path to the selected directory */\n path: string;\n}\n\n/**\n * Permission status for file access.\n *\n * @since 8.0.0\n */\nexport interface PermissionStatus {\n /**\n * Whether broad external storage or media permission is granted.\n * Picker APIs that return user-selected files usually do not require this on Android 13+.\n */\n readExternalStorage: PermissionState;\n /** Whether permission to access media location is granted */\n accessMediaLocation?: PermissionState;\n}\n\n/**\n * Permission state values.\n *\n * @since 8.0.0\n */\nexport type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied';\n\n/**\n * Listener callback for picker dismissed event.\n *\n * @since 8.0.0\n */\nexport type PickerDismissedListener = (event: null) => void;\n\n/**\n * Capacitor File Picker Plugin interface for selecting files, images, videos, and directories.\n *\n * @since 8.0.0\n */\nexport interface CapgoFilePickerPlugin {\n /**\n * Pick one or more files from the device.\n *\n * @param options - Options for picking files\n * @returns Promise that resolves with the picked files\n * @since 8.0.0\n * @example\n * ```typescript\n * const result = await CapgoFilePicker.pickFiles({\n * types: ['application/pdf', 'image/*'],\n * limit: 5,\n * readData: false\n * });\n * console.log('Picked files:', result.files);\n * ```\n */\n pickFiles(options?: PickFilesOptions): Promise<PickFilesResult>;\n\n /**\n * Pick one or more images from the gallery.\n * Android/iOS only.\n *\n * @param options - Options for picking images\n * @returns Promise that resolves with the picked images\n * @since 8.0.0\n * @example\n * ```typescript\n * const result = await CapgoFilePicker.pickImages({\n * limit: 10,\n * readData: false\n * });\n * console.log('Picked images:', result.files);\n * ```\n */\n pickImages(options?: PickMediaOptions): Promise<PickFilesResult>;\n\n /**\n * Pick one or more videos from the gallery.\n * Android/iOS only.\n *\n * @param options - Options for picking videos\n * @returns Promise that resolves with the picked videos\n * @since 8.0.0\n * @example\n * ```typescript\n * const result = await CapgoFilePicker.pickVideos({\n * limit: 3,\n * skipTranscoding: true\n * });\n * console.log('Picked videos:', result.files);\n * ```\n */\n pickVideos(options?: PickMediaOptions): Promise<PickFilesResult>;\n\n /**\n * Pick one or more images or videos from the gallery.\n * Android/iOS only.\n *\n * @param options - Options for picking media\n * @returns Promise that resolves with the picked media files\n * @since 8.0.0\n * @example\n * ```typescript\n * const result = await CapgoFilePicker.pickMedia({\n * limit: 5,\n * readData: true\n * });\n * console.log('Picked media:', result.files);\n * ```\n */\n pickMedia(options?: PickMediaOptions): Promise<PickFilesResult>;\n\n /**\n * Pick a directory from the device.\n * Android/iOS only.\n *\n * @returns Promise that resolves with the picked directory path\n * @since 8.0.0\n * @example\n * ```typescript\n * const result = await CapgoFilePicker.pickDirectory();\n * console.log('Selected directory:', result.path);\n * ```\n */\n pickDirectory(): Promise<PickDirectoryResult>;\n\n /**\n * Convert a HEIC image to JPEG format.\n * iOS only.\n *\n * @param options - Options for the conversion\n * @returns Promise that resolves with the converted file path\n * @since 8.0.0\n * @example\n * ```typescript\n * const result = await CapgoFilePicker.convertHeicToJpeg({\n * path: '/path/to/image.heic',\n * quality: 0.9\n * });\n * console.log('Converted file:', result.path);\n * ```\n */\n convertHeicToJpeg(options: ConvertHeicToJpegOptions): Promise<ConvertHeicToJpegResult>;\n\n /**\n * Copy a file to a new location.\n *\n * @param options - Options for copying the file\n * @returns Promise that resolves when the copy is complete\n * @since 8.0.0\n * @example\n * ```typescript\n * await CapgoFilePicker.copyFile({\n * from: '/source/file.pdf',\n * to: '/destination/file.pdf',\n * overwrite: true\n * });\n * ```\n */\n copyFile(options: CopyFileOptions): Promise<void>;\n\n /**\n * Check broad storage or media permission state.\n * Picker-only flows should not gate `pickFiles()`, `pickImages()`,\n * `pickVideos()`, or `pickMedia()` on this permission on Android 13+.\n * Android only.\n *\n * @returns Promise that resolves with the permission status\n * @since 8.0.0\n * @example\n * ```typescript\n * const status = await CapgoFilePicker.checkPermissions();\n * console.log('Read permission:', status.readExternalStorage);\n * ```\n */\n checkPermissions(): Promise<PermissionStatus>;\n\n /**\n * Request broad storage or media permissions.\n * Do not request or declare `READ_MEDIA_IMAGES` or `READ_MEDIA_VIDEO`\n * only to use picker APIs. Google Play allows these permissions only\n * when picker alternatives are not sufficient for core app functionality.\n * Use `@capgo/capacitor-file-picker` picker methods instead for\n * user-selected file, image, or video access.\n * Android only.\n *\n * @returns Promise that resolves with the permission status\n * @since 8.0.0\n * @example\n * ```typescript\n * const status = await CapgoFilePicker.requestPermissions();\n * if (status.readExternalStorage === 'granted') {\n * console.log('Permission granted');\n * }\n * ```\n */\n requestPermissions(): Promise<PermissionStatus>;\n\n /**\n * Add a listener for the picker dismissed event.\n * iOS only.\n *\n * @param eventName - The event name\n * @param listenerFunc - The listener function\n * @returns Promise that resolves with the listener handle\n * @since 8.0.0\n */\n addListener(eventName: 'pickerDismissed', listenerFunc: PickerDismissedListener): Promise<PluginListenerHandle>;\n\n /**\n * Remove all listeners for this plugin.\n *\n * @since 8.0.0\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Get the native Capacitor plugin version.\n *\n * @returns Promise that resolves with the plugin version\n * @since 8.0.0\n * @example\n * ```typescript\n * const { version } = await CapgoFilePicker.getPluginVersion();\n * console.log('Plugin version:', version);\n * ```\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n/**\n * Options for picking files.\n *\n * @since 8.0.0\n */\nexport interface PickFilesOptions {\n /**\n * List of accepted MIME types or file extensions.\n * On iOS, only MIME types are supported.\n * Examples: ['image/*'], ['application/pdf'], ['.pdf', '.doc']\n */\n types?: string[];\n /**\n * Maximum number of files to pick.\n * Set to 0 for unlimited (platform default).\n * @default 0\n */\n limit?: number;\n /**\n * Whether to read the file data as base64.\n * Note: Reading large files may cause memory issues.\n * @default false\n */\n readData?: boolean;\n}\n\n/**\n * Options for picking media (images/videos).\n *\n * @since 8.0.0\n */\nexport interface PickMediaOptions {\n /**\n * Maximum number of files to pick.\n * Set to 0 for unlimited (platform default).\n * On Android, when the system photo picker is available, the platform enforces this\n * limit (capped by the device maximum). On older Android versions the picker may not\n * enforce the limit; the plugin truncates the returned list to this value when needed.\n * @default 0\n */\n limit?: number;\n /**\n * Whether to read the file data as base64.\n * Note: Reading large files may cause memory issues.\n * @default false\n */\n readData?: boolean;\n /**\n * iOS only: Skip transcoding of videos.\n * @default false\n */\n skipTranscoding?: boolean;\n /**\n * iOS 15+ only: Show ordered selection badges.\n * @default false\n */\n ordered?: boolean;\n}\n\n/**\n * Options for converting HEIC to JPEG.\n *\n * @since 8.0.0\n */\nexport interface ConvertHeicToJpegOptions {\n /** The path to the HEIC file to convert */\n path: string;\n /**\n * The compression quality for JPEG (0.0 - 1.0).\n * @default 0.9\n */\n quality?: number;\n}\n\n/**\n * Result of HEIC to JPEG conversion.\n *\n * @since 8.0.0\n */\nexport interface ConvertHeicToJpegResult {\n /** The path to the converted JPEG file */\n path: string;\n}\n\n/**\n * Options for copying a file.\n *\n * @since 8.0.0\n */\nexport interface CopyFileOptions {\n /** Source file path */\n from: string;\n /** Destination file path */\n to: string;\n /**\n * Whether to overwrite if destination exists.\n * @default false\n */\n overwrite?: boolean;\n}\n\n/**\n * Represents a picked file.\n *\n * @since 8.0.0\n */\nexport interface PickedFile {\n /** The name of the file */\n name: string;\n /** The path to the file */\n path?: string;\n /** The MIME type of the file */\n mimeType: string;\n /** The size of the file in bytes */\n size: number;\n /**\n * The base64 encoded data of the file.\n * Only present if readData was true.\n */\n data?: string;\n /**\n * The Blob instance of the file.\n * Web only.\n */\n blob?: Blob;\n /** Width in pixels (images/videos only) */\n width?: number;\n /** Height in pixels (images/videos only) */\n height?: number;\n /** Duration in seconds (videos only) */\n duration?: number;\n /** Last modified timestamp in milliseconds */\n modifiedAt?: number;\n}\n\n/**\n * Result of picking files.\n *\n * @since 8.0.0\n */\nexport interface PickFilesResult {\n /** Array of picked files */\n files: PickedFile[];\n}\n\n/**\n * Result of picking a directory.\n *\n * @since 8.0.0\n */\nexport interface PickDirectoryResult {\n /** The path to the selected directory */\n path: string;\n}\n\n/**\n * Permission status for file access.\n *\n * @since 8.0.0\n */\nexport interface PermissionStatus {\n /**\n * Whether broad external storage or media permission is granted.\n * Picker APIs that return user-selected files usually do not require this on Android 13+.\n */\n readExternalStorage: PermissionState;\n /** Whether permission to access media location is granted */\n accessMediaLocation?: PermissionState;\n}\n\n/**\n * Permission state values.\n *\n * @since 8.0.0\n */\nexport type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied';\n\n/**\n * Listener callback for picker dismissed event.\n *\n * @since 8.0.0\n */\nexport type PickerDismissedListener = (event: null) => void;\n\n/**\n * Capacitor File Picker Plugin interface for selecting files, images, videos, and directories.\n *\n * @since 8.0.0\n */\nexport interface CapgoFilePickerPlugin {\n /**\n * Pick one or more files from the device.\n *\n * @param options - Options for picking files\n * @returns Promise that resolves with the picked files\n * @since 8.0.0\n * @example\n * ```typescript\n * const result = await CapgoFilePicker.pickFiles({\n * types: ['application/pdf', 'image/*'],\n * limit: 5,\n * readData: false\n * });\n * console.log('Picked files:', result.files);\n * ```\n */\n pickFiles(options?: PickFilesOptions): Promise<PickFilesResult>;\n\n /**\n * Pick one or more images from the gallery.\n * Android/iOS only.\n * On Android, `limit` is enforced by the system photo picker when available\n * (Android 13+, or Android 11-12 with the Google Play system photo picker extension).\n * Older Android versions may allow selecting more items than `limit`; results are\n * truncated to `limit` before they are returned.\n *\n * @param options - Options for picking images\n * @returns Promise that resolves with the picked images\n * @since 8.0.0\n * @example\n * ```typescript\n * const result = await CapgoFilePicker.pickImages({\n * limit: 10,\n * readData: false\n * });\n * console.log('Picked images:', result.files);\n * ```\n */\n pickImages(options?: PickMediaOptions): Promise<PickFilesResult>;\n\n /**\n * Pick one or more videos from the gallery.\n * Android/iOS only.\n * On Android, `limit` is enforced by the system photo picker when available\n * (Android 13+, or Android 11-12 with the Google Play system photo picker extension).\n * Older Android versions may allow selecting more items than `limit`; results are\n * truncated to `limit` before they are returned.\n *\n * @param options - Options for picking videos\n * @returns Promise that resolves with the picked videos\n * @since 8.0.0\n * @example\n * ```typescript\n * const result = await CapgoFilePicker.pickVideos({\n * limit: 3,\n * skipTranscoding: true\n * });\n * console.log('Picked videos:', result.files);\n * ```\n */\n pickVideos(options?: PickMediaOptions): Promise<PickFilesResult>;\n\n /**\n * Pick one or more images or videos from the gallery.\n * Android/iOS only.\n *\n * @param options - Options for picking media\n * @returns Promise that resolves with the picked media files\n * @since 8.0.0\n * @example\n * ```typescript\n * const result = await CapgoFilePicker.pickMedia({\n * limit: 5,\n * readData: true\n * });\n * console.log('Picked media:', result.files);\n * ```\n */\n pickMedia(options?: PickMediaOptions): Promise<PickFilesResult>;\n\n /**\n * Pick a directory from the device.\n * Android/iOS only.\n *\n * @returns Promise that resolves with the picked directory path\n * @since 8.0.0\n * @example\n * ```typescript\n * const result = await CapgoFilePicker.pickDirectory();\n * console.log('Selected directory:', result.path);\n * ```\n */\n pickDirectory(): Promise<PickDirectoryResult>;\n\n /**\n * Convert a HEIC image to JPEG format.\n * iOS only.\n *\n * @param options - Options for the conversion\n * @returns Promise that resolves with the converted file path\n * @since 8.0.0\n * @example\n * ```typescript\n * const result = await CapgoFilePicker.convertHeicToJpeg({\n * path: '/path/to/image.heic',\n * quality: 0.9\n * });\n * console.log('Converted file:', result.path);\n * ```\n */\n convertHeicToJpeg(options: ConvertHeicToJpegOptions): Promise<ConvertHeicToJpegResult>;\n\n /**\n * Copy a file to a new location.\n *\n * @param options - Options for copying the file\n * @returns Promise that resolves when the copy is complete\n * @since 8.0.0\n * @example\n * ```typescript\n * await CapgoFilePicker.copyFile({\n * from: '/source/file.pdf',\n * to: '/destination/file.pdf',\n * overwrite: true\n * });\n * ```\n */\n copyFile(options: CopyFileOptions): Promise<void>;\n\n /**\n * Check broad storage or media permission state.\n * Picker-only flows should not gate `pickFiles()`, `pickImages()`,\n * `pickVideos()`, or `pickMedia()` on this permission on Android 13+.\n * Android only.\n *\n * @returns Promise that resolves with the permission status\n * @since 8.0.0\n * @example\n * ```typescript\n * const status = await CapgoFilePicker.checkPermissions();\n * console.log('Read permission:', status.readExternalStorage);\n * ```\n */\n checkPermissions(): Promise<PermissionStatus>;\n\n /**\n * Request broad storage or media permissions.\n * Do not request or declare `READ_MEDIA_IMAGES` or `READ_MEDIA_VIDEO`\n * only to use picker APIs. Google Play allows these permissions only\n * when picker alternatives are not sufficient for core app functionality.\n * Use `@capgo/capacitor-file-picker` picker methods instead for\n * user-selected file, image, or video access.\n * Android only.\n *\n * @returns Promise that resolves with the permission status\n * @since 8.0.0\n * @example\n * ```typescript\n * const status = await CapgoFilePicker.requestPermissions();\n * if (status.readExternalStorage === 'granted') {\n * console.log('Permission granted');\n * }\n * ```\n */\n requestPermissions(): Promise<PermissionStatus>;\n\n /**\n * Add a listener for the picker dismissed event.\n * iOS only.\n *\n * @param eventName - The event name\n * @param listenerFunc - The listener function\n * @returns Promise that resolves with the listener handle\n * @since 8.0.0\n */\n addListener(eventName: 'pickerDismissed', listenerFunc: PickerDismissedListener): Promise<PluginListenerHandle>;\n\n /**\n * Remove all listeners for this plugin.\n *\n * @since 8.0.0\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Get the native Capacitor plugin version.\n *\n * @returns Promise that resolves with the plugin version\n * @since 8.0.0\n * @example\n * ```typescript\n * const { version } = await CapgoFilePicker.getPluginVersion();\n * console.log('Plugin version:', version);\n * ```\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n"]}
@@ -11,7 +11,7 @@ import UniformTypeIdentifiers
11
11
  */
12
12
  @objc(CapgoFilePickerPlugin)
13
13
  public class CapgoFilePickerPlugin: CAPPlugin, CAPBridgedPlugin {
14
- private let pluginVersion: String = "8.2.5"
14
+ private let pluginVersion: String = "8.2.7"
15
15
  public let identifier = "CapgoFilePickerPlugin"
16
16
  public let jsName = "CapgoFilePicker"
17
17
  public let pluginMethods: [CAPPluginMethod] = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-file-picker",
3
- "version": "8.2.5",
3
+ "version": "8.2.7",
4
4
  "description": "File picker Capacitor plugin - Pick files, images, videos, and directories",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -43,7 +43,7 @@
43
43
  "verify:web": "bun run build",
44
44
  "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
45
45
  "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
46
- "eslint": "eslint . --ext ts",
46
+ "eslint": "eslint",
47
47
  "prettier": "prettier-pretty-check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
48
48
  "swiftlint": "node-swiftlint",
49
49
  "docgen": "docgen --api CapgoFilePickerPlugin --output-readme README.md --output-json dist/docs.json",
@@ -64,18 +64,18 @@
64
64
  "@capacitor/core": "^8.0.0",
65
65
  "@capacitor/docgen": "^0.3.1",
66
66
  "@capacitor/ios": "^8.0.0",
67
- "@ionic/eslint-config": "^0.4.0",
67
+ "@ionic/eslint-config": "^0.5.0",
68
68
  "@ionic/prettier-config": "^4.0.0",
69
69
  "@ionic/swiftlint-config": "^2.0.0",
70
70
  "@types/node": "^24.10.1",
71
- "eslint": "^8.57.1",
71
+ "eslint": "^10.0.0",
72
72
  "eslint-plugin-import": "^2.31.0",
73
73
  "prettier": "^3.6.2",
74
74
  "prettier-plugin-java": "^2.7.7",
75
75
  "rimraf": "^6.1.0",
76
76
  "rollup": "^4.53.2",
77
77
  "swiftlint": "^2.0.0",
78
- "typescript": "^5.9.3",
78
+ "typescript": "^6.0.3",
79
79
  "prettier-pretty-check": "^0.2.0"
80
80
  },
81
81
  "peerDependencies": {
@@ -83,9 +83,6 @@
83
83
  },
84
84
  "prettier": "@ionic/prettier-config",
85
85
  "swiftlint": "@ionic/swiftlint-config",
86
- "eslintConfig": {
87
- "extends": "@ionic/eslint-config/recommended"
88
- },
89
86
  "capacitor": {
90
87
  "ios": {
91
88
  "src": "ios"