Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ The file size of the document. _On Android some DocumentProviders may not provid

The base64 encoded content of the picked file if the option `readContent` was set to `true`.


#### [Android only] `DocumentPicker.pickDirectory(options)`

Open a system directory picker. Returns a promise that resolves to the directory selected by user.

### Result

##### `uri`:

The URI of the selected directory. Usually it will be a content URI.


### `DocumentPicker.types.*`

`DocumentPicker.types.*` provides a few common types for use as `type` values, these types will use the correct format for each platform (MIME types on Android, UTIs on iOS).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
public class DocumentPickerModule extends ReactContextBaseJavaModule {
private static final String NAME = "RNDocumentPicker";
private static final int READ_REQUEST_CODE = 41;
private static final int PICK_DIR_REQUEST_CODE = 42;

private static final String E_ACTIVITY_DOES_NOT_EXIST = "ACTIVITY_DOES_NOT_EXIST";
private static final String E_FAILED_TO_SHOW_PICKER = "FAILED_TO_SHOW_PICKER";
Expand All @@ -51,7 +52,7 @@ public class DocumentPickerModule extends ReactContextBaseJavaModule {
private static final String E_UNEXPECTED_EXCEPTION = "UNEXPECTED_EXCEPTION";

private static final String OPTION_TYPE = "type";
private static final String OPTION_MULIPLE = "multiple";
private static final String OPTION_MULTIPLE = "multiple";
private static final String OPTION_COPYTO = "copyTo";

private static final String FIELD_URI = "uri";
Expand All @@ -61,13 +62,17 @@ public class DocumentPickerModule extends ReactContextBaseJavaModule {
private static final String FIELD_TYPE = "type";
private static final String FIELD_SIZE = "size";


private final ActivityEventListener activityEventListener = new BaseActivityEventListener() {
@Override
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
if (promise == null) {
return;
}
if (requestCode == READ_REQUEST_CODE) {
if (promise != null) {
onShowActivityResult(resultCode, data, promise);
}
onShowActivityResult(resultCode, data, promise);
} else if (requestCode == PICK_DIR_REQUEST_CODE) {
onPickDirectoryResult(resultCode, data, promise);
}
}
};
Expand Down Expand Up @@ -126,7 +131,7 @@ public void pick(ReadableMap args, Promise promise) {
}
}

boolean multiple = !args.isNull(OPTION_MULIPLE) && args.getBoolean(OPTION_MULIPLE);
boolean multiple = !args.isNull(OPTION_MULTIPLE) && args.getBoolean(OPTION_MULTIPLE);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multiple);

currentActivity.startActivityForResult(Intent.createChooser(intent, null), READ_REQUEST_CODE, Bundle.EMPTY);
Expand Down Expand Up @@ -175,6 +180,43 @@ public void onShowActivityResult(int resultCode, Intent data, Promise promise) {
}
}

@ReactMethod
public void pickDirectory(Promise promise) {
Activity currentActivity = getCurrentActivity();

if (currentActivity == null) {
promise.reject(E_ACTIVITY_DOES_NOT_EXIST, "Current activity does not exist");
return;
}
this.promise = promise;
try {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
currentActivity.startActivityForResult(intent, PICK_DIR_REQUEST_CODE, null);
} catch (Exception e) {
sendError(E_FAILED_TO_SHOW_PICKER, "Failed to create directory picker", e);
}
}

private void onPickDirectoryResult(int resultCode, Intent data, Promise promise) {
if (resultCode == Activity.RESULT_CANCELED) {
sendError(E_DOCUMENT_PICKER_CANCELED, "User canceled directory picker");
return;
} else if (resultCode != Activity.RESULT_OK) {
sendError(E_UNKNOWN_ACTIVITY_RESULT, "Unknown activity result: " + resultCode);
return;
}

if (data == null || data.getData() == null) {
sendError(E_INVALID_DATA_RETURNED, "Invalid data returned by intent");
return;
}
Uri uri = data.getData();

WritableMap map = Arguments.createMap();
map.putString(FIELD_URI, uri.toString());
promise.resolve(map);
}

private static class ProcessDataTask extends GuardedResultAsyncTask<ReadableArray> {
private final WeakReference<Context> weakContext;
private final List<Uri> uris;
Expand Down
5 changes: 5 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ declare module 'react-native-document-picker' {
name: string;
size: number;
}
interface DirectoryPickerResponse {
uri: string;
}

type Platform = 'ios' | 'android' | 'windows';
export default class DocumentPicker<OS extends keyof PlatformTypes = Platform> {
static types: PlatformTypes['ios'] | PlatformTypes['android'] | PlatformTypes['windows'];
Expand All @@ -89,5 +93,6 @@ declare module 'react-native-document-picker' {
): Promise<DocumentPickerResponse[]>;
static isCancel<IError extends { code?: string }>(err?: IError): boolean;
static releaseSecureAccess(uris: Array<string>): void;
static pickDirectory(): Promise<DirectoryPickerResponse | null>;
}
}
8 changes: 8 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,12 @@ export default class DocumentPicker {
static releaseSecureAccess(uris) {
releaseSecureAccess(uris);
}

static pickDirectory() {
if (Platform.OS === 'android') {
return RNDocumentPicker.pickDirectory();
} else {
return Promise.resolve(null);
}
}
}