Shuffle/app/lib/features/auth/presentation/widgets/sign_in_prompt.dart
cschlaefke f078c8a094 feat(auth): sign-in prompt card on the home screen for signed-out users
Adds SignInPrompt (sign in / create account), showSignInPromptProvider,
HomeScreen as ConsumerWidget, l10n de/en, widget/unit tests and a
Playwright web test (#49 criterion 1, QUE-09 criterion 13, QUE-06).

Refs #49

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 01:03:16 +01:00

75 lines
2.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:shuffle/core/l10n/l10n.dart';
import 'package:shuffle/core/routing/app_routes.dart';
import 'package:shuffle/core/theme/app_spacing.dart';
import 'package:shuffle/core/widgets/app_primary_button.dart';
/// Hint card for signed-out users with the way to sign in and to register
/// (Spec #49 E1, QUE-09 Kriterium 13). Contains no logic: the host decides
/// whether to show it (see `showSignInPromptProvider`).
///
/// At most [AppBreakpoints.authCardMaxWidth] wide. Heading, text and both
/// buttons are separate semantics nodes in reading and tab order.
class SignInPrompt extends StatelessWidget {
const SignInPrompt({super.key});
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
final textTheme = Theme.of(context).textTheme;
return ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: AppBreakpoints.authCardMaxWidth,
),
child: Card(
key: const Key('sign_in_prompt'),
// Card is a semantics container; keep the children separate.
child: Semantics(
explicitChildNodes: true,
child: Padding(
padding: const EdgeInsets.all(AppSpacing.xl),
child: FocusTraversalGroup(
policy: ReadingOrderTraversalPolicy(),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Semantics(
header: true,
child: Text(
l10n.signInPromptTitle,
key: const Key('sign_in_prompt_title'),
style: textTheme.titleLarge,
),
),
const SizedBox(height: AppSpacing.sm),
Text(
l10n.signInPromptBody,
key: const Key('sign_in_prompt_body'),
style: textTheme.bodyMedium,
),
const SizedBox(height: AppSpacing.xl),
AppPrimaryButton(
key: const Key('sign_in_prompt_sign_in'),
label: l10n.signInPromptSignIn,
onPressed: () => context.go(AppRoutes.login),
),
const SizedBox(height: AppSpacing.md),
OutlinedButton(
key: const Key('sign_in_prompt_register'),
onPressed: () => context.go(AppRoutes.register),
child: Text(
l10n.signInPromptRegister,
textAlign: TextAlign.center,
),
),
],
),
),
),
),
),
);
}
}