[fix]: cursorConnt.color notify the text_line to repaint if it was disposed

pull/427/head
appflowy 4 years ago
parent d1320c4236
commit c929bb1ae3
  1. 200
      lib/src/widgets/text_line.dart

@ -56,16 +56,8 @@ class TextLine extends StatelessWidget {
strutStyle: strutStyle,
textScaleFactor: MediaQuery.textScaleFactorOf(context),
);
return RichTextProxy(
child,
textSpan.style!,
textAlign,
textDirection!,
1,
Localizations.localeOf(context),
strutStyle,
TextWidthBasis.parent,
null);
return RichTextProxy(child, textSpan.style!, textAlign, textDirection!, 1, Localizations.localeOf(context),
strutStyle, TextWidthBasis.parent, null);
}
InlineSpan _getTextSpanForWholeLine(BuildContext context) {
@ -84,8 +76,7 @@ class TextLine extends StatelessWidget {
textNodes = LinkedList<Node>();
}
// Here it should be image
final embed = WidgetSpan(
child: EmbedProxy(embedBuilder(context, child, readOnly)));
final embed = WidgetSpan(child: EmbedProxy(embedBuilder(context, child, readOnly)));
textSpanChildren.add(embed);
continue;
}
@ -115,11 +106,8 @@ class TextLine extends StatelessWidget {
return TextAlign.start;
}
TextSpan _buildTextSpan(DefaultStyles defaultStyles, LinkedList<Node> nodes,
TextStyle lineStyle) {
final children = nodes
.map((node) => _getTextSpanFromNode(defaultStyles, node))
.toList(growable: false);
TextSpan _buildTextSpan(DefaultStyles defaultStyles, LinkedList<Node> nodes, TextStyle lineStyle) {
final children = nodes.map((node) => _getTextSpanFromNode(defaultStyles, node)).toList(growable: false);
return TextSpan(children: children, style: lineStyle);
}
@ -163,8 +151,7 @@ class TextLine extends StatelessWidget {
return textStyle;
}
TextStyle _applyCustomAttributes(
TextStyle textStyle, Map<String, Attribute> attributes) {
TextStyle _applyCustomAttributes(TextStyle textStyle, Map<String, Attribute> attributes) {
if (customStyleBuilder == null) {
return textStyle;
}
@ -200,8 +187,7 @@ class TextLine extends StatelessWidget {
if (color?.value is String) {
textColor = stringToColor(color?.value);
}
res = _merge(res.copyWith(decorationColor: textColor),
s!.copyWith(decorationColor: textColor));
res = _merge(res.copyWith(decorationColor: textColor), s!.copyWith(decorationColor: textColor));
} else {
res = _merge(res, s!);
}
@ -263,9 +249,7 @@ class TextLine extends StatelessWidget {
if (b.decoration != null) {
decorations.add(b.decoration);
}
return a.merge(b).apply(
decoration: TextDecoration.combine(
List.castFrom<dynamic, TextDecoration>(decorations)));
return a.merge(b).apply(decoration: TextDecoration.combine(List.castFrom<dynamic, TextDecoration>(decorations)));
}
}
@ -305,21 +289,12 @@ class EditableTextLine extends RenderObjectWidget {
@override
RenderObject createRenderObject(BuildContext context) {
return RenderEditableTextLine(
line,
textDirection,
textSelection,
enableInteractiveSelection,
hasFocus,
devicePixelRatio,
_getPadding(),
color,
cursorCont);
return RenderEditableTextLine(line, textDirection, textSelection, enableInteractiveSelection, hasFocus,
devicePixelRatio, _getPadding(), color, cursorCont);
}
@override
void updateRenderObject(
BuildContext context, covariant RenderEditableTextLine renderObject) {
void updateRenderObject(BuildContext context, covariant RenderEditableTextLine renderObject) {
renderObject
..setLine(line)
..setPadding(_getPadding())
@ -333,10 +308,7 @@ class EditableTextLine extends RenderObjectWidget {
}
EdgeInsetsGeometry _getPadding() {
return EdgeInsetsDirectional.only(
start: indentWidth,
top: verticalSpacing.item1,
bottom: verticalSpacing.item2);
return EdgeInsetsDirectional.only(start: indentWidth, top: verticalSpacing.item1, bottom: verticalSpacing.item2);
}
}
@ -413,7 +385,7 @@ class RenderEditableTextLine extends RenderEditableBox {
color = c;
if (containsTextSelection()) {
markNeedsPaint();
safeMarkNeedsPaint();
}
}
@ -425,7 +397,7 @@ class RenderEditableTextLine extends RenderEditableBox {
final containsSelection = containsTextSelection();
if (attached && containsCursor()) {
cursorCont.removeListener(markNeedsLayout);
cursorCont.color.removeListener(markNeedsPaint);
cursorCont.color.removeListener(safeMarkNeedsPaint);
}
textSelection = t;
@ -433,11 +405,11 @@ class RenderEditableTextLine extends RenderEditableBox {
_containsCursor = null;
if (attached && containsCursor()) {
cursorCont.addListener(markNeedsLayout);
cursorCont.color.addListener(markNeedsPaint);
cursorCont.color.addListener(safeMarkNeedsPaint);
}
if (containsSelection || containsTextSelection()) {
markNeedsPaint();
safeMarkNeedsPaint();
}
}
@ -478,17 +450,14 @@ class RenderEditableTextLine extends RenderEditableBox {
}
bool containsTextSelection() {
return line.documentOffset <= textSelection.end &&
textSelection.start <= line.documentOffset + line.length - 1;
return line.documentOffset <= textSelection.end && textSelection.start <= line.documentOffset + line.length - 1;
}
bool containsCursor() {
return _containsCursor ??= textSelection.isCollapsed &&
line.containsOffset(textSelection.baseOffset);
return _containsCursor ??= textSelection.isCollapsed && line.containsOffset(textSelection.baseOffset);
}
RenderBox? _updateChild(
RenderBox? old, RenderBox? newChild, TextLineSlot slot) {
RenderBox? _updateChild(RenderBox? old, RenderBox? newChild, TextLineSlot slot) {
if (old != null) {
dropChild(old);
children.remove(slot);
@ -527,46 +496,35 @@ class RenderEditableTextLine extends RenderEditableBox {
}
@override
TextSelectionPoint getExtentEndpointForSelection(
TextSelection textSelection) {
TextSelectionPoint getExtentEndpointForSelection(TextSelection textSelection) {
return _getEndpointForSelection(textSelection, false);
}
TextSelectionPoint _getEndpointForSelection(
TextSelection textSelection, bool first) {
TextSelectionPoint _getEndpointForSelection(TextSelection textSelection, bool first) {
if (textSelection.isCollapsed) {
return TextSelectionPoint(
Offset(0, preferredLineHeight(textSelection.extent)) +
getOffsetForCaret(textSelection.extent),
null);
Offset(0, preferredLineHeight(textSelection.extent)) + getOffsetForCaret(textSelection.extent), null);
}
final boxes = _getBoxes(textSelection);
assert(boxes.isNotEmpty);
final targetBox = first ? boxes.first : boxes.last;
return TextSelectionPoint(
Offset(first ? targetBox.start : targetBox.end, targetBox.bottom),
targetBox.direction);
return TextSelectionPoint(Offset(first ? targetBox.start : targetBox.end, targetBox.bottom), targetBox.direction);
}
@override
TextRange getLineBoundary(TextPosition position) {
final lineDy = getOffsetForCaret(position)
.translate(0, 0.5 * preferredLineHeight(position))
.dy;
final lineBoxes =
_getBoxes(TextSelection(baseOffset: 0, extentOffset: line.length - 1))
.where((element) => element.top < lineDy && element.bottom > lineDy)
.toList(growable: false);
final lineDy = getOffsetForCaret(position).translate(0, 0.5 * preferredLineHeight(position)).dy;
final lineBoxes = _getBoxes(TextSelection(baseOffset: 0, extentOffset: line.length - 1))
.where((element) => element.top < lineDy && element.bottom > lineDy)
.toList(growable: false);
return TextRange(
start:
getPositionForOffset(Offset(lineBoxes.first.left, lineDy)).offset,
start: getPositionForOffset(Offset(lineBoxes.first.left, lineDy)).offset,
end: getPositionForOffset(Offset(lineBoxes.last.right, lineDy)).offset);
}
@override
Offset getOffsetForCaret(TextPosition position) {
return _body!.getOffsetForCaret(position, _caretPrototype) +
(_body!.parentData as BoxParentData).offset;
return _body!.getOffsetForCaret(position, _caretPrototype) + (_body!.parentData as BoxParentData).offset;
}
@override
@ -581,10 +539,8 @@ class RenderEditableTextLine extends RenderEditableBox {
TextPosition? _getPosition(TextPosition textPosition, double dyScale) {
assert(textPosition.offset < line.length);
final offset = getOffsetForCaret(textPosition)
.translate(0, dyScale * preferredLineHeight(textPosition));
if (_body!.size
.contains(offset - (_body!.parentData as BoxParentData).offset)) {
final offset = getOffsetForCaret(textPosition).translate(0, dyScale * preferredLineHeight(textPosition));
if (_body!.size.contains(offset - (_body!.parentData as BoxParentData).offset)) {
return getPositionForOffset(offset);
}
return null;
@ -592,8 +548,7 @@ class RenderEditableTextLine extends RenderEditableBox {
@override
TextPosition getPositionForOffset(Offset offset) {
return _body!.getPositionForOffset(
offset - (_body!.parentData as BoxParentData).offset);
return _body!.getPositionForOffset(offset - (_body!.parentData as BoxParentData).offset);
}
@override
@ -613,9 +568,7 @@ class RenderEditableTextLine extends RenderEditableBox {
double get cursorWidth => cursorCont.style.width;
double get cursorHeight =>
cursorCont.style.height ??
preferredLineHeight(const TextPosition(offset: 0));
double get cursorHeight => cursorCont.style.height ?? preferredLineHeight(const TextPosition(offset: 0));
void _computeCaretPrototype() {
switch (defaultTargetPlatform) {
@ -642,7 +595,7 @@ class RenderEditableTextLine extends RenderEditableBox {
}
if (containsCursor()) {
cursorCont.addListener(markNeedsLayout);
cursorCont.color.addListener(markNeedsPaint);
cursorCont.color.addListener(safeMarkNeedsPaint);
}
}
@ -654,7 +607,7 @@ class RenderEditableTextLine extends RenderEditableBox {
}
if (containsCursor()) {
cursorCont.removeListener(markNeedsLayout);
cursorCont.color.removeListener(markNeedsPaint);
cursorCont.color.removeListener(safeMarkNeedsPaint);
}
}
@ -690,14 +643,8 @@ class RenderEditableTextLine extends RenderEditableBox {
_resolvePadding();
final horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
final leadingWidth = _leading == null
? 0
: _leading!.getMinIntrinsicWidth(height - verticalPadding).ceil();
final bodyWidth = _body == null
? 0
: _body!
.getMinIntrinsicWidth(math.max(0, height - verticalPadding))
.ceil();
final leadingWidth = _leading == null ? 0 : _leading!.getMinIntrinsicWidth(height - verticalPadding).ceil();
final bodyWidth = _body == null ? 0 : _body!.getMinIntrinsicWidth(math.max(0, height - verticalPadding)).ceil();
return horizontalPadding + leadingWidth + bodyWidth;
}
@ -706,14 +653,8 @@ class RenderEditableTextLine extends RenderEditableBox {
_resolvePadding();
final horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
final leadingWidth = _leading == null
? 0
: _leading!.getMaxIntrinsicWidth(height - verticalPadding).ceil();
final bodyWidth = _body == null
? 0
: _body!
.getMaxIntrinsicWidth(math.max(0, height - verticalPadding))
.ceil();
final leadingWidth = _leading == null ? 0 : _leading!.getMaxIntrinsicWidth(height - verticalPadding).ceil();
final bodyWidth = _body == null ? 0 : _body!.getMaxIntrinsicWidth(math.max(0, height - verticalPadding)).ceil();
return horizontalPadding + leadingWidth + bodyWidth;
}
@ -723,9 +664,7 @@ class RenderEditableTextLine extends RenderEditableBox {
final horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
if (_body != null) {
return _body!
.getMinIntrinsicHeight(math.max(0, width - horizontalPadding)) +
verticalPadding;
return _body!.getMinIntrinsicHeight(math.max(0, width - horizontalPadding)) + verticalPadding;
}
return verticalPadding;
}
@ -736,9 +675,7 @@ class RenderEditableTextLine extends RenderEditableBox {
final horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
if (_body != null) {
return _body!
.getMaxIntrinsicHeight(math.max(0, width - horizontalPadding)) +
verticalPadding;
return _body!.getMaxIntrinsicHeight(math.max(0, width - horizontalPadding)) + verticalPadding;
}
return verticalPadding;
}
@ -746,8 +683,7 @@ class RenderEditableTextLine extends RenderEditableBox {
@override
double computeDistanceToActualBaseline(TextBaseline baseline) {
_resolvePadding();
return _body!.getDistanceToActualBaseline(baseline)! +
_resolvedPadding!.top;
return _body!.getDistanceToActualBaseline(baseline)! + _resolvedPadding!.top;
}
@override
@ -767,22 +703,16 @@ class RenderEditableTextLine extends RenderEditableBox {
}
final innerConstraints = constraints.deflate(_resolvedPadding!);
final indentWidth = textDirection == TextDirection.ltr
? _resolvedPadding!.left
: _resolvedPadding!.right;
final indentWidth = textDirection == TextDirection.ltr ? _resolvedPadding!.left : _resolvedPadding!.right;
_body!.layout(innerConstraints, parentUsesSize: true);
(_body!.parentData as BoxParentData).offset =
Offset(_resolvedPadding!.left, _resolvedPadding!.top);
(_body!.parentData as BoxParentData).offset = Offset(_resolvedPadding!.left, _resolvedPadding!.top);
if (_leading != null) {
final leadingConstraints = innerConstraints.copyWith(
minWidth: indentWidth,
maxWidth: indentWidth,
maxHeight: _body!.size.height);
final leadingConstraints =
innerConstraints.copyWith(minWidth: indentWidth, maxWidth: indentWidth, maxHeight: _body!.size.height);
_leading!.layout(leadingConstraints, parentUsesSize: true);
(_leading!.parentData as BoxParentData).offset =
Offset(0, _resolvedPadding!.top);
(_leading!.parentData as BoxParentData).offset = Offset(0, _resolvedPadding!.top);
}
size = constraints.constrain(Size(
@ -822,19 +752,13 @@ class RenderEditableTextLine extends RenderEditableBox {
_paintSelection(context, effectiveOffset);
}
if (hasFocus &&
cursorCont.show.value &&
containsCursor() &&
!cursorCont.style.paintAboveText) {
if (hasFocus && cursorCont.show.value && containsCursor() && !cursorCont.style.paintAboveText) {
_paintCursor(context, effectiveOffset, line.hasEmbed);
}
context.paintChild(_body!, effectiveOffset);
if (hasFocus &&
cursorCont.show.value &&
containsCursor() &&
cursorCont.style.paintAboveText) {
if (hasFocus && cursorCont.show.value && containsCursor() && cursorCont.style.paintAboveText) {
_paintCursor(context, effectiveOffset, line.hasEmbed);
}
}
@ -848,14 +772,12 @@ class RenderEditableTextLine extends RenderEditableBox {
}
}
void _paintCursor(
PaintingContext context, Offset effectiveOffset, bool lineHasEmbed) {
void _paintCursor(PaintingContext context, Offset effectiveOffset, bool lineHasEmbed) {
final position = TextPosition(
offset: textSelection.extentOffset - line.documentOffset,
affinity: textSelection.base.affinity,
);
_cursorPainter.paint(
context.canvas, effectiveOffset, position, lineHasEmbed);
_cursorPainter.paint(context.canvas, effectiveOffset, position, lineHasEmbed);
}
@override
@ -866,8 +788,7 @@ class RenderEditableTextLine extends RenderEditableBox {
@override
Rect getLocalRectForCaret(TextPosition position) {
final caretOffset = getOffsetForCaret(position);
var rect =
Rect.fromLTWH(0, 0, cursorWidth, cursorHeight).shift(caretOffset);
var rect = Rect.fromLTWH(0, 0, cursorWidth, cursorHeight).shift(caretOffset);
final cursorOffset = cursorCont.style.offset;
// Add additional cursor offset (generally only if on iOS).
if (cursorOffset != null) rect = rect.shift(cursorOffset);
@ -876,13 +797,20 @@ class RenderEditableTextLine extends RenderEditableBox {
@override
TextPosition globalToLocalPosition(TextPosition position) {
assert(getContainer().containsOffset(position.offset),
'The provided text position is not in the current node');
assert(getContainer().containsOffset(position.offset), 'The provided text position is not in the current node');
return TextPosition(
offset: position.offset - getContainer().documentOffset,
affinity: position.affinity,
);
}
void safesafeMarkNeedsPaint() {
if (!attached) {
//Should not paint if it was unattach.
return;
}
markNeedsPaint();
}
}
class _TextLineElement extends RenderObjectElement {
@ -894,8 +822,7 @@ class _TextLineElement extends RenderObjectElement {
EditableTextLine get widget => super.widget as EditableTextLine;
@override
RenderEditableTextLine get renderObject =>
super.renderObject as RenderEditableTextLine;
RenderEditableTextLine get renderObject => super.renderObject as RenderEditableTextLine;
@override
void visitChildren(ElementVisitor visitor) {
@ -942,8 +869,7 @@ class _TextLineElement extends RenderObjectElement {
}
@override
void moveRenderObjectChild(
RenderObject child, dynamic oldSlot, dynamic newSlot) {
void moveRenderObjectChild(RenderObject child, dynamic oldSlot, dynamic newSlot) {
throw UnimplementedError();
}

Loading…
Cancel
Save