-
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.
All proposed changes have been made.
- Loading branch information
Showing
7 changed files
with
213 additions
and
74 deletions.
There are no files selected for viewing
157 changes: 102 additions & 55 deletions
157
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 |
---|---|---|
@@ -1,107 +1,154 @@ | ||
import 'dart:developer'; | ||
|
||
import 'package:flutter/gestures.dart'; | ||
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/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; | ||
|
||
/// List which contains Mistake objects spans are built from | ||
List<Mistake> _mistakes = []; | ||
|
||
final double _backGroundOpacity = | ||
final double _backgroundOpacity = | ||
0.2; // background opacity for mistake TextSpan | ||
|
||
final double _mistakeLineThickness = | ||
1.5; // mistake TextSpan underline thickness | ||
|
||
/// A method sets new list of Mistake and triggers buildTextSpan | ||
void setMistakes(List<Mistake> list) { | ||
_mistakes = list; | ||
notifyListeners(); | ||
@override | ||
set value(TextEditingValue newValue) { | ||
_handleTextChange(newValue.text); | ||
super.value = newValue; | ||
} | ||
|
||
/// builds TextSpan from Mistake list | ||
/// Controller constructor | ||
ColoredTextEditingController({this.highlightColorScheme}); | ||
|
||
/// Generates TextSpan from Mistake list | ||
@override | ||
TextSpan buildTextSpan({ | ||
required BuildContext context, | ||
TextStyle? style, | ||
required bool withComposing, | ||
}) { | ||
int currentOffset = 0; // enter index | ||
final List<TextSpan> spans = []; // List of TextSpan | ||
final int textLength = text.length; // Length of text to be built | ||
|
||
/// Iterates _mistakes and adds TextSpans from Mistake offset and 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 before mistake | ||
spans.add( | ||
TextSpan( | ||
final int textLength = text.length; | ||
|
||
/// 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, | ||
), | ||
); | ||
); | ||
|
||
/// Setting color of the mistake by its type | ||
final Color mistakeColor = _getMistakeColor(mistake.type); | ||
/// Get a highlight color | ||
final Color mistakeColor = _getMistakeColor(mistake.type); | ||
|
||
/// The mistake TextSpan | ||
spans.add( | ||
TextSpan( | ||
/// Mistake highlighted TextSpan | ||
yield TextSpan( | ||
text: text.substring(mistake.offset, mistake.offset + mistake.length), | ||
mouseCursor: MaterialStateMouseCursor.clickable, | ||
recognizer: TapGestureRecognizer() | ||
..onTapDown = _callOverlay, // calls overlay with mistakes details | ||
style: style?.copyWith( | ||
backgroundColor: mistakeColor.withOpacity(_backGroundOpacity), | ||
backgroundColor: mistakeColor.withOpacity(_backgroundOpacity), | ||
decoration: TextDecoration.underline, | ||
decorationColor: mistakeColor, | ||
decorationThickness: _mistakeLineThickness, | ||
), | ||
), | ||
); | ||
); | ||
|
||
/// Changing enter index position for the next iteration | ||
currentOffset = mistake.offset + mistake.length; | ||
} | ||
currentOffset = mistake.offset + mistake.length; | ||
} | ||
|
||
/// TextSpan after mistake | ||
spans.add( | ||
TextSpan( | ||
/// TextSpan after mistake | ||
yield TextSpan( | ||
text: text.substring(currentOffset), | ||
style: style, | ||
), | ||
); | ||
); | ||
} | ||
|
||
/// Returns TextSpan | ||
return TextSpan(children: spans); | ||
return TextSpan(children: generateSpans().toList()); | ||
} | ||
|
||
void _callOverlay(TapDownDetails details) { | ||
log(details.globalPosition.toString()); | ||
/// Apply changes to Mistake list while new data being fetched | ||
void _handleTextChange(String newText) { | ||
final int deltaLength = newText.length - text.length; | ||
|
||
/// Update the _mistakes list in-place based on the text modifications | ||
_mistakes = _mistakes | ||
.map((mistake) { | ||
int newOffset = mistake.offset; | ||
int newLength = mistake.length; | ||
|
||
/// If the text modification starts within the mistake | ||
if (selection.start >= mistake.offset && | ||
selection.start <= mistake.offset + mistake.length) { | ||
newLength += deltaLength; | ||
} | ||
|
||
/// If the text modification starts before the mistake | ||
else if (selection.start < mistake.offset) { | ||
newOffset += deltaLength; | ||
} | ||
|
||
/// Return the updated mistake (if the length is greater than 0) | ||
return newLength > 0 | ||
? Mistake( | ||
message: mistake.message, | ||
type: mistake.type, | ||
offset: newOffset, | ||
length: newLength, | ||
replacements: mistake.replacements, | ||
) | ||
: null; | ||
}) | ||
.whereType<Mistake>() | ||
.toList(); | ||
|
||
/// Notify listeners to rebuild the widget | ||
notifyListeners(); | ||
} | ||
|
||
/// A method sets new list of Mistake and triggers buildTextSpan | ||
void highlightMistakes(List<Mistake> list) { | ||
_mistakes = list; | ||
notifyListeners(); | ||
} | ||
|
||
/// Returns color for mistake TextSpan style | ||
Color _getMistakeColor(String type) { | ||
Color _getMistakeColor(MistakeType type) { | ||
switch (type) { | ||
case 'misspelling': | ||
return Colors.red; | ||
case 'style': | ||
return Colors.blue; | ||
case 'uncategorized': | ||
return Colors.amber; | ||
default: | ||
return Colors.green; | ||
case MistakeType.misspelling: | ||
return highlightColorScheme?.misspellingMistakeColor ?? Colors.red; | ||
case MistakeType.typographical: | ||
return highlightColorScheme?.typographicalMistakeColor ?? Colors.green; | ||
case MistakeType.grammar: | ||
return highlightColorScheme?.grammarMistakeColor ?? Colors.amber; | ||
case MistakeType.uncategorized: | ||
return highlightColorScheme?.uncategorizedMistakeColor ?? Colors.blue; | ||
case MistakeType.nonConformance: | ||
return highlightColorScheme?.nonConformanceMistakeColor ?? | ||
Colors.greenAccent; | ||
case MistakeType.style: | ||
return highlightColorScheme?.styleMistakeColor ?? | ||
Colors.deepPurpleAccent; | ||
case MistakeType.other: | ||
return highlightColorScheme?.otherMistakeColor ?? Colors.white60; | ||
} | ||
} | ||
} |
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,36 @@ | ||
import 'dart:ui'; | ||
|
||
/// Class creates color scheme for highlighting mistakes | ||
class HighlightColors { | ||
/// 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; | ||
|
||
///Color scheme constructor | ||
HighlightColors( | ||
this.misspellingMistakeColor, | ||
this.typographicalMistakeColor, | ||
this.grammarMistakeColor, | ||
this.uncategorizedMistakeColor, | ||
this.nonConformanceMistakeColor, | ||
this.styleMistakeColor, | ||
this.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
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
Oops, something went wrong.