import 'dart:async'; import 'package:flutter/material.dart'; import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( primarySwatch: Colors.blue, ), home: LoginPage( onSignIn: () => print('login successful!'), ), ); } } class LoginPage extends StatefulWidget { final VoidCallback _onSignIn; LoginPage({required onSignIn}) : assert(onSignIn != null), _onSignIn = onSignIn; @override _LoginPageState createState() => _LoginPageState(); } class _LoginPageState extends State { // maintains validators and state of form fields final GlobalKey _loginFormKey = GlobalKey(); // manage state of modal progress HUD widget bool _isInAsyncCall = false; bool _isInvalidAsyncUser = false; // managed after response from server bool _isInvalidAsyncPass = false; // managed after response from server String? _username; String? _password; bool _isLoggedIn = false; double bur = 0; // validate user name String? _validateUserName(String? userName) { if (userName!.length < 8) { return 'Username must be at least 8 characters'; } if (_isInvalidAsyncUser) { // disable message until after next async call _isInvalidAsyncUser = false; return 'Incorrect user name'; } return null; } // validate password String? _validatePassword(String? password) { if (password!.length < 8) { return 'Password must be at least 8 characters'; } if (_isInvalidAsyncPass) { // disable message until after next async call _isInvalidAsyncPass = false; return 'Incorrect password'; } return null; } void _submit() { if (_loginFormKey.currentState!.validate()) { _loginFormKey.currentState!.save(); // dismiss keyboard during async call FocusScope.of(context).requestFocus(new FocusNode()); // start the modal progress HUD setState(() { _isInAsyncCall = true; }); // Simulate a service call Future.delayed(Duration(seconds: 1), () { final _accountUsername = 'username1'; final _accountPassword = 'password1'; setState(() { if (_username == _accountUsername) { _isInvalidAsyncUser = false; if (_password == _accountPassword) { // username and password are correct _isInvalidAsyncPass = false; _isLoggedIn = true; } else // username is correct, but password is incorrect _isInvalidAsyncPass = true; } else { // incorrect username and have not checked password result _isInvalidAsyncUser = true; // no such user, so no need to trigger async password validator _isInvalidAsyncPass = false; } // stop the modal progress HUD _isInAsyncCall = false; }); if (_isLoggedIn) // do something widget._onSignIn(); }); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Modal Progress HUD Demo'), backgroundColor: Colors.blue, ), // display modal progress HUD (heads-up display, or indicator) // when in async call body: ModalProgressHUD( child: SingleChildScrollView( child: Container( padding: const EdgeInsets.all(16.0), child: buildLoginForm(context), ), ), inAsyncCall: _isInAsyncCall, // demo of some additional parameters opacity: 0.5, blur: bur, progressIndicator: CircularProgressIndicator(), ), ); } Widget buildLoginForm(BuildContext context) { final TextTheme textTheme = Theme .of(context) .textTheme; // run the validators on reload to process async results _loginFormKey.currentState?.validate(); return Form( key: this._loginFormKey, child: Column( children: [ Padding( padding: const EdgeInsets.all(8.0), child: TextFormField( key: Key('username'), decoration: InputDecoration( hintText: 'enter username', labelText: 'User Name'), style: TextStyle(fontSize: 20.0, color: textTheme.button!.color), validator: _validateUserName, onSaved: (value) => _username = value, ), ), Padding( padding: const EdgeInsets.all(8.0), child: TextFormField( key: Key('password'), obscureText: true, decoration: InputDecoration( hintText: 'enter password', labelText: 'Password'), style: TextStyle(fontSize: 20.0, color: textTheme.button!.color), validator: _validatePassword, onSaved: (value) => _password = value, ), ), Padding( padding: const EdgeInsets.all(32.0), child: ElevatedButton( onPressed: _submit, child: Text('Login'), ), ), Padding( padding: const EdgeInsets.all(8.0), child: _isLoggedIn ? Text( 'Login successful!', key: Key('loggedIn'), style: TextStyle(fontSize: 20.0), ) : Text( 'Not logged in', key: Key('notLoggedIn'), style: TextStyle(fontSize: 20.0), ), ), Slider(min: 0, max: 10, value: bur, divisions: 100, onChanged: (val) { setState(() { bur = val; }); },), ], ), ); } }