Skip to content

Commit

Permalink
[SuperEditor][SuperTextField] - Paint underline beneath text in compo…
Browse files Browse the repository at this point in the history
…sing region (Resolves 1603) (#1639)
  • Loading branch information
matthew-carroll authored Dec 9, 2023
1 parent 01778d0 commit b19e1ca
Show file tree
Hide file tree
Showing 80 changed files with 970 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ class HeaderWithHintComponentBuilder implements ComponentBuilder {
),
textSelection: textSelection,
selectionColor: componentViewModel.selectionColor,
composingRegion: componentViewModel.composingRegion,
showComposingUnderline: componentViewModel.showComposingUnderline,
);
}
}
46 changes: 26 additions & 20 deletions super_editor/lib/src/core/document_composer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -295,12 +295,10 @@ class ChangeSelectionRequest implements EditRequest {
this.newSelection,
this.changeType,
this.reason, {
this.newComposingRegion,
this.notifyListeners = true,
});

final DocumentSelection? newSelection;
final DocumentRange? newComposingRegion;

/// Whether to notify [DocumentComposer] listeners when the selection is changed.
// TODO: configure the composer so it plugs into the editor in way that this is unnecessary.
Expand All @@ -317,18 +315,12 @@ class ChangeSelectionRequest implements EditRequest {
other is ChangeSelectionRequest &&
runtimeType == other.runtimeType &&
newSelection == other.newSelection &&
newComposingRegion == other.newComposingRegion &&
notifyListeners == other.notifyListeners &&
changeType == other.changeType &&
reason == other.reason;

@override
int get hashCode =>
newSelection.hashCode ^
newComposingRegion.hashCode ^
notifyListeners.hashCode ^
changeType.hashCode ^
reason.hashCode;
int get hashCode => newSelection.hashCode ^ notifyListeners.hashCode ^ changeType.hashCode ^ reason.hashCode;
}

/// An [EditCommand] that changes the [DocumentSelection] in the [DocumentComposer]
Expand All @@ -338,12 +330,10 @@ class ChangeSelectionCommand implements EditCommand {
this.newSelection,
this.changeType,
this.reason, {
this.newComposingRegion,
this.notifyListeners = true,
});

final DocumentSelection? newSelection;
final DocumentRange? newComposingRegion;

/// Whether to notify [DocumentComposer] listeners when the selection is changed.
// TODO: configure the composer so it plugs into the editor in way that this is unnecessary.
Expand All @@ -357,17 +347,13 @@ class ChangeSelectionCommand implements EditCommand {
void execute(EditContext context, CommandExecutor executor) {
final composer = context.find<MutableDocumentComposer>(Editor.composerKey);
final initialSelection = composer.selection;
final initialComposingRegion = composer.composingRegion.value;

composer.setSelectionWithReason(newSelection, reason);
composer.setComposingRegion(newComposingRegion);

executor.logChanges([
SelectionChangeEvent(
oldSelection: initialSelection,
newSelection: newSelection,
oldComposingRegion: initialComposingRegion,
newComposingRegion: newComposingRegion,
changeType: changeType,
reason: reason,
)
Expand All @@ -380,16 +366,12 @@ class SelectionChangeEvent implements EditEvent {
const SelectionChangeEvent({
required this.oldSelection,
required this.newSelection,
required this.oldComposingRegion,
required this.newComposingRegion,
required this.changeType,
required this.reason,
});

final DocumentSelection? oldSelection;
final DocumentSelection? newSelection;
final DocumentRange? oldComposingRegion;
final DocumentRange? newComposingRegion;
final SelectionChangeType changeType;
// TODO: can we replace the concept of a `reason` with `changeType`
final String reason;
Expand All @@ -398,6 +380,20 @@ class SelectionChangeEvent implements EditEvent {
String toString() => "[SelectionChangeEvent] - New selection: $newSelection, change type: $changeType";
}

/// A [EditEvent] that represents a change to the user's composing region within a document.
class ComposingRegionChangeEvent implements EditEvent {
const ComposingRegionChangeEvent({
required this.oldComposingRegion,
required this.newComposingRegion,
});

final DocumentRange? oldComposingRegion;
final DocumentRange? newComposingRegion;

@override
String toString() => "[ComposingRegionChangeEvent] - New composing region: $newComposingRegion";
}

/// Represents a change of a [DocumentSelection].
///
/// The [reason] represents what cause the selection to change.
Expand Down Expand Up @@ -486,7 +482,17 @@ class ChangeComposingRegionCommand implements EditCommand {

@override
void execute(EditContext context, CommandExecutor executor) {
context.find<MutableDocumentComposer>(Editor.composerKey)._composingRegion.value = composingRegion;
final composer = context.find<MutableDocumentComposer>(Editor.composerKey);
final initialComposingRegion = composer.composingRegion.value;

composer._composingRegion.value = composingRegion;

executor.logChanges([
ComposingRegionChangeEvent(
oldComposingRegion: initialComposingRegion,
newComposingRegion: composingRegion,
)
]);
}
}

Expand Down
26 changes: 23 additions & 3 deletions super_editor/lib/src/default_editor/blockquote.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ class BlockquoteComponentBuilder implements ComponentBuilder {
textSelection: componentViewModel.selection,
selectionColor: componentViewModel.selectionColor,
highlightWhenEmpty: componentViewModel.highlightWhenEmpty,
composingRegion: componentViewModel.composingRegion,
showComposingUnderline: componentViewModel.showComposingUnderline,
);
}
}
Expand All @@ -94,6 +96,8 @@ class BlockquoteComponentViewModel extends SingleColumnLayoutComponentViewModel
this.selection,
required this.selectionColor,
this.highlightWhenEmpty = false,
this.composingRegion,
this.showComposingUnderline = false,
}) : super(nodeId: nodeId, maxWidth: maxWidth, padding: padding);

@override
Expand All @@ -110,6 +114,10 @@ class BlockquoteComponentViewModel extends SingleColumnLayoutComponentViewModel
Color selectionColor;
@override
bool highlightWhenEmpty;
@override
TextRange? composingRegion;
@override
bool showComposingUnderline;

Color backgroundColor;
BorderRadius borderRadius;
Expand All @@ -136,6 +144,8 @@ class BlockquoteComponentViewModel extends SingleColumnLayoutComponentViewModel
selection: selection,
selectionColor: selectionColor,
highlightWhenEmpty: highlightWhenEmpty,
composingRegion: composingRegion,
showComposingUnderline: showComposingUnderline,
);
}

Expand All @@ -153,7 +163,9 @@ class BlockquoteComponentViewModel extends SingleColumnLayoutComponentViewModel
borderRadius == other.borderRadius &&
selection == other.selection &&
selectionColor == other.selectionColor &&
highlightWhenEmpty == other.highlightWhenEmpty;
highlightWhenEmpty == other.highlightWhenEmpty &&
composingRegion == other.composingRegion &&
showComposingUnderline == other.showComposingUnderline;

@override
int get hashCode =>
Expand All @@ -166,7 +178,9 @@ class BlockquoteComponentViewModel extends SingleColumnLayoutComponentViewModel
borderRadius.hashCode ^
selection.hashCode ^
selectionColor.hashCode ^
highlightWhenEmpty.hashCode;
highlightWhenEmpty.hashCode ^
composingRegion.hashCode ^
showComposingUnderline.hashCode;
}

/// Displays a blockquote in a document.
Expand All @@ -180,8 +194,10 @@ class BlockquoteComponent extends StatelessWidget {
this.selectionColor = Colors.lightBlueAccent,
required this.backgroundColor,
required this.borderRadius,
this.showDebugPaint = false,
this.highlightWhenEmpty = false,
this.composingRegion,
this.showComposingUnderline = false,
this.showDebugPaint = false,
}) : super(key: key);

final GlobalKey textKey;
Expand All @@ -192,6 +208,8 @@ class BlockquoteComponent extends StatelessWidget {
final Color backgroundColor;
final BorderRadius borderRadius;
final bool highlightWhenEmpty;
final TextRange? composingRegion;
final bool showComposingUnderline;
final bool showDebugPaint;

@override
Expand All @@ -210,6 +228,8 @@ class BlockquoteComponent extends StatelessWidget {
textSelection: textSelection,
selectionColor: selectionColor,
highlightWhenEmpty: highlightWhenEmpty,
composingRegion: composingRegion,
showComposingUnderline: showComposingUnderline,
showDebugPaint: showDebugPaint,
),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class TextDeltasDocumentEditor {
selection: selection.value != null
? _serializedDoc.documentToImeSelection(selection.value!)
: const TextSelection.collapsed(offset: -1),
composing: _serializedDoc.documentToImeRange(_serializedDoc.composingRegion),
);

for (final delta in textEditingDeltas) {
Expand Down Expand Up @@ -163,6 +164,13 @@ class TextDeltasDocumentEditor {
composingRegion.value,
_serializedDoc.didPrependPlaceholder ? PrependedCharacterPolicy.include : PrependedCharacterPolicy.exclude,
)..imeText = _previousImeValue.text;

// The delta's composing region is based on the content after insertion, so we
// apply the composing region here instead of during insertion operation above.
final insertionComposingRegion = _serializedDoc.imeToDocumentRange(delta.composing);
editor.execute([
ChangeComposingRegionRequest(insertionComposingRegion),
]);
}

void _applyReplacement(TextEditingDeltaReplacement delta) {
Expand Down Expand Up @@ -206,6 +214,13 @@ class TextDeltasDocumentEditor {
composingRegion.value,
_serializedDoc.didPrependPlaceholder ? PrependedCharacterPolicy.include : PrependedCharacterPolicy.exclude,
)..imeText = _previousImeValue.text;

// The delta's composing region is based on the content after insertion, so we
// apply the composing region here instead of during the replacement operation above.
final insertionComposingRegion = _serializedDoc.imeToDocumentRange(delta.composing);
editor.execute([
ChangeComposingRegionRequest(insertionComposingRegion),
]);
}

void _applyDeletion(TextEditingDeltaDeletion delta) {
Expand All @@ -230,6 +245,7 @@ class TextDeltasDocumentEditor {
editorImeLog.fine("OS-side composing - ${delta.composing}");

final docSelection = _serializedDoc.imeToDocumentSelection(delta.selection);
final docComposingRegion = _serializedDoc.imeToDocumentRange(delta.composing);
if (docSelection != null) {
// We got a selection from the platform.
// This could happen in some software keyboards, like GBoard,
Expand All @@ -240,6 +256,7 @@ class TextDeltasDocumentEditor {
docSelection.isCollapsed ? SelectionChangeType.placeCaret : SelectionChangeType.expandSelection,
SelectionReason.userInteraction,
),
ChangeComposingRegionRequest(docComposingRegion),
]);
}

Expand Down
Loading

0 comments on commit b19e1ca

Please sign in to comment.