fix(app): keyboards learn nothing of a password, a code or the phrase

The fields for a password, a code and the recovery phrase's words already
turned suggestions and corrections off; keyboards (Gboard, SwiftKey) still
learnt what was typed into them unless told not to. They now are
(enableIMEPersonalizedLearning: false), and the two sheets taking the
whole phrase share one PhraseField.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-21 14:48:43 +02:00
commit c9904de31d
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
3 changed files with 106 additions and 31 deletions

View file

@ -90,24 +90,8 @@ class _AccountRecoveryState() extends State<_AccountRecovery> {
}
}
Widget _phraseField(bool enabled, {String? errorText}) {
final l10n = HalkyonAppLocalizations.of(context);
return TextField(
controller: _phrase,
enabled: enabled,
autocorrect: false,
enableSuggestions: false,
minLines: 2,
maxLines: 5,
maxLength: TextLimits.passage,
buildCounter: nearLimitCounter,
decoration: InputDecoration(
labelText: l10n.passwordPhraseField,
hintText: l10n.passwordPhraseFieldHint,
errorText: errorText,
),
);
}
Widget _phraseField(bool enabled, {String? errorText}) =>
PhraseField(controller: _phrase, enabled: enabled, errorText: errorText);
@override
Widget build(BuildContext context) {

View file

@ -266,21 +266,12 @@ class _PasswordSignInState() extends State<_PasswordSignIn> {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SheetIntro(l10n.passwordPhraseFieldIntro),
TextField(
PhraseField(
controller: _phrase,
enabled: enabled,
autofocus: true,
autocorrect: false,
enableSuggestions: false,
minLines: 3,
maxLines: 5,
maxLength: TextLimits.passage,
buildCounter: nearLimitCounter,
decoration: InputDecoration(
labelText: l10n.passwordPhraseField,
hintText: l10n.passwordPhraseFieldHint,
errorText: problem,
),
errorText: problem,
),
],
),

View file

@ -52,6 +52,8 @@ class _PasswordFieldState() extends State<PasswordField> {
obscureText: !_shown,
autocorrect: false,
enableSuggestions: false,
// Nothing typed here is the keyboard's to learn.
enableIMEPersonalizedLearning: false,
keyboardType: TextInputType.visiblePassword,
autofillHints: [
if (widget.isNew)
@ -155,6 +157,8 @@ class const CodeField({
autofillHints: const [AutofillHints.oneTimeCode],
autocorrect: false,
enableSuggestions: false,
// Nothing typed here is the keyboard's to learn.
enableIMEPersonalizedLearning: false,
keyboardType: digits ? TextInputType.number : TextInputType.text,
textCapitalization: TextCapitalization.characters,
textInputAction: textInputAction,
@ -357,6 +361,41 @@ class const RecoveryPhraseView({required final String phrase, super.key})
}
}
/// The field a recovery phrase is typed into: its words, whatever spaces or
/// lines are between them, nothing the keyboard suggests, corrects or
/// learns.
class const PhraseField({
required final TextEditingController controller,
final bool enabled = true,
final bool autofocus = false,
final String? errorText,
final int minLines = 2,
super.key,
}) extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = HalkyonAppLocalizations.of(context);
return TextField(
controller: controller,
enabled: enabled,
autofocus: autofocus,
autocorrect: false,
enableSuggestions: false,
// Nothing typed here is the keyboard's to learn.
enableIMEPersonalizedLearning: false,
minLines: minLines,
maxLines: 5,
maxLength: TextLimits.passage,
buildCounter: nearLimitCounter,
decoration: InputDecoration(
labelText: l10n.passwordPhraseField,
hintText: l10n.passwordPhraseFieldHint,
errorText: errorText,
),
);
}
}
/// Fields for the words of a recovery phrase at [positions] (from 0).
class const PhraseCheckFields({
required final List<int> positions,
@ -379,6 +418,8 @@ class const PhraseCheckFields({
autofocus: i == 0,
autocorrect: false,
enableSuggestions: false,
// Nothing typed here is the keyboard's to learn.
enableIMEPersonalizedLearning: false,
textInputAction: i == positions.length - 1
? TextInputAction.done
: TextInputAction.next,