Step 7 of remaking the example

pull/1530/head
Ellet 1 year ago
parent 7f1b4bd699
commit ec44d81f7c
No known key found for this signature in database
GPG Key ID: C488CC70BBCEF0D1
  1. 45
      example/lib/presentation/quill/embeds/timestamp_embed.dart
  2. 26
      example/lib/presentation/quill/quill_editor.dart
  3. 61
      example/lib/presentation/quill/quill_toolbar.dart
  4. 15
      example/macos/Podfile.lock
  5. 2
      example/macos/Runner/DebugProfile.entitlements
  6. 2
      example/macos/Runner/Release.entitlements
  7. 2
      flutter_quill_extensions/lib/presentation/embeds/editor/image/image_menu.dart
  8. 16
      flutter_quill_extensions/lib/presentation/utils/utils.dart
  9. 6
      lib/src/utils/platform.dart

@ -0,0 +1,45 @@
import 'dart:convert' show jsonDecode, jsonEncode;
import 'package:flutter/material.dart' show Icons;
import 'package:flutter/widgets.dart';
import 'package:flutter_quill/flutter_quill.dart';
class TimeStampEmbed extends Embeddable {
const TimeStampEmbed(
String value,
) : super(timeStampType, value);
static const String timeStampType = 'timeStamp';
static TimeStampEmbed fromDocument(Document document) =>
TimeStampEmbed(jsonEncode(document.toDelta().toJson()));
Document get document => Document.fromJson(jsonDecode(data));
}
class TimeStampEmbedBuilderWidget extends EmbedBuilder {
@override
String get key => 'timeStamp';
@override
String toPlainText(Embed node) {
return node.value.data;
}
@override
Widget build(
BuildContext context,
QuillController controller,
Embed node,
bool readOnly,
bool inline,
TextStyle textStyle,
) {
return Row(
children: [
const Icon(Icons.access_time_rounded),
Text(node.value.data as String),
],
);
}
}

@ -1,3 +1,5 @@
import 'dart:io' as io show Directory, File;
import 'package:cached_network_image/cached_network_image.dart'
show CachedNetworkImageProvider;
import 'package:desktop_drop/desktop_drop.dart' show DropTarget;
@ -7,8 +9,10 @@ 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 getImageProviderByImageSource, imageFileExtensions;
import 'package:path/path.dart' as path;
import '../extensions/scaffold_messenger.dart';
import 'embeds/timestamp_embed.dart';
class MyQuillEditor extends StatelessWidget {
const MyQuillEditor({
@ -31,7 +35,23 @@ class MyQuillEditor extends StatelessWidget {
scrollable: true,
placeholder: 'Start writting your notes...',
padding: const EdgeInsets.all(16),
embedBuilders: isWeb()
onImagePaste: (imageBytes) async {
if (isWeb()) {
return null;
}
// We will save it to system temporary files
final newFileName = '${DateTime.now().toIso8601String()}.png';
final newPath = path.join(
io.Directory.systemTemp.path,
newFileName,
);
final file = await io.File(
newPath,
).writeAsBytes(imageBytes, flush: true);
return file.path;
},
embedBuilders: [
...(isWeb()
? FlutterQuillEmbeds.editorWebBuilders()
: FlutterQuillEmbeds.editorBuilders(
imageEmbedConfigurations: QuillEditorImageEmbedConfigurations(
@ -63,7 +83,9 @@ class MyQuillEditor extends StatelessWidget {
);
},
),
),
)),
TimeStampEmbedBuilderWidget(),
],
builder: (context, rawEditor) {
// The `desktop_drop` plugin doesn't support iOS platform for now
if (isIOS(supportWeb: false)) {

@ -12,6 +12,7 @@ import 'package:path_provider/path_provider.dart'
import '../extensions/scaffold_messenger.dart';
import '../settings/cubit/settings_cubit.dart';
import 'embeds/timestamp_embed.dart';
class MyQuillToolbar extends StatelessWidget {
const MyQuillToolbar({super.key});
@ -67,13 +68,19 @@ class MyQuillToolbar extends StatelessWidget {
controller.insertImageBlock(imageSource: newSavedImage);
}
/// Copies the picked file from temporary cache to applications directory
/// For mobile platforms it will copies the picked file from temporary cache
/// to applications directory
///
/// for desktop platforms, it will do the same but from user files this time
Future<String> saveImage(io.File file) async {
final appDocDir = await getApplicationDocumentsDirectory();
final copiedFile = await file.copy(path.join(
final fileExt = path.extension(file.path);
final newFileName = '${DateTime.now().toIso8601String()}$fileExt';
final newPath = path.join(
appDocDir.path,
'${DateTime.now().toIso8601String()}${path.extension(file.path)}',
));
newFileName,
);
final copiedFile = await file.copy(newPath);
return copiedFile.path;
}
@ -205,6 +212,52 @@ class MyQuillToolbar extends StatelessWidget {
return QuillToolbar(
configurations: QuillToolbarConfigurations(
customButtons: [
QuillToolbarCustomButtonOptions(
icon: const Icon(Icons.add_alarm_rounded),
onPressed: () {
final controller = context.requireQuillController;
controller.document
.insert(controller.selection.extentOffset, '\n');
controller.updateSelection(
TextSelection.collapsed(
offset: controller.selection.extentOffset + 1,
),
ChangeSource.local,
);
controller.document.insert(
controller.selection.extentOffset,
TimeStampEmbed(
DateTime.now().toString(),
),
);
controller.updateSelection(
TextSelection.collapsed(
offset: controller.selection.extentOffset + 1,
),
ChangeSource.local,
);
controller.document
.insert(controller.selection.extentOffset, ' ');
controller.updateSelection(
TextSelection.collapsed(
offset: controller.selection.extentOffset + 1,
),
ChangeSource.local,
);
controller.document
.insert(controller.selection.extentOffset, '\n');
controller.updateSelection(
TextSelection.collapsed(
offset: controller.selection.extentOffset + 1,
),
ChangeSource.local,
);
},
),
QuillToolbarCustomButtonOptions(
icon: const Icon(Icons.ac_unit),
onPressed: () {

@ -6,6 +6,9 @@ PODS:
- file_selector_macos (0.0.1):
- FlutterMacOS
- FlutterMacOS (1.0.0)
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- gal (1.0.0):
- Flutter
- FlutterMacOS
@ -16,6 +19,9 @@ PODS:
- FlutterMacOS
- share_plus (0.0.1):
- FlutterMacOS
- sqflite (0.0.2):
- FlutterMacOS
- FMDB (>= 2.7.5)
- url_launcher_macos (0.0.1):
- FlutterMacOS
- video_player_avfoundation (0.0.1):
@ -31,9 +37,14 @@ DEPENDENCIES:
- pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- video_player_avfoundation (from `Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin`)
SPEC REPOS:
trunk:
- FMDB
EXTERNAL SOURCES:
desktop_drop:
:path: Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos
@ -51,6 +62,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
share_plus:
:path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos
sqflite:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos
url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
video_player_avfoundation:
@ -61,10 +74,12 @@ SPEC CHECKSUMS:
device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f
file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
gal: 61e868295d28fe67ffa297fae6dacebf56fd53e1
pasteboard: 9b69dba6fedbb04866be632205d532fe2f6b1d99
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
share_plus: 76dd39142738f7a68dd57b05093b5e8193f220f7
sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
video_player_avfoundation: 8563f13d8fc8b2c29dc2d09e60b660e4e8128837

@ -12,5 +12,7 @@
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<!-- <key>com.apple.security.files.user-selected.read-write</key>
<true/> -->
</dict>
</plist>

@ -8,5 +8,7 @@
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<!-- <key>com.apple.security.files.user-selected.read-write</key>
<true/> -->
</dict>
</plist>

@ -142,7 +142,7 @@ class ImageOptionsMenu extends StatelessWidget {
imageUrl: imageSource,
imageSaverService: imageSaverService,
);
final imageSavedSuccessfully = saveImageResult.isSuccess;
final imageSavedSuccessfully = saveImageResult.error == null;
messenger.clearSnackBars();

@ -45,9 +45,9 @@ enum SaveImageResultMethod { network, localStorage }
@immutable
class SaveImageResult {
const SaveImageResult({required this.isSuccess, required this.method});
const SaveImageResult({required this.error, required this.method});
final bool isSuccess;
final String? error;
final SaveImageResultMethod method;
}
@ -67,12 +67,12 @@ Future<SaveImageResult> saveImage({
Uri.parse(appendFileExtensionToImageUrl(imageUrl)),
);
return const SaveImageResult(
isSuccess: true,
error: null,
method: SaveImageResultMethod.network,
);
} catch (e) {
return const SaveImageResult(
isSuccess: false,
return SaveImageResult(
error: e.toString(),
method: SaveImageResultMethod.network,
);
}
@ -80,12 +80,12 @@ Future<SaveImageResult> saveImage({
try {
await imageSaverService.saveLocalImage(imageUrl);
return const SaveImageResult(
isSuccess: true,
error: null,
method: SaveImageResultMethod.localStorage,
);
} catch (e) {
return const SaveImageResult(
isSuccess: false,
return SaveImageResult(
error: e.toString(),
method: SaveImageResultMethod.localStorage,
);
}

@ -2,10 +2,12 @@ import 'dart:io' show Platform;
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart'
show kIsWeb, TargetPlatform, defaultTargetPlatform;
show TargetPlatform, defaultTargetPlatform, kIsWeb, visibleForTesting;
/// If you want to override the [kIsWeb] use [overrideIsWeb]
bool isWeb({bool? overrideIsWeb}) {
bool isWeb({
@visibleForTesting bool? overrideIsWeb,
}) {
return overrideIsWeb ?? kIsWeb;
}

Loading…
Cancel
Save