Skip to content

Commit 4c24bda

Browse files
Merge pull request #92 from andrew-bekhiet-solid/feat-add-is-enabled-toggle
feat: add isEnabled toggle
2 parents 16e9371 + 5add954 commit 4c24bda

File tree

3 files changed

+81
-28
lines changed

3 files changed

+81
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
- BREAKING: require flutter 3.27.0 or higher
44
- BREAKING: require dart 3.0.0 or higher
55
- BREAKING: rename autoFocus to autofocus to match `TextField`'s naming
6+
- Add `isEnabled` to toggle spell check
67
- Add missing properties from flutter's `TextField`
78
- autofillHints
89
- autofocus

example/lib/main.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ class _AppState extends State<App> {
4141
controller: _controller,
4242
language: 'en-US',
4343
),
44+
ValueListenableBuilder(
45+
valueListenable: _controller,
46+
builder: (_, __, ___) => CheckboxListTile(
47+
title: const Text("Enable spell checking"),
48+
value: _controller.isEnabled,
49+
onChanged: (value) => _controller.isEnabled = value ?? false,
50+
),
51+
),
4452
DropdownMenu(
4553
hintText: "Select alignment...",
4654
onSelected: (value) => setState(() {

lib/src/core/controllers/language_tool_controller.dart

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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
2121
class 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

Comments
 (0)