diff --git a/example/lib/app.dart b/example/lib/app.dart index e22db0a..2f518fe 100644 --- a/example/lib/app.dart +++ b/example/lib/app.dart @@ -17,12 +17,17 @@ class _AppState extends State { /// Initialize DebounceLangToolService final DebounceLangToolService _debouncedLangService; + /// Initialize ColoredTextEditingController + final ColoredTextEditingController controller = + ColoredTextEditingController(); + /// Set DebounceLangToolService _AppState() : _debouncedLangService = DebounceLangToolService( LangToolService(_languageTool), const Duration(milliseconds: 500), ); + @override Widget build(BuildContext context) { return Material( @@ -33,6 +38,7 @@ class _AppState extends State { mistakeBuilder: () { return Container(); }, + coloredController: controller, ), ); } diff --git a/lib/core/controllers/colored_text_editing_controller.dart b/lib/core/controllers/colored_text_editing_controller.dart index 4a7bff7..5d7cd35 100644 --- a/lib/core/controllers/colored_text_editing_controller.dart +++ b/lib/core/controllers/colored_text_editing_controller.dart @@ -1,23 +1,17 @@ import 'package:flutter/material.dart'; import 'package:languagetool_textfield/core/enums/mistake_type.dart'; -import 'package:languagetool_textfield/domain/highlight_colors.dart'; +import 'package:languagetool_textfield/domain/highlight_style.dart'; import 'package:languagetool_textfield/domain/mistake.dart'; /// A TextEditingController with overrides buildTextSpan for building /// marked TextSpans with tap recognizer class ColoredTextEditingController extends TextEditingController { /// Color scheme to highlight mistakes - final HighlightColors? highlightColorScheme; + final HighlightStyle highlightStyle; /// List which contains Mistake objects spans are built from List _mistakes = []; - final double _backgroundOpacity = - 0.2; // background opacity for mistake TextSpan - - final double _mistakeLineThickness = - 1.5; // mistake TextSpan underline thickness - @override set value(TextEditingValue newValue) { _handleTextChange(newValue.text); @@ -25,7 +19,9 @@ class ColoredTextEditingController extends TextEditingController { } /// Controller constructor - ColoredTextEditingController({this.highlightColorScheme}); + ColoredTextEditingController({ + this.highlightStyle = const HighlightStyle(), + }); /// Generates TextSpan from Mistake list @override @@ -34,55 +30,64 @@ class ColoredTextEditingController extends TextEditingController { TextStyle? style, required bool withComposing, }) { - int currentOffset = 0; // enter index - final int textLength = text.length; + final Iterable spanList = + _generateSpans(textLength: textLength, style: style); - /// Generator function to create TextSpan instances - Iterable generateSpans() sync* { - for (final Mistake mistake in _mistakes) { - /// Breaks the loop if iterated Mistake offset is bigger than text - /// length. - if (mistake.offset > textLength || - mistake.offset + mistake.length > textLength) { - break; - } - - /// TextSpan before mistake - yield TextSpan( - text: text.substring( - currentOffset, - mistake.offset, - ), - style: style, - ); - - /// Get a highlight color - final Color mistakeColor = _getMistakeColor(mistake.type); - - /// Mistake highlighted TextSpan - yield TextSpan( - text: text.substring(mistake.offset, mistake.offset + mistake.length), - mouseCursor: MaterialStateMouseCursor.clickable, - style: style?.copyWith( - backgroundColor: mistakeColor.withOpacity(_backgroundOpacity), - decoration: TextDecoration.underline, - decorationColor: mistakeColor, - decorationThickness: _mistakeLineThickness, - ), - ); + return TextSpan( + children: spanList.toList(), + ); + } + + /// Generator function to create TextSpan instances + Iterable _generateSpans({ + required int textLength, + TextStyle? style, + }) sync* { + int currentOffset = 0; // enter index - currentOffset = mistake.offset + mistake.length; + for (final Mistake mistake in _mistakes) { + /// Breaks the loop if iterated Mistake offset is bigger than text + /// length. + if (mistake.offset > textLength || + mistake.offset + mistake.length > textLength) { + break; } - /// TextSpan after mistake + /// TextSpan before mistake yield TextSpan( - text: text.substring(currentOffset), + text: text.substring( + currentOffset, + mistake.offset, + ), style: style, ); + + /// Get a highlight color + final Color mistakeColor = _getMistakeColor(mistake.type); + + /// Mistake highlighted TextSpan + yield TextSpan( + text: text.substring(mistake.offset, mistake.offset + mistake.length), + mouseCursor: MaterialStateMouseCursor.clickable, + style: style?.copyWith( + backgroundColor: mistakeColor.withOpacity( + highlightStyle.backgroundOpacity, + ), + decoration: TextDecoration.underline, + decorationColor: mistakeColor, + decorationThickness: highlightStyle.mistakeLineThickness, + ), + ); + + currentOffset = mistake.offset + mistake.length; } - return TextSpan(children: generateSpans().toList()); + /// TextSpan after mistake + yield TextSpan( + text: text.substring(currentOffset), + style: style, + ); } /// Apply changes to Mistake list while new data being fetched @@ -134,21 +139,19 @@ class ColoredTextEditingController extends TextEditingController { Color _getMistakeColor(MistakeType type) { switch (type) { case MistakeType.misspelling: - return highlightColorScheme?.misspellingMistakeColor ?? Colors.red; + return highlightStyle.misspellingMistakeColor; case MistakeType.typographical: - return highlightColorScheme?.typographicalMistakeColor ?? Colors.green; + return highlightStyle.typographicalMistakeColor; case MistakeType.grammar: - return highlightColorScheme?.grammarMistakeColor ?? Colors.amber; + return highlightStyle.grammarMistakeColor; case MistakeType.uncategorized: - return highlightColorScheme?.uncategorizedMistakeColor ?? Colors.blue; + return highlightStyle.uncategorizedMistakeColor; case MistakeType.nonConformance: - return highlightColorScheme?.nonConformanceMistakeColor ?? - Colors.greenAccent; + return highlightStyle.nonConformanceMistakeColor; case MistakeType.style: - return highlightColorScheme?.styleMistakeColor ?? - Colors.deepPurpleAccent; + return highlightStyle.styleMistakeColor; case MistakeType.other: - return highlightColorScheme?.otherMistakeColor ?? Colors.white60; + return highlightStyle.otherMistakeColor; } } } diff --git a/lib/domain/highlight_colors.dart b/lib/domain/highlight_colors.dart deleted file mode 100644 index 29a3080..0000000 --- a/lib/domain/highlight_colors.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'dart:ui'; - -/// Class creates color scheme for highlighting mistakes -class HighlightColors { - /// Misspelling mistake highlight color - final Color? misspellingMistakeColor; - - /// Misspelling mistake highlight color - final Color? typographicalMistakeColor; - - /// Typographical mistake highlight color - final Color? grammarMistakeColor; - - /// Uncategorized mistake highlight color - final Color? uncategorizedMistakeColor; - - /// NonConformance mistake highlight color - final Color? nonConformanceMistakeColor; - - /// Style mistake highlight color - final Color? styleMistakeColor; - - /// Other mistake highlight color - final Color? otherMistakeColor; - - ///Color scheme constructor - HighlightColors( - this.misspellingMistakeColor, - this.typographicalMistakeColor, - this.grammarMistakeColor, - this.uncategorizedMistakeColor, - this.nonConformanceMistakeColor, - this.styleMistakeColor, - this.otherMistakeColor, - ); -} diff --git a/lib/domain/highlight_style.dart b/lib/domain/highlight_style.dart new file mode 100644 index 0000000..f7c0925 --- /dev/null +++ b/lib/domain/highlight_style.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; + +/// Class creates color scheme for highlighting mistakes +class HighlightStyle { + ///Initial values + static const double _initialBackgroundOpacity = 0.2; + static const double _initialLineHeight = 1.5; + + /// Misspelling mistake highlight color + final Color misspellingMistakeColor; + + /// Misspelling mistake highlight color + final Color typographicalMistakeColor; + + /// Typographical mistake highlight color + final Color grammarMistakeColor; + + /// Uncategorized mistake highlight color + final Color uncategorizedMistakeColor; + + /// NonConformance mistake highlight color + final Color nonConformanceMistakeColor; + + /// Style mistake highlight color + final Color styleMistakeColor; + + /// Other mistake highlight color + final Color otherMistakeColor; + + /// background opacity for mistake TextSpan + final double backgroundOpacity; + + /// mistake TextSpan underline thickness + final double mistakeLineThickness; + + ///Color scheme constructor + const HighlightStyle({ + this.misspellingMistakeColor = Colors.red, + this.typographicalMistakeColor = Colors.green, + this.grammarMistakeColor = Colors.amber, + this.uncategorizedMistakeColor = Colors.blue, + this.nonConformanceMistakeColor = Colors.greenAccent, + this.styleMistakeColor = Colors.deepPurpleAccent, + this.otherMistakeColor = Colors.white60, + this.backgroundOpacity = _initialBackgroundOpacity, + this.mistakeLineThickness = _initialLineHeight, + }); +} diff --git a/lib/languagetool_textfield.dart b/lib/languagetool_textfield.dart index b86e916..1050872 100644 --- a/lib/languagetool_textfield.dart +++ b/lib/languagetool_textfield.dart @@ -2,7 +2,8 @@ library languagetool_textfield; export 'package:language_tool/language_tool.dart'; -export 'domain/highlight_colors.dart'; +export 'core/controllers/colored_text_editing_controller.dart'; +export 'domain/highlight_style.dart'; export 'domain/language_check_service.dart'; export 'domain/mistake.dart'; export 'implementations/debounce_lang_tool_service.dart'; diff --git a/lib/presentation/language_tool_text_field.dart b/lib/presentation/language_tool_text_field.dart index 4f25664..0fa9dab 100644 --- a/lib/presentation/language_tool_text_field.dart +++ b/lib/presentation/language_tool_text_field.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:languagetool_textfield/core/controllers/colored_text_editing_controller.dart'; -import 'package:languagetool_textfield/domain/highlight_colors.dart'; +import 'package:languagetool_textfield/domain/highlight_style.dart'; import 'package:languagetool_textfield/domain/language_check_service.dart'; /// A TextField widget that checks the grammar using the given [langService] @@ -18,7 +18,7 @@ class LanguageToolTextField extends StatefulWidget { final Widget Function()? mistakeBuilder; /// Color scheme to highlight mistakes - final HighlightColors? highlightColorScheme; + final ColoredTextEditingController coloredController; /// Creates a widget that checks grammar errors. const LanguageToolTextField({ @@ -27,7 +27,7 @@ class LanguageToolTextField extends StatefulWidget { required this.style, required this.decoration, this.mistakeBuilder, - this.highlightColorScheme, + required this.coloredController, }) : super(key: key); @override @@ -35,21 +35,17 @@ class LanguageToolTextField extends StatefulWidget { } class _LanguageToolTextFieldState extends State { - ColoredTextEditingController? _controller; /// Sends API request to get a list of Mistake Future _check(String text) async { final mistakes = await widget.langService.findMistakes(text); if (mistakes.isNotEmpty) { - _controller?.highlightMistakes(mistakes); + widget.coloredController.highlightMistakes(mistakes); } } @override void initState() { - _controller = ColoredTextEditingController( - highlightColorScheme: widget.highlightColorScheme, - ); super.initState(); } @@ -59,12 +55,8 @@ class _LanguageToolTextFieldState extends State { padding: const EdgeInsets.all(24.0), child: Center( child: TextField( - controller: _controller, - onChanged: (String text) { - if (_controller != null) { - _check(text); - } - }, + controller: widget.coloredController, + onChanged: _check, style: widget.style, decoration: widget.decoration, ), @@ -75,6 +67,6 @@ class _LanguageToolTextFieldState extends State { @override void dispose() { super.dispose(); - _controller?.dispose(); // disposes controller + widget.coloredController.dispose(); } }