Skip to content

Commit 6d8782d

Browse files
[file_selector] Add file group to save return value - implementations (#4273)
Implementation package portion of #4222 Part of flutter/flutter#107093
1 parent d041934 commit 6d8782d

36 files changed

+982
-289
lines changed

packages/file_selector/file_selector_linux/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 0.9.2
22

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

56
## 0.9.1+3

packages/file_selector/file_selector_linux/example/lib/save_text_page.dart

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,20 @@ class SaveTextPage extends StatelessWidget {
1717

1818
Future<void> _saveFile() async {
1919
final String fileName = _nameController.text;
20-
// TODO(stuartmorgan): Update this to getSaveLocation in the next federated
21-
// change PR.
22-
// ignore: deprecated_member_use
23-
final String? path = await FileSelectorPlatform.instance.getSavePath(
24-
// Operation was canceled by the user.
25-
suggestedName: fileName,
20+
final FileSaveLocation? result =
21+
await FileSelectorPlatform.instance.getSaveLocation(
22+
options: SaveDialogOptions(suggestedName: fileName),
2623
);
27-
if (path == null) {
24+
// Operation was canceled by the user.
25+
if (result == null) {
2826
return;
2927
}
3028
final String text = _contentController.text;
3129
final Uint8List fileData = Uint8List.fromList(text.codeUnits);
3230
const String fileMimeType = 'text/plain';
3331
final XFile textFile =
3432
XFile.fromData(fileData, mimeType: fileMimeType, name: fileName);
35-
await textFile.saveTo(path);
33+
await textFile.saveTo(result.path);
3634
}
3735

3836
@override

packages/file_selector/file_selector_linux/example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ environment:
1010
dependencies:
1111
file_selector_linux:
1212
path: ../
13-
file_selector_platform_interface: ^2.4.0
13+
file_selector_platform_interface: ^2.6.0
1414
flutter:
1515
sdk: flutter
1616

packages/file_selector/file_selector_linux/lib/file_selector_linux.dart

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,19 +82,37 @@ class FileSelectorLinux extends FileSelectorPlatform {
8282
String? initialDirectory,
8383
String? suggestedName,
8484
String? confirmButtonText,
85+
}) async {
86+
final FileSaveLocation? location = await getSaveLocation(
87+
acceptedTypeGroups: acceptedTypeGroups,
88+
options: SaveDialogOptions(
89+
initialDirectory: initialDirectory,
90+
suggestedName: suggestedName,
91+
confirmButtonText: confirmButtonText,
92+
));
93+
return location?.path;
94+
}
95+
96+
@override
97+
Future<FileSaveLocation?> getSaveLocation({
98+
List<XTypeGroup>? acceptedTypeGroups,
99+
SaveDialogOptions options = const SaveDialogOptions(),
85100
}) async {
86101
final List<Map<String, Object>> serializedTypeGroups =
87102
_serializeTypeGroups(acceptedTypeGroups);
88-
return _channel.invokeMethod<String>(
103+
// TODO(stuartmorgan): Add the selected type group here and return it. See
104+
// https://github.com/flutter/flutter/issues/107093
105+
final String? path = await _channel.invokeMethod<String>(
89106
_getSavePathMethod,
90107
<String, dynamic>{
91108
if (serializedTypeGroups.isNotEmpty)
92109
_acceptedTypeGroupsKey: serializedTypeGroups,
93-
_initialDirectoryKey: initialDirectory,
94-
_suggestedNameKey: suggestedName,
95-
_confirmButtonTextKey: confirmButtonText,
110+
_initialDirectoryKey: options.initialDirectory,
111+
_suggestedNameKey: options.suggestedName,
112+
_confirmButtonTextKey: options.confirmButtonText,
96113
},
97114
);
115+
return path == null ? null : FileSaveLocation(path);
98116
}
99117

100118
@override

packages/file_selector/file_selector_linux/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: file_selector_linux
22
description: Liunx implementation of the file_selector plugin.
33
repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_linux
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22
5-
version: 0.9.1+3
5+
version: 0.9.2
66

77
environment:
88
sdk: ">=2.18.0 <4.0.0"
@@ -18,7 +18,7 @@ flutter:
1818

1919
dependencies:
2020
cross_file: ^0.3.1
21-
file_selector_platform_interface: ^2.4.0
21+
file_selector_platform_interface: ^2.6.0
2222
flutter:
2323
sdk: flutter
2424

packages/file_selector/file_selector_linux/test/file_selector_linux_test.dart

Lines changed: 119 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ void main() {
3232
expect(FileSelectorPlatform.instance, isA<FileSelectorLinux>());
3333
});
3434

35-
group('#openFile', () {
35+
group('openFile', () {
3636
test('passes the accepted type groups correctly', () async {
3737
const XTypeGroup group = XTypeGroup(
3838
label: 'text',
@@ -135,7 +135,7 @@ void main() {
135135
});
136136
});
137137

138-
group('#openFiles', () {
138+
group('openFiles', () {
139139
test('passes the accepted type groups correctly', () async {
140140
const XTypeGroup group = XTypeGroup(
141141
label: 'text',
@@ -209,7 +209,7 @@ void main() {
209209
);
210210

211211
await expectLater(
212-
plugin.openFile(acceptedTypeGroups: <XTypeGroup>[group]),
212+
plugin.openFiles(acceptedTypeGroups: <XTypeGroup>[group]),
213213
throwsArgumentError);
214214
});
215215

@@ -218,7 +218,7 @@ void main() {
218218
label: 'any',
219219
);
220220

221-
await plugin.openFile(acceptedTypeGroups: <XTypeGroup>[group]);
221+
await plugin.openFiles(acceptedTypeGroups: <XTypeGroup>[group]);
222222

223223
expectMethodCall(
224224
log,
@@ -232,13 +232,120 @@ void main() {
232232
],
233233
'initialDirectory': null,
234234
'confirmButtonText': null,
235-
'multiple': false,
235+
'multiple': true,
236+
},
237+
);
238+
});
239+
});
240+
241+
group('getSaveLocation', () {
242+
test('passes the accepted type groups correctly', () async {
243+
const XTypeGroup group = XTypeGroup(
244+
label: 'text',
245+
extensions: <String>['txt'],
246+
mimeTypes: <String>['text/plain'],
247+
);
248+
249+
const XTypeGroup groupTwo = XTypeGroup(
250+
label: 'image',
251+
extensions: <String>['jpg'],
252+
mimeTypes: <String>['image/jpg'],
253+
);
254+
255+
await plugin
256+
.getSaveLocation(acceptedTypeGroups: <XTypeGroup>[group, groupTwo]);
257+
258+
expectMethodCall(
259+
log,
260+
'getSavePath',
261+
arguments: <String, dynamic>{
262+
'acceptedTypeGroups': <Map<String, dynamic>>[
263+
<String, Object>{
264+
'label': 'text',
265+
'extensions': <String>['*.txt'],
266+
'mimeTypes': <String>['text/plain'],
267+
},
268+
<String, Object>{
269+
'label': 'image',
270+
'extensions': <String>['*.jpg'],
271+
'mimeTypes': <String>['image/jpg'],
272+
},
273+
],
274+
'initialDirectory': null,
275+
'suggestedName': null,
276+
'confirmButtonText': null,
277+
},
278+
);
279+
});
280+
281+
test('passes initialDirectory correctly', () async {
282+
await plugin.getSaveLocation(
283+
options:
284+
const SaveDialogOptions(initialDirectory: '/example/directory'));
285+
286+
expectMethodCall(
287+
log,
288+
'getSavePath',
289+
arguments: <String, dynamic>{
290+
'initialDirectory': '/example/directory',
291+
'suggestedName': null,
292+
'confirmButtonText': null,
293+
},
294+
);
295+
});
296+
297+
test('passes confirmButtonText correctly', () async {
298+
await plugin.getSaveLocation(
299+
options: const SaveDialogOptions(confirmButtonText: 'Open File'));
300+
301+
expectMethodCall(
302+
log,
303+
'getSavePath',
304+
arguments: <String, dynamic>{
305+
'initialDirectory': null,
306+
'suggestedName': null,
307+
'confirmButtonText': 'Open File',
308+
},
309+
);
310+
});
311+
312+
test('throws for a type group that does not support Linux', () async {
313+
const XTypeGroup group = XTypeGroup(
314+
label: 'images',
315+
webWildCards: <String>['images/*'],
316+
);
317+
318+
await expectLater(
319+
plugin.getSaveLocation(acceptedTypeGroups: <XTypeGroup>[group]),
320+
throwsArgumentError);
321+
});
322+
323+
test('passes a wildcard group correctly', () async {
324+
const XTypeGroup group = XTypeGroup(
325+
label: 'any',
326+
);
327+
328+
await plugin.getSaveLocation(acceptedTypeGroups: <XTypeGroup>[group]);
329+
330+
expectMethodCall(
331+
log,
332+
'getSavePath',
333+
arguments: <String, dynamic>{
334+
'acceptedTypeGroups': <Map<String, dynamic>>[
335+
<String, Object>{
336+
'label': 'any',
337+
'extensions': <String>['*'],
338+
},
339+
],
340+
'initialDirectory': null,
341+
'suggestedName': null,
342+
'confirmButtonText': null,
236343
},
237344
);
238345
});
239346
});
240347

241-
group('#getSavePath', () {
348+
group('getSavePath (deprecated)', () {
242349
test('passes the accepted type groups correctly', () async {
243350
const XTypeGroup group = XTypeGroup(
244351
label: 'text',
@@ -313,7 +420,7 @@ void main() {
313420
);
314421

315422
await expectLater(
316-
plugin.openFile(acceptedTypeGroups: <XTypeGroup>[group]),
423+
plugin.getSavePath(acceptedTypeGroups: <XTypeGroup>[group]),
317424
throwsArgumentError);
318425
});
319426

@@ -322,11 +429,11 @@ void main() {
322429
label: 'any',
323430
);
324431

325-
await plugin.openFile(acceptedTypeGroups: <XTypeGroup>[group]);
432+
await plugin.getSavePath(acceptedTypeGroups: <XTypeGroup>[group]);
326433

327434
expectMethodCall(
328435
log,
329-
'openFile',
436+
'getSavePath',
330437
arguments: <String, dynamic>{
331438
'acceptedTypeGroups': <Map<String, dynamic>>[
332439
<String, Object>{
@@ -335,14 +442,14 @@ void main() {
335442
},
336443
],
337444
'initialDirectory': null,
445+
'suggestedName': null,
338446
'confirmButtonText': null,
339-
'multiple': false,
340447
},
341448
);
342449
});
343450
});
344451

345-
group('#getDirectoryPath', () {
452+
group('getDirectoryPath', () {
346453
test('passes initialDirectory correctly', () async {
347454
await plugin.getDirectoryPath(initialDirectory: '/example/directory');
348455

@@ -369,7 +476,7 @@ void main() {
369476
});
370477
});
371478

372-
group('#getDirectoryPaths', () {
479+
group('getDirectoryPaths', () {
373480
test('passes initialDirectory correctly', () async {
374481
await plugin.getDirectoryPaths(initialDirectory: '/example/directory');
375482

packages/file_selector/file_selector_macos/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 0.9.3
22

3+
* Adds `getSaveLocation` and deprecates `getSavePath`.
34
* Updates minimum supported macOS version to 10.14.
45

56
## 0.9.2

packages/file_selector/file_selector_macos/example/lib/save_text_page.dart

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@ class SaveTextPage extends StatelessWidget {
1717

1818
Future<void> _saveFile() async {
1919
final String fileName = _nameController.text;
20-
// TODO(stuartmorgan): Update this to getSaveLocation in the next federated
21-
// change PR.
22-
// ignore: deprecated_member_use
23-
final String? path = await FileSelectorPlatform.instance.getSavePath(
24-
suggestedName: fileName,
20+
final FileSaveLocation? result =
21+
await FileSelectorPlatform.instance.getSaveLocation(
22+
options: SaveDialogOptions(suggestedName: fileName),
2523
);
26-
if (path == null) {
24+
if (result == null) {
2725
// Operation was canceled by the user.
2826
return;
2927
}
@@ -32,7 +30,7 @@ class SaveTextPage extends StatelessWidget {
3230
const String fileMimeType = 'text/plain';
3331
final XFile textFile =
3432
XFile.fromData(fileData, mimeType: fileMimeType, name: fileName);
35-
await textFile.saveTo(path);
33+
await textFile.saveTo(result.path);
3634
}
3735

3836
@override

packages/file_selector/file_selector_macos/example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ dependencies:
1515
# The example app is bundled with the plugin so we use a path dependency on
1616
# the parent directory to use the current plugin's version.
1717
path: ..
18-
file_selector_platform_interface: ^2.4.0
18+
file_selector_platform_interface: ^2.6.0
1919
flutter:
2020
sdk: flutter
2121

packages/file_selector/file_selector_macos/lib/file_selector_macos.dart

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,28 @@ class FileSelectorMacOS extends FileSelectorPlatform {
6060
String? suggestedName,
6161
String? confirmButtonText,
6262
}) async {
63-
return _hostApi.displaySavePanel(SavePanelOptions(
63+
final FileSaveLocation? location = await getSaveLocation(
64+
acceptedTypeGroups: acceptedTypeGroups,
65+
options: SaveDialogOptions(
66+
initialDirectory: initialDirectory,
67+
suggestedName: suggestedName,
68+
confirmButtonText: confirmButtonText,
69+
));
70+
return location?.path;
71+
}
72+
73+
@override
74+
Future<FileSaveLocation?> getSaveLocation({
75+
List<XTypeGroup>? acceptedTypeGroups,
76+
SaveDialogOptions options = const SaveDialogOptions(),
77+
}) async {
78+
final String? path = await _hostApi.displaySavePanel(SavePanelOptions(
6479
allowedFileTypes: _allowedTypesFromTypeGroups(acceptedTypeGroups),
65-
directoryPath: initialDirectory,
66-
nameFieldStringValue: suggestedName,
67-
prompt: confirmButtonText,
80+
directoryPath: options.initialDirectory,
81+
nameFieldStringValue: options.suggestedName,
82+
prompt: options.confirmButtonText,
6883
));
84+
return path == null ? null : FileSaveLocation(path);
6985
}
7086

7187
@override

0 commit comments

Comments
 (0)