-
-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement directory picking and related functions #20
Open
amake
wants to merge
28
commits into
hpoul:main
Choose a base branch
from
amake:directory-picker
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
amake
force-pushed
the
directory-picker
branch
3 times, most recently
from
April 18, 2021 15:02
88b14f2
to
20bc343
Compare
@hpoul Would it help if I broke this PR up into smaller ones? |
amake
added a commit
to amake/orgro
that referenced
this pull request
Apr 26, 2021
Otherwise we can't get a bookmark
amake
force-pushed
the
directory-picker
branch
from
August 24, 2021 11:46
0844a79
to
966ce1a
Compare
The call to URL.bookmarkData() can fail with some file providers if the file is e.g. online only and not yet materialized to the local device.
amake
added a commit
to amake/orgro
that referenced
this pull request
Sep 22, 2023
amake
force-pushed
the
directory-picker
branch
from
October 30, 2023 10:21
4a5bd63
to
d8bdd1a
Compare
I have been actively using this branch in my app for years now. I will continue to maintain it. I just mention this to note that I am merging other, smaller PRs into it so if you ever do feel like looking at this one, I suggest you merge the others first. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Note: This PR includes the changes in #19, so you might want to review that one first.This PR addresses #16 by adding the following functions:
FilePickerWritable.openDirectory
FilePickerWritable.getDirectory
FilePickerWritable.resolveRelativePath
FilePickerWritable.isDirectoryAccessSupported
Please see the dartdoc comments of each for details.
To represent the result of picking a directory or resolving a relative path to a directory, I have introduced the
DirectoryInfo
class. Because the result ofresolveRelativePath
could be either a file or a directory, I have moved the bulk ofFileInfo
into a new abstract classEntityInfo
from which bothFileInfo
andDirectoryInfo
inherit (both classes have the same properties for now). See #16 (comment) for additional discussion of this design decision.Android details
Android only supports obtaining persistable directory access on API 21 (Android 5 "Lollipop") and later, but this plugin supports back to API 19. I have maintained compatibility with this PR; users are expected to use
isDirectoryAccessSupported
to check if directory access is supported before calling any of the other new functions.Another wrinkle is that one of the core primitives required to implement
getDirectory
(and resolve..
inresolveRelativePath
),DocumentsContract#findDocumentPath
, is only available on API 26 (Android 8 "Oreo"). To supportgetDirectory
on prior OSes I implemented a potentially very costly breadth-first recursive search through the filesystem. It works, but the experience could be quite poor if the user has a lot of files, or if the root is far removed from the target file.(On Android 7 and earlier you currently can't resolve
..
above your start point. This could be improved, but I'm not sure how to make the API clear enough to be usable.)Android URIs
To make sense of the Android implementation you need to know the following about Android Storage Access Framework URIs.
There are three kinds of URI that we care about:
content://com.android.externalstorage.documents/document/primary%3ADocuments%2Ffoo%bar.txt
Documents/foo/bar.txt
inprimary
storageDocuments/foo/bar.txt
content://com.android.externalstorage.documents/tree/primary%3ADocuments
Documents
inprimary
storageDocuments
content://com.android.externalstorage.documents/tree/primary%3ADocuments/document/primary%3ADocuments%2Ffoo%bar.txt
Documents/foo/bar.txt
under the directory treeDocuments
, both inprimary
storageDocumentsContract
Much of the code in the Android implementation concerns itself with the manipulation such URIs:
The above example URIs are taken from the local storage provider. While you can dissect and make sense of the parts of these URIs, so you might be tempted to try parsing them for easier manipulation, please note that there are various exhortations against doing so in the Android documentation:
(source)
Compatibility
Unfortunately directory access is not widely supported by third-party apps. The only sources that work are:
Apps confirmed to not support directory access include Dropbox, Google Drive, and FileBrowser.
Intended use case
I have implemented these features for use in my app, Orgro, which is a viewer for Org Mode files. My use case is:
isDirectoryAccessSupported
returns false then we quit heregetDirectory
is called to get an identifier for the directory containing the opened fileresolveRelativePath
readFile
methodopenDirectory
I have this implemented and tested on iOS 14, Android 11, and Android 6.