@@ -108,6 +108,12 @@ class _ImagePickerState extends State<ImagePicker>
108
108
/// Flag indicating state of image selecting.
109
109
bool _isImageSelectedDone = false ;
110
110
111
+ /// Flag indicating status of permission to access cameras
112
+ bool _isCameraPermissionOK = false ;
113
+
114
+ /// Flag indicating status of permission to access photo libray
115
+ bool _isGalleryPermissionOK = false ;
116
+
111
117
/// Image configuration.
112
118
ImagePickerConfigs _configs = ImagePickerConfigs ();
113
119
@@ -228,16 +234,20 @@ class _ImagePickerState extends State<ImagePicker>
228
234
Future <void > _initPhotoCapture () async {
229
235
LogUtils .log ("[_initPhotoCapture] start" );
230
236
231
- // List all cameras in current device.
232
- _cameras = await availableCameras ();
233
-
234
- // Select new camera for capturing.
235
- if (_cameras.isNotEmpty) {
236
- final CameraDescription ? newDescription = _getCamera (
237
- _cameras, _getCameraDirection (_configs.cameraLensDirection));
238
- if (newDescription != null ) {
239
- await _onNewCameraSelected (newDescription);
237
+ try {
238
+ // List all cameras in current device.
239
+ _cameras = await availableCameras ();
240
+
241
+ // Select new camera for capturing.
242
+ if (_cameras.isNotEmpty) {
243
+ final CameraDescription ? newDescription = _getCamera (
244
+ _cameras, _getCameraDirection (_configs.cameraLensDirection));
245
+ if (newDescription != null ) {
246
+ await _onNewCameraSelected (newDescription);
247
+ }
240
248
}
249
+ } on CameraException catch (e) {
250
+ LogUtils .log ('Camera error ${e .code }, ${e .description }' );
241
251
}
242
252
}
243
253
@@ -265,6 +275,43 @@ class _ImagePickerState extends State<ImagePicker>
265
275
}
266
276
}
267
277
278
+ /// Initialize current selected camera
279
+ void _initCameraController () {
280
+ // Create future object for initializing new camera controller.
281
+ final cameraController = _controller! ;
282
+ _initializeControllerFuture =
283
+ cameraController.initialize ().then ((value) async {
284
+ LogUtils .log ("[_onNewCameraSelected] cameraController initialized." );
285
+
286
+ _isCameraPermissionOK = true ;
287
+
288
+ // After initialized, setting zoom & exposure values
289
+ await Future .wait ([
290
+ cameraController.lockCaptureOrientation (DeviceOrientation .portraitUp),
291
+ cameraController.setFlashMode (_configs.flashMode),
292
+ cameraController
293
+ .getMinExposureOffset ()
294
+ .then ((value) => _minAvailableExposureOffset = value),
295
+ cameraController
296
+ .getMaxExposureOffset ()
297
+ .then ((value) => _maxAvailableExposureOffset = value),
298
+ cameraController
299
+ .getMaxZoomLevel ()
300
+ .then ((value) => _maxAvailableZoom = value),
301
+ cameraController
302
+ .getMinZoomLevel ()
303
+ .then ((value) => _minAvailableZoom = value),
304
+ ]);
305
+
306
+ // Refresh screen for applying new updated
307
+ if (mounted) {
308
+ setState (() {});
309
+ }
310
+ }).catchError ((e) {
311
+ LogUtils .log ('Camera error ${e .toString ()}' );
312
+ });
313
+ }
314
+
268
315
/// Select new camera for capturing
269
316
Future <void > _onNewCameraSelected (CameraDescription cameraDescription) async {
270
317
LogUtils .log ("[_onNewCameraSelected] start" );
@@ -281,64 +328,44 @@ class _ImagePickerState extends State<ImagePicker>
281
328
);
282
329
_controller = cameraController;
283
330
331
+ // Init selected camera
332
+ _initCameraController ();
333
+
284
334
// If the controller is updated then update the UI.
285
- cameraController .addListener (() {
335
+ _controller ! .addListener (() {
286
336
if (mounted) setState (() {});
287
337
if (cameraController.value.hasError) {
288
338
LogUtils .log ('Camera error ${cameraController .value .errorDescription }' );
289
339
}
290
340
});
291
-
292
- // Create future object for initializing new camera controller.
293
- try {
294
- _initializeControllerFuture =
295
- cameraController.initialize ().then ((value) async {
296
- LogUtils .log ("[_onNewCameraSelected] cameraController initialized." );
297
-
298
- // After initialized, setting zoom & exposure values
299
- await Future .wait ([
300
- cameraController.lockCaptureOrientation (DeviceOrientation .portraitUp),
301
- cameraController.setFlashMode (_configs.flashMode),
302
- cameraController
303
- .getMinExposureOffset ()
304
- .then ((value) => _minAvailableExposureOffset = value),
305
- cameraController
306
- .getMaxExposureOffset ()
307
- .then ((value) => _maxAvailableExposureOffset = value),
308
- cameraController
309
- .getMaxZoomLevel ()
310
- .then ((value) => _maxAvailableZoom = value),
311
- cameraController
312
- .getMinZoomLevel ()
313
- .then ((value) => _minAvailableZoom = value),
314
- ]);
315
-
316
- // Refresh screen for applying new updated
317
- if (mounted) {
318
- setState (() {});
319
- }
320
- });
321
- } on CameraException catch (e) {
322
- LogUtils .log ('Camera error ${e .code }, ${e .description }' );
323
- }
324
341
}
325
342
326
343
/// Init photo gallery for image selecting
327
344
Future <void > _initPhotoGallery () async {
328
345
LogUtils .log ("[_initPhotoGallery] start" );
329
346
330
- // Request permission for image selecting
331
- final result = await PhotoManager .requestPermission ();
332
- if (result) {
333
- // Get albums then set first album as current album
334
- _albums = await PhotoManager .getAssetPathList (type: RequestType .image);
335
- if (_albums.isNotEmpty) {
336
- final isAllAlbum = _albums.firstWhere ((element) => element.isAll,
337
- orElse: () => _albums.first);
338
- setState (() {
339
- _currentAlbum = isAllAlbum;
340
- });
347
+ try {
348
+ // Request permission for image selecting
349
+ final result = await PhotoManager .requestPermissionExtend ();
350
+ if (result.isAuth) {
351
+ LogUtils .log ('PhotoGallery permission allowed' );
352
+
353
+ _isGalleryPermissionOK = true ;
354
+
355
+ // Get albums then set first album as current album
356
+ _albums = await PhotoManager .getAssetPathList (type: RequestType .image);
357
+ if (_albums.isNotEmpty) {
358
+ final isAllAlbum = _albums.firstWhere ((element) => element.isAll,
359
+ orElse: () => _albums.first);
360
+ setState (() {
361
+ _currentAlbum = isAllAlbum;
362
+ });
363
+ }
364
+ } else {
365
+ LogUtils .log ('PhotoGallery permission not allowed' );
341
366
}
367
+ } catch (e) {
368
+ LogUtils .log ('PhotoGallery error ${e .toString ()}' );
342
369
}
343
370
}
344
371
@@ -607,9 +634,13 @@ class _ImagePickerState extends State<ImagePicker>
607
634
return Stack (children: [
608
635
SizedBox (height: size.height, width: size.width),
609
636
if (_mode == PickerMode .Camera )
610
- Center (child: _buildCameraPreview (context))
637
+ _isCameraPermissionOK
638
+ ? Center (child: _buildCameraPreview (context))
639
+ : _buildCameraRequestPermissionView (context)
611
640
else
612
- _buildAlbumPreview (context),
641
+ _isGalleryPermissionOK
642
+ ? _buildAlbumPreview (context)
643
+ : _builGalleryRequestPermissionView (context),
613
644
if (_mode == PickerMode .Camera ) ...[
614
645
Positioned (
615
646
bottom: bottomHeight.toDouble (),
@@ -778,6 +809,37 @@ class _ImagePickerState extends State<ImagePicker>
778
809
: container;
779
810
}
780
811
812
+ /// Build camera request permission view
813
+ Widget _buildCameraRequestPermissionView (BuildContext context) {
814
+ final size = MediaQuery .of (context).size;
815
+ final bottomHeight = (widget.maxCount == 1 )
816
+ ? (kBottomControlPanelHeight - 40 )
817
+ : kBottomControlPanelHeight;
818
+ return SizedBox (
819
+ width: size.width,
820
+ height: size.height - bottomHeight,
821
+ child: Column (
822
+ mainAxisAlignment: MainAxisAlignment .center,
823
+ children: [
824
+ TextButton (
825
+ style: TextButton .styleFrom (
826
+ backgroundColor: Colors .grey.shade400,
827
+ padding: const EdgeInsets .symmetric (horizontal: 12 ),
828
+ shape: const RoundedRectangleBorder (
829
+ borderRadius: BorderRadius .all (Radius .circular (30 )),
830
+ ),
831
+ ),
832
+ onPressed: _initCameraController,
833
+ child: Text (_configs.textRequestPermission,
834
+ style: const TextStyle (color: Colors .black)),
835
+ ),
836
+ Text (_configs.textRequestCameraPermission,
837
+ style: const TextStyle (color: Colors .grey))
838
+ ],
839
+ ),
840
+ );
841
+ }
842
+
781
843
/// Build camera preview widget.
782
844
Widget _buildCameraPreview (BuildContext context) {
783
845
LogUtils .log ("[_buildCameraPreview] start" );
@@ -859,6 +921,33 @@ class _ImagePickerState extends State<ImagePicker>
859
921
});
860
922
}
861
923
924
+ /// Build camera request permission view
925
+ Widget _builGalleryRequestPermissionView (BuildContext context) {
926
+ final size = MediaQuery .of (context).size;
927
+ final bottomHeight = (widget.maxCount == 1 )
928
+ ? (kBottomControlPanelHeight - 40 )
929
+ : kBottomControlPanelHeight;
930
+ return SizedBox (
931
+ width: size.width,
932
+ height: size.height - bottomHeight,
933
+ child: Column (mainAxisAlignment: MainAxisAlignment .center, children: [
934
+ TextButton (
935
+ style: TextButton .styleFrom (
936
+ backgroundColor: Colors .grey.shade400,
937
+ padding: const EdgeInsets .symmetric (horizontal: 12 ),
938
+ shape: const RoundedRectangleBorder (
939
+ borderRadius: BorderRadius .all (Radius .circular (30 )),
940
+ ),
941
+ ),
942
+ onPressed: _initPhotoGallery,
943
+ child: Text (_configs.textRequestPermission,
944
+ style: const TextStyle (color: Colors .black)),
945
+ ),
946
+ Text (_configs.textRequestGalleryPermission,
947
+ style: const TextStyle (color: Colors .grey))
948
+ ]));
949
+ }
950
+
862
951
/// Build album preview widget.
863
952
Widget _buildAlbumPreview (BuildContext context) {
864
953
LogUtils .log ("[_buildAlbumPreview] start" );
@@ -1344,9 +1433,11 @@ class _ImagePickerState extends State<ImagePicker>
1344
1433
groupValue: _mode,
1345
1434
onValueChanged: (dynamic val) async {
1346
1435
if (_mode != val) {
1347
- if (val == PickerMode .Camera && _cameras.isEmpty) {
1436
+ if (val == PickerMode .Camera &&
1437
+ (_cameras.isEmpty || ! _isCameraPermissionOK)) {
1348
1438
await _initPhotoCapture ();
1349
- } else if (val == PickerMode .Album && _albums.isEmpty) {
1439
+ } else if (val == PickerMode .Album &&
1440
+ (_albums.isEmpty || ! _isGalleryPermissionOK)) {
1350
1441
await _initPhotoGallery ();
1351
1442
}
1352
1443
0 commit comments