save doc & switch doc

This commit is contained in:
appflowy 2021-07-24 22:27:24 +08:00
parent 7b1e5aaba2
commit 29f5f1ac27
11 changed files with 221 additions and 229 deletions

View File

@ -40,7 +40,7 @@ class ApplicationBlocObserver extends BlocObserver {
@override
// ignore: unnecessary_overrides
void onTransition(Bloc bloc, Transition transition) {
// Log.debug(transition);
Log.debug(transition);
super.onTransition(bloc, transition);
}
@ -50,9 +50,3 @@ class ApplicationBlocObserver extends BlocObserver {
super.onError(bloc, error, stackTrace);
}
}
class EngineBlocConfig {
static void setup() {
Bloc.observer = ApplicationBlocObserver();
}
}

View File

@ -14,7 +14,6 @@ class DocBloc extends Bloc<DocEvent, DocState> {
Stream<DocState> mapEventToState(DocEvent event) async* {
yield* event.map(
initial: (e) async* {},
save: (Save value) async* {},
close: (Close value) async* {},
);
}
@ -23,7 +22,6 @@ class DocBloc extends Bloc<DocEvent, DocState> {
@freezed
abstract class DocEvent with _$DocEvent {
const factory DocEvent.initial() = Initial;
const factory DocEvent.save(String jsonStr) = Save;
const factory DocEvent.close() = Close;
}

View File

@ -20,12 +20,6 @@ class _$DocEventTearOff {
return const Initial();
}
Save save(String jsonStr) {
return Save(
jsonStr,
);
}
Close close() {
return const Close();
}
@ -39,14 +33,12 @@ mixin _$DocEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(String jsonStr) save,
required TResult Function() close,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(String jsonStr)? save,
TResult Function()? close,
required TResult orElse(),
}) =>
@ -54,14 +46,12 @@ mixin _$DocEvent {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(Save value) save,
required TResult Function(Close value) close,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(Save value)? save,
TResult Function(Close value)? close,
required TResult orElse(),
}) =>
@ -121,7 +111,6 @@ class _$Initial implements Initial {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(String jsonStr) save,
required TResult Function() close,
}) {
return initial();
@ -131,7 +120,6 @@ class _$Initial implements Initial {
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(String jsonStr)? save,
TResult Function()? close,
required TResult orElse(),
}) {
@ -145,7 +133,6 @@ class _$Initial implements Initial {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(Save value) save,
required TResult Function(Close value) close,
}) {
return initial(this);
@ -155,7 +142,6 @@ class _$Initial implements Initial {
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(Save value)? save,
TResult Function(Close value)? close,
required TResult orElse(),
}) {
@ -170,122 +156,6 @@ abstract class Initial implements DocEvent {
const factory Initial() = _$Initial;
}
/// @nodoc
abstract class $SaveCopyWith<$Res> {
factory $SaveCopyWith(Save value, $Res Function(Save) then) =
_$SaveCopyWithImpl<$Res>;
$Res call({String jsonStr});
}
/// @nodoc
class _$SaveCopyWithImpl<$Res> extends _$DocEventCopyWithImpl<$Res>
implements $SaveCopyWith<$Res> {
_$SaveCopyWithImpl(Save _value, $Res Function(Save) _then)
: super(_value, (v) => _then(v as Save));
@override
Save get _value => super._value as Save;
@override
$Res call({
Object? jsonStr = freezed,
}) {
return _then(Save(
jsonStr == freezed
? _value.jsonStr
: jsonStr // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$Save implements Save {
const _$Save(this.jsonStr);
@override
final String jsonStr;
@override
String toString() {
return 'DocEvent.save(jsonStr: $jsonStr)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is Save &&
(identical(other.jsonStr, jsonStr) ||
const DeepCollectionEquality().equals(other.jsonStr, jsonStr)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(jsonStr);
@JsonKey(ignore: true)
@override
$SaveCopyWith<Save> get copyWith =>
_$SaveCopyWithImpl<Save>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(String jsonStr) save,
required TResult Function() close,
}) {
return save(jsonStr);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(String jsonStr)? save,
TResult Function()? close,
required TResult orElse(),
}) {
if (save != null) {
return save(jsonStr);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(Save value) save,
required TResult Function(Close value) close,
}) {
return save(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(Save value)? save,
TResult Function(Close value)? close,
required TResult orElse(),
}) {
if (save != null) {
return save(this);
}
return orElse();
}
}
abstract class Save implements DocEvent {
const factory Save(String jsonStr) = _$Save;
String get jsonStr => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$SaveCopyWith<Save> get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CloseCopyWith<$Res> {
factory $CloseCopyWith(Close value, $Res Function(Close) then) =
@ -324,7 +194,6 @@ class _$Close implements Close {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(String jsonStr) save,
required TResult Function() close,
}) {
return close();
@ -334,7 +203,6 @@ class _$Close implements Close {
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(String jsonStr)? save,
TResult Function()? close,
required TResult orElse(),
}) {
@ -348,7 +216,6 @@ class _$Close implements Close {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(Save value) save,
required TResult Function(Close value) close,
}) {
return close(this);
@ -358,7 +225,6 @@ class _$Close implements Close {
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(Save value)? save,
TResult Function(Close value)? close,
required TResult orElse(),
}) {

View File

@ -63,7 +63,8 @@ List<Widget> _buildStackWidget(HomeStackView stackView) {
case ViewType.Blank:
return BlankPage(stackView: stackView as BlankStackView);
case ViewType.Doc:
return DocPage(stackView: stackView as DocPageStackView);
final docView = stackView as DocPageStackView;
return DocPage(key: ValueKey(docView.view.id), stackView: docView);
default:
return BlankPage(stackView: stackView as BlankStackView);
}

View File

@ -15,6 +15,7 @@ import 'package:app_flowy/workspace/infrastructure/repos/app_repo.dart';
import 'package:app_flowy/workspace/infrastructure/repos/doc_repo.dart';
import 'package:app_flowy/workspace/infrastructure/repos/view_repo.dart';
import 'package:app_flowy/workspace/infrastructure/repos/workspace_repo.dart';
import 'package:flowy_editor/flowy_editor.dart';
import 'package:get_it/get_it.dart';
import 'i_view_impl.dart';
@ -66,6 +67,9 @@ class HomeDepsResolver {
getIt.registerFactoryParam<DocBloc, String, void>(
(docId, _) => DocBloc(getIt<IDoc>(param1: docId)));
// editor
getIt.registerFactoryParam<EditorPersistence, String, void>(
(docId, _) => EditorPersistenceImpl(repo: DocRepository(docId: docId)));
// getIt.registerFactoryParam<ViewBloc, String, void>(
// (viewId, _) => ViewBloc(iViewImpl: getIt<IView>(param1: viewId)));
}

View File

@ -1,10 +1,11 @@
import 'dart:convert';
import 'package:dartz/dartz.dart';
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flowy_sdk/protobuf/flowy-editor/errors.pb.dart';
import 'package:app_flowy/workspace/domain/i_doc.dart';
import 'package:app_flowy/workspace/infrastructure/repos/doc_repo.dart';
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flowy_sdk/protobuf/flowy-editor/errors.pb.dart';
import 'package:dartz/dartz.dart';
class IDocImpl extends IDoc {
DocRepository repo;
@ -49,3 +50,21 @@ class IDocImpl extends IDoc {
return document;
}
}
class EditorPersistenceImpl extends EditorPersistence {
DocRepository repo;
EditorPersistenceImpl({
required this.repo,
});
@override
Future<bool> save(List<dynamic> jsonList) async {
final json = jsonEncode(jsonList);
return repo.updateDoc(text: json).then((result) {
return result.fold(
(l) => true,
(r) => false,
);
});
}
}

View File

@ -36,6 +36,21 @@ class _DocPageState extends State<DocPage> {
}),
);
}
@override
void dispose() {
super.dispose();
}
@override
void deactivate() {
super.deactivate();
}
@override
void didUpdateWidget(covariant DocPage oldWidget) {
super.didUpdateWidget(oldWidget);
}
}
class DocPageStackView extends HomeStackView {

View File

@ -16,6 +16,7 @@ class EditorWdiget extends StatelessWidget {
controller = EditorController(
document: doc.data,
selection: const TextSelection.collapsed(offset: 0),
persistence: getIt<EditorPersistence>(param1: doc.info.id),
);
}
@ -23,12 +24,16 @@ class EditorWdiget extends StatelessWidget {
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => getIt<DocBloc>(param1: doc.info.id),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_renderEditor(controller),
_renderToolbar(controller),
],
child: BlocBuilder<DocBloc, DocState>(
builder: (ctx, state) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_renderEditor(controller),
_renderToolbar(controller),
],
);
},
),
);
}

View File

@ -49,4 +49,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c
COCOAPODS: 1.9.3
COCOAPODS: 1.10.1

View File

@ -10,10 +10,16 @@ import '../model/document/document.dart';
import '../model/document/style.dart';
import '../model/document/node/embed.dart';
abstract class EditorPersistence {
Future<bool> save(List<dynamic> jsonList);
}
class EditorController extends ChangeNotifier {
final EditorPersistence? persistence;
EditorController({
required this.document,
required this.selection,
this.persistence,
});
factory EditorController.basic() {
@ -38,7 +44,8 @@ class EditorController extends ChangeNotifier {
);
Style getSelectionStyle() =>
document.collectStyle(selection.start, selection.end - selection.start)..mergeAll(toggledStyle);
document.collectStyle(selection.start, selection.end - selection.start)
..mergeAll(toggledStyle);
bool get hasUndo => document.hasUndo;
@ -58,10 +65,10 @@ class EditorController extends ChangeNotifier {
}
}
Future<bool> save() async {
document.toDelta().toJson();
// TODO: vedon - Save document to database
return true;
void save() {
if (persistence != null) {
persistence!.save(document.toDelta().toJson());
}
}
@override
@ -80,7 +87,9 @@ class EditorController extends ChangeNotifier {
}
void formatText(int index, int length, Attribute? attribute) {
if (length == 0 && attribute!.isInline && attribute.key != Attribute.link.key) {
if (length == 0 &&
attribute!.isInline &&
attribute.key != Attribute.link.key) {
toggledStyle = toggledStyle.put(attribute);
}
@ -95,16 +104,24 @@ class EditorController extends ChangeNotifier {
notifyListeners();
}
void replaceText(int index, int length, Object? data, TextSelection? textSelection) {
void replaceText(
int index, int length, Object? data, TextSelection? textSelection) {
assert(data is String || data is Embeddable);
Delta? delta;
if (length > 0 || data is! String || data.isNotEmpty) {
delta = document.replace(index, length, data);
var shouldRetainDelta = toggledStyle.isNotEmpty && delta.isNotEmpty && delta.length <= 2 && delta.last.isInsert;
if (shouldRetainDelta && toggledStyle.isNotEmpty && delta.length == 2 && delta.last.data == '\n') {
var shouldRetainDelta = toggledStyle.isNotEmpty &&
delta.isNotEmpty &&
delta.length <= 2 &&
delta.last.isInsert;
if (shouldRetainDelta &&
toggledStyle.isNotEmpty &&
delta.length == 2 &&
delta.last.data == '\n') {
// if all attributes are inline, shouldRetainDelta should be false
final anyAttributeNotInline = toggledStyle.values.any((attr) => !attr.isInline);
final anyAttributeNotInline =
toggledStyle.values.any((attr) => !attr.isInline);
shouldRetainDelta &= anyAttributeNotInline;
}
if (shouldRetainDelta) {
@ -146,7 +163,8 @@ class EditorController extends ChangeNotifier {
textSelection = selection.copyWith(
baseOffset: delta.transformPosition(selection.baseOffset, force: false),
extentOffset: delta.transformPosition(selection.extentOffset, force: false),
extentOffset:
delta.transformPosition(selection.extentOffset, force: false),
);
if (selection != textSelection) {
_updateSelection(textSelection, source);

View File

@ -60,7 +60,8 @@ class RawEditor extends StatefulWidget {
this.embedBuilder,
) : assert(maxHeight == null || maxHeight > 0, 'maxHeight cannot be null'),
assert(minHeight == null || minHeight >= 0, 'minHeight cannot be null'),
assert(maxHeight == null || minHeight == null || maxHeight >= minHeight),
assert(
maxHeight == null || minHeight == null || maxHeight >= minHeight),
showCursor = showCursor ?? true,
super(key: key);
@ -111,7 +112,10 @@ abstract class EditorState extends State<RawEditor> {
}
class _RawEditorState extends EditorState
with AutomaticKeepAliveClientMixin<RawEditor>, WidgetsBindingObserver, TickerProviderStateMixin<RawEditor>
with
AutomaticKeepAliveClientMixin<RawEditor>,
WidgetsBindingObserver,
TickerProviderStateMixin<RawEditor>
implements TextSelectionDelegate, TextInputClient {
final GlobalKey _editorKey = GlobalKey();
final List<TextEditingValue> _sentRemoteValues = [];
@ -129,7 +133,8 @@ class _RawEditorState extends EditorState
bool _didAutoFocus = false;
bool _keyboardVisible = false;
DefaultStyles? _styles;
final ClipboardStatusNotifier? _clipboardStatus = kIsWeb ? null : ClipboardStatusNotifier();
final ClipboardStatusNotifier? _clipboardStatus =
kIsWeb ? null : ClipboardStatusNotifier();
final LayerLink _toolbarLayerLink = LayerLink();
final LayerLink _startHandleLayerLink = LayerLink();
final LayerLink _endHandleLayerLink = LayerLink();
@ -177,57 +182,78 @@ class _RawEditorState extends EditorState
downKey = key == LogicalKeyboardKey.arrowDown;
if ((rightKey || leftKey) && !(rightKey && leftKey)) {
newSelection =
_jumpToBeginOrEndOfWord(newSelection, wordModifier, leftKey, rightKey, plainText, lineModifier, shift);
newSelection = _jumpToBeginOrEndOfWord(newSelection, wordModifier,
leftKey, rightKey, plainText, lineModifier, shift);
}
if (downKey || upKey) {
newSelection = _handleMovingCursorVertically(upKey, downKey, shift, selection, newSelection, plainText);
newSelection = _handleMovingCursorVertically(
upKey, downKey, shift, selection, newSelection, plainText);
}
if (!shift) {
newSelection = _placeCollapsedSelection(selection, newSelection, leftKey, rightKey);
newSelection =
_placeCollapsedSelection(selection, newSelection, leftKey, rightKey);
}
widget.controller.updateSelection(newSelection, ChangeSource.LOCAL);
}
TextSelection _placeCollapsedSelection(
TextSelection selection, TextSelection newSelection, bool leftKey, bool rightKey) {
TextSelection _placeCollapsedSelection(TextSelection selection,
TextSelection newSelection, bool leftKey, bool rightKey) {
var newOffset = newSelection.extentOffset;
if (!selection.isCollapsed) {
if (leftKey) {
newOffset =
newSelection.baseOffset < newSelection.extentOffset ? newSelection.baseOffset : newSelection.extentOffset;
newOffset = newSelection.baseOffset < newSelection.extentOffset
? newSelection.baseOffset
: newSelection.extentOffset;
} else if (rightKey) {
newOffset =
newSelection.baseOffset > newSelection.extentOffset ? newSelection.baseOffset : newSelection.extentOffset;
newOffset = newSelection.baseOffset > newSelection.extentOffset
? newSelection.baseOffset
: newSelection.extentOffset;
}
}
return TextSelection.fromPosition(TextPosition(offset: newOffset));
}
TextSelection _handleMovingCursorVertically(
bool upKey, bool downKey, bool shift, TextSelection selection, TextSelection newSelection, String plainText) {
final originPosition = TextPosition(offset: upKey ? selection.baseOffset : selection.extentOffset);
bool upKey,
bool downKey,
bool shift,
TextSelection selection,
TextSelection newSelection,
String plainText) {
final originPosition = TextPosition(
offset: upKey ? selection.baseOffset : selection.extentOffset);
final child = getRenderEditor()!.childAtPosition(originPosition);
final localPosition = TextPosition(offset: originPosition.offset - child.container.documentOffset);
final localPosition = TextPosition(
offset: originPosition.offset - child.container.documentOffset);
var position = upKey ? child.getPositionAbove(localPosition) : child.getPositionBelow(localPosition);
var position = upKey
? child.getPositionAbove(localPosition)
: child.getPositionBelow(localPosition);
if (position == null) {
final sibling = upKey ? getRenderEditor()!.childBefore(child) : getRenderEditor()!.childAfter(child);
final sibling = upKey
? getRenderEditor()!.childBefore(child)
: getRenderEditor()!.childAfter(child);
if (sibling == null) {
position = TextPosition(offset: upKey ? 0 : plainText.length - 1);
} else {
final finalOffset = Offset(child.getOffsetForCaret(localPosition).dx,
sibling.getOffsetForCaret(TextPosition(offset: upKey ? sibling.container.length - 1 : 0)).dy);
final finalOffset = Offset(
child.getOffsetForCaret(localPosition).dx,
sibling
.getOffsetForCaret(TextPosition(
offset: upKey ? sibling.container.length - 1 : 0))
.dy);
final siblingPosition = sibling.getPositionForOffset(finalOffset);
position = TextPosition(offset: sibling.container.documentOffset + siblingPosition.offset);
position = TextPosition(
offset: sibling.container.documentOffset + siblingPosition.offset);
}
} else {
position = TextPosition(offset: child.container.documentOffset + position.offset);
position = TextPosition(
offset: child.container.documentOffset + position.offset);
}
if (position.offset == newSelection.extentOffset) {
@ -250,33 +276,47 @@ class _RawEditorState extends EditorState
return newSelection;
}
TextSelection _jumpToBeginOrEndOfWord(TextSelection newSelection, bool wordModifier, bool leftKey, bool rightKey,
String plainText, bool lineModifier, bool shift) {
TextSelection _jumpToBeginOrEndOfWord(
TextSelection newSelection,
bool wordModifier,
bool leftKey,
bool rightKey,
String plainText,
bool lineModifier,
bool shift) {
if (wordModifier) {
if (leftKey) {
final textSelection = getRenderEditor()!.selectWordAtPosition(
TextPosition(offset: _previousCharacter(newSelection.extentOffset, plainText, false)));
TextPosition(
offset: _previousCharacter(
newSelection.extentOffset, plainText, false)));
return newSelection.copyWith(extentOffset: textSelection.baseOffset);
}
final textSelection = getRenderEditor()!
.selectWordAtPosition(TextPosition(offset: _nextCharacter(newSelection.extentOffset, plainText, false)));
final textSelection = getRenderEditor()!.selectWordAtPosition(
TextPosition(
offset:
_nextCharacter(newSelection.extentOffset, plainText, false)));
return newSelection.copyWith(extentOffset: textSelection.extentOffset);
} else if (lineModifier) {
if (leftKey) {
final textSelection = getRenderEditor()!.selectLineAtPosition(
TextPosition(offset: _previousCharacter(newSelection.extentOffset, plainText, false)));
TextPosition(
offset: _previousCharacter(
newSelection.extentOffset, plainText, false)));
return newSelection.copyWith(extentOffset: textSelection.baseOffset);
}
final startPoint = newSelection.extentOffset;
if (startPoint < plainText.length) {
final textSelection = getRenderEditor()!.selectLineAtPosition(TextPosition(offset: startPoint));
final textSelection = getRenderEditor()!
.selectLineAtPosition(TextPosition(offset: startPoint));
return newSelection.copyWith(extentOffset: textSelection.extentOffset);
}
return newSelection;
}
if (rightKey && newSelection.extentOffset < plainText.length) {
final nextExtent = _nextCharacter(newSelection.extentOffset, plainText, true);
final nextExtent =
_nextCharacter(newSelection.extentOffset, plainText, true);
final distance = nextExtent - newSelection.extentOffset;
newSelection = newSelection.copyWith(extentOffset: nextExtent);
if (shift) {
@ -286,7 +326,8 @@ class _RawEditorState extends EditorState
}
if (leftKey && newSelection.extentOffset > 0) {
final previousExtent = _previousCharacter(newSelection.extentOffset, plainText, true);
final previousExtent =
_previousCharacter(newSelection.extentOffset, plainText, true);
final distance = newSelection.extentOffset - previousExtent;
newSelection = newSelection.copyWith(extentOffset: previousExtent);
if (shift) {
@ -326,7 +367,9 @@ class _RawEditorState extends EditorState
var count = 0;
int? lastNonWhitespace;
for (final currentString in string.characters) {
if (!includeWhitespace && !WHITE_SPACE.contains(currentString.characters.first.toString().codeUnitAt(0))) {
if (!includeWhitespace &&
!WHITE_SPACE.contains(
currentString.characters.first.toString().codeUnitAt(0))) {
lastNonWhitespace = count;
}
if (count + currentString.length >= index) {
@ -337,7 +380,8 @@ class _RawEditorState extends EditorState
return 0;
}
bool get hasConnection => _textInputConnection != null && _textInputConnection!.attached;
bool get hasConnection =>
_textInputConnection != null && _textInputConnection!.attached;
void openConnectionIfNeeded() {
if (!shouldCreateInputConnection) {
@ -388,7 +432,8 @@ class _RawEditorState extends EditorState
return;
}
final shouldRemember = textEditingValue.text != _lastKnownRemoteTextEditingValue!.text;
final shouldRemember =
textEditingValue.text != _lastKnownRemoteTextEditingValue!.text;
_lastKnownRemoteTextEditingValue = actualValue;
_textInputConnection!.setEditingState(actualValue);
if (shouldRemember) {
@ -397,7 +442,8 @@ class _RawEditorState extends EditorState
}
@override
TextEditingValue? get currentTextEditingValue => _lastKnownRemoteTextEditingValue;
TextEditingValue? get currentTextEditingValue =>
_lastKnownRemoteTextEditingValue;
@override
AutofillScope? get currentAutofillScope => null;
@ -429,7 +475,8 @@ class _RawEditorState extends EditorState
final text = value.text;
final cursorPosition = value.selection.extentOffset;
final diff = getDiff(oldText, text, cursorPosition);
widget.controller.replaceText(diff.start, diff.deleted.length, diff.inserted, value.selection);
widget.controller.replaceText(
diff.start, diff.deleted.length, diff.inserted, value.selection);
}
@override
@ -479,8 +526,11 @@ class _RawEditorState extends EditorState
super.build(context);
var _doc = widget.controller.document;
if (_doc.isEmpty() && !widget.focusNode.hasFocus && widget.placeholder != null) {
_doc = Document.fromJson(jsonDecode('[{"attributes":{"placeholder":true},"insert":"${widget.placeholder}\\n"}]'));
if (_doc.isEmpty() &&
!widget.focusNode.hasFocus &&
widget.placeholder != null) {
_doc = Document.fromJson(jsonDecode(
'[{"attributes":{"placeholder":true},"insert":"${widget.placeholder}\\n"}]'));
}
Widget child = CompositedTransformTarget(
@ -503,7 +553,8 @@ class _RawEditorState extends EditorState
);
if (widget.scrollable) {
final baselinePadding = EdgeInsets.only(top: _styles!.paragraph!.verticalSpacing.item1);
final baselinePadding =
EdgeInsets.only(top: _styles!.paragraph!.verticalSpacing.item1);
child = BaselineProxy(
textStyle: _styles!.paragraph!.style,
padding: baselinePadding,
@ -534,7 +585,8 @@ class _RawEditorState extends EditorState
);
}
void _handleSelectionChanged(TextSelection selection, SelectionChangedCause cause) {
void _handleSelectionChanged(
TextSelection selection, SelectionChangedCause cause) {
widget.controller.updateSelection(selection, ChangeSource.LOCAL);
_selectionOverlay?.handlesVisible = _shouldShowSelectionHandles();
@ -563,7 +615,9 @@ class _RawEditorState extends EditorState
_styles,
widget.enableInteractiveSelection,
_hasFocus,
attrs.containsKey(Attribute.codeBlock.key) ? const EdgeInsets.all(16) : null,
attrs.containsKey(Attribute.codeBlock.key)
? const EdgeInsets.all(16)
: null,
widget.embedBuilder,
_cursorController,
indentLevelCounts);
@ -575,7 +629,8 @@ class _RawEditorState extends EditorState
return result;
}
EditableTextLine _getEditableTextLineFromNode(Line node, BuildContext context) {
EditableTextLine _getEditableTextLineFromNode(
Line node, BuildContext context) {
final textLine = TextLine(
line: node,
textDirection: _textDirection,
@ -598,7 +653,8 @@ class _RawEditorState extends EditorState
return editableTextLine;
}
Tuple2<double, double> _getVerticalSpacingForLine(Line line, DefaultStyles? defaultStyles) {
Tuple2<double, double> _getVerticalSpacingForLine(
Line line, DefaultStyles? defaultStyles) {
final attrs = line.style.attributes;
if (attrs.containsKey(Attribute.header.key)) {
final int? level = attrs[Attribute.header.key]!.value;
@ -623,7 +679,8 @@ class _RawEditorState extends EditorState
return defaultStyles!.paragraph!.verticalSpacing;
}
Tuple2<double, double> _getVerticalSpacingForBlock(Block node, DefaultStyles? defaultStyles) {
Tuple2<double, double> _getVerticalSpacingForBlock(
Block node, DefaultStyles? defaultStyles) {
final attrs = node.style.attributes;
if (attrs.containsKey(Attribute.quoteBlock.key)) {
return defaultStyles!.quote!.verticalSpacing;
@ -666,7 +723,8 @@ class _RawEditorState extends EditorState
} else {
_keyboardVisibilityController = KeyboardVisibilityController();
_keyboardVisible = _keyboardVisibilityController!.isVisible;
_keyboardVisibilitySubscription = _keyboardVisibilityController?.onChange.listen((visible) {
_keyboardVisibilitySubscription =
_keyboardVisibilityController?.onChange.listen((visible) {
_keyboardVisible = visible;
if (visible) {
_onChangeTextEditingValue();
@ -689,7 +747,9 @@ class _RawEditorState extends EditorState
super.didChangeDependencies();
final parentStyles = EditorStyles.getStyles(context, true);
final defaultStyles = DefaultStyles.getInstance(context);
_styles = (parentStyles != null) ? defaultStyles.merge(parentStyles) : defaultStyles;
_styles = (parentStyles != null)
? defaultStyles.merge(parentStyles)
: defaultStyles;
if (widget.customStyles != null) {
_styles = _styles!.merge(widget.customStyles!);
@ -749,7 +809,8 @@ class _RawEditorState extends EditorState
}
bool _shouldShowSelectionHandles() {
return widget.showSelectionHandles && !widget.controller.selection.isCollapsed;
return widget.showSelectionHandles &&
!widget.controller.selection.isCollapsed;
}
void handleDelete(bool forward) {
@ -760,7 +821,8 @@ class _RawEditorState extends EditorState
var textAfter = selection.textAfter(plainText);
if (selection.isCollapsed) {
if (!forward && textBefore.isNotEmpty) {
final characterBoundary = _previousCharacter(textBefore.length, textBefore, true);
final characterBoundary =
_previousCharacter(textBefore.length, textBefore, true);
textBefore = textBefore.substring(0, characterBoundary);
cursorPosition = characterBoundary;
}
@ -784,15 +846,13 @@ class _RawEditorState extends EditorState
final selection = widget.controller.selection;
final plainText = textEditingValue.text;
if (shortcut == InputShortcut.SAVE) {
bool saved = await widget.controller.save();
if (!saved) {
log('Unabled to save document.');
}
widget.controller.save();
return;
}
if (shortcut == InputShortcut.COPY) {
if (!selection.isCollapsed) {
await Clipboard.setData(ClipboardData(text: selection.textInside(plainText)));
await Clipboard.setData(
ClipboardData(text: selection.textInside(plainText)));
}
return;
}
@ -809,7 +869,8 @@ class _RawEditorState extends EditorState
);
textEditingValue = TextEditingValue(
text: selection.textBefore(plainText) + selection.textAfter(plainText),
text:
selection.textBefore(plainText) + selection.textAfter(plainText),
selection: TextSelection.collapsed(offset: selection.start),
);
}
@ -827,7 +888,8 @@ class _RawEditorState extends EditorState
}
return;
}
if (shortcut == InputShortcut.SELECT_ALL && widget.enableInteractiveSelection) {
if (shortcut == InputShortcut.SELECT_ALL &&
widget.enableInteractiveSelection) {
widget.controller.updateSelection(
selection.copyWith(
baseOffset: 0,
@ -881,14 +943,16 @@ class _RawEditorState extends EditorState
void _onChangeTextEditingValue() {
_showCaretOnScreen();
updateRemoteValueIfNeeded();
_cursorController.startOrStopCursorTimerIfNeeded(_hasFocus, widget.controller.selection);
_cursorController.startOrStopCursorTimerIfNeeded(
_hasFocus, widget.controller.selection);
if (hasConnection) {
_cursorController
..stopCursorTimer(resetCharTicks: false)
..startCursorTimer();
}
SchedulerBinding.instance!.addPostFrameCallback((_) => _updateOrDisposeSelectionOverlayIfNeeded());
SchedulerBinding.instance!.addPostFrameCallback(
(_) => _updateOrDisposeSelectionOverlayIfNeeded());
if (mounted) {
setState(() {
// Use widget.controller.value in build()
@ -931,7 +995,8 @@ class _RawEditorState extends EditorState
void _handleFocusChanged() {
openOrCloseConnection();
_cursorController.startOrStopCursorTimerIfNeeded(_hasFocus, widget.controller.selection);
_cursorController.startOrStopCursorTimerIfNeeded(
_hasFocus, widget.controller.selection);
_updateOrDisposeSelectionOverlayIfNeeded();
if (_hasFocus) {
WidgetsBinding.instance!.addObserver(this);
@ -962,7 +1027,8 @@ class _RawEditorState extends EditorState
_showCaretOnScreenScheduled = false;
final viewport = RenderAbstractViewport.of(getRenderEditor())!;
final editorOffset = getRenderEditor()!.localToGlobal(const Offset(0, 0), ancestor: viewport);
final editorOffset = getRenderEditor()!
.localToGlobal(const Offset(0, 0), ancestor: viewport);
final offsetInViewport = _scrollController!.offset + editorOffset.dy;
final offset = getRenderEditor()!.getOffsetToRevealCursor(
@ -1045,7 +1111,8 @@ class _RawEditorState extends EditorState
final value = textEditingValue;
final data = await Clipboard.getData(Clipboard.kTextPlain);
if (data != null) {
final length = textEditingValue.selection.end - textEditingValue.selection.start;
final length =
textEditingValue.selection.end - textEditingValue.selection.start;
widget.controller.replaceText(
value.selection.start,
length,
@ -1054,7 +1121,9 @@ class _RawEditorState extends EditorState
);
// move cursor to the end of pasted text selection
widget.controller.updateSelection(
TextSelection.collapsed(offset: value.selection.start + data.text!.length), ChangeSource.LOCAL);
TextSelection.collapsed(
offset: value.selection.start + data.text!.length),
ChangeSource.LOCAL);
}
}
}
@ -1064,7 +1133,8 @@ class _RawEditorState extends EditorState
if (data == null) {
return false;
}
return textEditingValue.text.length - value.text.length == data.text!.length;
return textEditingValue.text.length - value.text.length ==
data.text!.length;
}
@override
@ -1097,7 +1167,8 @@ class _RawEditorState extends EditorState
}
@override
void userUpdateTextEditingValue(TextEditingValue value, SelectionChangedCause cause) {
void userUpdateTextEditingValue(
TextEditingValue value, SelectionChangedCause cause) {
// TODO: implement userUpdateTextEditingValue
}
}
@ -1147,7 +1218,8 @@ class _Editor extends MultiChildRenderObjectWidget {
}
@override
void updateRenderObject(BuildContext context, covariant RenderEditor renderObject) {
void updateRenderObject(
BuildContext context, covariant RenderEditor renderObject) {
renderObject
..document = document
..container = document.root