From 4271dd824662625ccfa7645a2b2e1fe926be8e2b Mon Sep 17 00:00:00 2001 From: David Skelly Date: Tue, 15 Aug 2023 14:34:53 -0400 Subject: [PATCH 1/5] make zenity file filters case insensitive --- lib/src/linux/qarma_and_zenity_handler.dart | 19 +++++++++++++++---- lib/src/utils.dart | 6 ++++++ test/file_picker_utils_test.dart | 12 ++++++++++++ test/linux/qarma_and_zenity_handler_test.dart | 12 +++++++----- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/lib/src/linux/qarma_and_zenity_handler.dart b/lib/src/linux/qarma_and_zenity_handler.dart index 3089a0d5..b91155bc 100644 --- a/lib/src/linux/qarma_and_zenity_handler.dart +++ b/lib/src/linux/qarma_and_zenity_handler.dart @@ -2,6 +2,8 @@ import 'package:file_picker/file_picker.dart'; import 'package:file_picker/src/linux/dialog_handler.dart'; import 'package:path/path.dart' as p; +import '../utils.dart'; + class QarmaAndZenityHandler implements DialogHandler { @override List generateCommandLineArguments( @@ -48,15 +50,15 @@ class QarmaAndZenityHandler implements DialogHandler { case FileType.any: return ''; case FileType.audio: - return '*.aac *.midi *.mp3 *.ogg *.wav'; + return "Audio Files | ${toCaseInsensitive('*.aac *.midi *.mp3 *.ogg *.wav')}"; case FileType.custom: return '*.${allowedExtensions!.join(' *.')}'; case FileType.image: - return '*.bmp *.gif *.jpeg *.jpg *.png'; + return "Image Files | ${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 | ${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 | ${toCaseInsensitive('*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv')}"; default: throw Exception('unknown file type'); } @@ -72,4 +74,13 @@ class QarmaAndZenityHandler implements DialogHandler { .map((String path) => path.startsWith('/') ? path : '/$path') .toList(); } + + String toCaseInsensitive(String filter) { + return filter + .split("") + .map((e) => + isAlpha(e) ? "[" + e.toLowerCase() + e.toUpperCase() + "]" : e) + .join("") + .toString(); + } } diff --git a/lib/src/utils.dart b/lib/src/utils.dart index be1c83eb..a62ba1b6 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -63,3 +63,9 @@ Future 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); +} diff --git a/test/file_picker_utils_test.dart b/test/file_picker_utils_test.dart index 0eb16856..eb639894 100644 --- a/test/file_picker_utils_test.dart +++ b/test/file_picker_utils_test.dart @@ -143,4 +143,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)); + }); + }); } diff --git a/test/linux/qarma_and_zenity_handler_test.dart b/test/linux/qarma_and_zenity_handler_test.dart index 15784ac3..a9e1093a 100644 --- a/test/linux/qarma_and_zenity_handler_test.dart +++ b/test/linux/qarma_and_zenity_handler_test.dart @@ -1,5 +1,4 @@ @TestOn('linux') - import 'package:file_picker/src/file_picker.dart'; import 'package:file_picker/src/linux/qarma_and_zenity_handler.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -20,24 +19,27 @@ void main() { expect( dialogHandler.fileTypeToFileFilter(FileType.audio, null), - equals('*.aac *.midi *.mp3 *.ogg *.wav'), + equals( + 'Audio Files | *.[aA][aA][cC] *.[mM][iI][dD][iI] *.[mM][pP]3 *.[oO][gG][gG] *.[wW][aA][vV]'), ); expect( dialogHandler.fileTypeToFileFilter(FileType.image, null), - equals('*.bmp *.gif *.jpeg *.jpg *.png'), + equals( + 'Image Files | *.[bB][mM][pP] *.[gG][iI][fF] *.[jJ][pP][eE][gG] *.[jJ][pP][gG] *.[pP][nN][gG]'), ); expect( dialogHandler.fileTypeToFileFilter(FileType.media, null), equals( - '*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv *.bmp *.gif *.jpeg *.jpg *.png', + 'Media Files | *.[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('*.avi *.flv *.mkv *.mov *.mp4 *.mpeg *.webm *.wmv'), + equals( + 'Video Files | *.[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]'), ); }); From 7ac7925c6117653764186e0dc1f893ac6a1454e4 Mon Sep 17 00:00:00 2001 From: David Skelly Date: Tue, 15 Aug 2023 14:50:29 -0400 Subject: [PATCH 2/5] update changelog --- CHANGELOG.md | 5 +++++ pubspec.yaml | 2 +- test/file_picker_utils_test.dart | 1 - 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78d09054..8168d977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 5.3.4 +### Desktop (Linux) +File picker extensions for Linux Zenity are case insensitive now +Fixes [#1322](https://github.com/miguelpruivo/flutter_file_picker/issues/1322) + ## 5.3.3 fix [#1312](https://github.com/miguelpruivo/flutter_file_picker/issues/1312) ## 5.3.2 diff --git a/pubspec.yaml b/pubspec.yaml index 6e66ba03..9bf4bd88 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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: 5.3.3 +version: 5.3.4 dependencies: flutter: diff --git a/test/file_picker_utils_test.dart b/test/file_picker_utils_test.dart index eb639894..79351e0b 100644 --- a/test/file_picker_utils_test.dart +++ b/test/file_picker_utils_test.dart @@ -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'; From 3d0d1f5b4678bea70c40631dcaa4b6a26ec7abd1 Mon Sep 17 00:00:00 2001 From: David Skelly Date: Tue, 15 Aug 2023 15:42:21 -0400 Subject: [PATCH 3/5] remove some redundancy --- lib/src/linux/qarma_and_zenity_handler.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/linux/qarma_and_zenity_handler.dart b/lib/src/linux/qarma_and_zenity_handler.dart index b91155bc..34c07554 100644 --- a/lib/src/linux/qarma_and_zenity_handler.dart +++ b/lib/src/linux/qarma_and_zenity_handler.dart @@ -80,7 +80,6 @@ class QarmaAndZenityHandler implements DialogHandler { .split("") .map((e) => isAlpha(e) ? "[" + e.toLowerCase() + e.toUpperCase() + "]" : e) - .join("") - .toString(); + .join(); } } From c4bfaec42921a24b771cfcc1f58b26d33e8700c5 Mon Sep 17 00:00:00 2001 From: David Skelly Date: Fri, 15 Sep 2023 15:31:23 -0400 Subject: [PATCH 4/5] make custom filters case insensitive too --- lib/src/linux/qarma_and_zenity_handler.dart | 2 +- test/linux/qarma_and_zenity_handler_test.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/linux/qarma_and_zenity_handler.dart b/lib/src/linux/qarma_and_zenity_handler.dart index 34c07554..7b203438 100644 --- a/lib/src/linux/qarma_and_zenity_handler.dart +++ b/lib/src/linux/qarma_and_zenity_handler.dart @@ -52,7 +52,7 @@ class QarmaAndZenityHandler implements DialogHandler { case FileType.audio: return "Audio Files | ${toCaseInsensitive('*.aac *.midi *.mp3 *.ogg *.wav')}"; case FileType.custom: - return '*.${allowedExtensions!.join(' *.')}'; + return "Custom Files | ${toCaseInsensitive('*.${allowedExtensions!.join(' *.')}')}"; case FileType.image: return "Image Files | ${toCaseInsensitive('*.bmp *.gif *.jpeg *.jpg *.png')}"; case FileType.media: diff --git a/test/linux/qarma_and_zenity_handler_test.dart b/test/linux/qarma_and_zenity_handler_test.dart index a9e1093a..59d3bc01 100644 --- a/test/linux/qarma_and_zenity_handler_test.dart +++ b/test/linux/qarma_and_zenity_handler_test.dart @@ -48,12 +48,12 @@ void main() { expect( dialogHandler.fileTypeToFileFilter(FileType.custom, ['dart']), - equals('*.dart'), + equals('Custom Files | *.[dD][aA][rR][tT]'), ); expect( dialogHandler.fileTypeToFileFilter(FileType.custom, ['dart', 'html']), - equals('*.dart *.html'), + equals('Custom Files | *.[dD][aA][rR][tT] *.[hH][tT][mM][lL]'), ); }); }); From d5aae24fce96c71588ea0b7b4e54a3afe196db61 Mon Sep 17 00:00:00 2001 From: David Skelly Date: Mon, 18 Sep 2023 12:41:04 -0400 Subject: [PATCH 5/5] make kdialog case insensitive as well --- lib/src/linux/dialog_handler.dart | 10 ++++++++++ lib/src/linux/kdialog_handler.dart | 10 +++++----- lib/src/linux/qarma_and_zenity_handler.dart | 20 +++++--------------- test/linux/kdialog_handler_test.dart | 15 ++++++++------- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/lib/src/linux/dialog_handler.dart b/lib/src/linux/dialog_handler.dart index 82e3a5fa..6826447e 100644 --- a/lib/src/linux/dialog_handler.dart +++ b/lib/src/linux/dialog_handler.dart @@ -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(); @@ -40,4 +42,12 @@ abstract class DialogHandler { /// Converts the result string (stdout) of `qarma`, `zenity` or `kdialog` /// into a [List] of file paths. List resultStringToFilePaths(String fileSelectionResult); + + static String toCaseInsensitive(String filter) { + return filter + .split("") + .map((e) => + isAlpha(e) ? "[" + e.toLowerCase() + e.toUpperCase() + "]" : e) + .join(); + } } diff --git a/lib/src/linux/kdialog_handler.dart b/lib/src/linux/kdialog_handler.dart index 6b94f553..8d37c93f 100644 --- a/lib/src/linux/kdialog_handler.dart +++ b/lib/src/linux/kdialog_handler.dart @@ -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'); } diff --git a/lib/src/linux/qarma_and_zenity_handler.dart b/lib/src/linux/qarma_and_zenity_handler.dart index 7b203438..03bcb736 100644 --- a/lib/src/linux/qarma_and_zenity_handler.dart +++ b/lib/src/linux/qarma_and_zenity_handler.dart @@ -2,8 +2,6 @@ import 'package:file_picker/file_picker.dart'; import 'package:file_picker/src/linux/dialog_handler.dart'; import 'package:path/path.dart' as p; -import '../utils.dart'; - class QarmaAndZenityHandler implements DialogHandler { @override List generateCommandLineArguments( @@ -50,15 +48,15 @@ class QarmaAndZenityHandler implements DialogHandler { case FileType.any: return ''; case FileType.audio: - return "Audio Files | ${toCaseInsensitive('*.aac *.midi *.mp3 *.ogg *.wav')}"; + return "Audio Files | ${DialogHandler.toCaseInsensitive('*.aac *.midi *.mp3 *.ogg *.wav')}"; case FileType.custom: - return "Custom Files | ${toCaseInsensitive('*.${allowedExtensions!.join(' *.')}')}"; + return "Custom Files | ${DialogHandler.toCaseInsensitive('*.${allowedExtensions!.join(' *.')}')}"; case FileType.image: - return "Image Files | ${toCaseInsensitive('*.bmp *.gif *.jpeg *.jpg *.png')}"; + return "Image Files | ${DialogHandler.toCaseInsensitive('*.bmp *.gif *.jpeg *.jpg *.png')}"; case FileType.media: - return "Media Files | ${toCaseInsensitive('*.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 "Video Files | ${toCaseInsensitive('*.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'); } @@ -74,12 +72,4 @@ class QarmaAndZenityHandler implements DialogHandler { .map((String path) => path.startsWith('/') ? path : '/$path') .toList(); } - - String toCaseInsensitive(String filter) { - return filter - .split("") - .map((e) => - isAlpha(e) ? "[" + e.toLowerCase() + e.toUpperCase() + "]" : e) - .join(); - } } diff --git a/test/linux/kdialog_handler_test.dart b/test/linux/kdialog_handler_test.dart index 1e724780..77f98903 100644 --- a/test/linux/kdialog_handler_test.dart +++ b/test/linux/kdialog_handler_test.dart @@ -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'; @@ -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])'), ); }); @@ -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])'), ); }); });