mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge pull request #610 from LucasXu0/feat/flowy_editor
chore: (draft) support text node widget editing
This commit is contained in:
commit
b859e2a252
@ -1,5 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flowy_editor/flowy_editor.dart';
|
import 'package:flowy_editor/flowy_editor.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class TextNodeBuilder extends NodeWidgetBuilder {
|
class TextNodeBuilder extends NodeWidgetBuilder {
|
||||||
TextNodeBuilder.create({
|
TextNodeBuilder.create({
|
||||||
@ -11,41 +13,7 @@ class TextNodeBuilder extends NodeWidgetBuilder {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext buildContext) {
|
Widget build(BuildContext buildContext) {
|
||||||
final richText = SelectableText.rich(
|
return _TextNodeWidget(node: node, editorState: editorState);
|
||||||
TextSpan(
|
|
||||||
text: node.attributes['content'] as String,
|
|
||||||
style: node.attributes.toTextStyle(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget? children;
|
|
||||||
if (node.children.isNotEmpty) {
|
|
||||||
children = Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: node.children
|
|
||||||
.map(
|
|
||||||
(e) => renderPlugins.buildWidget(
|
|
||||||
context: NodeWidgetContext(
|
|
||||||
buildContext: buildContext,
|
|
||||||
node: e,
|
|
||||||
editorState: editorState,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (children != null) {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
richText,
|
|
||||||
children,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return richText;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,3 +25,141 @@ extension on Attributes {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _TextNodeWidget extends StatefulWidget {
|
||||||
|
final Node node;
|
||||||
|
final EditorState editorState;
|
||||||
|
|
||||||
|
const _TextNodeWidget({
|
||||||
|
Key? key,
|
||||||
|
required this.node,
|
||||||
|
required this.editorState,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_TextNodeWidget> createState() => __TextNodeWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class __TextNodeWidgetState extends State<_TextNodeWidget>
|
||||||
|
implements TextInputClient {
|
||||||
|
Node get node => widget.node;
|
||||||
|
EditorState get editorState => widget.editorState;
|
||||||
|
String get content => node.attributes['content'] as String;
|
||||||
|
TextEditingValue get textEditingValue => TextEditingValue(text: content);
|
||||||
|
|
||||||
|
TextInputConnection? _textInputConnection;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final editableRichText = ChangeNotifierProvider.value(
|
||||||
|
value: node,
|
||||||
|
builder: (_, __) => Consumer<Node>(
|
||||||
|
builder: ((context, value, child) => SelectableText.rich(
|
||||||
|
TextSpan(
|
||||||
|
text: content,
|
||||||
|
style: node.attributes.toTextStyle(),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
_textInputConnection?.close();
|
||||||
|
_textInputConnection = TextInput.attach(
|
||||||
|
this,
|
||||||
|
const TextInputConfiguration(
|
||||||
|
enableDeltaModel: false,
|
||||||
|
inputType: TextInputType.multiline,
|
||||||
|
textCapitalization: TextCapitalization.sentences,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
_textInputConnection
|
||||||
|
?..show()
|
||||||
|
..setEditingState(textEditingValue);
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final child = Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
editableRichText,
|
||||||
|
if (node.children.isNotEmpty)
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: node.children
|
||||||
|
.map(
|
||||||
|
(e) => editorState.renderPlugins.buildWidget(
|
||||||
|
context: NodeWidgetContext(
|
||||||
|
buildContext: context,
|
||||||
|
node: e,
|
||||||
|
editorState: editorState,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void connectionClosed() {
|
||||||
|
// TODO: implement connectionClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement currentAutofillScope
|
||||||
|
AutofillScope? get currentAutofillScope => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement currentTextEditingValue
|
||||||
|
TextEditingValue? get currentTextEditingValue => textEditingValue;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void insertTextPlaceholder(Size size) {
|
||||||
|
// TODO: implement insertTextPlaceholder
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void performAction(TextInputAction action) {
|
||||||
|
// TODO: implement performAction
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void performPrivateCommand(String action, Map<String, dynamic> data) {
|
||||||
|
// TODO: implement performPrivateCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void removeTextPlaceholder() {
|
||||||
|
// TODO: implement removeTextPlaceholder
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void showAutocorrectionPromptRect(int start, int end) {
|
||||||
|
// TODO: implement showAutocorrectionPromptRect
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void showToolbar() {
|
||||||
|
// TODO: implement showToolbar
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void updateEditingValue(TextEditingValue value) {
|
||||||
|
debugPrint(value.text);
|
||||||
|
editorState.update(
|
||||||
|
node,
|
||||||
|
Attributes.from(node.attributes)
|
||||||
|
..addAll(
|
||||||
|
{
|
||||||
|
'content': value.text,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void updateFloatingCursor(RawFloatingCursorPoint point) {
|
||||||
|
// TODO: implement updateFloatingCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -29,6 +29,7 @@ class Node extends ChangeNotifier with LinkedListEntry<Node> {
|
|||||||
factory Node.fromJson(Map<String, Object> json) {
|
factory Node.fromJson(Map<String, Object> json) {
|
||||||
assert(json['type'] is String);
|
assert(json['type'] is String);
|
||||||
|
|
||||||
|
// TODO: check the type that not exist on plugins.
|
||||||
final jType = json['type'] as String;
|
final jType = json['type'] as String;
|
||||||
final jChildren = json['children'] as List?;
|
final jChildren = json['children'] as List?;
|
||||||
final jAttributes = json['attributes'] != null
|
final jAttributes = json['attributes'] != null
|
||||||
|
Loading…
Reference in New Issue
Block a user