import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../providers/user_provider.dart'; class LoginPage extends StatefulWidget { const LoginPage({super.key}); @override State createState() => _LoginPageState(); } class _LoginPageState extends State { bool isRegisterMode = false; bool isLoading = false; final usernameController = TextEditingController(); final passwordController = TextEditingController(); final inviterController = TextEditingController(); String errorMessage = ''; // 定义主题粉色 static const _pinkColor = Color(0xFFFFC0D6); Future submit() async { // 基本验证 if (usernameController.text.trim().isEmpty || passwordController.text.trim().isEmpty) { setState(() => errorMessage = '用户名和密码不能为空'); return; } setState(() { isLoading = true; errorMessage = ''; }); final userProvider = Provider.of(context, listen: false); try { if (isRegisterMode) { await userProvider.register( usernameController.text.trim(), passwordController.text.trim(), inviterController.text.trim(), ); } else { await userProvider.login( usernameController.text.trim(), passwordController.text.trim(), ); } if (mounted) { Navigator.of(context).pop(); } } catch (e) { if (mounted) { setState(() => errorMessage = e.toString().replaceAll('Exception: ', '')); } } finally { if (mounted) { setState(() => isLoading = false); } } } @override void dispose() { usernameController.dispose(); passwordController.dispose(); inviterController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final isDark = theme.brightness == Brightness.dark; return Scaffold( backgroundColor: isDark ? Colors.black : Colors.white, appBar: AppBar( title: Text(isRegisterMode ? '创建账号' : '欢迎回来'), centerTitle: true, elevation: 0, backgroundColor: Colors.transparent, ), body: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: isDark ? [Colors.black, Colors.grey[900]!] : [Colors.white, Colors.grey[50]!], ), ), alignment: Alignment.center, padding: const EdgeInsets.all(24), child: Transform.translate( offset: const Offset(0, -30), child: SingleChildScrollView( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 400), child: Card( elevation: 8, shadowColor: _pinkColor.withOpacity(0.3), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), color: isDark ? Colors.grey[850] : Colors.white, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32), child: Column( mainAxisSize: MainAxisSize.min, children: [ // 头像/图标区域 - 已修改为黑白粉主题 Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: _pinkColor.withOpacity(0.15), shape: BoxShape.circle, ), child: Icon( // 更换为更美观的人物头像类图标 isRegisterMode ? Icons.person_add_rounded : Icons.person_rounded, size: 48, color: _pinkColor, ), ), const SizedBox(height: 24), Text( isRegisterMode ? '注册新账号' : '账号登录', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: isDark ? Colors.white : Colors.black87, ), ), const SizedBox(height: 8), Text( isRegisterMode ? '请填写以下信息' : '请输入您的凭证以继续', style: TextStyle( fontSize: 14, color: isDark ? Colors.grey[400] : Colors.grey[600], ), textAlign: TextAlign.center, ), const SizedBox(height: 24), if (errorMessage.isNotEmpty) Container( width: double.infinity, padding: const EdgeInsets.all(12), margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.red.withOpacity(0.1), borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.red.withOpacity(0.3)), ), child: Row( children: [ const Icon(Icons.error_outline, color: Colors.red, size: 20), const SizedBox(width: 8), Expanded( child: Text( errorMessage, style: const TextStyle(color: Colors.red, fontSize: 13), ), ), ], ), ), // 用户名输入框 TextField( controller: usernameController, enabled: !isLoading, decoration: InputDecoration( labelText: '用户名', prefixIcon: const Icon(Icons.person_outline, color: _pinkColor), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: _pinkColor), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: _pinkColor.withOpacity(0.5)), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: _pinkColor, width: 2), ), filled: true, fillColor: isDark ? Colors.grey[800] : Colors.grey[50], ), ), const SizedBox(height: 16), // 密码输入框 TextField( controller: passwordController, obscureText: true, enabled: !isLoading, decoration: InputDecoration( labelText: isRegisterMode ? '设置密码' : '密码 / TOTP验证码', prefixIcon: const Icon(Icons.lock_outline, color: _pinkColor), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: _pinkColor), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: _pinkColor.withOpacity(0.5)), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: _pinkColor, width: 2), ), filled: true, fillColor: isDark ? Colors.grey[800] : Colors.grey[50], ), ), if (isRegisterMode) ...[ const SizedBox(height: 16), TextField( controller: inviterController, enabled: !isLoading, decoration: InputDecoration( labelText: '邀请人 ID (可选)', prefixIcon: const Icon(Icons.card_giftcard_outlined, color: _pinkColor), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: _pinkColor), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: _pinkColor.withOpacity(0.5)), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: _pinkColor, width: 2), ), filled: true, fillColor: isDark ? Colors.grey[800] : Colors.grey[50], ), ), ], const SizedBox(height: 24), // 登录/注册按钮 SizedBox( width: double.infinity, height: 50, child: ElevatedButton( onPressed: isLoading ? null : submit, style: ElevatedButton.styleFrom( backgroundColor: _pinkColor, foregroundColor: Colors.black, elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: isLoading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Colors.black), ), ) : Text( isRegisterMode ? '立即注册' : '登录', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600), ), ), ), const SizedBox(height: 16), // 切换登录/注册 TextButton( onPressed: isLoading ? null : () { setState(() { isRegisterMode = !isRegisterMode; errorMessage = ''; }); }, child: Text( isRegisterMode ? '已有账号?去登录' : '没有账号?去注册', style: const TextStyle( color: _pinkColor, fontWeight: FontWeight.w500, fontSize: 14, ), ), ), ], ), ), ), ), ), ), ), ); } }