From 8dd48ec15b1e5a6f92ed6d0e9cac93d674937107 Mon Sep 17 00:00:00 2001 From: qzl Date: Tue, 10 Mar 2026 17:42:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E4=BD=BF=E7=94=A8=20AuthPageScaffold=20?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/ui/screens/login_screen.dart | 44 +++++-------- .../auth/ui/screens/register_screen.dart | 45 +++++-------- .../screens/register_verification_screen.dart | 43 ++++-------- .../ui/screens/reset_password_screen.dart | 34 +++------- .../auth/ui/widgets/auth_page_scaffold.dart | 66 +++++++++++++++++++ 5 files changed, 120 insertions(+), 112 deletions(-) create mode 100644 apps/lib/features/auth/ui/widgets/auth_page_scaffold.dart diff --git a/apps/lib/features/auth/ui/screens/login_screen.dart b/apps/lib/features/auth/ui/screens/login_screen.dart index dc5dc67..ff36aff 100644 --- a/apps/lib/features/auth/ui/screens/login_screen.dart +++ b/apps/lib/features/auth/ui/screens/login_screen.dart @@ -7,6 +7,7 @@ import '../../../../core/di/injection.dart'; import '../../../../shared/widgets/app_button.dart'; import '../../../../shared/widgets/banner/app_banner.dart'; import '../../../../shared/widgets/toast/toast_type.dart'; +import '../widgets/auth_page_scaffold.dart'; import '../../presentation/cubits/login_cubit.dart'; import '../../presentation/bloc/auth_bloc.dart'; import '../../presentation/bloc/auth_event.dart'; @@ -59,36 +60,21 @@ class _LoginViewState extends State { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.background, - body: SafeArea( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - key: const Key('login_main_content'), - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - _buildAppIcon(), - const SizedBox(height: 24), - _buildAppTitle(), - const SizedBox(height: 32), - _buildFormContainer(), - ], - ), - ), - ), - Container(key: const Key('login_footer'), child: _buildFooter()), - const SizedBox(height: 24), - ], - ), - ), + return AuthPageScaffold( + mainContentKey: const Key('login_main_content'), + footerKey: const Key('login_footer'), + mainContent: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildAppIcon(), + const SizedBox(height: 24), + _buildAppTitle(), + const SizedBox(height: 32), + _buildFormContainer(), + ], ), + footer: _buildFooter(), ); } diff --git a/apps/lib/features/auth/ui/screens/register_screen.dart b/apps/lib/features/auth/ui/screens/register_screen.dart index cf8cf08..b54615e 100644 --- a/apps/lib/features/auth/ui/screens/register_screen.dart +++ b/apps/lib/features/auth/ui/screens/register_screen.dart @@ -12,6 +12,7 @@ import '../../../../shared/widgets/toast/toast.dart'; import '../../../../shared/widgets/toast/toast_type.dart'; import '../../presentation/cubits/register_cubit.dart'; import '../../data/auth_repository.dart'; +import '../widgets/auth_page_scaffold.dart'; class RegisterScreen extends StatelessWidget { const RegisterScreen({super.key}); @@ -79,35 +80,19 @@ class _RegisterViewState extends State { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.background, - body: SafeArea( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - _buildAppIcon(), - const SizedBox(height: 24), - _buildAppTitle(), - const SizedBox(height: 24), - _buildFormContainer(), - ], - ), - ), - ), - _buildFooter(), - const SizedBox(height: 24), - ], - ), - ), + return AuthPageScaffold( + mainContent: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildAppIcon(), + const SizedBox(height: 24), + _buildAppTitle(), + const SizedBox(height: 24), + _buildFormContainer(), + ], ), + footer: _buildFooter(), ); } @@ -202,7 +187,7 @@ class _RegisterViewState extends State { style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w500, - color: Color(0xFF475569), + color: AppColors.slate600, ), ), const SizedBox(height: 6), @@ -223,7 +208,7 @@ class _RegisterViewState extends State { style: TextStyle( fontSize: 13, fontWeight: FontWeight.w500, - color: Color(0xFF475569), + color: AppColors.slate600, ), ), const SizedBox(height: 6), diff --git a/apps/lib/features/auth/ui/screens/register_verification_screen.dart b/apps/lib/features/auth/ui/screens/register_verification_screen.dart index 667f57c..1331e28 100644 --- a/apps/lib/features/auth/ui/screens/register_verification_screen.dart +++ b/apps/lib/features/auth/ui/screens/register_verification_screen.dart @@ -11,6 +11,7 @@ import '../../../../shared/widgets/toast/toast_type.dart'; import '../../presentation/cubits/register_cubit.dart'; import '../../presentation/bloc/auth_bloc.dart'; import '../../presentation/bloc/auth_event.dart'; +import '../widgets/auth_page_scaffold.dart'; class RegisterVerificationScreen extends StatelessWidget { final RegisterCubit? cubit; @@ -125,35 +126,19 @@ class _RegisterVerificationViewState extends State { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.background, - body: SafeArea( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - _buildAppIcon(), - const SizedBox(height: 24), - _buildAppTitle(), - const SizedBox(height: 24), - _buildFormContainer(), - ], - ), - ), - ), - _buildFooter(), - const SizedBox(height: 24), - ], - ), - ), + return AuthPageScaffold( + mainContent: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildAppIcon(), + const SizedBox(height: 24), + _buildAppTitle(), + const SizedBox(height: 24), + _buildFormContainer(), + ], ), + footer: _buildFooter(), ); } @@ -250,7 +235,7 @@ class _RegisterVerificationViewState extends State { style: TextStyle( fontSize: 13, fontWeight: FontWeight.w500, - color: Color(0xFF475569), + color: AppColors.slate600, ), ), const SizedBox(height: 6), diff --git a/apps/lib/features/auth/ui/screens/reset_password_screen.dart b/apps/lib/features/auth/ui/screens/reset_password_screen.dart index 5c3a1df..d78d1ca 100644 --- a/apps/lib/features/auth/ui/screens/reset_password_screen.dart +++ b/apps/lib/features/auth/ui/screens/reset_password_screen.dart @@ -9,6 +9,7 @@ import '../../../../shared/widgets/toast/toast.dart'; import '../../../../shared/widgets/toast/toast_type.dart'; import '../../presentation/cubits/reset_password_cubit.dart'; import '../../data/auth_repository.dart'; +import '../widgets/auth_page_scaffold.dart'; class ResetPasswordScreen extends StatelessWidget { const ResetPasswordScreen({super.key}); @@ -78,30 +79,15 @@ class _ResetPasswordViewState extends State { Toast.show(context, state.errorMessage!, type: ToastType.error); } }, - child: Scaffold( - backgroundColor: AppColors.background, - body: SafeArea( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - _buildTitle(), - const SizedBox(height: 32), - _buildFormContainer(), - ], - ), - ), - ), - ], - ), - ), + child: AuthPageScaffold( + mainContent: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildTitle(), + const SizedBox(height: 32), + _buildFormContainer(), + ], ), ), ); diff --git a/apps/lib/features/auth/ui/widgets/auth_page_scaffold.dart b/apps/lib/features/auth/ui/widgets/auth_page_scaffold.dart new file mode 100644 index 0000000..77942a5 --- /dev/null +++ b/apps/lib/features/auth/ui/widgets/auth_page_scaffold.dart @@ -0,0 +1,66 @@ +import 'dart:math' as math; + +import 'package:flutter/material.dart'; + +import '../../../../core/theme/design_tokens.dart'; + +class AuthPageScaffold extends StatelessWidget { + const AuthPageScaffold({ + super.key, + required this.mainContent, + this.footer, + this.mainContentKey, + this.footerKey, + }); + + final Widget mainContent; + final Widget? footer; + final Key? mainContentKey; + final Key? footerKey; + + @override + Widget build(BuildContext context) { + final keyboardInset = MediaQuery.viewInsetsOf(context).bottom; + + return Scaffold( + backgroundColor: AppColors.background, + body: SafeArea( + child: LayoutBuilder( + builder: (context, constraints) { + final viewportHeight = math.max( + constraints.maxHeight - keyboardInset, + AppSpacing.none, + ); + + return SingleChildScrollView( + keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, + padding: EdgeInsets.fromLTRB( + AppSpacing.xxl, + AppSpacing.none, + AppSpacing.xxl, + keyboardInset + AppSpacing.xxl, + ), + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: viewportHeight), + child: IntrinsicHeight( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + key: mainContentKey, + child: Center(child: mainContent), + ), + if (footer != null) + Container(key: footerKey, child: footer), + SizedBox(height: AppSpacing.xxl), + ], + ), + ), + ), + ); + }, + ), + ), + ); + } +}