modal_progress_hud 0.1.3

  • Readme
  • Changelog
  • Example
  • Installing
  • 98

modal_progress_hud #

A simple widget wrapper to enable modal progress HUD (a modal progress indicator, HUD = Heads Up Display)

pub package Build Status Coverage Status

Inspired by this article.

Demo #

Demo

See example for details

Usage #

Add the package to your pubspec.yml file.

dependencies:
  modal_progress_hud: ^0.1.3

Next, import the library into your widget.

import 'package:modal_progress_hud/modal_progress_hud.dart';

Now, all you have to do is simply wrap your widget as a child of ModalProgressHUD, typically a form, together with a boolean that is maintained in local state.

...
bool _saving = false
...

@override
Widget build(BuildContext context) {
  return Scaffold(
     body: ModalProgressHUD(child: Container(
       Form(...)
     ), inAsyncCall: _saving),
  );
}

Options #

The current parameters are customizable in the constructor

ModalProgressHUD(
  @required inAsyncCall: bool,
  @required child: Widget,
  opacity: double,
  color: Color,
  progressIndicator: CircularProgressIndicator,
  offset: double
  dismissible: bool,
);

Example #

Here is an example app that demonstrates the usage.

  1. On initial load, _saving is false which causes your child widget to display
  2. When the form is submitted, _saving is set to true, which will display the modal
  3. Once the async call is complete, _saving is set back to false, hiding the modal
class SettingsPage extends StatefulWidget {
  @override
  _SettingsPageState createState() => new _SettingsPageState();
}

class _SettingsPageState extends State<SettingsPage> {
  bool _saving = false;

  void _submit() {

    setState(() {
      _saving = true;
    });

    //Simulate a service call
    print('submitting to backend...');
    new Future.delayed(new Duration(seconds: 4), () {
      setState(() {
        _saving = false;
      });
    });
  }

  Widget _buildWidget() {
    return new Form(
      child: new Column(
        children: [
          new SwitchListTile(
            title: const Text('Bedroom'),
            value: _bedroom,
            onChanged: (bool value) {
              setState(() {
                _bedroom = value;
              });
            },
            secondary: const Icon(Icons.hotel),
          ),
          new RaisedButton(
            onPressed: _submit,
            child: new Text('Save'),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Flutter Progress Indicator Demo'),
        backgroundColor: Colors.blue,
      ),
      body: ModalProgressHUD(child: _buildWidget(), inAsyncCall: _saving),
    );
  }
}

Update: See this article on Medium about async form validation

See the example application source for a complete sample app using the modal progress HUD. Included in the example is a method for using a form's validators while making async calls (see flutter/issues/9688 for details).

Issues and feedback #

Please file issues to send feedback or report a bug. Thank you!

[0.1.3] #

  • Performance optimization
  • Improved docs

[0.1.2] #

  • Added option to dismiss modal
  • Refactored example

[0.1.1] #

  • Added option to position progress indicator
  • Refactored example

[0.1.0] #

  • Added support for Dart 2.0

[0.0.6] #

  • Pass any progress indicator
  • Added tests and code coverage
  • Refactoring for tests

[0.0.5] #

  • Changed layout of README and corrected spelling

[0.0.4] #

  • Updated README

[0.0.3] #

  • Fixed location of demo gif file

[0.0.2] #

  • Added example of use of modal progress hud with login screen, form and async calls.

[0.0.1] - July 10, 2018 #

  • Simple countainer widget to enable modal progress hud (progress indicator)

example/lib/main.dart

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:modal_progress_hud/modal_progress_hud.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<LoginPage> {
  // maintains validators and state of form fields
  final GlobalKey<FormState> _loginFormKey = GlobalKey<FormState>();

  // 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;

  // 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,
        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: RaisedButton(
              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),
                  ),
          ),
        ],
      ),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  modal_progress_hud: ^0.1.3

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:modal_progress_hud/modal_progress_hud.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
98
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
95
Overall:
Weighted score of the above. [more]
98
Learn more about scoring.

We analyzed this package on Apr 4, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.6
  • Flutter: 1.12.13+hotfix.8

Maintenance suggestions

Package is getting outdated. (-4.66 points)

The package was last published 54 weeks ago.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=1.20.1 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test