import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import '../config/app_version.dart'; import 'auth_view_model.dart'; /// 登录/注册页:手机号 + 密码;注册成功后自动登录。 class AuthScreen extends StatefulWidget { const AuthScreen({super.key}); @override State createState() => _AuthScreenState(); } class _AuthScreenState extends State { final _phoneCtrl = TextEditingController(); final _passwordCtrl = TextEditingController(); bool _obscure = true; @override void dispose() { _phoneCtrl.dispose(); _passwordCtrl.dispose(); super.dispose(); } static final _phoneRe = RegExp(r'^1[3-9]\d{9}$'); Future _submit() async { final vm = context.read(); final phone = _phoneCtrl.text.trim(); final password = _passwordCtrl.text; if (!_phoneRe.hasMatch(phone)) { vm.showError('请输入正确的 11 位手机号'); return; } if (password.length < 6) { vm.showError('密码至少 6 位'); return; } final ok = await vm.submit(phone: phone, password: password); if (ok && mounted) { Navigator.of(context).pushReplacementNamed('/home'); } } @override Widget build(BuildContext context) { final vm = context.watch(); final isLogin = vm.mode == AuthMode.login; return Scaffold( body: SafeArea( child: Column( children: [ Expanded( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 32), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Icon(Icons.pets, size: 64, color: Colors.green), const SizedBox(height: 12), const Text( '视野', textAlign: TextAlign.center, style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold), ), const SizedBox(height: 4), Text( '动物实时识别', textAlign: TextAlign.center, style: TextStyle(color: Colors.grey.shade600), ), const SizedBox(height: 32), TextField( controller: _phoneCtrl, keyboardType: TextInputType.phone, maxLength: 11, inputFormatters: [FilteringTextInputFormatter.digitsOnly], decoration: const InputDecoration( labelText: '手机号', prefixIcon: Icon(Icons.phone_android), border: OutlineInputBorder(), counterText: '', ), ), const SizedBox(height: 16), TextField( controller: _passwordCtrl, obscureText: _obscure, maxLength: 64, decoration: InputDecoration( labelText: '密码', prefixIcon: const Icon(Icons.lock_outline), border: const OutlineInputBorder(), counterText: '', suffixIcon: IconButton( icon: Icon(_obscure ? Icons.visibility_off : Icons.visibility), onPressed: () => setState(() => _obscure = !_obscure), ), ), ), const SizedBox(height: 24), FilledButton( onPressed: vm.loading ? null : _submit, style: FilledButton.styleFrom( minimumSize: const Size.fromHeight(48), ), child: vm.loading ? const SizedBox( width: 22, height: 22, child: CircularProgressIndicator(strokeWidth: 2), ) : Text(isLogin ? '登录' : '注册并登录'), ), const SizedBox(height: 12), TextButton( onPressed: vm.loading ? null : vm.switchMode, child: Text(isLogin ? '没有账号?去注册' : '已有账号?去登录'), ), if (vm.error != null) ...[ const SizedBox(height: 12), Text( vm.error!, textAlign: TextAlign.center, style: const TextStyle(color: Colors.red), ), ], ], ), ), ), ), Padding( padding: const EdgeInsets.only(bottom: 12), child: FutureBuilder( future: appVersion(), builder: (context, snapshot) => Text( 'v${snapshot.data ?? ''}', style: TextStyle( fontSize: 12, color: Colors.grey.shade500, ), ), ), ), ], ), ), ); } }