Repository navigation
[file_selector] Updates cross_file to 0.4.0 and updates to platform interface to latest standard - #13147
[file_selector] Updates cross_file to 0.4.0 and updates to platform interface to latest standard#13147bparrishMines wants to merge 104 commits into
cross_file to 0.4.0 and updates to platform interface to latest standard#13147Conversation
| if (kIsWeb) { | ||
| return Image.network(file.uri); | ||
| } else if (defaultTargetPlatform == TargetPlatform.macOS) { | ||
| return Image.file(File(Uri.parse(file.uri).toFilePath())); |
There was a problem hiding this comment.
This pattern has drawbacks:
- It depends on knowledge of the Darwin cross file implementation.
- It doesn't extend to out-of-tree platforms
An alternative might be to add an API to XFile to try to convert it to a File. If that operation succeeds, we can use Image.file, otherwise we fallback to Image.memory. What would you think of that approach?
There was a problem hiding this comment.
This is true, but you also need to know that web only works with Image.network anyways. I don't know if there is a way to avoid needing platform specific knowledge without proving an Image toImage(XFile) somewhere or adding XFile support to Image directly.
Added a TODO that includes flutter/flutter#196306 for this. I think it could still be worthwhile for a platform implementation to handle returning a file path if possible. That would at least make it so Uri.parse(file.uri).toFilePath() doesn't need to be called everywhere. Also, just attempting to create a File with the URI from XFile wouldn't be enough. One could make a valid file path from any URI like 123 and the user wouldn't know that you cant access the file that way. So the issue leaves it up to the platform implementation to handle whether the URI can be provided as a file path.
I also don't want to return a File in XFile because i think I want to avoid importing dart:io in the app-facing package. I could be wrong, but I remember a weird interaction with pub where if a package imports dart:io, it removes the flag that web is supported for a package.
There was a problem hiding this comment.
I could be wrong, but I remember a weird interaction with pub where if a package imports dart:io, it removes the flag that web is supported for a package.
Ah that's a very good point 👍
Added a TODO that includes flutter/flutter#196306 for this.
Ah nice, after this TODO I imagine the code will look something like this?
Future<Image> _getImage() async {
if (kIsWeb) {
return Image.network(file.uri);
} else if (file.asFilePath case String path) {
return Image.file(File(path));
} else {
return Image.memory(await file.readAsBytes());
}
}If so, that addresses my concern and SGTM 👍
| final XFile? file = await openFile( | ||
| acceptedTypeGroups: <XTypeGroup>[typeGroup], | ||
| initialDirectory: initialDirectory, | ||
| ); |
There was a problem hiding this comment.
If this is a ScopedStorageXFile, we need to dispose() it. On iOS/macOS, forgetting to call NSURL.stopAccessingSecurityScopedResource can result in the OS preventing the app from accessing more resources. Some thoughts:
- We should update the examples to properly dispose
XFiles - It seems we should add a
XFile.disposemethod. Apps shouldn't need to cast anXFileto check whether they need to dispose theXFile. - Your app now needs to call
dispose()when it didn't need before. This is a breaking change (even though your app will continue to compile). The CHANGELOG.md should explain this and provide migration instructions
There was a problem hiding this comment.
Yes, this was also brought up in the cross_file 1.0 PR and the design doc. To avoid requiring users to call dispose or potentially just forgetting, cross_file_darwin and cross_file_web automatically clean up resources when the ScopedStorageXFile is garbage collected. (cross_file_android doesn't need it)
I didn't consider this a breaking change because web and macOS need to clean up resources with the current implementation, but they don't. I think it's more of a bug:
Web: https://github.com/flutter/packages/blob/main/packages/file_selector/file_selector_web/lib/src/dom_helper.dart#L70
MacOS: NSURL.startAccessingSecurityScopedResource is called automatically and NSURL.stopAccessingSecurityScopedResource is supposed to be called.
I prefer not requiring calling dispose with every XFile and I don't want ScopedStorage platforms to expect the user to remember to do it. Unfortunately, requiring to call dispose affects more than just file_selector. Any API that returns or uses a XFile would have to remember to call dispose. But I think this is more of a cross_file plugin discussion and shouldn't affect this PR since it's currently handled automatically on all platforms.
I added documentation to the file_selector methods to recommend calling the dispose method though:
/// If the returned [XFile] is a [ScopedStorageXFile], it is recommended that
/// the [ScopedStorageXFile.dispose] is called when the app no longer needs
/// access to the resource.There was a problem hiding this comment.
Maurice and I discussed this offline. Adding XFile.dispose() has the following concerns:
- It complicates
XFile. One could argue this complexity is good: you get one API that works well across all implementations. Also, Flutter uses this pattern (e.g.,BoxPainterhas an emptydisposemethod that not all subclasses implement). XFile.dispose()could cause different implementations to behave differently. Calling a method afterdispose()would error forScopedStorageXFilebut notFileSystemXFile. We can mitigate this by adding adebugDisposedproperty so thatFileSystemXFilecan error if methods are called afterdispose().
We agreed to add XFile.dispose() after this discussion.
|
|
||
| * **BREAKING CHANGES**: | ||
| * Updates `file_selector_platform_interface` to `3.0.0` which updates `cross_file` dependency to | ||
| `0.4.0`. See its breaking changes in its [CHANGELOG](https://pub.dev/packages/cross_file/changelog#040). |
There was a problem hiding this comment.
I imagine that an app that uses file_selector might mock FileSelectorPlatform with an implements. This is no longer possible now that FileSelectorPlatform is an abstract base class. Could we add a quick migration guide for how to mock the file selector plugin?
| /// Opens a directory selection dialog and returns a list of the paths chosen | ||
| /// by the user. | ||
| /// | ||
| /// This always returns an empty array on the web. |
There was a problem hiding this comment.
It looks like FileSelectorWeb web doesn't implement getDirectories, so it throws an UnimplementedError. This is a pre-existing bug, but since we're introducing a new getDirectories method could you update FileSelectorWeb to return an empty array with a test?
| cross_file_platform_interface: ^1.0.0 | ||
| flutter_test: | ||
| sdk: flutter | ||
| plugin_platform_interface: ^2.1.7 |
| /// | ||
| /// Returns `null` if user cancels the operation. | ||
| @async | ||
| String? getDirectoryPath(String? initialDirectory); |
There was a problem hiding this comment.
Should we rename this to getDirectoryUri? If yes, don't forget to update the doc above :)
| /// An API to call to native code to select files or directories. | ||
| @HostApi() | ||
| abstract class FileSelectorApi { | ||
| /// Opens a file dialog for loading files and returns a file path. |
There was a problem hiding this comment.
Should this be update to returns a file URI.? Same comment for openFiles below
| @@ -8,10 +8,9 @@ import 'package:file_selector_platform_interface/file_selector_platform_interfac | |||
| import 'package:flutter/cupertino.dart'; | |||
There was a problem hiding this comment.
Can we replace this with import 'package:flutter/foundation.dart';? It doesn't look like we use Cupertino here.
- Render the static logo from the existing PNG and drop flutter_svg; this removes vector_graphics, vector_graphics_compiler, xml, and six more packages - Allowlist the remaining transitive pins with concrete reasons: cross_file (file_selector upstream PR flutter/packages#13147), material_color_utilities and test_api (Flutter SDK pins) - Make deps:check fail on undocumented transitive drift; deps:outdated now prints the full annotated report - Bump file_selector to ^1.1.0 - Document the allowlist workflow and the no-overrides rule
Because
file_selectorexportscross_file, a breaking change is needed to update the dependency. Since a breaking change is needed anyway, this also removes deprecated methods and API and adds support forXDirectorys.List of changes in the platform interface (also included in
CHANGELOG.md):cross_filedependency to0.4.0.MethodChannelimplementation.FileSelectorPlatform's of implementationPlatformInterfacewith thebasekeyword.openFileandopenFilesto take aOpenFileDialogOptionsandOpenFilesDialogOptions, respectively.getSavePath. Replaced bygetSaveLocation.getSaveLocationto take aSaveLocationOptions.FileSaveLocation.pathwithFileSaveLocation.file.getDirectoryPathwithgetDirectoryand now returns aXDirectory.getDirectoryPathswithgetDirectoriesand now returnsList<XDirectory.getDirectoryandgetDirectoriesto take aGetDirectoryDialogOptionsandGetDirectoriesDialogOptions, respectively.XTypeGroup.macUTIs. UseXTypeGroup.uniformTypeIdentifiersinstead.Every platform functionally remains the same except for Android. Android no longer copies a file from a content provider to a temporary directory. It now only returns the original content URIs for files and directories.
cross_filenow handles using those files directly.Part of flutter/flutter#193154
Related Issues this fixes or allows to be fixed:
DISPLAY_NAMEof the files selected usingopenFileflutter#131328Pre-Review Checklist
[shared_preferences]///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2