feat: Livraison version 3.0.6
- Amélioration de la gestion des entités et des utilisateurs - Mise à jour des modèles Amicale et Client avec champs supplémentaires - Ajout du service de logging et amélioration du chargement UI - Refactoring des formulaires utilisateur et amicale - Intégration de file_picker et image_picker pour la gestion des fichiers - Amélioration de la gestion des membres et de leur suppression - Optimisation des performances de l'API - Mise à jour de la documentation technique 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -35,13 +35,16 @@ class AmicaleModelAdapter extends TypeAdapter<AmicaleModel> {
|
||||
chkStripe: fields[19] as bool,
|
||||
createdAt: fields[20] as DateTime?,
|
||||
updatedAt: fields[21] as DateTime?,
|
||||
chkMdpManuel: fields[22] as bool,
|
||||
chkUsernameManuel: fields[23] as bool,
|
||||
logoBase64: fields[24] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, AmicaleModel obj) {
|
||||
writer
|
||||
..writeByte(22)
|
||||
..writeByte(25)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
@@ -85,7 +88,13 @@ class AmicaleModelAdapter extends TypeAdapter<AmicaleModel> {
|
||||
..writeByte(20)
|
||||
..write(obj.createdAt)
|
||||
..writeByte(21)
|
||||
..write(obj.updatedAt);
|
||||
..write(obj.updatedAt)
|
||||
..writeByte(22)
|
||||
..write(obj.chkMdpManuel)
|
||||
..writeByte(23)
|
||||
..write(obj.chkUsernameManuel)
|
||||
..writeByte(24)
|
||||
..write(obj.logoBase64);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -35,13 +35,15 @@ class ClientModelAdapter extends TypeAdapter<ClientModel> {
|
||||
chkStripe: fields[19] as bool?,
|
||||
createdAt: fields[20] as DateTime?,
|
||||
updatedAt: fields[21] as DateTime?,
|
||||
chkMdpManuel: fields[22] as bool?,
|
||||
chkUsernameManuel: fields[23] as bool?,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, ClientModel obj) {
|
||||
writer
|
||||
..writeByte(22)
|
||||
..writeByte(24)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
@@ -85,7 +87,11 @@ class ClientModelAdapter extends TypeAdapter<ClientModel> {
|
||||
..writeByte(20)
|
||||
..write(obj.createdAt)
|
||||
..writeByte(21)
|
||||
..write(obj.updatedAt);
|
||||
..write(obj.updatedAt)
|
||||
..writeByte(22)
|
||||
..write(obj.chkMdpManuel)
|
||||
..writeByte(23)
|
||||
..write(obj.chkUsernameManuel);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import 'package:connectivity_plus/src/connectivity_plus_web.dart';
|
||||
import 'package:geolocator_web/geolocator_web.dart';
|
||||
import 'package:image_picker_for_web/image_picker_for_web.dart';
|
||||
import 'package:package_info_plus/src/package_info_plus_web.dart';
|
||||
import 'package:shared_preferences_web/shared_preferences_web.dart';
|
||||
import 'package:url_launcher_web/url_launcher_web.dart';
|
||||
@@ -17,6 +18,7 @@ void registerPlugins([final Registrar? pluginRegistrar]) {
|
||||
final Registrar registrar = pluginRegistrar ?? webPluginRegistrar;
|
||||
ConnectivityPlusWebPlugin.registerWith(registrar);
|
||||
GeolocatorPlugin.registerWith(registrar);
|
||||
ImagePickerPlugin.registerWith(registrar);
|
||||
PackageInfoPlusWebPlugin.registerWith(registrar);
|
||||
SharedPreferencesPlugin.registerWith(registrar);
|
||||
UrlLauncherPlugin.registerWith(registrar);
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -86,6 +86,11 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/connectivity_plus_platform_interfa
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/connectivity_plus_platform_interface-2.0.1/lib/method_channel_connectivity.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/connectivity_plus_platform_interface-2.0.1/lib/src/enums.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/connectivity_plus_platform_interface-2.0.1/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/cross_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/base.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/html.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/web_helpers/web_helpers.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/x_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/crypto-3.0.6/lib/crypto.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/crypto-3.0.6/lib/src/digest.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/crypto-3.0.6/lib/src/digest_sink.dart
|
||||
@@ -103,36 +108,36 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/dart_polylabel2-1.0.0/lib/dart_pol
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dart_polylabel2-1.0.0/lib/src/impl.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dart_polylabel2-1.0.0/lib/src/point.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dart_polylabel2-1.0.0/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/dio.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/adapter.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/adapters/browser_adapter.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/cancel_token.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/compute/compute.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/compute/compute_web.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/dio.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/dio/dio_for_browser.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/dio_exception.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/dio_mixin.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/form_data.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/headers.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/interceptor.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/interceptors/imply_content_type.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/interceptors/log.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/multipart_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/multipart_file/browser_multipart_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/options.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/parameter.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/progress_stream/browser_progress_stream.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/redirect_record.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/response/response_stream_handler.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/transformers/background_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/transformers/fused_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/transformers/sync_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/transformers/util/consolidate_bytes.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/transformers/util/transform_empty_to_null.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/dio.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/adapter.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/adapters/browser_adapter.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/cancel_token.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/compute/compute.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/compute/compute_web.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/dio.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/dio/dio_for_browser.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/dio_exception.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/dio_mixin.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/form_data.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/headers.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/interceptor.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/interceptors/imply_content_type.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/interceptors/log.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/multipart_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/multipart_file/browser_multipart_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/options.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/parameter.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/progress_stream/browser_progress_stream.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/redirect_record.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/response/response_stream_handler.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/transformers/background_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/transformers/fused_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/transformers/sync_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/transformers/util/consolidate_bytes.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/transformers/util/transform_empty_to_null.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio_cache_interceptor-4.0.3/lib/dio_cache_interceptor.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio_cache_interceptor-4.0.3/lib/src/dio_cache_interceptor.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio_cache_interceptor-4.0.3/lib/src/dio_cache_interceptor_cache_utils.dart
|
||||
@@ -442,25 +447,25 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/hive_flutter-1.1.0/lib/src/hive_ex
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/hive_flutter-1.1.0/lib/src/stub/path.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/hive_flutter-1.1.0/lib/src/stub/path_provider.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/hive_flutter-1.1.0/lib/src/watch_box_builder.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/http.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/retry.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/abortable.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/base_client.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/base_request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/base_response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/boundary_characters.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/browser_client.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/byte_stream.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/client.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/exception.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/multipart_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/multipart_file_stub.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/multipart_request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/streamed_request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/streamed_response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/http.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/retry.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/abortable.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_client.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/boundary_characters.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/browser_client.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/byte_stream.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/client.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/exception.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file_stub.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_cache_core-1.1.1/lib/http_cache_core.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_cache_core-1.1.1/lib/src/model/cache/cache.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_cache_core-1.1.1/lib/src/model/cache/cache_cipher.dart
|
||||
@@ -497,6 +502,29 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/http_dat
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/media_type.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/scan.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker-1.1.2/lib/image_picker.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_for_web-3.0.6/lib/image_picker_for_web.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_for_web-3.0.6/lib/src/image_resizer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_for_web-3.0.6/lib/src/image_resizer_utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_for_web-3.0.6/lib/src/pkg_web_tweaks.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/image_picker_platform_interface.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/method_channel/method_channel_image_picker.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/platform_interface/image_picker_platform.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/camera_delegate.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/camera_device.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/image_options.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/image_source.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/lost_data_response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/media_options.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/media_selection_type.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/multi_image_picker_options.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/picked_file/base.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/picked_file/html.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/picked_file/lost_data.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/picked_file/picked_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/retrieve_type.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/types.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/intl-0.20.2/lib/date_symbol_data_custom.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/intl-0.20.2/lib/date_symbols.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/intl-0.20.2/lib/intl.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/intl-0.20.2/lib/number_symbols.dart
|
||||
@@ -615,6 +643,15 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/mgrs_dart-2.0.0/lib/src/classes/bb
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mgrs_dart-2.0.0/lib/src/classes/lonlat.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mgrs_dart-2.0.0/lib/src/classes/utm.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mgrs_dart-2.0.0/lib/src/mgrs.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/mime.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/bound_multipart_stream.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/char_code.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/default_extension_map.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/extension.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/magic_number.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/mime_multipart_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/mime_shared.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/mime_type.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/lib/package_info_plus.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/lib/src/package_info_plus_linux.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/lib/src/package_info_plus_web.dart
|
||||
@@ -736,129 +773,128 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/span_
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/string_scanner.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/string_scanner.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/charts.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/category_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/datetime_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/datetime_category_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/logarithmic_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/multi_level_labels.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/numeric_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/plot_band.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/base.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/behaviors/crosshair.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/behaviors/trackball.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/behaviors/zooming.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/cartesian_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/circular_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/annotation.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/callbacks.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/chart_point.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/circular_data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/circular_data_label_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/connector_line.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/core_legend.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/core_tooltip.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/element_widget.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/empty_points.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/funnel_data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/interactive_tooltip.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/layout_handler.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/legend.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/marker.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/pyramid_data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/title.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/funnel_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/accumulation_distribution_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/atr_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/bollinger_bands_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/ema_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/macd_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/momentum_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/roc_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/rsi_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/sma_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/stochastic_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/technical_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/tma_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/wma_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/interactions/behavior.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/interactions/selection.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/interactions/tooltip.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/pyramid_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/box_and_whisker_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/bubble_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/candle_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/chart_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/column_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/doughnut_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/error_bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/fast_line_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/funnel_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/hilo_open_close_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/hilo_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/histogram_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/line_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/pie_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/pyramid_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/radial_bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/range_area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/range_column_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/scatter_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/spline_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_area100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_bar100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_column100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_column_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_line100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_line_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/step_area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stepline_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/waterfall_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/trendline/trendline.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/utils/constants.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/utils/enum.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/utils/helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/utils/renderer_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/utils/typedef.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/utils/zooming_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/sparkline/marker.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/sparkline/utils/enum.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/sparkline/utils/helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/core.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/localizations.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/calendar/calendar_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/calendar/hijri_date_time.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/license.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/localizations/global_localizations.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/slider_controller.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/assistview_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/barcodes_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/calendar_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/charts_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/chat_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/color_scheme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/datagrid_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/datapager_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/daterangepicker_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/gauges_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/maps_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/pdfviewer_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/range_selector_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/range_slider_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/slider_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/spark_charts_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/theme_widget.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/treemap_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/utils/helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/utils/shape_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/charts.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/category_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/datetime_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/datetime_category_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/logarithmic_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/multi_level_labels.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/numeric_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/plot_band.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/base.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/behaviors/crosshair.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/behaviors/trackball.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/behaviors/zooming.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/cartesian_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/circular_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/annotation.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/callbacks.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/chart_point.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/circular_data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/circular_data_label_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/connector_line.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/core_legend.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/core_tooltip.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/element_widget.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/empty_points.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/funnel_data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/interactive_tooltip.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/layout_handler.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/legend.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/marker.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/pyramid_data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/title.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/funnel_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/accumulation_distribution_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/atr_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/bollinger_bands_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/ema_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/macd_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/momentum_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/roc_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/rsi_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/sma_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/stochastic_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/technical_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/tma_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/wma_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/interactions/behavior.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/interactions/selection.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/interactions/tooltip.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/pyramid_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/box_and_whisker_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/bubble_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/candle_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/chart_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/column_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/doughnut_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/error_bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/fast_line_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/funnel_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/hilo_open_close_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/hilo_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/histogram_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/line_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/pie_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/pyramid_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/radial_bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/range_area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/range_column_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/scatter_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/spline_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_area100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_bar100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_column100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_column_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_line100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_line_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/step_area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stepline_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/waterfall_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/trendline/trendline.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/utils/constants.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/utils/enum.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/utils/helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/utils/renderer_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/utils/typedef.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/utils/zooming_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/sparkline/marker.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/sparkline/utils/enum.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/sparkline/utils/helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/core.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/localizations.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/calendar/calendar_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/calendar/hijri_date_time.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/localizations/global_localizations.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/slider_controller.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/assistview_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/barcodes_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/calendar_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/charts_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/chat_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/color_scheme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/datagrid_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/datapager_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/daterangepicker_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/gauges_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/maps_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/pdfviewer_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/range_selector_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/range_slider_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/slider_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/spark_charts_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/theme_widget.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/treemap_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/utils/helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/utils/shape_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/ascii_glyph_set.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/glyph_set.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/top_level.dart
|
||||
@@ -951,6 +987,7 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/vector_math-2.1.4/lib/src/vector_m
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/vector_math-2.1.4/lib/src/vector_math_64/vector4.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/vector_math-2.1.4/lib/vector_math.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/vector_math-2.1.4/lib/vector_math_64.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/web-1.1.1/lib/helpers.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/web-1.1.1/lib/src/dom.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/web-1.1.1/lib/src/dom/accelerometer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/web-1.1.1/lib/src/dom/angle_instanced_arrays.dart
|
||||
@@ -1795,6 +1832,15 @@ file:///home/pierre/dev/flutter/packages/flutter/lib/src/widgets/widget_span.dar
|
||||
file:///home/pierre/dev/flutter/packages/flutter/lib/src/widgets/widget_state.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter/lib/widgets.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/flutter_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/cupertino_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/l10n/generated_date_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/l10n/generated_widgets_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/material_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/utils/date_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/widgets_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_web_plugins/lib/flutter_web_plugins.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_web_plugins/lib/src/navigation/utils.dart
|
||||
@@ -1858,6 +1904,7 @@ file:///home/pierre/dev/geosector/app/lib/core/services/hive_reset_state_service
|
||||
file:///home/pierre/dev/geosector/app/lib/core/services/hive_service.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/core/services/hive_web_fix.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/core/services/location_service.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/core/services/logger_service.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/core/services/sync_service.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/core/services/theme_service.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/core/theme/app_theme.dart
|
||||
@@ -1904,7 +1951,7 @@ file:///home/pierre/dev/geosector/app/lib/presentation/widgets/dashboard_app_bar
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/dashboard_layout.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/form_section.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/help_dialog.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/loading_progress_overlay.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/loading_spin_overlay.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/mapbox_map.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/membre_row_widget.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/membre_table_widget.dart
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -86,6 +86,11 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/connectivity_plus_platform_interfa
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/connectivity_plus_platform_interface-2.0.1/lib/method_channel_connectivity.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/connectivity_plus_platform_interface-2.0.1/lib/src/enums.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/connectivity_plus_platform_interface-2.0.1/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/cross_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/base.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/html.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/web_helpers/web_helpers.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/x_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/crypto-3.0.6/lib/crypto.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/crypto-3.0.6/lib/src/digest.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/crypto-3.0.6/lib/src/digest_sink.dart
|
||||
@@ -103,36 +108,36 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/dart_polylabel2-1.0.0/lib/dart_pol
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dart_polylabel2-1.0.0/lib/src/impl.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dart_polylabel2-1.0.0/lib/src/point.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dart_polylabel2-1.0.0/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/dio.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/adapter.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/adapters/browser_adapter.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/cancel_token.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/compute/compute.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/compute/compute_web.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/dio.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/dio/dio_for_browser.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/dio_exception.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/dio_mixin.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/form_data.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/headers.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/interceptor.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/interceptors/imply_content_type.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/interceptors/log.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/multipart_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/multipart_file/browser_multipart_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/options.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/parameter.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/progress_stream/browser_progress_stream.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/redirect_record.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/response/response_stream_handler.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/transformers/background_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/transformers/fused_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/transformers/sync_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/transformers/util/consolidate_bytes.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/transformers/util/transform_empty_to_null.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/dio.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/adapter.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/adapters/browser_adapter.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/cancel_token.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/compute/compute.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/compute/compute_web.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/dio.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/dio/dio_for_browser.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/dio_exception.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/dio_mixin.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/form_data.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/headers.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/interceptor.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/interceptors/imply_content_type.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/interceptors/log.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/multipart_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/multipart_file/browser_multipart_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/options.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/parameter.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/progress_stream/browser_progress_stream.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/redirect_record.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/response/response_stream_handler.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/transformers/background_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/transformers/fused_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/transformers/sync_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/transformers/util/consolidate_bytes.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/transformers/util/transform_empty_to_null.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio_cache_interceptor-4.0.3/lib/dio_cache_interceptor.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio_cache_interceptor-4.0.3/lib/src/dio_cache_interceptor.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio_cache_interceptor-4.0.3/lib/src/dio_cache_interceptor_cache_utils.dart
|
||||
@@ -442,25 +447,25 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/hive_flutter-1.1.0/lib/src/hive_ex
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/hive_flutter-1.1.0/lib/src/stub/path.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/hive_flutter-1.1.0/lib/src/stub/path_provider.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/hive_flutter-1.1.0/lib/src/watch_box_builder.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/http.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/retry.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/abortable.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/base_client.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/base_request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/base_response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/boundary_characters.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/browser_client.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/byte_stream.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/client.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/exception.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/multipart_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/multipart_file_stub.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/multipart_request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/streamed_request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/streamed_response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/http.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/retry.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/abortable.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_client.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/boundary_characters.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/browser_client.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/byte_stream.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/client.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/exception.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file_stub.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_request.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_cache_core-1.1.1/lib/http_cache_core.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_cache_core-1.1.1/lib/src/model/cache/cache.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_cache_core-1.1.1/lib/src/model/cache/cache_cipher.dart
|
||||
@@ -497,6 +502,29 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/http_dat
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/media_type.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/scan.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker-1.1.2/lib/image_picker.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_for_web-3.0.6/lib/image_picker_for_web.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_for_web-3.0.6/lib/src/image_resizer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_for_web-3.0.6/lib/src/image_resizer_utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_for_web-3.0.6/lib/src/pkg_web_tweaks.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/image_picker_platform_interface.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/method_channel/method_channel_image_picker.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/platform_interface/image_picker_platform.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/camera_delegate.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/camera_device.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/image_options.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/image_source.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/lost_data_response.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/media_options.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/media_selection_type.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/multi_image_picker_options.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/picked_file/base.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/picked_file/html.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/picked_file/lost_data.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/picked_file/picked_file.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/retrieve_type.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/src/types/types.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/intl-0.20.2/lib/date_symbol_data_custom.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/intl-0.20.2/lib/date_symbols.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/intl-0.20.2/lib/intl.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/intl-0.20.2/lib/number_symbols.dart
|
||||
@@ -615,6 +643,15 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/mgrs_dart-2.0.0/lib/src/classes/bb
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mgrs_dart-2.0.0/lib/src/classes/lonlat.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mgrs_dart-2.0.0/lib/src/classes/utm.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mgrs_dart-2.0.0/lib/src/mgrs.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/mime.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/bound_multipart_stream.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/char_code.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/default_extension_map.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/extension.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/magic_number.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/mime_multipart_transformer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/mime_shared.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/mime-2.0.0/lib/src/mime_type.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/lib/package_info_plus.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/lib/src/package_info_plus_linux.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/lib/src/package_info_plus_web.dart
|
||||
@@ -736,129 +773,128 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/span_
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/string_scanner.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/utils.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/string_scanner.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/charts.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/category_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/datetime_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/datetime_category_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/logarithmic_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/multi_level_labels.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/numeric_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/axis/plot_band.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/base.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/behaviors/crosshair.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/behaviors/trackball.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/behaviors/zooming.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/cartesian_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/circular_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/annotation.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/callbacks.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/chart_point.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/circular_data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/circular_data_label_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/connector_line.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/core_legend.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/core_tooltip.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/element_widget.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/empty_points.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/funnel_data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/interactive_tooltip.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/layout_handler.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/legend.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/marker.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/pyramid_data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/common/title.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/funnel_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/accumulation_distribution_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/atr_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/bollinger_bands_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/ema_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/macd_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/momentum_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/roc_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/rsi_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/sma_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/stochastic_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/technical_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/tma_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/indicators/wma_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/interactions/behavior.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/interactions/selection.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/interactions/tooltip.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/pyramid_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/box_and_whisker_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/bubble_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/candle_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/chart_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/column_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/doughnut_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/error_bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/fast_line_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/funnel_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/hilo_open_close_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/hilo_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/histogram_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/line_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/pie_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/pyramid_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/radial_bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/range_area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/range_column_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/scatter_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/spline_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_area100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_bar100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_column100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_column_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_line100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stacked_line_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/step_area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/stepline_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/series/waterfall_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/trendline/trendline.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/utils/constants.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/utils/enum.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/utils/helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/utils/renderer_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/utils/typedef.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/charts/utils/zooming_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/sparkline/marker.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/sparkline/utils/enum.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/src/sparkline/utils/helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/core.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/localizations.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/calendar/calendar_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/calendar/hijri_date_time.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/license.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/localizations/global_localizations.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/slider_controller.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/assistview_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/barcodes_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/calendar_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/charts_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/chat_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/color_scheme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/datagrid_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/datapager_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/daterangepicker_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/gauges_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/maps_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/pdfviewer_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/range_selector_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/range_slider_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/slider_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/spark_charts_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/theme_widget.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/theme/treemap_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/utils/helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/src/utils/shape_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/charts.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/category_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/datetime_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/datetime_category_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/logarithmic_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/multi_level_labels.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/numeric_axis.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/axis/plot_band.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/base.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/behaviors/crosshair.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/behaviors/trackball.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/behaviors/zooming.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/cartesian_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/circular_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/annotation.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/callbacks.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/chart_point.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/circular_data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/circular_data_label_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/connector_line.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/core_legend.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/core_tooltip.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/element_widget.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/empty_points.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/funnel_data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/interactive_tooltip.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/layout_handler.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/legend.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/marker.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/pyramid_data_label.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/common/title.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/funnel_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/accumulation_distribution_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/atr_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/bollinger_bands_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/ema_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/macd_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/momentum_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/roc_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/rsi_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/sma_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/stochastic_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/technical_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/tma_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/indicators/wma_indicator.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/interactions/behavior.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/interactions/selection.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/interactions/tooltip.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/pyramid_chart.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/box_and_whisker_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/bubble_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/candle_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/chart_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/column_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/doughnut_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/error_bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/fast_line_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/funnel_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/hilo_open_close_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/hilo_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/histogram_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/line_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/pie_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/pyramid_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/radial_bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/range_area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/range_column_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/scatter_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/spline_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_area100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_bar100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_bar_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_column100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_column_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_line100_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stacked_line_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/step_area_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/stepline_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/series/waterfall_series.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/trendline/trendline.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/utils/constants.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/utils/enum.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/utils/helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/utils/renderer_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/utils/typedef.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/charts/utils/zooming_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/sparkline/marker.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/sparkline/utils/enum.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/src/sparkline/utils/helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/core.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/localizations.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/calendar/calendar_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/calendar/hijri_date_time.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/localizations/global_localizations.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/slider_controller.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/assistview_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/barcodes_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/calendar_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/charts_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/chat_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/color_scheme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/datagrid_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/datapager_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/daterangepicker_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/gauges_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/maps_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/pdfviewer_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/range_selector_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/range_slider_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/slider_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/spark_charts_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/theme_widget.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/theme/treemap_theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/utils/helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/src/utils/shape_helper.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/theme.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/ascii_glyph_set.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/glyph_set.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/top_level.dart
|
||||
@@ -951,6 +987,7 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/vector_math-2.1.4/lib/src/vector_m
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/vector_math-2.1.4/lib/src/vector_math_64/vector4.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/vector_math-2.1.4/lib/vector_math.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/vector_math-2.1.4/lib/vector_math_64.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/web-1.1.1/lib/helpers.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/web-1.1.1/lib/src/dom.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/web-1.1.1/lib/src/dom/accelerometer.dart
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/web-1.1.1/lib/src/dom/angle_instanced_arrays.dart
|
||||
@@ -1794,6 +1831,15 @@ file:///home/pierre/dev/flutter/packages/flutter/lib/src/widgets/widget_span.dar
|
||||
file:///home/pierre/dev/flutter/packages/flutter/lib/src/widgets/widget_state.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter/lib/widgets.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/flutter_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/cupertino_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/l10n/generated_date_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/l10n/generated_widgets_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/material_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/utils/date_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/src/widgets_localizations.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_web_plugins/lib/flutter_web_plugins.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart
|
||||
file:///home/pierre/dev/flutter/packages/flutter_web_plugins/lib/src/navigation/utils.dart
|
||||
@@ -1857,6 +1903,7 @@ file:///home/pierre/dev/geosector/app/lib/core/services/hive_reset_state_service
|
||||
file:///home/pierre/dev/geosector/app/lib/core/services/hive_service.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/core/services/hive_web_fix.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/core/services/location_service.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/core/services/logger_service.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/core/services/sync_service.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/core/services/theme_service.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/core/theme/app_theme.dart
|
||||
@@ -1903,7 +1950,7 @@ file:///home/pierre/dev/geosector/app/lib/presentation/widgets/dashboard_app_bar
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/dashboard_layout.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/form_section.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/help_dialog.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/loading_progress_overlay.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/loading_spin_overlay.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/mapbox_map.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/membre_row_widget.dart
|
||||
file:///home/pierre/dev/geosector/app/lib/presentation/widgets/membre_table_widget.dart
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import 'package:connectivity_plus/src/connectivity_plus_web.dart';
|
||||
import 'package:geolocator_web/geolocator_web.dart';
|
||||
import 'package:image_picker_for_web/image_picker_for_web.dart';
|
||||
import 'package:package_info_plus/src/package_info_plus_web.dart';
|
||||
import 'package:shared_preferences_web/shared_preferences_web.dart';
|
||||
import 'package:url_launcher_web/url_launcher_web.dart';
|
||||
@@ -17,6 +18,7 @@ void registerPlugins([final Registrar? pluginRegistrar]) {
|
||||
final Registrar registrar = pluginRegistrar ?? webPluginRegistrar;
|
||||
ConnectivityPlusWebPlugin.registerWith(registrar);
|
||||
GeolocatorPlugin.registerWith(registrar);
|
||||
ImagePickerPlugin.registerWith(registrar);
|
||||
PackageInfoPlusWebPlugin.registerWith(registrar);
|
||||
SharedPreferencesPlugin.registerWith(registrar);
|
||||
UrlLauncherPlugin.registerWith(registrar);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -87,7 +87,7 @@
|
||||
},
|
||||
{
|
||||
"name": "built_value",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/built_value-8.11.0",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/built_value-8.11.1",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.0"
|
||||
},
|
||||
@@ -151,6 +151,12 @@
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "cross_file",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.3"
|
||||
},
|
||||
{
|
||||
"name": "crypto",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/crypto-3.0.6",
|
||||
@@ -195,7 +201,7 @@
|
||||
},
|
||||
{
|
||||
"name": "dio",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.18"
|
||||
},
|
||||
@@ -241,6 +247,30 @@
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.0"
|
||||
},
|
||||
{
|
||||
"name": "file_selector_linux",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.3"
|
||||
},
|
||||
{
|
||||
"name": "file_selector_macos",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+3",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.6"
|
||||
},
|
||||
{
|
||||
"name": "file_selector_platform_interface",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.0"
|
||||
},
|
||||
{
|
||||
"name": "file_selector_windows",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "fixnum",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/fixnum-1.1.1",
|
||||
@@ -295,6 +325,12 @@
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "flutter_localizations",
|
||||
"rootUri": "file:///home/pierre/dev/flutter/packages/flutter_localizations",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.7"
|
||||
},
|
||||
{
|
||||
"name": "flutter_map",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_map-8.2.1",
|
||||
@@ -307,6 +343,12 @@
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.6"
|
||||
},
|
||||
{
|
||||
"name": "flutter_plugin_android_lifecycle",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.29",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.6"
|
||||
},
|
||||
{
|
||||
"name": "flutter_svg",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_svg-2.2.0",
|
||||
@@ -435,7 +477,7 @@
|
||||
},
|
||||
{
|
||||
"name": "http",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
@@ -469,6 +511,54 @@
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.0"
|
||||
},
|
||||
{
|
||||
"name": "image_picker",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker-1.1.2",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.3"
|
||||
},
|
||||
{
|
||||
"name": "image_picker_android",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_android-0.8.12+25",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.6"
|
||||
},
|
||||
{
|
||||
"name": "image_picker_for_web",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_for_web-3.0.6",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "image_picker_ios",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.12+2",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "image_picker_linux",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.1+2",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "image_picker_macos",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.1+2",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "image_picker_platform_interface",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "image_picker_windows",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.1+1",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.19"
|
||||
},
|
||||
{
|
||||
"name": "intl",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/intl-0.20.2",
|
||||
@@ -717,7 +807,7 @@
|
||||
},
|
||||
{
|
||||
"name": "shared_preferences_android",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.10",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.11",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.6"
|
||||
},
|
||||
@@ -819,13 +909,13 @@
|
||||
},
|
||||
{
|
||||
"name": "syncfusion_flutter_charts",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.7"
|
||||
},
|
||||
{
|
||||
"name": "syncfusion_flutter_core",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.7"
|
||||
},
|
||||
@@ -891,7 +981,7 @@
|
||||
},
|
||||
{
|
||||
"name": "url_launcher_android",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.16",
|
||||
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.17",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.6"
|
||||
},
|
||||
|
||||
@@ -52,8 +52,8 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/built_collection-5.1.1/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/built_collection-5.1.1/lib/
|
||||
built_value
|
||||
3.0
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/built_value-8.11.0/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/built_value-8.11.0/lib/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/built_value-8.11.1/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/built_value-8.11.1/lib/
|
||||
characters
|
||||
3.4
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/characters-1.4.0/
|
||||
@@ -94,6 +94,10 @@ convert
|
||||
3.4
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/convert-3.1.2/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/convert-3.1.2/lib/
|
||||
cross_file
|
||||
3.3
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/
|
||||
crypto
|
||||
3.4
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/crypto-3.0.6/
|
||||
@@ -124,8 +128,8 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/dbus-0.7.11/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/
|
||||
dio
|
||||
2.18
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.8.0+1/lib/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0/lib/
|
||||
dio_cache_interceptor
|
||||
3.0
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/dio_cache_interceptor-4.0.3/
|
||||
@@ -154,6 +158,22 @@ file
|
||||
3.0
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/file-7.0.1/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/file-7.0.1/lib/
|
||||
file_selector_linux
|
||||
3.3
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/
|
||||
file_selector_macos
|
||||
3.6
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+3/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+3/lib/
|
||||
file_selector_platform_interface
|
||||
3.0
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/
|
||||
file_selector_windows
|
||||
3.4
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/
|
||||
fixnum
|
||||
3.1
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/fixnum-1.1.1/
|
||||
@@ -194,6 +214,10 @@ flutter_map_cache
|
||||
3.6
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_map_cache-2.0.0+1/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_map_cache-2.0.0+1/lib/
|
||||
flutter_plugin_android_lifecycle
|
||||
3.6
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.29/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.29/lib/
|
||||
flutter_svg
|
||||
3.6
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_svg-2.2.0/
|
||||
@@ -272,8 +296,8 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/html-0.15.6/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/html-0.15.6/lib/
|
||||
http
|
||||
3.4
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0-beta.2/lib/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http-1.5.0/lib/
|
||||
http_cache_core
|
||||
3.0
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/http_cache_core-1.1.1/
|
||||
@@ -294,6 +318,38 @@ image
|
||||
3.0
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image-4.5.4/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image-4.5.4/lib/
|
||||
image_picker
|
||||
3.3
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker-1.1.2/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker-1.1.2/lib/
|
||||
image_picker_android
|
||||
3.6
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_android-0.8.12+25/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_android-0.8.12+25/lib/
|
||||
image_picker_for_web
|
||||
3.4
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_for_web-3.0.6/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_for_web-3.0.6/lib/
|
||||
image_picker_ios
|
||||
3.4
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.12+2/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.12+2/lib/
|
||||
image_picker_linux
|
||||
3.4
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.1+2/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.1+2/lib/
|
||||
image_picker_macos
|
||||
3.4
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.1+2/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.1+2/lib/
|
||||
image_picker_platform_interface
|
||||
3.4
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.10.1/lib/
|
||||
image_picker_windows
|
||||
2.19
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.1+1/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.1+1/lib/
|
||||
intl
|
||||
3.3
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/intl-0.20.2/
|
||||
@@ -460,8 +516,8 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences-2.5.3/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences-2.5.3/lib/
|
||||
shared_preferences_android
|
||||
3.6
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.10/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.10/lib/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.11/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.11/lib/
|
||||
shared_preferences_foundation
|
||||
3.4
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/
|
||||
@@ -524,12 +580,12 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/
|
||||
syncfusion_flutter_charts
|
||||
3.7
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.1.42/lib/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.4/lib/
|
||||
syncfusion_flutter_core
|
||||
3.7
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.1.42/lib/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-30.2.4/lib/
|
||||
synchronized
|
||||
3.8
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/synchronized-3.4.0/
|
||||
@@ -572,8 +628,8 @@ file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher-6.3.2/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher-6.3.2/lib/
|
||||
url_launcher_android
|
||||
3.6
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.16/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.16/lib/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.17/
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.17/lib/
|
||||
url_launcher_ios
|
||||
3.4
|
||||
file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.3/
|
||||
@@ -670,6 +726,10 @@ flutter
|
||||
3.7
|
||||
file:///home/pierre/dev/flutter/packages/flutter/
|
||||
file:///home/pierre/dev/flutter/packages/flutter/lib/
|
||||
flutter_localizations
|
||||
3.7
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/
|
||||
file:///home/pierre/dev/flutter/packages/flutter_localizations/lib/
|
||||
flutter_test
|
||||
3.7
|
||||
file:///home/pierre/dev/flutter/packages/flutter_test/
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"packages": [
|
||||
{
|
||||
"name": "geosector_app",
|
||||
"version": "3.0.4+304",
|
||||
"version": "3.0.6+306",
|
||||
"dependencies": [
|
||||
"connectivity_plus",
|
||||
"cupertino_icons",
|
||||
@@ -13,6 +13,7 @@
|
||||
"fl_chart",
|
||||
"flutter",
|
||||
"flutter_local_notifications",
|
||||
"flutter_localizations",
|
||||
"flutter_map",
|
||||
"flutter_map_cache",
|
||||
"flutter_svg",
|
||||
@@ -22,6 +23,7 @@
|
||||
"hive",
|
||||
"hive_flutter",
|
||||
"http_cache_file_store",
|
||||
"image_picker",
|
||||
"intl",
|
||||
"latlong2",
|
||||
"mqtt5_client",
|
||||
@@ -101,6 +103,20 @@
|
||||
"vm_service"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "image_picker",
|
||||
"version": "1.1.2",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"image_picker_android",
|
||||
"image_picker_for_web",
|
||||
"image_picker_ios",
|
||||
"image_picker_linux",
|
||||
"image_picker_macos",
|
||||
"image_picker_platform_interface",
|
||||
"image_picker_windows"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "universal_html",
|
||||
"version": "2.2.4",
|
||||
@@ -136,16 +152,6 @@
|
||||
"intl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "syncfusion_flutter_charts",
|
||||
"version": "30.1.42",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"intl",
|
||||
"syncfusion_flutter_core",
|
||||
"vector_math"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fl_chart",
|
||||
"version": "1.0.0",
|
||||
@@ -203,6 +209,21 @@
|
||||
"meta"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "flutter_localizations",
|
||||
"version": "0.0.0",
|
||||
"dependencies": [
|
||||
"characters",
|
||||
"clock",
|
||||
"collection",
|
||||
"flutter",
|
||||
"intl",
|
||||
"material_color_utilities",
|
||||
"meta",
|
||||
"path",
|
||||
"vector_math"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "flutter",
|
||||
"version": "0.0.0",
|
||||
@@ -406,14 +427,6 @@
|
||||
"package_info_plus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "syncfusion_flutter_core",
|
||||
"version": "30.1.42",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"vector_math"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "equatable",
|
||||
"version": "2.0.7",
|
||||
@@ -489,6 +502,24 @@
|
||||
"url_launcher_windows"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "syncfusion_flutter_charts",
|
||||
"version": "30.2.4",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"intl",
|
||||
"syncfusion_flutter_core",
|
||||
"vector_math"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "syncfusion_flutter_core",
|
||||
"version": "30.2.4",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"vector_math"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "connectivity_plus",
|
||||
"version": "6.1.4",
|
||||
@@ -560,6 +591,26 @@
|
||||
"yaml"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "image_picker_windows",
|
||||
"version": "0.2.1+1",
|
||||
"dependencies": [
|
||||
"file_selector_platform_interface",
|
||||
"file_selector_windows",
|
||||
"flutter",
|
||||
"image_picker_platform_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "image_picker_platform_interface",
|
||||
"version": "2.10.1",
|
||||
"dependencies": [
|
||||
"cross_file",
|
||||
"flutter",
|
||||
"http",
|
||||
"plugin_platform_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "typed_data",
|
||||
"version": "1.4.0",
|
||||
@@ -567,6 +618,13 @@
|
||||
"collection"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "plugin_platform_interface",
|
||||
"version": "2.1.8",
|
||||
"dependencies": [
|
||||
"meta"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "http_cache_core",
|
||||
"version": "1.1.1",
|
||||
@@ -656,16 +714,6 @@
|
||||
"unicode"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "http",
|
||||
"version": "1.5.0-beta.2",
|
||||
"dependencies": [
|
||||
"async",
|
||||
"http_parser",
|
||||
"meta",
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "dart_earcut",
|
||||
"version": "1.2.0",
|
||||
@@ -701,6 +749,26 @@
|
||||
"version": "2.7.0",
|
||||
"dependencies": []
|
||||
},
|
||||
{
|
||||
"name": "image_picker_macos",
|
||||
"version": "0.2.1+2",
|
||||
"dependencies": [
|
||||
"file_selector_macos",
|
||||
"file_selector_platform_interface",
|
||||
"flutter",
|
||||
"image_picker_platform_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "image_picker_linux",
|
||||
"version": "0.2.1+2",
|
||||
"dependencies": [
|
||||
"file_selector_linux",
|
||||
"file_selector_platform_interface",
|
||||
"flutter",
|
||||
"image_picker_platform_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "csslib",
|
||||
"version": "1.0.2",
|
||||
@@ -731,6 +799,16 @@
|
||||
"version": "1.1.1",
|
||||
"dependencies": []
|
||||
},
|
||||
{
|
||||
"name": "http",
|
||||
"version": "1.5.0",
|
||||
"dependencies": [
|
||||
"async",
|
||||
"http_parser",
|
||||
"meta",
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "url_launcher_platform_interface",
|
||||
"version": "2.3.2",
|
||||
@@ -739,13 +817,6 @@
|
||||
"plugin_platform_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "plugin_platform_interface",
|
||||
"version": "2.1.8",
|
||||
"dependencies": [
|
||||
"meta"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "path_provider_windows",
|
||||
"version": "2.3.0",
|
||||
@@ -955,6 +1026,33 @@
|
||||
"url_launcher_platform_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "xdg_directories",
|
||||
"version": "1.1.0",
|
||||
"dependencies": [
|
||||
"meta",
|
||||
"path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_selector_linux",
|
||||
"version": "0.9.3+2",
|
||||
"dependencies": [
|
||||
"cross_file",
|
||||
"file_selector_platform_interface",
|
||||
"flutter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_selector_platform_interface",
|
||||
"version": "2.6.2",
|
||||
"dependencies": [
|
||||
"cross_file",
|
||||
"flutter",
|
||||
"http",
|
||||
"plugin_platform_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "http_parser",
|
||||
"version": "4.1.2",
|
||||
@@ -965,14 +1063,6 @@
|
||||
"typed_data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "xdg_directories",
|
||||
"version": "1.1.0",
|
||||
"dependencies": [
|
||||
"meta",
|
||||
"path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "crypto",
|
||||
"version": "3.0.6",
|
||||
@@ -1094,6 +1184,22 @@
|
||||
"path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "image_picker_for_web",
|
||||
"version": "3.0.6",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"flutter_web_plugins",
|
||||
"image_picker_platform_interface",
|
||||
"mime",
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mime",
|
||||
"version": "2.0.0",
|
||||
"dependencies": []
|
||||
},
|
||||
{
|
||||
"name": "platform",
|
||||
"version": "3.1.6",
|
||||
@@ -1151,6 +1257,15 @@
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_selector_macos",
|
||||
"version": "0.9.4+3",
|
||||
"dependencies": [
|
||||
"cross_file",
|
||||
"file_selector_platform_interface",
|
||||
"flutter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "logger",
|
||||
"version": "2.6.1",
|
||||
@@ -1203,15 +1318,24 @@
|
||||
"vector_graphics_codec"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "path_provider_android",
|
||||
"version": "2.2.17",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"path_provider_platform_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "dio",
|
||||
"version": "5.8.0+1",
|
||||
"version": "5.9.0",
|
||||
"dependencies": [
|
||||
"async",
|
||||
"collection",
|
||||
"dio_web_adapter",
|
||||
"http_parser",
|
||||
"meta",
|
||||
"mime",
|
||||
"path"
|
||||
]
|
||||
},
|
||||
@@ -1225,17 +1349,9 @@
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "path_provider_android",
|
||||
"version": "2.2.17",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"path_provider_platform_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "shared_preferences_android",
|
||||
"version": "2.4.10",
|
||||
"version": "2.4.11",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"shared_preferences_platform_interface"
|
||||
@@ -1434,16 +1550,6 @@
|
||||
"path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "built_value",
|
||||
"version": "8.11.0",
|
||||
"dependencies": [
|
||||
"built_collection",
|
||||
"collection",
|
||||
"fixnum",
|
||||
"meta"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "watcher",
|
||||
"version": "1.1.2",
|
||||
@@ -1484,6 +1590,16 @@
|
||||
"collection"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "built_value",
|
||||
"version": "8.11.1",
|
||||
"dependencies": [
|
||||
"built_collection",
|
||||
"collection",
|
||||
"fixnum",
|
||||
"meta"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stream_transform",
|
||||
"version": "2.1.1",
|
||||
@@ -1540,11 +1656,6 @@
|
||||
"web_socket_channel"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mime",
|
||||
"version": "2.0.0",
|
||||
"dependencies": []
|
||||
},
|
||||
{
|
||||
"name": "js",
|
||||
"version": "0.7.2",
|
||||
@@ -1602,6 +1713,14 @@
|
||||
"stream_channel"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "image_picker_ios",
|
||||
"version": "0.8.12+2",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"image_picker_platform_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "win32",
|
||||
"version": "5.14.0",
|
||||
@@ -1609,13 +1728,46 @@
|
||||
"ffi"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_selector_windows",
|
||||
"version": "0.9.3+4",
|
||||
"dependencies": [
|
||||
"cross_file",
|
||||
"file_selector_platform_interface",
|
||||
"flutter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cross_file",
|
||||
"version": "0.3.4+2",
|
||||
"dependencies": [
|
||||
"meta",
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "url_launcher_android",
|
||||
"version": "6.3.16",
|
||||
"version": "6.3.17",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"url_launcher_platform_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "image_picker_android",
|
||||
"version": "0.8.12+25",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"flutter_plugin_android_lifecycle",
|
||||
"image_picker_platform_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "flutter_plugin_android_lifecycle",
|
||||
"version": "2.0.29",
|
||||
"dependencies": [
|
||||
"flutter"
|
||||
]
|
||||
}
|
||||
],
|
||||
"configVersion": 1
|
||||
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -96,6 +96,7 @@ GEOSECTOR est une solution complète développée en Flutter qui révolutionne l
|
||||
| **Géolocalisation** | Geolocator | 10.1.0 | Services de localisation |
|
||||
| **Chat** | MQTT5 Client | 4.2.0 | Messagerie temps réel |
|
||||
| **UI** | Material Design 3 | Native | Composants d'interface |
|
||||
| **Logging** | LoggerService | Custom | Logs conditionnels par env |
|
||||
|
||||
### 🏛️ Architecture en couches
|
||||
|
||||
@@ -423,6 +424,355 @@ Interface : Affichage utilisateur via ApiException.showError()
|
||||
Network Errors : "Problème de connexion réseau"
|
||||
Timeout : "Délai d'attente dépassé"
|
||||
|
||||
## 🔧 Pattern de gestion des erreurs API dans les Repositories
|
||||
|
||||
### 🎯 Problème à résoudre
|
||||
|
||||
Les messages d'erreur spécifiques de l'API (comme "Cet email est déjà utilisé") n'étaient pas affichés à l'utilisateur. À la place, un message générique "Erreur inattendue" apparaissait.
|
||||
|
||||
### 📝 Modifications requises
|
||||
|
||||
#### **1. ApiService - Conversion automatique des DioException**
|
||||
|
||||
Toutes les méthodes HTTP génériques doivent convertir les `DioException` en `ApiException` :
|
||||
|
||||
```dart
|
||||
// ✅ CORRECT - ApiService avec conversion automatique
|
||||
Future<Response> put(String path, {dynamic data}) async {
|
||||
try {
|
||||
return await _dio.put(path, data: data);
|
||||
} on DioException catch (e) {
|
||||
throw ApiException.fromDioException(e); // ← Extraction automatique du message
|
||||
} catch (e) {
|
||||
if (e is ApiException) rethrow;
|
||||
throw ApiException('Erreur inattendue lors de la requête PUT', originalError: e);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Appliquer le même pattern pour `post()`, `get()`, `delete()`.
|
||||
|
||||
#### **2. Repository - Simplification de la gestion des erreurs**
|
||||
|
||||
```dart
|
||||
// ❌ INCORRECT - Code inutile qui ne sera jamais exécuté
|
||||
Future<bool> updateMembre(MembreModel membre) async {
|
||||
try {
|
||||
final response = await ApiService.instance.put('/users/${membre.id}', data: data);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
await saveMembreBox(membre);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ⚠️ CE CODE NE SERA JAMAIS ATTEINT car Dio lance une exception pour les codes d'erreur
|
||||
if (response.data != null && response.data is Map<String, dynamic>) {
|
||||
final responseData = response.data as Map<String, dynamic>;
|
||||
if (responseData['status'] == 'error') {
|
||||
throw Exception(responseData['message']);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```dart
|
||||
// ✅ CORRECT - Code simplifié et fonctionnel
|
||||
Future<bool> updateMembre(MembreModel membre) async {
|
||||
try {
|
||||
final response = await ApiService.instance.put('/users/${membre.id}', data: data);
|
||||
|
||||
// Si on arrive ici, c'est que la requête a réussi (200)
|
||||
await saveMembreBox(membre);
|
||||
return true;
|
||||
|
||||
} catch (e) {
|
||||
// L'ApiException contient déjà le message extrait de l'API
|
||||
rethrow; // Propager l'exception pour affichage
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **3. Amélioration des logs (avec LoggerService)**
|
||||
|
||||
```dart
|
||||
// ✅ CORRECT - Logs propres sans détails techniques
|
||||
catch (e) {
|
||||
// Ne pas logger les détails techniques de DioException
|
||||
if (e is ApiException) {
|
||||
LoggerService.error('Erreur lors de la mise à jour: ${e.message}');
|
||||
} else {
|
||||
LoggerService.error('Erreur lors de la mise à jour');
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
```
|
||||
|
||||
N'oubliez pas d'importer `ApiException` :
|
||||
```dart
|
||||
import 'package:geosector_app/core/utils/api_exception.dart';
|
||||
```
|
||||
|
||||
### 🔄 Flux d'erreur corrigé
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant API as API Server
|
||||
participant Dio as Dio Client
|
||||
participant AS as ApiService
|
||||
participant AE as ApiException
|
||||
participant R as Repository
|
||||
participant UI as Interface
|
||||
|
||||
UI->>R: updateData()
|
||||
R->>AS: put('/endpoint')
|
||||
AS->>Dio: HTTP PUT
|
||||
Dio->>API: Request
|
||||
|
||||
alt Code d'erreur (409, 400, etc.)
|
||||
API-->>Dio: Error + JSON body
|
||||
Note over API: {"status": "error",<br/>"message": "Message spécifique"}
|
||||
|
||||
Dio-->>AS: DioException
|
||||
AS->>AE: fromDioException()
|
||||
Note over AE: Extrait message<br/>depuis response.data
|
||||
AE-->>AS: ApiException("Message spécifique")
|
||||
AS-->>R: throw ApiException
|
||||
R-->>UI: throw ApiException
|
||||
UI->>UI: showError("Message spécifique")
|
||||
else Succès (200, 201)
|
||||
API-->>Dio: Success
|
||||
Dio-->>AS: Response
|
||||
AS-->>R: Response
|
||||
R->>R: Sauvegarde Hive
|
||||
R-->>UI: return true
|
||||
end
|
||||
```
|
||||
|
||||
### ✅ Checklist de migration
|
||||
|
||||
Pour chaque repository :
|
||||
|
||||
- [ ] Vérifier que l'ApiService convertit les DioException en ApiException
|
||||
- [ ] Simplifier le code : supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Propager les exceptions avec `rethrow`
|
||||
- [ ] Améliorer les logs pour ne pas afficher les détails techniques
|
||||
- [ ] Importer `ApiException` si nécessaire
|
||||
- [ ] Tester avec une erreur 409 pour vérifier l'affichage du message
|
||||
|
||||
### 📊 Résultat attendu
|
||||
|
||||
| Avant | Après |
|
||||
|-------|-------|
|
||||
| "Erreur inattendue" | "Cet email est déjà utilisé par un autre utilisateur" |
|
||||
| Logs avec stack trace Dio | Message d'erreur simple et clair |
|
||||
| Code complexe avec vérifications inutiles | Code simplifié et maintenable |
|
||||
|
||||
Cette approche garantit que tous les messages d'erreur de l'API sont correctement affichés à l'utilisateur, améliorant ainsi l'expérience utilisateur et facilitant le débogage.
|
||||
|
||||
## 📝 Service de Logging Intelligent
|
||||
|
||||
### 🎯 Vue d'ensemble
|
||||
|
||||
GEOSECTOR v2.0 implémente un **LoggerService centralisé** qui désactive automatiquement les logs de debug en production, optimisant ainsi les performances et la sécurité tout en facilitant le développement.
|
||||
|
||||
### 🔍 Détection automatique de l'environnement
|
||||
|
||||
Le LoggerService détecte automatiquement l'environnement d'exécution :
|
||||
|
||||
```dart
|
||||
// Détection basée sur l'URL pour le web
|
||||
if (currentUrl.contains('dapp.geosector.fr')) → DEV
|
||||
if (currentUrl.contains('rapp.geosector.fr')) → REC
|
||||
Sinon → PROD
|
||||
|
||||
// Pour mobile/desktop : utilise kReleaseMode de Flutter
|
||||
```
|
||||
|
||||
**Comportement par environnement :**
|
||||
|
||||
| Environnement | Logs Debug | Logs Erreur | Stack Traces |
|
||||
|---------------|------------|-------------|--------------|
|
||||
| **DEV** | ✅ Activés | ✅ Activés | ✅ Complètes |
|
||||
| **REC** | ✅ Activés | ✅ Activés | ✅ Complètes |
|
||||
| **PROD** | ❌ Désactivés | ✅ Activés | ❌ Masquées |
|
||||
|
||||
### 🛠️ API du LoggerService
|
||||
|
||||
#### **Méthodes principales**
|
||||
|
||||
```dart
|
||||
// Remplacement direct de debugPrint
|
||||
LoggerService.log('Message simple');
|
||||
|
||||
// Logs catégorisés avec emojis automatiques
|
||||
LoggerService.info('Information'); // ℹ️
|
||||
LoggerService.success('Opération réussie'); // ✅
|
||||
LoggerService.warning('Attention'); // ⚠️
|
||||
LoggerService.error('Erreur', exception); // ❌ (toujours affiché)
|
||||
LoggerService.debug('Debug', emoji: '🔧'); // 🔧
|
||||
|
||||
// Logs spécialisés
|
||||
LoggerService.api('Requête API envoyée'); // 🔗
|
||||
LoggerService.database('Box Hive ouverte'); // 💾
|
||||
LoggerService.navigation('Route: /admin'); // 🧭
|
||||
LoggerService.performance('Temps: 45ms'); // ⏱️
|
||||
```
|
||||
|
||||
#### **Fonctionnalités avancées**
|
||||
|
||||
```dart
|
||||
// Logs groupés pour améliorer la lisibilité
|
||||
LoggerService.group('Traitement utilisateur', [
|
||||
'Validation des données',
|
||||
'Appel API',
|
||||
'Sauvegarde locale',
|
||||
'Notification envoyée'
|
||||
]);
|
||||
// Affiche :
|
||||
// ┌─ Traitement utilisateur
|
||||
// ├─ Validation des données
|
||||
// ├─ Appel API
|
||||
// ├─ Sauvegarde locale
|
||||
// └─ Notification envoyée
|
||||
|
||||
// Log JSON formaté
|
||||
LoggerService.json('Payload API', {
|
||||
'id': 123,
|
||||
'name': 'Test',
|
||||
'active': true
|
||||
});
|
||||
// Affiche :
|
||||
// 📋 Payload API:
|
||||
// id: 123
|
||||
// name: Test
|
||||
// active: true
|
||||
|
||||
// Log conditionnel
|
||||
LoggerService.conditional(
|
||||
'Debug spécifique',
|
||||
condition: user.role > 2
|
||||
);
|
||||
```
|
||||
|
||||
### 🔄 Migration depuis debugPrint
|
||||
|
||||
#### **Avant (debugPrint partout)**
|
||||
|
||||
```dart
|
||||
debugPrint('🔄 Début de la création d\'un nouveau membre');
|
||||
debugPrint('📤 Données envoyées à l\'API: $data');
|
||||
debugPrint('❌ Erreur: $e');
|
||||
```
|
||||
|
||||
#### **Après (LoggerService)**
|
||||
|
||||
```dart
|
||||
LoggerService.info('Début de la création d\'un nouveau membre');
|
||||
LoggerService.api('Données envoyées à l\'API: $data');
|
||||
LoggerService.error('Erreur lors de la création', e);
|
||||
```
|
||||
|
||||
### 📋 Utilisation avec les extensions
|
||||
|
||||
Pour une syntaxe encore plus concise, utilisez les extensions String :
|
||||
|
||||
```dart
|
||||
// Import nécessaire
|
||||
import 'package:geosector_app/core/services/logger_service.dart';
|
||||
|
||||
// Utilisation directe sur les strings
|
||||
'Connexion réussie'.logSuccess();
|
||||
'Erreur de validation'.logError(exception);
|
||||
'Requête GET /users'.logApi();
|
||||
'Box membres ouverte'.logDatabase();
|
||||
```
|
||||
|
||||
### 🎯 Bonnes pratiques
|
||||
|
||||
#### **1. Catégorisation des logs**
|
||||
|
||||
```dart
|
||||
// ✅ BON - Log catégorisé et clair
|
||||
LoggerService.api('POST /users - Création membre');
|
||||
LoggerService.database('Sauvegarde dans Box membres');
|
||||
|
||||
// ❌ MAUVAIS - Log générique sans contexte
|
||||
debugPrint('Traitement en cours...');
|
||||
```
|
||||
|
||||
#### **2. Gestion des erreurs**
|
||||
|
||||
```dart
|
||||
try {
|
||||
await operation();
|
||||
LoggerService.success('Opération terminée');
|
||||
} catch (e, stackTrace) {
|
||||
// Les erreurs sont TOUJOURS loggées, même en PROD
|
||||
LoggerService.error('Échec de l\'opération', e, stackTrace);
|
||||
}
|
||||
```
|
||||
|
||||
#### **3. Logs de performance**
|
||||
|
||||
```dart
|
||||
final stopwatch = Stopwatch()..start();
|
||||
await heavyOperation();
|
||||
stopwatch.stop();
|
||||
LoggerService.performance('Opération lourde: ${stopwatch.elapsedMilliseconds}ms');
|
||||
```
|
||||
|
||||
### 🔒 Sécurité et performances
|
||||
|
||||
#### **Avantages en production**
|
||||
|
||||
1. **Sécurité** : Aucune information sensible exposée dans la console
|
||||
2. **Performance** : Pas d'appels inutiles à debugPrint
|
||||
3. **Taille** : Bundle JavaScript plus léger (tree shaking)
|
||||
4. **Professionnalisme** : Console propre pour les utilisateurs finaux
|
||||
|
||||
#### **Conservation des logs d'erreur**
|
||||
|
||||
Les erreurs restent visibles en production pour faciliter le support :
|
||||
|
||||
```dart
|
||||
// Toujours affiché, même en PROD
|
||||
LoggerService.error('Erreur critique détectée', error);
|
||||
// Mais sans la stack trace complète qui pourrait révéler
|
||||
// des détails d'implémentation
|
||||
```
|
||||
|
||||
### 📊 Impact sur le codebase
|
||||
|
||||
| Métrique | Avant | Après |
|
||||
|----------|-------|-------|
|
||||
| **Logs en PROD** | Tous visibles | Erreurs uniquement |
|
||||
| **Performance web** | debugPrint actifs | Désactivés automatiquement |
|
||||
| **Maintenance** | debugPrint dispersés | Service centralisé |
|
||||
| **Lisibilité** | Emojis manuels | Catégorisation automatique |
|
||||
|
||||
### 🚀 Configuration et initialisation
|
||||
|
||||
Le LoggerService fonctionne automatiquement sans configuration :
|
||||
|
||||
```dart
|
||||
// main.dart - Aucune initialisation requise
|
||||
void main() async {
|
||||
// LoggerService détecte automatiquement l'environnement
|
||||
// via ApiService.getCurrentEnvironment()
|
||||
|
||||
runApp(GeosectorApp());
|
||||
}
|
||||
|
||||
// Utilisation immédiate dans n'importe quel fichier
|
||||
LoggerService.info('Application démarrée');
|
||||
```
|
||||
|
||||
Cette architecture garantit un système de logging professionnel, sécurisé et performant, adapté aux besoins de développement tout en protégeant la production. 📝✨
|
||||
|
||||
## 🎯 Gestion des rôles
|
||||
|
||||
### Hiérarchie des permissions
|
||||
|
||||
766
app/TODO-APP.md
Normal file
766
app/TODO-APP.md
Normal file
@@ -0,0 +1,766 @@
|
||||
# TODO-APP.md
|
||||
|
||||
## 📋 Liste des tâches à effectuer sur l'application GEOSECTOR
|
||||
|
||||
### 🔧 Migration du pattern de gestion des erreurs API
|
||||
|
||||
#### 🎯 Objectif
|
||||
Appliquer le nouveau pattern de gestion des erreurs pour que tous les messages spécifiques de l'API soient correctement affichés aux utilisateurs (au lieu du message générique "Erreur inattendue").
|
||||
|
||||
---
|
||||
|
||||
### ✅ Repositories déjà migrés
|
||||
- [x] **MembreRepository** (`lib/core/repositories/membre_repository.dart`)
|
||||
- ✅ Conversion DioException → ApiException
|
||||
- ✅ Simplification du code
|
||||
- ✅ Logs avec LoggerService
|
||||
|
||||
---
|
||||
|
||||
### 📝 Repositories à migrer
|
||||
|
||||
#### 1. **UserRepository** (`lib/core/repositories/user_repository.dart`)
|
||||
- [ ] Vérifier/ajouter l'import `ApiException`
|
||||
- [ ] Simplifier `updateUser()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `syncUser()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `syncAllUsers()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Remplacer `debugPrint` par `LoggerService`
|
||||
- [ ] Améliorer la gestion des erreurs dans le bloc catch (ne pas logger DioException)
|
||||
|
||||
#### 2. **OperationRepository** (`lib/core/repositories/operation_repository.dart`)
|
||||
- [ ] Vérifier/ajouter l'import `ApiException`
|
||||
- [ ] Simplifier `createOperation()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `updateOperation()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `deleteOperation()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `activateOperation()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Remplacer `debugPrint` par `LoggerService`
|
||||
- [ ] Améliorer la gestion des erreurs dans le bloc catch (ne pas logger DioException)
|
||||
|
||||
#### 3. **PassageRepository** (`lib/core/repositories/passage_repository.dart`)
|
||||
- [ ] Vérifier/ajouter l'import `ApiException`
|
||||
- [ ] Simplifier `createPassage()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `updatePassage()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `updatePassageStatus()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `syncPassages()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Remplacer `debugPrint` par `LoggerService`
|
||||
- [ ] Améliorer la gestion des erreurs dans le bloc catch (ne pas logger DioException)
|
||||
|
||||
#### 4. **SectorRepository** (`lib/core/repositories/sector_repository.dart`)
|
||||
- [ ] Vérifier/ajouter l'import `ApiException`
|
||||
- [ ] Simplifier `createSector()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `updateSector()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `deleteSector()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `assignUserToSector()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Remplacer `debugPrint` par `LoggerService`
|
||||
- [ ] Améliorer la gestion des erreurs dans le bloc catch (ne pas logger DioException)
|
||||
|
||||
#### 5. **AmicaleRepository** (`lib/core/repositories/amicale_repository.dart`)
|
||||
- [ ] Vérifier/ajouter l'import `ApiException`
|
||||
- [ ] Simplifier `updateAmicale()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `createAmicale()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Simplifier `syncAmicales()` - supprimer les vérifications de statut après l'appel API
|
||||
- [ ] Remplacer `debugPrint` par `LoggerService`
|
||||
- [ ] Améliorer la gestion des erreurs dans le bloc catch (ne pas logger DioException)
|
||||
|
||||
---
|
||||
|
||||
### 🛠️ Pattern à appliquer
|
||||
|
||||
#### ❌ Code à supprimer (ancien pattern)
|
||||
```dart
|
||||
try {
|
||||
final response = await ApiService.instance.put('/endpoint', data: data);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// Traitement succès
|
||||
return true;
|
||||
}
|
||||
|
||||
// ⚠️ Ce code ne sera JAMAIS exécuté
|
||||
if (response.data != null && response.data is Map<String, dynamic>) {
|
||||
final responseData = response.data as Map<String, dynamic>;
|
||||
if (responseData['status'] == 'error') {
|
||||
throw Exception(responseData['message']);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur: $e');
|
||||
rethrow;
|
||||
}
|
||||
```
|
||||
|
||||
#### ✅ Nouveau pattern à utiliser
|
||||
```dart
|
||||
try {
|
||||
final response = await ApiService.instance.put('/endpoint', data: data);
|
||||
|
||||
// Si on arrive ici, la requête a réussi (200/201)
|
||||
// Traitement succès
|
||||
return true;
|
||||
|
||||
} catch (e) {
|
||||
// Log propre sans détails techniques
|
||||
if (e is ApiException) {
|
||||
LoggerService.error('Erreur lors de l\'opération: ${e.message}');
|
||||
} else {
|
||||
LoggerService.error('Erreur lors de l\'opération');
|
||||
}
|
||||
rethrow; // Propager pour affichage UI
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 📦 Imports nécessaires
|
||||
|
||||
Ajouter ces imports dans chaque repository si manquants :
|
||||
|
||||
```dart
|
||||
import 'package:geosector_app/core/services/logger_service.dart';
|
||||
import 'package:geosector_app/core/utils/api_exception.dart';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🧪 Tests de validation
|
||||
|
||||
Pour chaque repository migré, tester :
|
||||
|
||||
1. **Test d'erreur 409 (Conflict)** :
|
||||
- Créer/modifier avec un email déjà existant
|
||||
- Vérifier que le message "Cet email est déjà utilisé" s'affiche
|
||||
|
||||
2. **Test d'erreur 400 (Bad Request)** :
|
||||
- Envoyer des données invalides
|
||||
- Vérifier que le message d'erreur spécifique s'affiche
|
||||
|
||||
3. **Test d'erreur réseau** :
|
||||
- Couper la connexion
|
||||
- Vérifier que "Problème de connexion réseau" s'affiche
|
||||
|
||||
4. **Test de succès** :
|
||||
- Opération normale
|
||||
- Vérifier que tout fonctionne comme avant
|
||||
|
||||
---
|
||||
|
||||
### 📊 Critères de succès
|
||||
|
||||
- [ ] Tous les repositories utilisent le nouveau pattern
|
||||
- [ ] Plus aucun `debugPrint` dans les repositories (remplacé par `LoggerService`)
|
||||
- [ ] Les messages d'erreur spécifiques de l'API s'affichent correctement
|
||||
- [ ] Les logs en production sont désactivés (sauf erreurs)
|
||||
- [ ] Le code est plus simple et maintenable
|
||||
|
||||
---
|
||||
|
||||
### 🔍 Commandes utiles pour vérifier
|
||||
|
||||
```bash
|
||||
# Rechercher les anciens patterns à remplacer
|
||||
grep -r "response.statusCode ==" lib/core/repositories/
|
||||
grep -r "responseData\['status'\] == 'error'" lib/core/repositories/
|
||||
grep -r "debugPrint" lib/core/repositories/
|
||||
|
||||
# Vérifier les imports manquants
|
||||
grep -L "LoggerService" lib/core/repositories/*.dart
|
||||
grep -L "ApiException" lib/core/repositories/*.dart
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 📅 Priorité
|
||||
|
||||
1. **Haute** : UserRepository (utilisé partout)
|
||||
2. **Haute** : OperationRepository (fonctionnalité critique)
|
||||
3. **Moyenne** : PassageRepository (utilisé fréquemment)
|
||||
4. **Moyenne** : AmicaleRepository (gestion administrative)
|
||||
5. **Basse** : SectorRepository (moins critique)
|
||||
|
||||
---
|
||||
|
||||
### 📝 Notes
|
||||
|
||||
- Cette migration améliore l'UX en affichant des messages d'erreur clairs
|
||||
- Le LoggerService désactive automatiquement les logs en production
|
||||
- Le code devient plus maintenable et cohérent
|
||||
- Documenter dans README-APP.md une fois terminé
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Tests unitaires Flutter à implémenter
|
||||
|
||||
### 📁 Structure des tests
|
||||
|
||||
Le dossier `/test` doit contenir des tests unitaires pour valider le comportement de l'application.
|
||||
|
||||
### 📝 Tests prioritaires à créer
|
||||
|
||||
#### 1. **Tests des Repositories** (`test/repositories/`)
|
||||
|
||||
##### `test/repositories/membre_repository_test.dart`
|
||||
- [ ] Test de création d'un membre avec succès
|
||||
- [ ] Test de création avec email déjà existant (409)
|
||||
- [ ] Test de mise à jour d'un membre
|
||||
- [ ] Test de suppression d'un membre
|
||||
- [ ] Test de gestion des erreurs réseau
|
||||
- [ ] Test du cache Hive local
|
||||
|
||||
##### `test/repositories/user_repository_test.dart`
|
||||
- [ ] Test de connexion réussie
|
||||
- [ ] Test de connexion avec mauvais identifiants
|
||||
- [ ] Test de mise à jour du profil utilisateur
|
||||
- [ ] Test de synchronisation des données
|
||||
- [ ] Test de gestion de session
|
||||
|
||||
##### `test/repositories/operation_repository_test.dart`
|
||||
- [ ] Test de création d'opération
|
||||
- [ ] Test d'activation/désactivation
|
||||
- [ ] Test de récupération des opérations par amicale
|
||||
- [ ] Test de suppression avec transfert de passages
|
||||
|
||||
#### 2. **Tests des Services** (`test/services/`)
|
||||
|
||||
##### `test/services/api_service_test.dart`
|
||||
- [ ] Test de détection d'environnement (DEV/REC/PROD)
|
||||
- [ ] Test de gestion des sessions
|
||||
- [ ] Test de conversion DioException vers ApiException
|
||||
- [ ] Test des différents codes d'erreur HTTP
|
||||
- [ ] Test du retry automatique
|
||||
|
||||
##### `test/services/logger_service_test.dart`
|
||||
- [ ] Test de désactivation des logs en PROD
|
||||
- [ ] Test des différents niveaux de log
|
||||
- [ ] Test du formatage des messages
|
||||
|
||||
##### `test/services/hive_service_test.dart`
|
||||
- [ ] Test d'initialisation des boîtes Hive
|
||||
- [ ] Test de sauvegarde et récupération
|
||||
- [ ] Test de suppression de données
|
||||
- [ ] Test de migration de schéma
|
||||
|
||||
#### 3. **Tests des Models** (`test/models/`)
|
||||
|
||||
##### `test/models/membre_model_test.dart`
|
||||
- [ ] Test de sérialisation JSON
|
||||
- [ ] Test de désérialisation JSON
|
||||
- [ ] Test de conversion vers UserModel
|
||||
- [ ] Test des valeurs par défaut
|
||||
|
||||
##### `test/models/amicale_model_test.dart`
|
||||
- [ ] Test de sérialisation/désérialisation
|
||||
- [ ] Test des nouveaux champs booléens (chk_mdp_manuel, chk_username_manuel)
|
||||
- [ ] Test de validation des données
|
||||
|
||||
#### 4. **Tests des Widgets** (`test/widgets/`)
|
||||
|
||||
##### `test/widgets/user_form_test.dart`
|
||||
- [ ] Test d'affichage conditionnel des champs (username/password)
|
||||
- [ ] Test de validation du mot de passe (regex)
|
||||
- [ ] Test de validation de l'username (pas d'espaces)
|
||||
- [ ] Test de génération automatique d'username
|
||||
- [ ] Test du mode création vs modification
|
||||
|
||||
##### `test/widgets/membre_table_widget_test.dart`
|
||||
- [ ] Test d'affichage responsive (mobile vs web)
|
||||
- [ ] Test de masquage des colonnes sur mobile
|
||||
- [ ] Test des icônes de statut
|
||||
- [ ] Test du tri et filtrage
|
||||
|
||||
#### 5. **Tests d'intégration** (`test/integration/`)
|
||||
|
||||
##### `test/integration/auth_flow_test.dart`
|
||||
- [ ] Test du flow complet de connexion
|
||||
- [ ] Test de persistance de session
|
||||
- [ ] Test de déconnexion
|
||||
- [ ] Test de redirection après expiration
|
||||
|
||||
##### `test/integration/membre_management_test.dart`
|
||||
- [ ] Test de création complète d'un membre
|
||||
- [ ] Test de modification avec validation
|
||||
- [ ] Test de suppression avec transfert
|
||||
- [ ] Test de gestion des erreurs
|
||||
|
||||
### 🛠️ Configuration des tests
|
||||
|
||||
#### Fichier `test/test_helpers.dart`
|
||||
```dart
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
|
||||
// Mocks nécessaires
|
||||
class MockDio extends Mock implements Dio {}
|
||||
class MockBox<T> extends Mock implements Box<T> {}
|
||||
class MockApiService extends Mock implements ApiService {}
|
||||
|
||||
// Helper pour initialiser Hive en tests
|
||||
Future<void> setupTestHive() async {
|
||||
await Hive.initFlutter();
|
||||
// Initialiser les boîtes de test
|
||||
}
|
||||
|
||||
// Helper pour nettoyer après les tests
|
||||
Future<void> tearDownTestHive() async {
|
||||
await Hive.deleteFromDisk();
|
||||
}
|
||||
|
||||
// Helper pour créer des données de test
|
||||
class TestDataFactory {
|
||||
static UserModel createTestUser() {
|
||||
return UserModel(
|
||||
id: 1,
|
||||
username: 'test_user',
|
||||
email: 'test@example.com',
|
||||
// ...
|
||||
);
|
||||
}
|
||||
|
||||
static MembreModel createTestMembre() {
|
||||
return MembreModel(
|
||||
id: 1,
|
||||
fkEntite: 100,
|
||||
name: 'Test',
|
||||
firstName: 'User',
|
||||
// ...
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 📋 Commandes de test
|
||||
|
||||
```bash
|
||||
# Lancer tous les tests
|
||||
flutter test
|
||||
|
||||
# Lancer un test spécifique
|
||||
flutter test test/repositories/membre_repository_test.dart
|
||||
|
||||
# Lancer avec coverage
|
||||
flutter test --coverage
|
||||
|
||||
# Générer un rapport HTML de couverture
|
||||
genhtml coverage/lcov.info -o coverage/html
|
||||
open coverage/html/index.html
|
||||
```
|
||||
|
||||
### 🎯 Objectifs de couverture
|
||||
|
||||
- [ ] **Repositories** : 80% minimum
|
||||
- [ ] **Services** : 90% minimum
|
||||
- [ ] **Models** : 95% minimum
|
||||
- [ ] **Widgets critiques** : 70% minimum
|
||||
- [ ] **Couverture globale** : 75% minimum
|
||||
|
||||
### 📚 Dépendances de test à ajouter
|
||||
|
||||
Dans `pubspec.yaml` :
|
||||
```yaml
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
mockito: ^5.4.4
|
||||
build_runner: ^2.4.8
|
||||
test: ^1.25.2
|
||||
flutter_lints: ^4.0.0
|
||||
coverage: ^1.7.2
|
||||
```
|
||||
|
||||
### 🔄 Intégration CI/CD
|
||||
|
||||
Ajouter dans le pipeline CI :
|
||||
```yaml
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- flutter test --coverage
|
||||
- genhtml coverage/lcov.info -o coverage/html
|
||||
artifacts:
|
||||
paths:
|
||||
- coverage/
|
||||
coverage: '/lines\.*: \d+\.\d+\%/'
|
||||
```
|
||||
|
||||
### 📝 Bonnes pratiques
|
||||
|
||||
1. **Isolation** : Chaque test doit être indépendant
|
||||
2. **Mocking** : Utiliser des mocks pour les dépendances externes
|
||||
3. **Nommage** : Utiliser des noms descriptifs (test_should_xxx_when_yyy)
|
||||
4. **AAA** : Suivre le pattern Arrange-Act-Assert
|
||||
5. **Edge cases** : Tester les cas limites et erreurs
|
||||
6. **Performance** : Les tests unitaires doivent être rapides (<100ms)
|
||||
|
||||
---
|
||||
|
||||
## 💬 Module Chat en ligne GEOSECTOR
|
||||
|
||||
### 📋 Vue d'ensemble
|
||||
|
||||
Le module chat est partiellement implémenté avec une architecture MQTT pour les notifications en temps réel. Il nécessite des développements supplémentaires pour être pleinement fonctionnel.
|
||||
|
||||
### 🏗️ Architecture existante
|
||||
|
||||
```
|
||||
lib/chat/
|
||||
├── models/ # ✅ Modèles créés avec Hive
|
||||
│ ├── conversation_model.dart # Conversations (one-to-one, groupe, annonce)
|
||||
│ ├── message_model.dart # Messages avec pièces jointes
|
||||
│ ├── participant_model.dart # Participants aux conversations
|
||||
│ └── audience_target_model.dart # Cibles pour les annonces
|
||||
├── repositories/ # ⚠️ À compléter
|
||||
│ └── chat_repository.dart # Logique métier du chat
|
||||
├── services/ # ⚠️ Partiellement implémenté
|
||||
│ ├── chat_api_service.dart # Communication avec l'API
|
||||
│ ├── offline_queue_service.dart # File d'attente hors ligne
|
||||
│ └── notifications/ # 🔧 MQTT configuré
|
||||
│ ├── mqtt_notification_service.dart
|
||||
│ └── mqtt_config.dart
|
||||
├── widgets/ # ⚠️ À implémenter
|
||||
│ ├── chat_screen.dart # Écran principal du chat
|
||||
│ ├── conversations_list.dart # Liste des conversations
|
||||
│ ├── message_bubble.dart # Bulles de messages
|
||||
│ └── chat_input.dart # Zone de saisie
|
||||
└── pages/ # ⚠️ À compléter
|
||||
└── chat_page.dart # Page principale
|
||||
```
|
||||
|
||||
### 📝 Tâches de développement Chat
|
||||
|
||||
#### 1. **Finalisation des modèles Hive**
|
||||
- [ ] Compléter les adaptateurs Hive pour tous les modèles
|
||||
- [ ] Ajouter la gestion des pièces jointes (images, documents)
|
||||
- [ ] Implémenter le modèle `AnonymousUserModel` pour les utilisateurs temporaires
|
||||
- [ ] Ajouter les timestamps et statuts de lecture
|
||||
|
||||
#### 2. **Repository ChatRepository**
|
||||
- [ ] Implémenter `createConversation()` avec participants
|
||||
- [ ] Implémenter `sendMessage()` avec queue hors ligne
|
||||
- [ ] Implémenter `getConversations()` avec pagination
|
||||
- [ ] Implémenter `getMessages()` avec lazy loading
|
||||
- [ ] Ajouter la gestion des participants (ajout/suppression)
|
||||
- [ ] Implémenter les annonces ciblées par groupe
|
||||
|
||||
#### 3. **Services**
|
||||
- [ ] Compléter `ChatApiService` avec endpoints REST
|
||||
- [ ] Implémenter la synchronisation bidirectionnelle
|
||||
- [ ] Configurer `OfflineQueueService` pour messages en attente
|
||||
- [ ] Implémenter le retry automatique avec exponential backoff
|
||||
- [ ] Ajouter la compression des images avant envoi
|
||||
|
||||
#### 4. **Notifications MQTT**
|
||||
- [ ] Installer et configurer Mosquitto dans le container Incus
|
||||
- [ ] Configurer SSL/TLS pour MQTT (port 8883)
|
||||
- [ ] Implémenter l'authentification par token JWT
|
||||
- [ ] Créer les topics par utilisateur/groupe/conversation
|
||||
- [ ] Implémenter le système de présence (online/offline/typing)
|
||||
- [ ] Ajouter les ACLs pour sécuriser les topics
|
||||
|
||||
#### 5. **Interface utilisateur**
|
||||
- [ ] Créer `ChatScreen` avec liste de messages
|
||||
- [ ] Implémenter `ConversationsList` avec badges non-lus
|
||||
- [ ] Designer `MessageBubble` (texte, images, documents)
|
||||
- [ ] Créer `ChatInput` avec:
|
||||
- [ ] Saisie de texte avec emoji picker
|
||||
- [ ] Bouton d'envoi de fichiers
|
||||
- [ ] Indicateur "en train d'écrire"
|
||||
- [ ] Enregistrement vocal (optionnel)
|
||||
- [ ] Ajouter les animations (apparition messages, typing indicator)
|
||||
- [ ] Implémenter le swipe pour répondre
|
||||
- [ ] Ajouter la recherche dans les conversations
|
||||
|
||||
#### 6. **Fonctionnalités avancées**
|
||||
- [ ] Notifications push locales via `flutter_local_notifications`
|
||||
- [ ] Chiffrement end-to-end des messages sensibles
|
||||
- [ ] Réactions aux messages (emojis)
|
||||
- [ ] Messages éphémères avec auto-suppression
|
||||
- [ ] Partage de localisation en temps réel
|
||||
- [ ] Appels audio/vidéo via WebRTC (phase 2)
|
||||
|
||||
### 🔧 Configuration backend requise
|
||||
|
||||
#### Base de données
|
||||
```sql
|
||||
-- Tables à créer (voir chat_tables.sql)
|
||||
CREATE TABLE chat_conversations (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
type ENUM('one_to_one', 'group', 'announcement'),
|
||||
created_by INT,
|
||||
created_at TIMESTAMP,
|
||||
updated_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE chat_messages (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
conversation_id INT,
|
||||
sender_id INT,
|
||||
content TEXT,
|
||||
type ENUM('text', 'image', 'file', 'location'),
|
||||
status ENUM('sent', 'delivered', 'read'),
|
||||
created_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE chat_participants (
|
||||
conversation_id INT,
|
||||
user_id INT,
|
||||
role ENUM('admin', 'member'),
|
||||
joined_at TIMESTAMP,
|
||||
last_read_message_id INT
|
||||
);
|
||||
```
|
||||
|
||||
#### Configuration MQTT
|
||||
```bash
|
||||
# Installation Mosquitto
|
||||
apt-get install mosquitto mosquitto-clients
|
||||
|
||||
# Configuration /etc/mosquitto/mosquitto.conf
|
||||
listener 1883
|
||||
listener 8883
|
||||
cafile /etc/mosquitto/ca.crt
|
||||
certfile /etc/mosquitto/server.crt
|
||||
keyfile /etc/mosquitto/server.key
|
||||
allow_anonymous false
|
||||
password_file /etc/mosquitto/passwd
|
||||
```
|
||||
|
||||
### 📦 Dépendances à ajouter
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
# MQTT et notifications
|
||||
mqtt5_client: ^4.0.0
|
||||
flutter_local_notifications: ^17.0.0
|
||||
|
||||
# UI et UX
|
||||
emoji_picker_flutter: ^2.0.0
|
||||
cached_network_image: ^3.3.1
|
||||
photo_view: ^0.14.0
|
||||
file_picker: ^6.1.1
|
||||
|
||||
# Utilitaires
|
||||
path_provider: ^2.1.2
|
||||
image_picker: ^1.0.7
|
||||
image: ^4.1.7 # Pour compression
|
||||
intl: ^0.19.0 # Pour formatage dates
|
||||
```
|
||||
|
||||
### 🧪 Tests à implémenter
|
||||
- [ ] Tests unitaires des repositories
|
||||
- [ ] Tests d'intégration MQTT
|
||||
- [ ] Tests de performance (1000+ messages)
|
||||
- [ ] Tests hors ligne/online
|
||||
- [ ] Tests de sécurité (injection, XSS)
|
||||
|
||||
---
|
||||
|
||||
## 💳 Module de paiement Stripe
|
||||
|
||||
### 📋 Vue d'ensemble
|
||||
|
||||
Intégration de Stripe pour permettre aux amicales ayant activé `chk_stripe` d'accepter les paiements par carte bancaire avec une commission de 1.4%.
|
||||
|
||||
### 🎯 Objectifs
|
||||
|
||||
1. Permettre le paiement en ligne lors des passages
|
||||
2. Gérer les comptes Stripe des amicales
|
||||
3. Suivre les transactions et commissions
|
||||
4. Offrir une expérience de paiement fluide
|
||||
|
||||
### 📝 Tâches de développement Stripe
|
||||
|
||||
#### 1. **Configuration initiale Stripe**
|
||||
- [ ] Créer un compte Stripe Connect Platform
|
||||
- [ ] Configurer les webhooks Stripe
|
||||
- [ ] Mettre en place l'environnement de test (sandbox)
|
||||
- [ ] Configurer les clés API (publishable/secret)
|
||||
- [ ] Implémenter la gestion sécurisée des clés
|
||||
|
||||
#### 2. **Onboarding des amicales**
|
||||
- [ ] Créer un workflow d'inscription Stripe pour les amicales
|
||||
- [ ] Implémenter Stripe Connect Onboarding
|
||||
- [ ] Gérer le KYC (Know Your Customer) requis par Stripe
|
||||
- [ ] Stocker de manière sécurisée le `stripe_account_id`
|
||||
- [ ] Créer une page de statut du compte Stripe
|
||||
- [ ] Gérer les documents requis (RIB, statuts, etc.)
|
||||
|
||||
#### 3. **Modèles de données**
|
||||
- [ ] Créer `StripeAccountModel` pour les comptes Connect
|
||||
- [ ] Créer `PaymentIntentModel` pour les intentions de paiement
|
||||
- [ ] Créer `TransactionModel` pour l'historique
|
||||
- [ ] Ajouter les champs Stripe dans `PassageModel`
|
||||
- [ ] Implémenter la table des commissions
|
||||
|
||||
#### 4. **Service StripeService**
|
||||
```dart
|
||||
class StripeService {
|
||||
// Compte Connect
|
||||
Future<String> createConnectAccount(AmicaleModel amicale);
|
||||
Future<void> updateAccountStatus(String accountId);
|
||||
Future<String> createAccountLink(String accountId);
|
||||
|
||||
// Paiements
|
||||
Future<PaymentIntent> createPaymentIntent({
|
||||
required double amount,
|
||||
required String currency,
|
||||
required String connectedAccountId,
|
||||
});
|
||||
|
||||
Future<void> confirmPayment(String paymentIntentId);
|
||||
Future<void> refundPayment(String paymentIntentId);
|
||||
|
||||
// Commissions
|
||||
double calculateApplicationFee(double amount); // 1.4%
|
||||
}
|
||||
```
|
||||
|
||||
#### 5. **Interface de paiement dans PassageForm**
|
||||
- [ ] Détecter si l'amicale accepte Stripe (`chk_stripe`)
|
||||
- [ ] Ajouter l'option "Paiement par carte" dans le dropdown
|
||||
- [ ] Intégrer Stripe Elements pour la saisie de carte
|
||||
- [ ] Implémenter le flow de paiement 3D Secure
|
||||
- [ ] Gérer les erreurs de paiement
|
||||
- [ ] Afficher le reçu de paiement
|
||||
- [ ] Permettre l'envoi du reçu par email
|
||||
|
||||
#### 6. **Widget StripePaymentSheet**
|
||||
```dart
|
||||
class StripePaymentSheet extends StatefulWidget {
|
||||
final double amount;
|
||||
final String currency;
|
||||
final AmicaleModel amicale;
|
||||
final Function(String) onSuccess;
|
||||
final Function(String) onError;
|
||||
|
||||
// UI avec:
|
||||
// - Montant à payer
|
||||
// - Formulaire de carte (Stripe Elements)
|
||||
// - Bouton de validation
|
||||
// - Indicateur de traitement
|
||||
// - Gestion 3D Secure
|
||||
}
|
||||
```
|
||||
|
||||
#### 7. **Tableau de bord financier**
|
||||
- [ ] Page de suivi des transactions Stripe
|
||||
- [ ] Graphiques des paiements par période
|
||||
- [ ] Export des transactions (CSV/Excel)
|
||||
- [ ] Calcul automatique des commissions
|
||||
- [ ] Rapprochement bancaire
|
||||
- [ ] Dashboard temps réel des paiements
|
||||
|
||||
#### 8. **Webhooks Stripe**
|
||||
```php
|
||||
// Backend PHP pour gérer les webhooks
|
||||
class StripeWebhookHandler {
|
||||
// Events à gérer:
|
||||
- payment_intent.succeeded
|
||||
- payment_intent.failed
|
||||
- account.updated
|
||||
- payout.created
|
||||
- refund.created
|
||||
}
|
||||
```
|
||||
|
||||
#### 9. **Sécurité**
|
||||
- [ ] Chiffrement des données sensibles
|
||||
- [ ] Validation PCI DSS
|
||||
- [ ] Audit trail des transactions
|
||||
- [ ] Détection de fraude
|
||||
- [ ] Rate limiting sur les API
|
||||
- [ ] Tokenisation des cartes
|
||||
|
||||
#### 10. **Tests et conformité**
|
||||
- [ ] Tests avec cartes de test Stripe
|
||||
- [ ] Tests des cas d'erreur (carte refusée, etc.)
|
||||
- [ ] Tests 3D Secure
|
||||
- [ ] Tests de performance
|
||||
- [ ] Conformité RGPD pour les données de paiement
|
||||
- [ ] Documentation utilisateur
|
||||
|
||||
### 🔧 Configuration backend requise
|
||||
|
||||
#### Tables base de données
|
||||
```sql
|
||||
CREATE TABLE stripe_accounts (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
fk_entite INT NOT NULL,
|
||||
stripe_account_id VARCHAR(255) ENCRYPTED,
|
||||
status ENUM('pending', 'active', 'restricted'),
|
||||
charges_enabled BOOLEAN DEFAULT FALSE,
|
||||
payouts_enabled BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP,
|
||||
updated_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE stripe_transactions (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
fk_passage INT,
|
||||
stripe_payment_intent_id VARCHAR(255),
|
||||
amount DECIMAL(10,2),
|
||||
currency VARCHAR(3),
|
||||
status VARCHAR(50),
|
||||
application_fee DECIMAL(10,2),
|
||||
created_at TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
#### Variables d'environnement
|
||||
```env
|
||||
STRIPE_PUBLISHABLE_KEY=pk_test_xxx
|
||||
STRIPE_SECRET_KEY=sk_test_xxx
|
||||
STRIPE_WEBHOOK_SECRET=whsec_xxx
|
||||
STRIPE_APPLICATION_FEE_PERCENT=1.4
|
||||
```
|
||||
|
||||
### 📦 Dépendances Stripe
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
# Stripe
|
||||
flutter_stripe: ^10.1.1
|
||||
|
||||
# Sécurité
|
||||
flutter_secure_storage: ^9.0.0
|
||||
|
||||
# UI
|
||||
shimmer: ^3.0.0 # Loading states
|
||||
lottie: ^3.1.0 # Animations succès/échec
|
||||
```
|
||||
|
||||
### 🚀 Roadmap d'implémentation
|
||||
|
||||
**Phase 1 (2 semaines)**
|
||||
- Configuration Stripe Connect
|
||||
- Onboarding basique des amicales
|
||||
- Tests en sandbox
|
||||
|
||||
**Phase 2 (3 semaines)**
|
||||
- Intégration dans PassageForm
|
||||
- Gestion des paiements simples
|
||||
- Webhooks essentiels
|
||||
|
||||
**Phase 3 (2 semaines)**
|
||||
- Dashboard financier
|
||||
- Export et rapports
|
||||
- Tests complets
|
||||
|
||||
**Phase 4 (1 semaine)**
|
||||
- Mise en production
|
||||
- Monitoring
|
||||
- Documentation
|
||||
|
||||
### 💰 Estimation des coûts
|
||||
|
||||
- **Stripe Connect** : 0.25€ par compte actif/mois
|
||||
- **Transactions** : 1.4% + 0.25€ par transaction
|
||||
- **Commission application** : 1.4% (reversée à GEOSECTOR)
|
||||
- **Coût net pour l'amicale** : ~2.8% + 0.25€ par transaction
|
||||
|
||||
---
|
||||
|
||||
**Date de création** : 2025-08-07
|
||||
**Auteur** : Architecture Team
|
||||
**Version** : 1.2.0
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:geosector_app/core/theme/app_theme.dart';
|
||||
import 'package:geosector_app/core/services/theme_service.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
@@ -44,6 +45,17 @@ class GeosectorApp extends StatelessWidget {
|
||||
themeMode: themeService.themeMode,
|
||||
routerConfig: _createRouter(),
|
||||
debugShowCheckedModeBanner: false,
|
||||
// Configuration des localisations pour le français
|
||||
localizationsDelegates: const [
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [
|
||||
Locale('fr', 'FR'), // Français comme langue principale
|
||||
Locale('en', 'US'), // Anglais en fallback
|
||||
],
|
||||
locale: const Locale('fr', 'FR'), // Forcer le français par défaut
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -70,6 +70,15 @@ class AmicaleModel extends HiveObject {
|
||||
@HiveField(21)
|
||||
final DateTime? updatedAt;
|
||||
|
||||
@HiveField(22)
|
||||
final bool chkMdpManuel;
|
||||
|
||||
@HiveField(23)
|
||||
final bool chkUsernameManuel;
|
||||
|
||||
@HiveField(24)
|
||||
final String? logoBase64; // Logo en base64 (data:image/png;base64,...)
|
||||
|
||||
AmicaleModel({
|
||||
required this.id,
|
||||
required this.name,
|
||||
@@ -93,6 +102,9 @@ class AmicaleModel extends HiveObject {
|
||||
this.chkStripe = false,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.chkMdpManuel = false,
|
||||
this.chkUsernameManuel = false,
|
||||
this.logoBase64,
|
||||
});
|
||||
|
||||
// Factory pour convertir depuis JSON (API)
|
||||
@@ -123,6 +135,17 @@ class AmicaleModel extends HiveObject {
|
||||
json['chk_active'] == 1 || json['chk_active'] == true;
|
||||
final bool chkStripe =
|
||||
json['chk_stripe'] == 1 || json['chk_stripe'] == true;
|
||||
final bool chkMdpManuel =
|
||||
json['chk_mdp_manuel'] == 1 || json['chk_mdp_manuel'] == true;
|
||||
final bool chkUsernameManuel =
|
||||
json['chk_username_manuel'] == 1 || json['chk_username_manuel'] == true;
|
||||
|
||||
// Traiter le logo si présent
|
||||
String? logoBase64;
|
||||
if (json['logo'] != null && json['logo'] is Map) {
|
||||
final logoData = json['logo'] as Map<String, dynamic>;
|
||||
logoBase64 = logoData['data_url'] as String?;
|
||||
}
|
||||
|
||||
// Traiter les dates si présentes
|
||||
DateTime? createdAt;
|
||||
@@ -166,6 +189,9 @@ class AmicaleModel extends HiveObject {
|
||||
chkStripe: chkStripe,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
chkMdpManuel: chkMdpManuel,
|
||||
chkUsernameManuel: chkUsernameManuel,
|
||||
logoBase64: logoBase64,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -194,6 +220,9 @@ class AmicaleModel extends HiveObject {
|
||||
'chk_stripe': chkStripe ? 1 : 0,
|
||||
'created_at': createdAt?.toIso8601String(),
|
||||
'updated_at': updatedAt?.toIso8601String(),
|
||||
'chk_mdp_manuel': chkMdpManuel ? 1 : 0,
|
||||
'chk_username_manuel': chkUsernameManuel ? 1 : 0,
|
||||
// Note: logoBase64 n'est pas envoyé via toJson (lecture seule depuis l'API)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -220,6 +249,9 @@ class AmicaleModel extends HiveObject {
|
||||
bool? chkStripe,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
bool? chkMdpManuel,
|
||||
bool? chkUsernameManuel,
|
||||
String? logoBase64,
|
||||
}) {
|
||||
return AmicaleModel(
|
||||
id: id,
|
||||
@@ -244,6 +276,9 @@ class AmicaleModel extends HiveObject {
|
||||
chkStripe: chkStripe ?? this.chkStripe,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
chkMdpManuel: chkMdpManuel ?? this.chkMdpManuel,
|
||||
chkUsernameManuel: chkUsernameManuel ?? this.chkUsernameManuel,
|
||||
logoBase64: logoBase64 ?? this.logoBase64,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,13 +39,16 @@ class AmicaleModelAdapter extends TypeAdapter<AmicaleModel> {
|
||||
chkStripe: fields[19] as bool,
|
||||
createdAt: fields[20] as DateTime?,
|
||||
updatedAt: fields[21] as DateTime?,
|
||||
chkMdpManuel: fields[22] as bool,
|
||||
chkUsernameManuel: fields[23] as bool,
|
||||
logoBase64: fields[24] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, AmicaleModel obj) {
|
||||
writer
|
||||
..writeByte(22)
|
||||
..writeByte(25)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
@@ -89,7 +92,13 @@ class AmicaleModelAdapter extends TypeAdapter<AmicaleModel> {
|
||||
..writeByte(20)
|
||||
..write(obj.createdAt)
|
||||
..writeByte(21)
|
||||
..write(obj.updatedAt);
|
||||
..write(obj.updatedAt)
|
||||
..writeByte(22)
|
||||
..write(obj.chkMdpManuel)
|
||||
..writeByte(23)
|
||||
..write(obj.chkUsernameManuel)
|
||||
..writeByte(24)
|
||||
..write(obj.logoBase64);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -70,6 +70,12 @@ class ClientModel extends HiveObject {
|
||||
@HiveField(21)
|
||||
final DateTime? updatedAt;
|
||||
|
||||
@HiveField(22)
|
||||
final bool? chkMdpManuel;
|
||||
|
||||
@HiveField(23)
|
||||
final bool? chkUsernameManuel;
|
||||
|
||||
ClientModel({
|
||||
required this.id,
|
||||
required this.name,
|
||||
@@ -93,6 +99,8 @@ class ClientModel extends HiveObject {
|
||||
this.chkStripe,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.chkMdpManuel,
|
||||
this.chkUsernameManuel,
|
||||
});
|
||||
|
||||
// Factory pour convertir depuis JSON (API)
|
||||
@@ -138,6 +146,8 @@ class ClientModel extends HiveObject {
|
||||
chkStripe: json['chk_stripe'] == 1 || json['chk_stripe'] == true,
|
||||
createdAt: json['created_at'] != null ? DateTime.parse(json['created_at']) : null,
|
||||
updatedAt: json['updated_at'] != null ? DateTime.parse(json['updated_at']) : null,
|
||||
chkMdpManuel: json['chk_mdp_manuel'] == 1 || json['chk_mdp_manuel'] == true,
|
||||
chkUsernameManuel: json['chk_username_manuel'] == 1 || json['chk_username_manuel'] == true,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -166,6 +176,8 @@ class ClientModel extends HiveObject {
|
||||
'chk_stripe': chkStripe,
|
||||
'created_at': createdAt?.toIso8601String(),
|
||||
'updated_at': updatedAt?.toIso8601String(),
|
||||
'chk_mdp_manuel': chkMdpManuel,
|
||||
'chk_username_manuel': chkUsernameManuel,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -192,6 +204,8 @@ class ClientModel extends HiveObject {
|
||||
bool? chkStripe,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
bool? chkMdpManuel,
|
||||
bool? chkUsernameManuel,
|
||||
}) {
|
||||
return ClientModel(
|
||||
id: id,
|
||||
@@ -216,6 +230,8 @@ class ClientModel extends HiveObject {
|
||||
chkStripe: chkStripe ?? this.chkStripe,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
chkMdpManuel: chkMdpManuel ?? this.chkMdpManuel,
|
||||
chkUsernameManuel: chkUsernameManuel ?? this.chkUsernameManuel,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,13 +39,15 @@ class ClientModelAdapter extends TypeAdapter<ClientModel> {
|
||||
chkStripe: fields[19] as bool?,
|
||||
createdAt: fields[20] as DateTime?,
|
||||
updatedAt: fields[21] as DateTime?,
|
||||
chkMdpManuel: fields[22] as bool?,
|
||||
chkUsernameManuel: fields[23] as bool?,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, ClientModel obj) {
|
||||
writer
|
||||
..writeByte(22)
|
||||
..writeByte(24)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
@@ -89,7 +91,11 @@ class ClientModelAdapter extends TypeAdapter<ClientModel> {
|
||||
..writeByte(20)
|
||||
..write(obj.createdAt)
|
||||
..writeByte(21)
|
||||
..write(obj.updatedAt);
|
||||
..write(obj.updatedAt)
|
||||
..writeByte(22)
|
||||
..write(obj.chkMdpManuel)
|
||||
..writeByte(23)
|
||||
..write(obj.chkUsernameManuel);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -3,6 +3,8 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:geosector_app/core/data/models/membre_model.dart';
|
||||
import 'package:geosector_app/core/services/api_service.dart';
|
||||
import 'package:geosector_app/core/services/logger_service.dart';
|
||||
import 'package:geosector_app/core/utils/api_exception.dart';
|
||||
import 'package:geosector_app/core/constants/app_keys.dart';
|
||||
|
||||
class MembreRepository extends ChangeNotifier {
|
||||
@@ -19,7 +21,7 @@ class MembreRepository extends ChangeNotifier {
|
||||
throw Exception('La boîte ${AppKeys.membresBoxName} n\'est pas ouverte. Initialisez d\'abord l\'application.');
|
||||
}
|
||||
_cachedMembreBox = Hive.box<MembreModel>(AppKeys.membresBoxName);
|
||||
debugPrint('MembreRepository: Box ${AppKeys.membresBoxName} mise en cache');
|
||||
LoggerService.database('MembreRepository: Box ${AppKeys.membresBoxName} mise en cache');
|
||||
}
|
||||
return _cachedMembreBox!;
|
||||
}
|
||||
@@ -120,7 +122,7 @@ class MembreRepository extends ChangeNotifier {
|
||||
// === MÉTHODES API ===
|
||||
|
||||
// Créer un membre via l'API
|
||||
Future<MembreModel?> createMembre(MembreModel membre) async {
|
||||
Future<MembreModel?> createMembre(MembreModel membre, {String? password}) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
@@ -130,48 +132,97 @@ class MembreRepository extends ChangeNotifier {
|
||||
final data = userModel.toJson();
|
||||
data.remove('id'); // L'API génère l'ID
|
||||
data.remove('created_at'); // L'API génère created_at
|
||||
// Supprimer les champs de session qui ne doivent pas être envoyés
|
||||
data.remove('session_id');
|
||||
data.remove('session_expiry');
|
||||
data.remove('last_path');
|
||||
|
||||
// Convertir is_active en chk_active pour l'API
|
||||
if (data.containsKey('is_active')) {
|
||||
data['chk_active'] = data['is_active'] ? 1 : 0;
|
||||
data.remove('is_active');
|
||||
}
|
||||
|
||||
// Convertir role en fk_role pour l'API
|
||||
if (data.containsKey('role')) {
|
||||
data['fk_role'] = data['role'];
|
||||
data.remove('role');
|
||||
}
|
||||
|
||||
// Ajouter le mot de passe si fourni (sera ignoré par l'API si chk_mdp_manuel=0)
|
||||
if (password != null && password.isNotEmpty) {
|
||||
data['password'] = password;
|
||||
debugPrint('🔑 Mot de passe inclus dans la requête');
|
||||
} else {
|
||||
debugPrint('⚠️ Pas de mot de passe fourni');
|
||||
}
|
||||
|
||||
// Vérifier la présence de l'username (sera ignoré par l'API si chk_username_manuel=0)
|
||||
if (data.containsKey('username') && data['username'] != null && data['username'].toString().isNotEmpty) {
|
||||
debugPrint('👤 Username inclus dans la requête: ${data['username']}');
|
||||
} else {
|
||||
debugPrint('⚠️ Username manquant ou vide dans la requête');
|
||||
// Si pas d'username, s'assurer qu'il n'est pas envoyé du tout
|
||||
data.remove('username');
|
||||
}
|
||||
|
||||
LoggerService.api('Données envoyées à l\'API pour création membre: $data');
|
||||
|
||||
// Appeler l'API users
|
||||
final response = await ApiService.instance.post('/users', data: data);
|
||||
|
||||
if (response.statusCode == 201) {
|
||||
// Extraire l'ID de la réponse API
|
||||
final responseData = response.data;
|
||||
debugPrint('🎉 Réponse API création utilisateur: $responseData');
|
||||
// Vérifier d'abord si on a une réponse avec un statut d'erreur
|
||||
if (response.data != null && response.data is Map<String, dynamic>) {
|
||||
final responseData = response.data as Map<String, dynamic>;
|
||||
|
||||
// Si l'API retourne un status error, propager le message
|
||||
if (responseData['status'] == 'error' && responseData['message'] != null) {
|
||||
throw Exception(responseData['message']);
|
||||
}
|
||||
|
||||
// Si succès avec code 201
|
||||
if (response.statusCode == 201 && responseData['status'] == 'success') {
|
||||
debugPrint('🎉 Réponse API création utilisateur: $responseData');
|
||||
|
||||
// L'API retourne {"status":"success","message":"Utilisateur créé avec succès","id":"10027748"}
|
||||
final userId = responseData['id'] is String ? int.parse(responseData['id']) : responseData['id'] as int;
|
||||
// L'API retourne {"status":"success","message":"Utilisateur créé avec succès","id":"10027748"}
|
||||
final userId = responseData['id'] is String ? int.parse(responseData['id']) : responseData['id'] as int;
|
||||
|
||||
// Créer le nouveau membre avec l'ID retourné par l'API
|
||||
final createdMember = MembreModel(
|
||||
id: userId,
|
||||
fkEntite: membre.fkEntite,
|
||||
role: membre.role,
|
||||
fkTitre: membre.fkTitre,
|
||||
name: membre.name,
|
||||
firstName: membre.firstName,
|
||||
username: membre.username,
|
||||
sectName: membre.sectName,
|
||||
email: membre.email,
|
||||
phone: membre.phone,
|
||||
mobile: membre.mobile,
|
||||
dateNaissance: membre.dateNaissance,
|
||||
dateEmbauche: membre.dateEmbauche,
|
||||
createdAt: DateTime.now(),
|
||||
isActive: membre.isActive,
|
||||
);
|
||||
// Créer le nouveau membre avec l'ID retourné par l'API
|
||||
final createdMember = MembreModel(
|
||||
id: userId,
|
||||
fkEntite: membre.fkEntite,
|
||||
role: membre.role,
|
||||
fkTitre: membre.fkTitre,
|
||||
name: membre.name,
|
||||
firstName: membre.firstName,
|
||||
username: membre.username,
|
||||
sectName: membre.sectName,
|
||||
email: membre.email,
|
||||
phone: membre.phone,
|
||||
mobile: membre.mobile,
|
||||
dateNaissance: membre.dateNaissance,
|
||||
dateEmbauche: membre.dateEmbauche,
|
||||
createdAt: DateTime.now(),
|
||||
isActive: membre.isActive,
|
||||
);
|
||||
|
||||
// Sauvegarder localement dans Hive (saveMembreBox gère déjà _resetCache)
|
||||
await saveMembreBox(createdMember);
|
||||
// Sauvegarder localement dans Hive (saveMembreBox gère déjà _resetCache)
|
||||
await saveMembreBox(createdMember);
|
||||
|
||||
debugPrint('✅ Membre créé avec l\'ID: $userId et sauvegardé localement');
|
||||
return createdMember;
|
||||
debugPrint('✅ Membre créé avec l\'ID: $userId et sauvegardé localement');
|
||||
return createdMember;
|
||||
}
|
||||
}
|
||||
|
||||
debugPrint('❌ Échec création membre - Code: ${response.statusCode}');
|
||||
return null;
|
||||
LoggerService.error('Échec création membre - Code: ${response.statusCode}');
|
||||
throw Exception('Erreur lors de la création du membre');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur lors de la création du membre: $e');
|
||||
// Ne pas logger les détails techniques de DioException
|
||||
if (e is ApiException) {
|
||||
LoggerService.error('Erreur lors de la création du membre: ${e.message}');
|
||||
} else {
|
||||
LoggerService.error('Erreur lors de la création du membre');
|
||||
}
|
||||
rethrow; // Propager l'exception pour la gestion d'erreurs
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
@@ -180,27 +231,67 @@ class MembreRepository extends ChangeNotifier {
|
||||
}
|
||||
|
||||
// Mettre à jour un membre via l'API
|
||||
Future<bool> updateMembre(MembreModel membre) async {
|
||||
Future<bool> updateMembre(MembreModel membre, {String? password}) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
// Convertir en UserModel pour l'API
|
||||
final userModel = membre.toUserModel();
|
||||
final data = userModel.toJson();
|
||||
// Supprimer les champs de session qui ne doivent pas être envoyés
|
||||
data.remove('session_id');
|
||||
data.remove('session_expiry');
|
||||
data.remove('last_path');
|
||||
|
||||
// Convertir is_active en chk_active pour l'API
|
||||
if (data.containsKey('is_active')) {
|
||||
data['chk_active'] = data['is_active'] ? 1 : 0;
|
||||
data.remove('is_active');
|
||||
}
|
||||
|
||||
// Convertir role en fk_role pour l'API
|
||||
if (data.containsKey('role')) {
|
||||
data['fk_role'] = data['role'];
|
||||
data.remove('role');
|
||||
}
|
||||
|
||||
// Ajouter le mot de passe si fourni (sera ignoré par l'API si chk_mdp_manuel=0)
|
||||
if (password != null && password.isNotEmpty) {
|
||||
data['password'] = password;
|
||||
debugPrint('🔑 Mot de passe inclus dans la requête de mise à jour');
|
||||
} else {
|
||||
debugPrint('⚠️ Pas de mot de passe fourni pour la mise à jour');
|
||||
}
|
||||
|
||||
// L'username ne devrait pas être modifiable en update, mais on le garde pour l'API
|
||||
if (data.containsKey('username') && data['username'] != null && data['username'].toString().isNotEmpty) {
|
||||
debugPrint('👤 Username présent dans la requête de mise à jour: ${data['username']}');
|
||||
} else {
|
||||
debugPrint('⚠️ Username manquant dans la requête de mise à jour');
|
||||
}
|
||||
|
||||
LoggerService.api('Données envoyées à l\'API pour mise à jour membre: $data');
|
||||
|
||||
// Appeler l'API users au lieu de membres
|
||||
final response = await ApiService.instance.put('/users/${membre.id}', data: userModel.toJson());
|
||||
final response = await ApiService.instance.put('/users/${membre.id}', data: data);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// Sauvegarder le membre mis à jour localement
|
||||
await saveMembreBox(membre);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// Si on arrive ici, c'est que la requête a réussi (200)
|
||||
// Sauvegarder le membre mis à jour localement
|
||||
await saveMembreBox(membre);
|
||||
return true;
|
||||
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la mise à jour du membre: $e');
|
||||
return false;
|
||||
// Ne pas logger les détails techniques de DioException
|
||||
if (e is ApiException) {
|
||||
LoggerService.error('Erreur lors de la mise à jour du membre: ${e.message}');
|
||||
} else {
|
||||
LoggerService.error('Erreur lors de la mise à jour du membre');
|
||||
}
|
||||
|
||||
// Si c'est une DioException, elle sera automatiquement convertie en ApiException
|
||||
// par ApiException.fromDioException() qui extrait le message de l'API
|
||||
rethrow; // Propager l'exception pour que le message d'erreur soit affiché
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
@@ -215,13 +306,26 @@ class MembreRepository extends ChangeNotifier {
|
||||
try {
|
||||
final response = await ApiService.instance.post('/users/$membreId/reset-password');
|
||||
|
||||
// Vérifier si on a une réponse avec un statut d'erreur
|
||||
if (response.data != null && response.data is Map<String, dynamic>) {
|
||||
final responseData = response.data as Map<String, dynamic>;
|
||||
if (responseData['status'] == 'error' && responseData['message'] != null) {
|
||||
throw Exception(responseData['message']);
|
||||
}
|
||||
}
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
throw Exception('Erreur lors de la réinitialisation du mot de passe');
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la réinitialisation du mot de passe: $e');
|
||||
// Ne pas logger les détails techniques de DioException
|
||||
if (e is ApiException) {
|
||||
LoggerService.error('Erreur lors de la réinitialisation du mot de passe: ${e.message}');
|
||||
} else {
|
||||
LoggerService.error('Erreur lors de la réinitialisation du mot de passe');
|
||||
}
|
||||
rethrow;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
@@ -254,19 +358,32 @@ class MembreRepository extends ChangeNotifier {
|
||||
endpoint += '?${queryParams.join('&')}';
|
||||
}
|
||||
|
||||
debugPrint('🔗 DELETE endpoint: $endpoint');
|
||||
LoggerService.api('DELETE endpoint: $endpoint');
|
||||
|
||||
final response = await ApiService.instance.delete(endpoint);
|
||||
|
||||
// Vérifier si on a une réponse avec un statut d'erreur
|
||||
if (response.data != null && response.data is Map<String, dynamic>) {
|
||||
final responseData = response.data as Map<String, dynamic>;
|
||||
if (responseData['status'] == 'error' && responseData['message'] != null) {
|
||||
throw Exception(responseData['message']);
|
||||
}
|
||||
}
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 204) {
|
||||
// Supprimer le membre localement
|
||||
await deleteMembreBox(membreId);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
throw Exception('Erreur lors de la suppression du membre');
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la suppression du membre: $e');
|
||||
// Ne pas logger les détails techniques de DioException
|
||||
if (e is ApiException) {
|
||||
LoggerService.error('Erreur lors de la suppression du membre: ${e.message}');
|
||||
} else {
|
||||
LoggerService.error('Erreur lors de la suppression du membre');
|
||||
}
|
||||
rethrow;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
|
||||
@@ -15,12 +15,10 @@ import 'package:geosector_app/core/data/models/operation_model.dart';
|
||||
import 'package:geosector_app/core/data/models/sector_model.dart';
|
||||
import 'package:geosector_app/core/data/models/passage_model.dart';
|
||||
import 'package:geosector_app/core/data/models/membre_model.dart';
|
||||
import 'package:geosector_app/presentation/widgets/loading_progress_overlay.dart';
|
||||
import 'package:geosector_app/presentation/widgets/loading_spin_overlay.dart';
|
||||
import 'package:geosector_app/core/models/loading_state.dart';
|
||||
|
||||
class UserRepository extends ChangeNotifier {
|
||||
// Overlay pour afficher la progression du chargement
|
||||
OverlayEntry? _progressOverlay;
|
||||
bool _isLoading = false;
|
||||
|
||||
// Constructeur simplifié - plus d'injection d'ApiService
|
||||
@@ -336,64 +334,39 @@ class UserRepository extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
/// Connexion avec interface utilisateur et progression
|
||||
Future<bool> loginWithUI(
|
||||
|
||||
/// Connexion avec spinner moderne (pour remplacer la barre de progression)
|
||||
Future<bool> loginWithSpinner(
|
||||
BuildContext context, String username, String password,
|
||||
{required String type}) async {
|
||||
OverlayEntry? spinOverlay;
|
||||
try {
|
||||
// Créer et afficher l'overlay de progression
|
||||
_progressOverlay = LoadingProgressOverlayUtils.show(
|
||||
// Déterminer le message selon le type de connexion
|
||||
final message = type == 'admin'
|
||||
? 'Connexion administrateur...'
|
||||
: 'Connexion utilisateur...';
|
||||
|
||||
// Afficher le spinner moderne
|
||||
spinOverlay = LoadingSpinOverlayUtils.show(
|
||||
context: context,
|
||||
message: 'Connexion en cours...',
|
||||
progress: 0.0,
|
||||
stepDescription: 'Préparation',
|
||||
blurAmount: 5.0,
|
||||
message: message,
|
||||
blurAmount: 10.0,
|
||||
showCard: true,
|
||||
);
|
||||
|
||||
// Écouter les changements d'état du DataLoadingService
|
||||
void listener() {
|
||||
if (_progressOverlay != null) {
|
||||
final loadingState = DataLoadingService.instance.loadingState;
|
||||
LoadingProgressOverlayUtils.update(
|
||||
overlayEntry: _progressOverlay!,
|
||||
message: loadingState.message,
|
||||
progress: loadingState.progress,
|
||||
stepDescription: loadingState.stepDescription,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Configurer le callback de progression
|
||||
DataLoadingService.instance.setProgressCallback((_) => listener());
|
||||
|
||||
// Exécuter la connexion
|
||||
final result = await login(username, password, type: type);
|
||||
|
||||
// Attendre un court instant pour que l'utilisateur voie le résultat
|
||||
if (result) {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
} else {
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
}
|
||||
// Petit délai pour une meilleure UX
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
// Supprimer l'overlay
|
||||
if (_progressOverlay != null) {
|
||||
_progressOverlay!.remove();
|
||||
_progressOverlay = null;
|
||||
}
|
||||
|
||||
// Nettoyer le callback
|
||||
DataLoadingService.instance.setProgressCallback(null);
|
||||
// Fermer le spinner
|
||||
LoadingSpinOverlayUtils.hideSpecific(spinOverlay);
|
||||
|
||||
return result;
|
||||
} catch (e) {
|
||||
// En cas d'erreur, supprimer l'overlay
|
||||
if (_progressOverlay != null) {
|
||||
_progressOverlay!.remove();
|
||||
_progressOverlay = null;
|
||||
}
|
||||
|
||||
DataLoadingService.instance.setProgressCallback(null);
|
||||
LoadingSpinOverlayUtils.hideSpecific(spinOverlay);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ class ApiService {
|
||||
late final String _baseUrl;
|
||||
late final String _appIdentifier;
|
||||
String? _sessionId;
|
||||
|
||||
// Getters pour les propriétés (lecture seule)
|
||||
String? get sessionId => _sessionId;
|
||||
String get baseUrl => _baseUrl;
|
||||
|
||||
// Singleton thread-safe
|
||||
static ApiService get instance {
|
||||
@@ -142,8 +146,11 @@ class ApiService {
|
||||
Future<Response> post(String path, {dynamic data}) async {
|
||||
try {
|
||||
return await _dio.post(path, data: data);
|
||||
} on DioException catch (e) {
|
||||
throw ApiException.fromDioException(e);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
if (e is ApiException) rethrow;
|
||||
throw ApiException('Erreur inattendue lors de la requête POST', originalError: e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,8 +158,11 @@ class ApiService {
|
||||
Future<Response> get(String path, {Map<String, dynamic>? queryParameters}) async {
|
||||
try {
|
||||
return await _dio.get(path, queryParameters: queryParameters);
|
||||
} on DioException catch (e) {
|
||||
throw ApiException.fromDioException(e);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
if (e is ApiException) rethrow;
|
||||
throw ApiException('Erreur inattendue lors de la requête GET', originalError: e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,8 +170,11 @@ class ApiService {
|
||||
Future<Response> put(String path, {dynamic data}) async {
|
||||
try {
|
||||
return await _dio.put(path, data: data);
|
||||
} on DioException catch (e) {
|
||||
throw ApiException.fromDioException(e);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
if (e is ApiException) rethrow;
|
||||
throw ApiException('Erreur inattendue lors de la requête PUT', originalError: e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,8 +182,81 @@ class ApiService {
|
||||
Future<Response> delete(String path) async {
|
||||
try {
|
||||
return await _dio.delete(path);
|
||||
} on DioException catch (e) {
|
||||
throw ApiException.fromDioException(e);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
if (e is ApiException) rethrow;
|
||||
throw ApiException('Erreur inattendue lors de la requête DELETE', originalError: e);
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode pour uploader un logo d'amicale
|
||||
Future<Map<String, dynamic>> uploadLogo(int entiteId, dynamic imageFile) async {
|
||||
try {
|
||||
FormData formData;
|
||||
|
||||
// Gestion différente selon la plateforme (Web ou Mobile)
|
||||
if (kIsWeb) {
|
||||
// Pour le web, imageFile est un XFile
|
||||
final bytes = await imageFile.readAsBytes();
|
||||
|
||||
// Vérification de la taille (5 Mo max)
|
||||
const int maxSize = 5 * 1024 * 1024;
|
||||
if (bytes.length > maxSize) {
|
||||
throw ApiException(
|
||||
'Le fichier est trop volumineux. Taille maximale: 5 Mo',
|
||||
statusCode: 413
|
||||
);
|
||||
}
|
||||
|
||||
formData = FormData.fromMap({
|
||||
'logo': MultipartFile.fromBytes(
|
||||
bytes,
|
||||
filename: imageFile.name,
|
||||
),
|
||||
});
|
||||
} else {
|
||||
// Pour mobile, imageFile est un File
|
||||
final fileLength = await imageFile.length();
|
||||
|
||||
// Vérification de la taille (5 Mo max)
|
||||
const int maxSize = 5 * 1024 * 1024;
|
||||
if (fileLength > maxSize) {
|
||||
throw ApiException(
|
||||
'Le fichier est trop volumineux. Taille maximale: 5 Mo',
|
||||
statusCode: 413
|
||||
);
|
||||
}
|
||||
|
||||
formData = FormData.fromMap({
|
||||
'logo': await MultipartFile.fromFile(
|
||||
imageFile.path,
|
||||
filename: imageFile.path.split('/').last,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
final response = await _dio.post(
|
||||
'/entites/$entiteId/logo',
|
||||
data: formData,
|
||||
options: Options(
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
return response.data;
|
||||
} else {
|
||||
throw ApiException('Erreur lors de l\'upload du logo',
|
||||
statusCode: response.statusCode);
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
throw ApiException.fromDioException(e);
|
||||
} catch (e) {
|
||||
if (e is ApiException) rethrow;
|
||||
throw ApiException('Erreur inattendue lors de l\'upload du logo', originalError: e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
163
app/lib/core/services/logger_service.dart
Normal file
163
app/lib/core/services/logger_service.dart
Normal file
@@ -0,0 +1,163 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:geosector_app/core/services/api_service.dart';
|
||||
|
||||
/// Service de logging centralisé qui désactive automatiquement les logs en production
|
||||
class LoggerService {
|
||||
static LoggerService? _instance;
|
||||
static bool? _isProduction;
|
||||
|
||||
// Singleton
|
||||
static LoggerService get instance {
|
||||
_instance ??= LoggerService._internal();
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
LoggerService._internal();
|
||||
|
||||
/// Détermine si on est en production
|
||||
static bool get isProduction {
|
||||
if (_isProduction != null) return _isProduction!;
|
||||
|
||||
try {
|
||||
// Vérifier si ApiService est initialisé
|
||||
final env = ApiService.instance.getCurrentEnvironment();
|
||||
_isProduction = env == 'PROD';
|
||||
} catch (e) {
|
||||
// Si ApiService n'est pas encore initialisé, utiliser kReleaseMode
|
||||
_isProduction = kReleaseMode;
|
||||
}
|
||||
|
||||
return _isProduction!;
|
||||
}
|
||||
|
||||
/// Réinitialiser le cache de l'environnement (utile pour les tests)
|
||||
static void resetEnvironmentCache() {
|
||||
_isProduction = null;
|
||||
}
|
||||
|
||||
/// Log simple (remplace debugPrint)
|
||||
static void log(String message, {String? prefix}) {
|
||||
if (!isProduction) {
|
||||
if (prefix != null) {
|
||||
debugPrint('$prefix $message');
|
||||
} else {
|
||||
debugPrint(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Log d'information
|
||||
static void info(String message) {
|
||||
if (!isProduction) {
|
||||
debugPrint('ℹ️ $message');
|
||||
}
|
||||
}
|
||||
|
||||
/// Log de succès
|
||||
static void success(String message) {
|
||||
if (!isProduction) {
|
||||
debugPrint('✅ $message');
|
||||
}
|
||||
}
|
||||
|
||||
/// Log d'avertissement
|
||||
static void warning(String message) {
|
||||
if (!isProduction) {
|
||||
debugPrint('⚠️ $message');
|
||||
}
|
||||
}
|
||||
|
||||
/// Log d'erreur (toujours affiché même en production pour le debugging)
|
||||
static void error(String message, [dynamic error, StackTrace? stackTrace]) {
|
||||
// Les erreurs sont toujours loggées, même en production
|
||||
debugPrint('❌ $message');
|
||||
if (error != null) {
|
||||
debugPrint(' Error: $error');
|
||||
}
|
||||
if (stackTrace != null && !isProduction) {
|
||||
// La stack trace n'est affichée qu'en DEV/REC
|
||||
debugPrint(' Stack trace:\n$stackTrace');
|
||||
}
|
||||
}
|
||||
|
||||
/// Log de debug (avec emoji personnalisé)
|
||||
static void debug(String message, {String emoji = '🔧'}) {
|
||||
if (!isProduction) {
|
||||
debugPrint('$emoji $message');
|
||||
}
|
||||
}
|
||||
|
||||
/// Log de requête API
|
||||
static void api(String message) {
|
||||
if (!isProduction) {
|
||||
debugPrint('🔗 $message');
|
||||
}
|
||||
}
|
||||
|
||||
/// Log de base de données
|
||||
static void database(String message) {
|
||||
if (!isProduction) {
|
||||
debugPrint('💾 $message');
|
||||
}
|
||||
}
|
||||
|
||||
/// Log de navigation
|
||||
static void navigation(String message) {
|
||||
if (!isProduction) {
|
||||
debugPrint('🧭 $message');
|
||||
}
|
||||
}
|
||||
|
||||
/// Log de performance/timing
|
||||
static void performance(String message) {
|
||||
if (!isProduction) {
|
||||
debugPrint('⏱️ $message');
|
||||
}
|
||||
}
|
||||
|
||||
/// Log conditionnel basé sur un flag custom
|
||||
static void conditional(String message, {required bool condition}) {
|
||||
if (!isProduction && condition) {
|
||||
debugPrint(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// Groupe de logs (pour regrouper visuellement des logs liés)
|
||||
static void group(String title, List<String> messages) {
|
||||
if (!isProduction) {
|
||||
debugPrint('┌─ $title');
|
||||
for (int i = 0; i < messages.length; i++) {
|
||||
if (i == messages.length - 1) {
|
||||
debugPrint('└─ ${messages[i]}');
|
||||
} else {
|
||||
debugPrint('├─ ${messages[i]}');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Log d'objet JSON (formaté)
|
||||
static void json(String label, Map<String, dynamic> data) {
|
||||
if (!isProduction) {
|
||||
debugPrint('📋 $label:');
|
||||
data.forEach((key, value) {
|
||||
debugPrint(' $key: $value');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extension pour faciliter l'utilisation
|
||||
extension LoggerExtension on String {
|
||||
void log({String? prefix}) => LoggerService.log(this, prefix: prefix);
|
||||
void logInfo() => LoggerService.info(this);
|
||||
void logSuccess() => LoggerService.success(this);
|
||||
void logWarning() => LoggerService.warning(this);
|
||||
void logError([dynamic error, StackTrace? stackTrace]) =>
|
||||
LoggerService.error(this, error, stackTrace);
|
||||
void logDebug({String emoji = '🔧'}) => LoggerService.debug(this, emoji: emoji);
|
||||
void logApi() => LoggerService.api(this);
|
||||
void logDatabase() => LoggerService.database(this);
|
||||
void logNavigation() => LoggerService.navigation(this);
|
||||
void logPerformance() => LoggerService.performance(this);
|
||||
}
|
||||
@@ -97,6 +97,9 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
}
|
||||
|
||||
void _handleEditMembre(MembreModel membre) {
|
||||
// Récupérer l'amicale actuelle
|
||||
final amicale = widget.amicaleRepository.getUserAmicale(_currentUser!.fkEntite!);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => UserFormDialog(
|
||||
@@ -104,8 +107,9 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
user: membre.toUserModel(),
|
||||
showRoleSelector: true,
|
||||
showActiveCheckbox: true, // Activer la checkbox
|
||||
allowUsernameEdit: true, // Permettre l'édition du username
|
||||
// allowSectNameEdit sera automatiquement true via UserForm
|
||||
allowUsernameEdit: amicale?.chkUsernameManuel == true, // Conditionnel selon amicale
|
||||
amicale: amicale, // Passer l'amicale
|
||||
isAdmin: true, // Car on est dans la page admin
|
||||
availableRoles: const [
|
||||
RoleOption(
|
||||
value: 1,
|
||||
@@ -118,23 +122,22 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
description: 'Peut gérer l\'amicale et ses membres',
|
||||
),
|
||||
],
|
||||
onSubmit: (updatedUser) async {
|
||||
onSubmit: (updatedUser, {String? password}) async {
|
||||
try {
|
||||
// Convertir le UserModel mis à jour vers MembreModel
|
||||
final updatedMembre =
|
||||
MembreModel.fromUserModel(updatedUser, membre);
|
||||
|
||||
// Utiliser directement updateMembre qui passe par l'API /users
|
||||
final success =
|
||||
await widget.membreRepository.updateMembre(updatedMembre);
|
||||
final success = await widget.membreRepository.updateMembre(
|
||||
updatedMembre,
|
||||
password: password,
|
||||
);
|
||||
|
||||
if (success && mounted) {
|
||||
Navigator.of(context).pop();
|
||||
ApiException.showSuccess(context,
|
||||
'Membre ${updatedMembre.firstName} ${updatedMembre.name} mis à jour');
|
||||
} else if (!success && mounted) {
|
||||
ApiException.showError(
|
||||
context, Exception('Erreur lors de la mise à jour'));
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur mise à jour membre: $e');
|
||||
@@ -557,9 +560,6 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
if (success && mounted) {
|
||||
ApiException.showSuccess(context,
|
||||
'Membre ${membre.firstName} ${membre.name} désactivé avec succès');
|
||||
} else if (mounted) {
|
||||
ApiException.showError(
|
||||
context, Exception('Erreur lors de la désactivation'));
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
@@ -571,6 +571,9 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
void _handleAddMembre() {
|
||||
if (_currentUser?.fkEntite == null) return;
|
||||
|
||||
// Récupérer l'amicale actuelle
|
||||
final amicale = widget.amicaleRepository.getUserAmicale(_currentUser!.fkEntite!);
|
||||
|
||||
// Créer un UserModel vide avec les valeurs par défaut
|
||||
final newUser = UserModel(
|
||||
id: 0, // ID temporaire pour nouveau membre
|
||||
@@ -596,7 +599,9 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
user: newUser,
|
||||
showRoleSelector: true,
|
||||
showActiveCheckbox: true,
|
||||
allowUsernameEdit: true,
|
||||
allowUsernameEdit: amicale?.chkUsernameManuel == true, // Conditionnel selon amicale
|
||||
amicale: amicale, // Passer l'amicale
|
||||
isAdmin: true, // Car on est dans la page admin
|
||||
availableRoles: const [
|
||||
RoleOption(
|
||||
value: 1,
|
||||
@@ -609,7 +614,7 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
description: 'Peut gérer l\'amicale et ses membres',
|
||||
),
|
||||
],
|
||||
onSubmit: (newUserData) async {
|
||||
onSubmit: (newUserData, {String? password}) async {
|
||||
try {
|
||||
// Créer un nouveau MembreModel directement
|
||||
final newMembre = MembreModel(
|
||||
@@ -631,8 +636,10 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
);
|
||||
|
||||
// Créer le membre via l'API (retourne maintenant le membre créé)
|
||||
final createdMembre =
|
||||
await widget.membreRepository.createMembre(newMembre);
|
||||
final createdMembre = await widget.membreRepository.createMembre(
|
||||
newMembre,
|
||||
password: password,
|
||||
);
|
||||
|
||||
if (createdMembre != null && mounted) {
|
||||
// Fermer le dialog
|
||||
|
||||
@@ -434,7 +434,8 @@ class _LoginPageState extends State<LoginPage> {
|
||||
'Login: Tentative avec type: $_loginType');
|
||||
|
||||
final success =
|
||||
await userRepository.login(
|
||||
await userRepository.loginWithSpinner(
|
||||
context,
|
||||
_usernameController.text.trim(),
|
||||
_passwordController.text,
|
||||
type: _loginType,
|
||||
@@ -575,9 +576,9 @@ class _LoginPageState extends State<LoginPage> {
|
||||
print(
|
||||
'Login: Tentative avec type: $_loginType');
|
||||
|
||||
// Utiliser directement userRepository avec l'overlay de chargement
|
||||
// Utiliser le nouveau spinner moderne pour la connexion
|
||||
final success = await userRepository
|
||||
.loginWithUI(
|
||||
.loginWithSpinner(
|
||||
context,
|
||||
_usernameController.text.trim(),
|
||||
_passwordController.text,
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:convert';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
||||
import 'package:geosector_app/core/repositories/user_repository.dart';
|
||||
import 'package:geosector_app/core/services/api_service.dart';
|
||||
import 'package:geosector_app/presentation/widgets/mapbox_map.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'dart:io';
|
||||
import 'package:geosector_app/presentation/widgets/loading_spin_overlay.dart';
|
||||
import 'custom_text_field.dart';
|
||||
|
||||
class AmicaleForm extends StatefulWidget {
|
||||
@@ -52,6 +58,13 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
bool _chkAcceptSms = false;
|
||||
bool _chkActive = true;
|
||||
bool _chkStripe = false;
|
||||
bool _chkMdpManuel = false;
|
||||
bool _chkUsernameManuel = false;
|
||||
|
||||
// Pour l'upload du logo
|
||||
final ImagePicker _picker = ImagePicker();
|
||||
XFile? _selectedImage;
|
||||
String? _logoUrl;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -78,6 +91,10 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
_chkAcceptSms = amicale?.chkAcceptSms ?? false;
|
||||
_chkActive = amicale?.chkActive ?? true;
|
||||
_chkStripe = amicale?.chkStripe ?? false;
|
||||
_chkMdpManuel = amicale?.chkMdpManuel ?? false;
|
||||
_chkUsernameManuel = amicale?.chkUsernameManuel ?? false;
|
||||
|
||||
// Note : Le logo sera chargé dynamiquement depuis l'API
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -133,6 +150,8 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
'chk_copie_mail_recu': amicale.chkCopieMailRecu ? 1 : 0,
|
||||
'chk_accept_sms': amicale.chkAcceptSms ? 1 : 0,
|
||||
'chk_stripe': amicale.chkStripe ? 1 : 0,
|
||||
'chk_mdp_manuel': amicale.chkMdpManuel ? 1 : 0,
|
||||
'chk_username_manuel': amicale.chkUsernameManuel ? 1 : 0,
|
||||
};
|
||||
|
||||
// Ajouter les champs réservés aux administrateurs si l'utilisateur est admin
|
||||
@@ -232,6 +251,115 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode pour sélectionner une image
|
||||
Future<void> _selectImage() async {
|
||||
try {
|
||||
final XFile? image = await _picker.pickImage(
|
||||
source: ImageSource.gallery,
|
||||
maxWidth: 1024,
|
||||
maxHeight: 1024,
|
||||
imageQuality: 85,
|
||||
);
|
||||
|
||||
if (image != null) {
|
||||
// Vérifier la taille du fichier (limite 5 Mo)
|
||||
final int fileSize = await image.length();
|
||||
const int maxSize = 5 * 1024 * 1024; // 5 Mo en octets
|
||||
|
||||
if (fileSize > maxSize) {
|
||||
// Fichier trop volumineux
|
||||
final double sizeMB = fileSize / (1024 * 1024);
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'Le fichier est trop volumineux (${sizeMB.toStringAsFixed(2)} Mo). '
|
||||
'La taille maximale autorisée est de 5 Mo.',
|
||||
),
|
||||
backgroundColor: Colors.orange,
|
||||
duration: const Duration(seconds: 5),
|
||||
),
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_selectedImage = image;
|
||||
});
|
||||
|
||||
// Upload immédiatement après sélection
|
||||
if (widget.amicale?.id != null) {
|
||||
await _uploadLogo();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la sélection de l\'image: $e');
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Erreur lors de la sélection de l\'image: $e'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode pour uploader le logo
|
||||
Future<void> _uploadLogo() async {
|
||||
if (_selectedImage == null || widget.amicale?.id == null) return;
|
||||
|
||||
OverlayEntry? spinOverlay;
|
||||
try {
|
||||
// Afficher le spinner
|
||||
spinOverlay = LoadingSpinOverlayUtils.show(
|
||||
context: context,
|
||||
message: 'Upload du logo en cours...',
|
||||
blurAmount: 10.0,
|
||||
showCard: true,
|
||||
);
|
||||
|
||||
// Appeler l'API pour uploader le logo
|
||||
final response = await widget.apiService?.uploadLogo(
|
||||
widget.amicale!.id,
|
||||
_selectedImage!,
|
||||
);
|
||||
|
||||
if (response != null && response['status'] == 'success') {
|
||||
// Succès
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Logo uploadé avec succès'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Mettre à jour l'amicale avec le nouveau logo en base64
|
||||
// Note : Le serveur devrait aussi mettre à jour le logo dans la session
|
||||
// Pour l'instant on garde l'image sélectionnée en preview
|
||||
setState(() {
|
||||
// L'image reste en preview jusqu'au prochain login
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de l\'upload du logo: $e');
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Erreur lors de l\'upload: ${e.toString()}'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
// Fermer le spinner
|
||||
LoadingSpinOverlayUtils.hideSpecific(spinOverlay);
|
||||
}
|
||||
}
|
||||
|
||||
void _submitForm() {
|
||||
debugPrint('🔧 _submitForm appelée');
|
||||
|
||||
@@ -271,6 +399,8 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
chkAcceptSms: _chkAcceptSms,
|
||||
chkActive: _chkActive,
|
||||
chkStripe: _chkStripe,
|
||||
chkMdpManuel: _chkMdpManuel,
|
||||
chkUsernameManuel: _chkUsernameManuel,
|
||||
) ??
|
||||
AmicaleModel(
|
||||
id: 0, // Sera remplacé par l'API
|
||||
@@ -291,6 +421,9 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
chkCopieMailRecu: _chkCopieMailRecu,
|
||||
chkAcceptSms: _chkAcceptSms,
|
||||
chkActive: _chkActive,
|
||||
chkStripe: _chkStripe,
|
||||
chkMdpManuel: _chkMdpManuel,
|
||||
chkUsernameManuel: _chkUsernameManuel,
|
||||
);
|
||||
|
||||
debugPrint('🔧 AmicaleModel créé: ${amicale.name}');
|
||||
@@ -305,6 +438,10 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
|
||||
// Construire la section logo
|
||||
Widget _buildLogoSection() {
|
||||
// Vérifier si on est admin d'amicale (role 2)
|
||||
final userRole = widget.userRepository.getUserRole();
|
||||
final canUploadLogo = userRole == 2 && !widget.readOnly;
|
||||
|
||||
return Container(
|
||||
width: 150,
|
||||
height: 150,
|
||||
@@ -323,40 +460,40 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Stack(
|
||||
children: [
|
||||
// Image par défaut
|
||||
// Afficher l'image sélectionnée, ou le logo depuis l'API, ou l'image par défaut
|
||||
Center(
|
||||
child: Image.asset(
|
||||
'assets/images/logo_recu.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
child: _buildLogoImage(),
|
||||
),
|
||||
|
||||
// Overlay pour indiquer que l'image est modifiable (si non en lecture seule)
|
||||
if (!widget.readOnly)
|
||||
// Overlay pour indiquer que l'image est modifiable (si admin d'amicale)
|
||||
if (canUploadLogo)
|
||||
Positioned.fill(
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
// TODO: Implémenter la sélection d'image
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Fonctionnalité de modification du logo à venir'),
|
||||
),
|
||||
);
|
||||
},
|
||||
onTap: _selectImage,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
color: Colors.black.withOpacity(0.3),
|
||||
),
|
||||
child: const Center(
|
||||
child: Icon(
|
||||
Icons.camera_alt,
|
||||
color: Colors.white,
|
||||
size: 40,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: const [
|
||||
Icon(
|
||||
Icons.camera_alt,
|
||||
color: Colors.white,
|
||||
size: 32,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
'Modifier',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -367,6 +504,102 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Méthode pour construire l'image du logo
|
||||
Widget _buildLogoImage() {
|
||||
// 1. Si une image a été sélectionnée localement (preview)
|
||||
if (_selectedImage != null) {
|
||||
if (kIsWeb) {
|
||||
return FutureBuilder<Uint8List>(
|
||||
future: _selectedImage!.readAsBytes(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Image.memory(
|
||||
snapshot.data!,
|
||||
width: 150,
|
||||
height: 150,
|
||||
fit: BoxFit.contain,
|
||||
);
|
||||
}
|
||||
return const CircularProgressIndicator();
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return Image.file(
|
||||
File(_selectedImage!.path),
|
||||
width: 150,
|
||||
height: 150,
|
||||
fit: BoxFit.contain,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Si l'amicale a un logo en base64 stocké dans Hive
|
||||
if (widget.amicale?.logoBase64 != null && widget.amicale!.logoBase64!.isNotEmpty) {
|
||||
try {
|
||||
// Le logoBase64 contient déjà le data URL complet (data:image/png;base64,...)
|
||||
final dataUrl = widget.amicale!.logoBase64!;
|
||||
|
||||
// Extraire le base64 du data URL
|
||||
final base64Data = dataUrl.split(',').last;
|
||||
final bytes = base64Decode(base64Data);
|
||||
|
||||
return Image.memory(
|
||||
bytes,
|
||||
width: 150,
|
||||
height: 150,
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
debugPrint('Erreur affichage logo base64: $error');
|
||||
// En cas d'erreur, essayer l'API
|
||||
return _buildLogoFromApi();
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint('Erreur décodage base64: $e');
|
||||
// En cas d'erreur, essayer l'API
|
||||
return _buildLogoFromApi();
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Sinon, essayer de charger depuis l'API
|
||||
return _buildLogoFromApi();
|
||||
}
|
||||
|
||||
// Méthode pour charger le logo depuis l'API
|
||||
Widget _buildLogoFromApi() {
|
||||
if (widget.amicale?.id != null && widget.apiService != null) {
|
||||
// Construire l'URL complète du logo
|
||||
final logoUrl = '${widget.apiService!.baseUrl}/entites/${widget.amicale!.id}/logo';
|
||||
|
||||
return Image.network(
|
||||
logoUrl,
|
||||
width: 150,
|
||||
height: 150,
|
||||
fit: BoxFit.contain,
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${widget.apiService!.sessionId ?? ""}',
|
||||
},
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
// En cas d'erreur, afficher l'image par défaut
|
||||
return Image.asset(
|
||||
'assets/images/logo_recu.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
fit: BoxFit.contain,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Par défaut, afficher l'image locale
|
||||
return Image.asset(
|
||||
'assets/images/logo_recu.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
fit: BoxFit.contain,
|
||||
);
|
||||
}
|
||||
|
||||
// Construire la minimap
|
||||
Widget _buildMiniMap() {
|
||||
@@ -825,59 +1058,106 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Checkbox Demo
|
||||
_buildCheckboxOption(
|
||||
label: "Mode démo",
|
||||
value: _chkDemo,
|
||||
onChanged: restrictedFieldsReadOnly
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
_chkDemo = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// Options organisées sur 2 colonnes
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Colonne de gauche
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
// Checkbox Demo
|
||||
_buildCheckboxOption(
|
||||
label: "Mode démo",
|
||||
value: _chkDemo,
|
||||
onChanged: restrictedFieldsReadOnly
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
_chkDemo = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Checkbox Copie Mail Reçu
|
||||
_buildCheckboxOption(
|
||||
label: "Copie des mails reçus",
|
||||
value: _chkCopieMailRecu,
|
||||
onChanged: widget.readOnly
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
_chkCopieMailRecu = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// Checkbox Copie Mail Reçu
|
||||
_buildCheckboxOption(
|
||||
label: "Copie des mails reçus",
|
||||
value: _chkCopieMailRecu,
|
||||
onChanged: widget.readOnly
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
_chkCopieMailRecu = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Checkbox Accept SMS
|
||||
_buildCheckboxOption(
|
||||
label: "Accepte les SMS",
|
||||
value: _chkAcceptSms,
|
||||
onChanged: widget.readOnly
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
_chkAcceptSms = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// Checkbox Accept SMS
|
||||
_buildCheckboxOption(
|
||||
label: "Accepte les SMS",
|
||||
value: _chkAcceptSms,
|
||||
onChanged: widget.readOnly
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
_chkAcceptSms = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 32),
|
||||
// Colonne de droite
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
// Checkbox Active
|
||||
_buildCheckboxOption(
|
||||
label: "Actif",
|
||||
value: _chkActive,
|
||||
onChanged: restrictedFieldsReadOnly
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
_chkActive = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Checkbox Active
|
||||
_buildCheckboxOption(
|
||||
label: "Actif",
|
||||
value: _chkActive,
|
||||
onChanged: restrictedFieldsReadOnly
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
_chkActive = value!;
|
||||
});
|
||||
},
|
||||
// Checkbox Mot de passe manuel
|
||||
_buildCheckboxOption(
|
||||
label: "Saisie manuelle des mots de passe",
|
||||
value: _chkMdpManuel,
|
||||
onChanged: widget.readOnly
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
_chkMdpManuel = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Checkbox Username manuel
|
||||
_buildCheckboxOption(
|
||||
label: "Saisie manuelle des identifiants",
|
||||
value: _chkUsernameManuel,
|
||||
onChanged: widget.readOnly
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
_chkUsernameManuel = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
|
||||
|
||||
@@ -171,9 +171,10 @@ class DashboardAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
user: user,
|
||||
readOnly: false,
|
||||
showRoleSelector: false,
|
||||
onSubmit: (updatedUser) async {
|
||||
onSubmit: (updatedUser, {String? password}) async {
|
||||
try {
|
||||
// Sauvegarder les modifications de l'utilisateur
|
||||
// Note: password est ignoré ici car l'utilisateur normal ne peut pas changer son mot de passe
|
||||
await userRepository.updateUser(updatedUser);
|
||||
|
||||
if (context.mounted) {
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:ui';
|
||||
|
||||
/// Widget d'overlay de chargement amélioré qui affiche une barre de progression
|
||||
/// avec un effet de flou sur l'arrière-plan et un message détaillé sur l'étape en cours
|
||||
class LoadingProgressOverlay extends StatefulWidget {
|
||||
final String? message;
|
||||
final double progress;
|
||||
final String? stepDescription;
|
||||
final Color backgroundColor;
|
||||
final Color progressColor;
|
||||
final Color textColor;
|
||||
final double blurAmount;
|
||||
final bool showPercentage;
|
||||
|
||||
const LoadingProgressOverlay({
|
||||
super.key,
|
||||
this.message,
|
||||
required this.progress,
|
||||
this.stepDescription,
|
||||
this.backgroundColor = Colors.black54,
|
||||
this.progressColor = Colors.white,
|
||||
this.textColor = Colors.white,
|
||||
this.blurAmount = 5.0,
|
||||
this.showPercentage = true,
|
||||
});
|
||||
|
||||
@override
|
||||
State<LoadingProgressOverlay> createState() => _LoadingProgressOverlayState();
|
||||
}
|
||||
|
||||
class _LoadingProgressOverlayState extends State<LoadingProgressOverlay>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
late Animation<double> _progressAnimation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
);
|
||||
_progressAnimation = Tween<double>(begin: 0, end: widget.progress).animate(
|
||||
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
|
||||
);
|
||||
_animationController.forward();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(LoadingProgressOverlay oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.progress != widget.progress) {
|
||||
_progressAnimation = Tween<double>(
|
||||
begin: oldWidget.progress,
|
||||
end: widget.progress,
|
||||
).animate(
|
||||
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
|
||||
);
|
||||
_animationController.reset();
|
||||
_animationController.forward();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BackdropFilter(
|
||||
filter: ImageFilter.blur(
|
||||
sigmaX: widget.blurAmount, sigmaY: widget.blurAmount),
|
||||
child: Container(
|
||||
color: widget.backgroundColor,
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width * 0.85,
|
||||
padding: const EdgeInsets.all(30),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withOpacity(0.9),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Colors.black45,
|
||||
blurRadius: 15,
|
||||
spreadRadius: 5,
|
||||
offset: Offset(0, 5),
|
||||
),
|
||||
],
|
||||
border: Border.all(
|
||||
color: Colors.white.withOpacity(0.1),
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (widget.message != null) ...[
|
||||
Text(
|
||||
widget.message!,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: widget.textColor,
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
AnimatedBuilder(
|
||||
animation: _progressAnimation,
|
||||
builder: (context, child) {
|
||||
return Column(
|
||||
children: [
|
||||
LinearProgressIndicator(
|
||||
value: _progressAnimation.value,
|
||||
backgroundColor:
|
||||
widget.progressColor.withOpacity(0.3),
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
widget.progressColor),
|
||||
minHeight: 15,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
if (widget.showPercentage) ...[
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${(_progressAnimation.value * 100).toInt()}%',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: widget.textColor,
|
||||
letterSpacing: 1.2,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
if (widget.stepDescription != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
widget.stepDescription!,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: widget.textColor.withOpacity(0.9),
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Classe utilitaire pour gérer l'overlay de chargement avec progression
|
||||
class LoadingProgressOverlayUtils {
|
||||
/// Méthode pour afficher l'overlay de chargement avec progression
|
||||
static OverlayEntry show({
|
||||
required BuildContext context,
|
||||
String? message,
|
||||
double progress = 0.0,
|
||||
String? stepDescription,
|
||||
double blurAmount = 5.0,
|
||||
bool showPercentage = true,
|
||||
}) {
|
||||
final overlayEntry = OverlayEntry(
|
||||
builder: (context) => LoadingProgressOverlay(
|
||||
message: message,
|
||||
progress: progress,
|
||||
stepDescription: stepDescription,
|
||||
blurAmount: blurAmount,
|
||||
showPercentage: showPercentage,
|
||||
),
|
||||
);
|
||||
|
||||
Overlay.of(context).insert(overlayEntry);
|
||||
return overlayEntry;
|
||||
}
|
||||
|
||||
/// Méthode pour mettre à jour l'overlay existant
|
||||
static void update({
|
||||
required OverlayEntry overlayEntry,
|
||||
String? message,
|
||||
required double progress,
|
||||
String? stepDescription,
|
||||
}) {
|
||||
overlayEntry.markNeedsBuild();
|
||||
}
|
||||
}
|
||||
229
app/lib/presentation/widgets/loading_spin_overlay.dart
Normal file
229
app/lib/presentation/widgets/loading_spin_overlay.dart
Normal file
@@ -0,0 +1,229 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:ui';
|
||||
|
||||
/// Widget d'overlay de chargement moderne avec spinner circulaire
|
||||
/// Affiche un spinner animé avec fond flou et message optionnel
|
||||
class LoadingSpinOverlay extends StatefulWidget {
|
||||
final String? message;
|
||||
final Color backgroundColor;
|
||||
final Color spinnerColor;
|
||||
final Color textColor;
|
||||
final double blurAmount;
|
||||
final double spinnerSize;
|
||||
final bool showCard;
|
||||
|
||||
const LoadingSpinOverlay({
|
||||
super.key,
|
||||
this.message,
|
||||
this.backgroundColor = Colors.black54,
|
||||
this.spinnerColor = Colors.blue,
|
||||
this.textColor = Colors.white,
|
||||
this.blurAmount = 8.0,
|
||||
this.spinnerSize = 50.0,
|
||||
this.showCard = true,
|
||||
});
|
||||
|
||||
@override
|
||||
State<LoadingSpinOverlay> createState() => _LoadingSpinOverlayState();
|
||||
}
|
||||
|
||||
class _LoadingSpinOverlayState extends State<LoadingSpinOverlay>
|
||||
with TickerProviderStateMixin {
|
||||
late AnimationController _fadeController;
|
||||
late AnimationController _rotationController;
|
||||
late Animation<double> _fadeAnimation;
|
||||
late Animation<double> _rotationAnimation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_fadeController = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
);
|
||||
_rotationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(seconds: 1),
|
||||
);
|
||||
|
||||
_fadeAnimation = Tween<double>(
|
||||
begin: 0.0,
|
||||
end: 1.0,
|
||||
).animate(CurvedAnimation(
|
||||
parent: _fadeController,
|
||||
curve: Curves.easeInOut,
|
||||
));
|
||||
|
||||
_rotationAnimation = Tween<double>(
|
||||
begin: 0.0,
|
||||
end: 2 * 3.14159,
|
||||
).animate(CurvedAnimation(
|
||||
parent: _rotationController,
|
||||
curve: Curves.linear,
|
||||
));
|
||||
|
||||
_fadeController.forward();
|
||||
_rotationController.repeat();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_fadeController.dispose();
|
||||
_rotationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FadeTransition(
|
||||
opacity: _fadeAnimation,
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(
|
||||
sigmaX: widget.blurAmount,
|
||||
sigmaY: widget.blurAmount,
|
||||
),
|
||||
child: Container(
|
||||
color: widget.backgroundColor,
|
||||
child: Center(
|
||||
child: widget.showCard
|
||||
? _buildCardContent()
|
||||
: _buildSimpleContent(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCardContent() {
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(32),
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 280,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.92), // Semi-transparent
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.15),
|
||||
blurRadius: 20,
|
||||
spreadRadius: 2,
|
||||
offset: const Offset(0, 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Spinner simple de Flutter
|
||||
SizedBox(
|
||||
width: widget.spinnerSize,
|
||||
height: widget.spinnerSize,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 3,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(widget.spinnerColor),
|
||||
),
|
||||
),
|
||||
if (widget.message != null) ...[
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
widget.message!,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.grey[800],
|
||||
letterSpacing: 0.3,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSimpleContent() {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: widget.spinnerSize,
|
||||
height: widget.spinnerSize,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 3,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(widget.spinnerColor),
|
||||
),
|
||||
),
|
||||
if (widget.message != null) ...[
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
widget.message!,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: widget.textColor,
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Classe utilitaire pour gérer l'overlay de chargement avec spinner
|
||||
class LoadingSpinOverlayUtils {
|
||||
static OverlayEntry? _currentOverlay;
|
||||
|
||||
/// Affiche l'overlay de chargement avec spinner
|
||||
static OverlayEntry show({
|
||||
required BuildContext context,
|
||||
String? message,
|
||||
double blurAmount = 8.0,
|
||||
bool showCard = true,
|
||||
Color? spinnerColor,
|
||||
}) {
|
||||
// Fermer l'overlay existant s'il y en a un
|
||||
hide();
|
||||
|
||||
final theme = Theme.of(context);
|
||||
final overlayEntry = OverlayEntry(
|
||||
builder: (context) => LoadingSpinOverlay(
|
||||
message: message,
|
||||
blurAmount: blurAmount,
|
||||
showCard: showCard,
|
||||
spinnerColor: spinnerColor ?? theme.colorScheme.primary,
|
||||
),
|
||||
);
|
||||
|
||||
_currentOverlay = overlayEntry;
|
||||
Overlay.of(context).insert(overlayEntry);
|
||||
return overlayEntry;
|
||||
}
|
||||
|
||||
/// Met à jour le message de l'overlay existant
|
||||
static void updateMessage({
|
||||
required OverlayEntry overlayEntry,
|
||||
String? message,
|
||||
}) {
|
||||
overlayEntry.markNeedsBuild();
|
||||
}
|
||||
|
||||
/// Cache l'overlay de chargement
|
||||
static void hide() {
|
||||
_currentOverlay?.remove();
|
||||
_currentOverlay = null;
|
||||
}
|
||||
|
||||
/// Cache un overlay spécifique
|
||||
static void hideSpecific(OverlayEntry? overlayEntry) {
|
||||
overlayEntry?.remove();
|
||||
if (_currentOverlay == overlayEntry) {
|
||||
_currentOverlay = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ class MembreRowWidget extends StatelessWidget {
|
||||
final Function(MembreModel)? onResetPassword;
|
||||
final bool isAlternate;
|
||||
final VoidCallback? onTap;
|
||||
final bool isMobile;
|
||||
|
||||
const MembreRowWidget({
|
||||
super.key,
|
||||
@@ -17,6 +18,7 @@ class MembreRowWidget extends StatelessWidget {
|
||||
this.onResetPassword,
|
||||
this.isAlternate = false,
|
||||
this.onTap,
|
||||
this.isMobile = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -37,20 +39,29 @@ class MembreRowWidget extends StatelessWidget {
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// ... existing row content ...
|
||||
|
||||
// ID
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
membre.id.toString() ?? '',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
// ID - masqué en mobile
|
||||
if (!isMobile)
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
membre.id.toString() ?? '',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
|
||||
// Identifiant (username) - masqué en mobile
|
||||
if (!isMobile)
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
membre.username ?? '',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Prénom
|
||||
Expanded(
|
||||
flex: 2,
|
||||
flex: isMobile ? 2 : 2,
|
||||
child: Text(
|
||||
membre.firstName ?? '',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
@@ -59,47 +70,44 @@ class MembreRowWidget extends StatelessWidget {
|
||||
|
||||
// Nom
|
||||
Expanded(
|
||||
flex: 2,
|
||||
flex: isMobile ? 2 : 2,
|
||||
child: Text(
|
||||
membre.name ?? '',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
|
||||
// Email
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
membre.email ?? '',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
// Email - masqué en mobile
|
||||
if (!isMobile)
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
membre.email ?? '',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Rôle
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
_getRoleName(membre.role),
|
||||
style: theme.textTheme.bodyMedium,
|
||||
// Rôle - masqué en mobile
|
||||
if (!isMobile)
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
_getRoleName(membre.role),
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Statut
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
|
||||
decoration: BoxDecoration(
|
||||
color: _getStatusColor(membre.isActive),
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
),
|
||||
child: Text(
|
||||
membre.isActive == true ? 'Actif' : 'Inactif',
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w500,
|
||||
child: Center(
|
||||
child: Tooltip(
|
||||
message: membre.isActive == true ? 'Actif' : 'Inactif',
|
||||
child: Icon(
|
||||
membre.isActive == true ? Icons.check_circle : Icons.cancel,
|
||||
color: membre.isActive == true ? Colors.green : Colors.red,
|
||||
size: 24,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -107,21 +115,21 @@ class MembreRowWidget extends StatelessWidget {
|
||||
// Actions
|
||||
if (onEdit != null || onDelete != null || onResetPassword != null)
|
||||
Expanded(
|
||||
flex: 2,
|
||||
flex: isMobile ? 2 : 2,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
// Bouton reset password (uniquement pour les membres actifs)
|
||||
if (onResetPassword != null && membre.isActive == true)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.lock_reset, size: 22),
|
||||
icon: Icon(Icons.lock_reset, size: isMobile ? 20 : 22),
|
||||
onPressed: () => onResetPassword!(membre),
|
||||
tooltip: 'Réinitialiser le mot de passe',
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
if (onDelete != null)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete, size: 22),
|
||||
icon: Icon(Icons.delete, size: isMobile ? 20 : 22),
|
||||
onPressed: () => onDelete!(membre),
|
||||
tooltip: 'Supprimer',
|
||||
color: theme.colorScheme.error,
|
||||
|
||||
@@ -32,6 +32,8 @@ class MembreTableWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final isMobile = screenWidth < 768;
|
||||
|
||||
return Container(
|
||||
height: height,
|
||||
@@ -61,21 +63,35 @@ class MembreTableWidget extends StatelessWidget {
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// ID
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
'ID',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.primary,
|
||||
// ID - masqué en mobile
|
||||
if (!isMobile)
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
'ID',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Identifiant (username) - masqué en mobile
|
||||
if (!isMobile)
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
'Identifiant',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Prénom (firstName)
|
||||
Expanded(
|
||||
flex: 2,
|
||||
flex: isMobile ? 2 : 2,
|
||||
child: Text(
|
||||
'Prénom',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
@@ -87,7 +103,7 @@ class MembreTableWidget extends StatelessWidget {
|
||||
|
||||
// Nom (name)
|
||||
Expanded(
|
||||
flex: 2,
|
||||
flex: isMobile ? 2 : 2,
|
||||
child: Text(
|
||||
'Nom',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
@@ -97,29 +113,31 @@ class MembreTableWidget extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
|
||||
// Email
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
'Email',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.primary,
|
||||
// Email - masqué en mobile
|
||||
if (!isMobile)
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
'Email',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Rôle (fkRole)
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
'Rôle',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.primary,
|
||||
// Rôle (fkRole) - masqué en mobile
|
||||
if (!isMobile)
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
'Rôle',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Statut
|
||||
Expanded(
|
||||
@@ -136,7 +154,7 @@ class MembreTableWidget extends StatelessWidget {
|
||||
// Actions (si onEdit, onDelete ou onResetPassword sont fournis)
|
||||
if (onEdit != null || onDelete != null || onResetPassword != null)
|
||||
Expanded(
|
||||
flex: 2,
|
||||
flex: isMobile ? 2 : 2,
|
||||
child: Text(
|
||||
'Actions',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
@@ -152,14 +170,14 @@ class MembreTableWidget extends StatelessWidget {
|
||||
|
||||
// Corps du tableau
|
||||
Expanded(
|
||||
child: _buildTableContent(context),
|
||||
child: _buildTableContent(context, isMobile),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTableContent(BuildContext context) {
|
||||
Widget _buildTableContent(BuildContext context, bool isMobile) {
|
||||
// Afficher un indicateur de chargement si isLoading est true
|
||||
if (isLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
@@ -193,6 +211,7 @@ class MembreTableWidget extends StatelessWidget {
|
||||
onResetPassword: onResetPassword,
|
||||
isAlternate: index % 2 == 1,
|
||||
onTap: onEdit != null ? () => onEdit!(membre) : null,
|
||||
isMobile: isMobile,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'dart:math';
|
||||
import 'package:geosector_app/core/data/models/user_model.dart';
|
||||
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
||||
import 'package:geosector_app/core/services/api_service.dart';
|
||||
import 'custom_text_field.dart';
|
||||
|
||||
class UserForm extends StatefulWidget {
|
||||
@@ -10,6 +13,8 @@ class UserForm extends StatefulWidget {
|
||||
final bool readOnly;
|
||||
final bool allowUsernameEdit;
|
||||
final bool allowSectNameEdit;
|
||||
final AmicaleModel? amicale; // Nouveau paramètre pour l'amicale
|
||||
final bool isAdmin; // Nouveau paramètre pour savoir si c'est un admin
|
||||
|
||||
const UserForm({
|
||||
super.key,
|
||||
@@ -18,6 +23,8 @@ class UserForm extends StatefulWidget {
|
||||
this.readOnly = false,
|
||||
this.allowUsernameEdit = false,
|
||||
this.allowSectNameEdit = false,
|
||||
this.amicale,
|
||||
this.isAdmin = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -37,11 +44,19 @@ class _UserFormState extends State<UserForm> {
|
||||
late final TextEditingController _emailController;
|
||||
late final TextEditingController _dateNaissanceController;
|
||||
late final TextEditingController _dateEmbaucheController;
|
||||
late final TextEditingController _passwordController; // Nouveau controller pour le mot de passe
|
||||
|
||||
// Form values
|
||||
int _fkTitre = 1; // 1 = M., 2 = Mme
|
||||
DateTime? _dateNaissance;
|
||||
DateTime? _dateEmbauche;
|
||||
|
||||
// Pour la génération automatique d'username
|
||||
bool _isGeneratingUsername = false;
|
||||
final Random _random = Random();
|
||||
|
||||
// Pour afficher/masquer le mot de passe
|
||||
bool _obscurePassword = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -64,11 +79,34 @@ class _UserFormState extends State<UserForm> {
|
||||
|
||||
_dateEmbaucheController = TextEditingController(text: _dateEmbauche != null ? DateFormat('dd/MM/yyyy').format(_dateEmbauche!) : '');
|
||||
|
||||
_passwordController = TextEditingController(); // Initialiser le controller du mot de passe
|
||||
|
||||
_fkTitre = user?.fkTitre ?? 1;
|
||||
|
||||
// Ajouter des listeners pour auto-générer l'username en création
|
||||
if (widget.user?.id == 0 && widget.isAdmin && widget.amicale?.chkUsernameManuel == true) {
|
||||
_nameController.addListener(_onNameOrSectNameChanged);
|
||||
_sectNameController.addListener(_onNameOrSectNameChanged);
|
||||
}
|
||||
}
|
||||
|
||||
void _onNameOrSectNameChanged() {
|
||||
// Auto-générer username seulement en création et si le champ username est vide
|
||||
if (widget.user?.id == 0 &&
|
||||
_usernameController.text.isEmpty &&
|
||||
(_nameController.text.isNotEmpty || _sectNameController.text.isNotEmpty)) {
|
||||
_generateAndCheckUsername();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Retirer les listeners si ajoutés
|
||||
if (widget.user?.id == 0 && widget.isAdmin && widget.amicale?.chkUsernameManuel == true) {
|
||||
_nameController.removeListener(_onNameOrSectNameChanged);
|
||||
_sectNameController.removeListener(_onNameOrSectNameChanged);
|
||||
}
|
||||
|
||||
_usernameController.dispose();
|
||||
_firstNameController.dispose();
|
||||
_nameController.dispose();
|
||||
@@ -78,6 +116,7 @@ class _UserFormState extends State<UserForm> {
|
||||
_emailController.dispose();
|
||||
_dateNaissanceController.dispose();
|
||||
_dateEmbaucheController.dispose();
|
||||
_passwordController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -98,13 +137,49 @@ class _UserFormState extends State<UserForm> {
|
||||
void _selectDate(BuildContext context, bool isDateNaissance) {
|
||||
// Utiliser un bloc try-catch pour capturer toutes les erreurs possibles
|
||||
try {
|
||||
// Afficher le sélecteur de date sans spécifier de locale
|
||||
// Déterminer la date initiale
|
||||
DateTime initialDate;
|
||||
if (isDateNaissance) {
|
||||
initialDate = _dateNaissance ?? DateTime.now().subtract(const Duration(days: 365 * 30)); // 30 ans par défaut
|
||||
} else {
|
||||
initialDate = _dateEmbauche ?? DateTime.now();
|
||||
}
|
||||
|
||||
// S'assurer que la date initiale est dans la plage autorisée
|
||||
if (initialDate.isAfter(DateTime.now())) {
|
||||
initialDate = DateTime.now();
|
||||
}
|
||||
if (initialDate.isBefore(DateTime(1900))) {
|
||||
initialDate = DateTime(1950);
|
||||
}
|
||||
|
||||
// Afficher le sélecteur de date avec locale française
|
||||
showDatePicker(
|
||||
context: context,
|
||||
initialDate: DateTime.now(), // Toujours utiliser la date actuelle
|
||||
initialDate: initialDate,
|
||||
firstDate: DateTime(1900),
|
||||
lastDate: DateTime.now(),
|
||||
// Ne pas spécifier de locale pour éviter les problèmes
|
||||
locale: const Locale('fr', 'FR'), // Forcer la locale française
|
||||
builder: (context, child) {
|
||||
return Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
colorScheme: Theme.of(context).colorScheme.copyWith(
|
||||
primary: Theme.of(context).colorScheme.primary,
|
||||
onPrimary: Colors.white,
|
||||
surface: Colors.white,
|
||||
onSurface: Colors.black,
|
||||
),
|
||||
),
|
||||
child: child!,
|
||||
);
|
||||
},
|
||||
helpText: isDateNaissance ? 'SÉLECTIONNER LA DATE DE NAISSANCE' : 'SÉLECTIONNER LA DATE D\'EMBAUCHE',
|
||||
cancelText: 'ANNULER',
|
||||
confirmText: 'VALIDER',
|
||||
fieldLabelText: 'Entrer une date',
|
||||
fieldHintText: 'jj/mm/aaaa',
|
||||
errorFormatText: 'Format de date invalide',
|
||||
errorInvalidText: 'Date invalide',
|
||||
).then((DateTime? picked) {
|
||||
// Vérifier si une date a été sélectionnée
|
||||
if (picked != null) {
|
||||
@@ -141,30 +216,247 @@ class _UserFormState extends State<UserForm> {
|
||||
}
|
||||
}
|
||||
|
||||
// Nettoyer une chaîne pour l'username
|
||||
String _cleanString(String input) {
|
||||
return input.toLowerCase()
|
||||
.replaceAll(RegExp(r'[^a-z0-9]'), ''); // Garder seulement lettres et chiffres
|
||||
}
|
||||
|
||||
// Extraire une partie aléatoire d'une chaîne
|
||||
String _extractRandomPart(String input, int minLength, int maxLength) {
|
||||
if (input.isEmpty) return '';
|
||||
final cleaned = _cleanString(input);
|
||||
if (cleaned.isEmpty) return '';
|
||||
|
||||
final length = minLength + _random.nextInt(maxLength - minLength + 1);
|
||||
if (cleaned.length <= length) return cleaned;
|
||||
|
||||
// Prendre les premiers caractères jusqu'à la longueur désirée
|
||||
return cleaned.substring(0, length);
|
||||
}
|
||||
|
||||
// Générer un username selon l'algorithme spécifié
|
||||
String _generateUsername() {
|
||||
// Récupérer les données nécessaires
|
||||
final nom = _nameController.text.isNotEmpty ? _nameController.text : _sectNameController.text;
|
||||
final codePostal = widget.amicale?.codePostal ?? '';
|
||||
final ville = widget.amicale?.ville ?? '';
|
||||
|
||||
// Nettoyer et extraire les parties
|
||||
final nomPart = _extractRandomPart(nom, 2, 5);
|
||||
final cpPart = _extractRandomPart(codePostal, 2, 3);
|
||||
final villePart = _extractRandomPart(ville, 2, 4);
|
||||
final nombreAleatoire = 10 + _random.nextInt(990); // 10 à 999
|
||||
|
||||
// Choisir des séparateurs aléatoires (uniquement ceux autorisés: ., _, -)
|
||||
final separateurs = ['', '.', '_', '-'];
|
||||
final sep1 = separateurs[_random.nextInt(separateurs.length)];
|
||||
final sep2 = separateurs[_random.nextInt(separateurs.length)];
|
||||
|
||||
// Assembler l'username
|
||||
String username = '$nomPart$sep1$cpPart$sep2$villePart$nombreAleatoire';
|
||||
|
||||
// Si trop court, ajouter des chiffres pour atteindre minimum 10 caractères
|
||||
while (username.length < 10) {
|
||||
username += _random.nextInt(10).toString();
|
||||
}
|
||||
|
||||
// S'assurer que l'username ne contient que des caractères autorisés (a-z, 0-9, ., -, _)
|
||||
// Normalement déjà le cas avec notre algorithme, mais au cas où
|
||||
username = username.toLowerCase().replaceAll(RegExp(r'[^a-z0-9._-]'), '');
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
// Vérifier la disponibilité d'un username via l'API
|
||||
Future<Map<String, dynamic>> _checkUsernameAvailability(String username) async {
|
||||
try {
|
||||
final response = await ApiService.instance.post(
|
||||
'/users/check-username',
|
||||
data: {'username': username},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return response.data;
|
||||
}
|
||||
return {'available': false};
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la vérification de l\'username: $e');
|
||||
return {'available': false};
|
||||
}
|
||||
}
|
||||
|
||||
// Générer et vérifier un username jusqu'à en trouver un disponible
|
||||
Future<void> _generateAndCheckUsername() async {
|
||||
if (_isGeneratingUsername) return; // Éviter les appels multiples
|
||||
|
||||
setState(() {
|
||||
_isGeneratingUsername = true;
|
||||
});
|
||||
|
||||
try {
|
||||
int attempts = 0;
|
||||
const maxAttempts = 10;
|
||||
|
||||
while (attempts < maxAttempts) {
|
||||
final username = _generateUsername();
|
||||
debugPrint('Tentative ${attempts + 1}: Vérification de $username');
|
||||
|
||||
final result = await _checkUsernameAvailability(username);
|
||||
|
||||
if (result['available'] == true) {
|
||||
// Username disponible, l'utiliser
|
||||
setState(() {
|
||||
_usernameController.text = username;
|
||||
});
|
||||
debugPrint('✅ Username disponible trouvé: $username');
|
||||
break;
|
||||
} else {
|
||||
// Si l'API propose des suggestions, essayer la première
|
||||
if (result['suggestions'] != null && result['suggestions'].isNotEmpty) {
|
||||
final suggestion = result['suggestions'][0];
|
||||
debugPrint('Vérification de la suggestion: $suggestion');
|
||||
|
||||
final suggestionResult = await _checkUsernameAvailability(suggestion);
|
||||
if (suggestionResult['available'] == true) {
|
||||
setState(() {
|
||||
_usernameController.text = suggestion;
|
||||
});
|
||||
debugPrint('✅ Suggestion disponible utilisée: $suggestion');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attempts++;
|
||||
}
|
||||
|
||||
if (attempts >= maxAttempts) {
|
||||
debugPrint('⚠️ Impossible de trouver un username disponible après $maxAttempts tentatives');
|
||||
}
|
||||
} finally {
|
||||
setState(() {
|
||||
_isGeneratingUsername = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Valider le mot de passe selon les règles
|
||||
String? _validatePassword(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
// Pour un nouveau membre, le mot de passe est obligatoire si le champ est affiché
|
||||
if (widget.user?.id == 0) {
|
||||
return "Veuillez entrer un mot de passe";
|
||||
}
|
||||
return null; // En modification, vide = garder l'ancien
|
||||
}
|
||||
|
||||
// Faire un trim pour retirer les espaces en début/fin
|
||||
final trimmedValue = value.trim();
|
||||
if (trimmedValue.isEmpty) {
|
||||
return "Le mot de passe ne peut pas être vide";
|
||||
}
|
||||
|
||||
// Vérifier qu'il n'y a pas d'espaces dans le mot de passe
|
||||
if (trimmedValue.contains(' ')) {
|
||||
return "Le mot de passe ne doit pas contenir d'espaces";
|
||||
}
|
||||
|
||||
// Vérifier la longueur
|
||||
if (trimmedValue.length < 12) {
|
||||
return "Le mot de passe doit contenir au moins 12 caractères";
|
||||
}
|
||||
if (trimmedValue.length > 16) {
|
||||
return "Le mot de passe ne doit pas dépasser 16 caractères";
|
||||
}
|
||||
|
||||
// Vérifier qu'il n'est pas égal au username (après trim des deux)
|
||||
if (trimmedValue == _usernameController.text.trim()) {
|
||||
return "Le mot de passe ne doit pas être identique au nom d'utilisateur";
|
||||
}
|
||||
|
||||
// Vérifier la présence d'au moins une minuscule
|
||||
if (!trimmedValue.contains(RegExp(r'[a-z]'))) {
|
||||
return "Le mot de passe doit contenir au moins une lettre minuscule";
|
||||
}
|
||||
|
||||
// Vérifier la présence d'au moins une majuscule
|
||||
if (!trimmedValue.contains(RegExp(r'[A-Z]'))) {
|
||||
return "Le mot de passe doit contenir au moins une lettre majuscule";
|
||||
}
|
||||
|
||||
// Vérifier la présence d'au moins un chiffre
|
||||
if (!trimmedValue.contains(RegExp(r'[0-9]'))) {
|
||||
return "Le mot de passe doit contenir au moins un chiffre";
|
||||
}
|
||||
|
||||
// Vérifier la présence d'au moins un caractère spécial
|
||||
if (!trimmedValue.contains(RegExp(r'[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]'))) {
|
||||
return "Le mot de passe doit contenir au moins un caractère spécial (!@#\$%^&*()_+-=[]{}|;:,.<>?)";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Générer un mot de passe aléatoire respectant les règles
|
||||
String _generatePassword() {
|
||||
const String lowercase = 'abcdefghijklmnopqrstuvwxyz';
|
||||
const String uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
const String digits = '0123456789';
|
||||
const String special = '!@#\$%^&*()_+-=[]{}|;:,.<>?';
|
||||
|
||||
// Longueur aléatoire entre 12 et 16
|
||||
final length = 12 + _random.nextInt(5);
|
||||
|
||||
// S'assurer d'avoir au moins un caractère de chaque type
|
||||
List<String> password = [];
|
||||
password.add(lowercase[_random.nextInt(lowercase.length)]);
|
||||
password.add(uppercase[_random.nextInt(uppercase.length)]);
|
||||
password.add(digits[_random.nextInt(digits.length)]);
|
||||
password.add(special[_random.nextInt(special.length)]);
|
||||
|
||||
// Compléter avec des caractères aléatoires
|
||||
const String allChars = lowercase + uppercase + digits + special;
|
||||
for (int i = password.length; i < length; i++) {
|
||||
password.add(allChars[_random.nextInt(allChars.length)]);
|
||||
}
|
||||
|
||||
// Mélanger les caractères
|
||||
password.shuffle(_random);
|
||||
|
||||
return password.join('');
|
||||
}
|
||||
|
||||
// Méthode publique pour récupérer le mot de passe si défini
|
||||
String? getPassword() {
|
||||
final password = _passwordController.text.trim();
|
||||
return password.isNotEmpty ? password : null;
|
||||
}
|
||||
|
||||
// Méthode publique pour valider et récupérer l'utilisateur
|
||||
UserModel? validateAndGetUser() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
return widget.user?.copyWith(
|
||||
username: _usernameController.text,
|
||||
firstName: _firstNameController.text,
|
||||
name: _nameController.text,
|
||||
sectName: _sectNameController.text,
|
||||
phone: _phoneController.text,
|
||||
mobile: _mobileController.text,
|
||||
email: _emailController.text,
|
||||
username: _usernameController.text.trim(), // Appliquer trim
|
||||
firstName: _firstNameController.text.trim(),
|
||||
name: _nameController.text.trim(),
|
||||
sectName: _sectNameController.text.trim(),
|
||||
phone: _phoneController.text.trim(),
|
||||
mobile: _mobileController.text.trim(),
|
||||
email: _emailController.text.trim(),
|
||||
fkTitre: _fkTitre,
|
||||
dateNaissance: _dateNaissance,
|
||||
dateEmbauche: _dateEmbauche,
|
||||
) ??
|
||||
UserModel(
|
||||
id: 0,
|
||||
username: _usernameController.text,
|
||||
firstName: _firstNameController.text,
|
||||
name: _nameController.text,
|
||||
sectName: _sectNameController.text,
|
||||
phone: _phoneController.text,
|
||||
mobile: _mobileController.text,
|
||||
email: _emailController.text,
|
||||
username: _usernameController.text.trim(), // Appliquer trim
|
||||
firstName: _firstNameController.text.trim(),
|
||||
name: _nameController.text.trim(),
|
||||
sectName: _sectNameController.text.trim(),
|
||||
phone: _phoneController.text.trim(),
|
||||
mobile: _mobileController.text.trim(),
|
||||
email: _emailController.text.trim(),
|
||||
fkTitre: _fkTitre,
|
||||
dateNaissance: _dateNaissance,
|
||||
dateEmbauche: _dateEmbauche,
|
||||
@@ -180,90 +472,36 @@ class _UserFormState extends State<UserForm> {
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final isWideScreen = MediaQuery.of(context).size.width > 900;
|
||||
|
||||
// Déterminer si on doit afficher le champ username selon les règles
|
||||
final bool shouldShowUsernameField = widget.isAdmin && widget.amicale?.chkUsernameManuel == true;
|
||||
// Déterminer si le username est éditable (seulement en création, jamais en modification)
|
||||
final bool canEditUsername = shouldShowUsernameField && widget.allowUsernameEdit && widget.user?.id == 0;
|
||||
// Déterminer si on doit afficher le champ mot de passe
|
||||
final bool shouldShowPasswordField = widget.isAdmin && widget.amicale?.chkMdpManuel == true;
|
||||
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Ligne 1: Username et Email (si écran large)
|
||||
if (isWideScreen)
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextField(
|
||||
controller: _usernameController,
|
||||
label: "Nom d'utilisateur",
|
||||
readOnly: !widget.allowUsernameEdit, // Utiliser le paramètre
|
||||
prefixIcon: Icons.account_circle,
|
||||
isRequired: widget.allowUsernameEdit,
|
||||
validator: widget.allowUsernameEdit
|
||||
? (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Veuillez entrer le nom d'utilisateur";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
: null,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: CustomTextField(
|
||||
controller: _emailController,
|
||||
label: "Email",
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
readOnly: widget.readOnly,
|
||||
isRequired: true, // Email toujours obligatoire
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Veuillez entrer l'adresse email";
|
||||
}
|
||||
if (!value.contains('@') || !value.contains('.')) {
|
||||
return "Veuillez entrer une adresse email valide";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
else ...[
|
||||
// Version mobile: Username seul
|
||||
CustomTextField(
|
||||
controller: _usernameController,
|
||||
label: "Nom d'utilisateur",
|
||||
readOnly: !widget.allowUsernameEdit, // Utiliser le paramètre
|
||||
prefixIcon: Icons.account_circle,
|
||||
isRequired: widget.allowUsernameEdit, // Obligatoire si éditable
|
||||
validator: widget.allowUsernameEdit
|
||||
? (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Veuillez entrer le nom d'utilisateur";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
: null,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Email seul en mobile
|
||||
CustomTextField(
|
||||
controller: _emailController,
|
||||
label: "Email",
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
readOnly: widget.readOnly,
|
||||
isRequired: true, // Email toujours obligatoire
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Veuillez entrer l'adresse email";
|
||||
}
|
||||
if (!value.contains('@') || !value.contains('.')) {
|
||||
return "Veuillez entrer une adresse email valide";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
],
|
||||
// Email seul sur la première ligne
|
||||
CustomTextField(
|
||||
controller: _emailController,
|
||||
label: "Email",
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
readOnly: widget.readOnly,
|
||||
isRequired: true,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Veuillez entrer l'adresse email";
|
||||
}
|
||||
if (!value.contains('@') || !value.contains('.')) {
|
||||
return "Veuillez entrer une adresse email valide";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Titre (M. ou Mme)
|
||||
@@ -378,7 +616,7 @@ class _UserFormState extends State<UserForm> {
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
|
||||
// Ligne 3: Téléphones (fixe et mobile)
|
||||
// Ligne 2: Téléphones (fixe et mobile)
|
||||
if (isWideScreen)
|
||||
Row(
|
||||
children: [
|
||||
@@ -458,6 +696,224 @@ class _UserFormState extends State<UserForm> {
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Ligne 3: Username et Password (si applicable)
|
||||
if (shouldShowUsernameField || shouldShowPasswordField) ...[
|
||||
if (isWideScreen)
|
||||
Row(
|
||||
children: [
|
||||
if (shouldShowUsernameField)
|
||||
Expanded(
|
||||
child: CustomTextField(
|
||||
controller: _usernameController,
|
||||
label: "Nom d'utilisateur",
|
||||
readOnly: !canEditUsername,
|
||||
prefixIcon: Icons.account_circle,
|
||||
isRequired: canEditUsername,
|
||||
suffixIcon: (widget.user?.id == 0 && canEditUsername)
|
||||
? _isGeneratingUsername
|
||||
? SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
)
|
||||
: IconButton(
|
||||
icon: Icon(Icons.refresh),
|
||||
onPressed: _generateAndCheckUsername,
|
||||
tooltip: "Générer un nom d'utilisateur",
|
||||
)
|
||||
: null,
|
||||
helperText: canEditUsername
|
||||
? "Min. 10 caractères (a-z, 0-9, . - _)"
|
||||
: null,
|
||||
validator: canEditUsername
|
||||
? (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Veuillez entrer le nom d'utilisateur";
|
||||
}
|
||||
// Faire un trim pour retirer les espaces en début/fin
|
||||
final trimmedValue = value.trim();
|
||||
if (trimmedValue.isEmpty) {
|
||||
return "Le nom d'utilisateur ne peut pas être vide";
|
||||
}
|
||||
// Vérifier qu'il n'y a pas d'espaces dans l'username
|
||||
if (trimmedValue.contains(' ')) {
|
||||
return "Le nom d'utilisateur ne doit pas contenir d'espaces";
|
||||
}
|
||||
// Vérifier la longueur minimale
|
||||
if (trimmedValue.length < 10) {
|
||||
return "Le nom d'utilisateur doit contenir au moins 10 caractères";
|
||||
}
|
||||
// Vérifier les caractères autorisés (a-z, 0-9, ., -, _)
|
||||
if (!RegExp(r'^[a-z0-9._-]+$').hasMatch(trimmedValue)) {
|
||||
return "Caractères autorisés : lettres minuscules, chiffres, . - _";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
: null,
|
||||
),
|
||||
),
|
||||
if (shouldShowUsernameField && shouldShowPasswordField)
|
||||
const SizedBox(width: 16),
|
||||
if (shouldShowPasswordField)
|
||||
Expanded(
|
||||
child: CustomTextField(
|
||||
controller: _passwordController,
|
||||
label: "Mot de passe",
|
||||
obscureText: _obscurePassword,
|
||||
readOnly: widget.readOnly,
|
||||
prefixIcon: Icons.lock,
|
||||
suffixIcon: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Bouton pour afficher/masquer le mot de passe
|
||||
IconButton(
|
||||
icon: Icon(_obscurePassword ? Icons.visibility : Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_obscurePassword = !_obscurePassword;
|
||||
});
|
||||
},
|
||||
tooltip: _obscurePassword ? "Afficher le mot de passe" : "Masquer le mot de passe",
|
||||
),
|
||||
// Bouton pour générer un mot de passe (seulement si éditable)
|
||||
if (!widget.readOnly)
|
||||
IconButton(
|
||||
icon: Icon(Icons.auto_awesome),
|
||||
onPressed: () {
|
||||
final newPassword = _generatePassword();
|
||||
setState(() {
|
||||
_passwordController.text = newPassword;
|
||||
_obscurePassword = false; // Afficher le mot de passe généré
|
||||
});
|
||||
// Revalider le formulaire
|
||||
_formKey.currentState?.validate();
|
||||
},
|
||||
tooltip: "Générer un mot de passe sécurisé",
|
||||
),
|
||||
],
|
||||
),
|
||||
helperText: widget.user?.id != 0
|
||||
? "Laissez vide pour conserver le mot de passe actuel"
|
||||
: "12-16 car. avec min/maj, chiffres et spéciaux (!@#\$%^&*()_+-=[]{}|;:,.<>?)",
|
||||
validator: _validatePassword,
|
||||
),
|
||||
),
|
||||
// Si seulement un des deux est affiché, ajouter un Expanded vide pour garder l'alignement
|
||||
if ((shouldShowUsernameField && !shouldShowPasswordField) || (!shouldShowUsernameField && shouldShowPasswordField))
|
||||
const Expanded(child: SizedBox()),
|
||||
],
|
||||
)
|
||||
else ...[
|
||||
// Version mobile: Username et Password séparés
|
||||
if (shouldShowUsernameField) ...[
|
||||
CustomTextField(
|
||||
controller: _usernameController,
|
||||
label: "Nom d'utilisateur",
|
||||
readOnly: !canEditUsername,
|
||||
prefixIcon: Icons.account_circle,
|
||||
isRequired: canEditUsername,
|
||||
suffixIcon: (widget.user?.id == 0 && canEditUsername)
|
||||
? _isGeneratingUsername
|
||||
? SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
)
|
||||
: IconButton(
|
||||
icon: Icon(Icons.refresh),
|
||||
onPressed: _generateAndCheckUsername,
|
||||
tooltip: "Générer un nom d'utilisateur",
|
||||
)
|
||||
: null,
|
||||
helperText: canEditUsername
|
||||
? "Min. 10 caractères (a-z, 0-9, . - _)"
|
||||
: null,
|
||||
validator: canEditUsername
|
||||
? (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Veuillez entrer le nom d'utilisateur";
|
||||
}
|
||||
// Faire un trim pour retirer les espaces en début/fin
|
||||
final trimmedValue = value.trim();
|
||||
if (trimmedValue.isEmpty) {
|
||||
return "Le nom d'utilisateur ne peut pas être vide";
|
||||
}
|
||||
// Vérifier qu'il n'y a pas d'espaces dans l'username
|
||||
if (trimmedValue.contains(' ')) {
|
||||
return "Le nom d'utilisateur ne doit pas contenir d'espaces";
|
||||
}
|
||||
// Vérifier la longueur minimale
|
||||
if (trimmedValue.length < 10) {
|
||||
return "Le nom d'utilisateur doit contenir au moins 10 caractères";
|
||||
}
|
||||
// Vérifier les caractères autorisés (a-z, 0-9, ., -, _)
|
||||
if (!RegExp(r'^[a-z0-9._-]+$').hasMatch(trimmedValue)) {
|
||||
return "Caractères autorisés : lettres minuscules, chiffres, . - _";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
: null,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
if (shouldShowPasswordField) ...[
|
||||
CustomTextField(
|
||||
controller: _passwordController,
|
||||
label: "Mot de passe",
|
||||
obscureText: _obscurePassword,
|
||||
readOnly: widget.readOnly,
|
||||
prefixIcon: Icons.lock,
|
||||
suffixIcon: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Bouton pour afficher/masquer le mot de passe
|
||||
IconButton(
|
||||
icon: Icon(_obscurePassword ? Icons.visibility : Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_obscurePassword = !_obscurePassword;
|
||||
});
|
||||
},
|
||||
tooltip: _obscurePassword ? "Afficher le mot de passe" : "Masquer le mot de passe",
|
||||
),
|
||||
// Bouton pour générer un mot de passe (seulement si éditable)
|
||||
if (!widget.readOnly)
|
||||
IconButton(
|
||||
icon: Icon(Icons.auto_awesome),
|
||||
onPressed: () {
|
||||
final newPassword = _generatePassword();
|
||||
setState(() {
|
||||
_passwordController.text = newPassword;
|
||||
_obscurePassword = false; // Afficher le mot de passe généré
|
||||
});
|
||||
// Revalider le formulaire
|
||||
_formKey.currentState?.validate();
|
||||
},
|
||||
tooltip: "Générer un mot de passe sécurisé",
|
||||
),
|
||||
],
|
||||
),
|
||||
helperText: widget.user?.id != 0
|
||||
? "Laissez vide pour conserver le mot de passe actuel"
|
||||
: "12-16 car. avec min/maj, chiffres et spéciaux (!@#\$%^&*()_+-=[]{}|;:,.<>?)",
|
||||
validator: _validatePassword,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
|
||||
// Ligne 4: Dates (naissance et embauche)
|
||||
if (isWideScreen)
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geosector_app/core/data/models/user_model.dart';
|
||||
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
||||
import 'package:geosector_app/presentation/widgets/user_form.dart';
|
||||
|
||||
class UserFormDialog extends StatefulWidget {
|
||||
final UserModel? user;
|
||||
final String title;
|
||||
final bool readOnly;
|
||||
final Function(UserModel)? onSubmit;
|
||||
final Function(UserModel, {String? password})? onSubmit; // Modifié pour inclure le mot de passe
|
||||
final bool showRoleSelector;
|
||||
final List<RoleOption>? availableRoles;
|
||||
final bool showActiveCheckbox;
|
||||
final bool allowUsernameEdit;
|
||||
final AmicaleModel? amicale; // Nouveau paramètre
|
||||
final bool isAdmin; // Nouveau paramètre
|
||||
|
||||
const UserFormDialog({
|
||||
super.key,
|
||||
@@ -22,6 +25,8 @@ class UserFormDialog extends StatefulWidget {
|
||||
this.availableRoles,
|
||||
this.showActiveCheckbox = false,
|
||||
this.allowUsernameEdit = false,
|
||||
this.amicale,
|
||||
this.isAdmin = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -55,6 +60,7 @@ class _UserFormDialogState extends State<UserFormDialog> {
|
||||
void _handleSubmit() async {
|
||||
// Utiliser la méthode validateAndGetUser du UserForm
|
||||
final userData = _userFormKey.currentState?.validateAndGetUser();
|
||||
final password = _userFormKey.currentState?.getPassword(); // Récupérer le mot de passe
|
||||
|
||||
if (userData != null) {
|
||||
var finalUser = userData;
|
||||
@@ -70,7 +76,7 @@ class _UserFormDialogState extends State<UserFormDialog> {
|
||||
}
|
||||
|
||||
if (widget.onSubmit != null) {
|
||||
widget.onSubmit!(finalUser);
|
||||
widget.onSubmit!(finalUser, password: password); // Passer le mot de passe
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,6 +206,8 @@ class _UserFormDialogState extends State<UserFormDialog> {
|
||||
readOnly: widget.readOnly,
|
||||
allowUsernameEdit: widget.allowUsernameEdit,
|
||||
allowSectNameEdit: widget.allowUsernameEdit,
|
||||
amicale: widget.amicale, // Passer l'amicale
|
||||
isAdmin: widget.isAdmin, // Passer isAdmin
|
||||
onSubmit: null, // Pas besoin de callback
|
||||
),
|
||||
],
|
||||
|
||||
1
app/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux
Symbolic link
1
app/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux
Symbolic link
@@ -0,0 +1 @@
|
||||
/home/pierre/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/
|
||||
1
app/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux
Symbolic link
1
app/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux
Symbolic link
@@ -0,0 +1 @@
|
||||
/home/pierre/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.1+2/
|
||||
@@ -6,9 +6,13 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_linux
|
||||
url_launcher_linux
|
||||
)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import connectivity_plus
|
||||
import file_selector_macos
|
||||
import flutter_local_notifications
|
||||
import geolocator_apple
|
||||
import package_info_plus
|
||||
@@ -15,6 +16,7 @@ import url_launcher_macos
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||
|
||||
@@ -3,8 +3,8 @@ FLUTTER_ROOT=/home/pierre/dev/flutter
|
||||
FLUTTER_APPLICATION_PATH=/home/pierre/dev/geosector/app
|
||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||
FLUTTER_BUILD_DIR=build
|
||||
FLUTTER_BUILD_NAME=3.0.4
|
||||
FLUTTER_BUILD_NUMBER=304
|
||||
FLUTTER_BUILD_NAME=3.0.6
|
||||
FLUTTER_BUILD_NUMBER=306
|
||||
DART_OBFUSCATION=false
|
||||
TRACK_WIDGET_CREATION=true
|
||||
TREE_SHAKE_ICONS=false
|
||||
|
||||
@@ -4,8 +4,8 @@ export "FLUTTER_ROOT=/home/pierre/dev/flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=/home/pierre/dev/geosector/app"
|
||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "FLUTTER_BUILD_NAME=3.0.4"
|
||||
export "FLUTTER_BUILD_NUMBER=304"
|
||||
export "FLUTTER_BUILD_NAME=3.0.6"
|
||||
export "FLUTTER_BUILD_NUMBER=306"
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=true"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
|
||||
145
app/pubspec.lock
145
app/pubspec.lock
@@ -114,10 +114,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: "0b1b12a0a549605e5f04476031cd0bc91ead1d7c8e830773a18ee54179b3cb62"
|
||||
sha256: ba95c961bafcd8686d1cf63be864eb59447e795e124d98d6a27d91fcd13602fb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.11.0"
|
||||
version: "8.11.1"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -198,6 +198,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
cross_file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cross_file
|
||||
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.4+2"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -258,10 +266,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dio
|
||||
sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9"
|
||||
sha256: d90ee57923d1828ac14e492ca49440f65477f4bb1263575900be731a3dac66a9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.8.0+1"
|
||||
version: "5.9.0"
|
||||
dio_cache_interceptor:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -318,6 +326,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
file_selector_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_linux
|
||||
sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.3+2"
|
||||
file_selector_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_macos
|
||||
sha256: "8c9250b2bd2d8d4268e39c82543bacbaca0fda7d29e0728c3c4bbb7c820fd711"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.4+3"
|
||||
file_selector_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_platform_interface
|
||||
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.2"
|
||||
file_selector_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_windows
|
||||
sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.3+4"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -387,6 +427,11 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
flutter_localizations:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_map:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -403,6 +448,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0+1"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: "6382ce712ff69b0f719640ce957559dde459e55ecd433c767e06d139ddf16cab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.29"
|
||||
flutter_svg:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -569,10 +622,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "85ab0074f9bf2b24625906d8382bbec84d3d6919d285ba9c106b07b65791fb99"
|
||||
sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.0-beta.2"
|
||||
version: "1.5.0"
|
||||
http_cache_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -613,6 +666,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.4"
|
||||
image_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image_picker
|
||||
sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
image_picker_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_android
|
||||
sha256: b08e9a04d0f8d91f4a6e767a745b9871bfbc585410205c311d0492de20a7ccd6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.12+25"
|
||||
image_picker_for_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_for_web
|
||||
sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.6"
|
||||
image_picker_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_ios
|
||||
sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.12+2"
|
||||
image_picker_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_linux
|
||||
sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+2"
|
||||
image_picker_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_macos
|
||||
sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+2"
|
||||
image_picker_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_platform_interface
|
||||
sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.10.1"
|
||||
image_picker_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_windows
|
||||
sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+1"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -945,10 +1062,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
|
||||
sha256: "5bcf0772a761b04f8c6bf814721713de6f3e5d9d89caf8d3fe031b02a342379e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.10"
|
||||
version: "2.4.11"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1078,18 +1195,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: syncfusion_flutter_charts
|
||||
sha256: "55bc6210265483eba4ea168931e4edd3df24510d1ea99c177df46d69ab0deb6f"
|
||||
sha256: a2263d6221b17d49ea9c23709df8796abde4cd2d2664960d48fac62b9d8c3eb8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "30.1.42"
|
||||
version: "30.2.4"
|
||||
syncfusion_flutter_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: syncfusion_flutter_core
|
||||
sha256: f999f11af9c54bd46ceb478273e06774d28723ffa2c622d2d6e7e84a358c23e0
|
||||
sha256: "9d6b7722331e8c84e837d852da03f3735bf436fe6ebf2acc3455a2a21a0d47ff"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "30.1.42"
|
||||
version: "30.2.4"
|
||||
synchronized:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1174,10 +1291,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79"
|
||||
sha256: "0aedad096a85b49df2e4725fa32118f9fa580f3b14af7a2d2221896a02cd5656"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.16"
|
||||
version: "6.3.17"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: geosector_app
|
||||
description: 'GEOSECTOR - Gestion de distribution des calendriers par secteurs géographiques pour les amicales de pompiers'
|
||||
publish_to: 'none'
|
||||
version: 3.0.4+304
|
||||
version: 3.0.6+306
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
@@ -9,6 +9,8 @@ environment:
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
cupertino_icons: ^1.0.6
|
||||
|
||||
# Navigation
|
||||
@@ -49,6 +51,9 @@ dependencies:
|
||||
mqtt5_client: ^4.11.0
|
||||
flutter_local_notifications: ^19.0.1
|
||||
|
||||
# Upload d'images
|
||||
image_picker: ^1.1.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/home/pierre/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/
|
||||
@@ -0,0 +1 @@
|
||||
/home/pierre/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.1+1/
|
||||
@@ -7,12 +7,15 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <geolocator_windows/geolocator_windows.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
GeolocatorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("GeolocatorWindows"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
connectivity_plus
|
||||
file_selector_windows
|
||||
geolocator_windows
|
||||
url_launcher_windows
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user