mmcc007/modal_progress_hud

close the progress indicator

nitneuq33000 opened this issue · 1 comments

hello, I tried to add a function to close the progress indicator manualy (button) or automaticaly (delay) but I havn't succeded. I would add the posibility for the user to close the progress indicator if there is no connection.

I put together a demo app that shows how it works with a local timeout with modal_progress_hud. It also shows one method for dealing with responses from server arriving out of order (as is often the case if making frequent calls to a slow server):

import 'dart:async';
import 'dart:math';

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(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Demo of modal_progress_hud'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Random _random = Random(42);
  String _appStatusStr = 'before first async call';
  bool _inAsyncCall = false;
  bool _localTimeout = false;
  // used to demonstrate that slow responses can overwrite faster responses
  // unless handled correctly
  int _asyncCallCounter = 0;

  void _submit() {
    // Simulate a service call with random duration and 50% random timeout
    _localTimeout = false;
    int asyncCallDuration = _random.nextInt(3) + 3;
    int timeoutDuration =
        _random.nextBool() ? asyncCallDuration - 2 : asyncCallDuration + 1;
    _asyncCallCounter += 1;
    // every 4th call add a long call with a timeout
    if (_asyncCallCounter % 4 == 0) {
      print('!!!submitting long async call!!!');
      asyncCallDuration = 10;
      timeoutDuration = 1;
    }
    print('submitting to backend: '
        'asyncCallID = $_asyncCallCounter, '
        'duration = $asyncCallDuration, '
        'timeout = $timeoutDuration'
        '...');
    setState(() {
      // turn on modal progress hud
      _inAsyncCall = true;
      final timeoutStr = timeoutDuration < asyncCallDuration
          ? 'timeout: $timeoutDuration'
          : '';
      _appStatusStr = 'async call($_asyncCallCounter) '
          'duration: $asyncCallDuration, '
          '$timeoutStr '
          'pending';
    });
    simulatedBackend(_asyncCallCounter, asyncCallDuration)
        .then((transactionID) {
          // futures are not cancellable (AFAIK)
          print('response from backend: transactionID: $transactionID');
          if (_localTimeout)
            print('response ignored: timeout');
          else if (_asyncCallCounter == transactionID) {
            setState(() {
              // turn off modal progress hud
              _inAsyncCall = false;
              _appStatusStr = 'async call($_asyncCallCounter) succeeded';
            });
          } else
            print('response ignored: old async call($transactionID)');
        })
        .timeout(Duration(seconds: timeoutDuration))
        .catchError((err) {
          print('local timeout: $err');
          setState(() {
            // turn off modal progress hud
            _inAsyncCall = false;
            _localTimeout = true;
            _appStatusStr = 'async call($_asyncCallCounter) timeout';
          });
        });
  }

  Future<int> simulatedBackend(int transactionID, int duration) async {
    await Future.delayed(Duration(seconds: duration));
    return Future.value(transactionID);
  }

  @override
  Widget build(BuildContext context) {
    return ModalProgressHUD(
      inAsyncCall: _inAsyncCall,
      child: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'Demo of modal_progress_hud',
                style: Theme.of(context).textTheme.body1,
              ),
              RaisedButton(
                onPressed: _submit,
                child: Text('Submit'),
              ),
              Text(
                _appStatusStr,
                style: Theme.of(context).textTheme.body1,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Allowing the user to cancel would require adding a button outside the modal which should be possible. Checking for no connection before entering modal is preferable to cancelling after entering modal.
😄👍