Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 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
3 changes: 2 additions & 1 deletion packages/file_selector/file_selector/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## NEXT
## 0.9.4

* Adds `getSaveLocation` and deprecates `getSavePath`.
* Updates minimum supported macOS version to 10.14.
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ class _MyAppState extends State<MyApp> {
Future<void> saveFile() async {
// #docregion Save
const String fileName = 'suggested_name.txt';
final String? path = await getSavePath(suggestedName: fileName);
if (path == null) {
final FileSaveLocationResult? result =
await getSaveLocation(suggestedName: fileName);
if (result == null) {
// Operation was canceled by the user.
return;
}
Expand All @@ -49,7 +50,7 @@ class _MyAppState extends State<MyApp> {
const String mimeType = 'text/plain';
final XFile textFile =
XFile.fromData(fileData, mimeType: mimeType, name: fileName);
await textFile.saveTo(path);
await textFile.saveTo(result.path);
// #enddocregion Save
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ class SaveTextPage extends StatelessWidget {
// file will be saved. In most cases, this parameter should not be provided.
final String initialDirectory =
(await getApplicationDocumentsDirectory()).path;
final String? path = await getSavePath(
final FileSaveLocationResult? result = await getSaveLocation(
initialDirectory: initialDirectory,
suggestedName: fileName,
);
if (path == null) {
if (result == null) {
// Operation was canceled by the user.
return;
}
Expand All @@ -39,7 +39,7 @@ class SaveTextPage extends StatelessWidget {
final XFile textFile =
XFile.fromData(fileData, mimeType: fileMimeType, name: fileName);

await textFile.saveTo(path);
await textFile.saveTo(result.path);
}

@override
Expand Down
5 changes: 5 additions & 0 deletions packages/file_selector/file_selector/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@ dev_dependencies:

flutter:
uses-material-design: true

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins
dependency_overrides:
{file_selector_platform_interface: {path: ../../../file_selector/file_selector_platform_interface}}
47 changes: 42 additions & 5 deletions packages/file_selector/file_selector/lib/file_selector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'dart:async';
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';

export 'package:file_selector_platform_interface/file_selector_platform_interface.dart'
show XFile, XTypeGroup;
show FileSaveLocationResult, XFile, XTypeGroup;

/// Opens a file selection dialog and returns the path chosen by the user.
///
Expand Down Expand Up @@ -92,17 +92,54 @@ Future<List<XFile>> openFiles({
/// When not provided, the default OS label is used (for example, "Save").
///
/// Returns `null` if the user cancels the operation.
@Deprecated('Use getSaveLocation instead')
Future<String?> getSavePath({
List<XTypeGroup> acceptedTypeGroups = const <XTypeGroup>[],
String? initialDirectory,
String? suggestedName,
String? confirmButtonText,
}) async {
return FileSelectorPlatform.instance.getSavePath(
return (await getSaveLocation(
acceptedTypeGroups: acceptedTypeGroups,
initialDirectory: initialDirectory,
suggestedName: suggestedName,
confirmButtonText: confirmButtonText))
?.path;
}

/// 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.
/// Throws an [ArgumentError] if any type groups do not include filters
/// supported by the current platform.
///
/// [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<FileSaveLocationResult?> getSaveLocation({
List<XTypeGroup> acceptedTypeGroups = const <XTypeGroup>[],
String? initialDirectory,
String? suggestedName,
String? confirmButtonText,
}) async {
return FileSelectorPlatform.instance.getSaveLocation(
acceptedTypeGroups: acceptedTypeGroups,
initialDirectory: initialDirectory,
suggestedName: suggestedName,
confirmButtonText: confirmButtonText);
options: SaveDialogOptions(
initialDirectory: initialDirectory,
suggestedName: suggestedName,
confirmButtonText: confirmButtonText));
}

/// Opens a directory selection dialog and returns the path chosen by the user.
Expand Down
7 changes: 6 additions & 1 deletion packages/file_selector/file_selector/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for opening and saving files, or selecting
directories, using native file selection UI.
repository: https://github.com/flutter/packages/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.9.3
version: 0.9.4

environment:
sdk: ">=2.18.0 <4.0.0"
Expand Down Expand Up @@ -38,3 +38,8 @@ dev_dependencies:
sdk: flutter
plugin_platform_interface: ^2.0.0
test: ^1.16.3

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins
dependency_overrides:
{file_selector_platform_interface: {path: ../../file_selector/file_selector_platform_interface}}
111 changes: 104 additions & 7 deletions packages/file_selector/file_selector/test/file_selector_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,80 @@ void main() {
});
});

group('getSavePath', () {
group('getSaveLocation', () {
const String expectedSavePath = '/example/path';

test('works', () async {
const int expectedActiveFilter = 1;
fakePlatformImplementation
..setExpectations(
initialDirectory: initialDirectory,
confirmButtonText: confirmButtonText,
acceptedTypeGroups: acceptedTypeGroups,
suggestedName: suggestedName)
..setPathsResponse(<String>[expectedSavePath],
activeFilter: expectedActiveFilter);

final FileSaveLocationResult? location = await getSaveLocation(
initialDirectory: initialDirectory,
confirmButtonText: confirmButtonText,
acceptedTypeGroups: acceptedTypeGroups,
suggestedName: suggestedName,
);

expect(location?.path, expectedSavePath);
expect(location?.activeFilter, acceptedTypeGroups[expectedActiveFilter]);
});

test('works with no arguments', () async {
fakePlatformImplementation.setPathsResponse(<String>[expectedSavePath]);

final FileSaveLocationResult? location = await getSaveLocation();
expect(location?.path, expectedSavePath);
});

test('sets the initial directory', () async {
fakePlatformImplementation
..setExpectations(initialDirectory: initialDirectory)
..setPathsResponse(<String>[expectedSavePath]);

final FileSaveLocationResult? location =
await getSaveLocation(initialDirectory: initialDirectory);
expect(location?.path, expectedSavePath);
});

test('sets the button confirmation label', () async {
fakePlatformImplementation
..setExpectations(confirmButtonText: confirmButtonText)
..setPathsResponse(<String>[expectedSavePath]);

final FileSaveLocationResult? location =
await getSaveLocation(confirmButtonText: confirmButtonText);
expect(location?.path, expectedSavePath);
});

test('sets the accepted type groups', () async {
fakePlatformImplementation
..setExpectations(acceptedTypeGroups: acceptedTypeGroups)
..setPathsResponse(<String>[expectedSavePath]);

final FileSaveLocationResult? location =
await getSaveLocation(acceptedTypeGroups: acceptedTypeGroups);
expect(location?.path, expectedSavePath);
});

test('sets the suggested name', () async {
fakePlatformImplementation
..setExpectations(suggestedName: suggestedName)
..setPathsResponse(<String>[expectedSavePath]);

final FileSaveLocationResult? location =
await getSaveLocation(suggestedName: suggestedName);
expect(location?.path, expectedSavePath);
});
});

group('getSavePath (deprecated)', () {
const String expectedSavePath = '/example/path';

test('works', () async {
Expand Down Expand Up @@ -321,6 +394,7 @@ class FakeFileSelector extends Fake
// Return values.
List<XFile>? files;
List<String>? paths;
int? activeFilter;

void setExpectations({
List<XTypeGroup> acceptedTypeGroups = const <XTypeGroup>[],
Expand All @@ -339,9 +413,9 @@ class FakeFileSelector extends Fake
this.files = files;
}

// ignore: use_setters_to_change_properties
void setPathsResponse(List<String> paths) {
void setPathsResponse(List<String> paths, {int? activeFilter}) {
this.paths = paths;
this.activeFilter = activeFilter;
}

@override
Expand Down Expand Up @@ -374,12 +448,35 @@ class FakeFileSelector extends Fake
String? initialDirectory,
String? suggestedName,
String? confirmButtonText,
}) async {
return (await getSaveLocation(
acceptedTypeGroups: acceptedTypeGroups,
options: SaveDialogOptions(
initialDirectory: initialDirectory,
suggestedName: suggestedName,
confirmButtonText: confirmButtonText,
),
))
?.path;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this intentional (or produced with dartfmt)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dartfmt :( But @ditman's suggestion fixed it.

}

@override
Future<FileSaveLocationResult?> getSaveLocation({
List<XTypeGroup>? acceptedTypeGroups,
SaveDialogOptions options = const SaveDialogOptions(),
}) async {
expect(acceptedTypeGroups, this.acceptedTypeGroups);
expect(initialDirectory, this.initialDirectory);
expect(suggestedName, this.suggestedName);
expect(confirmButtonText, this.confirmButtonText);
return paths?[0];
expect(options.initialDirectory, initialDirectory);
expect(options.suggestedName, suggestedName);
expect(options.confirmButtonText, confirmButtonText);
final String? path = paths?[0];
final int? activeFilterIndex = activeFilter;
return path == null
? null
: FileSaveLocationResult(path,
activeFilter: activeFilterIndex == null
? null
: acceptedTypeGroups?[activeFilterIndex]);
}

@override
Expand Down
4 changes: 4 additions & 0 deletions packages/file_selector/file_selector_ios/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.5.2

* Adds `getSaveLocation` and deprecates `getSavePath`.

## 0.5.1+4

* Updates references to the deprecated `macUTIs`.
Expand Down
5 changes: 5 additions & 0 deletions packages/file_selector/file_selector_ios/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,8 @@ dev_dependencies:

flutter:
uses-material-design: true

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins
dependency_overrides:
{file_selector_platform_interface: {path: ../../../file_selector/file_selector_platform_interface}}
7 changes: 6 additions & 1 deletion packages/file_selector/file_selector_ios/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: file_selector_ios
description: iOS implementation of the file_selector plugin.
repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_ios
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22
version: 0.5.1+4
version: 0.5.2

environment:
sdk: ">=2.18.0 <4.0.0"
Expand All @@ -27,3 +27,8 @@ dev_dependencies:
sdk: flutter
mockito: 5.4.1
pigeon: ^9.2.4

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins
dependency_overrides:
{file_selector_platform_interface: {path: ../../file_selector/file_selector_platform_interface}}
3 changes: 2 additions & 1 deletion packages/file_selector/file_selector_linux/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## NEXT
## 0.9.2

* Adds `getSaveLocation` and deprecates `getSavePath`.
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.

## 0.9.1+3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@ class SaveTextPage extends StatelessWidget {

Future<void> _saveFile() async {
final String fileName = _nameController.text;
final String? path = await FileSelectorPlatform.instance.getSavePath(
// Operation was canceled by the user.
suggestedName: fileName,
final FileSaveLocationResult? result =
await FileSelectorPlatform.instance.getSaveLocation(
options: SaveDialogOptions(suggestedName: fileName),
);
if (path == null) {
// Operation was canceled by the user.
if (result == null) {
return;
}
final String text = _contentController.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);
await textFile.saveTo(result.path);
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,8 @@ dev_dependencies:

flutter:
uses-material-design: true

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins
dependency_overrides:
{file_selector_platform_interface: {path: ../../../file_selector/file_selector_platform_interface}}
Loading