Step 5 of remaking the example

pull/1530/head
Ellet 1 year ago
parent 2b171d04af
commit e03501b944
No known key found for this signature in database
GPG Key ID: C488CC70BBCEF0D1
  1. 4
      example/android/app/src/main/AndroidManifest.xml
  2. 2
      example/lib/main.dart
  3. 132
      example/lib/presentation/quill/quill_screen.dart
  4. 2
      example/macos/Flutter/GeneratedPluginRegistrant.swift
  5. 1
      example/pubspec.yaml
  6. 5
      example/web/index.html
  7. 2
      flutter_quill_extensions/lib/presentation/embeds/editor/image/image_menu.dart
  8. 3
      flutter_quill_extensions/lib/presentation/models/config/editor/image/image.dart

@ -40,6 +40,10 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data

@ -61,7 +61,7 @@ class MyApp extends StatelessWidget {
SettingsScreen.routeName: (context) => const SettingsScreen(),
},
onGenerateRoute: (settings) {
final name = settings.name ?? '/';
final name = settings.name;
if (name == HomeScreen.routeName) {
return MaterialPageRoute(
builder: (context) {

@ -1,12 +1,13 @@
import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:desktop_drop/desktop_drop.dart';
import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
import 'package:flutter_quill_extensions/presentation/embeds/widgets/image.dart'
show imageFileExtensions;
show getImageProviderByImageSource, imageFileExtensions;
import 'package:image_cropper/image_cropper.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
@ -47,7 +48,8 @@ class _QuillScreenState extends State<QuillScreen> {
_controller.document = widget.args.document;
}
Future<void> onImageInsert(String image, QuillController controller) async {
Future<void> onImageInsertWithCropping(
String image, QuillController controller) async {
final croppedFile = await ImageCropper().cropImage(
sourcePath: image,
aspectRatioPresets: [
@ -85,6 +87,15 @@ class _QuillScreenState extends State<QuillScreen> {
controller.insertImageBlock(imageSource: newSavedImage);
}
Future<void> onImageInsert(String image, QuillController controller) async {
if (isWeb()) {
controller.insertImageBlock(imageSource: image);
return;
}
final newSavedImage = await saveImage(File(image));
controller.insertImageBlock(imageSource: newSavedImage);
}
/// Copies the picked file from temporary cache to applications directory
Future<String> saveImage(File file) async {
final appDocDir = await getApplicationDocumentsDirectory();
@ -147,44 +158,95 @@ class _QuillScreenState extends State<QuillScreen> {
if (!_isReadOnly)
QuillToolbar(
configurations: QuillToolbarConfigurations(
embedButtons: FlutterQuillEmbeds.toolbarButtons(),
embedButtons: FlutterQuillEmbeds.toolbarButtons(
imageButtonOptions: QuillToolbarImageButtonOptions(
imageButtonConfigurations:
QuillToolbarImageConfigurations(
onImageInsertCallback: isAndroid(supportWeb: false) ||
isIOS(supportWeb: false) ||
isWeb()
? onImageInsertWithCropping
: onImageInsert,
),
),
),
),
),
Expanded(
child: QuillEditor.basic(
configurations: QuillEditorConfigurations(
scrollable: true,
readOnly: _isReadOnly,
placeholder: 'Start writting your notes...',
padding: const EdgeInsets.all(16),
embedBuilders: FlutterQuillEmbeds.defaultEditorBuilders(),
builder: (context, rawEditor) {
// The `desktop_drop` plugin doesn't support iOS platform for now
if (isIOS(supportWeb: false)) {
return rawEditor;
}
return DropTarget(
onDragDone: (details) {
final scaffoldMessenger = ScaffoldMessenger.of(context);
final file = details.files.first;
final isSupported = imageFileExtensions
.any((ext) => file.name.endsWith(ext));
if (!isSupported) {
scaffoldMessenger.showText(
'Only images are supported right now: ${file.mimeType}, ${file.name}, ${file.path}, $imageFileExtensions',
);
return;
Builder(
builder: (context) {
return Expanded(
child: QuillEditor.basic(
configurations: QuillEditorConfigurations(
scrollable: true,
readOnly: _isReadOnly,
placeholder: 'Start writting your notes...',
padding: const EdgeInsets.all(16),
embedBuilders: isWeb()
? FlutterQuillEmbeds.editorWebBuilders()
: FlutterQuillEmbeds.editorBuilders(
imageEmbedConfigurations:
QuillEditorImageEmbedConfigurations(
imageErrorWidgetBuilder:
(context, error, stackTrace) {
return Text(
'Error while loading an image: ${error.toString()}',
);
},
imageProviderBuilder: (imageUrl) {
// cached_network_image is supported
// only for Android, iOS and web
// We will use it only if image from network
if (isAndroid(supportWeb: false) ||
isIOS(supportWeb: false) ||
isWeb()) {
if (isHttpBasedUrl(imageUrl)) {
return CachedNetworkImageProvider(
imageUrl,
);
}
}
return getImageProviderByImageSource(
imageUrl,
imageProviderBuilder: null,
assetsPrefix:
QuillSharedExtensionsConfigurations.get(
context: context)
.assetsPrefix,
);
},
),
),
builder: (context, rawEditor) {
// The `desktop_drop` plugin doesn't support iOS platform for now
if (isIOS(supportWeb: false)) {
return rawEditor;
}
_controller.insertImageBlock(
imageSource: file.path,
return DropTarget(
onDragDone: (details) {
final scaffoldMessenger =
ScaffoldMessenger.of(context);
final file = details.files.first;
final isSupported = imageFileExtensions
.any((ext) => file.name.endsWith(ext));
if (!isSupported) {
scaffoldMessenger.showText(
'Only images are supported right now: ${file.mimeType}, ${file.name}, ${file.path}, $imageFileExtensions',
);
return;
}
_controller.insertImageBlock(
imageSource: file.path,
);
scaffoldMessenger.showText('Image is inserted.');
},
child: rawEditor,
);
scaffoldMessenger.showText('Image is inserted.');
},
child: rawEditor,
);
},
),
),
),
),
);
},
),
],
),

@ -12,6 +12,7 @@ import gal
import pasteboard
import path_provider_foundation
import share_plus
import sqflite
import url_launcher_macos
import video_player_avfoundation
@ -23,6 +24,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
}

@ -22,6 +22,7 @@ dependencies:
path: ^1.8.3
equatable: ^2.0.5
cross_file: ^0.3.3+6
cached_network_image: ^3.3.0
# Bloc libraries
bloc: ^8.1.2

@ -32,6 +32,11 @@
<title>example</title>
<link rel="manifest" href="manifest.json">
<!-- Croppie for `image_cropper` plugin -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.5/croppie.css" />
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/exif-js/2.3.0/exif.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.5/croppie.min.js"></script>
<script>
// The value below is injected by flutter build, do not touch.
const serviceWorkerVersion = null;

@ -1,6 +1,6 @@
import 'package:flutter/cupertino.dart' show showCupertinoModalPopup;
import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart' show isDesktop, isMobile;
import 'package:flutter_quill/extensions.dart' show isMobile;
import 'package:flutter_quill/flutter_quill.dart'
show ImageUrl, QuillController, StyleAttribute, getEmbedNode;
import 'package:flutter_quill/translations.dart';

@ -101,6 +101,9 @@ class QuillEditorImageEmbedConfigurations {
///
final ImageEmbedBuilderErrorWidgetBuilder? imageErrorWidgetBuilder;
/// What should happen when the image is pressed?
///
/// By default will show `ImageOptionsMenu` dialog
final VoidCallback? onImageClicked;
static ImageEmbedBuilderOnRemovedCallback get defaultOnImageRemovedCallback {

Loading…
Cancel
Save