@@ -2,6 +2,7 @@ import 'package:app_settings/app_settings.dart';
2
2
import 'package:file_picker/file_picker.dart' ;
3
3
import 'package:flutter/material.dart' ;
4
4
import 'package:flutter/services.dart' ;
5
+ import 'package:image_picker/image_picker.dart' ;
5
6
import 'dialog.dart' ;
6
7
7
8
import '../api/route/messages.dart' ;
@@ -385,6 +386,51 @@ class _AttachMediaButton extends _AttachUploadsButton {
385
386
}
386
387
}
387
388
389
+ class _AttachFromCameraButton extends _AttachUploadsButton {
390
+ const _AttachFromCameraButton ({required super .contentController, required super .contentFocusNode});
391
+
392
+ @override
393
+ IconData get icon => Icons .camera_alt;
394
+
395
+ @override
396
+ Future <Iterable <_File >> getFiles (BuildContext context) async {
397
+ final picker = ImagePicker ();
398
+ final XFile ? result;
399
+ try {
400
+ // Ideally we'd open a platform interface that lets you choose between
401
+ // taking a photo and a video. `image_picker` doesn't yet have that
402
+ // option: https://github.com/flutter/flutter/issues/89159
403
+ // so just stick with images for now. We could add another button for
404
+ // videos, but we don't want too many buttons.
405
+ result = await picker.pickImage (source: ImageSource .camera, requestFullMetadata: false );
406
+ } catch (e) {
407
+ if (e is PlatformException && e.code == 'camera_access_denied' ) {
408
+ // iOS has a quirk where it will only request the native
409
+ // permission-request alert once, the first time the app wants to
410
+ // use a protected resource. After that, the only way the user can
411
+ // grant it is in Settings.
412
+ showSuggestedActionDialog (context: context, // TODO(i18n)
413
+ title: 'Permissions needed' ,
414
+ message: 'To upload an image, please grant Zulip additional permissions in Settings.' ,
415
+ actionButtonText: 'Open settings' ,
416
+ onActionButtonPress: () {
417
+ AppSettings .openAppSettings ();
418
+ });
419
+ } else {
420
+ // TODO(i18n)
421
+ showErrorDialog (context: context, title: 'Error' , message: e.toString ());
422
+ }
423
+ return [];
424
+ }
425
+ if (result == null ) {
426
+ return []; // User cancelled; do nothing
427
+ }
428
+ final length = await result.length ();
429
+
430
+ return [_File (content: result.openRead (), length: length, filename: result.name)];
431
+ }
432
+ }
433
+
388
434
/// The send button for StreamComposeBox.
389
435
class _StreamSendButton extends StatefulWidget {
390
436
const _StreamSendButton ({required this .topicController, required this .contentController});
@@ -584,6 +630,7 @@ class _StreamComposeBoxState extends State<StreamComposeBox> {
584
630
children: [
585
631
_AttachFileButton (contentController: _contentController, contentFocusNode: _contentFocusNode),
586
632
_AttachMediaButton (contentController: _contentController, contentFocusNode: _contentFocusNode),
633
+ _AttachFromCameraButton (contentController: _contentController, contentFocusNode: _contentFocusNode),
587
634
])),
588
635
]))));
589
636
}
0 commit comments