diff --git a/example/lib/app.dart b/example/lib/app.dart index e42dfd9..8134142 100644 --- a/example/lib/app.dart +++ b/example/lib/app.dart @@ -14,6 +14,23 @@ class App extends StatefulWidget { class _AppState extends State { final _langToolService = LangToolService(LanguageTool()); + final _textController = LanguageToolTextEditingController( + text: 'OKAYOKAYOKAYOKAYOKAY', + mistakes: [ + const Mistake( + message: 'bad', + type: 'bad', + offset: 0, + length: 3, + ), + const Mistake( + message: 'bad', + type: 'bad', + offset: 8, + length: 5, + ), + ], + ); @override Widget build(BuildContext context) { @@ -23,29 +40,7 @@ class _AppState extends State { padding: const EdgeInsets.all(20.0), child: LanguageToolTextField( langService: _langToolService, - controller: LanguageToolTextEditingController( - text: 'OKAYOKAYOKAY', - mistakes: [ - const Mistake( - message: 'bad', - type: 'bad', - offset: 2, - length: 2, - ), - const Mistake( - message: 'bad', - type: 'bad', - offset: 5, - length: 1, - ), - const Mistake( - message: 'bad', - type: 'bad', - offset: 7, - length: 3, - ), - ], - ), + controller: _textController, style: const TextStyle(), ), ), diff --git a/lib/presentation/widgets/language_tool_text_editing_controller.dart b/lib/presentation/widgets/language_tool_text_editing_controller.dart index 98de964..517bf45 100644 --- a/lib/presentation/widgets/language_tool_text_editing_controller.dart +++ b/lib/presentation/widgets/language_tool_text_editing_controller.dart @@ -19,7 +19,7 @@ class LanguageToolTextEditingController extends TextEditingController { TextStyle? style, required bool withComposing, }) { - final children = []; + final children = []; const underlineThickness = 2.0; const backgroundOpacity = 0.2; @@ -54,24 +54,34 @@ class LanguageToolTextEditingController extends TextEditingController { ); final textStyle = style ?? const TextStyle(); + final mistakeText = text.substring(mistakeStart, mistakeEnd); + + // WidgetSpans with mistake text characters are used here to calculate the correct caret position, which can be incorrectly positioned because of the WidgetSpan issue, described here: https://github.com/flutter/flutter/issues/107432. + // TextSpan recognizer to process clicks can't be used, because it requires the RichText widget instead of TextField, which we are using. Issue described here: https://github.com/flutter/flutter/issues/34931 + children.add( TextSpan( - text: text.substring(mistakeStart, mistakeEnd), style: textStyle.copyWith( decoration: TextDecoration.underline, decorationColor: Colors.red, decorationThickness: underlineThickness, backgroundColor: Colors.red.withOpacity(backgroundOpacity), ), + children: [ + for (final mistakeCharacter in mistakeText.characters) + WidgetSpan( + child: Text( + mistakeCharacter, + style: style, + ), + ), + ], ), ); - if (i == lastMistakeIndex) { children.add( TextSpan( - text: text.substring( - mistakeEnd, - ), + text: text.substring(mistakeEnd), ), ); }