-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from solid-software/nazarski
Textfield with mistake highlights
- Loading branch information
Showing
9 changed files
with
297 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,47 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:languagetool_textfield/languagetool_textfield.dart'; | ||
|
||
/// Example App main page | ||
class App extends StatefulWidget { | ||
/// Example app constructor | ||
const App({super.key}); | ||
|
||
@override | ||
State<App> createState() => _AppState(); | ||
} | ||
|
||
class _AppState extends State<App> { | ||
/// Initialize LanguageTool | ||
static final LanguageTool _languageTool = LanguageTool(); | ||
|
||
/// Initialize DebounceLangToolService | ||
static final DebounceLangToolService _debouncedLangService = | ||
DebounceLangToolService( | ||
LangToolService(_languageTool), | ||
const Duration(milliseconds: 500), | ||
); | ||
|
||
/// Initialize ColoredTextEditingController | ||
final ColoredTextEditingController _controller = | ||
ColoredTextEditingController(languageCheckService: _debouncedLangService); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return const Placeholder(); | ||
return Material( | ||
child: LanguageToolTextField( | ||
style: const TextStyle(), | ||
decoration: const InputDecoration(), | ||
mistakeBuilder: () { | ||
return Container(); | ||
}, | ||
coloredController: _controller, | ||
), | ||
); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_controller.dispose(); | ||
super.dispose(); | ||
} | ||
} |
128 changes: 128 additions & 0 deletions
128
lib/core/controllers/colored_text_editing_controller.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:languagetool_textfield/core/enums/mistake_type.dart'; | ||
import 'package:languagetool_textfield/domain/highlight_style.dart'; | ||
import 'package:languagetool_textfield/domain/language_check_service.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 HighlightStyle highlightStyle; | ||
|
||
/// Language tool API index | ||
final LanguageCheckService languageCheckService; | ||
|
||
/// List which contains Mistake objects spans are built from | ||
List<Mistake> _mistakes = []; | ||
|
||
@override | ||
set value(TextEditingValue newValue) { | ||
_handleTextChange(newValue.text); | ||
super.value = newValue; | ||
} | ||
|
||
/// Controller constructor | ||
ColoredTextEditingController({ | ||
required this.languageCheckService, | ||
this.highlightStyle = const HighlightStyle(), | ||
}); | ||
|
||
/// Clear mistakes list when text mas modified and get a new list of mistakes | ||
/// via API | ||
Future<void> _handleTextChange(String newText) async { | ||
///set value triggers each time, even when cursor changes its location | ||
///so this check avoid cleaning Mistake list when text wasn't really changed | ||
if (newText.length == text.length) return; | ||
_mistakes.clear(); | ||
final mistakes = await languageCheckService.findMistakes(newText); | ||
if (mistakes.isNotEmpty) { | ||
_mistakes = mistakes; | ||
notifyListeners(); | ||
} | ||
} | ||
|
||
/// Generates TextSpan from Mistake list | ||
@override | ||
TextSpan buildTextSpan({ | ||
required BuildContext context, | ||
TextStyle? style, | ||
required bool withComposing, | ||
}) { | ||
final formattedTextSpans = _generateSpans( | ||
style: style, | ||
); | ||
|
||
return TextSpan( | ||
children: formattedTextSpans.toList(), | ||
); | ||
} | ||
|
||
/// Generator function to create TextSpan instances | ||
Iterable<TextSpan> _generateSpans({ | ||
TextStyle? style, | ||
}) sync* { | ||
int currentOffset = 0; // enter index | ||
|
||
for (final Mistake mistake in _mistakes) { | ||
/// 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( | ||
children: [ | ||
TextSpan( | ||
text: | ||
text.substring(mistake.offset, mistake.offset + mistake.length), | ||
mouseCursor: MaterialStateMouseCursor.clickable, | ||
style: style?.copyWith( | ||
backgroundColor: mistakeColor.withOpacity( | ||
highlightStyle.backgroundOpacity, | ||
), | ||
decoration: highlightStyle.decoration, | ||
decorationColor: mistakeColor, | ||
decorationThickness: highlightStyle.mistakeLineThickness, | ||
), | ||
), | ||
], | ||
); | ||
|
||
currentOffset = mistake.offset + mistake.length; | ||
} | ||
|
||
/// TextSpan after mistake | ||
yield TextSpan( | ||
text: text.substring(currentOffset), | ||
style: style, | ||
); | ||
} | ||
|
||
/// Returns color for mistake TextSpan style | ||
Color _getMistakeColor(MistakeType type) { | ||
switch (type) { | ||
case MistakeType.misspelling: | ||
return highlightStyle.misspellingMistakeColor; | ||
case MistakeType.typographical: | ||
return highlightStyle.typographicalMistakeColor; | ||
case MistakeType.grammar: | ||
return highlightStyle.grammarMistakeColor; | ||
case MistakeType.uncategorized: | ||
return highlightStyle.uncategorizedMistakeColor; | ||
case MistakeType.nonConformance: | ||
return highlightStyle.nonConformanceMistakeColor; | ||
case MistakeType.style: | ||
return highlightStyle.styleMistakeColor; | ||
case MistakeType.other: | ||
return highlightStyle.otherMistakeColor; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
///Enumerate several mistake types | ||
enum MistakeType { | ||
/// Misspelling mistake type | ||
misspelling, | ||
|
||
/// Typographical mistake type | ||
typographical, | ||
|
||
/// Grammar mistake type | ||
grammar, | ||
|
||
/// Uncategorized mistake type | ||
uncategorized, | ||
|
||
/// NonConformance mistake type | ||
nonConformance, | ||
|
||
/// Style mistake type | ||
style, | ||
|
||
/// Any other mistake type | ||
other, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
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; | ||
|
||
/// Mistaken text decoration style | ||
final TextDecoration decoration; | ||
|
||
///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, | ||
this.decoration = TextDecoration.underline, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,12 @@ | ||
library languagetool_textfield; | ||
|
||
export 'package:language_tool/language_tool.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'; | ||
export 'implementations/lang_tool_service.dart'; | ||
export 'implementations/throttling_lang_tool_service.dart'; | ||
export "presentation/language_tool_text_field.dart"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters