feat(learn): the assistant's field laid out as Claude's, with files attached and questions spoken, and no Check (ADR 0021, D67)

The question's text stands above its buttons: + attaching files, who
answers as a chip (Effort now a submenu of it), the conversations kept,
and the microphone while nothing is written, which gives way to the
button sending. What goes along is one row above the text, opening a
sheet with how far the assistant looks and the parts to send. A
conversation's follow-up has the same + and microphone.

Files are read on the device: an image goes as itself to an assistant
that reads images, a PDF as its pages' text, a text file as its text,
each cut at 20,000 characters and labelled by its name after the
question.

Voice is the device's own speech recognition (speech_to_text: Android,
Apple, Windows; none on Linux), in the app's language, the microphone
asked for once tapped. The privacy page says that Android's recogniser
may send the sound to Google or the phone's maker.

The field's Check goes, with its LanguageTool sheet (amending ADR 0024);
the editors' underlining and Why? stay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-02 05:50:36 +01:00
commit 447e00c52a
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
5 changed files with 1843 additions and 1085 deletions

View file

@ -1839,11 +1839,27 @@
"assistantScope": "Was er nachschlagen darf",
"assistantEffortTooltip": "Denkaufwand: wie viel er nachdenkt, bevor er antwortet",
"assistantEffortDefault": "{effort} (Standard)",
"assistantEffortMenu": "Denkaufwand: {effort}",
"assistantContext": "Was mitgeht",
"assistantContextReach": "Wie weit er schaut",
"assistantContextParts": "Mitschicken",
"assistantContextChosen": "{count, plural, =1{1 Teil} other{{count} Teile}}",
"assistantContextDone": "Fertig",
"assistantAttach": "Foto oder Datei anhängen",
"assistantAttachFile": "Datei anhängen",
"assistantAttachFiles": "Bilder, PDFs und Textdateien",
"assistantAttachNotRead": "{name} kann nicht mit: nur Bilder, PDFs und Textdateien können es.",
"assistantAttachTooLarge": "{name} ist größer als 5 MB, mehr als Assistenten annehmen.",
"assistantAttachNoImages": "{name} ist ein Bild, und {assistant} liest keine.",
"assistantAttachRemove": "Entfernen",
"assistantSpeak": "Frage sprechen",
"assistantStopListening": "Zuhören beenden",
"assistantSpeechUnavailable": "Dieses Gerät kann gerade nicht zuhören. Prüfe, ob die App das Mikrofon nutzen darf und die Spracherkennung an ist.",
"assistantScopeTicked": "Nur was ich auswähle",
"assistantScopeStudyset": "Dieses Lernset",
"assistantScopeTree": "Ganzer Baum",
"assistantScopeLibrary": "Bibliothek",
"assistantScopeTickedLong": "Nur was ich oben auswähle",
"assistantScopeTickedLong": "Nur was ich mitschicke",
"assistantScopeStudysetLong": "Dieses Lernset mit seinen Themen",
"assistantScopeTreeLong": "Sein ganzer Baum, von oben",
"assistantScopeLibraryLong": "Meine ganze Bibliothek",
@ -1902,19 +1918,11 @@
"assistantExplainQuestion": "Warum ist das die Antwort?",
"studyTypedWhy": "Warum?",
"assistantWhyTyped": "Ich habe „{typed}“ getippt. Warum stimmt das nicht?",
"assistantCheck": "Auf Fehler prüfen",
"grammarNoSuggestions": "Keine Vorschläge",
"grammarNothingFound": "Keine Rechtschreib- oder Grammatikfehler gefunden",
"grammarPrivateAsk": "Rechtschreibung und Grammatik in diesem privaten Lernset prüfen? Während geprüft wird, geht, was du hier schreibst, lesbar an {instance}, ein Absatz nach dem anderen; weder die Instanz noch ihr LanguageTool behält etwas davon. Gefragt wird einmal für dieses Lernset und seine Themen.",
"grammarPrivateNotHere": "Hier nicht",
"grammarPrivateCheckHere": "Hier prüfen",
"grammarCheckTitle": "Rechtschreibung und Grammatik",
"grammarCheckTooOften": "Gerade zu oft geprüft. Versuche es in einer Minute erneut.",
"grammarCheckTooLong": "Zu lang, um es auf einmal zu prüfen.",
"grammarCheckUnknownLanguage": "Diese Sprache prüft die Instanz nicht.",
"grammarCheckFailed": "Die Prüfung der Instanz ist nicht erreichbar. Versuche es später erneut.",
"grammarCheckAskWhy": "{name} fragen, warum",
"grammarCheckAskInstead": "{name} prüfen lassen",
"proposalsTitle": "Karteikarten von {name}",
"proposalsWriting": "{name} schreibt Karteikarten …",
"proposalsNone": "{name} hat keine Karteikarten vorgeschlagen.",

View file

@ -2165,11 +2165,37 @@
"@assistantEffortTooltip": {"description": "Tooltip of the effort chip in the field (ADR 0021, D63): more effort thinks longer and uses more of the budget."},
"assistantEffortDefault": "{effort} (default)",
"@assistantEffortDefault": {"description": "The effort the operator set up for an assistant, among those to choose, by its name.", "placeholders": {"effort": {"type": "String"}}},
"assistantEffortMenu": "Effort: {effort}",
"@assistantEffortMenu": {"description": "In the menu of who answers, the submenu of how much the assistant thinks (D63), with the one it asks at.", "placeholders": {"effort": {"type": "String"}}},
"assistantContext": "What goes along",
"@assistantContext": {"description": "Title of the sheet, and tooltip of the row below the field opening it (D67): how far the assistant looks, and the parts sent along."},
"assistantContextReach": "How far it looks",
"assistantContextParts": "Send along",
"assistantContextChosen": "{count, plural, =1{1 part} other{{count} parts}}",
"@assistantContextChosen": {"description": "Beside how far it looks on the row below the field: how many parts were chosen to go along.", "placeholders": {"count": {"type": "int"}}},
"assistantContextDone": "Done",
"assistantAttach": "Attach a photo or file",
"@assistantAttach": {"description": "The + below the field (D67), for an assistant that reads images."},
"assistantAttachFile": "Attach a file",
"@assistantAttachFile": {"description": "The + below the field (D67), for an assistant that reads no images."},
"assistantAttachFiles": "Images, PDFs and text files",
"@assistantAttachFiles": {"description": "The kind of files the + offers, in the platform's file dialog."},
"assistantAttachNotRead": "{name} can't go along: only images, PDFs and text files can.",
"@assistantAttachNotRead": {"placeholders": {"name": {"type": "String"}}},
"assistantAttachTooLarge": "{name} is larger than 5 MB, more than assistants take.",
"@assistantAttachTooLarge": {"placeholders": {"name": {"type": "String"}}},
"assistantAttachNoImages": "{name} is an image, and {assistant} reads none.",
"@assistantAttachNoImages": {"placeholders": {"name": {"type": "String"}, "assistant": {"type": "String"}}},
"assistantAttachRemove": "Remove",
"assistantSpeak": "Speak your question",
"@assistantSpeak": {"description": "The microphone below the field while it is empty (D67): the device's own speech recognition writes what is said."},
"assistantStopListening": "Stop listening",
"assistantSpeechUnavailable": "This device can't listen now. Check that the app may use the microphone and that speech recognition is on.",
"assistantScopeTicked": "Only what I choose",
"assistantScopeStudyset": "This studyset",
"assistantScopeTree": "Its tree",
"assistantScopeLibrary": "Library",
"assistantScopeTickedLong": "Only what I choose above",
"assistantScopeTickedLong": "Only what I send along",
"assistantScopeStudysetLong": "This studyset with its topics",
"assistantScopeTreeLong": "Its whole tree, from the top",
"assistantScopeLibraryLong": "My whole library",
@ -2254,8 +2280,6 @@
"@studyTypedWhy": {"description": "Asks an assistant why a reading typed is wrong (D54)."},
"assistantWhyTyped": "I typed “{typed}”. Why isn't that right?",
"@assistantWhyTyped": {"description": "The question an assistant is asked about a reading typed wrong.", "placeholders": {"typed": {"type": "String"}}},
"assistantCheck": "Check for mistakes",
"@assistantCheck": {"description": "Has an assistant check what was written in the field (D54)."},
"grammarNoSuggestions": "No suggestions",
"@grammarNoSuggestions": {"description": "In place of suggestions for a mistake that has none."},
"grammarNothingFound": "No spelling or grammar mistakes found",
@ -2263,16 +2287,6 @@
"@grammarPrivateAsk": {"placeholders": {"instance": {"type": "String"}}, "description": "The banner above an editor in a private studyset not asked yet (ADR 0024)."},
"grammarPrivateNotHere": "Not here",
"grammarPrivateCheckHere": "Check here",
"grammarCheckTitle": "Spelling and grammar",
"@grammarCheckTitle": {"description": "The field's Check sheet, what the instance's LanguageTool found."},
"grammarCheckTooOften": "Checked too often for now. Try again in a minute.",
"grammarCheckTooLong": "Too long to check at once.",
"grammarCheckUnknownLanguage": "The instance doesn't check this language.",
"grammarCheckFailed": "The instance's check couldn't be reached. Try again later.",
"grammarCheckAskWhy": "Ask {name} why",
"@grammarCheckAskWhy": {"placeholders": {"name": {"type": "String"}}},
"grammarCheckAskInstead": "Ask {name} to check",
"@grammarCheckAskInstead": {"placeholders": {"name": {"type": "String"}}},
"proposalsTitle": "Flashcards by {name}",
"@proposalsTitle": {"description": "The sheet of cards an assistant proposes (ADR 0021, D55).", "placeholders": {"name": {"type": "String"}}},
"proposalsWriting": "{name} is writing flashcards…",

View file

@ -10851,6 +10851,102 @@ abstract class AppLocalizations {
/// **'{effort} (default)'**
String assistantEffortDefault(String effort);
/// In the menu of who answers, the submenu of how much the assistant thinks (D63), with the one it asks at.
///
/// In en, this message translates to:
/// **'Effort: {effort}'**
String assistantEffortMenu(String effort);
/// Title of the sheet, and tooltip of the row below the field opening it (D67): how far the assistant looks, and the parts sent along.
///
/// In en, this message translates to:
/// **'What goes along'**
String get assistantContext;
/// No description provided for @assistantContextReach.
///
/// In en, this message translates to:
/// **'How far it looks'**
String get assistantContextReach;
/// No description provided for @assistantContextParts.
///
/// In en, this message translates to:
/// **'Send along'**
String get assistantContextParts;
/// Beside how far it looks on the row below the field: how many parts were chosen to go along.
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 part} other{{count} parts}}'**
String assistantContextChosen(int count);
/// No description provided for @assistantContextDone.
///
/// In en, this message translates to:
/// **'Done'**
String get assistantContextDone;
/// The + below the field (D67), for an assistant that reads images.
///
/// In en, this message translates to:
/// **'Attach a photo or file'**
String get assistantAttach;
/// The + below the field (D67), for an assistant that reads no images.
///
/// In en, this message translates to:
/// **'Attach a file'**
String get assistantAttachFile;
/// The kind of files the + offers, in the platform's file dialog.
///
/// In en, this message translates to:
/// **'Images, PDFs and text files'**
String get assistantAttachFiles;
/// No description provided for @assistantAttachNotRead.
///
/// In en, this message translates to:
/// **'{name} can\'t go along: only images, PDFs and text files can.'**
String assistantAttachNotRead(String name);
/// No description provided for @assistantAttachTooLarge.
///
/// In en, this message translates to:
/// **'{name} is larger than 5 MB, more than assistants take.'**
String assistantAttachTooLarge(String name);
/// No description provided for @assistantAttachNoImages.
///
/// In en, this message translates to:
/// **'{name} is an image, and {assistant} reads none.'**
String assistantAttachNoImages(String name, String assistant);
/// No description provided for @assistantAttachRemove.
///
/// In en, this message translates to:
/// **'Remove'**
String get assistantAttachRemove;
/// The microphone below the field while it is empty (D67): the device's own speech recognition writes what is said.
///
/// In en, this message translates to:
/// **'Speak your question'**
String get assistantSpeak;
/// No description provided for @assistantStopListening.
///
/// In en, this message translates to:
/// **'Stop listening'**
String get assistantStopListening;
/// No description provided for @assistantSpeechUnavailable.
///
/// In en, this message translates to:
/// **'This device can\'t listen now. Check that the app may use the microphone and that speech recognition is on.'**
String get assistantSpeechUnavailable;
/// No description provided for @assistantScopeTicked.
///
/// In en, this message translates to:
@ -10878,7 +10974,7 @@ abstract class AppLocalizations {
/// No description provided for @assistantScopeTickedLong.
///
/// In en, this message translates to:
/// **'Only what I choose above'**
/// **'Only what I send along'**
String get assistantScopeTickedLong;
/// No description provided for @assistantScopeStudysetLong.
@ -11234,12 +11330,6 @@ abstract class AppLocalizations {
/// **'I typed “{typed}”. Why isn\'t that right?'**
String assistantWhyTyped(String typed);
/// Has an assistant check what was written in the field (D54).
///
/// In en, this message translates to:
/// **'Check for mistakes'**
String get assistantCheck;
/// In place of suggestions for a mistake that has none.
///
/// In en, this message translates to:
@ -11270,48 +11360,6 @@ abstract class AppLocalizations {
/// **'Check here'**
String get grammarPrivateCheckHere;
/// The field's Check sheet, what the instance's LanguageTool found.
///
/// In en, this message translates to:
/// **'Spelling and grammar'**
String get grammarCheckTitle;
/// No description provided for @grammarCheckTooOften.
///
/// In en, this message translates to:
/// **'Checked too often for now. Try again in a minute.'**
String get grammarCheckTooOften;
/// No description provided for @grammarCheckTooLong.
///
/// In en, this message translates to:
/// **'Too long to check at once.'**
String get grammarCheckTooLong;
/// No description provided for @grammarCheckUnknownLanguage.
///
/// In en, this message translates to:
/// **'The instance doesn\'t check this language.'**
String get grammarCheckUnknownLanguage;
/// No description provided for @grammarCheckFailed.
///
/// In en, this message translates to:
/// **'The instance\'s check couldn\'t be reached. Try again later.'**
String get grammarCheckFailed;
/// No description provided for @grammarCheckAskWhy.
///
/// In en, this message translates to:
/// **'Ask {name} why'**
String grammarCheckAskWhy(String name);
/// No description provided for @grammarCheckAskInstead.
///
/// In en, this message translates to:
/// **'Ask {name} to check'**
String grammarCheckAskInstead(String name);
/// The sheet of cards an assistant proposes (ADR 0021, D55).
///
/// In en, this message translates to:

View file

@ -6796,6 +6796,71 @@ class AppLocalizationsDe extends AppLocalizations {
return '$effort (Standard)';
}
@override
String assistantEffortMenu(String effort) {
return 'Denkaufwand: $effort';
}
@override
String get assistantContext => 'Was mitgeht';
@override
String get assistantContextReach => 'Wie weit er schaut';
@override
String get assistantContextParts => 'Mitschicken';
@override
String assistantContextChosen(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Teile',
one: '1 Teil',
);
return '$_temp0';
}
@override
String get assistantContextDone => 'Fertig';
@override
String get assistantAttach => 'Foto oder Datei anhängen';
@override
String get assistantAttachFile => 'Datei anhängen';
@override
String get assistantAttachFiles => 'Bilder, PDFs und Textdateien';
@override
String assistantAttachNotRead(String name) {
return '$name kann nicht mit: nur Bilder, PDFs und Textdateien können es.';
}
@override
String assistantAttachTooLarge(String name) {
return '$name ist größer als 5 MB, mehr als Assistenten annehmen.';
}
@override
String assistantAttachNoImages(String name, String assistant) {
return '$name ist ein Bild, und $assistant liest keine.';
}
@override
String get assistantAttachRemove => 'Entfernen';
@override
String get assistantSpeak => 'Frage sprechen';
@override
String get assistantStopListening => 'Zuhören beenden';
@override
String get assistantSpeechUnavailable =>
'Dieses Gerät kann gerade nicht zuhören. Prüfe, ob die App das Mikrofon nutzen darf und die Spracherkennung an ist.';
@override
String get assistantScopeTicked => 'Nur was ich auswähle';
@ -6809,7 +6874,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get assistantScopeLibrary => 'Bibliothek';
@override
String get assistantScopeTickedLong => 'Nur was ich oben auswähle';
String get assistantScopeTickedLong => 'Nur was ich mitschicke';
@override
String get assistantScopeStudysetLong => 'Dieses Lernset mit seinen Themen';
@ -7087,9 +7152,6 @@ class AppLocalizationsDe extends AppLocalizations {
return 'Ich habe „$typed“ getippt. Warum stimmt das nicht?';
}
@override
String get assistantCheck => 'Auf Fehler prüfen';
@override
String get grammarNoSuggestions => 'Keine Vorschläge';
@ -7108,34 +7170,6 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get grammarPrivateCheckHere => 'Hier prüfen';
@override
String get grammarCheckTitle => 'Rechtschreibung und Grammatik';
@override
String get grammarCheckTooOften =>
'Gerade zu oft geprüft. Versuche es in einer Minute erneut.';
@override
String get grammarCheckTooLong => 'Zu lang, um es auf einmal zu prüfen.';
@override
String get grammarCheckUnknownLanguage =>
'Diese Sprache prüft die Instanz nicht.';
@override
String get grammarCheckFailed =>
'Die Prüfung der Instanz ist nicht erreichbar. Versuche es später erneut.';
@override
String grammarCheckAskWhy(String name) {
return '$name fragen, warum';
}
@override
String grammarCheckAskInstead(String name) {
return '$name prüfen lassen';
}
@override
String proposalsTitle(String name) {
return 'Karteikarten von $name';

View file

@ -6732,6 +6732,71 @@ class AppLocalizationsEn extends AppLocalizations {
return '$effort (default)';
}
@override
String assistantEffortMenu(String effort) {
return 'Effort: $effort';
}
@override
String get assistantContext => 'What goes along';
@override
String get assistantContextReach => 'How far it looks';
@override
String get assistantContextParts => 'Send along';
@override
String assistantContextChosen(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count parts',
one: '1 part',
);
return '$_temp0';
}
@override
String get assistantContextDone => 'Done';
@override
String get assistantAttach => 'Attach a photo or file';
@override
String get assistantAttachFile => 'Attach a file';
@override
String get assistantAttachFiles => 'Images, PDFs and text files';
@override
String assistantAttachNotRead(String name) {
return '$name can\'t go along: only images, PDFs and text files can.';
}
@override
String assistantAttachTooLarge(String name) {
return '$name is larger than 5 MB, more than assistants take.';
}
@override
String assistantAttachNoImages(String name, String assistant) {
return '$name is an image, and $assistant reads none.';
}
@override
String get assistantAttachRemove => 'Remove';
@override
String get assistantSpeak => 'Speak your question';
@override
String get assistantStopListening => 'Stop listening';
@override
String get assistantSpeechUnavailable =>
'This device can\'t listen now. Check that the app may use the microphone and that speech recognition is on.';
@override
String get assistantScopeTicked => 'Only what I choose';
@ -6745,7 +6810,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get assistantScopeLibrary => 'Library';
@override
String get assistantScopeTickedLong => 'Only what I choose above';
String get assistantScopeTickedLong => 'Only what I send along';
@override
String get assistantScopeStudysetLong => 'This studyset with its topics';
@ -7021,9 +7086,6 @@ class AppLocalizationsEn extends AppLocalizations {
return 'I typed “$typed”. Why isn\'t that right?';
}
@override
String get assistantCheck => 'Check for mistakes';
@override
String get grammarNoSuggestions => 'No suggestions';
@ -7041,34 +7103,6 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get grammarPrivateCheckHere => 'Check here';
@override
String get grammarCheckTitle => 'Spelling and grammar';
@override
String get grammarCheckTooOften =>
'Checked too often for now. Try again in a minute.';
@override
String get grammarCheckTooLong => 'Too long to check at once.';
@override
String get grammarCheckUnknownLanguage =>
'The instance doesn\'t check this language.';
@override
String get grammarCheckFailed =>
'The instance\'s check couldn\'t be reached. Try again later.';
@override
String grammarCheckAskWhy(String name) {
return 'Ask $name why';
}
@override
String grammarCheckAskInstead(String name) {
return 'Ask $name to check';
}
@override
String proposalsTitle(String name) {
return 'Flashcards by $name';