import 'package:web/web.dart' as web; import 'package:flutter/material.dart'; import 'package:grpc/grpc_web.dart'; import 'package:softplayer_web/api/grpc/accounts.dart'; class LoginForm extends StatefulWidget { const LoginForm({ super.key, required this.grpcChannel, required this.notifyParent, }); final Function() notifyParent; final GrpcWebClientChannel grpcChannel; @override State createState() => _LoginFormState(); } enum Action { singIn, signUp, resetPassword } class _LoginFormState extends State { final _formKey = GlobalKey(); final usernameCtrl = TextEditingController(); final passwordCtrl = TextEditingController(); final passwordVerifyCtrl = TextEditingController(); final emailCtrl = TextEditingController(); final codeCtrl = TextEditingController(); late AccountsGrpc accountsGrpc; Action action = Action.singIn; bool codeEnabled = false; static const dialogName = "Login"; void submitSignUp() { // Validate returns true if the form is valid, or false otherwise. if (_formKey.currentState!.validate()) { final username = usernameCtrl.text; final password = passwordCtrl.text; final email = emailCtrl.text; accountsGrpc.signUp(username, email, password).then((rs) { web.window.localStorage.setItem("token", rs.token); web.window.localStorage.setItem("uuid", rs.uuid); widget.notifyParent(); Navigator.of(context, rootNavigator: true).pop(); }).catchError((e) { GrpcError error = e; String msg; if (error.message != null) { msg = error.message!; } else { msg = error.toString(); } ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text(msg), backgroundColor: Colors.red, showCloseIcon: true, behavior: SnackBarBehavior.floating, )); passwordCtrl.clear(); }); } } List signUpActions() => [ TextButton( onPressed: () => setState(() { action = Action.singIn; }), child: const Text('Sign In'), ), TextButton( onPressed: submitSignUp, child: const Text('OK'), ), ]; List resetPasswordActions() => [ TextButton( onPressed: () => setState(() { action = Action.singIn; }), child: const Text('Sign In'), ), TextButton( onPressed: () => setState(() { action = Action.signUp; }), child: const Text('Sing Up'), ), ]; Widget signUpForm() => SizedBox( width: 420, height: 280, child: Form( key: _formKey, child: Center( child: Column(children: [ TextFormField( onFieldSubmitted: (value) => submitSignUp(), autofocus: true, controller: usernameCtrl, decoration: const InputDecoration( hintText: "Enter your username", icon: Icon(Icons.account_circle), label: Text("Username"), ), cursorWidth: 1, cursorHeight: 18, cursorRadius: const Radius.circular(10), ), TextFormField( onFieldSubmitted: (value) => submitSignUp(), controller: emailCtrl, autofocus: true, decoration: const InputDecoration( hintText: "Enter your email", icon: Icon(Icons.email), label: Text("Email"), ), cursorWidth: 1, cursorHeight: 18, cursorRadius: const Radius.circular(10), ), TextFormField( onFieldSubmitted: (value) => submitSignUp(), controller: passwordCtrl, obscureText: true, decoration: const InputDecoration( hintText: "Enter your password", icon: Icon(Icons.password), label: Text("Password")), cursorWidth: 1, cursorHeight: 18, cursorRadius: const Radius.circular(10), ), TextFormField( onFieldSubmitted: (value) => submitSignUp(), controller: passwordVerifyCtrl, obscureText: true, decoration: const InputDecoration( hintText: "Verify your password", icon: Icon(Icons.password), label: Text("Confirm Password")), cursorWidth: 1, cursorHeight: 18, cursorRadius: const Radius.circular(10), ), ])))); @override void initState() { super.initState(); accountsGrpc = AccountsGrpc(channel: widget.grpcChannel); accountsGrpc.init(); } @override Widget build(BuildContext context) => AlertDialog( title: const Text(dialogName), // content: action == Action.singIn ? signInForm() : signUpForm(), content: () { switch (action) { default: return signUpForm(); } }(), actions: () { switch (action) { default: return signUpActions(); } }()); }