|
|
|
@@ -14,7 +14,7 @@ import 'package:video_player/video_player.dart';
|
|
|
|
|
/// Camera example home widget.
|
|
|
|
|
class CameraExampleHome extends StatefulWidget {
|
|
|
|
|
/// Default Constructor
|
|
|
|
|
const CameraExampleHome({Key? key}) : super(key: key);
|
|
|
|
|
const CameraExampleHome({super.key});
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
State<CameraExampleHome> createState() {
|
|
|
|
@@ -31,17 +31,16 @@ IconData getCameraLensIcon(CameraLensDirection direction) {
|
|
|
|
|
return Icons.camera_front;
|
|
|
|
|
case CameraLensDirection.external:
|
|
|
|
|
return Icons.camera;
|
|
|
|
|
default:
|
|
|
|
|
throw ArgumentError('Unknown lens direction');
|
|
|
|
|
}
|
|
|
|
|
// This enum is from a different package, so a new value could be added at
|
|
|
|
|
// any time. The example should keep working if that happens.
|
|
|
|
|
// ignore: dead_code
|
|
|
|
|
return Icons.camera;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _logError(String code, String? message) {
|
|
|
|
|
if (message != null) {
|
|
|
|
|
print('Error: $code\nError Message: $message');
|
|
|
|
|
} else {
|
|
|
|
|
print('Error: $code');
|
|
|
|
|
}
|
|
|
|
|
// ignore: avoid_print
|
|
|
|
|
print('Error: $code${message == null ? '' : '\nError Message: $message'}');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _CameraExampleHomeState extends State<CameraExampleHome>
|
|
|
|
@@ -72,7 +71,7 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
|
|
|
|
|
@override
|
|
|
|
|
void initState() {
|
|
|
|
|
super.initState();
|
|
|
|
|
_ambiguate(WidgetsBinding.instance)?.addObserver(this);
|
|
|
|
|
WidgetsBinding.instance.addObserver(this);
|
|
|
|
|
|
|
|
|
|
_flashModeControlRowAnimationController = AnimationController(
|
|
|
|
|
duration: const Duration(milliseconds: 300),
|
|
|
|
@@ -102,7 +101,7 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void dispose() {
|
|
|
|
|
_ambiguate(WidgetsBinding.instance)?.removeObserver(this);
|
|
|
|
|
WidgetsBinding.instance.removeObserver(this);
|
|
|
|
|
_flashModeControlRowAnimationController.dispose();
|
|
|
|
|
_exposureModeControlRowAnimationController.dispose();
|
|
|
|
|
super.dispose();
|
|
|
|
@@ -121,7 +120,7 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
|
|
|
|
|
if (state == AppLifecycleState.inactive) {
|
|
|
|
|
cameraController.dispose();
|
|
|
|
|
} else if (state == AppLifecycleState.resumed) {
|
|
|
|
|
onNewCameraSelected(cameraController.description);
|
|
|
|
|
_initializeCameraController(cameraController.description);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// #enddocregion AppLifecycle
|
|
|
|
@@ -251,9 +250,7 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
|
|
|
|
|
child: Center(
|
|
|
|
|
child: AspectRatio(
|
|
|
|
|
aspectRatio:
|
|
|
|
|
localVideoController.value.size != null
|
|
|
|
|
? localVideoController.value.aspectRatio
|
|
|
|
|
: 1.0,
|
|
|
|
|
localVideoController.value.aspectRatio,
|
|
|
|
|
child: VideoPlayer(localVideoController)),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
@@ -368,16 +365,12 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
|
|
|
|
|
|
|
|
|
|
Widget _exposureModeControlRowWidget() {
|
|
|
|
|
final ButtonStyle styleAuto = TextButton.styleFrom(
|
|
|
|
|
// TODO(darrenaustin): Migrate to new API once it lands in stable: https://github.com/flutter/flutter/issues/105724
|
|
|
|
|
// ignore: deprecated_member_use
|
|
|
|
|
primary: controller?.value.exposureMode == ExposureMode.auto
|
|
|
|
|
foregroundColor: controller?.value.exposureMode == ExposureMode.auto
|
|
|
|
|
? Colors.orange
|
|
|
|
|
: Colors.blue,
|
|
|
|
|
);
|
|
|
|
|
final ButtonStyle styleLocked = TextButton.styleFrom(
|
|
|
|
|
// TODO(darrenaustin): Migrate to new API once it lands in stable: https://github.com/flutter/flutter/issues/105724
|
|
|
|
|
// ignore: deprecated_member_use
|
|
|
|
|
primary: controller?.value.exposureMode == ExposureMode.locked
|
|
|
|
|
foregroundColor: controller?.value.exposureMode == ExposureMode.locked
|
|
|
|
|
? Colors.orange
|
|
|
|
|
: Colors.blue,
|
|
|
|
|
);
|
|
|
|
@@ -455,16 +448,12 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
|
|
|
|
|
|
|
|
|
|
Widget _focusModeControlRowWidget() {
|
|
|
|
|
final ButtonStyle styleAuto = TextButton.styleFrom(
|
|
|
|
|
// TODO(darrenaustin): Migrate to new API once it lands in stable: https://github.com/flutter/flutter/issues/105724
|
|
|
|
|
// ignore: deprecated_member_use
|
|
|
|
|
primary: controller?.value.focusMode == FocusMode.auto
|
|
|
|
|
foregroundColor: controller?.value.focusMode == FocusMode.auto
|
|
|
|
|
? Colors.orange
|
|
|
|
|
: Colors.blue,
|
|
|
|
|
);
|
|
|
|
|
final ButtonStyle styleLocked = TextButton.styleFrom(
|
|
|
|
|
// TODO(darrenaustin): Migrate to new API once it lands in stable: https://github.com/flutter/flutter/issues/105724
|
|
|
|
|
// ignore: deprecated_member_use
|
|
|
|
|
primary: controller?.value.focusMode == FocusMode.locked
|
|
|
|
|
foregroundColor: controller?.value.focusMode == FocusMode.locked
|
|
|
|
|
? Colors.orange
|
|
|
|
|
: Colors.blue,
|
|
|
|
|
);
|
|
|
|
@@ -585,7 +574,7 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_cameras.isEmpty) {
|
|
|
|
|
_ambiguate(SchedulerBinding.instance)?.addPostFrameCallback((_) async {
|
|
|
|
|
SchedulerBinding.instance.addPostFrameCallback((_) async {
|
|
|
|
|
showInSnackBar('No camera found.');
|
|
|
|
|
});
|
|
|
|
|
return const Text('None');
|
|
|
|
@@ -598,10 +587,7 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
|
|
|
|
|
title: Icon(getCameraLensIcon(cameraDescription.lensDirection)),
|
|
|
|
|
groupValue: controller?.description,
|
|
|
|
|
value: cameraDescription,
|
|
|
|
|
onChanged:
|
|
|
|
|
controller != null && controller!.value.isRecordingVideo
|
|
|
|
|
? null
|
|
|
|
|
: onChanged,
|
|
|
|
|
onChanged: onChanged,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
@@ -634,17 +620,15 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> onNewCameraSelected(CameraDescription cameraDescription) async {
|
|
|
|
|
final CameraController? oldController = controller;
|
|
|
|
|
if (oldController != null) {
|
|
|
|
|
// `controller` needs to be set to null before getting disposed,
|
|
|
|
|
// to avoid a race condition when we use the controller that is being
|
|
|
|
|
// disposed. This happens when camera permission dialog shows up,
|
|
|
|
|
// which triggers `didChangeAppLifecycleState`, which disposes and
|
|
|
|
|
// re-creates the controller.
|
|
|
|
|
controller = null;
|
|
|
|
|
await oldController.dispose();
|
|
|
|
|
if (controller != null) {
|
|
|
|
|
return controller!.setDescription(cameraDescription);
|
|
|
|
|
} else {
|
|
|
|
|
return _initializeCameraController(cameraDescription);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> _initializeCameraController(
|
|
|
|
|
CameraDescription cameraDescription) async {
|
|
|
|
|
final CameraController cameraController = CameraController(
|
|
|
|
|
cameraDescription,
|
|
|
|
|
kIsWeb ? ResolutionPreset.max : ResolutionPreset.medium,
|
|
|
|
@@ -1002,11 +986,15 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final VideoPlayerController vController = kIsWeb
|
|
|
|
|
// TODO(gabrielokura): remove the ignore once the following line can migrate to
|
|
|
|
|
// use VideoPlayerController.networkUrl after the issue is resolved.
|
|
|
|
|
// https://github.com/flutter/flutter/issues/121927
|
|
|
|
|
// ignore: deprecated_member_use
|
|
|
|
|
? VideoPlayerController.network(videoFile!.path)
|
|
|
|
|
: VideoPlayerController.file(File(videoFile!.path));
|
|
|
|
|
|
|
|
|
|
videoPlayerListener = () {
|
|
|
|
|
if (videoController != null && videoController!.value.size != null) {
|
|
|
|
|
if (videoController != null) {
|
|
|
|
|
// Refreshing the state to update video player with the correct ratio.
|
|
|
|
|
if (mounted) {
|
|
|
|
|
setState(() {});
|
|
|
|
@@ -1057,7 +1045,7 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
|
|
|
|
|
/// CameraApp is the Main Application.
|
|
|
|
|
class CameraApp extends StatelessWidget {
|
|
|
|
|
/// Default Constructor
|
|
|
|
|
const CameraApp({Key? key}) : super(key: key);
|
|
|
|
|
const CameraApp({super.key});
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
@@ -1079,10 +1067,3 @@ Future<void> main() async {
|
|
|
|
|
}
|
|
|
|
|
runApp(const CameraApp());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// This allows a value of type T or T? to be treated as a value of type T?.
|
|
|
|
|
///
|
|
|
|
|
/// We use this so that APIs that have become non-nullable can still be used
|
|
|
|
|
/// with `!` and `?` on the stable branch.
|
|
|
|
|
// TODO(ianh): Remove this once we roll stable in late 2021.
|
|
|
|
|
T? _ambiguate<T>(T? value) => value;
|
|
|
|
|