mirror of
https://github.com/flutter/packages.git
synced 2025-06-29 22:33:11 +08:00
[file_selector] Add file group to save return value - platform interface (#4254)
Platform interface portion of https://github.com/flutter/packages/pull/4222 Part of https://github.com/flutter/flutter/issues/107093
This commit is contained in:
@ -98,6 +98,9 @@ Future<String?> getSavePath({
|
|||||||
String? suggestedName,
|
String? suggestedName,
|
||||||
String? confirmButtonText,
|
String? confirmButtonText,
|
||||||
}) async {
|
}) async {
|
||||||
|
// TODO(stuartmorgan): Update this to getSaveLocation in the next federated
|
||||||
|
// change PR.
|
||||||
|
// ignore: deprecated_member_use
|
||||||
return FileSelectorPlatform.instance.getSavePath(
|
return FileSelectorPlatform.instance.getSavePath(
|
||||||
acceptedTypeGroups: acceptedTypeGroups,
|
acceptedTypeGroups: acceptedTypeGroups,
|
||||||
initialDirectory: initialDirectory,
|
initialDirectory: initialDirectory,
|
||||||
|
@ -17,6 +17,9 @@ class SaveTextPage extends StatelessWidget {
|
|||||||
|
|
||||||
Future<void> _saveFile() async {
|
Future<void> _saveFile() async {
|
||||||
final String fileName = _nameController.text;
|
final String fileName = _nameController.text;
|
||||||
|
// TODO(stuartmorgan): Update this to getSaveLocation in the next federated
|
||||||
|
// change PR.
|
||||||
|
// ignore: deprecated_member_use
|
||||||
final String? path = await FileSelectorPlatform.instance.getSavePath(
|
final String? path = await FileSelectorPlatform.instance.getSavePath(
|
||||||
// Operation was canceled by the user.
|
// Operation was canceled by the user.
|
||||||
suggestedName: fileName,
|
suggestedName: fileName,
|
||||||
|
@ -17,6 +17,9 @@ class SaveTextPage extends StatelessWidget {
|
|||||||
|
|
||||||
Future<void> _saveFile() async {
|
Future<void> _saveFile() async {
|
||||||
final String fileName = _nameController.text;
|
final String fileName = _nameController.text;
|
||||||
|
// TODO(stuartmorgan): Update this to getSaveLocation in the next federated
|
||||||
|
// change PR.
|
||||||
|
// ignore: deprecated_member_use
|
||||||
final String? path = await FileSelectorPlatform.instance.getSavePath(
|
final String? path = await FileSelectorPlatform.instance.getSavePath(
|
||||||
suggestedName: fileName,
|
suggestedName: fileName,
|
||||||
);
|
);
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
## 2.6.0
|
||||||
|
|
||||||
|
* Adds `getSaveLocation` and deprecates `getSavePath`.
|
||||||
|
|
||||||
## 2.5.1
|
## 2.5.1
|
||||||
|
|
||||||
* Adds compatibility with `http` 1.0.
|
* Adds compatibility with `http` 1.0.
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||||
|
|
||||||
import '../../file_selector_platform_interface.dart';
|
import '../../file_selector_platform_interface.dart';
|
||||||
@ -37,7 +35,10 @@ abstract class FileSelectorPlatform extends PlatformInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Opens a file dialog for loading files and returns a file path.
|
/// Opens a file dialog for loading files and returns a file path.
|
||||||
/// Returns `null` if user cancels the operation.
|
///
|
||||||
|
/// Returns `null` if the user cancels the operation.
|
||||||
|
// TODO(stuartmorgan): Switch to FileDialogOptions if we ever need to
|
||||||
|
// duplicate this to add a parameter.
|
||||||
Future<XFile?> openFile({
|
Future<XFile?> openFile({
|
||||||
List<XTypeGroup>? acceptedTypeGroups,
|
List<XTypeGroup>? acceptedTypeGroups,
|
||||||
String? initialDirectory,
|
String? initialDirectory,
|
||||||
@ -47,6 +48,10 @@ abstract class FileSelectorPlatform extends PlatformInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Opens a file dialog for loading files and returns a list of file paths.
|
/// Opens a file dialog for loading files and returns a list of file paths.
|
||||||
|
///
|
||||||
|
/// Returns an empty list if the user cancels the operation.
|
||||||
|
// TODO(stuartmorgan): Switch to FileDialogOptions if we ever need to
|
||||||
|
// duplicate this to add a parameter.
|
||||||
Future<List<XFile>> openFiles({
|
Future<List<XFile>> openFiles({
|
||||||
List<XTypeGroup>? acceptedTypeGroups,
|
List<XTypeGroup>? acceptedTypeGroups,
|
||||||
String? initialDirectory,
|
String? initialDirectory,
|
||||||
@ -55,8 +60,13 @@ abstract class FileSelectorPlatform extends PlatformInterface {
|
|||||||
throw UnimplementedError('openFiles() has not been implemented.');
|
throw UnimplementedError('openFiles() has not been implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Opens a file dialog for saving files and returns a file path at which to save.
|
/// Opens a file dialog for saving files and returns a file path at which to
|
||||||
/// Returns `null` if user cancels the operation.
|
/// save.
|
||||||
|
///
|
||||||
|
/// Returns `null` if the user cancels the operation.
|
||||||
|
// TODO(stuartmorgan): Switch to FileDialogOptions if we ever need to
|
||||||
|
// duplicate this to add a parameter.
|
||||||
|
@Deprecated('Use getSaveLocation instead')
|
||||||
Future<String?> getSavePath({
|
Future<String?> getSavePath({
|
||||||
List<XTypeGroup>? acceptedTypeGroups,
|
List<XTypeGroup>? acceptedTypeGroups,
|
||||||
String? initialDirectory,
|
String? initialDirectory,
|
||||||
@ -66,8 +76,28 @@ abstract class FileSelectorPlatform extends PlatformInterface {
|
|||||||
throw UnimplementedError('getSavePath() has not been implemented.');
|
throw UnimplementedError('getSavePath() has not been implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Opens a file dialog for saving files and returns a file location at which
|
||||||
|
/// to save.
|
||||||
|
///
|
||||||
|
/// Returns `null` if the user cancels the operation.
|
||||||
|
Future<FileSaveLocation?> getSaveLocation({
|
||||||
|
List<XTypeGroup>? acceptedTypeGroups,
|
||||||
|
SaveDialogOptions options = const SaveDialogOptions(),
|
||||||
|
}) async {
|
||||||
|
final String? path = await getSavePath(
|
||||||
|
acceptedTypeGroups: acceptedTypeGroups,
|
||||||
|
initialDirectory: options.initialDirectory,
|
||||||
|
suggestedName: options.suggestedName,
|
||||||
|
confirmButtonText: options.confirmButtonText,
|
||||||
|
);
|
||||||
|
return path == null ? null : FileSaveLocation(path);
|
||||||
|
}
|
||||||
|
|
||||||
/// Opens a file dialog for loading directories and returns a directory path.
|
/// Opens a file dialog for loading directories and returns a directory path.
|
||||||
/// Returns `null` if user cancels the operation.
|
///
|
||||||
|
/// Returns `null` if the user cancels the operation.
|
||||||
|
// TODO(stuartmorgan): Switch to FileDialogOptions if we ever need to
|
||||||
|
// duplicate this to add a parameter.
|
||||||
Future<String?> getDirectoryPath({
|
Future<String?> getDirectoryPath({
|
||||||
String? initialDirectory,
|
String? initialDirectory,
|
||||||
String? confirmButtonText,
|
String? confirmButtonText,
|
||||||
@ -75,7 +105,12 @@ abstract class FileSelectorPlatform extends PlatformInterface {
|
|||||||
throw UnimplementedError('getDirectoryPath() has not been implemented.');
|
throw UnimplementedError('getDirectoryPath() has not been implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Opens a file dialog for loading directories and returns multiple directory paths.
|
/// Opens a file dialog for loading directories and returns multiple directory
|
||||||
|
/// paths.
|
||||||
|
///
|
||||||
|
/// Returns an empty list if the user cancels the operation.
|
||||||
|
// TODO(stuartmorgan): Switch to FileDialogOptions if we ever need to
|
||||||
|
// duplicate this to add a parameter.
|
||||||
Future<List<String>> getDirectoryPaths({
|
Future<List<String>> getDirectoryPaths({
|
||||||
String? initialDirectory,
|
String? initialDirectory,
|
||||||
String? confirmButtonText,
|
String? confirmButtonText,
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart' show immutable;
|
||||||
|
|
||||||
|
/// Configuration options for any file selector dialog.
|
||||||
|
@immutable
|
||||||
|
class FileDialogOptions {
|
||||||
|
/// Creates a new options set with the given settings.
|
||||||
|
const FileDialogOptions({this.initialDirectory, this.confirmButtonText});
|
||||||
|
|
||||||
|
/// The initial directory the dialog should open with.
|
||||||
|
final String? initialDirectory;
|
||||||
|
|
||||||
|
/// The label for the button that confirms selection.
|
||||||
|
final String? confirmButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration options for a save dialog.
|
||||||
|
@immutable
|
||||||
|
class SaveDialogOptions extends FileDialogOptions {
|
||||||
|
/// Creates a new options set with the given settings.
|
||||||
|
const SaveDialogOptions(
|
||||||
|
{super.initialDirectory, super.confirmButtonText, this.suggestedName});
|
||||||
|
|
||||||
|
/// The suggested name of the file to save or open.
|
||||||
|
final String? suggestedName;
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart' show immutable;
|
||||||
|
|
||||||
|
import 'x_type_group.dart';
|
||||||
|
|
||||||
|
export 'x_type_group.dart';
|
||||||
|
|
||||||
|
/// The response from a save dialog.
|
||||||
|
@immutable
|
||||||
|
class FileSaveLocation {
|
||||||
|
/// Creates a result with the given [path] and optional other dialog state.
|
||||||
|
const FileSaveLocation(this.path, {this.activeFilter});
|
||||||
|
|
||||||
|
/// The path to save to.
|
||||||
|
final String path;
|
||||||
|
|
||||||
|
/// The currently active filter group, if any.
|
||||||
|
///
|
||||||
|
/// This is null on platforms that do not support user-selectable filter
|
||||||
|
/// groups in save dialogs (for example, macOS), or when no filter groups
|
||||||
|
/// were provided when showing the dialog.
|
||||||
|
final XTypeGroup? activeFilter;
|
||||||
|
}
|
@ -3,4 +3,6 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
export 'package:cross_file/cross_file.dart';
|
export 'package:cross_file/cross_file.dart';
|
||||||
export 'x_type_group/x_type_group.dart';
|
export 'file_dialog_options.dart';
|
||||||
|
export 'file_save_location.dart';
|
||||||
|
export 'x_type_group.dart';
|
||||||
|
@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/file_selector
|
|||||||
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22
|
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22
|
||||||
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
|
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
|
||||||
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
|
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
|
||||||
version: 2.5.1
|
version: 2.6.0
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.18.0 <4.0.0"
|
sdk: ">=2.18.0 <4.0.0"
|
||||||
|
@ -10,7 +10,7 @@ void main() {
|
|||||||
// Store the initial instance before any tests change it.
|
// Store the initial instance before any tests change it.
|
||||||
final FileSelectorPlatform initialInstance = FileSelectorPlatform.instance;
|
final FileSelectorPlatform initialInstance = FileSelectorPlatform.instance;
|
||||||
|
|
||||||
group('$FileSelectorPlatform', () {
|
group('FileSelectorPlatform', () {
|
||||||
test('$MethodChannelFileSelector() is the default instance', () {
|
test('$MethodChannelFileSelector() is the default instance', () {
|
||||||
expect(initialInstance, isInstanceOf<MethodChannelFileSelector>());
|
expect(initialInstance, isInstanceOf<MethodChannelFileSelector>());
|
||||||
});
|
});
|
||||||
@ -20,7 +20,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group('#GetDirectoryPaths', () {
|
group('getDirectoryPaths', () {
|
||||||
test('Should throw unimplemented exception', () async {
|
test('Should throw unimplemented exception', () async {
|
||||||
final FileSelectorPlatform fileSelector = ExtendsFileSelectorPlatform();
|
final FileSelectorPlatform fileSelector = ExtendsFileSelectorPlatform();
|
||||||
|
|
||||||
@ -29,6 +29,30 @@ void main() {
|
|||||||
}, throwsA(isA<UnimplementedError>()));
|
}, throwsA(isA<UnimplementedError>()));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('getSaveLocation falls back to getSavePath by default', () async {
|
||||||
|
final FileSelectorPlatform fileSelector =
|
||||||
|
OldFileSelectorPlatformImplementation();
|
||||||
|
|
||||||
|
final FileSaveLocation? result = await fileSelector.getSaveLocation();
|
||||||
|
|
||||||
|
expect(result?.path, OldFileSelectorPlatformImplementation.savePath);
|
||||||
|
expect(result?.activeFilter, null);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExtendsFileSelectorPlatform extends FileSelectorPlatform {}
|
class ExtendsFileSelectorPlatform extends FileSelectorPlatform {}
|
||||||
|
|
||||||
|
class OldFileSelectorPlatformImplementation extends FileSelectorPlatform {
|
||||||
|
static const String savePath = '/a/path';
|
||||||
|
// Only implement the deprecated getSavePath.
|
||||||
|
@override
|
||||||
|
Future<String?> getSavePath({
|
||||||
|
List<XTypeGroup>? acceptedTypeGroups,
|
||||||
|
String? initialDirectory,
|
||||||
|
String? suggestedName,
|
||||||
|
String? confirmButtonText,
|
||||||
|
}) async {
|
||||||
|
return savePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,6 +17,9 @@ class SaveTextPage extends StatelessWidget {
|
|||||||
|
|
||||||
Future<void> _saveFile() async {
|
Future<void> _saveFile() async {
|
||||||
final String fileName = _nameController.text;
|
final String fileName = _nameController.text;
|
||||||
|
// TODO(stuartmorgan): Update this to getSaveLocation in the next federated
|
||||||
|
// change PR.
|
||||||
|
// ignore: deprecated_member_use
|
||||||
final String? path = await FileSelectorPlatform.instance.getSavePath(
|
final String? path = await FileSelectorPlatform.instance.getSavePath(
|
||||||
// Operation was canceled by the user.
|
// Operation was canceled by the user.
|
||||||
suggestedName: fileName,
|
suggestedName: fileName,
|
||||||
|
Reference in New Issue
Block a user