import 'package:flutter/material.dart'; import 'package:mysql_client/mysql_client.dart'; import 'dart:async'; import 'dart:math'; import 'package:mailer/mailer.dart'; import 'package:mailer/smtp_server.dart'; import 'package:validators/validators.dart' as validator; import 'generated/l10n.dart'; void main() { runApp(MaterialApp( home: RegisterPage(), )); } class RegisterPage extends StatefulWidget { @override _RegisterPageState createState() => _RegisterPageState(); } class _RegisterPageState extends State { late FocusNode _nameFocusNode, _emailFocusNode, _passwordFocusNode, _codeFocusNode; final TextEditingController _nameController = TextEditingController(); final TextEditingController _emailController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); final TextEditingController _codeController = TextEditingController(); bool _passwordNotVisible = true; bool _isButtonEnabled = true; int _seconds = 60; Timer? _timer; String _generatedCode = ''; @override void initState() { super.initState(); _fetchData(); _nameFocusNode = FocusNode(); _emailFocusNode = FocusNode(); _passwordFocusNode = FocusNode(); _codeFocusNode = FocusNode(); } void _fetchData() async { final conn = await MySQLConnection.createConnection( host: 'comprehensive-guardian.systems', port: 33061, userName: 'root', password: 'Topic@2024', databaseName: 'care', ); await conn.connect(); } void _startTimer() { setState(() { _isButtonEnabled = false; }); _timer = Timer.periodic(Duration(seconds: 1), (timer) { setState(() { if (_seconds > 0) { _seconds--; } else { _timer?.cancel(); _isButtonEnabled = true; _seconds = 60; } }); }); } String _generateVerificationCode() { final random = Random(); const availableChars = '0123456789'; return List.generate( 6, (index) => availableChars[random.nextInt(availableChars.length)]) .join(); } Future _sendEmail(String recipientEmail, String code) async { final smtpServer = SmtpServer( 'smtp.mail.me.com', port: 587, username: 'ltesr125124015@icloud.com', password: 'vwtp-bruz-xiav-rjee', ssl: false, allowInsecure: false, ); final message = Message() ..from = Address('user_manager@comprehensive-guardian.systems', '全方位照護守護者') ..recipients.add(recipientEmail) ..subject = '您的驗證碼' ..text = '您的驗證碼是: $code'; try { await send(message, smtpServer); print('驗證碼發送成功'); print('生成的驗證碼是: $code'); } catch (e) { print('驗證碼發送失敗: $e'); } } void _sendVerificationCode() { final email = _emailController.text; if (email.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(S.of(context).register_error_email_empty)), ); return; } else if (!validator.isEmail(email)) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(S.of(context).register_error_email_invalid)), ); _emailFocusNode.requestFocus(); return; } _generatedCode = _generateVerificationCode(); _sendEmail(email, _generatedCode); _startTimer(); } bool _isDataCorrect() { String name = _nameController.text; String email = _emailController.text; String password = _passwordController.text; String code = _codeController.text; if (name == '') { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(S.of(context).register_error_username_empty)), ); _nameFocusNode.requestFocus(); return false; } if (email == '') { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(S.of(context).register_error_email_empty)), ); _emailFocusNode.requestFocus(); return false; } if (password == '') { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(S.of(context).register_error_password_empty)), ); _passwordFocusNode.requestFocus(); return false; } if (_generatedCode == ''){ ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(S.of(context).register_error_verificationCode_not_send)), ); return false; } if (code == '' || code != _generatedCode) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(S.of(context).register_error_verificationCode_not_match)), ); _codeFocusNode.requestFocus(); return false; } return true; } void registerBtn() async { if (!_isDataCorrect()) return; final conn = await MySQLConnection.createConnection( host: 'comprehensive-guardian.systems', port: 33061, userName: 'root', password: 'Topic@2024', databaseName: 'care', ); await conn.connect(); try { String name = _nameController.text; String email = _emailController.text; String password = _passwordController.text; var result = await conn.execute( 'SELECT * FROM HomeLogin WHERE homeEmail = :email OR homeUserName = :name', {'email': email, 'name': name}, ); if (result.rows.isNotEmpty) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(S.of(context).register_error_usernameOrEmail_exist)), ); } else { await conn.execute( 'INSERT INTO HomeLogin (homeUserName, homeEmail, homePassword) VALUES (:name, :email, :password)', {'name': name, 'email': email, 'password': password}, ); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(S.of(context).register_success)), ); Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => VerifyPage(email: email), ), ); _nameController.clear(); _emailController.clear(); _passwordController.clear(); } } catch (e) { print('資料庫錯誤: $e'); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(S.of(context).register_error_server_error)), ); } finally { await conn.close(); } } @override void dispose() { super.dispose(); _timer?.cancel(); _nameFocusNode.dispose(); _emailFocusNode.dispose(); _passwordFocusNode.dispose(); _codeFocusNode.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Center( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 32.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( margin: EdgeInsets.only(bottom: 40), height: 100, child: Icon( Icons.account_circle, size: 100, color: Color(0xFF4FC3F7), ), ), Text( S.of(context).app_name, style: TextStyle( fontSize: 32, fontWeight: FontWeight.bold, color: Colors.black, ), ), SizedBox(height: 20), TextField( controller: _nameController, focusNode: _nameFocusNode, decoration: InputDecoration( border: OutlineInputBorder(), prefixIcon: Icon(Icons.person_outlined), labelText: '使用者名稱', ), ), SizedBox(height: 20), TextField( controller: _emailController, focusNode: _emailFocusNode, decoration: InputDecoration( border: OutlineInputBorder(), prefixIcon: Icon(Icons.email_outlined), labelText: '電子信箱', ), keyboardType: TextInputType.emailAddress, ), SizedBox(height: 20), TextField( controller: _passwordController, focusNode: _passwordFocusNode, decoration: InputDecoration( border: OutlineInputBorder(), prefixIcon: Icon(Icons.lock_outlined), suffixIcon: IconButton( icon: Icon(_passwordNotVisible ? Icons.visibility : Icons.visibility_off), onPressed: () { setState( () { _passwordNotVisible = !_passwordNotVisible; }, ); }, ), labelText: '密碼', ), obscureText: _passwordNotVisible, ), SizedBox(height: 20), Row( children: [ Expanded( child: TextField( controller: _codeController, focusNode: _codeFocusNode, decoration: InputDecoration( labelText: '驗證碼', hintText: '填寫驗證碼', ), ), ), SizedBox(width: 10), ElevatedButton( onPressed: _isButtonEnabled ? _sendVerificationCode : null, child: _isButtonEnabled ? Text('發送驗證碼') : Text('重新發送(${_seconds})'), style: ElevatedButton.styleFrom( backgroundColor: _isButtonEnabled ? Color(0xFF4FC3F7) : Colors.grey, padding: EdgeInsets.symmetric(horizontal: 16), ), ), ], ), SizedBox(height: 20), ElevatedButton( onPressed: registerBtn, child: Text('下一步'), style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF4FC3F7), padding: EdgeInsets.symmetric(horizontal: 50, vertical: 15), textStyle: TextStyle(fontSize: 18), ), ), SizedBox(height: 10), ElevatedButton( onPressed: () { Navigator.pop(context); }, child: Text('取消註冊'), style: TextButton.styleFrom( backgroundColor: Colors.transparent, textStyle: TextStyle(fontSize: 18), shadowColor: Colors.transparent, ), ), ], ), ), ), ), ), ); } } class VerifyPage extends StatelessWidget { final String email; VerifyPage({required this.email}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(S.of(context).register_success), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('Email: $email'), SizedBox(height: 20), ElevatedButton( onPressed: () { // 返回登入頁面 Navigator.pop(context); }, child: Text(S.of(context).register_turn_back), style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF4FC3F7), padding: EdgeInsets.symmetric(horizontal: 30, vertical: 15), textStyle: TextStyle(fontSize: 18), ), ), ], ), ), ); } }