[file_selector]Improve API docs and examples (#4824)
diff --git a/packages/file_selector/file_selector/AUTHORS b/packages/file_selector/file_selector/AUTHORS
index dbf9d19..94743a9 100644
--- a/packages/file_selector/file_selector/AUTHORS
+++ b/packages/file_selector/file_selector/AUTHORS
@@ -63,3 +63,4 @@
Anton Borries <mail@antonborri.es>
Alex Li <google@alexv525.com>
Rahul Raj <64.rahulraj@gmail.com>
+TowaYamashita <confirm.apps.develop@gmail.com>
diff --git a/packages/file_selector/file_selector/CHANGELOG.md b/packages/file_selector/file_selector/CHANGELOG.md
index 6397833..ed7b213 100644
--- a/packages/file_selector/file_selector/CHANGELOG.md
+++ b/packages/file_selector/file_selector/CHANGELOG.md
@@ -1,5 +1,6 @@
-## NEXT
+## 0.8.4+3
+* Improves API docs and examples.
* Minor fixes for new analysis options.
## 0.8.4+2
diff --git a/packages/file_selector/file_selector/README.md b/packages/file_selector/file_selector/README.md
index 89cac1e..f5c1de8 100644
--- a/packages/file_selector/file_selector/README.md
+++ b/packages/file_selector/file_selector/README.md
@@ -1,5 +1,7 @@
# file_selector
+<?code-excerpt path-base="excerpts/packages/file_selector_example"?>
+
[![pub package](https://img.shields.io/pub/v/file_selector.svg)](https://pub.dartlang.org/packages/file_selector)
A Flutter plugin that manages files and interactions with file dialogs.
@@ -30,25 +32,48 @@
Please also take a look at our [example][example] app.
#### Open a single file
+<?code-excerpt "open_image_page.dart (SingleOpen)"?>
``` dart
-final typeGroup = XTypeGroup(label: 'images', extensions: ['jpg', 'png']);
-final file = await openFile(acceptedTypeGroups: [typeGroup]);
+final XTypeGroup typeGroup = XTypeGroup(
+ label: 'images',
+ extensions: <String>['jpg', 'png'],
+);
+final XFile? file =
+ await openFile(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
```
#### Open multiple files at once
+<?code-excerpt "open_multiple_images_page.dart (MultiOpen)"?>
``` dart
-final typeGroup = XTypeGroup(label: 'images', extensions: ['jpg', 'png']);
-final files = await openFiles(acceptedTypeGroups: [typeGroup]);
+final XTypeGroup jpgsTypeGroup = XTypeGroup(
+ label: 'JPEGs',
+ extensions: <String>['jpg', 'jpeg'],
+);
+final XTypeGroup pngTypeGroup = XTypeGroup(
+ label: 'PNGs',
+ extensions: <String>['png'],
+);
+final List<XFile> files = await openFiles(acceptedTypeGroups: <XTypeGroup>[
+ jpgsTypeGroup,
+ pngTypeGroup,
+]);
```
#### Saving a file
+<?code-excerpt "readme_standalone_excerpts.dart (Save)"?>
```dart
-final path = await getSavePath();
-final name = "hello_file_selector.txt";
-final data = Uint8List.fromList("Hello World!".codeUnits);
-final mimeType = "text/plain";
-final file = XFile.fromData(data, name: name, mimeType: mimeType);
-await file.saveTo(path);
+const String fileName = 'suggested_name.txt';
+final String? path = await getSavePath(suggestedName: fileName);
+if (path == null) {
+ // Operation was canceled by the user.
+ return;
+}
+
+final Uint8List fileData = Uint8List.fromList('Hello World!'.codeUnits);
+const String mimeType = 'text/plain';
+final XFile textFile =
+ XFile.fromData(fileData, mimeType: mimeType, name: fileName);
+await textFile.saveTo(path);
```
[example]:./example
diff --git a/packages/file_selector/file_selector/example/build.excerpt.yaml b/packages/file_selector/file_selector/example/build.excerpt.yaml
new file mode 100644
index 0000000..e317efa
--- /dev/null
+++ b/packages/file_selector/file_selector/example/build.excerpt.yaml
@@ -0,0 +1,15 @@
+targets:
+ $default:
+ sources:
+ include:
+ - lib/**
+ # Some default includes that aren't really used here but will prevent
+ # false-negative warnings:
+ - $package$
+ - lib/$lib$
+ exclude:
+ - '**/.*/**'
+ - '**/build/**'
+ builders:
+ code_excerpter|code_excerpter:
+ enabled: true
diff --git a/packages/file_selector/file_selector/example/lib/main.dart b/packages/file_selector/file_selector/example/lib/main.dart
index 34f5857..d05e80f 100644
--- a/packages/file_selector/file_selector/example/lib/main.dart
+++ b/packages/file_selector/file_selector/example/lib/main.dart
@@ -2,14 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'package:example/get_directory_page.dart';
-import 'package:example/home_page.dart';
-import 'package:example/open_image_page.dart';
-import 'package:example/open_multiple_images_page.dart';
-import 'package:example/open_text_page.dart';
-import 'package:example/save_text_page.dart';
import 'package:flutter/material.dart';
+import 'get_directory_page.dart';
+import 'home_page.dart';
+import 'open_image_page.dart';
+import 'open_multiple_images_page.dart';
+import 'open_text_page.dart';
+import 'save_text_page.dart';
+
void main() {
runApp(const MyApp());
}
diff --git a/packages/file_selector/file_selector/example/lib/open_image_page.dart b/packages/file_selector/file_selector/example/lib/open_image_page.dart
index e520ffb..4fb0686 100644
--- a/packages/file_selector/file_selector/example/lib/open_image_page.dart
+++ b/packages/file_selector/file_selector/example/lib/open_image_page.dart
@@ -14,17 +14,18 @@
const OpenImagePage({Key? key}) : super(key: key);
Future<void> _openImageFile(BuildContext context) async {
+ // #docregion SingleOpen
final XTypeGroup typeGroup = XTypeGroup(
label: 'images',
extensions: <String>['jpg', 'png'],
);
- final List<XFile> files =
- await openFiles(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
- if (files.isEmpty) {
+ final XFile? file =
+ await openFile(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
+ // #enddocregion SingleOpen
+ if (file == null) {
// Operation was canceled by the user.
return;
}
- final XFile file = files[0];
final String fileName = file.name;
final String filePath = file.path;
diff --git a/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart b/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart
index e2d21c7..ac3d66f 100644
--- a/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart
+++ b/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart
@@ -14,6 +14,7 @@
const OpenMultipleImagesPage({Key? key}) : super(key: key);
Future<void> _openImageFile(BuildContext context) async {
+ // #docregion MultiOpen
final XTypeGroup jpgsTypeGroup = XTypeGroup(
label: 'JPEGs',
extensions: <String>['jpg', 'jpeg'],
@@ -26,6 +27,7 @@
jpgsTypeGroup,
pngTypeGroup,
]);
+ // #enddocregion MultiOpen
if (files.isEmpty) {
// Operation was canceled by the user.
return;
diff --git a/packages/file_selector/file_selector/example/lib/open_text_page.dart b/packages/file_selector/file_selector/example/lib/open_text_page.dart
index be48a43..057925e 100644
--- a/packages/file_selector/file_selector/example/lib/open_text_page.dart
+++ b/packages/file_selector/file_selector/example/lib/open_text_page.dart
@@ -4,6 +4,7 @@
import 'package:file_selector/file_selector.dart';
import 'package:flutter/material.dart';
+import 'package:path_provider/path_provider.dart';
/// Screen that shows an example of openFile
class OpenTextPage extends StatelessWidget {
@@ -15,8 +16,15 @@
label: 'text',
extensions: <String>['txt', 'json'],
);
- final XFile? file =
- await openFile(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
+ // This demonstrates using an initial directory for the prompt, which should
+ // only be done in cases where the application can likely predict where the
+ // file would be. In most cases, this parameter should not be provided.
+ final String initialDirectory =
+ (await getApplicationDocumentsDirectory()).path;
+ final XFile? file = await openFile(
+ acceptedTypeGroups: <XTypeGroup>[typeGroup],
+ initialDirectory: initialDirectory,
+ );
if (file == null) {
// Operation was canceled by the user.
return;
diff --git a/packages/file_selector/file_selector/example/lib/readme_standalone_excerpts.dart b/packages/file_selector/file_selector/example/lib/readme_standalone_excerpts.dart
new file mode 100644
index 0000000..c67c93f
--- /dev/null
+++ b/packages/file_selector/file_selector/example/lib/readme_standalone_excerpts.dart
@@ -0,0 +1,57 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file exists solely to host compiled excerpts for README.md, and is not
+// intended for use as an actual example application.
+
+// ignore_for_file: public_member_api_docs
+
+// TODO(a14n): remove this import once Flutter 3.1 or later reaches stable (including flutter/flutter#104231)
+// ignore: unnecessary_import
+import 'dart:typed_data';
+
+import 'package:file_selector/file_selector.dart';
+import 'package:flutter/material.dart';
+
+void main() {
+ runApp(const MyApp());
+}
+
+class MyApp extends StatefulWidget {
+ const MyApp({Key? key}) : super(key: key);
+
+ @override
+ State<MyApp> createState() => _MyAppState();
+}
+
+class _MyAppState extends State<MyApp> {
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ home: Scaffold(
+ appBar: AppBar(
+ title: const Text('README snippet app'),
+ ),
+ body: const Text('See example in main.dart'),
+ ),
+ );
+ }
+
+ Future<void> saveFile() async {
+ // #docregion Save
+ const String fileName = 'suggested_name.txt';
+ final String? path = await getSavePath(suggestedName: fileName);
+ if (path == null) {
+ // Operation was canceled by the user.
+ return;
+ }
+
+ final Uint8List fileData = Uint8List.fromList('Hello World!'.codeUnits);
+ const String mimeType = 'text/plain';
+ final XFile textFile =
+ XFile.fromData(fileData, mimeType: mimeType, name: fileName);
+ await textFile.saveTo(path);
+ // #enddocregion Save
+ }
+}
diff --git a/packages/file_selector/file_selector/example/lib/save_text_page.dart b/packages/file_selector/file_selector/example/lib/save_text_page.dart
index b031784..257add5 100644
--- a/packages/file_selector/file_selector/example/lib/save_text_page.dart
+++ b/packages/file_selector/file_selector/example/lib/save_text_page.dart
@@ -5,6 +5,7 @@
import 'dart:typed_data';
import 'package:file_selector/file_selector.dart';
import 'package:flutter/material.dart';
+import 'package:path_provider/path_provider.dart';
/// Page for showing an example of saving with file_selector
class SaveTextPage extends StatelessWidget {
@@ -15,17 +16,27 @@
final TextEditingController _contentController = TextEditingController();
Future<void> _saveFile() async {
- final String? path = await getSavePath();
+ final String fileName = _nameController.text;
+ // This demonstrates using an initial directory for the prompt, which should
+ // only be done in cases where the application can likely predict where the
+ // file will be saved. In most cases, this parameter should not be provided.
+ final String initialDirectory =
+ (await getApplicationDocumentsDirectory()).path;
+ final String? path = await getSavePath(
+ initialDirectory: initialDirectory,
+ suggestedName: fileName,
+ );
if (path == null) {
// Operation was canceled by the user.
return;
}
+
final String text = _contentController.text;
- final String fileName = _nameController.text;
final Uint8List fileData = Uint8List.fromList(text.codeUnits);
const String fileMimeType = 'text/plain';
final XFile textFile =
XFile.fromData(fileData, mimeType: fileMimeType, name: fileName);
+
await textFile.saveTo(path);
}
diff --git a/packages/file_selector/file_selector/example/pubspec.yaml b/packages/file_selector/file_selector/example/pubspec.yaml
index 531f479..011d958 100644
--- a/packages/file_selector/file_selector/example/pubspec.yaml
+++ b/packages/file_selector/file_selector/example/pubspec.yaml
@@ -1,4 +1,4 @@
-name: example
+name: file_selector_example
description: A new Flutter project.
publish_to: none
@@ -17,8 +17,10 @@
path: ../
flutter:
sdk: flutter
+ path_provider: ^2.0.9
dev_dependencies:
+ build_runner: ^2.1.10
flutter_test:
sdk: flutter
diff --git a/packages/file_selector/file_selector/example/windows/flutter/generated_plugins.cmake b/packages/file_selector/file_selector/example/windows/flutter/generated_plugins.cmake
index 63eda9b..a423a02 100644
--- a/packages/file_selector/file_selector/example/windows/flutter/generated_plugins.cmake
+++ b/packages/file_selector/file_selector/example/windows/flutter/generated_plugins.cmake
@@ -6,6 +6,9 @@
file_selector_windows
)
+list(APPEND FLUTTER_FFI_PLUGIN_LIST
+)
+
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -14,3 +17,8 @@
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
+
+foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
+ add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
+ list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
+endforeach(ffi_plugin)
diff --git a/packages/file_selector/file_selector/lib/file_selector.dart b/packages/file_selector/file_selector/lib/file_selector.dart
index c2803d6..322ae6c 100644
--- a/packages/file_selector/file_selector/lib/file_selector.dart
+++ b/packages/file_selector/file_selector/lib/file_selector.dart
@@ -9,7 +9,24 @@
export 'package:file_selector_platform_interface/file_selector_platform_interface.dart'
show XFile, XTypeGroup;
-/// Open file dialog for loading files and return a file path
+/// Opens a file selection dialog and returns the path chosen by the user.
+///
+/// [acceptedTypeGroups] is a list of file type groups that can be selected in
+/// the dialog. How this is displayed depends on the pltaform, for example:
+/// - On Windows and Linux, each group will be an entry in a list of filter
+/// options.
+/// - On macOS, the union of all types allowed by all of the groups will be
+/// allowed.
+///
+/// [initialDirectory] is the full path to the directory that will be displayed
+/// when the dialog is opened. When not provided, the platform will pick an
+/// initial location. This is ignored on the Web platform.
+///
+/// [confirmButtonText] is the text in the confirmation button of the dialog.
+/// When not provided, the default OS label is used (for example, "Open").
+/// This is ignored on the Web platform.
+///
+/// Returns `null` if the user cancels the operation.
Future<XFile?> openFile({
List<XTypeGroup> acceptedTypeGroups = const <XTypeGroup>[],
String? initialDirectory,
@@ -21,7 +38,24 @@
confirmButtonText: confirmButtonText);
}
-/// Open file dialog for loading files and return a list of file paths
+/// Opens a file selection dialog and returns the list of paths chosen by the
+/// user.
+///
+/// [acceptedTypeGroups] is a list of file type groups that can be selected in
+/// the dialog. How this is displayed depends on the pltaform, for example:
+/// - On Windows and Linux, each group will be an entry in a list of filter
+/// options.
+/// - On macOS, the union of all types allowed by all of the groups will be
+/// allowed.
+///
+/// [initialDirectory] is the full path to the directory that will be displayed
+/// when the dialog is opened. When not provided, the platform will pick an
+/// initial location.
+///
+/// [confirmButtonText] is the text in the confirmation button of the dialog.
+/// When not provided, the default OS label is used (for example, "Open").
+///
+/// Returns an empty list if the user cancels the operation.
Future<List<XFile>> openFiles({
List<XTypeGroup> acceptedTypeGroups = const <XTypeGroup>[],
String? initialDirectory,
@@ -33,7 +67,25 @@
confirmButtonText: confirmButtonText);
}
-/// Saves File to user's file system
+/// Opens a save dialog and returns the target path chosen by the user.
+///
+/// [acceptedTypeGroups] is a list of file type groups that can be selected in
+/// the dialog. How this is displayed depends on the pltaform, for example:
+/// - On Windows and Linux, each group will be an entry in a list of filter
+/// options.
+/// - On macOS, the union of all types allowed by all of the groups will be
+/// allowed.
+///
+/// [initialDirectory] is the full path to the directory that will be displayed
+/// when the dialog is opened. When not provided, the platform will pick an
+/// initial location.
+///
+/// [suggestedName] is initial value of file name.
+///
+/// [confirmButtonText] is the text in the confirmation button of the dialog.
+/// When not provided, the default OS label is used (for example, "Save").
+///
+/// Returns `null` if the user cancels the operation.
Future<String?> getSavePath({
List<XTypeGroup> acceptedTypeGroups = const <XTypeGroup>[],
String? initialDirectory,
@@ -47,7 +99,17 @@
confirmButtonText: confirmButtonText);
}
-/// Gets a directory path from a user's file system
+/// Opens a directory selection dialog and returns the path chosen by the user.
+/// This always returns `null` on the web.
+///
+/// [initialDirectory] is the full path to the directory that will be displayed
+/// when the dialog is opened. When not provided, the platform will pick an
+/// initial location.
+///
+/// [confirmButtonText] is the text in the confirmation button of the dialog.
+/// When not provided, the default OS label is used (for example, "Open").
+///
+/// Returns `null` if the user cancels the operation.
Future<String?> getDirectoryPath({
String? initialDirectory,
String? confirmButtonText,
diff --git a/packages/file_selector/file_selector/pubspec.yaml b/packages/file_selector/file_selector/pubspec.yaml
index 1c502c0..12a1fbc 100644
--- a/packages/file_selector/file_selector/pubspec.yaml
+++ b/packages/file_selector/file_selector/pubspec.yaml
@@ -3,7 +3,7 @@
directories, using native file selection UI.
repository: https://github.com/flutter/plugins/tree/main/packages/file_selector/file_selector
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22
-version: 0.8.4+2
+version: 0.8.4+3
environment:
sdk: ">=2.12.0 <3.0.0"
diff --git a/script/configs/temp_exclude_excerpt.yaml b/script/configs/temp_exclude_excerpt.yaml
index bd73880..dec99ee 100644
--- a/script/configs/temp_exclude_excerpt.yaml
+++ b/script/configs/temp_exclude_excerpt.yaml
@@ -7,7 +7,6 @@
# https://github.com/flutter/flutter/issues/102679
- camera_web
- espresso
-- file_selector/file_selector
- google_maps_flutter/google_maps_flutter
- google_sign_in/google_sign_in
- google_sign_in_web