diff --git a/.flutter-plugins b/.flutter-plugins index 6dce445..07732e3 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,6 +1,6 @@ # This is a generated file; do not edit or check into version control. -camera=/Users/jaumard/.pub-cache/hosted/pub.dartlang.org/camera-0.10.0/ -camera_android=/Users/jaumard/.pub-cache/hosted/pub.dartlang.org/camera_android-0.10.0/ -camera_avfoundation=/Users/jaumard/.pub-cache/hosted/pub.dartlang.org/camera_avfoundation-0.9.8+2/ -camera_web=/Users/jaumard/.pub-cache/hosted/pub.dartlang.org/camera_web-0.3.0/ -flutter_plugin_android_lifecycle=/Users/jaumard/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/ +camera=/home/elwiss/.pub-cache/hosted/pub.dartlang.org/camera-0.10.1/ +camera_android=/home/elwiss/.pub-cache/hosted/pub.dartlang.org/camera_android-0.10.2/ +camera_avfoundation=/home/elwiss/.pub-cache/hosted/pub.dartlang.org/camera_avfoundation-0.9.10/ +camera_web=/home/elwiss/.pub-cache/hosted/pub.dartlang.org/camera_web-0.3.1/ +flutter_plugin_android_lifecycle=/home/elwiss/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 735e6fb..6adc1b9 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"camera_avfoundation","path":"/Users/jaumard/.pub-cache/hosted/pub.dartlang.org/camera_avfoundation-0.9.8+2/","native_build":true,"dependencies":[]}],"android":[{"name":"camera_android","path":"/Users/jaumard/.pub-cache/hosted/pub.dartlang.org/camera_android-0.10.0/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/jaumard/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[{"name":"camera_web","path":"/Users/jaumard/.pub-cache/hosted/pub.dartlang.org/camera_web-0.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"camera","dependencies":["camera_android","camera_avfoundation","camera_web","flutter_plugin_android_lifecycle"]},{"name":"camera_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"camera_avfoundation","dependencies":[]},{"name":"camera_web","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]}],"date_created":"2022-07-13 14:19:13.511429","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"camera_avfoundation","path":"/home/elwiss/.pub-cache/hosted/pub.dartlang.org/camera_avfoundation-0.9.10/","native_build":true,"dependencies":[]}],"android":[{"name":"camera_android","path":"/home/elwiss/.pub-cache/hosted/pub.dartlang.org/camera_android-0.10.2/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/home/elwiss/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[{"name":"camera_web","path":"/home/elwiss/.pub-cache/hosted/pub.dartlang.org/camera_web-0.3.1/","dependencies":[]}]},"dependencyGraph":[{"name":"camera","dependencies":["camera_android","camera_avfoundation","camera_web","flutter_plugin_android_lifecycle"]},{"name":"camera_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"camera_avfoundation","dependencies":[]},{"name":"camera_web","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]}],"date_created":"2023-01-09 10:48:50.406166","version":"3.3.10"} \ No newline at end of file diff --git a/example/.metadata b/example/.metadata index ed0b518..32d8944 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled. version: - revision: cd41fdd495f6944ecd3506c21e94c6567b073278 + revision: 135454af32477f815a7525073027a3ff9eff1bfd channel: stable project_type: app @@ -13,26 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 - base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 - - platform: android - create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 - base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 - - platform: ios - create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 - base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 - - platform: linux - create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 - base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 - - platform: macos - create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 - base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 + create_revision: 135454af32477f815a7525073027a3ff9eff1bfd + base_revision: 135454af32477f815a7525073027a3ff9eff1bfd - platform: web - create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 - base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 - - platform: windows - create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 - base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 + create_revision: 135454af32477f815a7525073027a3ff9eff1bfd + base_revision: 135454af32477f815a7525073027a3ff9eff1bfd # User provided section diff --git a/example/pubspec.lock b/example/pubspec.lock index 8fe66ea..41aee62 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.2" + version: "2.9.0" boolean_selector: dependency: transitive description: @@ -63,21 +63,14 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" + version: "1.2.1" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: @@ -105,7 +98,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" flutter: dependency: "direct main" description: flutter @@ -162,28 +155,28 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.11" + version: "0.12.12" material_color_utilities: dependency: transitive description: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.1.5" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" plugin_platform_interface: dependency: transitive description: @@ -209,7 +202,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.9.0" stack_trace: dependency: transitive description: @@ -237,21 +230,21 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.12" vector_math: dependency: transitive description: diff --git a/example/web/favicon.png b/example/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/example/web/favicon.png differ diff --git a/example/web/icons/Icon-192.png b/example/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/example/web/icons/Icon-192.png differ diff --git a/example/web/icons/Icon-512.png b/example/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/example/web/icons/Icon-512.png differ diff --git a/example/web/icons/Icon-maskable-192.png b/example/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/example/web/icons/Icon-maskable-192.png differ diff --git a/example/web/icons/Icon-maskable-512.png b/example/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/example/web/icons/Icon-maskable-512.png differ diff --git a/example/web/index.html b/example/web/index.html new file mode 100644 index 0000000..41b3bc3 --- /dev/null +++ b/example/web/index.html @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + example + + + + + + + + + + diff --git a/example/web/manifest.json b/example/web/manifest.json new file mode 100644 index 0000000..096edf8 --- /dev/null +++ b/example/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/lib/camera_picker.dart b/lib/camera_picker.dart index 13eb4a0..b2bc18f 100644 --- a/lib/camera_picker.dart +++ b/lib/camera_picker.dart @@ -6,10 +6,12 @@ import 'dart:io'; import 'package:camera/camera.dart'; import 'package:camera_picker/src/picker_store.dart'; import 'package:collection/collection.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; export 'package:cross_file/cross_file.dart'; +export 'package:camera/camera.dart'; const _defaultPreviewHeight = 60.0; const _defaultPreviewWidth = 80.0; @@ -74,7 +76,10 @@ class CameraPicker extends HookWidget { @override Widget build(BuildContext context) { - final store = useMemoized(() => PickerStore(filesData: List.from(initialFiles ?? []), minPicture: minPicture, maxPicture: maxPicture)); + final store = useMemoized(() => PickerStore( + filesData: List.from(initialFiles ?? []), + minPicture: minPicture, + maxPicture: maxPicture)); final availableCamerasFuture = useMemoized(() => availableCameras()); final cameras = useState?>(null); return Material( @@ -91,7 +96,8 @@ class CameraPicker extends HookWidget { } }); - if (snapshot.connectionState == ConnectionState.waiting || cameras.value == null) { + if (snapshot.connectionState == ConnectionState.waiting || + cameras.value == null) { return const Center(child: CircularProgressIndicator()); } @@ -104,7 +110,8 @@ class CameraPicker extends HookWidget { children: [ Text( 'No camera available', - style: TextStyle(color: Theme.of(context).errorColor), + style: + TextStyle(color: Theme.of(context).errorColor), ), const SizedBox(height: 10), ElevatedButton( @@ -119,13 +126,16 @@ class CameraPicker extends HookWidget { return HookBuilder(builder: (context) { final cameraControllerState = useState(CameraController( - cameras.value!.firstWhereOrNull((element) => element.lensDirection == CameraLensDirection.back) ?? cameras.value!.first, + cameras.value!.firstWhereOrNull((element) => + element.lensDirection == CameraLensDirection.back) ?? + cameras.value!.first, resolutionPreset, enableAudio: false, )); final isBackCamera = useState(true); final cameraController = cameraControllerState.value; - final initializeCamera = useMemoized(() => cameraController.initialize(), [cameraController]); + final initializeCamera = useMemoized( + () => cameraController.initialize(), [cameraController]); return WillPopScope( onWillPop: () async { @@ -135,8 +145,10 @@ class CameraPicker extends HookWidget { child: FutureBuilder( future: initializeCamera, builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); + if (snapshot.connectionState == + ConnectionState.waiting) { + return const Center( + child: CircularProgressIndicator()); } return CameraPreview( @@ -156,46 +168,65 @@ class CameraPicker extends HookWidget { onPressed: () { if (mode.value == FlashMode.auto) { mode.value = FlashMode.torch; - cameraController.setFlashMode(FlashMode.torch); + cameraController + .setFlashMode(FlashMode.torch); } else { mode.value = FlashMode.auto; - cameraController.setFlashMode(FlashMode.auto); + cameraController + .setFlashMode(FlashMode.auto); } }, - icon: Icon(mode.value == FlashMode.auto ? Icons.flashlight_on_outlined : Icons.flashlight_on), + icon: Icon(mode.value == FlashMode.auto + ? Icons.flashlight_on_outlined + : Icons.flashlight_on), color: iconColor, ); }), ), - if (showSwitchCameraButton && cameras.value!.length > 1) + if (showSwitchCameraButton && + cameras.value!.length > 1) Positioned( top: 10, left: 10, child: IconButton( onPressed: () { if (isBackCamera.value) { - cameraControllerState.value = CameraController( - cameras.value!.firstWhereOrNull((element) => element.lensDirection == CameraLensDirection.front) ?? + cameraControllerState.value = + CameraController( + cameras.value!.firstWhereOrNull( + (element) => + element.lensDirection == + CameraLensDirection + .front) ?? cameras.value!.last, resolutionPreset, enableAudio: false, ); } else { - cameraControllerState.value = CameraController( - cameras.value!.firstWhereOrNull((element) => element.lensDirection == CameraLensDirection.back) ?? + cameraControllerState.value = + CameraController( + cameras.value!.firstWhereOrNull( + (element) => + element.lensDirection == + CameraLensDirection + .back) ?? cameras.value!.first, resolutionPreset, enableAudio: false, ); } - isBackCamera.value = !isBackCamera.value; + isBackCamera.value = + !isBackCamera.value; }, - icon: Icon(isBackCamera.value ? Icons.camera_front_outlined : Icons.camera_rear_outlined), + icon: Icon(isBackCamera.value + ? Icons.camera_front_outlined + : Icons.camera_rear_outlined), color: iconColor, ), ), Padding( - padding: const EdgeInsets.symmetric(vertical: 12), + padding: + const EdgeInsets.symmetric(vertical: 12), child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ @@ -208,16 +239,21 @@ class CameraPicker extends HookWidget { previewWidth: previewWidth, previewHeight: previewHeight, onDelete: (index) async { - if (onDelete == null || await onDelete!(store.filesData[index])) { - store.removeFile(store.filesData[index]); + if (onDelete == null || + await onDelete!( + store.filesData[index])) { + store.removeFile( + store.filesData[index]); } }, ); }), const SizedBox(height: 10), Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + crossAxisAlignment: + CrossAxisAlignment.end, children: [ if (showCancelButton) IconButton( @@ -225,7 +261,9 @@ class CameraPicker extends HookWidget { cameraController.dispose(); Navigator.of(context).pop(); }, - tooltip: MaterialLocalizations.of(context).cancelButtonLabel, + tooltip: MaterialLocalizations.of( + context) + .cancelButtonLabel, color: iconColor, enableFeedback: true, icon: const Icon(Icons.close), @@ -233,7 +271,9 @@ class CameraPicker extends HookWidget { IconButton( onPressed: () async { try { - final file = await cameraController.takePicture(); + final file = + await cameraController + .takePicture(); store.addFile(file); } catch (ex, stack) { onError?.call(ex, stack); @@ -251,12 +291,16 @@ class CameraPicker extends HookWidget { return IconButton( onPressed: store.canContinue ? () { - cameraController.dispose(); - Navigator.of(context).pop(store.filesData); + cameraController + .dispose(); + Navigator.of(context) + .pop(store.filesData); } : null, enableFeedback: true, - tooltip: MaterialLocalizations.of(context).okButtonLabel, + tooltip: MaterialLocalizations.of( + context) + .okButtonLabel, icon: const Icon(Icons.check), disabledColor: Colors.grey[600], color: iconColor, @@ -315,15 +359,15 @@ class ImagesPreview extends HookWidget { @override Widget build(BuildContext context) { - final ioFiles = useMemoized(() => files.map((e) => File(e.path)).toList(), [files, files.length]); + // final ioFiles = useMemoized(() => files.map((e) => File(e.path)).toList(), [files, files.length]); return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: [ - for (var i = 0; i < ioFiles.length; i++) + for (var i = 0; i < files.length; i++) ImagePreview( - file: ioFiles[i], + file: files[i], previewHeight: previewHeight, previewWidth: previewWidth, borderColor: borderColor, @@ -343,7 +387,7 @@ class ImagesPreview extends HookWidget { /// Preview on one single image use in [ImagePreviews] class ImagePreview extends StatelessWidget { // File to preview - final File file; + final XFile file; /// Border color of the preview final Color borderColor; @@ -380,12 +424,20 @@ class ImagePreview extends StatelessWidget { padding: const EdgeInsets.all(1), child: Stack( children: [ - Image.file( - file, - height: previewHeight, - width: previewWidth, - fit: BoxFit.cover, - ), + if (!kIsWeb) + Image.file( + File(file.path), + height: previewHeight, + width: previewWidth, + fit: BoxFit.cover, + ), + if (kIsWeb) + Image.network( + file.path, + height: previewHeight, + width: previewWidth, + fit: BoxFit.cover, + ), if (onDelete != null) Positioned( top: -10, @@ -394,7 +446,8 @@ class ImagePreview extends StatelessWidget { onPressed: onDelete, color: iconColor, iconSize: 18, - tooltip: MaterialLocalizations.of(context).deleteButtonTooltip, + tooltip: + MaterialLocalizations.of(context).deleteButtonTooltip, icon: const Icon(Icons.cancel), ), )