import 'package:cloudreve4_flutter/data/models/login_config_model.dart'; import 'package:cloudreve4_flutter/presentation/widgets/desktop_constrained.dart'; import 'package:cloudreve4_flutter/services/captcha_service.dart'; import 'package:flutter/material.dart'; import 'package:lucide_icons/lucide_icons.dart'; import '../../../core/validators/string_validator.dart'; import '../../../services/auth_service.dart'; import '../../../services/server_service.dart'; import '../../widgets/toast_helper.dart'; class RegisterPage extends StatefulWidget { final LoginConfigModel loginConfig; const RegisterPage({super.key, this.loginConfig = const LoginConfigModel()}); @override State createState() => _RegisterPageState(); } class _RegisterPageState extends State { final _formKey = GlobalKey(); final _emailController = TextEditingController(); final _passwordController = TextEditingController(); final _confirmPasswordController = TextEditingController(); bool _obscurePassword = true; bool _obscureConfirmPassword = true; bool _isLoading = false; String? _errorMessage; @override void initState() { super.initState(); if (widget.loginConfig.regCaptcha) { WidgetsBinding.instance.addPostFrameCallback((_) { final server = ServerService.instance.currentServer; if (server != null) { CaptchaService.instance.loadCaptcha(server.baseUrl).then((_) { if (mounted) setState(() {}); }); } }); } } @override void dispose() { _emailController.dispose(); _passwordController.dispose(); _confirmPasswordController.dispose(); super.dispose(); } Future _register() async { if (!_formKey.currentState!.validate()) return; if (_passwordController.text != _confirmPasswordController.text) { setState(() => _errorMessage = '两次输入的密码不一致'); return; } final captcha = CaptchaService.instance; if (widget.loginConfig.regCaptcha && !captcha.isWebCaptchaVerified) { ToastHelper.failure('请先完成人机验证'); return; } setState(() { _isLoading = true; _errorMessage = null; }); try { final captchaParams = widget.loginConfig.regCaptcha ? captcha.getCaptchaParams() : {}; final response = await AuthService.instance.signUp( email: _emailController.text.trim(), password: _passwordController.text, language: 'zh-CN', captcha: captchaParams['captcha'], ticket: captchaParams['ticket'], ); if (mounted) { ToastHelper.success( response.requiresEmailActivation ? '注册成功,请查收邮箱进行验证' : '注册成功', ); Navigator.of(context).pop(); } } catch (e) { if (mounted) { if (widget.loginConfig.regCaptcha) { await captcha.refreshCaptcha(); setState(() {}); } setState(() => _errorMessage = e.toString()); } } finally { if (mounted) setState(() => _isLoading = false); } } @override Widget build(BuildContext context) { final theme = Theme.of(context); final captcha = CaptchaService.instance; return Scaffold( appBar: AppBar(title: const Text('注册')), body: SafeArea( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: DesktopConstrained( maxContentWidth: 480, child: Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), child: Padding( padding: const EdgeInsets.all(24), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ TextFormField( controller: _emailController, keyboardType: TextInputType.emailAddress, validator: StringValidator.validateEmail, decoration: const InputDecoration( labelText: '邮箱', hintText: '请输入邮箱地址', prefixIcon: Icon(LucideIcons.mail), ), ), const SizedBox(height: 16), TextFormField( controller: _passwordController, obscureText: _obscurePassword, validator: StringValidator.validatePassword, decoration: InputDecoration( labelText: '密码', hintText: '请输入密码(至少6位)', prefixIcon: const Icon(LucideIcons.lock), suffixIcon: IconButton( icon: Icon( _obscurePassword ? LucideIcons.eye : LucideIcons.eyeOff, size: 20, ), onPressed: () => setState( () => _obscurePassword = !_obscurePassword, ), ), ), ), const SizedBox(height: 16), TextFormField( controller: _confirmPasswordController, obscureText: _obscureConfirmPassword, validator: (value) { if (value == null || value.isEmpty) return '请确认密码'; if (value != _passwordController.text) { return '两次输入的密码不一致'; } return null; }, decoration: InputDecoration( labelText: '确认密码', hintText: '请再次输入密码', prefixIcon: const Icon(LucideIcons.lock), suffixIcon: IconButton( icon: Icon( _obscureConfirmPassword ? LucideIcons.eye : LucideIcons.eyeOff, size: 20, ), onPressed: () => setState( () => _obscureConfirmPassword = !_obscureConfirmPassword, ), ), ), ), if (widget.loginConfig.regCaptcha) ...[ const SizedBox(height: 16), captcha.buildCaptchaInput(context), ], if (_errorMessage != null) ...[ const SizedBox(height: 16), Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 8, ), decoration: BoxDecoration( color: theme.colorScheme.errorContainer, borderRadius: BorderRadius.circular(8), ), child: Text( _errorMessage!, style: TextStyle( color: theme.colorScheme.onErrorContainer, fontSize: 13, ), ), ), ], const SizedBox(height: 24), FilledButton( onPressed: _isLoading ? null : _register, style: FilledButton.styleFrom( minimumSize: const Size(double.infinity, 48), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: _isLoading ? const SizedBox( width: 24, height: 24, child: CircularProgressIndicator( strokeWidth: 2, ), ) : const Text('注册'), ), const SizedBox(height: 16), TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('已有账号?去登录'), ), ], ), ), ), ), ), ), ), ), ); } }