Skip to content

Commit

Permalink
Customization approach fix
Browse files Browse the repository at this point in the history
  • Loading branch information
nazarski committed Apr 27, 2023
1 parent 8af6194 commit 8fa0fb7
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 109 deletions.
6 changes: 6 additions & 0 deletions example/lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@ class _AppState extends State<App> {
/// 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(
Expand All @@ -33,6 +38,7 @@ class _AppState extends State<App> {
mistakeBuilder: () {
return Container();
},
coloredController: controller,
),
);
}
Expand Down
117 changes: 60 additions & 57 deletions lib/core/controllers/colored_text_editing_controller.dart
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
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<Mistake> _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);
super.value = newValue;
}

/// Controller constructor
ColoredTextEditingController({this.highlightColorScheme});
ColoredTextEditingController({
this.highlightStyle = const HighlightStyle(),
});

/// Generates TextSpan from Mistake list
@override
Expand All @@ -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<TextSpan> spanList =
_generateSpans(textLength: textLength, style: style);

/// Generator function to create TextSpan instances
Iterable<TextSpan> 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<TextSpan> _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
Expand Down Expand Up @@ -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;
}
}
}
36 changes: 0 additions & 36 deletions lib/domain/highlight_colors.dart

This file was deleted.

48 changes: 48 additions & 0 deletions lib/domain/highlight_style.dart
Original file line number Diff line number Diff line change
@@ -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,
});
}
3 changes: 2 additions & 1 deletion lib/languagetool_textfield.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
22 changes: 7 additions & 15 deletions lib/presentation/language_tool_text_field.dart
Original file line number Diff line number Diff line change
@@ -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]
Expand All @@ -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({
Expand All @@ -27,29 +27,25 @@ class LanguageToolTextField extends StatefulWidget {
required this.style,
required this.decoration,
this.mistakeBuilder,
this.highlightColorScheme,
required this.coloredController,
}) : super(key: key);

@override
State<LanguageToolTextField> createState() => _LanguageToolTextFieldState();
}

class _LanguageToolTextFieldState extends State<LanguageToolTextField> {
ColoredTextEditingController? _controller;

/// Sends API request to get a list of Mistake
Future<void> _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();
}

Expand All @@ -59,12 +55,8 @@ class _LanguageToolTextFieldState extends State<LanguageToolTextField> {
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,
),
Expand All @@ -75,6 +67,6 @@ class _LanguageToolTextFieldState extends State<LanguageToolTextField> {
@override
void dispose() {
super.dispose();
_controller?.dispose(); // disposes controller
widget.coloredController.dispose();
}
}

0 comments on commit 8fa0fb7

Please sign in to comment.