Refactor out camera button in toolbar

pull/307/head
Xin Yao 4 years ago
parent e3bb1030b2
commit 853aea3820
  1. 26
      lib/src/widgets/toolbar.dart
  2. 80
      lib/src/widgets/toolbar/camera_button.dart
  3. 61
      lib/src/widgets/toolbar/image_button.dart
  4. 115
      lib/src/widgets/toolbar/image_video_utils.dart
  5. 61
      lib/src/widgets/toolbar/video_button.dart

@ -2,11 +2,11 @@ import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import '../models/documents/attribute.dart';
import 'controller.dart';
import 'toolbar/arrow_indicated_button_list.dart';
import 'toolbar/camera_button.dart';
import 'toolbar/clear_format_button.dart';
import 'toolbar/color_button.dart';
import 'toolbar/history_button.dart';
@ -82,6 +82,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
OnVideoPickCallback? onVideoPickCallback,
FilePickImpl? filePickImpl,
WebImagePickImpl? webImagePickImpl,
WebVideoPickImpl? webVideoPickImpl,
Key? key,
}) {
final isButtonGroupShown = [
@ -173,7 +174,6 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
icon: Icons.image,
iconSize: toolbarIconSize,
controller: controller,
imageSource: ImageSource.gallery,
onImagePickCallback: onImagePickCallback,
filePickImpl: filePickImpl,
webImagePickImpl: webImagePickImpl,
@ -183,21 +183,21 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
icon: Icons.movie_creation,
iconSize: toolbarIconSize,
controller: controller,
videoSource: ImageSource.gallery,
onVideoPickCallback: onVideoPickCallback,
filePickImpl: filePickImpl,
webVideoPickImpl: webImagePickImpl,
),
if (onImagePickCallback != null && showCamera)
ImageButton(
icon: Icons.photo_camera,
iconSize: toolbarIconSize,
controller: controller,
imageSource: ImageSource.camera,
onImagePickCallback: onImagePickCallback,
filePickImpl: filePickImpl,
webImagePickImpl: webImagePickImpl,
),
if ((onImagePickCallback != null || onVideoPickCallback != null) &&
showCamera)
CameraButton(
icon: Icons.photo_camera,
iconSize: toolbarIconSize,
controller: controller,
onImagePickCallback: onImagePickCallback,
onVideoPickCallback: onVideoPickCallback,
filePickImpl: filePickImpl,
webImagePickImpl: webImagePickImpl,
webVideoPickImpl: webVideoPickImpl),
if (isButtonGroupShown[0] &&
(isButtonGroupShown[1] ||
isButtonGroupShown[2] ||

@ -0,0 +1,80 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import '../controller.dart';
import '../toolbar.dart';
import 'image_video_utils.dart';
import 'quill_icon_button.dart';
class CameraButton extends StatelessWidget {
const CameraButton({
required this.icon,
required this.controller,
this.iconSize = kDefaultIconSize,
this.fillColor,
this.onImagePickCallback,
this.onVideoPickCallback,
this.filePickImpl,
this.webImagePickImpl,
this.webVideoPickImpl,
Key? key,
}) : super(key: key);
final IconData icon;
final double iconSize;
final Color? fillColor;
final QuillController controller;
final OnImagePickCallback? onImagePickCallback;
final OnVideoPickCallback? onVideoPickCallback;
final WebImagePickImpl? webImagePickImpl;
final WebVideoPickImpl? webVideoPickImpl;
final FilePickImpl? filePickImpl;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return QuillIconButton(
icon: Icon(icon, size: iconSize, color: theme.iconTheme.color),
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
fillColor: fillColor ?? theme.canvasColor,
onPressed: () => _handleCameraButtonTap(context, controller,
onImagePickCallback: onImagePickCallback,
onVideoPickCallback: onVideoPickCallback,
filePickImpl: filePickImpl,
webImagePickImpl: webImagePickImpl),
);
}
Future<void> _handleCameraButtonTap(
BuildContext context, QuillController controller,
{OnImagePickCallback? onImagePickCallback,
OnVideoPickCallback? onVideoPickCallback,
FilePickImpl? filePickImpl,
WebImagePickImpl? webImagePickImpl}) async {
if (onImagePickCallback != null && onVideoPickCallback != null) {
// TODO: show dialog to choose Image or Video
}
if (onImagePickCallback != null) {
return ImageVideoUtils.handleImageButtonTap(
context, controller, ImageSource.camera, onImagePickCallback,
filePickImpl: filePickImpl, webImagePickImpl: webImagePickImpl);
}
assert(onVideoPickCallback != null, 'onVideoPickCallback must not be null');
return ImageVideoUtils.handleVideoButtonTap(
context, controller, ImageSource.camera, onVideoPickCallback!,
filePickImpl: filePickImpl, webVideoPickImpl: webVideoPickImpl);
}
}

@ -1,22 +1,19 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import '../../models/documents/nodes/embed.dart';
import '../controller.dart';
import '../toolbar.dart';
import 'image_video_utils.dart';
import 'quill_icon_button.dart';
class ImageButton extends StatelessWidget {
const ImageButton({
required this.icon,
required this.controller,
required this.imageSource,
required this.onImagePickCallback,
this.iconSize = kDefaultIconSize,
this.fillColor,
this.onImagePickCallback,
this.filePickImpl,
this.webImagePickImpl,
Key? key,
@ -29,12 +26,10 @@ class ImageButton extends StatelessWidget {
final QuillController controller;
final OnImagePickCallback? onImagePickCallback;
final OnImagePickCallback onImagePickCallback;
final WebImagePickImpl? webImagePickImpl;
final ImageSource imageSource;
final FilePickImpl? filePickImpl;
@override
@ -47,53 +42,9 @@ class ImageButton extends StatelessWidget {
hoverElevation: 0,
size: iconSize * 1.77,
fillColor: fillColor ?? theme.canvasColor,
onPressed: () => _handleImageButtonTap(context, filePickImpl),
onPressed: () => ImageVideoUtils.handleImageButtonTap(
context, controller, ImageSource.gallery, onImagePickCallback,
filePickImpl: filePickImpl, webImagePickImpl: webImagePickImpl),
);
}
Future<void> _handleImageButtonTap(BuildContext context,
[FilePickImpl? filePickImpl]) async {
final index = controller.selection.baseOffset;
final length = controller.selection.extentOffset - index;
String? imageUrl;
if (kIsWeb) {
assert(
webImagePickImpl != null,
'Please provide webImagePickImpl for Web '
'(check out example directory for how to do it)');
imageUrl = await webImagePickImpl!(onImagePickCallback!);
} else if (Platform.isAndroid || Platform.isIOS) {
imageUrl = await _pickImage(imageSource, onImagePickCallback!);
} else {
assert(filePickImpl != null, 'Desktop must provide filePickImpl');
imageUrl =
await _pickImageDesktop(context, filePickImpl!, onImagePickCallback!);
}
if (imageUrl != null) {
controller.replaceText(index, length, BlockEmbed.image(imageUrl), null);
}
}
Future<String?> _pickImage(
ImageSource source, OnImagePickCallback onImagePickCallback) async {
final pickedFile = await ImagePicker().pickImage(source: source);
if (pickedFile == null) {
return null;
}
return onImagePickCallback(File(pickedFile.path));
}
Future<String?> _pickImageDesktop(
BuildContext context,
FilePickImpl filePickImpl,
OnImagePickCallback onImagePickCallback) async {
final filePath = await filePickImpl(context);
if (filePath == null || filePath.isEmpty) return null;
final file = File(filePath);
return onImagePickCallback(file);
}
}

@ -0,0 +1,115 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import '../../models/documents/nodes/embed.dart';
import '../controller.dart';
import '../toolbar.dart';
class ImageVideoUtils {
/// For image picking logic
static Future<void> handleImageButtonTap(
BuildContext context,
QuillController controller,
ImageSource imageSource,
OnImagePickCallback onImagePickCallback,
{FilePickImpl? filePickImpl,
WebImagePickImpl? webImagePickImpl}) async {
final index = controller.selection.baseOffset;
final length = controller.selection.extentOffset - index;
String? imageUrl;
if (kIsWeb) {
assert(
webImagePickImpl != null,
'Please provide webImagePickImpl for Web '
'(check out example directory for how to do it)');
imageUrl = await webImagePickImpl!(onImagePickCallback);
} else if (Platform.isAndroid || Platform.isIOS) {
imageUrl = await _pickImage(imageSource, onImagePickCallback);
} else {
assert(filePickImpl != null, 'Desktop must provide filePickImpl');
imageUrl =
await _pickImageDesktop(context, filePickImpl!, onImagePickCallback);
}
if (imageUrl != null) {
controller.replaceText(index, length, BlockEmbed.image(imageUrl), null);
}
}
static Future<String?> _pickImage(
ImageSource source, OnImagePickCallback onImagePickCallback) async {
final pickedFile = await ImagePicker().pickImage(source: source);
if (pickedFile == null) {
return null;
}
return onImagePickCallback(File(pickedFile.path));
}
static Future<String?> _pickImageDesktop(
BuildContext context,
FilePickImpl filePickImpl,
OnImagePickCallback onImagePickCallback) async {
final filePath = await filePickImpl(context);
if (filePath == null || filePath.isEmpty) return null;
final file = File(filePath);
return onImagePickCallback(file);
}
/// For video picking logic
static Future<void> handleVideoButtonTap(
BuildContext context,
QuillController controller,
ImageSource videoSource,
OnVideoPickCallback onVideoPickCallback,
{FilePickImpl? filePickImpl,
WebVideoPickImpl? webVideoPickImpl}) async {
final index = controller.selection.baseOffset;
final length = controller.selection.extentOffset - index;
String? videoUrl;
if (kIsWeb) {
assert(
webVideoPickImpl != null,
'Please provide webVideoPickImpl for Web '
'(check out example directory for how to do it)');
videoUrl = await webVideoPickImpl!(onVideoPickCallback);
} else if (Platform.isAndroid || Platform.isIOS) {
videoUrl = await _pickVideo(ImageSource.gallery, onVideoPickCallback);
} else {
assert(filePickImpl != null, 'Desktop must provide filePickImpl');
videoUrl =
await _pickVideoDesktop(context, filePickImpl!, onVideoPickCallback);
}
if (videoUrl != null) {
controller.replaceText(index, length, BlockEmbed.video(videoUrl), null);
}
}
static Future<String?> _pickVideo(
ImageSource source, OnVideoPickCallback onVideoPickCallback) async {
final pickedFile = await ImagePicker().pickVideo(source: source);
if (pickedFile == null) {
return null;
}
return onVideoPickCallback(File(pickedFile.path));
}
static Future<String?> _pickVideoDesktop(
BuildContext context,
FilePickImpl filePickImpl,
OnVideoPickCallback onVideoPickCallback) async {
final filePath = await filePickImpl(context);
if (filePath == null || filePath.isEmpty) return null;
final file = File(filePath);
return onVideoPickCallback(file);
}
}

@ -1,22 +1,19 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import '../../models/documents/nodes/embed.dart';
import '../controller.dart';
import '../toolbar.dart';
import 'image_video_utils.dart';
import 'quill_icon_button.dart';
class VideoButton extends StatelessWidget {
const VideoButton({
required this.icon,
required this.controller,
required this.videoSource,
required this.onVideoPickCallback,
this.iconSize = kDefaultIconSize,
this.fillColor,
this.onVideoPickCallback,
this.filePickImpl,
this.webVideoPickImpl,
Key? key,
@ -29,12 +26,10 @@ class VideoButton extends StatelessWidget {
final QuillController controller;
final OnVideoPickCallback? onVideoPickCallback;
final OnVideoPickCallback onVideoPickCallback;
final WebVideoPickImpl? webVideoPickImpl;
final ImageSource videoSource;
final FilePickImpl? filePickImpl;
@override
@ -47,53 +42,9 @@ class VideoButton extends StatelessWidget {
hoverElevation: 0,
size: iconSize * 1.77,
fillColor: fillColor ?? theme.canvasColor,
onPressed: () => _handleVideoButtonTap(context, filePickImpl),
onPressed: () => ImageVideoUtils.handleVideoButtonTap(
context, controller, ImageSource.gallery, onVideoPickCallback,
filePickImpl: filePickImpl, webVideoPickImpl: webVideoPickImpl),
);
}
Future<void> _handleVideoButtonTap(BuildContext context,
[FilePickImpl? filePickImpl]) async {
final index = controller.selection.baseOffset;
final length = controller.selection.extentOffset - index;
String? videoUrl;
if (kIsWeb) {
assert(
webVideoPickImpl != null,
'Please provide webVideoPickImpl for Web '
'(check out example directory for how to do it)');
videoUrl = await webVideoPickImpl!(onVideoPickCallback!);
} else if (Platform.isAndroid || Platform.isIOS) {
videoUrl = await _pickVideo(videoSource, onVideoPickCallback!);
} else {
assert(filePickImpl != null, 'Desktop must provide filePickImpl');
videoUrl =
await _pickVideoDesktop(context, filePickImpl!, onVideoPickCallback!);
}
if (videoUrl != null) {
controller.replaceText(index, length, BlockEmbed.video(videoUrl), null);
}
}
Future<String?> _pickVideo(
ImageSource source, OnVideoPickCallback onVideoPickCallback) async {
final pickedFile = await ImagePicker().pickVideo(source: source);
if (pickedFile == null) {
return null;
}
return onVideoPickCallback(File(pickedFile.path));
}
Future<String?> _pickVideoDesktop(
BuildContext context,
FilePickImpl filePickImpl,
OnVideoPickCallback onVideoPickCallback) async {
final filePath = await filePickImpl(context);
if (filePath == null || filePath.isEmpty) return null;
final file = File(filePath);
return onVideoPickCallback(file);
}
}

Loading…
Cancel
Save