// auth_screen.dart — 登录 / 注册页(文案经 AppText 单显) import 'package:flutter/material.dart'; import '../l10n/app_text.dart'; import '../pangolin_theme.dart'; import 'pangolin_button.dart'; import 'pangolin_icons.dart'; import 'pangolin_logo.dart'; enum _AuthMode { login, register } class AuthScreen extends StatefulWidget { const AuthScreen({super.key, required this.onDone, required this.t}); final VoidCallback onDone; final AppText t; @override State createState() => _AuthScreenState(); } class _AuthScreenState extends State { _AuthMode _mode = _AuthMode.login; int _step = 0; bool _sent = false; final _email = TextEditingController(); final _code = TextEditingController(); final _pw = TextEditingController(); bool get _emailValid => RegExp(r'\S+@\S+\.\S+').hasMatch(_email.text); @override void dispose() { _email.dispose(); _code.dispose(); _pw.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final c = context.pangolin; final t = widget.t; return Scaffold( backgroundColor: c.bg, body: SafeArea( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 28), child: Column( children: [ const SizedBox(height: 18), Column(children: [ const PangolinMark(size: 52), const SizedBox(height: 12), Text(t.brand, style: PangolinText.h1.copyWith(color: c.fg1)), const SizedBox(height: 4), Text(t.authTagline, style: PangolinText.sm.copyWith(color: c.accent, fontWeight: FontWeight.w600)), ]), const SizedBox(height: 28), Row(children: [ _tab(_AuthMode.login, t.tabLogin, c), _tab(_AuthMode.register, t.tabRegister, c), ]), Divider(height: 1, color: c.border), const SizedBox(height: 22), Expanded(child: _mode == _AuthMode.login ? _login(c, t) : _register(c, t)), Padding( padding: const EdgeInsets.symmetric(vertical: 20), child: Text(t.tos, textAlign: TextAlign.center, style: PangolinText.caption.copyWith(color: c.fg3, fontWeight: FontWeight.w400)), ), ], ), ), ), ); } Widget _tab(_AuthMode m, String label, PangolinScheme c) { final on = _mode == m; return Expanded( child: GestureDetector( onTap: () => setState(() { _mode = m; _step = 0; _sent = false; }), child: Container( padding: const EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration(border: Border(bottom: BorderSide(color: on ? c.accent : Colors.transparent, width: 2))), child: Center(child: Text(label, style: PangolinText.body.copyWith(color: on ? c.fg1 : c.fg3, fontWeight: on ? FontWeight.w700 : FontWeight.w500))), ), ), ); } Widget _field(PangolinScheme c, {required IconData icon, required String label, required Widget child}) { return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: PangolinText.caption.copyWith(color: c.fg2, fontWeight: FontWeight.w600)), const SizedBox(height: 7), Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 2), decoration: BoxDecoration(color: c.surface, borderRadius: BorderRadius.circular(PangolinRadius.md), border: Border.all(color: c.borderStrong, width: 1.5)), child: Row(children: [Icon(icon, size: 18, color: c.fg3), const SizedBox(width: 10), Expanded(child: child)]), ), ]); } InputDecoration get _bare => const InputDecoration(border: InputBorder.none, isCollapsed: true, contentPadding: EdgeInsets.symmetric(vertical: 12)); Widget _login(PangolinScheme c, AppText t) { return Column(children: [ _field(c, icon: PangolinIcons.mail, label: t.emailLabel, child: TextField(controller: _email, decoration: _bare.copyWith(hintText: t.emailPh), onChanged: (_) => setState(() {}))), const SizedBox(height: 16), _field(c, icon: PangolinIcons.lock, label: t.pwLabel, child: TextField(controller: _pw, obscureText: true, decoration: _bare.copyWith(hintText: t.pwPh), onChanged: (_) => setState(() {}))), Align( alignment: Alignment.centerRight, child: Padding( padding: const EdgeInsets.only(top: 8), child: Text(t.forgotPw, style: PangolinText.sm.copyWith(color: c.accent, fontWeight: FontWeight.w600)), ), ), const SizedBox(height: 18), PangolinButton(label: t.doLogin, expand: true, onPressed: (_emailValid && _pw.text.isNotEmpty) ? widget.onDone : null), ]); } Widget _register(PangolinScheme c, AppText t) { if (_step == 0) { return Column(children: [ _field(c, icon: PangolinIcons.mail, label: t.emailLabel, child: Row(children: [ Expanded(child: TextField(controller: _email, decoration: _bare.copyWith(hintText: t.emailPh), onChanged: (_) => setState(() {}))), GestureDetector( onTap: _emailValid ? () => setState(() => _sent = true) : null, child: Text(_sent ? t.resend : t.sendCode, style: PangolinText.caption.copyWith(color: _emailValid ? c.accent : c.fg3, fontWeight: FontWeight.w700)), ), ])), if (_sent) Padding( padding: const EdgeInsets.only(top: 8), child: Row(children: [ Icon(PangolinIcons.checkCircle, size: 14, color: c.success), const SizedBox(width: 6), Expanded(child: Text(t.codeSentTo(_email.text), style: PangolinText.caption.copyWith(color: c.success, fontWeight: FontWeight.w400))), ]), ), const SizedBox(height: 16), _field(c, icon: PangolinIcons.shieldCheck, label: t.codeLabel, child: TextField(controller: _code, keyboardType: TextInputType.number, maxLength: 6, style: PangolinText.mono.copyWith(letterSpacing: 6, color: c.fg1), decoration: _bare.copyWith(counterText: '', hintText: '······'), onChanged: (_) => setState(() {}))), const SizedBox(height: 8), PangolinButton(label: t.doNext, expand: true, onPressed: (_sent && _code.text.length == 6) ? () => setState(() => _step = 1) : null), ]); } return Column(children: [ Row(children: [Icon(PangolinIcons.checkCircle, size: 15, color: c.success), const SizedBox(width: 7), Text(_email.text, style: PangolinText.sm.copyWith(color: c.fg2))]), const SizedBox(height: 16), _field(c, icon: PangolinIcons.lock, label: t.pwLabel, child: TextField(controller: _pw, obscureText: true, decoration: _bare.copyWith(hintText: t.setPwPh), onChanged: (_) => setState(() {}))), const SizedBox(height: 18), PangolinButton(label: t.doCreate, expand: true, onPressed: _pw.text.length >= 6 ? widget.onDone : null), ]); } }