@@ -8,6 +8,7 @@ import 'dart:async';
8
8
import 'dart:io' ;
9
9
10
10
import 'package:camera/camera.dart' ;
11
+ import 'package:flutter/foundation.dart' ;
11
12
import 'package:flutter/material.dart' ;
12
13
import 'package:video_player/video_player.dart' ;
13
14
@@ -68,7 +69,7 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
68
69
@override
69
70
void initState () {
70
71
super .initState ();
71
- WidgetsBinding .instance? .addObserver (this );
72
+ _ambiguate ( WidgetsBinding .instance) ? .addObserver (this );
72
73
73
74
_flashModeControlRowAnimationController = AnimationController (
74
75
duration: const Duration (milliseconds: 300 ),
@@ -98,7 +99,7 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
98
99
99
100
@override
100
101
void dispose () {
101
- WidgetsBinding .instance? .removeObserver (this );
102
+ _ambiguate ( WidgetsBinding .instance) ? .removeObserver (this );
102
103
_flashModeControlRowAnimationController.dispose ();
103
104
_exposureModeControlRowAnimationController.dispose ();
104
105
super .dispose ();
@@ -231,7 +232,14 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
231
232
? Container ()
232
233
: SizedBox (
233
234
child: (localVideoController == null )
234
- ? Image .file (File (imageFile! .path))
235
+ ? (
236
+ // The captured image on the web contains a network-accessible URL
237
+ // pointing to a location within the browser. It may be displayed
238
+ // either with Image.network or Image.memory after loading the image
239
+ // bytes to memory.
240
+ kIsWeb
241
+ ? Image .network (imageFile! .path)
242
+ : Image .file (File (imageFile! .path)))
235
243
: Container (
236
244
child: Center (
237
245
child: AspectRatio (
@@ -267,17 +275,24 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
267
275
color: Colors .blue,
268
276
onPressed: controller != null ? onFlashModeButtonPressed : null ,
269
277
),
270
- IconButton (
271
- icon: Icon (Icons .exposure),
272
- color: Colors .blue,
273
- onPressed:
274
- controller != null ? onExposureModeButtonPressed : null ,
275
- ),
276
- IconButton (
277
- icon: Icon (Icons .filter_center_focus),
278
- color: Colors .blue,
279
- onPressed: controller != null ? onFocusModeButtonPressed : null ,
280
- ),
278
+ // The exposure and focus mode are currently not supported on the web.
279
+ ...(! kIsWeb
280
+ ? [
281
+ IconButton (
282
+ icon: Icon (Icons .exposure),
283
+ color: Colors .blue,
284
+ onPressed: controller != null
285
+ ? onExposureModeButtonPressed
286
+ : null ,
287
+ ),
288
+ IconButton (
289
+ icon: Icon (Icons .filter_center_focus),
290
+ color: Colors .blue,
291
+ onPressed:
292
+ controller != null ? onFocusModeButtonPressed : null ,
293
+ )
294
+ ]
295
+ : []),
281
296
IconButton (
282
297
icon: Icon (enableAudio ? Icons .volume_up : Icons .volume_mute),
283
298
color: Colors .blue,
@@ -399,6 +414,13 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
399
414
onSetExposureModeButtonPressed (ExposureMode .locked)
400
415
: null ,
401
416
),
417
+ TextButton (
418
+ child: Text ('RESET OFFSET' ),
419
+ style: styleLocked,
420
+ onPressed: controller != null
421
+ ? () => controller! .setExposureOffset (0.0 )
422
+ : null ,
423
+ ),
402
424
],
403
425
),
404
426
Center (
@@ -530,7 +552,16 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
530
552
cameraController.value.isRecordingVideo
531
553
? onStopButtonPressed
532
554
: null ,
533
- )
555
+ ),
556
+ IconButton (
557
+ icon: const Icon (Icons .pause_presentation),
558
+ color:
559
+ cameraController != null && cameraController.value.isPreviewPaused
560
+ ? Colors .red
561
+ : Colors .blue,
562
+ onPressed:
563
+ cameraController == null ? null : onPausePreviewButtonPressed,
564
+ ),
534
565
],
535
566
);
536
567
}
@@ -597,12 +628,14 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
597
628
if (controller != null ) {
598
629
await controller! .dispose ();
599
630
}
631
+
600
632
final CameraController cameraController = CameraController (
601
633
cameraDescription,
602
- ResolutionPreset .medium,
634
+ kIsWeb ? ResolutionPreset .max : ResolutionPreset .medium,
603
635
enableAudio: enableAudio,
604
636
imageFormatGroup: ImageFormatGroup .jpeg,
605
637
);
638
+
606
639
controller = cameraController;
607
640
608
641
// If the controller is updated then update the UI.
@@ -617,12 +650,17 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
617
650
try {
618
651
await cameraController.initialize ();
619
652
await Future .wait ([
620
- cameraController
621
- .getMinExposureOffset ()
622
- .then ((value) => _minAvailableExposureOffset = value),
623
- cameraController
624
- .getMaxExposureOffset ()
625
- .then ((value) => _maxAvailableExposureOffset = value),
653
+ // The exposure mode is currently not supported on the web.
654
+ ...(! kIsWeb
655
+ ? [
656
+ cameraController
657
+ .getMinExposureOffset ()
658
+ .then ((value) => _minAvailableExposureOffset = value),
659
+ cameraController
660
+ .getMaxExposureOffset ()
661
+ .then ((value) => _maxAvailableExposureOffset = value)
662
+ ]
663
+ : []),
626
664
cameraController
627
665
.getMaxZoomLevel ()
628
666
.then ((value) => _maxAvailableZoom = value),
@@ -690,16 +728,20 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
690
728
}
691
729
692
730
void onCaptureOrientationLockButtonPressed () async {
693
- if (controller != null ) {
694
- final CameraController cameraController = controller! ;
695
- if (cameraController.value.isCaptureOrientationLocked) {
696
- await cameraController.unlockCaptureOrientation ();
697
- showInSnackBar ('Capture orientation unlocked' );
698
- } else {
699
- await cameraController.lockCaptureOrientation ();
700
- showInSnackBar (
701
- 'Capture orientation locked to ${cameraController .value .lockedCaptureOrientation .toString ().split ('.' ).last }' );
731
+ try {
732
+ if (controller != null ) {
733
+ final CameraController cameraController = controller! ;
734
+ if (cameraController.value.isCaptureOrientationLocked) {
735
+ await cameraController.unlockCaptureOrientation ();
736
+ showInSnackBar ('Capture orientation unlocked' );
737
+ } else {
738
+ await cameraController.lockCaptureOrientation ();
739
+ showInSnackBar (
740
+ 'Capture orientation locked to ${cameraController .value .lockedCaptureOrientation .toString ().split ('.' ).last }' );
741
+ }
702
742
}
743
+ } on CameraException catch (e) {
744
+ _showCameraException (e);
703
745
}
704
746
}
705
747
@@ -741,6 +783,23 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
741
783
});
742
784
}
743
785
786
+ Future <void > onPausePreviewButtonPressed () async {
787
+ final CameraController ? cameraController = controller;
788
+
789
+ if (cameraController == null || ! cameraController.value.isInitialized) {
790
+ showInSnackBar ('Error: select a camera first.' );
791
+ return ;
792
+ }
793
+
794
+ if (cameraController.value.isPreviewPaused) {
795
+ await cameraController.resumePreview ();
796
+ } else {
797
+ await cameraController.pausePreview ();
798
+ }
799
+
800
+ if (mounted) setState (() {});
801
+ }
802
+
744
803
void onPauseButtonPressed () {
745
804
pauseVideoRecording ().then ((_) {
746
805
if (mounted) setState (() {});
@@ -881,8 +940,10 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
881
940
return ;
882
941
}
883
942
884
- final VideoPlayerController vController =
885
- VideoPlayerController .file (File (videoFile! .path));
943
+ final VideoPlayerController vController = kIsWeb
944
+ ? VideoPlayerController .network (videoFile! .path)
945
+ : VideoPlayerController .file (File (videoFile! .path));
946
+
886
947
videoPlayerListener = () {
887
948
if (videoController != null && videoController! .value.size != null ) {
888
949
// Refreshing the state to update video player with the correct ratio.
@@ -951,3 +1012,10 @@ Future<void> main() async {
951
1012
}
952
1013
runApp (CameraApp ());
953
1014
}
1015
+
1016
+ /// This allows a value of type T or T? to be treated as a value of type T?.
1017
+ ///
1018
+ /// We use this so that APIs that have become non-nullable can still be used
1019
+ /// with `!` and `?` on the stable branch.
1020
+ // TODO(ianh): Remove this once we roll stable in late 2021.
1021
+ T ? _ambiguate <T >(T ? value) => value;
0 commit comments