|
| 1 | +import 'package:app_settings/app_settings.dart'; |
1 | 2 | import 'package:file_picker/file_picker.dart';
|
2 | 3 | import 'package:flutter/material.dart';
|
| 4 | +import 'package:flutter/services.dart'; |
| 5 | +import 'package:image_picker/image_picker.dart'; |
3 | 6 | import 'dialog.dart';
|
4 | 7 |
|
5 | 8 | import '../api/route/messages.dart';
|
@@ -356,6 +359,61 @@ class _AttachMediaButton extends StatelessWidget {
|
356 | 359 | }
|
357 | 360 | }
|
358 | 361 |
|
| 362 | +class _AttachFromCameraButton extends StatelessWidget { |
| 363 | + _AttachFromCameraButton({required this.contentController, required this.contentFocusNode}); |
| 364 | + |
| 365 | + final _picker = ImagePicker(); |
| 366 | + final ContentTextEditingController contentController; |
| 367 | + final FocusNode contentFocusNode; |
| 368 | + |
| 369 | + _handlePress(BuildContext context) async { |
| 370 | + final XFile? result; |
| 371 | + try { |
| 372 | + // Ideally we'd open a platform interface that lets you choose between |
| 373 | + // taking a photo and a video. `image_picker` doesn't yet have that |
| 374 | + // option: https://github.com/flutter/flutter/issues/89159 |
| 375 | + // so just stick with images for now. We could add another button for |
| 376 | + // videos, but we don't want too many buttons. |
| 377 | + result = await _picker.pickImage(source: ImageSource.camera, requestFullMetadata: false); |
| 378 | + } catch (e) { |
| 379 | + if (e is PlatformException && e.code == 'camera_access_denied') { |
| 380 | + // iOS has a quirk where it will only request the native |
| 381 | + // permission-request alert once, the first time the app wants to |
| 382 | + // use a protected resource. After that, the only way the user can |
| 383 | + // grant it is in Settings. |
| 384 | + showSuggestedActionDialog(context: context, // TODO(i18n) |
| 385 | + title: 'Permissions needed', |
| 386 | + message: 'To upload an image, please grant Zulip additional permissions in Settings.', |
| 387 | + actionButtonText: 'Open settings', |
| 388 | + onActionButtonPress: () { |
| 389 | + AppSettings.openAppSettings(); |
| 390 | + }); |
| 391 | + } else { |
| 392 | + // TODO(i18n) |
| 393 | + showErrorDialog(context: context, title: 'Error', message: e.toString()); |
| 394 | + } |
| 395 | + return; |
| 396 | + } |
| 397 | + if (result == null) { |
| 398 | + return; // User cancelled; do nothing |
| 399 | + } |
| 400 | + final length = await result.length(); |
| 401 | + |
| 402 | + if (context.mounted) {} // https://github.com/dart-lang/linter/issues/4007 |
| 403 | + else { |
| 404 | + return; |
| 405 | + } |
| 406 | + |
| 407 | + _uploadFiles(context: context, contentController: contentController, contentFocusNode: contentFocusNode, |
| 408 | + files: [_File(content: result.openRead(), length: length, filename: result.name)]); |
| 409 | + } |
| 410 | + |
| 411 | + @override |
| 412 | + Widget build(BuildContext context) { |
| 413 | + return IconButton(icon: const Icon(Icons.camera_alt), onPressed: () => _handlePress(context)); |
| 414 | + } |
| 415 | +} |
| 416 | + |
359 | 417 | /// The send button for StreamComposeBox.
|
360 | 418 | class _StreamSendButton extends StatefulWidget {
|
361 | 419 | const _StreamSendButton({required this.topicController, required this.contentController});
|
@@ -555,6 +613,7 @@ class _StreamComposeBoxState extends State<StreamComposeBox> {
|
555 | 613 | children: [
|
556 | 614 | _AttachFileButton(contentController: _contentController, contentFocusNode: _contentFocusNode),
|
557 | 615 | _AttachMediaButton(contentController: _contentController, contentFocusNode: _contentFocusNode),
|
| 616 | + _AttachFromCameraButton(contentController: _contentController, contentFocusNode: _contentFocusNode), |
558 | 617 | ])),
|
559 | 618 | ]))));
|
560 | 619 | }
|
|
0 commit comments