Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Samoy authored Mar 20, 2024
2 parents 21004d0 + e777abe commit f28bde1
Show file tree
Hide file tree
Showing 14 changed files with 103 additions and 65 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@

## 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)

## 7.0.0
### Mobile (Android, iOS)
Save file to mobile platforms with `bytes`.

## 6.2.1
### Desktop (Windows)
The `initialDirectory` parameter of `getDirectoryPath()` now works ([#970](https://github.com/miguelpruivo/flutter_file_picker/issues/970)).

## 6.2.0
### Android
Add ability to compress images on android by specifying a compression quality value ([#735]
Expand Down Expand Up @@ -30,10 +40,13 @@ Fix several warnings in the iOS plugin implementation.
### 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

## 5.3.4
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)

## 5.3.2
### Desktop (Windows)
Bumps the dependency `win32` to 5.0.2 ([#1281](https://github.com/miguelpruivo/flutter_file_picker/pull/1281)). Thank you @frg2089!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcelable;
import android.os.Message;
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.util.Log;

Expand All @@ -24,6 +24,7 @@
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;

import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodChannel;
Expand Down Expand Up @@ -118,7 +119,6 @@ public boolean onActivityResult(final int requestCode, final int resultCode, fin
}

if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) {

this.dispatchEventStatus(true);

new Thread(new Runnable() {
Expand All @@ -127,16 +127,14 @@ public void run() {
if (data != null) {
final ArrayList<FileInfo> files = new ArrayList<>();


if (data.getClipData() != null) {
final int count = data.getClipData().getItemCount();
int currentItem = 0;
while (currentItem < count) {
Uri currentUri = data.getClipData().getItemAt(currentItem).getUri();

if(type=="image/*" && compressionQuality>0) {

currentUri=FileUtils.compressImage(currentUri,compressionQuality,activity.getApplicationContext());
if (Objects.equals(type, "image/*") && compressionQuality > 0) {
currentUri = FileUtils.compressImage(currentUri, compressionQuality, activity.getApplicationContext());
}
final FileInfo file = FileUtils.openFileStream(FilePickerDelegate.this.activity, currentUri, loadDataToMemory);
if(file != null) {
Expand All @@ -150,8 +148,8 @@ public void run() {
} else if (data.getData() != null) {
Uri uri = data.getData();

if(type=="image/*" && compressionQuality>0) {
uri=FileUtils.compressImage(uri,compressionQuality,activity.getApplicationContext());
if (Objects.equals(type, "image/*") && compressionQuality > 0) {
uri = FileUtils.compressImage(uri, compressionQuality, activity.getApplicationContext());
}

if (type.equals("dir") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Expand Down Expand Up @@ -265,7 +263,6 @@ private ArrayList<Parcelable> getSelectedItems(Bundle bundle){
return bundle.getParcelableArrayList("selectedItems");
}

@SuppressWarnings("deprecation")
private void startFileExplorer() {
final Intent intent;

Expand Down Expand Up @@ -300,7 +297,7 @@ private void startFileExplorer() {
}

if (intent.resolveActivity(this.activity.getPackageManager()) != null) {
this.activity.startActivityForResult(intent, REQUEST_CODE);
this.activity.startActivityForResult(Intent.createChooser(intent, null), REQUEST_CODE);
} else {
Log.e(TAG, "Can't find a valid activity to handle the request. Make sure you've a file explorer installed.");
finishWithError("invalid_format_type", "Can't handle the provided file type.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,28 +92,27 @@ public static String getFileName(Uri uri, final Context context) {
}


public static Uri compressImage(Uri originalImageUri, int compressionQuality,Context context) {
String originalImagePath = getRealPathFromURI(context,originalImageUri);
Uri compressedUri=null;
File compressedFile=null;
try {
compressedFile=createImageFile();
Bitmap originalBitmap = BitmapFactory.decodeFile(originalImagePath);
String file_path = Environment.getExternalStorageDirectory().getAbsolutePath() +
"/FilePicker";
public static Uri compressImage(Uri originalImageUri, int compressionQuality, Context context) {
Uri compressedUri;
try (InputStream imageStream = context.getContentResolver().openInputStream(originalImageUri)) {
File compressedFile = createImageFile();
Bitmap originalBitmap = BitmapFactory.decodeStream(imageStream);
// Compress and save the image
FileOutputStream fos = new FileOutputStream(compressedFile);
originalBitmap.compress(Bitmap.CompressFormat.JPEG, compressionQuality, fos);
fos.flush();
fos.close();
compressedUri=Uri.fromFile(compressedFile);
}catch (FileNotFoundException e) {
compressedUri = Uri.fromFile(compressedFile);
}
catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
}
catch (IOException e) {
throw new RuntimeException(e);
}
return compressedUri;
}

private static File createImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
Expand Down Expand Up @@ -297,7 +296,7 @@ public static FileInfo openFileStream(final Context context, final Uri uri, bool
FileOutputStream fos = null;
final FileInfo.Builder fileInfo = new FileInfo.Builder();
final String fileName = FileUtils.getFileName(uri, context);
final String path = context.getCacheDir().getAbsolutePath() + "/file_picker/" + (fileName != null ? fileName : System.currentTimeMillis());
final String path = context.getCacheDir().getAbsolutePath() + "/file_picker/"+System.currentTimeMillis() +"/"+ (fileName != null ? fileName : "unamed");

final File file = new File(path);

Expand Down
4 changes: 2 additions & 2 deletions example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
compileSdkVersion 33
compileSdk 33

lintOptions {
disable 'InvalidPackage'
Expand All @@ -24,7 +24,7 @@ android {
defaultConfig {
applicationId "com.mr.flutter.plugin.filepicker.example"
minSdkVersion flutter.minSdkVersion
targetSdkVersion 33
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down
2 changes: 1 addition & 1 deletion lib/src/file_picker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ abstract class FilePicker extends PlatformInterface {
/// window). This parameter works only on Windows desktop.
///
/// [initialDirectory] can be optionally set to an absolute path to specify
/// where the dialog should open. Only supported on Linux and macOS.
/// where the dialog should open. Only supported on Linux, macOS, and Windows.
///
/// Returns a [Future<String?>] which resolves to the absolute path of the selected directory,
/// if the user selected a directory. Returns `null` if the user aborted the dialog or if the
Expand Down
10 changes: 10 additions & 0 deletions lib/src/linux/dialog_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ 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';

abstract class DialogHandler {
factory DialogHandler(String pathToExecutable) {
pathToExecutable = pathToExecutable.toLowerCase();
Expand Down Expand Up @@ -40,4 +42,12 @@ abstract class DialogHandler {
/// Converts the result string (stdout) of `qarma`, `zenity` or `kdialog`
/// into a [List<String>] of file paths.
List<String> resultStringToFilePaths(String fileSelectionResult);

static String toCaseInsensitive(String filter) {
return filter
.split("")
.map((e) =>
isAlpha(e) ? "[" + e.toLowerCase() + e.toUpperCase() + "]" : e)
.join();
}
}
10 changes: 5 additions & 5 deletions lib/src/linux/kdialog_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ class KDialogHandler implements DialogHandler {
case FileType.any:
return '';
case FileType.audio:
return 'Audio File (*.aac *.midi *.mp3 *.ogg *.wav)';
return 'Audio File (${DialogHandler.toCaseInsensitive("*.aac *.midi *.mp3 *.ogg *.wav")})';
case FileType.custom:
return '${allowedExtensions!.map((ext) => ext.toUpperCase()).join(' File, ')} File (*.${allowedExtensions.join(' *.')})';
return '${allowedExtensions!.map((ext) => ext.toUpperCase()).join(' File, ')} File (${DialogHandler.toCaseInsensitive("*.${allowedExtensions.join(' *.')}")})';
case FileType.image:
return 'Image File (*.bmp *.gif *.jpeg *.jpg *.png)';
return 'Image File (${DialogHandler.toCaseInsensitive("*.bmp *.gif *.jpeg *.jpg *.png")})';
case FileType.media:
return 'Media File (*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv *.bmp *.gif *.jpeg *.jpg *.png)';
return 'Media File (${DialogHandler.toCaseInsensitive("*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv *.bmp *.gif *.jpeg *.jpg *.png")})';
case FileType.video:
return 'Video File (*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv)';
return 'Video File (${DialogHandler.toCaseInsensitive("*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv")})';
default:
throw Exception('unknown file type');
}
Expand Down
10 changes: 5 additions & 5 deletions lib/src/linux/qarma_and_zenity_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ class QarmaAndZenityHandler implements DialogHandler {
case FileType.any:
return '';
case FileType.audio:
return '*.aac *.midi *.mp3 *.ogg *.wav';
return "Audio Files | ${DialogHandler.toCaseInsensitive('*.aac *.midi *.mp3 *.ogg *.wav')}";
case FileType.custom:
return '*.${allowedExtensions!.join(' *.')}';
return "Custom Files | ${DialogHandler.toCaseInsensitive('*.${allowedExtensions!.join(' *.')}')}";
case FileType.image:
return '*.bmp *.gif *.jpeg *.jpg *.png';
return "Image Files | ${DialogHandler.toCaseInsensitive('*.bmp *.gif *.jpeg *.jpg *.png')}";
case FileType.media:
return '*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv *.bmp *.gif *.jpeg *.jpg *.png';
return "Media Files | ${DialogHandler.toCaseInsensitive('*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv *.bmp *.gif *.jpeg *.jpg *.png')}";
case FileType.video:
return '*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv';
return "Video Files | ${DialogHandler.toCaseInsensitive('*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv')}";
default:
throw Exception('unknown file type');
}
Expand Down
6 changes: 6 additions & 0 deletions lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,9 @@ Future<String> isExecutableOnPath(String executable) async {
}
return path;
}

bool isAlpha(String x) {
int codeUnit = x.codeUnitAt(0);
return 'a'.codeUnitAt(0) <= codeUnit && codeUnit <= 'z'.codeUnitAt(0) ||
'A'.codeUnitAt(0) <= codeUnit && codeUnit <= 'Z'.codeUnitAt(0);
}
25 changes: 12 additions & 13 deletions lib/src/windows/file_picker_windows.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,19 +116,18 @@ class FilePickerWindows extends FilePicker {
if (!SUCCEEDED(hr)) throw WindowsException(hr);
free(title);

// TODO: figure out how to set the initial directory via SetDefaultFolder / SetFolder
// if (initialDirectory != null) {
// final folder = TEXT(initialDirectory);
// final riid = calloc<COMObject>();
// final item = IShellItem(riid);
// final location = item.ptr;
// SHCreateItemFromParsingName(folder, nullptr, riid.cast(), item.ptr.cast());
// hr = fileDialog.AddPlace(item.ptr, FDAP.FDAP_TOP);
// if (!SUCCEEDED(hr)) throw WindowsException(hr);
// hr = fileDialog.SetFolder(location);
// if (!SUCCEEDED(hr)) throw WindowsException(hr);
// free(folder);
// }
if (initialDirectory != null) {
final folder = TEXT(initialDirectory);
final riid = convertToIID(IID_IShellItem);
final ppv = calloc<Pointer>();
hr = SHCreateItemFromParsingName(folder, nullptr, riid, ppv);
final item = IShellItem(ppv.cast());
free(riid);
free(folder);
if (!SUCCEEDED(hr)) throw WindowsException(hr);
hr = fileDialog.setFolder(item.ptr.cast<Pointer<COMObject>>().value);
if (!SUCCEEDED(hr)) throw WindowsException(hr);
}

final hwndOwner = lockParentWindow ? GetForegroundWindow() : NULL;
hr = fileDialog.show(hwndOwner);
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ 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.0
version: 7.0.2

dependencies:
flutter:
Expand Down
13 changes: 12 additions & 1 deletion test/file_picker_utils_test.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
@TestOn('linux || mac-os')

import 'dart:io';
import 'package:file_picker/src/utils.dart';
import 'package:flutter_test/flutter_test.dart';
Expand Down Expand Up @@ -143,4 +142,16 @@ void main() {
);
});
});

group('isAlpha()', () {
test('should identify alpha chars', () async {
expect(isAlpha('a'), equals(true));
expect(isAlpha('A'), equals(true));
expect(isAlpha('z'), equals(true));
expect(isAlpha('Z'), equals(true));
expect(isAlpha('.'), equals(false));
expect(isAlpha('*'), equals(false));
expect(isAlpha(' '), equals(false));
});
});
}
15 changes: 8 additions & 7 deletions test/linux/kdialog_handler_test.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
@TestOn('linux')

import 'package:file_picker/src/file_picker.dart';
import 'package:file_picker/src/linux/kdialog_handler.dart';
import 'package:flutter_test/flutter_test.dart';
Expand All @@ -21,25 +20,27 @@ void main() {

expect(
dialogHandler.fileTypeToFileFilter(FileType.audio, null),
equals('Audio File (*.aac *.midi *.mp3 *.ogg *.wav)'),
equals(
'Audio File (*.[aA][aA][cC] *.[mM][iI][dD][iI] *.[mM][pP]3 *.[oO][gG][gG] *.[wW][aA][vV])'),
);

expect(
dialogHandler.fileTypeToFileFilter(FileType.image, null),
equals('Image File (*.bmp *.gif *.jpeg *.jpg *.png)'),
equals(
'Image File (*.[bB][mM][pP] *.[gG][iI][fF] *.[jJ][pP][eE][gG] *.[jJ][pP][gG] *.[pP][nN][gG])'),
);

expect(
dialogHandler.fileTypeToFileFilter(FileType.media, null),
equals(
'Media File (*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv *.bmp *.gif *.jpeg *.jpg *.png)',
'Media File (*.[aA][vV][iI] *.[fF][lL][vV] *.[mM][kK][vV] *.[mM][oO][vV] *.[mM][pP]4 *.[mM][pP][eE][gG] *.[wW][eE][bB][mM] *.[wW][mM][vV] *.[bB][mM][pP] *.[gG][iI][fF] *.[jJ][pP][eE][gG] *.[jJ][pP][gG] *.[pP][nN][gG])',
),
);

expect(
dialogHandler.fileTypeToFileFilter(FileType.video, null),
equals(
'Video File (*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv)'),
'Video File (*.[aA][vV][iI] *.[fF][lL][vV] *.[mM][kK][vV] *.[mM][oO][vV] *.[mM][pP]4 *.[mM][pP][eE][gG] *.[wW][eE][bB][mM] *.[wW][mM][vV])'),
);
});

Expand All @@ -48,12 +49,12 @@ void main() {

expect(
dialogHandler.fileTypeToFileFilter(FileType.custom, ['dart']),
equals('DART File (*.dart)'),
equals('DART File (*.[dD][aA][rR][tT])'),
);

expect(
dialogHandler.fileTypeToFileFilter(FileType.custom, ['dart', 'html']),
equals('DART File, HTML File (*.dart *.html)'),
equals('DART File, HTML File (*.[dD][aA][rR][tT] *.[hH][tT][mM][lL])'),
);
});
});
Expand Down
Loading

0 comments on commit f28bde1

Please sign in to comment.