@@ -19,6 +19,8 @@ import 'package:languagetool_textfield/src/utils/mistake_popup.dart';
1919/// A TextEditingController with overrides buildTextSpan for building
2020/// marked TextSpans with tap recognizer
2121class LanguageToolController extends TextEditingController {
22+ bool _isEnabled;
23+
2224 /// Color scheme to highlight mistakes
2325 final HighlightStyle highlightStyle;
2426
@@ -73,21 +75,46 @@ class LanguageToolController extends TextEditingController {
7375 _languageToolClient.language = language;
7476 }
7577
78+ /// Indicates whether spell checking is enabled
79+ bool get isEnabled => _isEnabled;
80+
81+ set isEnabled (bool value) {
82+ if (value == _isEnabled) return ;
83+
84+ _isEnabled = value;
85+
86+ if (_isEnabled) {
87+ _handleTextChange (text, spellCheckSameText: true );
88+ } else {
89+ _mistakes = [];
90+ for (final recognizer in _recognizers) {
91+ recognizer.dispose ();
92+ }
93+ _recognizers.clear ();
94+
95+ notifyListeners ();
96+ }
97+ }
98+
7699 /// An error that may have occurred during the API fetch.
77100 Object ? get fetchError => _fetchError;
78101
79102 @override
80103 set value (TextEditingValue newValue) {
81- _handleTextChange (newValue.text);
104+ if (_isEnabled) {
105+ _handleTextChange (newValue.text);
106+ }
107+
82108 super .value = newValue;
83109 }
84110
85111 /// Controller constructor
86112 LanguageToolController ({
113+ bool isEnabled = true ,
87114 this .highlightStyle = const HighlightStyle (),
88115 this .delay = Duration .zero,
89116 this .delayType = DelayType .debouncing,
90- }) {
117+ }) : _isEnabled = isEnabled {
91118 _languageCheckService = _getLanguageCheckService ();
92119 }
93120
@@ -111,9 +138,17 @@ class LanguageToolController extends TextEditingController {
111138 @override
112139 TextSpan buildTextSpan ({
113140 required BuildContext context,
114- TextStyle ? style,
115141 required bool withComposing,
142+ TextStyle ? style,
116143 }) {
144+ if (! _isEnabled) {
145+ return super .buildTextSpan (
146+ context: context,
147+ withComposing: withComposing,
148+ style: style,
149+ );
150+ }
151+
117152 final formattedTextSpans = _generateSpans (
118153 context,
119154 style: style,
@@ -132,6 +167,10 @@ class LanguageToolController extends TextEditingController {
132167
133168 /// Replaces mistake with given replacement
134169 void replaceMistake (Mistake mistake, String replacement) {
170+ if (! _isEnabled) {
171+ throw StateError ('LanguageToolController is not enabled' );
172+ }
173+
135174 final mistakes = List <Mistake >.from (_mistakes);
136175 mistakes.remove (mistake);
137176 _mistakes = mistakes;
@@ -145,33 +184,38 @@ class LanguageToolController extends TextEditingController {
145184
146185 /// Clear mistakes list when text mas modified and get a new list of mistakes
147186 /// via API
148- Future <void > _handleTextChange (String newText) async {
187+ Future <void > _handleTextChange (
188+ String newText, {
189+ bool spellCheckSameText = false ,
190+ }) async {
149191 ///set value triggers each time, even when cursor changes its location
150192 ///so this check avoid cleaning Mistake list when text wasn't really changed
151- if (newText == text || newText.isEmpty) return ;
193+ if (spellCheckSameText || newText != text && newText.isNotEmpty) {
194+ final filteredMistakes = _filterMistakesOnChanged (newText);
195+ _mistakes = filteredMistakes.toList ();
196+
197+ // If we have a text change and we have a popup on hold
198+ // it will close the popup
199+ _closePopup ();
200+
201+ for (final recognizer in _recognizers) {
202+ recognizer.dispose ();
203+ }
204+ _recognizers.clear ();
205+
206+ final mistakesWrapper =
207+ await _latestResponseService.processLatestOperation (
208+ () =>
209+ _languageCheckService? .findMistakes (newText) ?? Future (() => null ),
210+ );
211+ if (mistakesWrapper == null || ! mistakesWrapper.hasResult) return ;
152212
153- final filteredMistakes = _filterMistakesOnChanged (newText );
154- _mistakes = filteredMistakes. toList () ;
213+ final mistakes = mistakesWrapper. result ( );
214+ _fetchError = mistakesWrapper.error ;
155215
156- // If we have a text change and we have a popup on hold
157- // it will close the popup
158- _closePopup ();
159-
160- for (final recognizer in _recognizers) {
161- recognizer.dispose ();
216+ _mistakes = mistakes;
217+ notifyListeners ();
162218 }
163- _recognizers.clear ();
164-
165- final mistakesWrapper = await _latestResponseService.processLatestOperation (
166- () => _languageCheckService? .findMistakes (newText) ?? Future (() => null ),
167- );
168- if (mistakesWrapper == null || ! mistakesWrapper.hasResult) return ;
169-
170- final mistakes = mistakesWrapper.result ();
171- _fetchError = mistakesWrapper.error;
172-
173- _mistakes = mistakes;
174- notifyListeners ();
175219 }
176220
177221 /// Generator function to create TextSpan instances
@@ -200,7 +244,7 @@ class LanguageToolController extends TextEditingController {
200244 final Color mistakeColor = _getMistakeColor (mistake.type);
201245
202246 /// Create a gesture recognizer for mistake
203- final _onTap = TapGestureRecognizer ()
247+ final onTap = TapGestureRecognizer ()
204248 ..onTapDown = (details) {
205249 popupWidget? .show (
206250 context,
@@ -223,7 +267,7 @@ class LanguageToolController extends TextEditingController {
223267 };
224268
225269 /// Adding recognizer to the list for future disposing
226- _recognizers.add (_onTap );
270+ _recognizers.add (onTap );
227271
228272 /// Mistake highlighted TextSpan
229273 yield TextSpan (
@@ -242,7 +286,7 @@ class LanguageToolController extends TextEditingController {
242286 decorationColor: mistakeColor,
243287 decorationThickness: highlightStyle.mistakeLineThickness,
244288 ),
245- recognizer: _onTap ,
289+ recognizer: onTap ,
246290 ),
247291 ],
248292 );
0 commit comments