Skip to content

Commit 340fb2c

Browse files
committed
compose: Prototype upload-from-camera UI
Fixes: #61
1 parent 0ae1de3 commit 340fb2c

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

ios/Runner/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
<array>
5454
<string>fetch</string>
5555
</array>
56+
<key>NSCameraUsageDescription</key>
57+
<string>By allowing camera access, you can take photos and send them in Zulip messages.</string>
5658
<key>NSPhotoLibraryUsageDescription</key>
5759
<string>Choose photos from your library and send them in Zulip messages.</string>
5860
</dict>

lib/widgets/compose_box.dart

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import 'package:app_settings/app_settings.dart';
12
import 'package:file_picker/file_picker.dart';
23
import 'package:flutter/material.dart';
4+
import 'package:flutter/services.dart';
5+
import 'package:image_picker/image_picker.dart';
36
import 'dialog.dart';
47

58
import '../api/route/messages.dart';
@@ -356,6 +359,61 @@ class _AttachMediaButton extends StatelessWidget {
356359
}
357360
}
358361

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+
359417
/// The send button for StreamComposeBox.
360418
class _StreamSendButton extends StatefulWidget {
361419
const _StreamSendButton({required this.topicController, required this.contentController});
@@ -555,6 +613,7 @@ class _StreamComposeBoxState extends State<StreamComposeBox> {
555613
children: [
556614
_AttachFileButton(contentController: _contentController, contentFocusNode: _contentFocusNode),
557615
_AttachMediaButton(contentController: _contentController, contentFocusNode: _contentFocusNode),
616+
_AttachFromCameraButton(contentController: _contentController, contentFocusNode: _contentFocusNode),
558617
])),
559618
]))));
560619
}

0 commit comments

Comments
 (0)