Skip to content

Commit

Permalink
Merge pull request #48 from solid-software/feat/remove_language_tool_…
Browse files Browse the repository at this point in the history
…package

Feat/remove language tool package
  • Loading branch information
solid-danylokhvan committed Jul 4, 2023
2 parents cddfd8e + dc134c4 commit 274082f
Show file tree
Hide file tree
Showing 12 changed files with 316 additions and 43 deletions.
4 changes: 2 additions & 2 deletions example/lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ class App extends StatefulWidget {
}

class _AppState extends State<App> {
/// Initialize LanguageTool
static final LanguageTool _languageTool = LanguageTool();
/// Initialize LanguageToolClient
static final LanguageToolClient _languageTool = LanguageToolClient();

/// Initialize DebounceLangToolService
static final DebounceLangToolService _debouncedLangService =
Expand Down
74 changes: 74 additions & 0 deletions lib/client/language_tool_client.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import 'dart:convert';

import 'package:http/http.dart' as http;
import 'package:languagetool_textfield/core/model/language_tool_raw.dart';
import 'package:languagetool_textfield/domain/writing_mistake.dart';

/// Class to interact with the LanguageTool API.
///
/// Read more @ https://languagetool.org/http-api/swagger-ui/#/
class LanguageToolClient {
/// Url of LanguageTool API.
static const _url = 'api.languagetoolplus.com';

/// Headers for request.
static const _headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
};

/// Constructor for [LanguageToolClient].
LanguageToolClient();

/// Checks the errors in text.
Future<List<WritingMistake>> check(
String text, {
String language = 'auto',
}) async {
final encodedText = Uri.encodeQueryComponent(text);
final encodedLanguage = Uri.encodeQueryComponent(language);

final result = await http.post(
Uri.https(_url, 'v2/check', {
'text': encodedText,
'language': encodedLanguage,
'enabledOnly': 'false',
'level': 'default',
}),
headers: _headers,
);

final languageToolAnswer = LanguageToolRaw.fromJson(
json.decode(result.body) as Map<String, dynamic>,
);

return _parseRawAnswer(languageToolAnswer);
}

/// Converts a [LanguageToolRaw] in a [WritingMistake].
List<WritingMistake> _parseRawAnswer(
LanguageToolRaw languageToolAnswer,
) {
final result = <WritingMistake>[];
for (final match in languageToolAnswer.matches) {
final replacements = <String>[];
for (final item in match.replacements) {
replacements.add(item.value);
}

result.add(
WritingMistake(
issueDescription: match.rule.description,
issueType: match.rule.issueType,
length: match.length,
offset: match.offset,
replacements: replacements,
message: match.message,
shortMessage: match.shortMessage,
),
);
}

return result;
}
}
29 changes: 22 additions & 7 deletions lib/core/enums/mistake_type.dart
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@
///Enumerate several mistake types
enum MistakeType {
/// Misspelling mistake type
misspelling,
misspelling('misspelling'),

/// Typographical mistake type
typographical,
typographical('typographical'),

/// Grammar mistake type
grammar,
grammar('grammar'),

/// Uncategorized mistake type
uncategorized,
uncategorized('uncategorized'),

/// NonConformance mistake type
nonConformance,
nonConformance('nonconformance'),

/// Style mistake type
style,
style('style'),

/// Any other mistake type
other,
other('other');

/// The string value associated with the MistakeType variant
final String value;

const MistakeType(this.value);

/// Getting the [MistakeType] from String.
static MistakeType fromString(String value) {
final lowercasedValue = value.toLowerCase();

return MistakeType.values.firstWhere(
(type) => type.value == lowercasedValue,
orElse: () => MistakeType.other,
);
}
}
20 changes: 20 additions & 0 deletions lib/core/model/category.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/// Object that stores information about category of the rule.
class Category {
/// Id field.
final String id;

/// Name field.
final String name;

/// Creates a new instance of the [Category] class.
Category({
required this.id,
required this.name,
});

/// Parse [Category] from json.
factory Category.fromJson(Map<String, dynamic> json) => Category(
id: json['id'] as String,
name: json['name'] as String,
);
}
24 changes: 24 additions & 0 deletions lib/core/model/language_tool_raw.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:languagetool_textfield/languagetool_textfield.dart';

/// The raw bean that is returned from the API call.
///
/// It's possible to add software, language and warning information.
class LanguageToolRaw {
/// The matched mistakes.
final List<Match> matches;

/// Creates a new instance of the [LanguageToolRaw] class.
LanguageToolRaw({
required this.matches,
});

/// Parse [LanguageToolRaw] from json.
factory LanguageToolRaw.fromJson(Map<String, dynamic> json) =>
LanguageToolRaw(
matches: (json['matches'] as Iterable)
.map<Match>(
(e) => Match.fromJson(e as Map<String, dynamic>),
)
.toList(),
);
}
63 changes: 63 additions & 0 deletions lib/core/model/match.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import 'package:languagetool_textfield/core/model/replacement.dart';
import 'package:languagetool_textfield/core/model/rule.dart';

/// Object that stores information about matched mistakes.
class Match {
/// The message about the error.
final String message;

/// Shortened message (may be empty).
final String shortMessage;

/// List of possible replacements
final List<Replacement> replacements;

/// Offset to the word.
final int offset;

/// Length of the word.
final int length;

/// The whole sentence.
final String sentence;

/// The mistake's rule.
final Rule rule;

/// Flag that indicates if the mistake is because sentence is incomplete.
final bool ignoreForIncompleteSentence;

/// Context for sure match (i.e. -1, 0, 1, etc).
final int contextForSureMatch;

/// Creates a new instance of the [Match] class.
Match({
required this.message,
required this.shortMessage,
required this.replacements,
required this.offset,
required this.length,
required this.sentence,
required this.rule,
required this.ignoreForIncompleteSentence,
required this.contextForSureMatch,
});

/// Parse [Match] from json.
factory Match.fromJson(Map<String, dynamic> json) => Match(
message: json['message'] as String,
shortMessage: json['shortMessage'] as String,
replacements: (json['replacements'] as Iterable)
.map<Replacement>(
(e) => Replacement.fromJson(e as Map<String, dynamic>),
)
.toList(),
offset: json['offset'] as int,
length: json['length'] as int,
sentence: json['sentence'] as String,
rule: Rule.fromJson(json['rule'] as Map<String, dynamic>),
ignoreForIncompleteSentence:
json['ignoreForIncompleteSentence'] as bool,
contextForSureMatch: json['contextForSureMatch'] as int,
);
}
15 changes: 15 additions & 0 deletions lib/core/model/replacement.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/// Object that stores information about possible replacement.
class Replacement {
/// The replacement word.
final String value;

/// Creates a new instance of the [Replacement] class.
Replacement({
required this.value,
});

/// Parse [Replacement] from json.
factory Replacement.fromJson(Map<String, dynamic> json) => Replacement(
value: json['value'] as String,
);
}
38 changes: 38 additions & 0 deletions lib/core/model/rule.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'package:languagetool_textfield/core/enums/mistake_type.dart';
import 'package:languagetool_textfield/core/model/category.dart';

/// Object that stores information about the rule (description, type, etc).
class Rule {
/// Id (i.e.UPPERCASE_SENTENCE_START).
final String id;

/// The description in the set language.
final String description;

/// The type of the error (spelling, typographical, etc).
final MistakeType issueType;

/// The category of the rule.
final Category category;

/// The subscription status of the rule.
final bool isPremium;

/// Creates a new instance of the [Rule] class.
Rule({
required this.id,
required this.description,
required this.issueType,
required this.category,
required this.isPremium,
});

/// Parse [Rule] from json.
factory Rule.fromJson(Map<String, dynamic> json) => Rule(
id: json['id'] as String,
description: json['description'] as String,
issueType: MistakeType.fromString(json['issueType'] as String),
category: Category.fromJson(json['category'] as Map<String, dynamic>),
isPremium: json['isPremium'] as bool,
);
}
38 changes: 38 additions & 0 deletions lib/domain/writing_mistake.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'package:languagetool_textfield/core/enums/mistake_type.dart';

/// Object that stores information about a single writing mistake.
class WritingMistake {
/// Position of the beginning of the mistake.
final int offset;

/// Length of the mistake after the offset.
final int length;

/// The type of mistake.
final MistakeType issueType;

/// Description of the [issueType].
final String issueDescription;

/// A brief description of the mistake.
final String message;

/// A list of suggestions for replacing the mistake.
///
/// Sorted by probability.
final List<String> replacements;

/// An optional shorter version of 'message'. ,
final String shortMessage;

/// Constructor for [WritingMistake].
WritingMistake({
required this.message,
required this.offset,
required this.length,
required this.issueType,
required this.issueDescription,
required this.replacements,
required this.shortMessage,
});
}
Loading

0 comments on commit 274082f

Please sign in to comment.