Search code examples
flutterflutter-alertdialog

Update alert modal child from parent


I'm calling show my dialog when a button is pushed to display the progress of an upload which is in the parent.

Throughout the upload function's parts I'm updating state like setState(() => _progress = _progress + 0.05); for example. However my dialog value is not correctly being updated as well. I think that the dialog is not rebuilding. How do I get the dialog to listen to this value and rebuild when it's updated?

Dialog code:

Future<void> _showMyDialog() async {
return showDialog<void>(
  context: context,
  barrierDismissible: true, // user must tap button!
  builder: (BuildContext context) {
    return AlertDialog(
        insetPadding: EdgeInsets.all(10.0),
        content: StatefulBuilder(
            builder: (BuildContext context, StateSetter setState) {
          return Container(
            height: MediaQuery.of(context).size.width * 0.3,
            width: MediaQuery.of(context).size.width * 0.9,
            child: Center(
                child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                  Text(
                    "Uploading...",
                    style: TextStyle(
                        fontWeight: FontWeight.bold, fontSize: 20),
                  ),
                  SizedBox(height: 30),
                  ClipRRect(
                      borderRadius: BorderRadius.all(Radius.circular(10)),
                      child: LinearProgressIndicator(
                        minHeight: 15,
                        value: _progress,
                      ))
                ])),
          );
        }));
  },
);

Trigger dialog code:

onPressed: () async {
              setState(() => loading = true);
                _showMyDialog();
                await uploadAudio();           
                setState(() => loading = false);
           },

Solution

  • You can copy paste run full code below
    You can use ValueNotifier<double> and ValueListenableBuilder
    code snippet

      final ValueNotifier<double> _progress = ValueNotifier<double>(0);
    
      Future<void> uploadAudio() async {
        await Future.delayed(Duration(seconds: 2), () {});
        _progress.value = 0.1;
        ...
        await Future.delayed(Duration(seconds: 2), () {});
        _progress.value = 1.0;
      }
    
      Future<void> _showMyDialog() async {
        ...
                          ClipRRect(
                              borderRadius: BorderRadius.all(Radius.circular(10)),
                              child: ValueListenableBuilder(
                                  builder: (BuildContext context, double value,
                                      Widget child) {
                                    return LinearProgressIndicator(
                                        minHeight: 15, value: value);
                                  },
                                  valueListenable: _progress))
                        ])),
                  );
                }));
          },
        );
      }
    
      ElevatedButton(
                    onPressed: () async {
                      setState(() => loading = true);
                      _progress.value = 0;
                      _showMyDialog();
                      await uploadAudio();
                      setState(() => loading = false);
                    },
                    child: Text('Upload')),
    

    working demo

    enter image description here

    full code

    import 'package:flutter/material.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: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      bool loading;
      final ValueNotifier<double> _progress = ValueNotifier<double>(0);
    
      Future<void> uploadAudio() async {
        await Future.delayed(Duration(seconds: 2), () {});
        _progress.value = 0.1;
        await Future.delayed(Duration(seconds: 2), () {});
        _progress.value = 0.5;
        await Future.delayed(Duration(seconds: 2), () {});
        _progress.value = 0.7;
        await Future.delayed(Duration(seconds: 2), () {});
        _progress.value = 1.0;
      }
    
      Future<void> _showMyDialog() async {
        return showDialog<void>(
          context: context,
          barrierDismissible: true, // user must tap button!
          builder: (BuildContext context) {
            return AlertDialog(
                insetPadding: EdgeInsets.all(10.0),
                content: StatefulBuilder(
                    builder: (BuildContext context, StateSetter setState) {
                  return Container(
                    height: MediaQuery.of(context).size.width * 0.3,
                    width: MediaQuery.of(context).size.width * 0.9,
                    child: Center(
                        child: Column(
                            mainAxisAlignment: MainAxisAlignment.center,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                          Text(
                            "Uploading...",
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 20),
                          ),
                          SizedBox(height: 30),
                          ClipRRect(
                              borderRadius: BorderRadius.all(Radius.circular(10)),
                              child: ValueListenableBuilder(
                                  builder: (BuildContext context, double value,
                                      Widget child) {
                                    return LinearProgressIndicator(
                                        minHeight: 15, value: value);
                                  },
                                  valueListenable: _progress))
                        ])),
                  );
                }));
          },
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                ElevatedButton(
                    onPressed: () async {
                      setState(() => loading = true);
                      _progress.value = 0;
                      _showMyDialog();
                      await uploadAudio();
                      setState(() => loading = false);
                    },
                    child: Text('Upload')),
              ],
            ),
          ),
        );
      }
    }