151 lines
3.9 KiB
Dart
151 lines
3.9 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
part of 'auth_view.dart';
|
|
|
|
class _AuthCardState {
|
|
const _AuthCardState({
|
|
required this.l10n,
|
|
required this.status,
|
|
required this.fields,
|
|
});
|
|
|
|
final AppLocalizations l10n;
|
|
final _AuthFormStatus status;
|
|
final _AuthFieldControllers fields;
|
|
}
|
|
|
|
class _AuthFormStatus {
|
|
const _AuthFormStatus({
|
|
required this.signUpMode,
|
|
required this.busy,
|
|
required this.errorMessage,
|
|
required this.fieldError,
|
|
required this.obscurePassword,
|
|
});
|
|
|
|
final bool signUpMode;
|
|
final bool busy;
|
|
final String? errorMessage;
|
|
final AuthFieldError? fieldError;
|
|
final bool obscurePassword;
|
|
}
|
|
|
|
class _AuthFieldControllers {
|
|
const _AuthFieldControllers({
|
|
required this.email,
|
|
required this.password,
|
|
required this.emailFocus,
|
|
required this.passwordFocus,
|
|
});
|
|
|
|
final TextEditingController email;
|
|
final TextEditingController password;
|
|
final FocusNode emailFocus;
|
|
final FocusNode passwordFocus;
|
|
}
|
|
|
|
class _AuthCardCallbacks {
|
|
const _AuthCardCallbacks({
|
|
required this.onModeSelected,
|
|
required this.onEmailChanged,
|
|
required this.onPasswordChanged,
|
|
required this.onTogglePasswordVisibility,
|
|
required this.onSubmit,
|
|
});
|
|
|
|
final ValueChanged<bool> onModeSelected;
|
|
final ValueChanged<String> onEmailChanged;
|
|
final ValueChanged<String> onPasswordChanged;
|
|
final VoidCallback onTogglePasswordVisibility;
|
|
final VoidCallback onSubmit;
|
|
}
|
|
|
|
class _AuthCard extends StatelessWidget {
|
|
const _AuthCard({required this.state, required this.callbacks});
|
|
|
|
final _AuthCardState state;
|
|
final _AuthCardCallbacks callbacks;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l10n = state.l10n;
|
|
final status = state.status;
|
|
// 不再做卡片盒子,表单直接排在红光晕背景上。
|
|
return Column(
|
|
key: const Key('auth-card'),
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
_AuthModeSwitch(
|
|
l10n: l10n,
|
|
signUpMode: status.signUpMode,
|
|
busy: status.busy,
|
|
onSelected: callbacks.onModeSelected,
|
|
),
|
|
const SizedBox(height: 24),
|
|
Text(
|
|
status.signUpMode ? l10n.authSignUpTitle : l10n.authSignInTitle,
|
|
style: const TextStyle(
|
|
color: AppColors.onSurface,
|
|
fontSize: 24,
|
|
fontWeight: FontWeight.w600,
|
|
height: 1.2,
|
|
),
|
|
),
|
|
const SizedBox(height: 6),
|
|
Text(
|
|
status.signUpMode ? l10n.authSignUpSubtitle : l10n.authSubtitle,
|
|
style: const TextStyle(
|
|
color: AppColors.muted,
|
|
fontSize: AppDimens.body,
|
|
height: 1.45,
|
|
),
|
|
),
|
|
const SizedBox(height: 20),
|
|
_AuthFields(state: state, callbacks: callbacks),
|
|
if (status.errorMessage != null) ...[
|
|
const SizedBox(height: 14),
|
|
_AuthError(message: status.errorMessage!),
|
|
],
|
|
const SizedBox(height: 22),
|
|
_AuthSubmitButton(state: state, onSubmit: callbacks.onSubmit),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _AuthModeSwitch extends StatelessWidget {
|
|
const _AuthModeSwitch({
|
|
required this.l10n,
|
|
required this.signUpMode,
|
|
required this.busy,
|
|
required this.onSelected,
|
|
});
|
|
|
|
final AppLocalizations l10n;
|
|
final bool signUpMode;
|
|
final bool busy;
|
|
final ValueChanged<bool> onSelected;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Row(
|
|
key: const Key('auth-switch-mode'),
|
|
children: [
|
|
_ModeTab(
|
|
segmentKey: const Key('auth-mode-sign-in'),
|
|
label: l10n.signIn,
|
|
selected: !signUpMode,
|
|
onTap: busy ? null : () => onSelected(false),
|
|
),
|
|
const SizedBox(width: AppDimens.followingSegmentGap),
|
|
_ModeTab(
|
|
segmentKey: const Key('auth-mode-sign-up'),
|
|
label: l10n.signUp,
|
|
selected: signUpMode,
|
|
onTap: busy ? null : () => onSelected(true),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|