# Auth-Screens: Layout-Skizzen und Texte (Spec #1, Task U1) Grundlage: `docs/specs/1-auth-registrierung-anmeldung.md` (§ 4.4 Meldungen, § 5.4 Screens, § 6 Plattform). Komponenten: `app/lib/core/widgets/` (siehe `docs/design-system.md`). Alle Texte unten sind **Vorschläge** und gehen über l10n (ARB); die ARB-Dateien pflegt der flutter-dev (A1/A2). Schlüssel sind `lowerCamelCase` mit Präfix `auth`. ## 1. Gemeinsames Layout - Alle sechs Screens nutzen `AppFormScaffold`. Kompakt (< 600 dp): Vollbild, scrollbar, Seitenrand 16 dp. Ab 600 dp: zentrierte Karte, max. 480 dp breit (`AppBreakpoints.authCardMaxWidth`), Innenabstand 24 dp. - Inhalt in einer Spalte, Abstand zwischen Feldern 16 dp, zwischen Gruppen 24 dp. - Reihenfolge = Lesereihenfolge = Tab-Reihenfolge: Titel, Banner (falls vorhanden), Felder, Checkboxen, Primärknopf, Sekundärlinks. - Titel: `headlineSmall`, darunter optional ein Einleitungssatz in `bodyMedium`. Titel als Semantics-Überschrift (`Semantics(header: true)`). - Banner (`AppBanner`) stehen **über** den Feldern, direkt unter dem Titel. Fehler am Feld stehen unter dem Feld. - Genau ein Primärknopf (`AppPrimaryButton`, volle Breite). Sekundäraktionen sind `TextButton`s (48 dp). - Eingaben bleiben bei jedem Fehler erhalten. Während `submitting` sind Knopf und Felder gesperrt, der Knopf zeigt den Spinner und den gesprochenen Text `authSubmitting`. - Nach einem Fehler setzt der Screen den Fokus auf das erste fehlerhafte Feld; bei Banner-Fehlern bleibt der Fokus am Knopf, das Banner wird als Live-Region angesagt. - Enter im letzten Feld sendet ab (`TextInputAction.done`), sonst `next`. Legende der Skizzen: `[ ]` Feld, `[x]` Checkbox, `( )` Primärknopf, `<…>` Link/TextButton, `!` Banner. ## 2. Skizzen ### RegisterScreen (`/register`) ``` Konto erstellen (Titel) ! Fehler-Banner (nur bei registrationRejected / network / rateLimited / unexpected) E-Mail [ name@example.com ] Fehler: authEmailInvalid Passwort [ •••••••••• (Auge) ] Hinweis: authPasswordRule / Fehler je Regel Anzeigename [ Alex 4/30 ] Fehler: authDisplayNameEmpty | TooLong | Invalid [x] Ich bin mindestens 16 Jahre alt Fehler: authAgeNotConfirmed [x] Ich habe die gelesen und stimme den zu Fehler: authTermsNotAccepted ( Konto erstellen ) ``` ### CheckEmailScreen (`/register/check-email`, Modus Bestätigung bzw. Reset) ``` Prüfe dein Postfach (Titel) Wir haben dir eine E-Mail geschickt, falls ... (Text, bodyLarge) Der Link ist 1 Stunde gültig. Die E-Mail kann einige Minuten dauern. Schau auch im Spam-Ordner nach. ! Info-Banner "E-Mail wurde erneut gesendet" (nach Resend, auch bei emailSendLimited) ! Fehler-Banner bei rateLimited / network (nur wenn E-Mail fehlt, z. B. nach Reload:) E-Mail [ ] ( E-Mail erneut senden ) -> nur Modus Bestätigung, gesperrt solange Anfrage läuft (Modus Reset: -> /forgot-password) ``` ### LoginScreen (`/login`) ``` Anmelden ! Fehler-Banner: authInvalidCredentials | rateLimited | network (über dem Formular, nie am Feld) ! Info-Banner emailNotConfirmed + Aktion "Bestätigungs-E-Mail erneut senden" E-Mail [ ] Passwort [ ••••• (Auge) ] ( Anmelden ) ``` ### ForgotPasswordScreen (`/forgot-password`) ``` Passwort zurücksetzen Gib die E-Mail-Adresse deines Kontos ein. Wir senden dir einen Link zum Zurücksetzen. E-Mail [ ] Fehler: authEmailInvalid ( Link senden ) ``` ### EmailLinkScreen (`/auth/confirm`) Zustände: `idle` (Knopf), `submitting`, `success` (nur Bestätigung), `error` (Link ungültig). ``` E-Mail-Adresse bestätigen | Neues Passwort festlegen (Titel je Typ) Ein Klick genügt, um fortzufahren. ( E-Mail-Adresse bestätigen ) | ( Weiter zum neuen Passwort ) Erfolg: ! Info-Banner "E-Mail bestätigt" (+ Mobile-Web: "Du kannst dich jetzt auch in der App anmelden.") Fehler: ! Fehler-Banner "Der Link ist abgelaufen ..." ( Neuen Link anfordern ) ``` ### ResetPasswordScreen (`/reset-password`) ``` Neues Passwort festlegen Neues Passwort [ ••••••••• (Auge) ] Live-Regeln: authPasswordRule, Fehler je Regel / samePassword ( Passwort speichern ) -> signOut Erfolg: Hinweis authPasswordChanged, dann Weiterleitung nach / ``` ## 3. Textvorschläge Ton: du-Form, kurz, sachlich-freundlich, keine Schuldzuweisung. Platzhalter in ICU-Syntax (`{n}`). Neutrale Texte (Krit. 4, F12) verraten nie, ob eine Adresse registriert ist. ### 3.1 Meldungen aus § 4.4 (Fehlerabbildung) | Schlüssel | de | en | |---|---|---| | `authErrorInvalidCredentials` | E-Mail-Adresse oder Passwort ist nicht korrekt. | Email address or password is incorrect. | | `authErrorEmailNotConfirmed` | Bestätige zuerst deine E-Mail-Adresse. Wir haben dir dazu eine E-Mail geschickt. | Please confirm your email address first. We sent you an email for this. | | `authActionResendConfirmation` | Bestätigungs-E-Mail erneut senden | Resend confirmation email | | `authErrorRateLimited` | Zu viele Versuche. Bitte warte einige Minuten und versuche es erneut. | Too many attempts. Please wait a few minutes and try again. | | `authErrorWeakPasswordLength` | Das Passwort ist zu kurz. | The password is too short. | | `authErrorWeakPasswordCharacters` | Das Passwort ist zu einfach. Wähle ein anderes. | The password is too simple. Choose a different one. | | `authErrorWeakPasswordPwned` | Dieses Passwort ist sehr verbreitet und leicht zu erraten. Wähle ein anderes. | This password is very common and easy to guess. Choose a different one. | | `authErrorSamePassword` | Wähle ein anderes als dein bisheriges Passwort. | Choose a password different from your current one. | | `authErrorLinkInvalidOrExpired` | Der Link ist abgelaufen oder wurde schon benutzt. | The link has expired or has already been used. | | `authActionRequestNewLink` | Neuen Link anfordern | Request a new link | | `authErrorEmailInvalid` | Gib eine gültige E-Mail-Adresse ein. | Enter a valid email address. | | `authErrorRegistrationRejected` | Registrierung nicht möglich. Bitte prüfe deine Angaben. | Registration is not possible. Please check your details. | | `authErrorNetwork` | Keine Verbindung. Für diesen Schritt brauchst du Internet. | No connection. You need internet access for this step. | | `authErrorUnexpected` | Etwas ist schiefgelaufen. Bitte versuche es erneut. | Something went wrong. Please try again. | | `authActionRetry` | Erneut versuchen | Try again | `emailSendLimited` hat bewusst **keinen** eigenen Text: Register/Forgot/CheckEmail zeigen den neutralen Erfolgstext (§ 3.3), nur der Resend im LoginScreen zeigt `authErrorRateLimited`. ### 3.2 Meldungen aus § 5.4 (Felder, Banner, Hinweise) | Schlüssel | de | en | |---|---|---| | `authPasswordTooShort` | Mindestens 10 Zeichen – {missing, plural, =1{es fehlt noch 1 Zeichen} other{es fehlen noch {missing} Zeichen}}. | At least 10 characters – {missing, plural, =1{1 more character needed} other{{missing} more characters needed}}. | | `authPasswordCommon` | Dieses Passwort ist sehr verbreitet und leicht zu erraten. Wähle ein anderes. | This password is very common and easy to guess. Choose a different one. | | `authPasswordRule` | Mindestens 10 Zeichen. Kein sehr verbreitetes Passwort. | At least 10 characters. Not a very common password. | | `authPasswordRequired` | Gib ein Passwort ein. | Enter a password. | | `authDisplayNameEmpty` | Gib einen Anzeigenamen ein. | Enter a display name. | | `authDisplayNameTooLong` | Der Anzeigename darf höchstens {max} Zeichen lang sein. | The display name can be at most {max} characters long. | | `authDisplayNameInvalid` | Dieser Anzeigename ist nicht erlaubt. Verwende sichtbare Zeichen. | This display name is not allowed. Use visible characters. | | `authAgeNotConfirmed` | Shuffle ist erst ab 16 Jahren nutzbar. | Shuffle can only be used from age 16. | | `authTermsNotAccepted` | Bitte stimme Datenschutzerklärung und Nutzungsbedingungen zu. | Please agree to the privacy policy and the terms of use. | | `authFieldEmailLabel` | E-Mail-Adresse | Email address | | `authFieldPasswordLabel` | Passwort | Password | | `authFieldNewPasswordLabel` | Neues Passwort | New password | | `authFieldDisplayNameLabel` | Anzeigename | Display name | | `authPasswordShow` | Passwort anzeigen | Show password | | `authPasswordHide` | Passwort verbergen | Hide password | | `authCheckboxAgeLabel` | Ich bin mindestens 16 Jahre alt | I am at least 16 years old | | `authCheckboxTermsPrefix` | Ich habe die | I have read the | | `authCheckboxTermsPrivacyLink` | Datenschutzerklärung | privacy policy | | `authCheckboxTermsMiddle` | gelesen und stimme den | and agree to the | | `authCheckboxTermsTermsLink` | Nutzungsbedingungen | terms of use | | `authCheckboxTermsSuffix` | zu | (leer) | | `authBannerTypeError` | Fehler | Error | | `authBannerTypeInfo` | Hinweis | Note | | `authSubmitting` | Bitte warten … | Please wait … | Hinweis zur Checkbox „Nutzungsbedingungen“: Satzbau ist je Sprache verschieden. Der Satz wird deshalb aus den Segmenten `Prefix`, `PrivacyLink`, `Middle`, `TermsLink`, `Suffix` zusammengesetzt (`AppCheckboxField.rich`); im Englischen bleibt `Suffix` leer. Alternativ ein ICU-Satz mit Platzhaltern, den der Screen an den Linkstellen teilt – Entscheidung beim flutter-dev (A2). ### 3.3 Screen-Texte | Schlüssel | de | en | |---|---|---| | `authRegisterTitle` | Konto erstellen | Create account | | `authRegisterSubmit` | Konto erstellen | Create account | | `authRegisterHaveAccount` | Schon ein Konto? Anmelden | Already have an account? Sign in | | `authCheckEmailTitle` | Prüfe dein Postfach | Check your inbox | | `authCheckEmailBody` | Wir haben dir eine E-Mail geschickt, falls die Adresse noch nicht registriert ist. Folge dem Link darin, um fortzufahren. | We sent you an email if the address is not registered yet. Follow the link in it to continue. | | `authCheckEmailBodyReset` | Wir haben dir eine E-Mail mit einem Link zum Zurücksetzen geschickt, falls zu dieser Adresse ein Konto besteht. | We sent you an email with a reset link if an account exists for this address. | | `authCheckEmailDelayHint` | Die E-Mail kann einige Minuten dauern. Schau auch im Spam-Ordner nach. | The email can take a few minutes. Also check your spam folder. | | `authCheckEmailValidity` | Der Link ist {duration} gültig. | The link is valid for {duration}. | | `authCheckEmailValidityOneHour` | 1 Stunde | 1 hour | | `authCheckEmailResend` | E-Mail erneut senden | Resend email | | `authCheckEmailResent` | Wir haben die E-Mail erneut gesendet, falls es zu dieser Adresse etwas zu senden gibt. | We resent the email, if there is something to send for this address. | | `authCheckEmailDifferentAddress` | Andere E-Mail-Adresse eingeben | Enter a different email address | | `authBackToLogin` | Zurück zur Anmeldung | Back to sign in | | `authLoginTitle` | Anmelden | Sign in | | `authLoginSubmit` | Anmelden | Sign in | | `authLoginForgotPassword` | Passwort vergessen? | Forgot password? | | `authLoginCreateAccount` | Konto erstellen | Create account | | `authForgotTitle` | Passwort zurücksetzen | Reset password | | `authForgotBody` | Gib die E-Mail-Adresse deines Kontos ein. Wir senden dir einen Link zum Zurücksetzen. | Enter the email address of your account. We will send you a reset link. | | `authForgotSubmit` | Link senden | Send link | | `authConfirmTitle` | E-Mail-Adresse bestätigen | Confirm email address | | `authConfirmBody` | Ein Klick genügt, um deine E-Mail-Adresse zu bestätigen. | One click is enough to confirm your email address. | | `authConfirmSubmit` | E-Mail-Adresse bestätigen | Confirm email address | | `authConfirmSuccess` | E-Mail bestätigt. | Email confirmed. | | `authConfirmSuccessMobileWeb` | Du kannst dich jetzt auch in der App anmelden. | You can now also sign in in the app. | | `authRecoveryTitle` | Neues Passwort festlegen | Set a new password | | `authRecoveryBody` | Ein Klick genügt, um ein neues Passwort festzulegen. | One click is enough to set a new password. | | `authRecoverySubmit` | Weiter zum neuen Passwort | Continue to new password | | `authResetTitle` | Neues Passwort festlegen | Set a new password | | `authResetSubmit` | Passwort speichern | Save password | | `authResetCancel` | Abbrechen | Cancel | | `authPasswordChanged` | Passwort geändert. Andere Geräte werden abgemeldet; das kann bis zu einer Stunde dauern. | Password changed. Other devices will be signed out; this can take up to an hour. | ## 4. Barrierefreiheit pro Screen (Checkliste für A2–A4 und T2) - Jedes Feld hat ein sichtbares Label (kein Platzhalter-Label); Fehler per `errorText` (Icon + Text + Live-Region). - Banner und Fehler werden beim Erscheinen vorgelesen (Live-Region); keine reinen Farb-Signale. - Passwortfelder: `AppPasswordField` mit `isNewPassword: true` bei Register/Reset, sonst `false`; E-Mail mit `AutofillHints.email` (Login: `AutofillHints.username`/`email`), `TextInputType.emailAddress`. - Links in Checkbox-Sätzen (`AppCheckboxField.rich`) sind eigene Semantics-Knoten (`link: true`, Label = Linktext, Tap), keine Custom Actions (Flutter-Web setzt diese nicht in ARIA um). Der Checkbox-Knoten trägt den ganzen Satz. - Meldungen, die sich bei jedem Tastendruck ändern („es fehlen noch n“), sind während des Tippens keine Live-Region (`liveError: false`) und werden beim Verlassen des Feldes angesagt; der sichtbare Text bleibt. - Alle interaktiven Elemente >= 48 dp, Tab-Reihenfolge wie Lesereihenfolge, Fokus sichtbar. - Test je Screen mit `textScaler` 2.0 (Android 320 x 640), `androidTapTargetGuideline`, `labeledTapTargetGuideline`, `textContrastGuideline`, Hell und Dunkel (T2).