fix: Récupérer l'opération active depuis la table operations

- Corrige l'erreur SQL 'Unknown column fk_operation in users'
- L'opération active est récupérée depuis operations.chk_active = 1
- Jointure avec users pour filtrer par entité de l'admin créateur
- Query: SELECT o.id FROM operations o INNER JOIN users u ON u.fk_entite = o.fk_entite WHERE u.id = ? AND o.chk_active = 1
This commit is contained in:
2026-01-26 16:57:08 +01:00
parent c24a3afe6a
commit 0687900564
3040 changed files with 77204 additions and 1578 deletions

View File

@@ -1 +0,0 @@
/home/pierre/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.1+2/

View File

@@ -0,0 +1,7 @@
# Below is a list of people and organizations that have contributed
# to the Flutter project. Names should be added to the list like so:
#
# Name/Organization <email address>
Google Inc.
Alexandre Zollinger Chohfi <alzollin@microsoft.com>

View File

@@ -0,0 +1,17 @@
## 0.2.1+2
* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4.
* Fixes `getMedia` mime types.
## 0.2.1+1
* Adds pub topics to package metadata.
* Updates minimum supported SDK version to Flutter 3.7/Dart 2.19.
## 0.2.1
* Adds `getMedia` method.
## 0.2.0
* Implements initial Linux support.

View File

@@ -0,0 +1,25 @@
Copyright 2013 The Flutter Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,27 @@
# image\_picker\_linux
A Linux implementation of [`image_picker`][1].
## Limitations
`ImageSource.camera` is not supported unless a `cameraDelegate` is set.
### pickImage()
The arguments `maxWidth`, `maxHeight`, and `imageQuality` are not currently supported.
### pickVideo()
The argument `maxDuration` is not currently supported.
## Usage
### Import the package
This package is [endorsed][2], which means you can simply use `file_selector`
normally. This package will be automatically included in your app when you do,
so you do not need to add it to your `pubspec.yaml`.
However, if you `import` this package to use any of its APIs directly, you
should add it to your `pubspec.yaml` as usual.
[1]: https://pub.dev/packages/image_picker
[2]: https://flutter.dev/to/endorsed-federated-plugin

View File

@@ -0,0 +1,9 @@
# Platform Implementation Test App
This is a test app for manual testing and automated integration testing
of this platform implementation. It is not intended to demonstrate actual use of
this package, since the intent is that plugin clients use the app-facing
package.
Unless you are making changes to this implementation package, this example is
very unlikely to be relevant.

View File

@@ -0,0 +1,516 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
import 'package:mime/mime.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Image Picker Demo',
home: MyHomePage(title: 'Image Picker Example'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, this.title});
final String? title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<XFile>? _mediaFileList;
// This must be called from within a setState() callback
void _setImageFileListFromFile(XFile? value) {
_mediaFileList = value == null ? null : <XFile>[value];
}
dynamic _pickImageError;
bool _isVideo = false;
VideoPlayerController? _controller;
VideoPlayerController? _toBeDisposed;
String? _retrieveDataError;
final ImagePickerPlatform _picker = ImagePickerPlatform.instance;
final TextEditingController maxWidthController = TextEditingController();
final TextEditingController maxHeightController = TextEditingController();
final TextEditingController qualityController = TextEditingController();
Future<void> _playVideo(XFile? file) async {
if (file != null && mounted) {
await _disposeVideoController();
final VideoPlayerController controller =
VideoPlayerController.file(File(file.path));
_controller = controller;
await controller.setVolume(1.0);
await controller.initialize();
await controller.setLooping(true);
await controller.play();
setState(() {});
}
}
Future<void> _onImageButtonPressed(
ImageSource source, {
required BuildContext context,
bool isMultiImage = false,
bool isMedia = false,
}) async {
if (_controller != null) {
await _controller!.setVolume(0.0);
}
if (context.mounted) {
if (_isVideo) {
final XFile? file = await _picker.getVideo(
source: source, maxDuration: const Duration(seconds: 10));
await _playVideo(file);
} else if (isMultiImage) {
await _displayPickImageDialog(context,
(double? maxWidth, double? maxHeight, int? quality) async {
try {
final List<XFile> pickedFileList = isMedia
? await _picker.getMedia(
options: MediaOptions(
allowMultiple: isMultiImage,
imageOptions: ImageOptions(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
)),
)
: await _picker.getMultiImageWithOptions(
options: MultiImagePickerOptions(
imageOptions: ImageOptions(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
),
),
);
setState(() {
_mediaFileList = pickedFileList;
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
});
} else if (isMedia) {
await _displayPickImageDialog(context,
(double? maxWidth, double? maxHeight, int? quality) async {
try {
final List<XFile> pickedFileList = <XFile>[];
final XFile? media = _firstOrNull(await _picker.getMedia(
options: MediaOptions(
allowMultiple: isMultiImage,
imageOptions: ImageOptions(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
)),
));
if (media != null) {
pickedFileList.add(media);
setState(() {
_mediaFileList = pickedFileList;
});
}
} catch (e) {
setState(() => _pickImageError = e);
}
});
} else {
await _displayPickImageDialog(context,
(double? maxWidth, double? maxHeight, int? quality) async {
try {
final XFile? pickedFile = await _picker.getImageFromSource(
source: source,
options: ImagePickerOptions(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
),
);
setState(() {
_setImageFileListFromFile(pickedFile);
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
});
}
}
}
@override
void deactivate() {
if (_controller != null) {
_controller!.setVolume(0.0);
_controller!.pause();
}
super.deactivate();
}
@override
void dispose() {
_disposeVideoController();
maxWidthController.dispose();
maxHeightController.dispose();
qualityController.dispose();
super.dispose();
}
Future<void> _disposeVideoController() async {
if (_toBeDisposed != null) {
await _toBeDisposed!.dispose();
}
_toBeDisposed = _controller;
_controller = null;
}
Widget _previewVideo() {
final Text? retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_controller == null) {
return const Text(
'You have not yet picked a video',
textAlign: TextAlign.center,
);
}
return Padding(
padding: const EdgeInsets.all(10.0),
child: AspectRatioVideo(_controller),
);
}
Widget _previewImages() {
final Text? retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_mediaFileList != null) {
return Semantics(
label: 'image_picker_example_picked_images',
child: ListView.builder(
key: UniqueKey(),
itemBuilder: (BuildContext context, int index) {
final String? mime = lookupMimeType(_mediaFileList![index].path);
return Semantics(
label: 'image_picker_example_picked_image',
child: mime == null || mime.startsWith('image/')
? Image.file(
File(_mediaFileList![index].path),
errorBuilder: (BuildContext context, Object error,
StackTrace? stackTrace) {
return const Center(
child: Text('This image type is not supported'));
},
)
: _buildInlineVideoPlayer(index),
);
},
itemCount: _mediaFileList!.length,
),
);
} else if (_pickImageError != null) {
return Text(
'Pick image error: $_pickImageError',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
Widget _buildInlineVideoPlayer(int index) {
final VideoPlayerController controller =
VideoPlayerController.file(File(_mediaFileList![index].path));
const double volume = 1.0;
controller.setVolume(volume);
controller.initialize();
controller.setLooping(true);
controller.play();
return Center(child: AspectRatioVideo(controller));
}
Widget _handlePreview() {
if (_isVideo) {
return _previewVideo();
} else {
return _previewImages();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title!),
),
body: Center(
child: _handlePreview(),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Semantics(
label: 'image_picker_example_from_gallery',
child: FloatingActionButton(
key: const Key('image_picker_example_from_gallery'),
onPressed: () {
_isVideo = false;
_onImageButtonPressed(ImageSource.gallery, context: context);
},
heroTag: 'image0',
tooltip: 'Pick Image from gallery',
child: const Icon(Icons.photo),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
_isVideo = false;
_onImageButtonPressed(
ImageSource.gallery,
context: context,
isMultiImage: true,
isMedia: true,
);
},
heroTag: 'multipleMedia',
tooltip: 'Pick Multiple Media from gallery',
child: const Icon(Icons.photo_library),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
_isVideo = false;
_onImageButtonPressed(
ImageSource.gallery,
context: context,
isMedia: true,
);
},
heroTag: 'media',
tooltip: 'Pick Single Media from gallery',
child: const Icon(Icons.photo_library),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
_isVideo = false;
_onImageButtonPressed(
ImageSource.gallery,
context: context,
isMultiImage: true,
);
},
heroTag: 'image1',
tooltip: 'Pick Multiple Image from gallery',
child: const Icon(Icons.photo_library),
),
),
if (_picker.supportsImageSource(ImageSource.camera))
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
_isVideo = false;
_onImageButtonPressed(ImageSource.camera, context: context);
},
heroTag: 'image2',
tooltip: 'Take a Photo',
child: const Icon(Icons.camera_alt),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
_isVideo = true;
_onImageButtonPressed(ImageSource.gallery, context: context);
},
heroTag: 'video0',
tooltip: 'Pick Video from gallery',
child: const Icon(Icons.video_library),
),
),
if (_picker.supportsImageSource(ImageSource.camera))
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
_isVideo = true;
_onImageButtonPressed(ImageSource.camera, context: context);
},
heroTag: 'video1',
tooltip: 'Take a Video',
child: const Icon(Icons.videocam),
),
),
],
),
);
}
Text? _getRetrieveErrorWidget() {
if (_retrieveDataError != null) {
final Text result = Text(_retrieveDataError!);
_retrieveDataError = null;
return result;
}
return null;
}
Future<void> _displayPickImageDialog(
BuildContext context, OnPickImageCallback onPick) async {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Add optional parameters'),
content: Column(
children: <Widget>[
TextField(
controller: maxWidthController,
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
decoration: const InputDecoration(
hintText: 'Enter maxWidth if desired'),
),
TextField(
controller: maxHeightController,
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
decoration: const InputDecoration(
hintText: 'Enter maxHeight if desired'),
),
TextField(
controller: qualityController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
hintText: 'Enter quality if desired'),
),
],
),
actions: <Widget>[
TextButton(
child: const Text('CANCEL'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('PICK'),
onPressed: () {
final double? width = maxWidthController.text.isNotEmpty
? double.parse(maxWidthController.text)
: null;
final double? height = maxHeightController.text.isNotEmpty
? double.parse(maxHeightController.text)
: null;
final int? quality = qualityController.text.isNotEmpty
? int.parse(qualityController.text)
: null;
onPick(width, height, quality);
Navigator.of(context).pop();
}),
],
);
});
}
}
typedef OnPickImageCallback = void Function(
double? maxWidth, double? maxHeight, int? quality);
class AspectRatioVideo extends StatefulWidget {
const AspectRatioVideo(this.controller, {super.key});
final VideoPlayerController? controller;
@override
AspectRatioVideoState createState() => AspectRatioVideoState();
}
class AspectRatioVideoState extends State<AspectRatioVideo> {
VideoPlayerController? get controller => widget.controller;
bool initialized = false;
void _onVideoControllerUpdate() {
if (!mounted) {
return;
}
if (initialized != controller!.value.isInitialized) {
initialized = controller!.value.isInitialized;
setState(() {});
}
}
@override
void initState() {
super.initState();
controller!.addListener(_onVideoControllerUpdate);
}
@override
void dispose() {
controller!.removeListener(_onVideoControllerUpdate);
super.dispose();
}
@override
Widget build(BuildContext context) {
if (initialized) {
return Center(
child: AspectRatio(
aspectRatio: controller!.value.aspectRatio,
child: VideoPlayer(controller!),
),
);
} else {
return Container();
}
}
}
T? _firstOrNull<T>(List<T> list) {
return list.isEmpty ? null : list.first;
}

View File

@@ -0,0 +1,138 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "example")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "dev.flutter.plugins.imagePickerExample")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(SET CMP0063 NEW)
# Load bundled libraries from the lib/ directory relative to the binary.
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
# Root filesystem for cross-building.
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()
# Define build configuration options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
# Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14)
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction()
# Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
# Define the application target. To change its name, change BINARY_NAME above,
# not the value here, or `flutter run` will no longer work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME}
"main.cc"
"my_application.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)
# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME})
# Add dependency libraries. Add any application-specific dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble)
# Only the install-generated bundle's copy of the executable will launch
# correctly, since the resources must in the right relative locations. To avoid
# people trying to run the unbundled copy, put it in a subdirectory instead of
# the default top-level location.
set_target_properties(${BINARY_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
)
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# By default, "installing" just makes a relocatable bundle in the build
# directory.
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
# Start with a clean build bundle directory every time.
install(CODE "
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
" COMPONENT Runtime)
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
install(FILES "${bundled_library}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endforeach(bundled_library)
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only.
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()

View File

@@ -0,0 +1,88 @@
# This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.10)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146.
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
# which isn't available in 3.10.
function(list_prepend LIST_NAME PREFIX)
set(NEW_LIST "")
foreach(element ${${LIST_NAME}})
list(APPEND NEW_LIST "${PREFIX}${element}")
endforeach(element)
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
endfunction()
# === Flutter Library ===
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
# Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"fl_basic_message_channel.h"
"fl_binary_codec.h"
"fl_binary_messenger.h"
"fl_dart_project.h"
"fl_engine.h"
"fl_json_message_codec.h"
"fl_json_method_codec.h"
"fl_message_codec.h"
"fl_method_call.h"
"fl_method_channel.h"
"fl_method_codec.h"
"fl_method_response.h"
"fl_plugin_registrar.h"
"fl_plugin_registry.h"
"fl_standard_message_codec.h"
"fl_standard_method_codec.h"
"fl_string_codec.h"
"fl_value.h"
"fl_view.h"
"flutter_linux.h"
)
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
target_link_libraries(flutter INTERFACE
PkgConfig::GTK
PkgConfig::GLIB
PkgConfig::GIO
)
add_dependencies(flutter flutter_assemble)
# === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the
# flutter tool.
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/_phony_
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
)

View File

@@ -0,0 +1,24 @@
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
endforeach(ffi_plugin)

View File

@@ -0,0 +1,10 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "my_application.h"
int main(int argc, char** argv) {
g_autoptr(MyApplication) app = my_application_new();
return g_application_run(G_APPLICATION(app), argc, argv);
}

View File

@@ -0,0 +1,111 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "my_application.h"
#include <flutter_linux/flutter_linux.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
#include "flutter/generated_plugin_registrant.h"
struct _MyApplication {
GtkApplication parent_instance;
char** dart_entrypoint_arguments;
};
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
// Implements GApplication::activate.
static void my_application_activate(GApplication* application) {
MyApplication* self = MY_APPLICATION(application);
GtkWindow* window =
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
// Use a header bar when running in GNOME as this is the common style used
// by applications and is the setup most users will be using (e.g. Ubuntu
// desktop).
// If running on X and not using GNOME then just use a traditional title bar
// in case the window manager does more exotic layout, e.g. tiling.
// If running on Wayland assume the header bar will work (may need changing
// if future cases occur).
gboolean use_header_bar = TRUE;
#ifdef GDK_WINDOWING_X11
GdkScreen* screen = gtk_window_get_screen(window);
if (GDK_IS_X11_SCREEN(screen)) {
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
use_header_bar = FALSE;
}
}
#endif
if (use_header_bar) {
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "example");
gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
} else {
gtk_window_set_title(window, "example");
}
gtk_window_set_default_size(window, 1280, 720);
gtk_widget_show(GTK_WIDGET(window));
g_autoptr(FlDartProject) project = fl_dart_project_new();
fl_dart_project_set_dart_entrypoint_arguments(
project, self->dart_entrypoint_arguments);
FlView* view = fl_view_new(project);
gtk_widget_show(GTK_WIDGET(view));
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
gtk_widget_grab_focus(GTK_WIDGET(view));
}
// Implements GApplication::local_command_line.
static gboolean my_application_local_command_line(GApplication* application,
gchar*** arguments,
int* exit_status) {
MyApplication* self = MY_APPLICATION(application);
// Strip out the first argument as it is the binary name.
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
g_autoptr(GError) error = nullptr;
if (!g_application_register(application, nullptr, &error)) {
g_warning("Failed to register: %s", error->message);
*exit_status = 1;
return TRUE;
}
g_application_activate(application);
*exit_status = 0;
return TRUE;
}
// Implements GObject::dispose.
static void my_application_dispose(GObject* object) {
MyApplication* self = MY_APPLICATION(object);
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
}
static void my_application_class_init(MyApplicationClass* klass) {
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
G_APPLICATION_CLASS(klass)->local_command_line =
my_application_local_command_line;
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
}
static void my_application_init(MyApplication* self) {}
MyApplication* my_application_new() {
return MY_APPLICATION(g_object_new(my_application_get_type(),
"application-id", APPLICATION_ID, "flags",
G_APPLICATION_NON_UNIQUE, nullptr));
}

View File

@@ -0,0 +1,22 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_MY_APPLICATION_H_
#define FLUTTER_MY_APPLICATION_H_
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
GtkApplication)
/**
* my_application_new:
*
* Creates a new Flutter-based application.
*
* Returns: a new #MyApplication.
*/
MyApplication* my_application_new();
#endif // FLUTTER_MY_APPLICATION_H_

View File

@@ -0,0 +1,29 @@
name: example
description: Example for image_picker_linux implementation.
publish_to: 'none'
version: 1.0.0
environment:
sdk: ^3.4.0
flutter: ">=3.22.0"
dependencies:
flutter:
sdk: flutter
image_picker_linux:
# When depending on this package from a real application you should use:
# image_picker_linux: ^x.y.z
# See https://dart.dev/tools/pub/dependencies#version-constraints
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ..
image_picker_platform_interface: ^2.8.0
mime: ^2.0.0
video_player: ^2.1.4
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true

View File

@@ -0,0 +1,182 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:file_selector_linux/file_selector_linux.dart';
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
import 'package:flutter/foundation.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
/// The Linux implementation of [ImagePickerPlatform].
///
/// This class implements the `package:image_picker` functionality for
/// Linux.
class ImagePickerLinux extends CameraDelegatingImagePickerPlatform {
/// Constructs a platform implementation.
ImagePickerLinux();
/// The file selector used to prompt the user to select images or videos.
@visibleForTesting
static FileSelectorPlatform fileSelector = FileSelectorLinux();
/// Registers this class as the default instance of [ImagePickerPlatform].
static void registerWith() {
ImagePickerPlatform.instance = ImagePickerLinux();
}
// This is soft-deprecated in the platform interface, and is only implemented
// for compatibility. Callers should be using getImageFromSource.
@override
Future<PickedFile?> pickImage({
required ImageSource source,
double? maxWidth,
double? maxHeight,
int? imageQuality,
CameraDevice preferredCameraDevice = CameraDevice.rear,
}) async {
final XFile? file = await getImageFromSource(
source: source,
options: ImagePickerOptions(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: imageQuality,
preferredCameraDevice: preferredCameraDevice));
if (file != null) {
return PickedFile(file.path);
}
return null;
}
// This is soft-deprecated in the platform interface, and is only implemented
// for compatibility. Callers should be using getVideo.
@override
Future<PickedFile?> pickVideo({
required ImageSource source,
CameraDevice preferredCameraDevice = CameraDevice.rear,
Duration? maxDuration,
}) async {
final XFile? file = await getVideo(
source: source,
preferredCameraDevice: preferredCameraDevice,
maxDuration: maxDuration);
if (file != null) {
return PickedFile(file.path);
}
return null;
}
// This is soft-deprecated in the platform interface, and is only implemented
// for compatibility. Callers should be using getImageFromSource.
@override
Future<XFile?> getImage({
required ImageSource source,
double? maxWidth,
double? maxHeight,
int? imageQuality,
CameraDevice preferredCameraDevice = CameraDevice.rear,
}) async {
return getImageFromSource(
source: source,
options: ImagePickerOptions(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: imageQuality,
preferredCameraDevice: preferredCameraDevice));
}
// [ImagePickerOptions] options are not currently supported. If any
// of its fields are set, they will be silently ignored.
//
// If source is `ImageSource.camera`, a `StateError` will be thrown
// unless a [cameraDelegate] is set.
@override
Future<XFile?> getImageFromSource({
required ImageSource source,
ImagePickerOptions options = const ImagePickerOptions(),
}) async {
switch (source) {
case ImageSource.camera:
return super.getImageFromSource(source: source);
case ImageSource.gallery:
const XTypeGroup typeGroup =
XTypeGroup(label: 'Images', mimeTypes: <String>['image/*']);
final XFile? file = await fileSelector
.openFile(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
return file;
}
// Ensure that there's a fallback in case a new source is added.
// ignore: dead_code
throw UnimplementedError('Unknown ImageSource: $source');
}
// `preferredCameraDevice` and `maxDuration` arguments are not currently
// supported. If either of these arguments are supplied, they will be silently
// ignored.
//
// If source is `ImageSource.camera`, a `StateError` will be thrown
// unless a [cameraDelegate] is set.
@override
Future<XFile?> getVideo({
required ImageSource source,
CameraDevice preferredCameraDevice = CameraDevice.rear,
Duration? maxDuration,
}) async {
switch (source) {
case ImageSource.camera:
return super.getVideo(
source: source,
preferredCameraDevice: preferredCameraDevice,
maxDuration: maxDuration);
case ImageSource.gallery:
const XTypeGroup typeGroup =
XTypeGroup(label: 'Videos', mimeTypes: <String>['video/*']);
final XFile? file = await fileSelector
.openFile(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
return file;
}
// Ensure that there's a fallback in case a new source is added.
// ignore: dead_code
throw UnimplementedError('Unknown ImageSource: $source');
}
// `maxWidth`, `maxHeight`, and `imageQuality` arguments are not currently
// supported. If any of these arguments are supplied, they will be silently
// ignored.
@override
Future<List<XFile>> getMultiImage({
double? maxWidth,
double? maxHeight,
int? imageQuality,
}) async {
const XTypeGroup typeGroup =
XTypeGroup(label: 'Images', mimeTypes: <String>['image/*']);
final List<XFile> files = await fileSelector
.openFiles(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
return files;
}
// `maxWidth`, `maxHeight`, and `imageQuality` arguments are not currently
// supported. If any of these arguments are supplied, they will be silently
// ignored.
@override
Future<List<XFile>> getMedia({required MediaOptions options}) async {
const XTypeGroup typeGroup = XTypeGroup(
label: 'Images and videos',
mimeTypes: <String>['image/*', 'video/*'],
);
List<XFile> files;
if (options.allowMultiple) {
files = await fileSelector
.openFiles(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
} else {
final XFile? file = await fileSelector
.openFile(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
files = <XFile>[
if (file != null) file,
];
}
return files;
}
}

View File

@@ -0,0 +1,34 @@
name: image_picker_linux
description: Linux platform implementation of image_picker
repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_linux
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
version: 0.2.1+2
environment:
sdk: ^3.4.0
flutter: ">=3.22.0"
flutter:
plugin:
implements: image_picker
platforms:
linux:
dartPluginClass: ImagePickerLinux
dependencies:
file_selector_linux: ^0.9.1+3
file_selector_platform_interface: ^2.2.0
flutter:
sdk: flutter
image_picker_platform_interface: ^2.8.0
dev_dependencies:
build_runner: ^2.1.5
flutter_test:
sdk: flutter
mockito: ^5.4.4
topics:
- image-picker
- files
- file-selection

View File

@@ -0,0 +1,180 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:image_picker_linux/image_picker_linux.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'image_picker_linux_test.mocks.dart';
@GenerateMocks(<Type>[FileSelectorPlatform])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
// Returns the captured type groups from a mock call result, assuming that
// exactly one call was made and only the type groups were captured.
List<XTypeGroup> capturedTypeGroups(VerificationResult result) {
return result.captured.single as List<XTypeGroup>;
}
late ImagePickerLinux plugin;
late MockFileSelectorPlatform mockFileSelectorPlatform;
setUp(() {
plugin = ImagePickerLinux();
mockFileSelectorPlatform = MockFileSelectorPlatform();
when(mockFileSelectorPlatform.openFile(
acceptedTypeGroups: anyNamed('acceptedTypeGroups')))
.thenAnswer((_) async => null);
when(mockFileSelectorPlatform.openFiles(
acceptedTypeGroups: anyNamed('acceptedTypeGroups')))
.thenAnswer((_) async => List<XFile>.empty());
ImagePickerLinux.fileSelector = mockFileSelectorPlatform;
});
test('registered instance', () {
ImagePickerLinux.registerWith();
expect(ImagePickerPlatform.instance, isA<ImagePickerLinux>());
});
group('images', () {
test('pickImage passes the accepted type groups correctly', () async {
await plugin.pickImage(source: ImageSource.gallery);
final VerificationResult result = verify(mockFileSelectorPlatform
.openFile(acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups')));
expect(capturedTypeGroups(result)[0].mimeTypes, <String>['image/*']);
});
test('getImage passes the accepted type groups correctly', () async {
await plugin.getImage(source: ImageSource.gallery);
final VerificationResult result = verify(mockFileSelectorPlatform
.openFile(acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups')));
expect(capturedTypeGroups(result)[0].mimeTypes, <String>['image/*']);
});
test('getImageFromSource passes the accepted type groups correctly',
() async {
await plugin.getImageFromSource(source: ImageSource.gallery);
final VerificationResult result = verify(mockFileSelectorPlatform
.openFile(acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups')));
expect(capturedTypeGroups(result)[0].mimeTypes, <String>['image/*']);
});
test('getImageFromSource calls delegate when source is camera', () async {
const String fakePath = '/tmp/foo';
plugin.cameraDelegate = FakeCameraDelegate(result: XFile(fakePath));
expect(
(await plugin.getImageFromSource(source: ImageSource.camera))!.path,
fakePath);
});
test(
'getImageFromSource throws StateError when source is camera with no delegate',
() async {
await expectLater(plugin.getImageFromSource(source: ImageSource.camera),
throwsStateError);
});
test('getMultiImage passes the accepted type groups correctly', () async {
await plugin.getMultiImage();
final VerificationResult result = verify(
mockFileSelectorPlatform.openFiles(
acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups')));
expect(capturedTypeGroups(result)[0].mimeTypes, <String>['image/*']);
});
});
group('videos', () {
test('pickVideo passes the accepted type groups correctly', () async {
await plugin.pickVideo(source: ImageSource.gallery);
final VerificationResult result = verify(mockFileSelectorPlatform
.openFile(acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups')));
expect(capturedTypeGroups(result)[0].mimeTypes, <String>['video/*']);
});
test('getVideo passes the accepted type groups correctly', () async {
await plugin.getVideo(source: ImageSource.gallery);
final VerificationResult result = verify(mockFileSelectorPlatform
.openFile(acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups')));
expect(capturedTypeGroups(result)[0].mimeTypes, <String>['video/*']);
});
test('getVideo calls delegate when source is camera', () async {
const String fakePath = '/tmp/foo';
plugin.cameraDelegate = FakeCameraDelegate(result: XFile(fakePath));
expect(
(await plugin.getVideo(source: ImageSource.camera))!.path, fakePath);
});
test('getVideo throws StateError when source is camera with no delegate',
() async {
await expectLater(
plugin.getVideo(source: ImageSource.camera), throwsStateError);
});
});
group('media', () {
test('getMedia passes the accepted type groups correctly', () async {
await plugin.getMedia(options: const MediaOptions(allowMultiple: true));
final VerificationResult result = verify(
mockFileSelectorPlatform.openFiles(
acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups')));
expect(capturedTypeGroups(result)[0].mimeTypes,
<String>['image/*', 'video/*']);
});
test('multiple media handles an empty path response gracefully', () async {
expect(
await plugin.getMedia(
options: const MediaOptions(
allowMultiple: true,
),
),
<String>[]);
});
test('single media handles an empty path response gracefully', () async {
expect(
await plugin.getMedia(
options: const MediaOptions(
allowMultiple: false,
),
),
<String>[]);
});
});
}
class FakeCameraDelegate extends ImagePickerCameraDelegate {
FakeCameraDelegate({this.result});
XFile? result;
@override
Future<XFile?> takePhoto(
{ImagePickerCameraDelegateOptions options =
const ImagePickerCameraDelegateOptions()}) async {
return result;
}
@override
Future<XFile?> takeVideo(
{ImagePickerCameraDelegateOptions options =
const ImagePickerCameraDelegateOptions()}) async {
return result;
}
}

View File

@@ -0,0 +1,143 @@
// Mocks generated by Mockito 5.4.4 from annotations
// in image_picker_linux/test/image_picker_linux_test.dart.
// Do not manually edit this file.
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i3;
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'
as _i2;
import 'package:mockito/mockito.dart' as _i1;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
/// A class which mocks [FileSelectorPlatform].
///
/// See the documentation for Mockito's code generation for more information.
class MockFileSelectorPlatform extends _i1.Mock
implements _i2.FileSelectorPlatform {
MockFileSelectorPlatform() {
_i1.throwOnMissingStub(this);
}
@override
_i3.Future<_i2.XFile?> openFile({
List<_i2.XTypeGroup>? acceptedTypeGroups,
String? initialDirectory,
String? confirmButtonText,
}) =>
(super.noSuchMethod(
Invocation.method(
#openFile,
[],
{
#acceptedTypeGroups: acceptedTypeGroups,
#initialDirectory: initialDirectory,
#confirmButtonText: confirmButtonText,
},
),
returnValue: _i3.Future<_i2.XFile?>.value(),
) as _i3.Future<_i2.XFile?>);
@override
_i3.Future<List<_i2.XFile>> openFiles({
List<_i2.XTypeGroup>? acceptedTypeGroups,
String? initialDirectory,
String? confirmButtonText,
}) =>
(super.noSuchMethod(
Invocation.method(
#openFiles,
[],
{
#acceptedTypeGroups: acceptedTypeGroups,
#initialDirectory: initialDirectory,
#confirmButtonText: confirmButtonText,
},
),
returnValue: _i3.Future<List<_i2.XFile>>.value(<_i2.XFile>[]),
) as _i3.Future<List<_i2.XFile>>);
@override
_i3.Future<String?> getSavePath({
List<_i2.XTypeGroup>? acceptedTypeGroups,
String? initialDirectory,
String? suggestedName,
String? confirmButtonText,
}) =>
(super.noSuchMethod(
Invocation.method(
#getSavePath,
[],
{
#acceptedTypeGroups: acceptedTypeGroups,
#initialDirectory: initialDirectory,
#suggestedName: suggestedName,
#confirmButtonText: confirmButtonText,
},
),
returnValue: _i3.Future<String?>.value(),
) as _i3.Future<String?>);
@override
_i3.Future<_i2.FileSaveLocation?> getSaveLocation({
List<_i2.XTypeGroup>? acceptedTypeGroups,
_i2.SaveDialogOptions? options = const _i2.SaveDialogOptions(),
}) =>
(super.noSuchMethod(
Invocation.method(
#getSaveLocation,
[],
{
#acceptedTypeGroups: acceptedTypeGroups,
#options: options,
},
),
returnValue: _i3.Future<_i2.FileSaveLocation?>.value(),
) as _i3.Future<_i2.FileSaveLocation?>);
@override
_i3.Future<String?> getDirectoryPath({
String? initialDirectory,
String? confirmButtonText,
}) =>
(super.noSuchMethod(
Invocation.method(
#getDirectoryPath,
[],
{
#initialDirectory: initialDirectory,
#confirmButtonText: confirmButtonText,
},
),
returnValue: _i3.Future<String?>.value(),
) as _i3.Future<String?>);
@override
_i3.Future<List<String>> getDirectoryPaths({
String? initialDirectory,
String? confirmButtonText,
}) =>
(super.noSuchMethod(
Invocation.method(
#getDirectoryPaths,
[],
{
#initialDirectory: initialDirectory,
#confirmButtonText: confirmButtonText,
},
),
returnValue: _i3.Future<List<String>>.value(<String>[]),
) as _i3.Future<List<String>>);
}