Skip to content

Commit 7776a60

Browse files
Merge pull request #64 from solid-software/task/hidden-deps-api-integration
Task/Hide dependencies & refactor
2 parents c37f1ec + 3e4126a commit 7776a60

File tree

11 files changed

+153
-96
lines changed

11 files changed

+153
-96
lines changed

README.md

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -51,37 +51,40 @@ import 'package:language_tool_textfield/language_tool_textfield.dart';
5151
To start using the plugin, copy this code or follow the example project in 'languagetool_textfield/example'
5252

5353
```dart
54-
// Create a base API client
55-
final _languageTool = LanguageToolClient(
54+
// Create a text controller for the Widget
55+
final _controller = LanguageToolController();
56+
57+
// Use the text field widget in your layout
58+
child: LanguageToolTextField(
59+
controller: _controller,
60+
5661
// A language code like en-US, de-DE, fr, or auto to guess
5762
// the language automatically.
5863
// language = 'auto' by default.
5964
language: 'en-US',
6065
);
6166
62-
// Add input debouncing
63-
final _debouncedLangService = DebounceLangToolService(
64-
LangToolService(_languageTool),
65-
const Duration(milliseconds: 500),
66-
);
67+
// Don't forget to dispose the controller
68+
_controller.dispose();
69+
```
6770

68-
// Create a text controller for the Widget
69-
final _controller = ColoredTextEditingController(
70-
languageCheckService: _debouncedLangService
71-
);
71+
## Using Debounce and Throttle in LanguageTool TextField
7272

73-
// Use the text field widget in your layout
74-
child: LanguageToolTextField(
75-
style: const TextStyle(),
76-
decoration: const InputDecoration(),
77-
coloredController: _controller,
78-
mistakePopup: MistakePopup(popupRenderer: PopupOverlayRenderer()),
79-
);
73+
To incorporate the debounce or throttle functionality into the `LanguageTool TextField`, follow these steps:
8074

81-
// Don't forget to dispose the controller
82-
_controller.dispose();
75+
Create a `LanguageToolController` and provide the desired debounce/throttle delay duration and delay type:
76+
```dart
77+
final _controller = LanguageToolController(
78+
// If the delay value is [Duration.zero], no delay is applied.
79+
delay: Duration(milliseconds: 500), // Set the debounce/throttle delay duration here
80+
delayType: DelayType.debouncing, // Choose either DelayType.debouncing or DelayType.throttling
81+
);
8382
```
8483

84+
`DelayType.debouncing` - Calls a function when a user hasn't carried out the event in a specific amount of time.
85+
86+
`DelayType.throttling` - Calls a function at intervals of a specified amount of time while the user is carrying out the event.
87+
8588
## Legal
8689

8790
This is an unofficial plugin. We are not affiliated with LanguageTool.

example/lib/main.dart

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,8 @@ class App extends StatefulWidget {
2020
}
2121

2222
class _AppState extends State<App> {
23-
/// Initialize LanguageToolClient
24-
static final LanguageToolClient _languageTool = LanguageToolClient(
25-
// A language code like en-US, de-DE, fr, or auto to guess
26-
// the language automatically.
27-
// language = 'auto' by default.
28-
language: 'en-US',
29-
);
30-
31-
/// Initialize DebounceLangToolService
32-
static final DebounceLangToolService _debouncedLangService =
33-
DebounceLangToolService(
34-
LangToolService(_languageTool),
35-
const Duration(milliseconds: 500),
36-
);
37-
38-
/// Initialize ColoredTextEditingController
39-
final ColoredTextEditingController _controller =
40-
ColoredTextEditingController(languageCheckService: _debouncedLangService);
23+
/// Initialize LanguageToolController
24+
final LanguageToolController _controller = LanguageToolController();
4125

4226
static const List<MainAxisAlignment> alignments = [
4327
MainAxisAlignment.center,
@@ -54,10 +38,8 @@ class _AppState extends State<App> {
5438
mainAxisAlignment: alignments[currentAlignmentIndex],
5539
children: [
5640
LanguageToolTextField(
57-
style: const TextStyle(),
58-
decoration: const InputDecoration(),
59-
coloredController: _controller,
60-
mistakePopup: MistakePopup(popupRenderer: PopupOverlayRenderer()),
41+
controller: _controller,
42+
language: 'en-US',
6143
),
6244
DropdownMenu(
6345
hintText: "Select alignment...",
@@ -69,7 +51,7 @@ class _AppState extends State<App> {
6951
DropdownMenuEntry(value: 1, label: "Top alignment"),
7052
DropdownMenuEntry(value: 2, label: "Bottom alignment"),
7153
],
72-
)
54+
),
7355
],
7456
),
7557
),

lib/client/language_tool_client.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ import 'package:languagetool_textfield/domain/writing_mistake.dart';
88
///
99
/// Read more @ https://languagetool.org/http-api/swagger-ui/#/
1010
class LanguageToolClient {
11-
/// A language code like en-US, de-DE, fr,
12-
/// or auto to guess the language automatically
13-
final String language;
14-
1511
/// Url of LanguageTool API.
1612
static const _url = 'api.languagetoolplus.com';
1713

@@ -21,6 +17,10 @@ class LanguageToolClient {
2117
'Accept': 'application/json',
2218
};
2319

20+
/// A language code like en-US, de-DE, fr,
21+
/// or auto to guess the language automatically
22+
String language;
23+
2424
/// Constructor for [LanguageToolClient].
2525
LanguageToolClient({this.language = 'auto'});
2626

lib/core/controllers/colored_text_editing_controller.dart renamed to lib/core/controllers/language_tool_controller.dart

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,76 @@ import 'dart:math';
33
import 'package:collection/collection.dart';
44
import 'package:flutter/gestures.dart';
55
import 'package:flutter/material.dart';
6+
import 'package:languagetool_textfield/client/language_tool_client.dart';
7+
import 'package:languagetool_textfield/core/enums/delay_type.dart';
68
import 'package:languagetool_textfield/core/enums/mistake_type.dart';
79
import 'package:languagetool_textfield/domain/highlight_style.dart';
810
import 'package:languagetool_textfield/domain/language_check_service.dart';
911
import 'package:languagetool_textfield/domain/mistake.dart';
12+
import 'package:languagetool_textfield/implementations/debounce_lang_tool_service.dart';
13+
import 'package:languagetool_textfield/implementations/lang_tool_service.dart';
14+
import 'package:languagetool_textfield/implementations/throttling_lang_tool_service.dart';
1015
import 'package:languagetool_textfield/utils/closed_range.dart';
1116
import 'package:languagetool_textfield/utils/keep_latest_response_service.dart';
1217
import 'package:languagetool_textfield/utils/mistake_popup.dart';
1318

1419
/// A TextEditingController with overrides buildTextSpan for building
1520
/// marked TextSpans with tap recognizer
16-
class ColoredTextEditingController extends TextEditingController {
21+
class LanguageToolController extends TextEditingController {
1722
/// Color scheme to highlight mistakes
1823
final HighlightStyle highlightStyle;
1924

20-
/// Language tool API index
21-
final LanguageCheckService languageCheckService;
25+
/// Represents the type of delay for language checking.
26+
///
27+
/// [DelayType.debouncing] - Calls a function when a user hasn't carried out
28+
/// the event in a specific amount of time.
29+
///
30+
/// [DelayType.throttling] - Calls a function at intervals of a specified
31+
/// amount of time while the user is carrying out the event.
32+
final DelayType delayType;
2233

23-
/// Create an instance of [KeepLatestResponseService]
24-
/// to handle asynchronous operations
25-
final latestResponseService = KeepLatestResponseService();
34+
/// Represents the duration of the delay for language checking.
35+
///
36+
/// If the delay is [Duration.zero], no delaying is applied.
37+
final Duration delay;
2638

27-
/// List which contains Mistake objects spans are built from
28-
List<Mistake> _mistakes = [];
39+
/// Create an instance of [LanguageToolClient] instance
40+
final _languageToolClient = LanguageToolClient();
41+
42+
/// Create an instance of [KeepLatestResponseService]
43+
/// to handle asynchronous operations
44+
final _latestResponseService = KeepLatestResponseService();
2945

3046
/// List of that is used to dispose recognizers after mistakes rebuilt
3147
final List<TapGestureRecognizer> _recognizers = [];
3248

33-
/// Reference to the popup widget
34-
MistakePopup? popupWidget;
49+
/// Language tool API index
50+
LanguageCheckService? _languageCheckService;
3551

3652
/// Reference to the focus of the LanguageTool TextField
3753
FocusNode? focusNode;
3854

55+
/// List which contains Mistake objects spans are built from
56+
List<Mistake> _mistakes = [];
57+
58+
/// Reference to the popup widget
59+
MistakePopup? popupWidget;
60+
3961
/// Represents the scroll offset value of the LanguageTool TextField.
4062
double? scrollOffset;
4163

4264
Object? _fetchError;
4365

66+
/// The language used for spellchecking in the text field.
67+
///
68+
/// A language code like en-US, de-DE, fr, or auto to guess
69+
/// the language automatically.
70+
String get language => _languageToolClient.language;
71+
72+
set language(String language) {
73+
_languageToolClient.language = language;
74+
}
75+
4476
/// An error that may have occurred during the API fetch.
4577
Object? get fetchError => _fetchError;
4678

@@ -51,10 +83,26 @@ class ColoredTextEditingController extends TextEditingController {
5183
}
5284

5385
/// Controller constructor
54-
ColoredTextEditingController({
55-
required this.languageCheckService,
86+
LanguageToolController({
5687
this.highlightStyle = const HighlightStyle(),
57-
});
88+
this.delay = Duration.zero,
89+
this.delayType = DelayType.debouncing,
90+
}) {
91+
_languageCheckService = _getLanguageCheckService();
92+
}
93+
94+
LanguageCheckService _getLanguageCheckService() {
95+
final languageToolService = LangToolService(_languageToolClient);
96+
97+
if (delay == Duration.zero) return languageToolService;
98+
99+
switch (delayType) {
100+
case DelayType.debouncing:
101+
return DebounceLangToolService(languageToolService, delay);
102+
case DelayType.throttling:
103+
return ThrottlingLangToolService(languageToolService, delay);
104+
}
105+
}
58106

59107
/// Close the popup widget
60108
void _closePopup() => popupWidget?.popupRenderer.dismiss();
@@ -78,7 +126,7 @@ class ColoredTextEditingController extends TextEditingController {
78126

79127
@override
80128
void dispose() {
81-
languageCheckService.dispose();
129+
_languageCheckService?.dispose();
82130
super.dispose();
83131
}
84132

@@ -114,8 +162,8 @@ class ColoredTextEditingController extends TextEditingController {
114162
}
115163
_recognizers.clear();
116164

117-
final mistakesWrapper = await latestResponseService.processLatestOperation(
118-
() => languageCheckService.findMistakes(newText),
165+
final mistakesWrapper = await _latestResponseService.processLatestOperation(
166+
() => _languageCheckService?.findMistakes(newText) ?? Future(() => null),
119167
);
120168
final mistakes = mistakesWrapper?.result();
121169
_fetchError = mistakesWrapper?.error;

lib/core/enums/delay_type.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
///Enumerate delay types
2+
enum DelayType {
3+
/// A debouncing used to debounce the API calls.
4+
debouncing,
5+
6+
/// A throttling used to throttle the API calls.
7+
throttling,
8+
}

lib/domain/language_check_service.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ abstract class LanguageCheckService {
77
const LanguageCheckService();
88

99
/// Returns found mistakes in the given [text].
10-
Future<Result<List<Mistake>>> findMistakes(String text);
10+
Future<Result<List<Mistake>>?> findMistakes(String text);
1111

1212
/// Disposes resources of this [LanguageCheckService].
1313
Future<void> dispose() async {

lib/domain/typedefs.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import 'package:flutter/widgets.dart';
2-
import 'package:languagetool_textfield/core/controllers/colored_text_editing_controller.dart';
2+
import 'package:languagetool_textfield/core/controllers/language_tool_controller.dart';
33
import 'package:languagetool_textfield/domain/mistake.dart';
44
import 'package:languagetool_textfield/utils/popup_overlay_renderer.dart';
55

66
/// Callback used to build popup body
77
typedef MistakeBuilderCallback = Widget Function({
88
required PopupOverlayRenderer popupRenderer,
99
required Mistake mistake,
10-
required ColoredTextEditingController controller,
10+
required LanguageToolController controller,
1111
required Offset mistakePosition,
1212
});
1313

@@ -16,5 +16,5 @@ typedef ShowPopupCallback = void Function(
1616
BuildContext context,
1717
Mistake mistake,
1818
Offset mistakePosition,
19-
ColoredTextEditingController controller,
19+
LanguageToolController controller,
2020
);

lib/implementations/throttling_lang_tool_service.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ class ThrottlingLangToolService extends LanguageCheckService {
1919
) : throttling = Throttling(duration: throttlingDuration);
2020

2121
@override
22-
Future<Result<List<Mistake>>> findMistakes(String text) {
22+
Future<Result<List<Mistake>>?> findMistakes(String text) async {
2323
final future = throttling.throttle(() => baseService.findMistakes(text))
24-
as Future<Result<List<Mistake>>?>;
24+
as Future<Result<List<Mistake>>?>?;
25+
26+
if (future == null) return null;
2527

2628
return future.then((res) => res ?? Result.success(<Mistake>[].toList()));
2729
}

lib/languagetool_textfield.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
library languagetool_textfield;
22

33
export 'client/language_tool_client.dart';
4-
export 'core/controllers/colored_text_editing_controller.dart';
4+
export 'core/controllers/language_tool_controller.dart';
5+
export 'core/enums/delay_type.dart';
56
export 'core/model/category.dart';
67
export 'core/model/language_tool_raw.dart';
78
export 'core/model/match.dart';

0 commit comments

Comments
 (0)