From d978cac883c964317cae46ea01f23f7d26655d49 Mon Sep 17 00:00:00 2001 From: Luke Date: Wed, 19 Jun 2024 16:55:45 +0100 Subject: [PATCH 1/4] feat: Add selected date to calendar --- example/lib/pages/components/calendar.dart | 5 ++ lib/src/components/organisms/calendar.dart | 57 ++++++++++++++++++- lib/src/utils/localizations/untranslated.json | 4 +- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/example/lib/pages/components/calendar.dart b/example/lib/pages/components/calendar.dart index 5455aab..0ae889d 100644 --- a/example/lib/pages/components/calendar.dart +++ b/example/lib/pages/components/calendar.dart @@ -28,6 +28,7 @@ class _CalendarDemoState extends State { child: const Text('increase day')), ZdsCalendar( selectedDay: focusedDate, + showSelectedDateHeader: true, events: [ CalendarEvent(id: 'a', date: DateTime.now()), CalendarEvent(id: 'b', date: DateTime.now().subtract(const Duration(days: 1))), @@ -43,6 +44,7 @@ class _CalendarDemoState extends State { ), const SizedBox(height: 50), ZdsCalendar.monthly( + showSelectedDateHeader: true, isRangeSelectable: true, events: [ CalendarEvent(id: 'a', date: DateTime.now()), @@ -57,6 +59,7 @@ class _CalendarDemoState extends State { height: 50, ), ZdsCalendar.weekly( + showSelectedDateHeader: true, startingDayOfWeek: StartingDayOfWeek.thursday, initialSelectedDay: DateTime(currentDate.year, currentDate.month, currentDate.day + 1), events: [ @@ -75,6 +78,7 @@ class _CalendarDemoState extends State { const SizedBox(height: 50), ZdsCalendar.weekly( initialSelectedWeek: DateTime(2022, 09, 10), + showSelectedDateHeader: true, startingDayOfWeek: StartingDayOfWeek.wednesday, showAllButton: true, events: const [], @@ -88,6 +92,7 @@ class _CalendarDemoState extends State { ), const SizedBox(height: 50), ZdsCalendar.monthly( + showSelectedDateHeader: true, headerPadding: const EdgeInsets.fromLTRB(4, 14, 8, 14), events: [ CalendarEvent(id: 'a', date: DateTime.now()), diff --git a/lib/src/components/organisms/calendar.dart b/lib/src/components/organisms/calendar.dart index 629f245..3483949 100644 --- a/lib/src/components/organisms/calendar.dart +++ b/lib/src/components/organisms/calendar.dart @@ -62,6 +62,7 @@ class ZdsCalendar extends StatefulWidget { this.holidayEvents = const [], this.allCustomLabel, this.calendarRowHeight, + this.showSelectedDateHeader = false, this.previousTooltip, this.nextTooltip, }) : _variant = _ZdsCalendarVariant.switchable, @@ -97,6 +98,7 @@ class ZdsCalendar extends StatefulWidget { this.holidayEvents = const [], this.allCustomLabel, this.calendarRowHeight, + this.showSelectedDateHeader = false, this.previousTooltip, this.nextTooltip, }) : _variant = _ZdsCalendarVariant.monthly; @@ -130,6 +132,7 @@ class ZdsCalendar extends StatefulWidget { this.holidayEvents = const [], this.allCustomLabel, this.calendarRowHeight, + this.showSelectedDateHeader = false, this.previousTooltip, this.nextTooltip, }) : _variant = _ZdsCalendarVariant.weekly, @@ -166,6 +169,9 @@ class ZdsCalendar extends StatefulWidget { /// format switcher. To not show a format switcher, use [ZdsCalendar.monthly] instead. final bool hasHeader; + /// Whether the selected date in the header should be shown or not. + final bool showSelectedDateHeader; + /// List of icons to be shown at the beginning of selected weeks. /// /// Defaults to empty. @@ -300,7 +306,8 @@ class ZdsCalendar extends StatefulWidget { ..add(ColorProperty('calendarTextColor', calendarTextColor)) ..add(IterableProperty('holidayEvents', holidayEvents)) ..add(StringProperty('allCustomLabel', allCustomLabel)) - ..add(DoubleProperty('calendarRowHeight', calendarRowHeight)); + ..add(DoubleProperty('calendarRowHeight', calendarRowHeight)) + ..add(DiagnosticsProperty('showSelectedDateHeader', showSelectedDateHeader)); } } @@ -666,7 +673,11 @@ class _ZdsCalendarState extends State { ), ), ); - + final calendarHeaderWithDate = Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [_getSelectedDateHeaderRow(languageCode), calendarHeader], + ); final List weekNumbers = _focusedDay.getWeeksNumbersInMonth(startingDayOfWeek, _focusedDay); final List weekStartDays = () { DateTime firstDayOfWeeks = _focusedDay.startOfMonth.getFirstDayOfWeek(); @@ -744,7 +755,7 @@ class _ZdsCalendarState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - if (widget.hasHeader) calendarHeader, + if (widget.hasHeader) (widget.showSelectedDateHeader) ? calendarHeaderWithDate : calendarHeader, if (widget.showAllButton && context.isSmallScreen()) Row(children: [Expanded(child: allButton)]), AbsorbPointer( absorbing: !widget.enabled, @@ -824,6 +835,46 @@ class _ZdsCalendarState extends State { ); } + Widget _getSelectedDateHeaderRow(String languageCode) { + return Padding( + padding: widget.headerPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + (widget.isRangeSelectable) + ? ComponentStrings.of(context).get('SEL_DATE', 'Selected date') + : ComponentStrings.of(context).get('SEL_DATE_RANGE', 'Selected date range'), + style: TextStyle( + color: widget.calendarHeaderTextColor ?? Theme.of(context).colorScheme.onSurface, + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + if (widget.isRangeSelectable) + Text( + '${_rangeStart != null ? DateFormat.MMMEd(languageCode).format(_rangeStart!) : ''} ${_rangeStart != null ? '-' : ''} ${_rangeEnd != null ? DateFormat.MMMEd(languageCode).format(_rangeEnd!) : ''}', + style: TextStyle( + color: widget.calendarHeaderTextColor ?? Theme.of(context).colorScheme.onSurface, + fontSize: 24, + fontWeight: FontWeight.w500, + ), + ) + else + Text( + _selectedDay != null ? DateFormat.MMMEd(languageCode).format(_selectedDay!) : '', + style: TextStyle( + color: widget.calendarHeaderTextColor ?? Theme.of(context).colorScheme.onSurface, + fontSize: 24, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ); + } + String _getCurrentLocaleString(BuildContext context) { var currentLocale = const Locale('en', 'US'); try { diff --git a/lib/src/utils/localizations/untranslated.json b/lib/src/utils/localizations/untranslated.json index 5ea7701..93e725b 100644 --- a/lib/src/utils/localizations/untranslated.json +++ b/lib/src/utils/localizations/untranslated.json @@ -20,5 +20,7 @@ "EXPAND_MESSAGE_OPTIONS": "Expand message options", "SEND_MESSAGE": "Send message", "ADD_VOICE_NOTE": "Add voice note", - "ATTACHMENTS": "Attachments" + "ATTACHMENTS": "Attachments", + "SEL_DATE": "Selected date", + "SEL_DATE_RANGE": "Selected date range" } \ No newline at end of file From b8e62d2b99d742773e430cef5c4902d3786946b2 Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 20 Jun 2024 11:23:31 +0100 Subject: [PATCH 2/4] feat(TM-38113): Restructure Quill Editor --- example/.metadata | 25 +- .../pages/components/quill_editor_demo.dart | 52 +- .../Flutter/GeneratedPluginRegistrant.swift | 2 + example/macos/Podfile.lock | 7 + .../macos/Runner.xcodeproj/project.pbxproj | 109 ++-- example/pubspec.yaml | 1 + .../flutter/generated_plugin_registrant.cc | 3 + .../windows/flutter/generated_plugins.cmake | 1 + .../organisms/quill_editor/quill_editor.dart | 28 +- .../quill_editor/quill_editor_page.dart | 43 +- .../organisms/quill_editor/quill_toolbar.dart | 582 +++++++----------- 11 files changed, 397 insertions(+), 456 deletions(-) diff --git a/example/.metadata b/example/.metadata index 24a13c1..bb11ee0 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "bae5e49bc2a867403c43b2aae2de8f8c33b037e4" + revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49" channel: "stable" project_type: app @@ -13,26 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - base_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - - platform: android - create_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - base_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - - platform: ios - create_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - base_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - - platform: linux - create_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - base_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - platform: macos - create_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - base_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - - platform: web - create_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - base_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - - platform: windows - create_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - base_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 # User provided section diff --git a/example/lib/pages/components/quill_editor_demo.dart b/example/lib/pages/components/quill_editor_demo.dart index d2a7b3f..0a0d37a 100644 --- a/example/lib/pages/components/quill_editor_demo.dart +++ b/example/lib/pages/components/quill_editor_demo.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:flutter_quill/extensions.dart'; import 'package:flutter_quill/flutter_quill.dart'; import 'package:zds_flutter/zds_flutter.dart'; +import 'package:flutter_quill_extensions/flutter_quill_extensions.dart'; ///Example for htmlEditor class QuillEditorDemo extends StatefulWidget { @@ -17,7 +19,7 @@ class _QuillEditorDemoState extends State { void initState() { super.initState(); ZdsQuillDelta.fromHtml(''' -

H1 heading

H2 Heading

H3 Heading

Normal
Because

+

Google Doodles




Doodles celebrate a wide range of events, from national holidays like Independence Day and Christmas to special occasions like the anniversary of the first moon landing or the birth of significant figures in history such as Albert Einstein and Frida Kahlo.

''').then((value) { controller.document = value.document; }); @@ -32,17 +34,20 @@ class _QuillEditorDemoState extends State { IconButton( icon: const Icon(Icons.html), onPressed: () { + final html = ZdsQuillDelta(document: controller.document).toHtml(); showDialog( context: context, builder: (context) { return ConstrainedBox( - constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.7), - child: Dialog( - child: ZdsCard( - child: Text(ZdsQuillDelta(document: controller.document).toHtml()), - ), - ), - ); + constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.7), + child: Dialog( + child: SingleChildScrollView( + child: Column( + children: [ + Text(html), + ], + ), + ))); }, ); }, @@ -55,8 +60,20 @@ class _QuillEditorDemoState extends State { ZdsQuillEditorPage.edit( context, title: 'Edit Notes', + embedBuilders: getEmbedBuilders(), initialDelta: ZdsQuillDelta(document: controller.document), charLimit: 20000, + embedButtons: FlutterQuillEmbeds.toolbarButtons( + videoButtonOptions: null, + imageButtonOptions: QuillToolbarImageButtonOptions( + imageButtonConfigurations: QuillToolbarImageConfigurations( + onImageInsertCallback: (image, controller) async { + // Upload to cloud + controller.insertImageBlock(imageSource: image); + }, + ), + ), + ), ).then((value) { if (value != null) { controller.document = value.document; @@ -67,11 +84,11 @@ class _QuillEditorDemoState extends State { body: Column( children: [ Expanded( - child: QuillEditor.basic( - configurations: QuillEditorConfigurations( - padding: const EdgeInsets.all(16), - controller: controller, - ), + child: ZdsQuillEditor( + controller: controller, + readOnly: true, + padding: const EdgeInsets.all(16), + embedBuilders: getEmbedBuilders(), focusNode: FocusNode(canRequestFocus: false), ), ), @@ -80,3 +97,12 @@ class _QuillEditorDemoState extends State { ); } } + +/// default embed builders +List getEmbedBuilders() { + if (isWeb()) { + return FlutterQuillEmbeds.editorWebBuilders(); + } else { + return FlutterQuillEmbeds.editorBuilders(); + } +} diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 234103a..a235c3b 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -10,6 +10,7 @@ import device_info_plus import file_selector_macos import flutter_image_compress_macos import flutter_inappwebview_macos +import gal import irondash_engine_context import just_audio import package_info_plus @@ -30,6 +31,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin")) InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) + GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin")) IrondashEngineContextPlugin.register(with: registry.registrar(forPlugin: "IrondashEngineContextPlugin")) JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index 2f3ddb8..4f33dd6 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -11,6 +11,9 @@ PODS: - FlutterMacOS - OrderedSet (~> 5.0) - FlutterMacOS (1.0.0) + - gal (1.0.0): + - Flutter + - FlutterMacOS - irondash_engine_context (0.0.1): - FlutterMacOS - just_audio (0.0.1): @@ -51,6 +54,7 @@ DEPENDENCIES: - flutter_image_compress_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_image_compress_macos/macos`) - flutter_inappwebview_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos`) - FlutterMacOS (from `Flutter/ephemeral`) + - gal (from `Flutter/ephemeral/.symlinks/plugins/gal/darwin`) - irondash_engine_context (from `Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos`) - just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/macos`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) @@ -82,6 +86,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos FlutterMacOS: :path: Flutter/ephemeral + gal: + :path: Flutter/ephemeral/.symlinks/plugins/gal/darwin irondash_engine_context: :path: Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos just_audio: @@ -116,6 +122,7 @@ SPEC CHECKSUMS: flutter_image_compress_macos: c26c3c13ea0f28ae6dea4e139b3292e7729f99f1 flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + gal: 61e868295d28fe67ffa297fae6dacebf56fd53e1 irondash_engine_context: da62996ee25616d2f01bbeb85dc115d813359478 just_audio: 9b67ca7b97c61cfc9784ea23cd8cc55eb226d489 OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index f05c8b0..cd11472 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -27,8 +27,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - DED17EA2623B45339748C1E4 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04F34FD62F4639D3DEBA2C55 /* Pods_Runner.framework */; }; - E03A1C663F26CB8BB8648761 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9CC9C3CCF6C6E78043FA63F /* Pods_RunnerTests.framework */; }; + 629BE838518FE69DEB9EBE2A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80BC3FD0BA113E1D54F62451 /* Pods_Runner.framework */; }; + 63FBD6C2E8C3F4C60AB19FBD /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F3E0D49B5FFB521E84C21C2 /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -62,8 +62,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 04F34FD62F4639D3DEBA2C55 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 22BBD49CF1B1A2BA48345085 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 0F3E0D49B5FFB521E84C21C2 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 2FDECF0E4FFA7411FB7A0FF4 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; @@ -80,14 +80,14 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 75F38E831AFE0D726A97BC42 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 398AEEEAE77D5B43149E61CA /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 80BC3FD0BA113E1D54F62451 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8B7E92B3CF7B57F90423AEF3 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - C8A96B62E1A0E9A31FCF1EE7 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - D0210F67B62574C34C5455D6 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - D9CC9C3CCF6C6E78043FA63F /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - E461359B444E3B1D8645B4D2 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - EDCB226C6A202F3F5B6D3173 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + A615EEB51A170533949683FB /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + AEBE20C4B0FEE170F4413693 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + E95373656C5F388D5692C03E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -95,7 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E03A1C663F26CB8BB8648761 /* Pods_RunnerTests.framework in Frameworks */, + 63FBD6C2E8C3F4C60AB19FBD /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -103,7 +103,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DED17EA2623B45339748C1E4 /* Pods_Runner.framework in Frameworks */, + 629BE838518FE69DEB9EBE2A /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -137,7 +137,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, - C37951C4EB49C2FF6EF5E2D8 /* Pods */, + 6B16353B9435601C0A53A529 /* Pods */, ); sourceTree = ""; }; @@ -185,24 +185,25 @@ path = Runner; sourceTree = ""; }; - C37951C4EB49C2FF6EF5E2D8 /* Pods */ = { + 6B16353B9435601C0A53A529 /* Pods */ = { isa = PBXGroup; children = ( - 75F38E831AFE0D726A97BC42 /* Pods-Runner.debug.xcconfig */, - EDCB226C6A202F3F5B6D3173 /* Pods-Runner.release.xcconfig */, - C8A96B62E1A0E9A31FCF1EE7 /* Pods-Runner.profile.xcconfig */, - 22BBD49CF1B1A2BA48345085 /* Pods-RunnerTests.debug.xcconfig */, - E461359B444E3B1D8645B4D2 /* Pods-RunnerTests.release.xcconfig */, - D0210F67B62574C34C5455D6 /* Pods-RunnerTests.profile.xcconfig */, - ); + 2FDECF0E4FFA7411FB7A0FF4 /* Pods-Runner.debug.xcconfig */, + 398AEEEAE77D5B43149E61CA /* Pods-Runner.release.xcconfig */, + E95373656C5F388D5692C03E /* Pods-Runner.profile.xcconfig */, + AEBE20C4B0FEE170F4413693 /* Pods-RunnerTests.debug.xcconfig */, + 8B7E92B3CF7B57F90423AEF3 /* Pods-RunnerTests.release.xcconfig */, + A615EEB51A170533949683FB /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; path = Pods; sourceTree = ""; }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( - 04F34FD62F4639D3DEBA2C55 /* Pods_Runner.framework */, - D9CC9C3CCF6C6E78043FA63F /* Pods_RunnerTests.framework */, + 80BC3FD0BA113E1D54F62451 /* Pods_Runner.framework */, + 0F3E0D49B5FFB521E84C21C2 /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -214,7 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 25E3994526C60699016CB03F /* [CP] Check Pods Manifest.lock */, + FEEDDDAC1C1F79C8AF7735E2 /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -233,13 +234,13 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 78B83200B0A1F2814B344AEB /* [CP] Check Pods Manifest.lock */, + 3018F783528E68B1519AB6BF /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, - 99E3080A002E2AF4A93D1860 /* [CP] Embed Pods Frameworks */, + B9195979AE9F69D4C9055829 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -257,6 +258,7 @@ 33CC10E52044A3C60003C045 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; @@ -321,7 +323,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 25E3994526C60699016CB03F /* [CP] Check Pods Manifest.lock */ = { + 3018F783528E68B1519AB6BF /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -336,7 +338,7 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -381,43 +383,43 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; - 78B83200B0A1F2814B344AEB /* [CP] Check Pods Manifest.lock */ = { + B9195979AE9F69D4C9055829 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 99E3080A002E2AF4A93D1860 /* [CP] Embed Pods Frameworks */ = { + FEEDDDAC1C1F79C8AF7735E2 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -471,7 +473,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 22BBD49CF1B1A2BA48345085 /* Pods-RunnerTests.debug.xcconfig */; + baseConfigurationReference = AEBE20C4B0FEE170F4413693 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -486,7 +488,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E461359B444E3B1D8645B4D2 /* Pods-RunnerTests.release.xcconfig */; + baseConfigurationReference = 8B7E92B3CF7B57F90423AEF3 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -501,7 +503,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D0210F67B62574C34C5455D6 /* Pods-RunnerTests.profile.xcconfig */; + baseConfigurationReference = A615EEB51A170533949683FB /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -519,6 +521,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -542,10 +545,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - EXCLUDED_ARCHS = arm64; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -570,7 +574,6 @@ CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - EXCLUDED_ARCHS = arm64; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -594,6 +597,7 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -617,10 +621,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - EXCLUDED_ARCHS = arm64; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -648,6 +653,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -671,10 +677,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - EXCLUDED_ARCHS = arm64; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -699,7 +706,6 @@ CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - EXCLUDED_ARCHS = arm64; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -720,7 +726,6 @@ CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - EXCLUDED_ARCHS = arm64; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/example/pubspec.yaml b/example/pubspec.yaml index f64d2c5..835de8e 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -24,6 +24,7 @@ dependencies: cross_file: ^0.3.3+8 zeta_flutter: any intl: any + flutter_quill_extensions: ^9.4.4 flutter: uses-material-design: true diff --git a/example/windows/flutter/generated_plugin_registrant.cc b/example/windows/flutter/generated_plugin_registrant.cc index 3fa5b68..68b7c0a 100644 --- a/example/windows/flutter/generated_plugin_registrant.cc +++ b/example/windows/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -17,6 +18,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); + GalPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("GalPluginCApi")); IrondashEngineContextPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("IrondashEngineContextPluginCApi")); PermissionHandlerWindowsPluginRegisterWithRegistrar( diff --git a/example/windows/flutter/generated_plugins.cmake b/example/windows/flutter/generated_plugins.cmake index 0d95c61..b13dd52 100644 --- a/example/windows/flutter/generated_plugins.cmake +++ b/example/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows + gal irondash_engine_context permission_handler_windows record_windows diff --git a/lib/src/components/organisms/quill_editor/quill_editor.dart b/lib/src/components/organisms/quill_editor/quill_editor.dart index e25e6db..017d83d 100644 --- a/lib/src/components/organisms/quill_editor/quill_editor.dart +++ b/lib/src/components/organisms/quill_editor/quill_editor.dart @@ -1,7 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_quill/flutter_quill.dart'; - import '../../../../zds_flutter.dart'; import 'quill_toolbar.dart'; @@ -26,6 +25,7 @@ class ZdsQuillEditor extends StatelessWidget { this.placeholder, this.editorKey, this.toolbarColor, + this.embedButtons, super.key, }); @@ -50,6 +50,9 @@ class ZdsQuillEditor extends StatelessWidget { /// Custom embed builders, for example for image or video embedding. final Iterable? embedBuilders; + /// Toolbar items to display for controls of embed blocks. + final List? embedButtons; + /// The appearance style of the keyboard, can be either dark or light. final Brightness? keyboardAppearance; @@ -78,6 +81,7 @@ class ZdsQuillEditor extends StatelessWidget { Widget build(BuildContext context) { // Base editor configuration final editor = QuillEditor.basic( + focusNode: readOnly ? FocusNode(canRequestFocus: false) : focusNode, configurations: QuillEditorConfigurations( controller: controller, keyboardAppearance: keyboardAppearance ?? Brightness.light, @@ -88,7 +92,6 @@ class ZdsQuillEditor extends StatelessWidget { placeholder: placeholder, editorKey: editorKey, ), - focusNode: readOnly ? FocusNode(canRequestFocus: false) : focusNode, ); // If readOnly, return just editor @@ -97,23 +100,25 @@ class ZdsQuillEditor extends StatelessWidget { // If not readOnly, wrap the editor in a column with the toolbar return Column( children: [ - if (quillToolbarPosition == QuillToolbarPosition.top) _buildToolbar(context, QuillToolbarPosition.top), + if (quillToolbarPosition == QuillToolbarPosition.top) + _buildToolbar(context, QuillToolbarPosition.top, embedButtons), Expanded(child: editor), - if (quillToolbarPosition == QuillToolbarPosition.bottom) _buildToolbar(context, QuillToolbarPosition.bottom), + if (quillToolbarPosition == QuillToolbarPosition.bottom) + _buildToolbar(context, QuillToolbarPosition.bottom, embedButtons), ], ); } /// Constructs the toolbar for the Quill editor. - Widget _buildToolbar(BuildContext context, QuillToolbarPosition position) { - return ZdsQuillToolbar.custom( + Widget _buildToolbar(BuildContext context, QuillToolbarPosition position, List? embedButtons) { + return ZdsQuillToolbar.basic( context: context, controller: controller, - toolbarOptions: toolbarOptions.isNotEmpty ? toolbarOptions : QuillToolbarOption.values.toSet(), + color: toolbarColor, + position: position, + embedButtons: embedButtons, toolbarIconSize: toolbarIconSize, - langCode: langCode, - toolbarColor: toolbarColor, - quillToolbarPosition: position, + toolbarOptions: toolbarOptions.isNotEmpty ? toolbarOptions : QuillToolbarOption.values.toSet(), ); } @@ -135,6 +140,7 @@ class ZdsQuillEditor extends StatelessWidget { ..add(DiagnosticsProperty('focusNode', focusNode)) ..add(StringProperty('placeholder', placeholder)) ..add(ColorProperty('toolbarColor', toolbarColor)) - ..add(DiagnosticsProperty?>('editorKey', editorKey)); + ..add(DiagnosticsProperty?>('editorKey', editorKey)) + ..add(IterableProperty('embedButtons', embedButtons)); } } diff --git a/lib/src/components/organisms/quill_editor/quill_editor_page.dart b/lib/src/components/organisms/quill_editor/quill_editor_page.dart index 3b3166c..2740fe1 100644 --- a/lib/src/components/organisms/quill_editor/quill_editor_page.dart +++ b/lib/src/components/organisms/quill_editor/quill_editor_page.dart @@ -28,6 +28,8 @@ class ZdsQuillEditorPage extends StatefulWidget { this.charLimit = 10000, this.placeholder = '', this.initialDelta, + this.embedBuilders, + this.embedButtons, }); /// The title displayed in the editor's AppBar. @@ -62,6 +64,12 @@ class ZdsQuillEditorPage extends StatefulWidget { /// Defaults to true. final bool showClearFormatAsFloating; + ///EmbedBuilders for image and video support + final List? embedBuilders; + + /// Toolbar items to display for controls of embed blocks. + final List? embedButtons; + /// Navigates to the editor page for creating or editing content. /// /// Returns a [ZdsQuillDelta] representing the edited content or null if the user cancels the operation. @@ -78,6 +86,8 @@ class ZdsQuillEditorPage extends StatefulWidget { bool showClearFormatAsFloating = true, Set? toolbarOptions, QuillToolbarPosition? quillToolbarPosition = QuillToolbarPosition.bottom, + List? embedBuilders, + List? embedButtons, }) { return Navigator.of(context).push( MaterialPageRoute( @@ -87,13 +97,15 @@ class ZdsQuillEditorPage extends StatefulWidget { title: title, readOnly: readOnly, charLimit: charLimit, + embedButtons: embedButtons, placeholder: placeholder, toolbarIconSize: toolbarIconSize, quillToolbarPosition: quillToolbarPosition, showClearFormatAsFloating: showClearFormatAsFloating, toolbarOptions: toolbarOptions ?? zdsQuillToolbarOptions, - langCode: langCode ?? ComponentStrings.of(context).locale.toString(), + langCode: langCode, initialDelta: initialDelta?.copyWith(document: initialDelta.document), + embedBuilders: embedBuilders, ); }, ), @@ -101,7 +113,7 @@ class ZdsQuillEditorPage extends StatefulWidget { } @override - State createState() => _ZdsQuillEditorState(); + State createState() => _ZdsQuillEditorPageState(); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { @@ -116,11 +128,13 @@ class ZdsQuillEditorPage extends StatefulWidget { ..add(DiagnosticsProperty('initialDelta', initialDelta)) ..add(StringProperty('placeholder', placeholder)) ..add(IterableProperty('toolbarOptions', toolbarOptions)) - ..add(DiagnosticsProperty('showClearFormatAsFloating', showClearFormatAsFloating)); + ..add(DiagnosticsProperty('showClearFormatAsFloating', showClearFormatAsFloating)) + ..add(IterableProperty('embedBuilders', embedBuilders)) + ..add(IterableProperty('embedButtons', embedButtons)); } } -class _ZdsQuillEditorState extends State with FrameCallbackMixin { +class _ZdsQuillEditorPageState extends State with FrameCallbackMixin { /// Builder for handling uncaught Flutter errors in the widget. ErrorWidgetBuilder? _originalErrorWidgetBuilder; @@ -178,6 +192,17 @@ class _ZdsQuillEditorState extends State with FrameCallbackM }); } + bool _showingLoading = false; + + bool get showingLoading => _showingLoading; + + set showingLoading(bool value) { + if (_showingLoading == value) return; + setState(() { + _showingLoading = value; + }); + } + int __characters = 0; int get _characters => __characters; @@ -382,8 +407,9 @@ class _ZdsQuillEditorState extends State with FrameCallbackM toolbarColor: Theme.of(context).colorScheme.surface, toolbarOptions: {...widget.toolbarOptions} ..remove(QuillToolbarOption.redo) - ..remove(QuillToolbarOption.undo) - ..remove(QuillToolbarOption.clearFormat), + ..remove(QuillToolbarOption.undo), + embedBuilders: widget.embedBuilders, + embedButtons: widget.embedButtons, ); } @@ -417,7 +443,7 @@ class _ZdsQuillEditorState extends State with FrameCallbackM AnimatedOpacity( duration: const Duration(milliseconds: 250), opacity: _withinLimit ? 1.0 : 0.3, - child: _fetchingText ? _buildProgressIndicator(context) : _buildSaveButton(context), + child: (_fetchingText || _showingLoading) ? _buildProgressIndicator(context) : _buildSaveButton(context), ), ], ); @@ -500,7 +526,8 @@ class _ZdsQuillEditorState extends State with FrameCallbackM properties ..add(DiagnosticsProperty('showingHtmlError', showingHtmlError)) ..add(DiagnosticsProperty('showClear', showClear)) - ..add(DiagnosticsProperty('showClearPill', showClearPill)); + ..add(DiagnosticsProperty('showClearPill', showClearPill)) + ..add(DiagnosticsProperty('showingLoading', showingLoading)); } } diff --git a/lib/src/components/organisms/quill_editor/quill_toolbar.dart b/lib/src/components/organisms/quill_editor/quill_toolbar.dart index 4487423..8dd5aad 100644 --- a/lib/src/components/organisms/quill_editor/quill_toolbar.dart +++ b/lib/src/components/organisms/quill_editor/quill_toolbar.dart @@ -1,4 +1,5 @@ // ignore_for_file: implementation_imports + import 'package:flutter/material.dart'; import 'package:flutter_quill/flutter_quill.dart'; import 'package:flutter_quill/src/widgets/toolbar/buttons/alignment/select_alignment_buttons.dart'; @@ -20,159 +21,97 @@ enum QuillToolbarPosition { } /// toolbar options +/// Enum representing the various options available in the Quill toolbar. enum QuillToolbarOption { - ///undo + /// Option to undo the last action. undo, - ///redo + /// Option to redo the last undone action. redo, - ///bold + /// Option to apply bold formatting to the selected text. bold, - ///italic + /// Option to apply italic formatting to the selected text. italic, - ///underline + /// Option to apply underline formatting to the selected text. underline, - ///strikeThrough + /// Option to apply strikethrough formatting to the selected text. strikeThrough, - ///Show small button + /// Option to show a small button on the toolbar. smallButton, - ///textColor + /// Option to change the color of the selected text. textColor, - ///backgroundColor + /// Option to change the background color of the selected text. backgroundColor, - ///clearFormat + /// Option to clear all formatting from the selected text. clearFormat, - ///inlineCode + /// Option to apply inline code formatting to the selected text. inlineCode, - ///alignmentButtons - alignmentButtons, - - ///headers + /// Option to apply header styles to the selected text. headers, - ///numberList + /// Option to create a numbered list. numberList, - ///bullets + /// Option to create a bulleted list. bullets, - ///checkBox + /// Option to add a checkbox to the text. checkBox, - ///codeBlock + /// Option to create a code block. codeBlock, - ///indentation - indentation, - - ///quotes + /// Option to apply blockquote formatting to the selected text. quotes, - ///link + /// Option to add a hyperlink to the selected text. link, -} - -/// Options for Toolbar buttons -enum ToolbarButtons { - /// Quill undo button. - undo, - - /// Quill redo button. - redo, - - /// Quill fontFamily button. - fontFamily, - - /// Quill fontSize button. - fontSize, - /// Quill bold button. - bold, - - /// Quill subscript button. + /// Option to apply subscript formatting to the selected text. subscript, - /// Quill superscript button. + /// Option to apply superscript formatting to the selected text. superscript, - /// Quill italic button. - italic, - - /// Quill small button. + /// Option to apply small text formatting to the selected text. small, - /// Quill underline button. - underline, - - /// Quill strikeThrough button. - strikeThrough, - - /// Quill inlineCode button. - inlineCode, - - /// Quill color button. + /// Option to change the text color. color, - /// Quill backgroundColor button. - backgroundColor, - - /// Quill clearFormat button. - clearFormat, - - /// Quill centerAlignment button. + /// Option to align the text to the center. centerAlignment, - /// Quill leftAlignment button. + /// Option to align the text to the left. leftAlignment, - /// Quill rightAlignment button. + /// Option to align the text to the right. rightAlignment, - /// Quill justifyAlignment button. + /// Option to justify the text alignment. justifyAlignment, - /// Quill direction button. + /// Option to change the text direction. direction, - /// Quill headerStyle button. + /// Option to apply header styles to the selected text. headerStyle, - /// Quill listNumbers button. - listNumbers, - - /// Quill listBullets button. - listBullets, - - /// Quill listChecks button. - listChecks, - - /// Quill codeBlock button. - codeBlock, - - /// Quill quote button. - quote, - - /// Quill indentIncrease button. + /// Option to increase the indentation of the selected text. indentIncrease, - /// Quill indentDecrease button. + /// Option to decrease the indentation of the selected text. indentDecrease, - - /// Quill link button. - link, - - /// Quill search button. - search, } /// The default size of the icon of a button. @@ -188,154 +127,130 @@ const double kToolbarSectionSpacing = 4; class ZdsQuillToolbar extends QuillToolbar { ///Constructor - const ZdsQuillToolbar({ + const ZdsQuillToolbar._({ super.configurations, required super.child, super.key, }) : super(); - /// Custom constructor for [ZdsQuillToolbar] - factory ZdsQuillToolbar.custom({ - required BuildContext context, - required QuillController controller, - required Set toolbarOptions, - QuillToolbarPosition quillToolbarPosition = QuillToolbarPosition.bottom, - double? toolbarIconSize, - String? langCode, - Color? toolbarColor, - }) { - final ColorScheme colorScheme = Theme.of(context).colorScheme; - final Color effectiveToolbarColor = toolbarColor ?? colorScheme.surface; - return ZdsQuillToolbar.basic( - context: context, - toolbarIconSize: toolbarIconSize ?? kDefaultIconSize, - controller: controller, - color: effectiveToolbarColor, - quillToolbarPosition: quillToolbarPosition, - locale: (langCode?.isNotEmpty ?? false) ? Locale(langCode!.substring(0, 2)) : null, - showUndo: toolbarOptions.contains(QuillToolbarOption.undo), - showRedo: toolbarOptions.contains(QuillToolbarOption.redo), - showBoldButton: toolbarOptions.contains(QuillToolbarOption.bold), - showItalicButton: toolbarOptions.contains(QuillToolbarOption.italic), - showUnderLineButton: toolbarOptions.contains(QuillToolbarOption.underline), - showStrikeThrough: toolbarOptions.contains(QuillToolbarOption.strikeThrough), - showSmallButton: toolbarOptions.contains(QuillToolbarOption.smallButton), - showColorButton: toolbarOptions.contains(QuillToolbarOption.textColor), - showCodeBlock: toolbarOptions.contains(QuillToolbarOption.codeBlock), - showBackgroundColorButton: toolbarOptions.contains(QuillToolbarOption.backgroundColor), - showClearFormat: toolbarOptions.contains(QuillToolbarOption.clearFormat), - showInlineCode: toolbarOptions.contains(QuillToolbarOption.inlineCode), - showAlignmentButtons: toolbarOptions.contains(QuillToolbarOption.alignmentButtons), - showHeaderStyle: toolbarOptions.contains(QuillToolbarOption.headers), - showListNumbers: toolbarOptions.contains(QuillToolbarOption.numberList), - showListBullets: toolbarOptions.contains(QuillToolbarOption.bullets), - showListCheck: toolbarOptions.contains(QuillToolbarOption.checkBox), - showIndent: toolbarOptions.contains(QuillToolbarOption.indentation), - showQuote: toolbarOptions.contains(QuillToolbarOption.quotes), - showLink: toolbarOptions.contains(QuillToolbarOption.link), - showSubscript: false, - showSuperscript: false, - showSearchButton: false, - multiRowsDisplay: false, - iconTheme: QuillIconTheme( - iconButtonUnselectedData: IconButtonData( - color: effectiveToolbarColor.onColor, - ), - iconButtonSelectedData: IconButtonData( - color: colorScheme.secondary, - ), - ), - ); - } - /// Basic constructor for ZdsQuillToolbar + /// Basic constructor for ZdsQuillToolbar. factory ZdsQuillToolbar.basic({ + /// The [BuildContext] in which the toolbar will be built. required BuildContext context, + + /// The [QuillController] that controls the Quill editor. required QuillController controller, + + /// The set of options to be displayed in the toolbar. + required Set toolbarOptions, + + /// The key for the toolbar. + Key? key, + + /// The position of the toolbar, defaults to [QuillToolbarPosition.bottom]. + QuillToolbarPosition position = QuillToolbarPosition.bottom, + + /// The axis of the toolbar, defaults to [Axis.horizontal]. Axis axis = Axis.horizontal, - double toolbarIconSize = kDefaultIconSize, + + /// The size of the icons in the toolbar. + double? toolbarIconSize, + + /// The spacing between sections in the toolbar, defaults to [kToolbarSectionSpacing]. double toolbarSectionSpacing = kToolbarSectionSpacing, - WrapAlignment toolbarIconAlignment = WrapAlignment.center, - WrapCrossAlignment toolbarIconCrossAlignment = WrapCrossAlignment.center, - bool multiRowsDisplay = true, + + /// Whether to show dividers between toolbar sections, defaults to true. bool showDividers = true, - bool showBoldButton = true, - bool showItalicButton = true, - bool showSmallButton = false, - bool showUnderLineButton = true, - bool showStrikeThrough = true, - bool showInlineCode = true, - bool showColorButton = true, - bool showCodeBlock = true, - bool showBackgroundColorButton = true, - bool showClearFormat = true, - bool showAlignmentButtons = false, - bool showLeftAlignment = true, - bool showCenterAlignment = true, - bool showRightAlignment = true, - bool showJustifyAlignment = true, - bool showHeaderStyle = true, - bool showListNumbers = true, - bool showListBullets = true, - bool showListCheck = true, - bool showQuote = true, - bool showIndent = true, - bool showLink = true, - bool showUndo = true, - bool showRedo = true, - bool showDirection = false, - bool showSearchButton = true, - bool showSubscript = true, - bool showSuperscript = true, - QuillToolbarPosition quillToolbarPosition = QuillToolbarPosition.bottom, + + /// Custom buttons to be added to the toolbar. List customButtons = const [], - /// Toolbar items to display for controls of embed blocks + /// Toolbar items to display for controls of embed blocks. List? embedButtons, - ///The theme to use for the icons in the toolbar, uses type [QuillIconTheme] + /// The theme to use for the icons in the toolbar, uses type [QuillIconTheme]. QuillIconTheme? iconTheme, - ///The theme to use for the theming of the [LinkDialog()], - ///shown when embedding an image, for example + /// The theme to use for the theming of the [LinkDialog()], shown when embedding an image, for example. QuillDialogTheme? dialogTheme, /// Callback to be called after any button on the toolbar is pressed. /// Is called after whatever logic the button performs has run. VoidCallback? afterButtonPressed, - ///Map of tooltips for toolbar buttons + /// Map of tooltips for toolbar buttons. /// - ///The example is: - ///```dart + /// The example is: + /// ```dart /// tooltips = { /// ToolbarButtons.undo: 'Undo', /// ToolbarButtons.redo: 'Redo', /// } + /// ``` /// - ///``` - /// - /// To disable tooltips just pass empty map as well. - Map? tooltips, + /// To disable tooltips just pass an empty map as well. + Map? tooltips, - /// The locale to use for the editor toolbar, defaults to system locale + /// The locale to use for the editor toolbar, defaults to system locale. /// More at https://github.com/singerdmx/flutter-quill#translation Locale? locale, - /// The color of the toolbar + /// The color of the toolbar. Color? color, - /// The color of the toolbar section divider + /// The color of the toolbar section divider. Color? sectionDividerColor, - /// The space occupied by toolbar divider + /// The space occupied by the toolbar divider. double? sectionDividerSpace, - /// Validate the legitimacy of hyperlinks + /// Regular expression to validate the legitimacy of hyperlinks. RegExp? linkRegExp, + + /// Action to be performed for the link dialog. LinkDialogAction? linkDialogAction, - Key? key, }) { + final showUndo = toolbarOptions.contains(QuillToolbarOption.undo); + final showRedo = toolbarOptions.contains(QuillToolbarOption.redo); + final showBoldButton = toolbarOptions.contains(QuillToolbarOption.bold); + final showItalicButton = toolbarOptions.contains(QuillToolbarOption.italic); + final showUnderLineButton = toolbarOptions.contains(QuillToolbarOption.underline); + final showStrikeThrough = toolbarOptions.contains(QuillToolbarOption.strikeThrough); + final showSmallButton = toolbarOptions.contains(QuillToolbarOption.smallButton); + final showColorButton = toolbarOptions.contains(QuillToolbarOption.textColor); + final showCodeBlock = toolbarOptions.contains(QuillToolbarOption.codeBlock); + final showBackgroundColorButton = toolbarOptions.contains(QuillToolbarOption.backgroundColor); + final showClearFormat = toolbarOptions.contains(QuillToolbarOption.clearFormat); + final showInlineCode = toolbarOptions.contains(QuillToolbarOption.inlineCode); + final showIndentDecrease = toolbarOptions.contains(QuillToolbarOption.indentDecrease); + final showIndentIncrease = toolbarOptions.contains(QuillToolbarOption.indentIncrease); + final showHeaderStyle = toolbarOptions.contains(QuillToolbarOption.headers); + final showListNumbers = toolbarOptions.contains(QuillToolbarOption.numberList); + final showListBullets = toolbarOptions.contains(QuillToolbarOption.bullets); + final showListCheck = toolbarOptions.contains(QuillToolbarOption.checkBox); + final showQuote = toolbarOptions.contains(QuillToolbarOption.quotes); + final showLink = toolbarOptions.contains(QuillToolbarOption.link); + + final showLeftAlignment = toolbarOptions.contains(QuillToolbarOption.leftAlignment); + final showCenterAlignment = toolbarOptions.contains(QuillToolbarOption.centerAlignment); + final showRightAlignment = toolbarOptions.contains(QuillToolbarOption.rightAlignment); + final showJustifyAlignment = toolbarOptions.contains(QuillToolbarOption.justifyAlignment); + final showAlignmentButtons = showLeftAlignment || showCenterAlignment || showRightAlignment || showJustifyAlignment; + + final showDirection = toolbarOptions.contains(QuillToolbarOption.direction); + final showSubscript = toolbarOptions.contains(QuillToolbarOption.subscript); + final showSuperscript = toolbarOptions.contains(QuillToolbarOption.superscript); + + final ColorScheme colorScheme = Theme.of(context).colorScheme; + final effectiveColor = color ?? colorScheme.surface; + final effectiveIconSize = toolbarIconSize ?? kDefaultIconSize; + final effectiveIconTheme = iconTheme ?? + QuillIconTheme( + iconButtonUnselectedData: IconButtonData(color: effectiveColor.onColor), + iconButtonSelectedData: IconButtonData(color: colorScheme.secondary), + ); + final List isButtonGroupShown = [ showBoldButton || showItalicButton || @@ -350,83 +265,62 @@ class ZdsQuillToolbar extends QuillToolbar { showLeftAlignment || showCenterAlignment || showRightAlignment || showJustifyAlignment || showDirection, showHeaderStyle, showListNumbers || showListBullets || showListCheck, - showQuote || showIndent, - showLink || showSearchButton, + showQuote || showIndentDecrease || showIndentIncrease, + showLink, ]; - final componentString = ComponentStrings.of(context); - final configurations = QuillSimpleToolbarConfigurations( - controller: controller, - axis: axis, - toolbarSize: toolbarIconSize * 3, - color: color, - toolbarSectionSpacing: toolbarSectionSpacing, - toolbarIconAlignment: toolbarIconAlignment, - toolbarIconCrossAlignment: toolbarIconCrossAlignment, - multiRowsDisplay: multiRowsDisplay, - ); - iconTheme ??= QuillIconTheme( - iconButtonSelectedData: IconButtonData( - iconSize: toolbarIconSize, - alignment: Alignment.topCenter, - ), - iconButtonUnselectedData: IconButtonData(iconSize: toolbarIconSize), - ); - - return ZdsQuillToolbar( + final strings = ComponentStrings.of(context); + return ZdsQuillToolbar._( configurations: QuillToolbarConfigurations( sharedConfigurations: QuillSharedConfigurations( - locale: locale, + locale: locale ?? strings.locale, ), ), key: key, child: TooltipTheme( - data: TooltipThemeData(preferBelow: quillToolbarPosition == QuillToolbarPosition.top), + data: TooltipThemeData(preferBelow: position == QuillToolbarPosition.top), child: Builder( builder: (context) { // default button tooltips final buttonTooltips = tooltips ?? - { - ToolbarButtons.undo: componentString.get('STR_UNDO', context.loc.undo), - ToolbarButtons.redo: componentString.get('REDO', context.loc.redo), - ToolbarButtons.fontFamily: componentString.get('FONT_FAMILY', context.loc.fontFamily), - ToolbarButtons.fontSize: componentString.get('FONT_SIZE', context.loc.fontSize), - ToolbarButtons.bold: componentString.get('BOLD', context.loc.bold), - ToolbarButtons.subscript: componentString.get('SUBSCRIPT', context.loc.subscript), - ToolbarButtons.superscript: componentString.get('SUPERSCRIPT', context.loc.superscript), - ToolbarButtons.italic: componentString.get('ITALIC', context.loc.italic), - ToolbarButtons.small: componentString.get('SMALL', context.loc.small), - ToolbarButtons.underline: componentString.get('UNDERLINE', context.loc.underline), - ToolbarButtons.strikeThrough: componentString.get('STRIKE_THROUGH', context.loc.strikeThrough), - ToolbarButtons.inlineCode: componentString.get('INLINE_CODE', context.loc.inlineCode), - ToolbarButtons.color: componentString.get('FONT_COLOR', context.loc.fontColor), - ToolbarButtons.backgroundColor: componentString.get('BACKGROUND_COLOR', context.loc.backgroundColor), - ToolbarButtons.clearFormat: componentString.get('CLEAR_FORMAT', context.loc.clearFormat), - ToolbarButtons.leftAlignment: componentString.get('ALIGN_LEFT', context.loc.alignLeft), - ToolbarButtons.centerAlignment: componentString.get('ALIGN_CENTER', context.loc.alignCenter), - ToolbarButtons.rightAlignment: componentString.get('ALIGN_RIGHT', context.loc.alignRight), - ToolbarButtons.justifyAlignment: componentString.get('JUSTIFY_WIDTH', context.loc.justifyWinWidth), - ToolbarButtons.direction: componentString.get('TEXT_DIRECTION', context.loc.textDirection), - ToolbarButtons.headerStyle: componentString.get('HEADER_STYLE', context.loc.headerStyle), - ToolbarButtons.listNumbers: componentString.get('NUMBERED_LIST', context.loc.numberedList), - ToolbarButtons.listBullets: componentString.get('BULLET_LIST', context.loc.bulletList), - ToolbarButtons.listChecks: componentString.get('CHECKED_LIST', context.loc.checkedList), - ToolbarButtons.codeBlock: componentString.get('CODE_BLOCK', context.loc.codeBlock), - ToolbarButtons.quote: componentString.get('EDITOR_QUOTE', context.loc.quote), - ToolbarButtons.indentIncrease: componentString.get('INCREASE_INDENT', context.loc.increaseIndent), - ToolbarButtons.indentDecrease: componentString.get('DECREASE_INDENT', context.loc.decreaseIndent), - ToolbarButtons.link: componentString.get('INSERT_URL', context.loc.link), - ToolbarButtons.search: componentString.get('SEARCH', context.loc.search), + { + QuillToolbarOption.undo: strings.get('STR_UNDO', context.loc.undo), + QuillToolbarOption.redo: strings.get('REDO', context.loc.redo), + QuillToolbarOption.bold: strings.get('BOLD', context.loc.bold), + QuillToolbarOption.subscript: strings.get('SUBSCRIPT', context.loc.subscript), + QuillToolbarOption.superscript: strings.get('SUPERSCRIPT', context.loc.superscript), + QuillToolbarOption.italic: strings.get('ITALIC', context.loc.italic), + QuillToolbarOption.small: strings.get('SMALL', context.loc.small), + QuillToolbarOption.underline: strings.get('UNDERLINE', context.loc.underline), + QuillToolbarOption.strikeThrough: strings.get('STRIKE_THROUGH', context.loc.strikeThrough), + QuillToolbarOption.inlineCode: strings.get('INLINE_CODE', context.loc.inlineCode), + QuillToolbarOption.color: strings.get('FONT_COLOR', context.loc.fontColor), + QuillToolbarOption.backgroundColor: strings.get('BACKGROUND_COLOR', context.loc.backgroundColor), + QuillToolbarOption.clearFormat: strings.get('CLEAR_FORMAT', context.loc.clearFormat), + QuillToolbarOption.leftAlignment: strings.get('ALIGN_LEFT', context.loc.alignLeft), + QuillToolbarOption.centerAlignment: strings.get('ALIGN_CENTER', context.loc.alignCenter), + QuillToolbarOption.rightAlignment: strings.get('ALIGN_RIGHT', context.loc.alignRight), + QuillToolbarOption.justifyAlignment: strings.get('JUSTIFY_WIDTH', context.loc.justifyWinWidth), + QuillToolbarOption.direction: strings.get('TEXT_DIRECTION', context.loc.textDirection), + QuillToolbarOption.headerStyle: strings.get('HEADER_STYLE', context.loc.headerStyle), + QuillToolbarOption.numberList: strings.get('NUMBERED_LIST', context.loc.numberedList), + QuillToolbarOption.bullets: strings.get('BULLET_LIST', context.loc.bulletList), + QuillToolbarOption.checkBox: strings.get('CHECKED_LIST', context.loc.checkedList), + QuillToolbarOption.codeBlock: strings.get('CODE_BLOCK', context.loc.codeBlock), + QuillToolbarOption.quotes: strings.get('EDITOR_QUOTE', context.loc.quote), + QuillToolbarOption.indentIncrease: strings.get('INCREASE_INDENT', context.loc.increaseIndent), + QuillToolbarOption.indentDecrease: strings.get('DECREASE_INDENT', context.loc.decreaseIndent), + QuillToolbarOption.link: strings.get('INSERT_URL', context.loc.link), }; return Container( - decoration: configurations.decoration ?? BoxDecoration(color: configurations.color), + decoration: BoxDecoration(color: effectiveColor), constraints: BoxConstraints.tightFor( - height: configurations.axis == Axis.horizontal ? configurations.toolbarSize : null, - width: configurations.axis == Axis.vertical ? configurations.toolbarSize : null, + height: axis == Axis.horizontal ? effectiveIconSize * 3 : null, + width: axis == Axis.vertical ? effectiveIconSize * 3 : null, ), child: Material( - color: configurations.color, + color: effectiveColor, child: QuillToolbarArrowIndicatedButtonList( axis: Axis.horizontal, buttons: [ @@ -437,10 +331,10 @@ class ZdsQuillToolbar extends QuillToolbar { options: QuillToolbarHistoryButtonOptions( iconButtonFactor: toolbarSectionSpacing, iconData: Icons.undo_outlined, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.undo], + tooltip: buttonTooltips[QuillToolbarOption.undo], ), ), if (showRedo) ...[ @@ -449,10 +343,10 @@ class ZdsQuillToolbar extends QuillToolbar { isUndo: false, options: QuillToolbarHistoryButtonOptions( iconData: Icons.redo_outlined, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.redo], + tooltip: buttonTooltips[QuillToolbarOption.redo], ), ), if (showDividers) @@ -462,10 +356,10 @@ class ZdsQuillToolbar extends QuillToolbar { QuillToolbarSelectHeaderStyleButtons( controller: controller, options: QuillToolbarSelectHeaderStyleButtonsOptions( - tooltip: buttonTooltips[ToolbarButtons.headerStyle], + tooltip: buttonTooltips[QuillToolbarOption.headerStyle], axis: axis, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, ), ), @@ -478,9 +372,9 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.format_bold, - iconSize: toolbarIconSize, - tooltip: buttonTooltips[ToolbarButtons.bold], - iconTheme: iconTheme, + iconSize: effectiveIconSize, + tooltip: buttonTooltips[QuillToolbarOption.bold], + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, ), ), @@ -490,9 +384,9 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.subscript, - iconSize: toolbarIconSize, - tooltip: buttonTooltips[ToolbarButtons.subscript], - iconTheme: iconTheme, + iconSize: effectiveIconSize, + tooltip: buttonTooltips[QuillToolbarOption.subscript], + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, ), ), @@ -502,9 +396,9 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.superscript, - iconSize: toolbarIconSize, - tooltip: buttonTooltips[ToolbarButtons.superscript], - iconTheme: iconTheme, + iconSize: effectiveIconSize, + tooltip: buttonTooltips[QuillToolbarOption.superscript], + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, ), ), @@ -514,9 +408,9 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.format_italic, - iconSize: toolbarIconSize, - iconTheme: iconTheme, - tooltip: buttonTooltips[ToolbarButtons.italic], + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, + tooltip: buttonTooltips[QuillToolbarOption.italic], afterButtonPressed: afterButtonPressed, ), ), @@ -526,10 +420,10 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.format_underline, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.underline], + tooltip: buttonTooltips[QuillToolbarOption.underline], ), ), if (showStrikeThrough) @@ -538,10 +432,10 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.format_strikethrough, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.strikeThrough], + tooltip: buttonTooltips[QuillToolbarOption.strikeThrough], ), ), if (showSmallButton) @@ -550,9 +444,9 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.format_size, - iconSize: toolbarIconSize, - tooltip: buttonTooltips[ToolbarButtons.small], - iconTheme: iconTheme, + iconSize: effectiveIconSize, + tooltip: buttonTooltips[QuillToolbarOption.small], + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, ), ), @@ -562,10 +456,10 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.code, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.inlineCode], + tooltip: buttonTooltips[QuillToolbarOption.inlineCode], ), ), if (showDividers) QuillToolbarDivider(axis, color: sectionDividerColor, space: sectionDividerSpace), @@ -575,9 +469,9 @@ class ZdsQuillToolbar extends QuillToolbar { isBackground: false, options: QuillToolbarColorButtonOptions( iconData: Icons.color_lens, - iconSize: toolbarIconSize, - tooltip: buttonTooltips[ToolbarButtons.color], - iconTheme: iconTheme, + iconSize: effectiveIconSize, + tooltip: buttonTooltips[QuillToolbarOption.color], + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, ), ), @@ -587,10 +481,10 @@ class ZdsQuillToolbar extends QuillToolbar { isBackground: true, options: QuillToolbarColorButtonOptions( iconData: Icons.format_color_fill, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.backgroundColor], + tooltip: buttonTooltips[QuillToolbarOption.backgroundColor], ), ), if (showClearFormat) @@ -598,15 +492,15 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarBaseButtonOptions( iconData: Icons.format_clear, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.clearFormat], + tooltip: buttonTooltips[QuillToolbarOption.clearFormat], ), ), if (embedButtons != null) for (final EmbedButtonBuilder builder in embedButtons) - builder(controller, toolbarIconSize, iconTheme, dialogTheme), + builder(controller, effectiveIconSize, effectiveIconTheme, dialogTheme), if (showDividers && isButtonGroupShown[0] && (isButtonGroupShown[1] || @@ -620,14 +514,15 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarSelectAlignmentButtonOptions( tooltips: QuillSelectAlignmentValues( - leftAlignment: buttonTooltips[ToolbarButtons.leftAlignment] ?? context.loc.alignLeft, - centerAlignment: buttonTooltips[ToolbarButtons.centerAlignment] ?? context.loc.alignCenter, - rightAlignment: buttonTooltips[ToolbarButtons.rightAlignment] ?? context.loc.alignRight, + leftAlignment: buttonTooltips[QuillToolbarOption.leftAlignment] ?? context.loc.alignLeft, + centerAlignment: + buttonTooltips[QuillToolbarOption.centerAlignment] ?? context.loc.alignCenter, + rightAlignment: buttonTooltips[QuillToolbarOption.rightAlignment] ?? context.loc.alignRight, justifyAlignment: - buttonTooltips[ToolbarButtons.justifyAlignment] ?? context.loc.justifyWinWidth, + buttonTooltips[QuillToolbarOption.justifyAlignment] ?? context.loc.justifyWinWidth, ), - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, showLeftAlignment: showLeftAlignment, showCenterAlignment: showCenterAlignment, showRightAlignment: showRightAlignment, @@ -641,10 +536,10 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.format_textdirection_r_to_l, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.direction], + tooltip: buttonTooltips[QuillToolbarOption.direction], ), ), if (showDividers && @@ -665,10 +560,10 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.format_list_numbered, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.listNumbers], + tooltip: buttonTooltips[QuillToolbarOption.numberList], ), ), if (showListBullets) @@ -677,10 +572,10 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.format_list_bulleted, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.listBullets], + tooltip: buttonTooltips[QuillToolbarOption.bullets], ), ), if (showListCheck) @@ -688,10 +583,10 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleCheckListButtonOptions( iconData: Icons.check_box, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.listChecks], + tooltip: buttonTooltips[QuillToolbarOption.checkBox], ), ), if (showCodeBlock) @@ -700,10 +595,10 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.code, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.codeBlock], + tooltip: buttonTooltips[QuillToolbarOption.codeBlock], ), ), if (showDividers && isButtonGroupShown[3] && (isButtonGroupShown[4] || isButtonGroupShown[5])) @@ -714,34 +609,34 @@ class ZdsQuillToolbar extends QuillToolbar { controller: controller, options: QuillToolbarToggleStyleButtonOptions( iconData: Icons.format_quote, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.quote], + tooltip: buttonTooltips[QuillToolbarOption.quotes], ), ), - if (showIndent) + if (showIndentIncrease) QuillToolbarIndentButton( controller: controller, isIncrease: true, options: QuillToolbarIndentButtonOptions( iconData: Icons.format_indent_increase, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.indentIncrease], + tooltip: buttonTooltips[QuillToolbarOption.indentIncrease], ), ), - if (showIndent) + if (showIndentDecrease) QuillToolbarIndentButton( controller: controller, isIncrease: false, options: QuillToolbarIndentButtonOptions( iconData: Icons.format_indent_decrease, - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.indentDecrease], + tooltip: buttonTooltips[QuillToolbarOption.indentDecrease], ), ), if (showDividers && isButtonGroupShown[4] && isButtonGroupShown[5]) @@ -750,8 +645,8 @@ class ZdsQuillToolbar extends QuillToolbar { QuillToolbarLinkStyleButton( controller: controller, options: QuillToolbarLinkStyleButtonOptions( - iconSize: toolbarIconSize, - iconTheme: iconTheme, + iconSize: effectiveIconSize, + iconTheme: effectiveIconTheme, dialogTheme: dialogTheme, afterButtonPressed: afterButtonPressed, linkRegExp: linkRegExp ?? @@ -759,19 +654,7 @@ class ZdsQuillToolbar extends QuillToolbar { r'(http|ftp|https)://[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?', ), linkDialogAction: linkDialogAction, - tooltip: buttonTooltips[ToolbarButtons.link], - ), - ), - if (showSearchButton) - QuillToolbarSearchButton( - controller: controller, - options: QuillToolbarSearchButtonOptions( - iconData: Icons.search, - iconSize: toolbarIconSize, - iconTheme: iconTheme, - dialogTheme: dialogTheme, - afterButtonPressed: afterButtonPressed, - tooltip: buttonTooltips[ToolbarButtons.search], + tooltip: buttonTooltips[QuillToolbarOption.link], ), ), if (customButtons.isNotEmpty) @@ -782,11 +665,6 @@ class ZdsQuillToolbar extends QuillToolbar { options: customButton.options, controller: controller, ), - for (final customButton in configurations.customButtons) - QuillToolbarCustomButton( - options: customButton, - controller: controller, - ), ], ), ), From ca143e44425ae0fe110b17bb64417b9584e6ee9f Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 20 Jun 2024 11:25:06 +0100 Subject: [PATCH 3/4] fix(WFM-37003): validation in inputdialog onSetText --- lib/src/components/molecules/input_dialog.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/components/molecules/input_dialog.dart b/lib/src/components/molecules/input_dialog.dart index 3a04c9b..8fdf4d1 100644 --- a/lib/src/components/molecules/input_dialog.dart +++ b/lib/src/components/molecules/input_dialog.dart @@ -171,9 +171,12 @@ class ZdsInputDialogState extends State { children: [ Expanded( child: Semantics( - textField: true, onTap: _focusNode.requestFocus, excludeSemantics: true, + onSetText: (value) async { + _controller.text = value; + await _validateText(); + }, label: _controller.text.isNotEmpty ? _controller.text : widget.hint, child: TextFormField( maxLength: widget.characterCount, From 988f8baa063505d25fb64a55fc390a8f21c3a2ac Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 20 Jun 2024 11:28:50 +0100 Subject: [PATCH 4/4] fix(TM-43864): Fixed delta formatting in new version of quill-editor --- .../pages/components/quill_editor_demo.dart | 243 +++++++++++++----- .../organisms/html_preview/html_body.dart | 50 +++- .../organisms/quill_editor/quill_delta.dart | 51 +++- pubspec.yaml | 2 +- 4 files changed, 269 insertions(+), 77 deletions(-) diff --git a/example/lib/pages/components/quill_editor_demo.dart b/example/lib/pages/components/quill_editor_demo.dart index 0a0d37a..d3f8334 100644 --- a/example/lib/pages/components/quill_editor_demo.dart +++ b/example/lib/pages/components/quill_editor_demo.dart @@ -15,85 +15,122 @@ class QuillEditorDemo extends StatefulWidget { class _QuillEditorDemoState extends State { final controller = QuillController.basic(); + var _htmlPreview = true; + + get htmlPreview => _htmlPreview; + + set htmlPreview(value) { + if (htmlPreview == value) return; + setState(() { + _htmlPreview = value; + }); + } + + var _loading = true; + + get loading => _loading; + + set loading(value) { + if (loading == value) return; + setState(() { + _loading = value; + }); + } + @override void initState() { super.initState(); - ZdsQuillDelta.fromHtml(''' -

Google Doodles




Doodles celebrate a wide range of events, from national holidays like Independence Day and Christmas to special occasions like the anniversary of the first moon landing or the birth of significant figures in history such as Albert Einstein and Frida Kahlo.

- ''').then((value) { + loading = true; + ZdsQuillDelta.fromHtml(editorData).then((value) { controller.document = value.document; + }).whenComplete(() { + loading = false; }); } @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Quill Editor'), - actions: [ - IconButton( - icon: const Icon(Icons.html), - onPressed: () { - final html = ZdsQuillDelta(document: controller.document).toHtml(); - showDialog( - context: context, - builder: (context) { - return ConstrainedBox( - constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.7), - child: Dialog( - child: SingleChildScrollView( - child: Column( - children: [ - Text(html), - ], - ), - ))); - }, - ); - }, - ), - ], - ), - floatingActionButton: FloatingActionButton( - child: const Icon(Icons.edit), - onPressed: () { - ZdsQuillEditorPage.edit( - context, - title: 'Edit Notes', - embedBuilders: getEmbedBuilders(), - initialDelta: ZdsQuillDelta(document: controller.document), - charLimit: 20000, - embedButtons: FlutterQuillEmbeds.toolbarButtons( - videoButtonOptions: null, - imageButtonOptions: QuillToolbarImageButtonOptions( - imageButtonConfigurations: QuillToolbarImageConfigurations( - onImageInsertCallback: (image, controller) async { - // Upload to cloud - controller.insertImageBlock(imageSource: image); - }, - ), - ), + return Column( + children: [ + Expanded( + child: Scaffold( + backgroundColor: Zeta.of(context).colors.surfacePrimary, + appBar: AppBar( + title: const Text('Quill Editor'), + actions: [ + Row( + children: [ + Text('HTML'), + Switch( + value: htmlPreview, + onChanged: (value) { + setState(() { + htmlPreview = !htmlPreview; + }); + }, + ), + ], + ) + ], + ), + floatingActionButton: FloatingActionButton( + child: const Icon(Icons.edit), + onPressed: () { + ZdsQuillEditorPage.edit( + context, + title: 'Edit Notes', + embedBuilders: getEmbedBuilders(), + initialDelta: ZdsQuillDelta(document: controller.document), + charLimit: 20000, + embedButtons: FlutterQuillEmbeds.toolbarButtons( + videoButtonOptions: null, + imageButtonOptions: QuillToolbarImageButtonOptions( + imageButtonConfigurations: QuillToolbarImageConfigurations( + onImageInsertCallback: (image, controller) async { + // Upload to cloud + controller.insertImageBlock(imageSource: image); + }, + ), + ), + ), + ).then((value) { + if (value != null) { + setState(() { + controller.document = value.document; + }); + } + }); + }, ), - ).then((value) { - if (value != null) { - controller.document = value.document; - } - }); - }, - ), - body: Column( - children: [ - Expanded( - child: ZdsQuillEditor( - controller: controller, - readOnly: true, - padding: const EdgeInsets.all(16), - embedBuilders: getEmbedBuilders(), - focusNode: FocusNode(canRequestFocus: false), + body: Stack( + children: [ + ZdsQuillEditor( + controller: controller, + readOnly: true, + padding: const EdgeInsets.all(16), + embedBuilders: getEmbedBuilders(), + focusNode: FocusNode(canRequestFocus: false), + ), + if (loading) const LinearProgressIndicator(), + ], ), ), - ], - ), + ), + const Divider(), + Expanded( + child: Scaffold( + backgroundColor: Zeta.of(context).colors.surfacePrimary, + body: Builder(builder: (context) { + final html = ZdsQuillDelta(document: controller.document).toHtml(); + return SingleChildScrollView( + padding: EdgeInsets.all(14), + physics: ClampingScrollPhysics(), + child: htmlPreview ? ZdsHtmlContainer(html, expanded: true, showReadMore: false) : Text(html), + ); + }), + ), + ) + ], ); } } @@ -106,3 +143,75 @@ List getEmbedBuilders() { return FlutterQuillEmbeds.editorBuilders(); } } + +const editorData = """ +

+
    +
  • Apple
  • +
  • Banana
  • +
  • Cherry
  • +
+
+
    +
  1. Plan the trip
      +
    1. Book flights
    2. +
    +
  2. +
  3. Reserve hotel
      +
    1. Something
    2. +
    +
  4. +
  5. Check review
      +
    1. Read recent comments
    2. +
    +
  6. +
  7. Compare prices
      +
    1. Use comparison websites
    2. +
    +
  8. +
  9. Pack luggage
      +
    1. Clothes
    2. +
    +
  10. +
+
+
    +
  • Toiletries
      +
    • Shampoo
    • +
    • Toothbrush
    • +
    +
  • +
  • Gadgets
      +
    • Phone
    • +
    • Charger
    • +
    +
  • +
+
+
Code snippet example:
+Line 1: Initialize the project
+Line 2: Write some code
+Line 3: Test the code
+
+
“The only limit to our realization of tomorrow is our + doubts of today.”
– Franklin D. Roosevelt
+
+

Main Title

+
+

Subtitle

+
+

Section Title

+


Bold text example

Italic text example
Underlined text example

Strikethrough text + example

Small text example

Inline code example

Red colored text

Yellow + background text

Indented paragraph example. Lorem ipsum dolor sit amet, consectetur adipiscing + elit. Vivamus lacinia odio vitae vestibulum vestibulum.

Another indented paragraph. Cras placerat + ultricies orci nec vestibulum.

Left aligned text example

+

Right aligned text example

+
+

Center aligned text example

+
+

Right to left text example

+


Multi-line strikethrough example:
Line 1
Line 2
Line 3

+"""; diff --git a/lib/src/components/organisms/html_preview/html_body.dart b/lib/src/components/organisms/html_preview/html_body.dart index 95f6193..9e2c74c 100644 --- a/lib/src/components/organisms/html_preview/html_body.dart +++ b/lib/src/components/organisms/html_preview/html_body.dart @@ -107,24 +107,42 @@ class ZdsHtml extends StatelessWidget { } Map _buildStyles(BuildContext context, ColorScheme colorscheme, BoxConstraints box) { + final zetaColors = Zeta.of(context).colors; + final bodyMedium = Theme.of(context).textTheme.bodyMedium; + final fSize = fontSize ?? bodyMedium?.fontSize; return { 'p': Style( - fontSize: fontSize != null ? FontSize(fontSize!) : null, + fontSize: fSize != null ? FontSize(fSize) : null, maxLines: maxLines, before: '\n', lineHeight: LineHeight.percent(125), textOverflow: TextOverflow.ellipsis, - margin: Margins.only(left: 0, right: 0), + margin: Margins.zero, + padding: HtmlPaddings.zero, ), 'li': Style( fontSize: fontSize != null ? FontSize(fontSize!) : null, maxLines: maxLines, lineHeight: LineHeight.percent(125), textOverflow: TextOverflow.ellipsis, - margin: Margins.only(left: 0, right: 0), - backgroundColor: Theme.of(context).colorScheme.surface, + margin: Margins.zero, + ), + 'ol': Style( + fontSize: fontSize != null ? FontSize(fontSize!) : null, + maxLines: maxLines, + lineHeight: LineHeight.percent(125), + textOverflow: TextOverflow.ellipsis, + margin: Margins.zero, + ), + 'ul': Style( + fontSize: fontSize != null ? FontSize(fontSize!) : null, + maxLines: maxLines, + lineHeight: LineHeight.percent(125), + textOverflow: TextOverflow.ellipsis, + margin: Margins.zero, ), 'table': Style( + margin: Margins.zero, height: Height.auto(), width: Width.auto(), border: Border( @@ -135,6 +153,7 @@ class ZdsHtml extends StatelessWidget { ), ), 'tr': Style( + margin: Margins.zero, height: Height.auto(), width: Width.auto(), border: Border( @@ -145,6 +164,7 @@ class ZdsHtml extends StatelessWidget { ), ), 'th': Style( + margin: Margins.zero, height: Height.auto(), width: Width.auto(), border: Border( @@ -156,6 +176,7 @@ class ZdsHtml extends StatelessWidget { padding: HtmlPaddings.all(6), ), 'td': Style( + margin: Margins.zero, height: Height.auto(), width: Width.auto(), padding: HtmlPaddings.all(6), @@ -167,12 +188,29 @@ class ZdsHtml extends StatelessWidget { top: BorderSide(color: colorscheme.onSurface, width: 0.5), ), ), + 'h3': Style(margin: Margins.zero), + 'h4': Style(margin: Margins.zero), 'h5': Style(maxLines: maxLines, textOverflow: TextOverflow.ellipsis), 'iframe': Style(width: Width(box.maxWidth), height: Height((box.maxWidth / 16) * 9)), 'figure': Style(width: Width(box.maxWidth)), 'blockquote': Style( - padding: HtmlPaddings.only(left: 16), - border: Border(left: BorderSide(color: Zeta.of(context).colors.borderSubtle, width: 5)), + margin: Margins.zero, + padding: HtmlPaddings.symmetric(horizontal: 14, vertical: 8), + border: Border(left: BorderSide(color: zetaColors.borderDisabled, width: 4)), + color: zetaColors.textSubtle, + ), + 'pre': Style( + margin: Margins.zero, + padding: HtmlPaddings.all(14), + backgroundColor: zetaColors.surfaceTertiary, + lineHeight: LineHeight.percent(100), + color: zetaColors.primary.selected, + ), + 'code': Style( + margin: Margins.zero, + backgroundColor: zetaColors.surfaceTertiary, + lineHeight: LineHeight.percent(100), + color: zetaColors.primary, ), ...style, }; diff --git a/lib/src/components/organisms/quill_editor/quill_delta.dart b/lib/src/components/organisms/quill_editor/quill_delta.dart index 898ba78..5f8e94e 100644 --- a/lib/src/components/organisms/quill_editor/quill_delta.dart +++ b/lib/src/components/organisms/quill_editor/quill_delta.dart @@ -1,4 +1,5 @@ // ignore_for_file: avoid_dynamic_calls + import 'package:flutter_quill/flutter_quill.dart'; import 'package:flutter_quill/quill_delta.dart'; import 'package:vsc_quill_delta_to_html/vsc_quill_delta_to_html.dart'; @@ -26,7 +27,7 @@ class ZdsQuillDelta { /// Converts the underlying Quill's Delta to an HTML string. String toHtml() { // Convert document to JSON format - final List deltaJson = document.toDelta().toJson(); + final List> deltaJson = _correctJsonArray(document.toDelta().toJson()); // Iterate through each Delta operation for (final dynamic element in deltaJson) { @@ -38,8 +39,11 @@ class ZdsQuillDelta { } // Use the QuillDeltaToHtmlConverter to convert modified Delta to HTML - final QuillDeltaToHtmlConverter converter = - QuillDeltaToHtmlConverter(List.castFrom(deltaJson), ConverterOptions.forEmail()); + final QuillDeltaToHtmlConverter converter = QuillDeltaToHtmlConverter( + List.castFrom(deltaJson), + ConverterOptions.forEmail(), + ); + return converter.convert(); } @@ -51,6 +55,47 @@ class ZdsQuillDelta { } } + List> _correctJsonArray(List> inputArray) { + final List> correctedArray = []; + + bool isBlock(dynamic attributes) { + return (attributes != null && attributes is Map) && + (attributes.containsKey('header') || + attributes.containsKey('list') || + attributes.containsKey('blockquote') || + attributes.containsKey('code-block') || + attributes.containsKey('direction') || + attributes.containsKey('align') || + attributes.containsKey('indent')); + } + + for (final element in inputArray) { + if (element['insert'] != '\n' && element['attributes'] != null && isBlock(element['attributes'])) { + final insertValue = element['insert']; + final attributes = element['attributes']; + + if (insertValue is String && insertValue.contains('\n')) { + final parts = insertValue.split('\n'); + for (int i = 0; i < parts.length; i++) { + if (parts[i].isNotEmpty) { + correctedArray + ..add({'insert': parts[i]}) + ..add({'attributes': attributes, 'insert': '\n'}); + } + } + } else { + correctedArray + ..add({'insert': insertValue}) + ..add({'attributes': attributes, 'insert': '\n'}); + } + } else { + correctedArray.add(element); + } + } + + return correctedArray; + } + /// Creates a copy with provided document ZdsQuillDelta copyWith({ Document? document, diff --git a/pubspec.yaml b/pubspec.yaml index bac1ed4..a5529df 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -71,7 +71,7 @@ dependencies: validators: ^3.0.0 video_compress: ^3.1.2 video_player: ^2.8.6 - vsc_quill_delta_to_html: ^1.0.4 + vsc_quill_delta_to_html: ^1.0.5 zeta_flutter: ^0.11.1 dev_dependencies: