From e837b63097a3560ad0234dcf1e43332e94341b6d Mon Sep 17 00:00:00 2001 From: mabroukb Date: Wed, 6 Oct 2021 11:08:07 +0200 Subject: [PATCH 1/4] made "Example" depends on local library code --- example/pubspec.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 35fdc8a..240a888 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -23,7 +23,8 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2 - camera_camera: ^2.0.2 + camera_camera: + path: .. dev_dependencies: flutter_test: From 507d8f1ce63c0f65b007b833f2cc20d8b80dd47b Mon Sep 17 00:00:00 2001 From: mabroukb Date: Wed, 6 Oct 2021 11:09:37 +0200 Subject: [PATCH 2/4] added aspect Ratio do preview widget so image is not distorted --- .../presentation/controller/camera_camera_controller.dart | 4 ++++ lib/src/presentation/widgets/camera_preview.dart | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/src/presentation/controller/camera_camera_controller.dart b/lib/src/presentation/controller/camera_camera_controller.dart index 4456597..b9390fe 100644 --- a/lib/src/presentation/controller/camera_camera_controller.dart +++ b/lib/src/presentation/controller/camera_camera_controller.dart @@ -153,4 +153,8 @@ class CameraCameraController { await _controller.dispose(); return; } + + double aspectRatio() { + return _controller.value.aspectRatio; + } } diff --git a/lib/src/presentation/widgets/camera_preview.dart b/lib/src/presentation/widgets/camera_preview.dart index 23e7a80..185cb36 100644 --- a/lib/src/presentation/widgets/camera_preview.dart +++ b/lib/src/presentation/widgets/camera_preview.dart @@ -41,7 +41,10 @@ class _CameraCameraPreviewState extends State { }, child: Stack( children: [ - Center(child: widget.controller.buildPreview()), + AspectRatio( + aspectRatio: 1 / widget.controller.aspectRatio(), + child: Center(child: widget.controller.buildPreview()) + ), if (widget.enableZoom) Positioned( bottom: 96, @@ -49,7 +52,7 @@ class _CameraCameraPreviewState extends State { right: 0.0, child: CircleAvatar( radius: 20, - backgroundColor: Colors.black.withOpacity(0.6), + backgroundColor: Colors.grey.withOpacity(0.6), child: IconButton( icon: Center( child: Text( From f81f4d050bc1d4c64a0369e0d672e0edc32ba360 Mon Sep 17 00:00:00 2001 From: mabroukb Date: Thu, 21 Oct 2021 17:21:25 +0200 Subject: [PATCH 3/4] moved buttons out of preview widget full screen preview maintained aspect ratio in full screen update dependencies --- example/lib/main.dart | 4 +- example/pubspec.yaml | 2 +- lib/src/core/camera_bloc.dart | 2 +- lib/src/presentation/camera_page.dart | 26 +-- .../controller/camera_camera_controller.dart | 19 +-- .../presentation/widgets/camera_preview.dart | 161 ++++++++++++------ pubspec.yaml | 6 +- 7 files changed, 128 insertions(+), 92 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index eda27a8..f593901 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -36,6 +36,7 @@ class _MyHomePageState extends State { context, MaterialPageRoute( builder: (_) => CameraCamera( + resolutionPreset: ResolutionPreset.ultraHigh, onFile: (file) { photos.add(file); Navigator.pop(context); @@ -53,8 +54,7 @@ class _MyHomePageState extends State { title: Text(widget.title), ), body: GridView.builder( - gridDelegate: - SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), itemCount: photos.length, itemBuilder: (_, index) => Padding( padding: const EdgeInsets.all(8.0), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 240a888..1cf4109 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 + cupertino_icons: ^1.0.3 camera_camera: path: .. diff --git a/lib/src/core/camera_bloc.dart b/lib/src/core/camera_bloc.dart index fa605e0..1809539 100644 --- a/lib/src/core/camera_bloc.dart +++ b/lib/src/core/camera_bloc.dart @@ -26,7 +26,7 @@ class CameraBloc { final statusStream = BehaviorSubject.seeded(CameraStatusEmpty()); CameraStatus get status => - statusStream.valueWrapper?.value ?? CameraStatusEmpty(); + statusStream.valueOrNull ?? CameraStatusEmpty(); set status(CameraStatus status) => statusStream.sink.add(status); void init() async { diff --git a/lib/src/presentation/camera_page.dart b/lib/src/presentation/camera_page.dart index 5f9e99b..97a95d8 100644 --- a/lib/src/presentation/camera_page.dart +++ b/lib/src/presentation/camera_page.dart @@ -89,29 +89,11 @@ class _CameraCameraState extends State { enableZoom: widget.enableZoom, key: UniqueKey(), controller: controller, + onCameraChange: () { + bloc.changeCamera(); + }, + enableFlipCamera: (bloc.status.preview.cameras.length > 1), ), - if (bloc.status.preview.cameras.length > 1) - Align( - alignment: Alignment.bottomRight, - child: Padding( - padding: const EdgeInsets.all(32.0), - child: InkWell( - onTap: () { - bloc.changeCamera(); - }, - child: CircleAvatar( - radius: 20, - backgroundColor: Colors.black.withOpacity(0.6), - child: Icon( - Platform.isAndroid - ? Icons.flip_camera_android - : Icons.flip_camera_ios, - color: Colors.white, - ), - ), - ), - ), - ) ], ), failure: (message, _) => Container( diff --git a/lib/src/presentation/controller/camera_camera_controller.dart b/lib/src/presentation/controller/camera_camera_controller.dart index b9390fe..20faa03 100644 --- a/lib/src/presentation/controller/camera_camera_controller.dart +++ b/lib/src/presentation/controller/camera_camera_controller.dart @@ -24,8 +24,7 @@ class CameraCameraController { required this.onPath, this.enableAudio = false, }) { - _controller = CameraController(cameraDescription, resolutionPreset, - enableAudio: enableAudio); + _controller = CameraController(cameraDescription, resolutionPreset, enableAudio: enableAudio); } void init() async { @@ -40,14 +39,7 @@ class CameraCameraController { await _controller.setFlashMode(FlashMode.off); } catch (e) {} - status = CameraCameraSuccess( - camera: Camera( - maxZoom: maxZoom, - minZoom: minZoom, - zoom: minZoom, - maxExposure: maxExposure, - minExposure: minExposure, - flashMode: FlashMode.off)); + status = CameraCameraSuccess(camera: Camera(maxZoom: maxZoom, minZoom: minZoom, zoom: minZoom, maxExposure: maxExposure, minExposure: minExposure, flashMode: FlashMode.off)); } on CameraException catch (e) { status = CameraCameraFailure(message: e.description ?? "", exception: e); } @@ -98,8 +90,7 @@ class CameraCameraController { void setZoomLevel(double zoom) async { if (zoom != 1) { var cameraZoom = double.parse(((zoom)).toStringAsFixed(1)); - if (cameraZoom >= status.camera.minZoom && - cameraZoom <= status.camera.maxZoom) { + if (cameraZoom >= status.camera.minZoom && cameraZoom <= status.camera.maxZoom) { final camera = status.camera.copyWith(zoom: cameraZoom); status = CameraCameraSuccess(camera: camera); await _controller.setZoomLevel(cameraZoom); @@ -157,4 +148,8 @@ class CameraCameraController { double aspectRatio() { return _controller.value.aspectRatio; } + + Size? size() { + return _controller.value.previewSize; + } } diff --git a/lib/src/presentation/widgets/camera_preview.dart b/lib/src/presentation/widgets/camera_preview.dart index 185cb36..b8a445f 100644 --- a/lib/src/presentation/widgets/camera_preview.dart +++ b/lib/src/presentation/widgets/camera_preview.dart @@ -1,3 +1,6 @@ +import 'dart:io'; + +import 'package:camera_camera/src/core/OrientationPreferences.dart'; import 'package:camera_camera/src/presentation/controller/camera_camera_controller.dart'; import 'package:camera_camera/src/presentation/controller/camera_camera_status.dart'; import 'package:flutter/material.dart'; @@ -6,11 +9,15 @@ class CameraCameraPreview extends StatefulWidget { final void Function(String value)? onFile; final CameraCameraController controller; final bool enableZoom; + final bool enableFlipCamera; + final GestureTapCallback? onCameraChange; CameraCameraPreview({ Key? key, this.onFile, required this.controller, required this.enableZoom, + required this.enableFlipCamera, + required this.onCameraChange, }) : super(key: key); @override @@ -20,6 +27,7 @@ class CameraCameraPreview extends StatefulWidget { class _CameraCameraPreviewState extends State { @override void initState() { + OrientationPreferences.portraitModeOnly(); widget.controller.init(); super.initState(); } @@ -28,6 +36,7 @@ class _CameraCameraPreviewState extends State { void dispose() { widget.controller.dispose(); super.dispose(); + OrientationPreferences.enableRotation(); } @override @@ -35,76 +44,126 @@ class _CameraCameraPreviewState extends State { return ValueListenableBuilder( valueListenable: widget.controller.statusNotifier, builder: (_, status, __) => status.when( - success: (camera) => GestureDetector( - onScaleUpdate: (details) { - widget.controller.setZoomLevel(details.scale); - }, - child: Stack( - children: [ - AspectRatio( - aspectRatio: 1 / widget.controller.aspectRatio(), - child: Center(child: widget.controller.buildPreview()) + success: (camera) { + Size? size = widget.controller.size(); + return GestureDetector( + onScaleUpdate: (details) { + widget.controller.setZoomLevel(details.scale); + }, + child: Stack( + children: [ + new OverflowBox( + maxWidth: double.infinity, + maxHeight: double.infinity, + alignment: Alignment.center, + child: new FittedBox( + fit: BoxFit.cover, + alignment: Alignment.center, + clipBehavior: Clip.hardEdge, + child: new Container( + width: size?.shortestSide, + height: size?.longestSide, + //child: AspectRatio( + //aspectRatio: widget.controller.aspectRatio(), + child: widget.controller.buildPreview(), + //), + ), + ), + ), + Positioned( + bottom: 0, + //left: 0.0, + //right: 0.0, + child: Container( + height: 96 + 2 * 20 + 32, + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + color: Colors.grey.withOpacity(0.4), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), + ), + ), + ), + if (widget.enableZoom) + Positioned( + bottom: 96, + left: 0.0, + right: 0.0, + child: CircleAvatar( + radius: 20, + backgroundColor: Colors.grey.withOpacity(0.6), + child: IconButton( + icon: Center( + child: Text( + "${camera.zoom.toStringAsFixed(1)}x", + style: TextStyle(color: Colors.white, fontSize: 12), + ), + ), + onPressed: () { + widget.controller.zoomChange(); + }, + ), + ), ), - if (widget.enableZoom) - Positioned( - bottom: 96, - left: 0.0, - right: 0.0, + if (widget.controller.flashModes.length > 1) + Align( + alignment: Alignment.bottomLeft, + child: Padding( + padding: const EdgeInsets.all(32.0), child: CircleAvatar( radius: 20, - backgroundColor: Colors.grey.withOpacity(0.6), + backgroundColor: Colors.black.withOpacity(0.6), child: IconButton( - icon: Center( - child: Text( - "${camera.zoom.toStringAsFixed(1)}x", - style: TextStyle( - color: Colors.white, fontSize: 12), - ), - ), onPressed: () { - widget.controller.zoomChange(); + widget.controller.changeFlashMode(); }, + icon: Icon( + camera.flashModeIcon, + color: Colors.white, + ), ), ), ), - if (widget.controller.flashModes.length > 1) - Align( - alignment: Alignment.bottomLeft, - child: Padding( - padding: const EdgeInsets.all(32.0), - child: CircleAvatar( - radius: 20, - backgroundColor: Colors.black.withOpacity(0.6), - child: IconButton( - onPressed: () { - widget.controller.changeFlashMode(); - }, - icon: Icon( - camera.flashModeIcon, - color: Colors.white, - ), - ), - ), + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.only(bottom: 24), + child: InkWell( + onTap: widget.controller.takePhoto, + child: CircleAvatar( + radius: 30, + backgroundColor: Colors.white, ), ), + ), + ), + if (widget.enableFlipCamera) Align( - alignment: Alignment.bottomCenter, + alignment: Alignment.bottomRight, child: Padding( - padding: const EdgeInsets.only(bottom: 24), + padding: const EdgeInsets.all(32.0), child: InkWell( - onTap: () { - widget.controller.takePhoto(); - }, + onTap: widget.onCameraChange, child: CircleAvatar( - radius: 30, - backgroundColor: Colors.white, + radius: 20, + backgroundColor: Colors.black.withOpacity(0.6), + child: Icon( + Platform.isAndroid // + ? Icons.flip_camera_android + : Icons.flip_camera_ios, + color: Colors.white, + ), ), ), ), - ), - ], - ), + ) + ], ), + ); + }, failure: (message, _) => Container( color: Colors.black, child: Text(message), diff --git a/pubspec.yaml b/pubspec.yaml index 5149792..adce259 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,16 +8,16 @@ environment: sdk: ">=2.12.0-0.0 <3.0.0" dependencies: - camera: ^0.8.0-nullsafety.2 + camera: ^0.9.4+3 font_awesome_flutter: ^9.0.0-nullsafety - rxdart: ^0.26.0 + rxdart: ^0.27.2 flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter - mocktail: ^0.0.1-dev.11 + mocktail: ^0.2.0 # For information on the generic Dart part of this file, see the # following page: https://www.dartlang.org/tools/pub/pubspec From 4dff8dc0fbe3abf565596f4d25ac7a398fd7e966 Mon Sep 17 00:00:00 2001 From: mabroukb Date: Thu, 21 Oct 2021 17:21:25 +0200 Subject: [PATCH 4/4] moved buttons out of preview widget full screen preview maintained aspect ratio in full screen added Orientations locking methods update dependencies --- example/lib/main.dart | 4 +- example/pubspec.yaml | 2 +- lib/src/core/OrientationPreferences.dart | 28 +++ lib/src/core/camera_bloc.dart | 2 +- lib/src/presentation/camera_page.dart | 26 +-- .../controller/camera_camera_controller.dart | 19 +-- .../presentation/widgets/camera_preview.dart | 161 ++++++++++++------ pubspec.yaml | 6 +- 8 files changed, 156 insertions(+), 92 deletions(-) create mode 100644 lib/src/core/OrientationPreferences.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index eda27a8..f593901 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -36,6 +36,7 @@ class _MyHomePageState extends State { context, MaterialPageRoute( builder: (_) => CameraCamera( + resolutionPreset: ResolutionPreset.ultraHigh, onFile: (file) { photos.add(file); Navigator.pop(context); @@ -53,8 +54,7 @@ class _MyHomePageState extends State { title: Text(widget.title), ), body: GridView.builder( - gridDelegate: - SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), itemCount: photos.length, itemBuilder: (_, index) => Padding( padding: const EdgeInsets.all(8.0), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 240a888..1cf4109 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 + cupertino_icons: ^1.0.3 camera_camera: path: .. diff --git a/lib/src/core/OrientationPreferences.dart b/lib/src/core/OrientationPreferences.dart new file mode 100644 index 0000000..1938183 --- /dev/null +++ b/lib/src/core/OrientationPreferences.dart @@ -0,0 +1,28 @@ +import 'package:flutter/services.dart'; + +class OrientationPreferences { + /// blocks rotation; sets orientation to: portrait + static portraitModeOnly() { + SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown, + ]); + } + + /// blocks rotation; sets orientation to: portrait + static landscapeModeOnly() { + SystemChrome.setPreferredOrientations([ + DeviceOrientation.landscapeLeft, + DeviceOrientation.landscapeRight, + ]); + } + + static enableRotation() { + SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown, + DeviceOrientation.landscapeLeft, + DeviceOrientation.landscapeRight, + ]); + } +} diff --git a/lib/src/core/camera_bloc.dart b/lib/src/core/camera_bloc.dart index fa605e0..1809539 100644 --- a/lib/src/core/camera_bloc.dart +++ b/lib/src/core/camera_bloc.dart @@ -26,7 +26,7 @@ class CameraBloc { final statusStream = BehaviorSubject.seeded(CameraStatusEmpty()); CameraStatus get status => - statusStream.valueWrapper?.value ?? CameraStatusEmpty(); + statusStream.valueOrNull ?? CameraStatusEmpty(); set status(CameraStatus status) => statusStream.sink.add(status); void init() async { diff --git a/lib/src/presentation/camera_page.dart b/lib/src/presentation/camera_page.dart index 5f9e99b..97a95d8 100644 --- a/lib/src/presentation/camera_page.dart +++ b/lib/src/presentation/camera_page.dart @@ -89,29 +89,11 @@ class _CameraCameraState extends State { enableZoom: widget.enableZoom, key: UniqueKey(), controller: controller, + onCameraChange: () { + bloc.changeCamera(); + }, + enableFlipCamera: (bloc.status.preview.cameras.length > 1), ), - if (bloc.status.preview.cameras.length > 1) - Align( - alignment: Alignment.bottomRight, - child: Padding( - padding: const EdgeInsets.all(32.0), - child: InkWell( - onTap: () { - bloc.changeCamera(); - }, - child: CircleAvatar( - radius: 20, - backgroundColor: Colors.black.withOpacity(0.6), - child: Icon( - Platform.isAndroid - ? Icons.flip_camera_android - : Icons.flip_camera_ios, - color: Colors.white, - ), - ), - ), - ), - ) ], ), failure: (message, _) => Container( diff --git a/lib/src/presentation/controller/camera_camera_controller.dart b/lib/src/presentation/controller/camera_camera_controller.dart index b9390fe..20faa03 100644 --- a/lib/src/presentation/controller/camera_camera_controller.dart +++ b/lib/src/presentation/controller/camera_camera_controller.dart @@ -24,8 +24,7 @@ class CameraCameraController { required this.onPath, this.enableAudio = false, }) { - _controller = CameraController(cameraDescription, resolutionPreset, - enableAudio: enableAudio); + _controller = CameraController(cameraDescription, resolutionPreset, enableAudio: enableAudio); } void init() async { @@ -40,14 +39,7 @@ class CameraCameraController { await _controller.setFlashMode(FlashMode.off); } catch (e) {} - status = CameraCameraSuccess( - camera: Camera( - maxZoom: maxZoom, - minZoom: minZoom, - zoom: minZoom, - maxExposure: maxExposure, - minExposure: minExposure, - flashMode: FlashMode.off)); + status = CameraCameraSuccess(camera: Camera(maxZoom: maxZoom, minZoom: minZoom, zoom: minZoom, maxExposure: maxExposure, minExposure: minExposure, flashMode: FlashMode.off)); } on CameraException catch (e) { status = CameraCameraFailure(message: e.description ?? "", exception: e); } @@ -98,8 +90,7 @@ class CameraCameraController { void setZoomLevel(double zoom) async { if (zoom != 1) { var cameraZoom = double.parse(((zoom)).toStringAsFixed(1)); - if (cameraZoom >= status.camera.minZoom && - cameraZoom <= status.camera.maxZoom) { + if (cameraZoom >= status.camera.minZoom && cameraZoom <= status.camera.maxZoom) { final camera = status.camera.copyWith(zoom: cameraZoom); status = CameraCameraSuccess(camera: camera); await _controller.setZoomLevel(cameraZoom); @@ -157,4 +148,8 @@ class CameraCameraController { double aspectRatio() { return _controller.value.aspectRatio; } + + Size? size() { + return _controller.value.previewSize; + } } diff --git a/lib/src/presentation/widgets/camera_preview.dart b/lib/src/presentation/widgets/camera_preview.dart index 185cb36..b8a445f 100644 --- a/lib/src/presentation/widgets/camera_preview.dart +++ b/lib/src/presentation/widgets/camera_preview.dart @@ -1,3 +1,6 @@ +import 'dart:io'; + +import 'package:camera_camera/src/core/OrientationPreferences.dart'; import 'package:camera_camera/src/presentation/controller/camera_camera_controller.dart'; import 'package:camera_camera/src/presentation/controller/camera_camera_status.dart'; import 'package:flutter/material.dart'; @@ -6,11 +9,15 @@ class CameraCameraPreview extends StatefulWidget { final void Function(String value)? onFile; final CameraCameraController controller; final bool enableZoom; + final bool enableFlipCamera; + final GestureTapCallback? onCameraChange; CameraCameraPreview({ Key? key, this.onFile, required this.controller, required this.enableZoom, + required this.enableFlipCamera, + required this.onCameraChange, }) : super(key: key); @override @@ -20,6 +27,7 @@ class CameraCameraPreview extends StatefulWidget { class _CameraCameraPreviewState extends State { @override void initState() { + OrientationPreferences.portraitModeOnly(); widget.controller.init(); super.initState(); } @@ -28,6 +36,7 @@ class _CameraCameraPreviewState extends State { void dispose() { widget.controller.dispose(); super.dispose(); + OrientationPreferences.enableRotation(); } @override @@ -35,76 +44,126 @@ class _CameraCameraPreviewState extends State { return ValueListenableBuilder( valueListenable: widget.controller.statusNotifier, builder: (_, status, __) => status.when( - success: (camera) => GestureDetector( - onScaleUpdate: (details) { - widget.controller.setZoomLevel(details.scale); - }, - child: Stack( - children: [ - AspectRatio( - aspectRatio: 1 / widget.controller.aspectRatio(), - child: Center(child: widget.controller.buildPreview()) + success: (camera) { + Size? size = widget.controller.size(); + return GestureDetector( + onScaleUpdate: (details) { + widget.controller.setZoomLevel(details.scale); + }, + child: Stack( + children: [ + new OverflowBox( + maxWidth: double.infinity, + maxHeight: double.infinity, + alignment: Alignment.center, + child: new FittedBox( + fit: BoxFit.cover, + alignment: Alignment.center, + clipBehavior: Clip.hardEdge, + child: new Container( + width: size?.shortestSide, + height: size?.longestSide, + //child: AspectRatio( + //aspectRatio: widget.controller.aspectRatio(), + child: widget.controller.buildPreview(), + //), + ), + ), + ), + Positioned( + bottom: 0, + //left: 0.0, + //right: 0.0, + child: Container( + height: 96 + 2 * 20 + 32, + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + color: Colors.grey.withOpacity(0.4), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), + ), + ), + ), + if (widget.enableZoom) + Positioned( + bottom: 96, + left: 0.0, + right: 0.0, + child: CircleAvatar( + radius: 20, + backgroundColor: Colors.grey.withOpacity(0.6), + child: IconButton( + icon: Center( + child: Text( + "${camera.zoom.toStringAsFixed(1)}x", + style: TextStyle(color: Colors.white, fontSize: 12), + ), + ), + onPressed: () { + widget.controller.zoomChange(); + }, + ), + ), ), - if (widget.enableZoom) - Positioned( - bottom: 96, - left: 0.0, - right: 0.0, + if (widget.controller.flashModes.length > 1) + Align( + alignment: Alignment.bottomLeft, + child: Padding( + padding: const EdgeInsets.all(32.0), child: CircleAvatar( radius: 20, - backgroundColor: Colors.grey.withOpacity(0.6), + backgroundColor: Colors.black.withOpacity(0.6), child: IconButton( - icon: Center( - child: Text( - "${camera.zoom.toStringAsFixed(1)}x", - style: TextStyle( - color: Colors.white, fontSize: 12), - ), - ), onPressed: () { - widget.controller.zoomChange(); + widget.controller.changeFlashMode(); }, + icon: Icon( + camera.flashModeIcon, + color: Colors.white, + ), ), ), ), - if (widget.controller.flashModes.length > 1) - Align( - alignment: Alignment.bottomLeft, - child: Padding( - padding: const EdgeInsets.all(32.0), - child: CircleAvatar( - radius: 20, - backgroundColor: Colors.black.withOpacity(0.6), - child: IconButton( - onPressed: () { - widget.controller.changeFlashMode(); - }, - icon: Icon( - camera.flashModeIcon, - color: Colors.white, - ), - ), - ), + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.only(bottom: 24), + child: InkWell( + onTap: widget.controller.takePhoto, + child: CircleAvatar( + radius: 30, + backgroundColor: Colors.white, ), ), + ), + ), + if (widget.enableFlipCamera) Align( - alignment: Alignment.bottomCenter, + alignment: Alignment.bottomRight, child: Padding( - padding: const EdgeInsets.only(bottom: 24), + padding: const EdgeInsets.all(32.0), child: InkWell( - onTap: () { - widget.controller.takePhoto(); - }, + onTap: widget.onCameraChange, child: CircleAvatar( - radius: 30, - backgroundColor: Colors.white, + radius: 20, + backgroundColor: Colors.black.withOpacity(0.6), + child: Icon( + Platform.isAndroid // + ? Icons.flip_camera_android + : Icons.flip_camera_ios, + color: Colors.white, + ), ), ), ), - ), - ], - ), + ) + ], ), + ); + }, failure: (message, _) => Container( color: Colors.black, child: Text(message), diff --git a/pubspec.yaml b/pubspec.yaml index 5149792..adce259 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,16 +8,16 @@ environment: sdk: ">=2.12.0-0.0 <3.0.0" dependencies: - camera: ^0.8.0-nullsafety.2 + camera: ^0.9.4+3 font_awesome_flutter: ^9.0.0-nullsafety - rxdart: ^0.26.0 + rxdart: ^0.27.2 flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter - mocktail: ^0.0.1-dev.11 + mocktail: ^0.2.0 # For information on the generic Dart part of this file, see the # following page: https://www.dartlang.org/tools/pub/pubspec