import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:food_hub_app/api/recipe.dart'; import 'package:food_hub_app/api/session.dart'; import 'package:food_hub_app/models/recipe.dart'; import 'package:food_hub_app/models/session.dart'; import 'package:food_hub_app/utils/sp_util.dart'; import 'package:food_hub_app/widgets/common/index.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart'; class LoginPage extends StatefulWidget { const LoginPage({super.key}); @override State createState() => _LoginPage(); } class _LoginPage extends State { final GlobalKey _formKey = GlobalKey(); late String _username, _password; bool _isObscure = true; Color _eyeColor = Colors.grey; final List _loginMethod = [ {"title": "phone", "icon": Icons.phone_android}, {"title": "email", "icon": Icons.email}, {"title": "wechat", "icon": Icons.wechat}, ]; void loginClick(BuildContext context) async { SPUtil.clear(); Session session = await loginApi("Cxx0822", "19940822Cxx"); SPUtil.set('token', session.saToken.tokenValue); Recipe recipe = await queryRecipeByIdApi(614660173221957); List recipeList = await queryRecipeByUserApi(691110779121733); // SPUtil.set("token", session?.saToken?.tokenValue); // Navigator.pushNamed(context, '/home'); return; // 表单校验通过才会继续执行 if ((_formKey.currentState as FormState).validate()) { (_formKey.currentState as FormState).save(); TDMessage.showMessage( context: context, visible: true, icon: true, content: "登录成功", theme: MessageTheme.success, duration: 3000, ); Navigator.pushNamed(context, '/home'); } else { TDMessage.showMessage( context: context, visible: true, icon: true, content: "请先输入信息", theme: MessageTheme.error, duration: 3000, ); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[100], body: Form( key: _formKey, autovalidateMode: AutovalidateMode.onUserInteraction, child: Column( children: [ // 可滚动的主要内容区域 Expanded( child: ListView( padding: const EdgeInsets.symmetric(horizontal: 20), children: [ const SizedBox(height: kToolbarHeight), buildTitle(), const SizedBox(height: 60), buildUsernameTextField(), const SizedBox(height: 20), buildPasswordTextField(context), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ buildRememberPasswordCheckbox(context), // 记住密码(左对齐) buildForgetPasswordText(context), ], ), const SizedBox(height: 20), // 调整与登录按钮的间距 buildLoginButton(context), ], ), ), // 固定在底部的其他登录选项区域 Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 50), child: Column( children: [ buildOtherLoginText(), const SizedBox(height: 15), buildOtherMethod(context), const SizedBox(height: 20), buildRegisterText(context), ], ), ), ], ), ), ); } Widget buildTitle() { return const Text( '食光集', textAlign: TextAlign.center, style: TextStyle(fontSize: 42), ); } Widget buildUsernameTextField() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ formLabelText(labelText: "账号:"), const SizedBox(height: 10), FormBuilderTextField( name: 'username', decoration: formInputDecoration( hintText: "请输入账号", prefixIcon: Icons.person, ), validator: FormBuilderValidators.required(), onSaved: (v) => _username = v!, ), ], ); } Widget buildPasswordTextField(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ formLabelText(labelText: "密码:"), const SizedBox(height: 10), FormBuilderTextField( name: 'password', obscureText: _isObscure, // 是否显示文字 onSaved: (v) => _password = v!, validator: FormBuilderValidators.required(), decoration: InputDecoration( prefixIcon: Icon(Icons.lock), hintText: "请输入密码", hintStyle: TextStyle(color: Colors.grey), border: OutlineInputBorder(), filled: true, fillColor: Colors.white, suffixIcon: IconButton( icon: Icon(Icons.remove_red_eye, color: _eyeColor), onPressed: () { // 修改 state 内部变量, 且需要界面内容更新, 需要使用 setState() setState(() { _isObscure = !_isObscure; _eyeColor = (_isObscure ? Colors.grey : Theme.of(context).iconTheme.color)!; }); }, ), ), ), ], ); } Widget buildRememberPasswordCheckbox(BuildContext context) { return Row( children: [ Checkbox( value: false, onChanged: (bool? value) { print("记住密码: $value"); }, ), const Text('记住密码', style: TextStyle(color: Colors.grey, fontSize: 14)), ], ); } Widget buildForgetPasswordText(BuildContext context) { return Align( alignment: Alignment.centerRight, child: TextButton( onPressed: () { print("忘记密码"); }, child: const Text( "忘记密码?", style: TextStyle(fontSize: 14, color: Colors.grey), ), ), ); } Widget buildLoginButton(BuildContext context) { return Align( child: SizedBox( height: 45, width: double.infinity, child: TDButton( text: '登录', size: TDButtonSize.large, type: TDButtonType.fill, shape: TDButtonShape.rectangle, theme: TDButtonTheme.primary, onTap: () => loginClick(context), ), ), ); } Widget buildOtherLoginText() { return TDDivider(text: '其他方式登录', alignment: TextAlignment.center); } Widget buildOtherMethod(context) { return OverflowBar( alignment: MainAxisAlignment.center, children: _loginMethod .map( (item) => Builder( builder: (context) { return IconButton( icon: Icon( item['icon'], color: Theme.of(context).iconTheme.color, ), onPressed: () { //TODO: 第三方登录方法 ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('${item['title']}登录'), action: SnackBarAction( label: '取消', onPressed: () {}, ), ), ); }, ); }, ), ) .toList(), ); } Widget buildRegisterText(context) { return Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('没有账号?', style: TextStyle(fontSize: 18)), GestureDetector( child: const Text( '点击注册', style: TextStyle(fontSize: 18, color: Colors.green), ), onTap: () { print("点击注册"); }, ), ], ), ); } }