feat(ui): 新增登录入口与我的页预览
This commit is contained in:
1 parent
21d457fd98
commit
fecc5b0d27
10 files changed
+1021
-649
No files matched your search
@@ -60,6 +60,7 @@ class _AuthPageState extends State<AuthPage> {
|
||||
late final FocusNode _emailFocus;
|
||||
late final FocusNode _passwordFocus;
|
||||
bool _obscurePassword = true;
|
||||
bool _emailEntryOpen = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -243,7 +244,13 @@ class _AuthPageState extends State<AuthPage> {
|
||||
tooltip: MaterialLocalizations.of(
|
||||
context,
|
||||
).backButtonTooltip,
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
onPressed: () {
|
||||
if (_emailEntryOpen) {
|
||||
setState(() => _emailEntryOpen = false);
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.arrow_back_rounded,
|
||||
color: AppColors.onPrimary,
|
||||
@@ -272,16 +279,107 @@ class _AuthPageState extends State<AuthPage> {
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
_AuthBrand(tagline: l10n.authBrandTagline, compact: compact),
|
||||
SizedBox(height: compact ? _compactBrandGap : 28),
|
||||
_authCard(l10n),
|
||||
],
|
||||
),
|
||||
child: _emailEntryOpen
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
_AuthBrand(tagline: l10n.authBrandTagline, compact: compact),
|
||||
SizedBox(height: compact ? _compactBrandGap : 28),
|
||||
_authCard(l10n),
|
||||
],
|
||||
)
|
||||
: _landing(l10n),
|
||||
);
|
||||
|
||||
Widget _landing(AppLocalizations l10n) => Column(
|
||||
key: const Key('auth-landing'),
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Center(
|
||||
child: Container(
|
||||
key: const Key('auth-brand-logo'),
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [AppColors.blue, AppColors.secondary],
|
||||
),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.play_arrow_rounded,
|
||||
color: AppColors.onPrimary,
|
||||
size: 32,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
Text(
|
||||
l10n.fruitShortsBrand,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Outfit',
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
l10n.authLandingSubtitle,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(color: Color(0xFF9A96A3), fontSize: 11),
|
||||
),
|
||||
const SizedBox(height: 22),
|
||||
_AuthEntryButton(
|
||||
key: const Key('auth-entry-google'),
|
||||
label: 'G ${l10n.authContinueGoogle}',
|
||||
background: Colors.white,
|
||||
foreground: const Color(0xFF1A1A1A),
|
||||
leadingColor: const Color(0xFF4285F4),
|
||||
onTap: () => _comingSoon(l10n),
|
||||
),
|
||||
const SizedBox(height: 11),
|
||||
_AuthEntryButton(
|
||||
key: const Key('auth-entry-phone'),
|
||||
label: l10n.authPhoneSignIn,
|
||||
icon: Icons.phone_android_rounded,
|
||||
background: AppColors.input,
|
||||
foreground: AppColors.onSurface,
|
||||
onTap: () => _comingSoon(l10n),
|
||||
),
|
||||
const SizedBox(height: 11),
|
||||
_AuthEntryButton(
|
||||
key: const Key('auth-entry-email'),
|
||||
label: l10n.authEmailSignIn,
|
||||
icon: Icons.mail_outline_rounded,
|
||||
background: AppColors.input,
|
||||
foreground: AppColors.onSurface,
|
||||
onTap: () => setState(() => _emailEntryOpen = true),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
Text(
|
||||
l10n.authLegal,
|
||||
key: const Key('auth-legal'),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF6B6772),
|
||||
fontSize: 9,
|
||||
height: 1.6,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
void _comingSoon(AppLocalizations l10n) {
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text(l10n.comingSoon)));
|
||||
}
|
||||
|
||||
Widget _authCard(AppLocalizations l10n) => _AuthCard(
|
||||
state: _AuthCardState(
|
||||
l10n: l10n,
|
||||
@@ -320,3 +418,57 @@ class _AuthPageState extends State<AuthPage> {
|
||||
setState(() => _logic.toggleMode());
|
||||
}
|
||||
}
|
||||
|
||||
class _AuthEntryButton extends StatelessWidget {
|
||||
const _AuthEntryButton({
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.background,
|
||||
required this.foreground,
|
||||
required this.onTap,
|
||||
this.icon,
|
||||
this.leadingColor,
|
||||
});
|
||||
|
||||
final String label;
|
||||
final Color background;
|
||||
final Color foreground;
|
||||
final VoidCallback onTap;
|
||||
final IconData? icon;
|
||||
final Color? leadingColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
color: background,
|
||||
borderRadius: BorderRadius.circular(9),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
child: SizedBox(
|
||||
height: 44,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (icon != null)
|
||||
Icon(icon, size: 16, color: leadingColor ?? foreground),
|
||||
if (icon != null) const SizedBox(width: 7),
|
||||
Flexible(
|
||||
child: Text(
|
||||
label,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
color: foreground,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user