2022-11-09 11:37:26 +08:00
|
|
|
import 'dart:convert';
|
|
|
|
|
|
|
|
|
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
2023-07-07 16:07:47 +08:00
|
|
|
class Editor extends StatelessWidget {
|
|
|
|
|
const Editor({
|
2022-11-09 11:37:26 +08:00
|
|
|
super.key,
|
|
|
|
|
required this.jsonString,
|
|
|
|
|
required this.onEditorStateChange,
|
2023-06-23 18:36:33 +08:00
|
|
|
this.editorStyle,
|
2022-11-09 11:37:26 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
final Future<String> jsonString;
|
2023-06-23 18:36:33 +08:00
|
|
|
final EditorStyle? editorStyle;
|
2022-11-09 11:37:26 +08:00
|
|
|
final void Function(EditorState editorState) onEditorStateChange;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return FutureBuilder<String>(
|
|
|
|
|
future: jsonString,
|
|
|
|
|
builder: (context, snapshot) {
|
|
|
|
|
if (snapshot.hasData &&
|
|
|
|
|
snapshot.connectionState == ConnectionState.done) {
|
|
|
|
|
final editorState = EditorState(
|
|
|
|
|
document: Document.fromJson(
|
|
|
|
|
Map<String, Object>.from(
|
|
|
|
|
json.decode(snapshot.data!),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
2022-12-20 09:37:18 +08:00
|
|
|
editorState.logConfiguration
|
|
|
|
|
..handler = debugPrint
|
2023-06-23 18:36:33 +08:00
|
|
|
..level = LogLevel.off;
|
2023-08-29 16:43:24 +08:00
|
|
|
editorState.transactionStream.listen((event) {
|
|
|
|
|
if (event.$1 == TransactionTime.after) {
|
|
|
|
|
onEditorStateChange(editorState);
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-09-11 15:03:14 +08:00
|
|
|
final editorScrollController = EditorScrollController(
|
|
|
|
|
editorState: editorState,
|
|
|
|
|
shrinkWrap: false,
|
|
|
|
|
);
|
2023-04-25 19:58:48 +08:00
|
|
|
if (PlatformExtension.isDesktopOrWeb) {
|
|
|
|
|
return FloatingToolbar(
|
2023-04-28 16:25:51 +08:00
|
|
|
items: [
|
|
|
|
|
paragraphItem,
|
2023-04-29 16:39:32 +08:00
|
|
|
...headingItems,
|
2023-05-02 18:44:52 +08:00
|
|
|
...markdownFormatItems,
|
2023-04-29 11:22:39 +08:00
|
|
|
quoteItem,
|
|
|
|
|
bulletedListItem,
|
|
|
|
|
numberedListItem,
|
|
|
|
|
linkItem,
|
2023-07-03 21:38:42 -05:00
|
|
|
buildTextColorItem(),
|
2023-07-12 06:21:38 +03:30
|
|
|
buildHighlightColorItem(),
|
2023-08-29 16:43:24 +08:00
|
|
|
...textDirectionItems,
|
|
|
|
|
...alignmentItems,
|
2023-04-28 16:25:51 +08:00
|
|
|
],
|
2023-04-28 13:33:13 +08:00
|
|
|
editorState: editorState,
|
2023-09-11 15:03:14 +08:00
|
|
|
editorScrollController: editorScrollController,
|
2023-06-23 18:36:33 +08:00
|
|
|
child: _buildDesktopEditor(
|
2023-04-28 13:33:13 +08:00
|
|
|
context,
|
|
|
|
|
editorState,
|
2023-09-11 15:03:14 +08:00
|
|
|
editorScrollController,
|
2023-04-28 13:33:13 +08:00
|
|
|
),
|
|
|
|
|
);
|
2023-06-13 01:01:08 -05:00
|
|
|
} else if (PlatformExtension.isMobile) {
|
2023-04-25 19:58:48 +08:00
|
|
|
return Column(
|
|
|
|
|
children: [
|
2023-04-28 13:33:13 +08:00
|
|
|
Expanded(
|
2023-05-20 05:43:38 -05:00
|
|
|
child: _buildMobileEditor(
|
|
|
|
|
context,
|
|
|
|
|
editorState,
|
2023-09-11 15:03:14 +08:00
|
|
|
editorScrollController,
|
2023-05-20 05:43:38 -05:00
|
|
|
),
|
2023-04-28 13:33:13 +08:00
|
|
|
),
|
2023-06-13 01:01:08 -05:00
|
|
|
MobileToolbar(
|
|
|
|
|
editorState: editorState,
|
|
|
|
|
toolbarItems: [
|
|
|
|
|
textDecorationMobileToolbarItem,
|
2023-07-03 21:38:42 -05:00
|
|
|
buildTextAndBackgroundColorMobileToolbarItem(),
|
2023-06-13 01:01:08 -05:00
|
|
|
headingMobileToolbarItem,
|
|
|
|
|
todoListMobileToolbarItem,
|
|
|
|
|
listMobileToolbarItem,
|
|
|
|
|
linkMobileToolbarItem,
|
|
|
|
|
quoteMobileToolbarItem,
|
2023-07-03 21:09:44 -05:00
|
|
|
dividerMobileToolbarItem,
|
2023-06-13 01:01:08 -05:00
|
|
|
codeMobileToolbarItem,
|
|
|
|
|
],
|
|
|
|
|
),
|
2023-04-25 19:58:48 +08:00
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-11-09 11:37:26 +08:00
|
|
|
}
|
2023-06-13 01:01:08 -05:00
|
|
|
return const Center(
|
|
|
|
|
child: CircularProgressIndicator(),
|
|
|
|
|
);
|
2022-11-09 11:37:26 +08:00
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
2023-04-20 13:45:46 +08:00
|
|
|
|
2023-05-20 05:43:38 -05:00
|
|
|
Widget _buildMobileEditor(
|
|
|
|
|
BuildContext context,
|
|
|
|
|
EditorState editorState,
|
2023-09-11 15:03:14 +08:00
|
|
|
EditorScrollController? editorScrollController,
|
2023-05-20 05:43:38 -05:00
|
|
|
) {
|
2023-07-07 16:07:47 +08:00
|
|
|
return AppFlowyEditor(
|
2023-05-20 05:43:38 -05:00
|
|
|
editorStyle: const EditorStyle.mobile(),
|
|
|
|
|
editorState: editorState,
|
2023-09-11 15:03:14 +08:00
|
|
|
editorScrollController: editorScrollController,
|
2023-05-20 05:43:38 -05:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-23 18:36:33 +08:00
|
|
|
Widget _buildDesktopEditor(
|
2023-04-28 13:33:13 +08:00
|
|
|
BuildContext context,
|
|
|
|
|
EditorState editorState,
|
2023-09-11 15:03:14 +08:00
|
|
|
EditorScrollController? editorScrollController,
|
2023-04-28 13:33:13 +08:00
|
|
|
) {
|
2023-06-30 13:40:18 +08:00
|
|
|
final customBlockComponentBuilders = {
|
|
|
|
|
...standardBlockComponentBuilderMap,
|
|
|
|
|
ImageBlockKeys.type: ImageBlockComponentBuilder(
|
|
|
|
|
showMenu: true,
|
|
|
|
|
menuBuilder: (node, _) {
|
|
|
|
|
return const Positioned(
|
|
|
|
|
right: 10,
|
|
|
|
|
child: Text('Sample Menu'),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
};
|
2023-07-07 16:07:47 +08:00
|
|
|
return AppFlowyEditor(
|
2023-04-20 13:45:46 +08:00
|
|
|
editorState: editorState,
|
2023-09-11 15:03:14 +08:00
|
|
|
shrinkWrap: true,
|
|
|
|
|
editorScrollController: editorScrollController,
|
2023-06-30 13:40:18 +08:00
|
|
|
blockComponentBuilders: customBlockComponentBuilders,
|
2023-08-10 16:38:45 +05:30
|
|
|
commandShortcutEvents: [
|
2023-08-29 12:55:08 +05:30
|
|
|
customToggleHighlightCommand(
|
|
|
|
|
style: ToggleColorsStyle(
|
|
|
|
|
highlightColor: Theme.of(context).highlightColor,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
...[
|
|
|
|
|
...standardCommandShortcutEvents
|
|
|
|
|
..removeWhere(
|
|
|
|
|
(el) => el == toggleHighlightCommand,
|
|
|
|
|
),
|
|
|
|
|
],
|
2023-08-10 16:38:45 +05:30
|
|
|
...findAndReplaceCommands(
|
|
|
|
|
context: context,
|
|
|
|
|
localizations: FindReplaceLocalizations(
|
|
|
|
|
find: 'Find',
|
|
|
|
|
previousMatch: 'Previous match',
|
|
|
|
|
nextMatch: 'Next match',
|
|
|
|
|
close: 'Close',
|
|
|
|
|
replace: 'Replace',
|
|
|
|
|
replaceAll: 'Replace all',
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
2023-06-30 13:40:18 +08:00
|
|
|
characterShortcutEvents: standardCharacterShortcutEvents,
|
2023-04-20 13:45:46 +08:00
|
|
|
);
|
|
|
|
|
}
|
2022-11-09 11:37:26 +08:00
|
|
|
}
|