import 'dart:html'; 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) { window.localStorage["token"] = rs.token; window.localStorage["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(); }); } } void submitSignIn() { // Validate returns true if the form is valid, or false otherwise. if (_formKey.currentState!.validate()) { final username = usernameCtrl.text; final password = passwordCtrl.text; accountsGrpc.signIn(username, "", password).then((rs) { window.localStorage["token"] = rs.token; window.localStorage["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(); }); } } void subminResetPassword() { // Validate returns true if the form is valid, or false otherwise. if (_formKey.currentState!.validate()) { final username = usernameCtrl.text; final password = passwordCtrl.text; final code = codeCtrl.text; accountsGrpc.newPassword(username, code, password).then((rs) { action = Action.singIn; // 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(); }); } } void sendCode() { if (_formKey.currentState!.validate()) { final username = usernameCtrl.text; final email = emailCtrl.text; accountsGrpc .resetPassword(username, email) .then((_) => setState(() { codeEnabled = true; })) .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, )); }); } } Widget signInForm() => SizedBox( width: 420, height: 280, child: Form( key: _formKey, child: Center( child: Column(children: [ TextFormField( onFieldSubmitted: (value) => submitSignIn(), 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) => submitSignIn(), 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), ), TextButton( onPressed: () => setState(() { action = Action.resetPassword; }), child: const Text("reset yomakeur password")), ])))); List signInActions() => [ TextButton( onPressed: () => setState(() { action = Action.signUp; }), child: const Text('Sing Up'), ), TextButton( onPressed: submitSignIn, child: const Text('OK'), ), ]; 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'), ), TextButton( onPressed: subminResetPassword, child: const Text('OK'), ), ]; 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), ), ])))); Widget resetPasswordForm() => SizedBox( width: 420, height: 420, 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), ), TextButton( onPressed: () => sendCode(), child: const Text("send code to email")), TextFormField( // onFieldSubmitted: (value) => submitSignUp(), controller: codeCtrl, autofocus: false, enabled: codeEnabled, decoration: const InputDecoration( hintText: "Enter code that you've received via the email", icon: Icon(Icons.numbers), label: Text("Code"), ), cursorWidth: 1, cursorHeight: 18, cursorRadius: const Radius.circular(10), ), TextFormField( // onFieldSubmitted: (value) => submitSignUp(), controller: passwordCtrl, autofocus: false, enabled: codeEnabled, obscureText: true, decoration: const InputDecoration( hintText: "Enter a new password", icon: Icon(Icons.password), label: Text("Password"), ), cursorWidth: 1, cursorHeight: 18, cursorRadius: const Radius.circular(10), ), TextFormField( // onFieldSubmitted: (value) => submitSignUp(), controller: passwordVerifyCtrl, autofocus: false, enabled: codeEnabled, obscureText: true, decoration: const InputDecoration( hintText: "Enter a new password", icon: Icon(Icons.password), label: Text("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) { case Action.signUp: return signUpForm(); case Action.resetPassword: return resetPasswordForm(); default: return signInForm(); } }(), actions: () { switch (action) { case Action.signUp: return signUpActions(); case Action.resetPassword: return resetPasswordActions(); default: return signInActions(); } }()); }