feat: support customizing editor edges
This commit is contained in:
parent
94b2a11506
commit
061a7d2af4
14 changed files with 172 additions and 157 deletions
|
|
@ -46,13 +46,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
extendBodyBehindAppBar: true,
|
extendBodyBehindAppBar: true,
|
||||||
body: Center(
|
body: _buildEditor(context),
|
||||||
child: Container(
|
|
||||||
width: 780,
|
|
||||||
alignment: Alignment.topCenter,
|
|
||||||
child: _buildEditor(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
floatingActionButton: _buildExpandableFab(),
|
floatingActionButton: _buildExpandableFab(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -100,6 +94,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
width: MediaQuery.of(context).size.width,
|
width: MediaQuery.of(context).size.width,
|
||||||
child: AppFlowyEditor(
|
child: AppFlowyEditor(
|
||||||
editorState: _editorState,
|
editorState: _editorState,
|
||||||
|
editorStyle: const EditorStyle.defaultStyle(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
library appflowy_editor;
|
library appflowy_editor;
|
||||||
|
|
||||||
export 'src/infra/log.dart';
|
export 'src/infra/log.dart';
|
||||||
|
export 'src/render/style/editor_style.dart';
|
||||||
export 'src/document/node.dart';
|
export 'src/document/node.dart';
|
||||||
export 'src/document/path.dart';
|
export 'src/document/path.dart';
|
||||||
export 'src/document/position.dart';
|
export 'src/document/position.dart';
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:appflowy_editor/src/infra/log.dart';
|
import 'package:appflowy_editor/src/infra/log.dart';
|
||||||
import 'package:appflowy_editor/src/render/selection_menu/selection_menu_widget.dart';
|
import 'package:appflowy_editor/src/render/selection_menu/selection_menu_widget.dart';
|
||||||
|
import 'package:appflowy_editor/src/render/style/editor_style.dart';
|
||||||
import 'package:appflowy_editor/src/service/service.dart';
|
import 'package:appflowy_editor/src/service/service.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
@ -58,6 +59,9 @@ class EditorState {
|
||||||
/// Stores the selection menu items.
|
/// Stores the selection menu items.
|
||||||
List<SelectionMenuItem> selectionMenuItems = [];
|
List<SelectionMenuItem> selectionMenuItems = [];
|
||||||
|
|
||||||
|
/// Stores the editor style.
|
||||||
|
EditorStyle editorStyle = const EditorStyle.defaultStyle();
|
||||||
|
|
||||||
final UndoManager undoManager = UndoManager();
|
final UndoManager undoManager = UndoManager();
|
||||||
Selection? _cursorSelection;
|
Selection? _cursorSelection;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import 'dart:math';
|
import 'package:appflowy_editor/src/extensions/object_extensions.dart';
|
||||||
|
|
||||||
import 'package:appflowy_editor/src/document/node.dart';
|
import 'package:appflowy_editor/src/document/node.dart';
|
||||||
import 'package:appflowy_editor/src/document/position.dart';
|
import 'package:appflowy_editor/src/document/position.dart';
|
||||||
import 'package:appflowy_editor/src/document/selection.dart';
|
import 'package:appflowy_editor/src/document/selection.dart';
|
||||||
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
|
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
|
||||||
import 'package:appflowy_editor/src/render/rich_text/rich_text_style.dart';
|
|
||||||
import 'package:appflowy_editor/src/render/selection/selectable.dart';
|
import 'package:appflowy_editor/src/render/selection/selectable.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
@ -35,6 +33,8 @@ class ImageNodeWidget extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ImageNodeWidgetState extends State<ImageNodeWidget> with Selectable {
|
class _ImageNodeWidgetState extends State<ImageNodeWidget> with Selectable {
|
||||||
|
final _imageKey = GlobalKey();
|
||||||
|
|
||||||
double? _imageWidth;
|
double? _imageWidth;
|
||||||
double _initial = 0;
|
double _initial = 0;
|
||||||
double _distance = 0;
|
double _distance = 0;
|
||||||
|
|
@ -50,8 +50,11 @@ class _ImageNodeWidgetState extends State<ImageNodeWidget> with Selectable {
|
||||||
_imageWidth = widget.width;
|
_imageWidth = widget.width;
|
||||||
_imageStreamListener = ImageStreamListener(
|
_imageStreamListener = ImageStreamListener(
|
||||||
(image, _) {
|
(image, _) {
|
||||||
_imageWidth =
|
_imageWidth = _imageKey.currentContext
|
||||||
min(defaultMaxTextNodeWidth, image.image.width.toDouble());
|
?.findRenderObject()
|
||||||
|
?.unwrapOrNull<RenderBox>()
|
||||||
|
?.size
|
||||||
|
.width;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -65,9 +68,8 @@ class _ImageNodeWidgetState extends State<ImageNodeWidget> with Selectable {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// only support network image.
|
// only support network image.
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
width: defaultMaxTextNodeWidth,
|
key: _imageKey,
|
||||||
padding: const EdgeInsets.only(top: 8, bottom: 8),
|
padding: const EdgeInsets.only(top: 8, bottom: 8),
|
||||||
child: _buildNetworkImage(context),
|
child: _buildNetworkImage(context),
|
||||||
);
|
);
|
||||||
|
|
@ -137,7 +139,7 @@ class _ImageNodeWidgetState extends State<ImageNodeWidget> with Selectable {
|
||||||
loadingBuilder: (context, child, loadingProgress) =>
|
loadingBuilder: (context, child, loadingProgress) =>
|
||||||
loadingProgress == null ? child : _buildLoading(context),
|
loadingProgress == null ? child : _buildLoading(context),
|
||||||
errorBuilder: (context, error, stackTrace) {
|
errorBuilder: (context, error, stackTrace) {
|
||||||
_imageWidth ??= defaultMaxTextNodeWidth;
|
// _imageWidth ??= defaultMaxTextNodeWidth;
|
||||||
return _buildError(context);
|
return _buildError(context);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -56,30 +56,27 @@ class _BulletedListTextNodeWidgetState extends State<BulletedListTextNodeWidget>
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Padding(
|
||||||
constraints: BoxConstraints(maxWidth: defaultMaxTextNodeWidth),
|
padding: EdgeInsets.only(bottom: defaultLinePadding),
|
||||||
child: Padding(
|
child: Row(
|
||||||
padding: EdgeInsets.only(bottom: defaultLinePadding),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Row(
|
children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
FlowySvg(
|
||||||
children: [
|
key: iconKey,
|
||||||
FlowySvg(
|
width: _iconWidth,
|
||||||
key: iconKey,
|
height: _iconWidth,
|
||||||
width: _iconWidth,
|
padding: EdgeInsets.only(right: _iconRightPadding),
|
||||||
height: _iconWidth,
|
name: 'point',
|
||||||
padding: EdgeInsets.only(right: _iconRightPadding),
|
),
|
||||||
name: 'point',
|
Flexible(
|
||||||
|
child: FlowyRichText(
|
||||||
|
key: _richTextKey,
|
||||||
|
placeholderText: 'List',
|
||||||
|
textNode: widget.textNode,
|
||||||
|
editorState: widget.editorState,
|
||||||
),
|
),
|
||||||
Flexible(
|
)
|
||||||
child: FlowyRichText(
|
],
|
||||||
key: _richTextKey,
|
|
||||||
placeholderText: 'List',
|
|
||||||
textNode: widget.textNode,
|
|
||||||
editorState: widget.editorState,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,41 +63,38 @@ class _CheckboxNodeWidgetState extends State<CheckboxNodeWidget>
|
||||||
|
|
||||||
Widget _buildWithSingle(BuildContext context) {
|
Widget _buildWithSingle(BuildContext context) {
|
||||||
final check = widget.textNode.attributes.check;
|
final check = widget.textNode.attributes.check;
|
||||||
return SizedBox(
|
return Padding(
|
||||||
width: defaultMaxTextNodeWidth,
|
padding: EdgeInsets.only(bottom: defaultLinePadding),
|
||||||
child: Padding(
|
child: Row(
|
||||||
padding: EdgeInsets.only(bottom: defaultLinePadding),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Row(
|
children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
GestureDetector(
|
||||||
children: [
|
key: iconKey,
|
||||||
GestureDetector(
|
child: FlowySvg(
|
||||||
key: iconKey,
|
width: _iconWidth,
|
||||||
child: FlowySvg(
|
height: _iconWidth,
|
||||||
width: _iconWidth,
|
padding: EdgeInsets.only(right: _iconRightPadding),
|
||||||
height: _iconWidth,
|
name: check ? 'check' : 'uncheck',
|
||||||
padding: EdgeInsets.only(right: _iconRightPadding),
|
|
||||||
name: check ? 'check' : 'uncheck',
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
TransactionBuilder(widget.editorState)
|
|
||||||
..updateNode(widget.textNode, {
|
|
||||||
StyleKey.checkbox: !check,
|
|
||||||
})
|
|
||||||
..commit();
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
Flexible(
|
onTap: () {
|
||||||
child: FlowyRichText(
|
TransactionBuilder(widget.editorState)
|
||||||
key: _richTextKey,
|
..updateNode(widget.textNode, {
|
||||||
placeholderText: 'To-do',
|
StyleKey.checkbox: !check,
|
||||||
textNode: widget.textNode,
|
})
|
||||||
textSpanDecorator: _textSpanDecorator,
|
..commit();
|
||||||
placeholderTextSpanDecorator: _textSpanDecorator,
|
},
|
||||||
editorState: widget.editorState,
|
),
|
||||||
),
|
Flexible(
|
||||||
|
child: FlowyRichText(
|
||||||
|
key: _richTextKey,
|
||||||
|
placeholderText: 'To-do',
|
||||||
|
textNode: widget.textNode,
|
||||||
|
textSpanDecorator: _textSpanDecorator,
|
||||||
|
placeholderTextSpanDecorator: _textSpanDecorator,
|
||||||
|
editorState: widget.editorState,
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,16 +63,13 @@ class _HeadingTextNodeWidgetState extends State<HeadingTextNodeWidget>
|
||||||
top: _topPadding,
|
top: _topPadding,
|
||||||
bottom: defaultLinePadding,
|
bottom: defaultLinePadding,
|
||||||
),
|
),
|
||||||
child: Container(
|
child: FlowyRichText(
|
||||||
constraints: BoxConstraints(maxWidth: defaultMaxTextNodeWidth),
|
key: _richTextKey,
|
||||||
child: FlowyRichText(
|
placeholderText: 'Heading',
|
||||||
key: _richTextKey,
|
placeholderTextSpanDecorator: _placeholderTextSpanDecorator,
|
||||||
placeholderText: 'Heading',
|
textSpanDecorator: _textSpanDecorator,
|
||||||
placeholderTextSpanDecorator: _placeholderTextSpanDecorator,
|
textNode: widget.textNode,
|
||||||
textSpanDecorator: _textSpanDecorator,
|
editorState: widget.editorState,
|
||||||
textNode: widget.textNode,
|
|
||||||
editorState: widget.editorState,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,28 +58,25 @@ class _NumberListTextNodeWidgetState extends State<NumberListTextNodeWidget>
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(bottom: defaultLinePadding),
|
padding: EdgeInsets.only(bottom: defaultLinePadding),
|
||||||
child: SizedBox(
|
child: Row(
|
||||||
width: defaultMaxTextNodeWidth,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Row(
|
children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
FlowySvg(
|
||||||
children: [
|
key: iconKey,
|
||||||
FlowySvg(
|
width: _iconWidth,
|
||||||
key: iconKey,
|
height: _iconWidth,
|
||||||
width: _iconWidth,
|
padding: EdgeInsets.only(right: _iconRightPadding),
|
||||||
height: _iconWidth,
|
number: widget.textNode.attributes.number,
|
||||||
padding: EdgeInsets.only(right: _iconRightPadding),
|
),
|
||||||
number: widget.textNode.attributes.number,
|
Flexible(
|
||||||
|
child: FlowyRichText(
|
||||||
|
key: _richTextKey,
|
||||||
|
placeholderText: 'List',
|
||||||
|
textNode: widget.textNode,
|
||||||
|
editorState: widget.editorState,
|
||||||
),
|
),
|
||||||
Flexible(
|
),
|
||||||
child: FlowyRichText(
|
],
|
||||||
key: _richTextKey,
|
|
||||||
placeholderText: 'List',
|
|
||||||
textNode: widget.textNode,
|
|
||||||
editorState: widget.editorState,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,30 +55,27 @@ class _QuotedTextNodeWidgetState extends State<QuotedTextNodeWidget>
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SizedBox(
|
return Padding(
|
||||||
width: defaultMaxTextNodeWidth,
|
padding: EdgeInsets.only(bottom: defaultLinePadding),
|
||||||
child: Padding(
|
child: IntrinsicHeight(
|
||||||
padding: EdgeInsets.only(bottom: defaultLinePadding),
|
child: Row(
|
||||||
child: IntrinsicHeight(
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
child: Row(
|
children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
FlowySvg(
|
||||||
children: [
|
key: iconKey,
|
||||||
FlowySvg(
|
width: _iconWidth,
|
||||||
key: iconKey,
|
padding: EdgeInsets.only(right: _iconRightPadding),
|
||||||
width: _iconWidth,
|
name: 'quote',
|
||||||
padding: EdgeInsets.only(right: _iconRightPadding),
|
),
|
||||||
name: 'quote',
|
Flexible(
|
||||||
|
child: FlowyRichText(
|
||||||
|
key: _richTextKey,
|
||||||
|
placeholderText: 'Quote',
|
||||||
|
textNode: widget.textNode,
|
||||||
|
editorState: widget.editorState,
|
||||||
),
|
),
|
||||||
Flexible(
|
),
|
||||||
child: FlowyRichText(
|
],
|
||||||
key: _richTextKey,
|
|
||||||
placeholderText: 'Quote',
|
|
||||||
textNode: widget.textNode,
|
|
||||||
editorState: widget.editorState,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -52,15 +52,12 @@ class _RichTextNodeWidgetState extends State<RichTextNodeWidget>
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Padding(
|
||||||
constraints: BoxConstraints(maxWidth: defaultMaxTextNodeWidth),
|
padding: EdgeInsets.only(bottom: defaultLinePadding),
|
||||||
child: Padding(
|
child: FlowyRichText(
|
||||||
padding: EdgeInsets.only(bottom: defaultLinePadding),
|
key: _richTextKey,
|
||||||
child: FlowyRichText(
|
textNode: widget.textNode,
|
||||||
key: _richTextKey,
|
editorState: widget.editorState,
|
||||||
textNode: widget.textNode,
|
|
||||||
editorState: widget.editorState,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,6 @@ class StyleKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: customize
|
// TODO: customize
|
||||||
double defaultMaxTextNodeWidth = 780.0;
|
|
||||||
double defaultLinePadding = 8.0;
|
double defaultLinePadding = 8.0;
|
||||||
double baseFontSize = 16.0;
|
double baseFontSize = 16.0;
|
||||||
String defaultHighlightColor = '0x6000BCF0';
|
String defaultHighlightColor = '0x6000BCF0';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Editor style configuration
|
||||||
|
class EditorStyle {
|
||||||
|
const EditorStyle({
|
||||||
|
required this.padding,
|
||||||
|
});
|
||||||
|
|
||||||
|
const EditorStyle.defaultStyle()
|
||||||
|
: padding = const EdgeInsets.fromLTRB(200.0, 0.0, 200.0, 0.0);
|
||||||
|
|
||||||
|
/// The margin of the document context from the editor.
|
||||||
|
final EdgeInsets padding;
|
||||||
|
|
||||||
|
EditorStyle copyWith({EdgeInsets? padding}) {
|
||||||
|
return EditorStyle(
|
||||||
|
padding: padding ?? this.padding,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:appflowy_editor/src/render/image/image_node_builder.dart';
|
import 'package:appflowy_editor/src/render/image/image_node_builder.dart';
|
||||||
import 'package:appflowy_editor/src/render/selection_menu/selection_menu_widget.dart';
|
import 'package:appflowy_editor/src/render/selection_menu/selection_menu_widget.dart';
|
||||||
|
import 'package:appflowy_editor/src/render/style/editor_style.dart';
|
||||||
import 'package:appflowy_editor/src/service/internal_key_event_handlers/default_key_event_handlers.dart';
|
import 'package:appflowy_editor/src/service/internal_key_event_handlers/default_key_event_handlers.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
@ -36,6 +37,7 @@ class AppFlowyEditor extends StatefulWidget {
|
||||||
this.customBuilders = const {},
|
this.customBuilders = const {},
|
||||||
this.keyEventHandlers = const [],
|
this.keyEventHandlers = const [],
|
||||||
this.selectionMenuItems = const [],
|
this.selectionMenuItems = const [],
|
||||||
|
this.editorStyle = const EditorStyle.defaultStyle(),
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final EditorState editorState;
|
final EditorState editorState;
|
||||||
|
|
@ -48,6 +50,8 @@ class AppFlowyEditor extends StatefulWidget {
|
||||||
|
|
||||||
final List<SelectionMenuItem> selectionMenuItems;
|
final List<SelectionMenuItem> selectionMenuItems;
|
||||||
|
|
||||||
|
final EditorStyle editorStyle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AppFlowyEditor> createState() => _AppFlowyEditorState();
|
State<AppFlowyEditor> createState() => _AppFlowyEditorState();
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +64,7 @@ class _AppFlowyEditorState extends State<AppFlowyEditor> {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
editorState.selectionMenuItems = widget.selectionMenuItems;
|
editorState.selectionMenuItems = widget.selectionMenuItems;
|
||||||
|
editorState.editorStyle = widget.editorStyle;
|
||||||
editorState.service.renderPluginService = _createRenderPlugin();
|
editorState.service.renderPluginService = _createRenderPlugin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,6 +73,8 @@ class _AppFlowyEditorState extends State<AppFlowyEditor> {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
|
|
||||||
if (editorState.service != oldWidget.editorState.service) {
|
if (editorState.service != oldWidget.editorState.service) {
|
||||||
|
editorState.selectionMenuItems = widget.selectionMenuItems;
|
||||||
|
editorState.editorStyle = widget.editorStyle;
|
||||||
editorState.service.renderPluginService = _createRenderPlugin();
|
editorState.service.renderPluginService = _createRenderPlugin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -76,27 +83,31 @@ class _AppFlowyEditorState extends State<AppFlowyEditor> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppFlowyScroll(
|
return AppFlowyScroll(
|
||||||
key: editorState.service.scrollServiceKey,
|
key: editorState.service.scrollServiceKey,
|
||||||
child: AppFlowySelection(
|
child: Padding(
|
||||||
key: editorState.service.selectionServiceKey,
|
padding: widget.editorStyle.padding,
|
||||||
editorState: editorState,
|
child: AppFlowySelection(
|
||||||
child: AppFlowyInput(
|
key: editorState.service.selectionServiceKey,
|
||||||
key: editorState.service.inputServiceKey,
|
|
||||||
editorState: editorState,
|
editorState: editorState,
|
||||||
child: AppFlowyKeyboard(
|
child: AppFlowyInput(
|
||||||
key: editorState.service.keyboardServiceKey,
|
key: editorState.service.inputServiceKey,
|
||||||
handlers: [
|
|
||||||
...defaultKeyEventHandlers,
|
|
||||||
...widget.keyEventHandlers,
|
|
||||||
],
|
|
||||||
editorState: editorState,
|
editorState: editorState,
|
||||||
child: FlowyToolbar(
|
child: AppFlowyKeyboard(
|
||||||
key: editorState.service.toolbarServiceKey,
|
key: editorState.service.keyboardServiceKey,
|
||||||
|
handlers: [
|
||||||
|
...defaultKeyEventHandlers,
|
||||||
|
...widget.keyEventHandlers,
|
||||||
|
],
|
||||||
editorState: editorState,
|
editorState: editorState,
|
||||||
child: editorState.service.renderPluginService.buildPluginWidget(
|
child: FlowyToolbar(
|
||||||
NodeWidgetContext(
|
key: editorState.service.toolbarServiceKey,
|
||||||
context: context,
|
editorState: editorState,
|
||||||
node: editorState.document.root,
|
child:
|
||||||
editorState: editorState,
|
editorState.service.renderPluginService.buildPluginWidget(
|
||||||
|
NodeWidgetContext(
|
||||||
|
context: context,
|
||||||
|
node: editorState.document.root,
|
||||||
|
editorState: editorState,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,10 @@ void main() async {
|
||||||
final editorRect = tester.getRect(editorFinder);
|
final editorRect = tester.getRect(editorFinder);
|
||||||
|
|
||||||
final leftImageRect = tester.getRect(imageFinder.at(0));
|
final leftImageRect = tester.getRect(imageFinder.at(0));
|
||||||
expect(leftImageRect.left, editorRect.left);
|
expect(leftImageRect.left, editor.editorState.editorStyle.padding.left);
|
||||||
final rightImageRect = tester.getRect(imageFinder.at(2));
|
final rightImageRect = tester.getRect(imageFinder.at(2));
|
||||||
expect(rightImageRect.right, editorRect.right);
|
expect(rightImageRect.right,
|
||||||
|
editorRect.right - editor.editorState.editorStyle.padding.right);
|
||||||
final centerImageRect = tester.getRect(imageFinder.at(1));
|
final centerImageRect = tester.getRect(imageFinder.at(1));
|
||||||
expect(centerImageRect.left,
|
expect(centerImageRect.left,
|
||||||
(leftImageRect.left + rightImageRect.left) / 2.0);
|
(leftImageRect.left + rightImageRect.left) / 2.0);
|
||||||
|
|
@ -73,8 +74,8 @@ void main() async {
|
||||||
leftImage.onAlign(Alignment.centerRight);
|
leftImage.onAlign(Alignment.centerRight);
|
||||||
await tester.pump(const Duration(milliseconds: 100));
|
await tester.pump(const Duration(milliseconds: 100));
|
||||||
expect(
|
expect(
|
||||||
tester.getRect(imageFinder.at(0)).left,
|
tester.getRect(imageFinder.at(0)).right,
|
||||||
rightImageRect.left,
|
rightImageRect.right,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue