Skip to content

Commit

Permalink
Adds support to cross_file (XFile) and other minor improvements & fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Miguel Ruivo committed Mar 20, 2024
1 parent a84f497 commit 07afbfa
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 76 deletions.
34 changes: 24 additions & 10 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
## 7.1.0
### General
- Adds `xFiles` getter to [FilePickerResult] and `XFile` to `PlatformFile` to retrieve a `List<XFile>` or single `XFile` accordingly.
- Bumps win32, flutter_plugin_android_lifecycle, plugin_platform_interface and lints versions.
- Fixes NPE when compressing images from gallery on Android 14 [#1455](https://github.com/miguelpruivo/flutter_file_picker/pull/1458). Thanks @mauriziopinotti.
- Other minor bugs & fixes.

## 7.0.2
### Desktop (Linux)
File picker extensions for Linux Zenity are case insensitive now
Fixes [#1322](https://github.com/miguelpruivo/flutter_file_picker/issues/1322)
- File picker extensions for Linux Zenity are case insensitive now
- Fixes [#1322](https://github.com/miguelpruivo/flutter_file_picker/issues/1322)

## 7.0.1
### Android
Fixes an issue where sequencial picks could replace the previous file [#1466](https://github.com/miguelpruivo/flutter_file_picker/pull/1466). Thanks @Arsanjuan87.

## 7.0.0
### iOS & Android
Adds possibility to save files on mobile platforms as well [#1452](https://github.com/miguelpruivo/flutter_file_picker/pull/1452). Thanks @Samoy.

## 7.0.0
### Mobile (Android, iOS)
Expand All @@ -26,26 +40,26 @@ on Android devices.

## 6.1.0
### Web
Fixed endless loop on ios safari when canceling picking. ([#1364](https://github.com/miguelpruivo/flutter_file_picker/issues/1364)). Thank you @test0terter0n!
Add `readSequential` flag for web. If `readSequential` is true, order of picked files will be preserved. If flag is false, files will be read parallel. Thank you @test0terter0n!
- Fixed endless loop on ios safari when canceling picking. ([#1364](https://github.com/miguelpruivo/flutter_file_picker/issues/1364)). Thank you @test0terter0n!
- Add `readSequential` flag for web. If `readSequential` is true, order of picked files will be preserved. If flag is false, files will be read parallel. Thank you @test0terter0n!

## 6.0.0
Update minimum Flutter version to 3.7.0.

### iOS
Update minimum iOS version to 11.0.
Fix several warnings in the iOS plugin implementation.
- Update minimum iOS version to 11.0.
- Fix several warnings in the iOS plugin implementation.

## 5.5.0
### iOS
Fix if selecting from gallery multiple files from remote sources (eg GoPro, Drone) imported to the device gallery and uploaded to iCloud they would have the same file name and it shows only one image repeated
Fix returned images are in different onder from the gallery selection
- Fix if selecting from gallery multiple files from remote sources (eg GoPro, Drone) imported to the device gallery and uploaded to iCloud they would have the same file name and it shows only one image repeated
- Fix returned images are in different onder from the gallery selection

## 5.3.4
fix [#1317](https://github.com/miguelpruivo/flutter_file_picker/issues/1317)
Fix [#1317](https://github.com/miguelpruivo/flutter_file_picker/issues/1317)

## 5.3.3
fix [#1312](https://github.com/miguelpruivo/flutter_file_picker/issues/1312)
Fix [#1312](https://github.com/miguelpruivo/flutter_file_picker/issues/1312)

## 5.3.2
### Desktop (Windows)
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ A package that allows you to use the native file explorer to pick single or mult
* Pick files using **custom format** filtering — you can provide a list of file extensions (pdf, svg, zip, etc.)
* Pick files from **cloud files** (GDrive, Dropbox, iCloud)
* Single or multiple file picks
* Supports retrieving as XFile (cross_file) for easy manipulation with other libraries
* Different default type filtering (media, image, video, audio or any)
* Picking directories
* Load file data immediately into memory (`Uint8List`) if needed;
Expand Down Expand Up @@ -128,6 +129,20 @@ if (result != null) {
// User canceled the picker
}
```
### Retrieve all files as XFiles or individually
```dart
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result != null) {
// All files
List<XFile> xFiles = result.xFiles;
// Individually
XFile xFile = result.files.first.xFile;
} else {
// User canceled the picker
}
```
#### Pick and upload a file to Firebase Storage with Flutter Web
```dart
FilePickerResult? result = await FilePicker.platform.pickFiles();
Expand Down
14 changes: 3 additions & 11 deletions lib/src/file_picker_macos.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'dart:ffi';
import 'dart:typed_data';

import 'package:file_picker/file_picker.dart';
Expand Down Expand Up @@ -182,10 +181,7 @@ class FilePickerMacOS extends FilePicker {
return arguments;
}

String escapeDialogTitle(String dialogTitle) => dialogTitle
.replaceAll('\\', '\\\\')
.replaceAll('"', '\\"')
.replaceAll('\n', '\\\n');
String escapeDialogTitle(String dialogTitle) => dialogTitle.replaceAll('\\', '\\\\').replaceAll('"', '\\"').replaceAll('\n', '\\\n');

/// Transforms the result string (stdout) of `osascript` into a [List] of
/// POSIX file paths.
Expand All @@ -194,12 +190,8 @@ class FilePickerMacOS extends FilePicker {
return [];
}

final paths = fileSelectionResult
.trim()
.split(', alias ')
.map((String path) => path.trim())
.where((String path) => path.isNotEmpty)
.toList();
final paths =
fileSelectionResult.trim().split(', alias ').map((String path) => path.trim()).where((String path) => path.isNotEmpty).toList();

if (paths.length == 1 && paths.first.startsWith('file ')) {
// The first token of the first path is "file" in case of the save file
Expand Down
4 changes: 4 additions & 0 deletions lib/src/file_picker_result.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:cross_file/cross_file.dart';
import 'package:file_picker/src/platform_file.dart';
import 'package:flutter/foundation.dart';

Expand Down Expand Up @@ -29,6 +30,9 @@ class FilePickerResult {
/// A `List<String>` containing all names from picked files with its extensions.
List<String?> get names => files.map((file) => file.name).toList();

/// Retrieves a `List<XFile` with all the files as `XFile` objects.
List<XFile> get xFiles => files.map((file) => file.xFile).toList();

@override
bool operator ==(Object other) {
if (identical(this, other)) {
Expand Down
5 changes: 2 additions & 3 deletions lib/src/linux/dialog_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:file_picker/file_picker.dart';
import 'package:file_picker/src/linux/kdialog_handler.dart';
import 'package:file_picker/src/linux/qarma_and_zenity_handler.dart';

import '../utils.dart';
import 'package:file_picker/src/utils.dart';

abstract class DialogHandler {
factory DialogHandler(String pathToExecutable) {
Expand Down Expand Up @@ -46,8 +46,7 @@ abstract class DialogHandler {
static String toCaseInsensitive(String filter) {
return filter
.split("")
.map((e) =>
isAlpha(e) ? "[" + e.toLowerCase() + e.toUpperCase() + "]" : e)
.map((e) => isAlpha(e) ? "[${e.toLowerCase()}${e.toUpperCase()}]" : e)
.join();
}
}
10 changes: 10 additions & 0 deletions lib/src/platform_file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';
// ignore: unnecessary_import
import 'dart:typed_data';

import 'package:cross_file/cross_file.dart';
import 'package:flutter/foundation.dart';

class PlatformFile {
Expand Down Expand Up @@ -72,6 +73,15 @@ class PlatformFile {
/// File extension for this file.
String? get extension => name.split('.').last;

/// Retrieves this as a XFile
XFile get xFile {
if (kIsWeb) {
return XFile.fromData(bytes!, name: name, length: size);
} else {
return XFile(path!, name: name, bytes: bytes, length: size);
}
}

@override
bool operator ==(Object other) {
if (identical(this, other)) {
Expand Down
11 changes: 6 additions & 5 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ description: A package that allows you to use a native file explorer to pick sin
homepage: https://github.com/miguelpruivo/plugins_flutter_file_picker
repository: https://github.com/miguelpruivo/flutter_file_picker
issue_tracker: https://github.com/miguelpruivo/flutter_file_picker/issues
version: 7.0.2
version: 7.1.0

dependencies:
flutter:
sdk: flutter
flutter_web_plugins:
sdk: flutter

flutter_plugin_android_lifecycle: ^2.0.9
plugin_platform_interface: ^2.1.4
flutter_plugin_android_lifecycle: ^2.0.17
plugin_platform_interface: ^2.1.8
ffi: ^2.0.1
path: ^1.8.2
win32: '^5.0.2'
win32: ^5.1.1
cross_file: ^0.3.3+7

dev_dependencies:
lints: ^2.0.1
lints: ^3.0.0
flutter_test:
sdk: flutter

Expand Down
66 changes: 19 additions & 47 deletions test/file_picker_macos_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void main() {
expect(
picker.fileTypeToFileFilter(FileType.media, null),
equals(
'"avi", "flv", "mkv", "mov", "mp4", "mpeg", "webm", "wmv", "bmp", "gif", "jpeg", "jpg", "png"',
'"avi", "flv", "m4v", "mkv", "mov", "mp4", "mpeg", "webm", "wmv", "bmp", "gif", "jpeg", "jpg", "png"',
),
);

Expand All @@ -37,9 +37,7 @@ void main() {
);
});

test(
'should return the file filter when given a list of custom file extensions',
() {
test('should return the file filter when given a list of custom file extensions', () {
final picker = FilePickerMacOS();

// TODO: the first empty file type ("", ) is required in some cases, e.g.
Expand Down Expand Up @@ -119,8 +117,7 @@ void main() {
);

expect(filePaths.length, equals(1));
expect(filePaths[0],
equals('/Volumes/macOS/Users/john/Downloads/config.yml'));
expect(filePaths[0], equals('/Volumes/macOS/Users/john/Downloads/config.yml'));
});

test('should interpret the result of picking two files', () {
Expand All @@ -143,13 +140,10 @@ void main() {
);

expect(filePaths.length, equals(1));
expect(filePaths[0],
equals('/Volumes/macOS/System/iOSSupport/usr/lib/swift'));
expect(filePaths[0], equals('/Volumes/macOS/System/iOSSupport/usr/lib/swift'));
});

test(
'should interpret the result of picking a file from an external hard drive',
() {
test('should interpret the result of picking a file from an external hard drive', () {
final picker = FilePickerMacOS();

final filePaths = picker.resultStringToFilePaths(
Expand All @@ -164,25 +158,20 @@ void main() {
),
);
});
test(
'should interpret the result of picking multiple files from an external hard drive',
() {
test('should interpret the result of picking multiple files from an external hard drive', () {
final picker = FilePickerMacOS();

final filePaths = picker.resultStringToFilePaths(
'alias WD Backup:photos:my screenshot.jpg, alias WD Backup:photos:christmas.png, alias WD Backup:photos:image33.png',
);

expect(filePaths.length, equals(3));
expect(
filePaths[0], equals('/Volumes/WD Backup/photos/my screenshot.jpg'));
expect(filePaths[0], equals('/Volumes/WD Backup/photos/my screenshot.jpg'));
expect(filePaths[1], equals('/Volumes/WD Backup/photos/christmas.png'));
expect(filePaths[2], equals('/Volumes/WD Backup/photos/image33.png'));
});

test(
'should interpret the result of picking a directory from an external hard drive',
() {
test('should interpret the result of picking a directory from an external hard drive', () {
final picker = FilePickerMacOS();

final filePaths = picker.resultStringToFilePaths(
Expand All @@ -196,9 +185,7 @@ void main() {
);
});

test(
'should interpret the result of picking filenames that contain blanks and commas',
() {
test('should interpret the result of picking filenames that contain blanks and commas', () {
final picker = FilePickerMacOS();

final filePaths = picker.resultStringToFilePaths(
Expand Down Expand Up @@ -260,8 +247,7 @@ void main() {

expect(
cliArguments.join(' '),
equals(
'-e choose file name default name "test.out" with prompt "Select output file:"'),
equals('-e choose file name default name "test.out" with prompt "Select output file:"'),
);
});

Expand All @@ -282,9 +268,7 @@ void main() {
);
});

test(
'should generate the arguments for picking a single file with a custom file filter',
() {
test('should generate the arguments for picking a single file with a custom file filter', () {
final picker = FilePickerMacOS();

final cliArguments = picker.generateCommandLineArguments(
Expand All @@ -296,14 +280,11 @@ void main() {

expect(
cliArguments.join(' '),
equals(
'-e choose file of type {"dart", "yml"} with prompt "Select a file:"'),
equals('-e choose file of type {"dart", "yml"} with prompt "Select a file:"'),
);
});

test(
'should generate the arguments for picking multiple files with a custom file filter',
() {
test('should generate the arguments for picking multiple files with a custom file filter', () {
final picker = FilePickerMacOS();

final cliArguments = picker.generateCommandLineArguments(
Expand Down Expand Up @@ -335,9 +316,7 @@ void main() {
);
});

test(
'should generate the arguments for picking a file when an initial directory is given',
() {
test('should generate the arguments for picking a file when an initial directory is given', () {
final picker = FilePickerMacOS();

final cliArguments = picker.generateCommandLineArguments(
Expand All @@ -347,14 +326,11 @@ void main() {

expect(
cliArguments.join(' '),
equals(
'-e choose file default location "/Users/john/Desktop" with prompt "Pick a file:"'),
equals('-e choose file default location "/Users/john/Desktop" with prompt "Pick a file:"'),
);
});

test(
'should generate the arguments for picking a directory when an initial directory is given',
() {
test('should generate the arguments for picking a directory when an initial directory is given', () {
final picker = FilePickerMacOS();

final cliArguments = picker.generateCommandLineArguments(
Expand All @@ -366,14 +342,11 @@ void main() {

expect(
cliArguments.join(' '),
equals(
'-e choose folder default location "/Users/john/workspace" with prompt "Pick directory:"'),
equals('-e choose folder default location "/Users/john/workspace" with prompt "Pick directory:"'),
);
});

test(
'should generate the arguments for saving a file when an initial directory is given',
() {
test('should generate the arguments for saving a file when an initial directory is given', () {
final picker = FilePickerMacOS();

final cliArguments = picker.generateCommandLineArguments(
Expand All @@ -385,8 +358,7 @@ void main() {

expect(
cliArguments.join(' '),
equals(
'-e choose file name default name "output.pdf" default location "/Users/john/Downloads" with prompt "Save as:"'),
equals('-e choose file name default name "output.pdf" default location "/Users/john/Downloads" with prompt "Save as:"'),
);
});
});
Expand Down

0 comments on commit 07afbfa

Please sign in to comment.