Redo custom camera pick

pull/920/head
X Code 3 years ago
parent c507e4fccd
commit 25cbc88422
  1. 29
      example/lib/pages/home_page.dart
  2. 44
      lib/src/translations/toolbar.i18n.dart
  3. 4
      lib/src/widgets/toolbar.dart
  4. 77
      lib/src/widgets/toolbar/camera_button.dart
  5. 2
      lib/src/widgets/toolbar/image_video_utils.dart

@ -156,6 +156,8 @@ class _HomePageState extends State<HomePage> {
onVideoPickCallback: _onVideoPickCallback, onVideoPickCallback: _onVideoPickCallback,
// uncomment to provide a custom "pick from" dialog. // uncomment to provide a custom "pick from" dialog.
// mediaPickSettingSelector: _selectMediaPickSetting, // mediaPickSettingSelector: _selectMediaPickSetting,
// uncomment to provide a custom "pick from" dialog.
// cameraPickSettingSelector: _selectCameraPickSetting,
showAlignmentButtons: true, showAlignmentButtons: true,
); );
if (kIsWeb) { if (kIsWeb) {
@ -271,6 +273,33 @@ class _HomePageState extends State<HomePage> {
), ),
); );
// ignore: unused_element
Future<MediaPickSetting?> _selectCameraPickSetting(BuildContext context) =>
showDialog<MediaPickSetting>(
context: context,
builder: (ctx) =>
AlertDialog(
contentPadding: EdgeInsets.zero,
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextButton.icon(
icon: const Icon(Icons.camera),
label: const Text('Capture a photo'),
onPressed: () =>
Navigator.pop(ctx, MediaPickSetting.Camera),
),
TextButton.icon(
icon: const Icon(Icons.video_call),
label: const Text('Capture a video'),
onPressed: () =>
Navigator.pop(ctx, MediaPickSetting.Video),
)
],
),
),
);
Widget _buildMenuBar(BuildContext context) { Widget _buildMenuBar(BuildContext context) {
final size = MediaQuery.of(context).size; final size = MediaQuery.of(context).size;
const itemStyle = TextStyle( const itemStyle = TextStyle(

@ -33,6 +33,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'en_us': { 'en_us': {
'Paste a link': 'Paste a link', 'Paste a link': 'Paste a link',
@ -64,6 +66,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'ar': { 'ar': {
'Paste a link': 'نسخ الرابط', 'Paste a link': 'نسخ الرابط',
@ -95,6 +99,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'da': { 'da': {
'Paste a link': 'Indsæt link', 'Paste a link': 'Indsæt link',
@ -126,6 +132,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'de': { 'de': {
'Paste a link': 'Link hinzufügen', 'Paste a link': 'Link hinzufügen',
@ -189,6 +197,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'zh_CN': { 'zh_CN': {
'Paste a link': '粘贴链接', 'Paste a link': '粘贴链接',
@ -220,6 +230,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'ko': { 'ko': {
'Paste a link': '링크를 붙여넣어 주세요.', 'Paste a link': '링크를 붙여넣어 주세요.',
@ -250,6 +262,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'ru': { 'ru': {
'Paste a link': 'Вставить ссылку', 'Paste a link': 'Вставить ссылку',
@ -281,6 +295,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'es': { 'es': {
'Paste a link': 'Pega un enlace', 'Paste a link': 'Pega un enlace',
@ -313,6 +329,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'tr': { 'tr': {
'Paste a link': 'Bağlantıyı Yapıştır', 'Paste a link': 'Bağlantıyı Yapıştır',
@ -344,6 +362,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'uk': { 'uk': {
'Paste a link': 'Вставити посилання', 'Paste a link': 'Вставити посилання',
@ -375,6 +395,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'pt': { 'pt': {
'Paste a link': 'Colar um link', 'Paste a link': 'Colar um link',
@ -407,6 +429,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'pl': { 'pl': {
'Paste a link': 'Wklej link', 'Paste a link': 'Wklej link',
@ -439,6 +463,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'vi': { 'vi': {
'Paste a link': 'Chèn liên kết', 'Paste a link': 'Chèn liên kết',
@ -471,6 +497,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'ur': { 'ur': {
'Paste a link': 'لنک پیسٹ کریں', 'Paste a link': 'لنک پیسٹ کریں',
@ -502,6 +530,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'id': { 'id': {
'Paste a link': 'Tempel tautan', 'Paste a link': 'Tempel tautan',
@ -533,6 +563,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'no': { 'no': {
'Paste a link': 'Lim inn lenke', 'Paste a link': 'Lim inn lenke',
@ -564,6 +596,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'fa': { 'fa': {
'Paste a link': 'جایگذاری لینک', 'Paste a link': 'جایگذاری لینک',
@ -595,6 +629,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'hi': { 'hi': {
'Paste a link': 'िक पट कर', 'Paste a link': 'िक पट कर',
@ -626,6 +662,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'nl': { 'nl': {
'Paste a link': 'Plak een link', 'Paste a link': 'Plak een link',
@ -657,6 +695,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'zh_HK': { 'zh_HK': {
'Paste a link': '貼上連結', 'Paste a link': '貼上連結',
@ -688,6 +728,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
'sr': { 'sr': {
'Paste a link': 'Nalepi vezu', 'Paste a link': 'Nalepi vezu',
@ -719,6 +761,8 @@ extension Localization on String {
'showing match': 'showing match', 'showing match': 'showing match',
'Prev': 'Prev', 'Prev': 'Prev',
'Next': 'Next', 'Next': 'Next',
'Camera': 'Camera',
'Video': 'Video',
}, },
}; };

@ -54,6 +54,8 @@ typedef WebVideoPickImpl = Future<String?> Function(
OnVideoPickCallback onImagePickCallback); OnVideoPickCallback onImagePickCallback);
typedef MediaPickSettingSelector = Future<MediaPickSetting?> Function( typedef MediaPickSettingSelector = Future<MediaPickSetting?> Function(
BuildContext context); BuildContext context);
typedef CameraPickSettingSelector = Future<MediaPickSetting?> Function(
BuildContext context);
// The default size of the icon of a button. // The default size of the icon of a button.
const double kDefaultIconSize = 18; const double kDefaultIconSize = 18;
@ -117,6 +119,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
OnImagePickCallback? onImagePickCallback, OnImagePickCallback? onImagePickCallback,
OnVideoPickCallback? onVideoPickCallback, OnVideoPickCallback? onVideoPickCallback,
MediaPickSettingSelector? mediaPickSettingSelector, MediaPickSettingSelector? mediaPickSettingSelector,
CameraPickSettingSelector? cameraPickSettingSelector,
FilePickImpl? filePickImpl, FilePickImpl? filePickImpl,
WebImagePickImpl? webImagePickImpl, WebImagePickImpl? webImagePickImpl,
WebVideoPickImpl? webVideoPickImpl, WebVideoPickImpl? webVideoPickImpl,
@ -364,6 +367,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
filePickImpl: filePickImpl, filePickImpl: filePickImpl,
webImagePickImpl: webImagePickImpl, webImagePickImpl: webImagePickImpl,
webVideoPickImpl: webVideoPickImpl, webVideoPickImpl: webVideoPickImpl,
cameraPickSettingSelector: cameraPickSettingSelector,
iconTheme: iconTheme, iconTheme: iconTheme,
), ),
if (showFormulaButton) if (showFormulaButton)

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import '../../models/themes/quill_icon_theme.dart'; import '../../models/themes/quill_icon_theme.dart';
import '../../translations/toolbar.i18n.dart';
import '../controller.dart'; import '../controller.dart';
import '../toolbar.dart'; import '../toolbar.dart';
@ -16,6 +17,7 @@ class CameraButton extends StatelessWidget {
this.filePickImpl, this.filePickImpl,
this.webImagePickImpl, this.webImagePickImpl,
this.webVideoPickImpl, this.webVideoPickImpl,
this.cameraPickSettingSelector,
this.iconTheme, this.iconTheme,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
@ -37,6 +39,8 @@ class CameraButton extends StatelessWidget {
final FilePickImpl? filePickImpl; final FilePickImpl? filePickImpl;
final CameraPickSettingSelector? cameraPickSettingSelector;
final QuillIconTheme? iconTheme; final QuillIconTheme? iconTheme;
@override @override
@ -69,48 +73,55 @@ class CameraButton extends StatelessWidget {
FilePickImpl? filePickImpl, FilePickImpl? filePickImpl,
WebImagePickImpl? webImagePickImpl}) async { WebImagePickImpl? webImagePickImpl}) async {
if (onImagePickCallback != null && onVideoPickCallback != null) { if (onImagePickCallback != null && onVideoPickCallback != null) {
// Show dialog to choose Photo or Video final selector = cameraPickSettingSelector ??
return await showDialog( (context) => showDialog<MediaPickSetting>(
context: context, context: context,
builder: (context) { builder: (ctx) => AlertDialog(
return AlertDialog( contentPadding: EdgeInsets.zero,
contentPadding: const EdgeInsets.all(0),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
content: Column(mainAxisSize: MainAxisSize.min, children: [ content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextButton.icon( TextButton.icon(
icon: const Icon(Icons.photo, color: Colors.cyanAccent), icon: const Icon(
label: const Text('Photo'), Icons.camera,
onPressed: () { color: Colors.orangeAccent,
ImageVideoUtils.handleImageButtonTap(context, controller, ),
ImageSource.camera, onImagePickCallback, label: Text('Camera'.i18n),
filePickImpl: filePickImpl, onPressed: () =>
webImagePickImpl: webImagePickImpl); Navigator.pop(ctx, MediaPickSetting.Camera),
},
), ),
TextButton.icon( TextButton.icon(
icon: const Icon(Icons.movie_creation, icon: const Icon(
color: Colors.orangeAccent), Icons.video_call,
label: const Text('Video'), color: Colors.cyanAccent,
onPressed: () { ),
ImageVideoUtils.handleVideoButtonTap(context, controller, label: Text('Video'.i18n),
ImageSource.camera, onVideoPickCallback, onPressed: () =>
filePickImpl: filePickImpl, Navigator.pop(ctx, MediaPickSetting.Video),
webVideoPickImpl: webVideoPickImpl);
},
) )
])); ],
}); ),
} ),
);
if (onImagePickCallback != null) { final source = await selector(context);
return ImageVideoUtils.handleImageButtonTap( if (source != null) {
switch (source) {
case MediaPickSetting.Camera:
await ImageVideoUtils.handleImageButtonTap(
context, controller, ImageSource.camera, onImagePickCallback, context, controller, ImageSource.camera, onImagePickCallback,
filePickImpl: filePickImpl, webImagePickImpl: webImagePickImpl); filePickImpl: filePickImpl, webImagePickImpl: webImagePickImpl);
} break;
case MediaPickSetting.Video:
assert(onVideoPickCallback != null, 'onVideoPickCallback must not be null'); await ImageVideoUtils.handleVideoButtonTap(
return ImageVideoUtils.handleVideoButtonTap( context, controller, ImageSource.camera, onVideoPickCallback,
context, controller, ImageSource.camera, onVideoPickCallback!,
filePickImpl: filePickImpl, webVideoPickImpl: webVideoPickImpl); filePickImpl: filePickImpl, webVideoPickImpl: webVideoPickImpl);
break;
default:
throw ArgumentError('Invalid MediaSetting');
}
}
}
} }
} }

@ -78,6 +78,8 @@ class LinkDialogState extends State<LinkDialog> {
enum MediaPickSetting { enum MediaPickSetting {
Gallery, Gallery,
Link, Link,
Camera,
Video,
} }
class ImageVideoUtils { class ImageVideoUtils {

Loading…
Cancel
Save