flutter_file_picker/lib/src/file_picker_linux.dart

129 lines
3.7 KiB
Dart

import 'dart:async';
import 'package:file_picker/src/file_picker.dart';
import 'package:file_picker/src/file_picker_result.dart';
import 'package:file_picker/src/platform_file.dart';
import 'package:file_picker/src/utils.dart';
class FilePickerLinux extends FilePicker {
@override
Future<FilePickerResult?> pickFiles({
String? dialogTitle,
FileType type = FileType.any,
List<String>? allowedExtensions,
Function(FilePickerStatus)? onFileLoading,
bool allowCompression = true,
bool allowMultiple = false,
bool withData = false,
bool withReadStream = false,
}) async {
final String executable = await _getPathToExecutable();
final String fileFilter = fileTypeToFileFilter(
type,
allowedExtensions,
);
final List<String> arguments = generateCommandLineArguments(
dialogTitle ?? defaultDialogTitle,
fileFilter: fileFilter,
multipleFiles: allowMultiple,
pickDirectory: false,
);
final String? fileSelectionResult = await runExecutableWithArguments(
executable,
arguments,
);
if (fileSelectionResult == null) {
return null;
}
final List<String> filePaths = resultStringToFilePaths(
fileSelectionResult,
);
final List<PlatformFile> platformFiles = await filePathsToPlatformFiles(
filePaths,
withReadStream,
withData,
);
return FilePickerResult(platformFiles);
}
@override
Future<String?> getDirectoryPath({
String? dialogTitle,
}) async {
final executable = await _getPathToExecutable();
final arguments = generateCommandLineArguments(
dialogTitle ?? defaultDialogTitle,
pickDirectory: true,
);
return await runExecutableWithArguments(executable, arguments);
}
/// Returns the path to the executables `qarma` or `zenity` as a [String].
///
/// On Linux, the CLI tools `qarma` or `zenity` can be used to open a native
/// file picker dialog. It seems as if all Linux distributions have at least
/// one of these two tools pre-installed (on Ubuntu `zenity` is pre-installed).
/// The future returns an error, if neither of both executables was found on
/// the path.
Future<String> _getPathToExecutable() async {
try {
return await isExecutableOnPath('qarma');
} on Exception {
return await isExecutableOnPath('zenity');
}
}
String fileTypeToFileFilter(FileType type, List<String>? allowedExtensions) {
switch (type) {
case FileType.any:
return '*.*';
case FileType.audio:
return '*.mp3 *.wav *.midi *.ogg *.aac';
case FileType.custom:
return '*.' + allowedExtensions!.join(' *.');
case FileType.image:
return '*.bmp *.gif *.jpg *.jpeg *.png';
case FileType.media:
return '*.webm *.mpeg *.mkv *.mp4 *.avi *.mov *.flv *.jpg *.jpeg *.bmp *.gif *.png';
case FileType.video:
return '*.webm *.mpeg *.mkv *.mp4 *.avi *.mov *.flv';
default:
throw Exception('unknown file type');
}
}
List<String> generateCommandLineArguments(
String dialogTitle, {
String fileFilter = '',
bool multipleFiles = false,
bool pickDirectory = false,
}) {
final arguments = ['--file-selection', '--title', dialogTitle];
if (fileFilter.isNotEmpty) {
arguments.add('--file-filter=$fileFilter');
}
if (multipleFiles) {
arguments.add('--multiple');
}
if (pickDirectory) {
arguments.add('--directory');
}
return arguments;
}
/// Transforms the result string (stdout) of `qarma` / `zenity` into a [List]
/// of file paths.
List<String> resultStringToFilePaths(String fileSelectionResult) {
if (fileSelectionResult.trim().isEmpty) {
return [];
}
return fileSelectionResult.split('|');
}
}