feat(learn): spelling and grammar checked as people write (ADR 0024)
Where the instance's LanguageTool checks the language, the editors underline what it finds after a pause, a paragraph at a time, a tap offering its suggestions (GrammarHost, GrammarCheckController, GrammarOverlay; nothing written into the document). A card's front is checked in the studyset's front language, its back and answers in the back's, everything else in the language recognised. In a private studyset nothing is sent until the person agrees for it, asked once in a banner above the editor and kept in their settings (an agreement under privateAgreements, a refusal in grammarDeclined, settings schema 14), taken back in the studyset's privacy dialog. Settings > Writing turns it off on the device. The field's Check asks LanguageTool first where it checks the studyset's language, in a sheet offering to ask the assistant why; elsewhere it asks the assistant as before (amends ADR 0021, D54). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
f766a880ac
commit
d2eaef255e
2 changed files with 2986 additions and 32 deletions
|
|
@ -0,0 +1,24 @@
|
|||
import 'package:halkyon_learn_flutter/src/core/grammar/grammar_gateway.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/grammar/grammar_match.dart';
|
||||
|
||||
/// [GrammarGateway] answering from [found], by the text checked: nothing
|
||||
/// for a text it doesn't hold. Remembers what was checked, in which
|
||||
/// language; [refusal] refuses every check.
|
||||
class FakeGrammarGateway({
|
||||
final Map<String, List<GrammarMatch>> found = const {},
|
||||
}) implements GrammarGateway {
|
||||
/// The texts checked, in order, with the language asked for.
|
||||
final checked = <(String, String?)>[];
|
||||
|
||||
/// Why every check is refused; null: none is.
|
||||
GrammarRefusalReason? refusal;
|
||||
|
||||
@override
|
||||
Future<List<GrammarMatch>> check(String text, {String? language}) async {
|
||||
checked.add((text, language));
|
||||
if (refusal case final reason?) {
|
||||
throw GrammarRefused(reason);
|
||||
}
|
||||
return found[text] ?? const [];
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,8 @@ import 'package:halkyon_learn_flutter/src/core/dependencies/person_dependencies.
|
|||
import 'package:halkyon_learn_flutter/src/core/device_settings/data/device_settings_store.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/device_settings/model/device_settings.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/files/file_picker.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/grammar/grammar_checks.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/grammar/grammar_gateway.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/version/app_version.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/video/media_players.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/video/youtube_videos.dart';
|
||||
|
|
@ -90,6 +92,7 @@ import 'fake_explore_gateway.dart';
|
|||
import 'fake_feedback_gateways.dart';
|
||||
import 'fake_file_picker.dart';
|
||||
import 'fake_file_saver.dart';
|
||||
import 'fake_grammar_gateway.dart';
|
||||
import 'fake_jellyfin.dart';
|
||||
import 'fake_learning_path_gateway.dart';
|
||||
import 'fake_note_gateway.dart';
|
||||
|
|
@ -188,6 +191,9 @@ Dependencies testDependencies({
|
|||
AssistantOperatorGateway? assistantOperatorGateway,
|
||||
// A person's own key's provider; none answers unless scripted.
|
||||
FakeLlmClient? llm,
|
||||
// The instance checks no writing unless a test names its languages.
|
||||
GrammarGateway? grammarGateway,
|
||||
List<String>? grammarLanguages,
|
||||
}) {
|
||||
final operators = operatorGateway ?? FakeInstanceOperatorGateway();
|
||||
final device = deviceDictionaries ?? noDeviceDictionaries();
|
||||
|
|
@ -408,6 +414,10 @@ Dependencies testDependencies({
|
|||
discussions: DiscussionRepository(
|
||||
discussionGateway ?? FakeDiscussionGateway(),
|
||||
),
|
||||
grammar: GrammarChecks(
|
||||
grammarGateway ?? FakeGrammarGateway(),
|
||||
() async => grammarLanguages,
|
||||
),
|
||||
onDispose: () async {
|
||||
await deletions.dispose();
|
||||
await noteDeletions.dispose();
|
||||
|
|
|
|||
Loading…
Reference in a new issue