feat: working on editor state

This commit is contained in:
jideguru 2021-06-06 16:42:55 +01:00
parent 3e8ade5b18
commit 066b2019f2
9 changed files with 138 additions and 55 deletions

View File

@ -10,20 +10,11 @@ PODS:
- image_picker (0.0.1):
- Flutter
- OrderedSet (5.0.0)
- video_player (0.0.1):
- Flutter
- wakelock (0.0.1):
- Flutter
- webview_flutter (0.0.1):
- Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
- image_picker (from `.symlinks/plugins/image_picker/ios`)
- video_player (from `.symlinks/plugins/video_player/ios`)
- wakelock (from `.symlinks/plugins/wakelock/ios`)
- webview_flutter (from `.symlinks/plugins/webview_flutter/ios`)
SPEC REPOS:
trunk:
@ -36,21 +27,12 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_inappwebview/ios"
image_picker:
:path: ".symlinks/plugins/image_picker/ios"
video_player:
:path: ".symlinks/plugins/video_player/ios"
wakelock:
:path: ".symlinks/plugins/wakelock/ios"
webview_flutter:
:path: ".symlinks/plugins/webview_flutter/ios"
SPEC CHECKSUMS:
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721
image_picker: 50e7c7ff960e5f58faa4d1f4af84a771c671bc4a
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
webview_flutter: 9f491a9b5a66f2573946a389b2677987b0ff8c0b
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c

View File

@ -0,0 +1,3 @@
class DidHtmlChangeListener {
didHtmlChange(bool didHtmlChange) {}
}

View File

@ -0,0 +1,3 @@
class GetCurrentHtmlCallback {
htmlRetrieved(String html) {}
}

View File

@ -0,0 +1,3 @@
class HtmlChangedListener {
htmlChangedAsync(String html) {}
}

View File

@ -0,0 +1,3 @@
class LoadedListener {
editorLoaded() {}
}

View File

@ -9,6 +9,7 @@ class RichEditorOptions {
String? placeholder;
String? baseFontFamily;
BarPosition? barPosition;
bool? enableVideo;
RichEditorOptions({
Color? backgroundColor,
@ -17,6 +18,7 @@ class RichEditorOptions {
String? placeholder,
String? baseFontFamily,
BarPosition? barPosition,
bool? enableVideo = true,
}) {
this.backgroundColor = backgroundColor;
this.baseTextColor = baseTextColor;
@ -24,5 +26,6 @@ class RichEditorOptions {
this.placeholder = placeholder;
this.baseFontFamily = baseFontFamily;
this.barPosition = barPosition;
this.enableVideo = enableVideo;
}
}

View File

@ -10,7 +10,6 @@ import 'package:rich_editor/src/models/rich_editor_options.dart';
import 'package:rich_editor/src/services/local_server.dart';
import 'package:rich_editor/src/utils/javascript_executor_base.dart';
import 'package:rich_editor/src/widgets/editor_tool_bar.dart';
// import 'package:webview_flutter/webview_flutter.dart';
class RichEditor extends StatefulWidget {
final String? value;
@ -35,8 +34,6 @@ class RichEditorState extends State<RichEditor> {
final Key _mapKey = UniqueKey();
String assetPath = 'packages/rich_editor/assets/editor/editor.html';
// InAppWebViewController? webViewController;
int port = 5321;
String html = '';
LocalServer? localServer;
@ -94,6 +91,7 @@ class RichEditorState extends State<RichEditor> {
child: EditorToolBar(
getImageUrl: widget.getImageUrl,
javascriptExecutor: javascriptExecutor,
enableVideo: widget.editorOptions!.enableVideo,
),
),
Expanded(
@ -114,9 +112,11 @@ class RichEditorState extends State<RichEditor> {
}
},
onLoadStop: (controller, link) async {
javascriptExecutor.init(_controller!);
await _setInitialValues();
_addJSListener();
if (link!.path != 'blank') {
javascriptExecutor.init(_controller!);
await _setInitialValues();
_addJSListener();
}
},
// javascriptMode: JavascriptMode.unrestricted,
// gestureNavigationEnabled: false,
@ -138,6 +138,7 @@ class RichEditorState extends State<RichEditor> {
child: EditorToolBar(
getImageUrl: widget.getImageUrl,
javascriptExecutor: javascriptExecutor,
enableVideo: widget.editorOptions!.enableVideo,
),
),
],

View File

@ -3,6 +3,9 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:rich_editor/src/extensions/extensions.dart';
import 'package:rich_editor/src/models/callbacks/did_html_change_listener.dart';
import 'package:rich_editor/src/models/callbacks/html_changed_listener.dart';
import 'package:rich_editor/src/models/callbacks/loaded_listener.dart';
import 'package:rich_editor/src/models/editor_state.dart';
import 'package:rich_editor/src/models/enum/command_name.dart';
@ -19,9 +22,27 @@ class JavascriptExecutorBase {
String defaultEncoding = "UTF-8";
String? htmlField = "";
var didHtmlChange = false;
Map<CommandName, CommandState> commandStates = {};
List<Map<CommandName, CommandState>> commandStatesChangedListeners =
<Map<CommandName, CommandState>>[];
List<DidHtmlChangeListener> didHtmlChangeListeners =
<DidHtmlChangeListener>[];
List<HtmlChangedListener> htmlChangedListeners = <HtmlChangedListener>[];
// protected val fireHtmlChangedListenersQueue = AsyncProducerConsumerQueue<String>(1) { html ->
// fireHtmlChangedListeners(html)
// }
bool isLoaded = false;
List<LoadedListener> loadedListeners = <LoadedListener>[];
init(InAppWebViewController? controller) {
_controller = controller;
}
@ -42,8 +63,8 @@ class JavascriptExecutorBase {
getCurrentHtml() async {
String? html = await executeJavascript('getEncodedHtml()');
String? decodedHtml = Uri.decodeFull(html!);
if (decodedHtml.startsWith('"') && decodedHtml.endsWith('"')) {
String? decodedHtml = decodeHtml(html!);
if (decodedHtml!.startsWith('"') && decodedHtml.endsWith('"')) {
decodedHtml = decodedHtml.substring(1, decodedHtml.length - 1);
}
return decodedHtml;
@ -247,11 +268,11 @@ class JavascriptExecutorBase {
await executeJavascript("setInputEnabled($inputEnabled);");
}
static decodeHtml(String html) {
decodeHtml(String html) {
return Uri.decodeFull(html);
}
static encodeHtml(String html) {
encodeHtml(String html) {
return Uri.encodeFull(html);
}
@ -295,9 +316,9 @@ class JavascriptExecutorBase {
bool didHtmlChange, Map<CommandName, CommandState> commandStates) {
if (this.didHtmlChange != didHtmlChange) {
this.didHtmlChange = didHtmlChange;
// didHtmlChangeListeners.forEach {
// it.didHtmlChange(didHtmlChange);
// }
didHtmlChangeListeners.forEach((element) {
element.didHtmlChange(didHtmlChange);
});
}
handleRetrievedCommandStates(commandStates);
@ -307,37 +328,91 @@ class JavascriptExecutorBase {
determineDerivedCommandStates(commandStates);
this.commandStates = commandStates;
// commandStatesChangedListeners.forEach {
// it.invoke(this.commandStates)
// }
commandStatesChangedListeners.forEach((element) {
element = this.commandStates;
});
}
determineDerivedCommandStates(Map<CommandName, CommandState> commandStates) {
// commandStates[CommandName.FORMATBLOCK]?.let {
// formatCommandState
// ->
// commandStates.put(CommandName.H1, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "h1")))
// commandStates.put(CommandName.H2, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "h2")))
// commandStates.put(CommandName.H3, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "h3")))
// commandStates.put(CommandName.H4, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "h4")))
// commandStates.put(CommandName.H5, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "h5")))
// commandStates.put(CommandName.H6, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "h6")))
// commandStates.put(CommandName.P, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "p")))
// commandStates.put(CommandName.PRE, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "pre")))
// commandStates.put(CommandName.BR, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "")))
// commandStates.put(CommandName.BLOCKQUOTE, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "blockquote")))
// }
//
// commandStates[CommandName.INSERTHTML]?.let { insertHtmlState ->
// commandStates.put(CommandName.INSERTLINK, insertHtmlState)
// commandStates.put(CommandName.INSERTIMAGE, insertHtmlState)
// commandStates.put(CommandName.INSERTCHECKBOX, insertHtmlState)
// }
if (commandStates[CommandName.FORMATBLOCK] != null) {
var formatCommandState = commandStates[CommandName.FORMATBLOCK];
commandStates.update(
CommandName.H1,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "h1")),
);
commandStates.update(
CommandName.H2,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "h2")));
commandStates.update(
CommandName.H3,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "h3")),
);
commandStates.update(
CommandName.H4,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "h4")),
);
commandStates.update(
CommandName.H5,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "h5")),
);
commandStates.update(
CommandName.H6,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "h6")),
);
commandStates.update(
CommandName.P,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "p")),
);
commandStates.update(
CommandName.PRE,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "pre")),
);
commandStates.update(
CommandName.BR,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "")),
);
commandStates.update(
CommandName.BLOCKQUOTE,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "blockquote")),
);
}
if (commandStates[CommandName.INSERTHTML] != null) {
CommandState? insertHtmlState = commandStates[CommandName.INSERTHTML];
commandStates.update(CommandName.INSERTLINK, (val) => insertHtmlState!);
commandStates.update(CommandName.INSERTIMAGE, (val) => insertHtmlState!);
commandStates.update(
CommandName.INSERTCHECKBOX, (val) => insertHtmlState!);
}
}
String isFormatActivated(CommandState formatCommandState, String format) {
return (formatCommandState.value == format)
.toString(); // rich_text_editor.js reports boolean values as string, so we also have to convert it to string
}
addCommandStatesChangedListener(
Map<CommandName, CommandState> commandStates) {
commandStatesChangedListeners.add(commandStates);
// listener.invoke(commandStates);
}
addDidHtmlChangeListener(DidHtmlChangeListener listener) {
didHtmlChangeListeners.add(listener);
}
addHtmlChangedListener(HtmlChangedListener listener) {
htmlChangedListeners.add(listener);
}
}

View File

@ -16,11 +16,13 @@ class EditorToolBar extends StatelessWidget {
final Function(File image)? getImageUrl;
final Function(File video)? getVideoUrl;
final JavascriptExecutorBase javascriptExecutor;
final bool? enableVideo;
EditorToolBar({
this.getImageUrl,
this.getVideoUrl,
required this.javascriptExecutor,
this.enableVideo,
});
@override
@ -85,6 +87,14 @@ class EditorToolBar extends StatelessWidget {
}
},
),
Visibility(
visible: false,
child: TabButton(
tooltip: 'Insert video',
icon: Icons.video_call_sharp,
onTap: () async {},
),
),
TabButton(
tooltip: 'Underline',
icon: Icons.format_underline,