2

Well the issue is kinda simple, but it needs to be done on a specific way. First I have a Class extending "ChangeNotifier" this class will perform some async tasks, so while it is doing so there's a variable that indicates if the class is currently bussy or not, so far it works flawlessly.

Using Riverpod as state managment I instanciate said class and provide it along my widget tree, but there's one Widget that needs to display a dialog and inside this dialog it can execute async tasks from the Class that I've been passing around. It all works except for the fact that I would like to display a CircularProgressIndicator inside this dialog, and it doesn't seems to be reacting propperly to the state changes.

Here's a sample code to recreate the scenario:

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

final dataProvider = ChangeNotifierProvider<Data>((_) => Data());

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'huh?',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: FirstPage(),
    );
  }
}

class FirstPage extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final data = useProvider(dataProvider);
    print('DATA STATE [source: FirstPage, data: ${data.loading}]');
    return Scaffold(
      body: Center(
        child: Container(
          width: 200,
          height: 50,
          child: ElevatedButton(
            child: Text('show dialog'),
            onPressed: () => showDialog(
              context: context,
              builder: (_) => Alert(data: data),
            ),
          ),
        ),
      ),
    );
  }
}

class Alert extends StatelessWidget {
  const Alert({required this.data});
  final Data data;
  Widget build(BuildContext context) {
    print('DATA STATE [source: Alert, data: ${data.loading}]');
    return AlertDialog(
      content: Container(
        width: 500,
        height: 500,
        padding: EdgeInsets.symmetric(horizontal: 100, vertical: 200),
        child: ElevatedButton(
          child: data.loading ? CircularProgressIndicator(color: Colors.white) : Text('click here'),
          onPressed: () async => await data.randomTask(),
        ),
      ),
    );
  }
}

class Data extends ChangeNotifier {
  Data({
    this.loading = false,
  });
  bool loading;

  Future<void> randomTask() async {
    print('Actually waiting 3 seconds..');
    _update(loading: true);
    await Future.delayed(Duration(seconds: 3));
    print('Waiting done.');
    _update(loading: false);
  }

  void _update({bool? loading}) {
    this.loading = loading ?? this.loading;
    notifyListeners();
  }
}

Notice the prints I've placed, because of them if you run the app you'll see outputs on the console like:

DATA STATE [source: FirstPage, data: false]
DATA STATE [source: Alert, data: false]
Actually waiting 3 seconds..
DATA STATE [source: FirstPage, data: true]
Waiting done.
DATA STATE [source: FirstPage, data: false]

Which means that the state is actually changing, and everything is working fine, except for the dialog that seems to be static.

I already tried adding a "loading" bool as part of the "Alert" widget, and letting it manage its own state, and it works, but the code is not as clean as I would like to, because the Class "Data" is supposed to manage this kind of stuff.

Is there anything that can be done?

Thankyou in advance!

1 Answers1

0

Adding StatefulBulider do the trick

class Alert extends StatelessWidget {
  const Alert({required this.data});
  final Data data;
  Widget build(BuildContext context) {
    print('DATA STATE [source: Alert, data: ${data.loading}]');
    return AlertDialog(
      content: StatefulBuilder(builder: (context, setState) {
        return Container(
          width: 500,
          height: 500,
          padding: EdgeInsets.symmetric(horizontal: 100, vertical: 200),
          child: ElevatedButton(
            child: data.loading
                ? CircularProgressIndicator(color: Colors.white)
                : Text('click here'),
            onPressed: () async => await data.randomTask(),
          ),
        );
      }),
    );
  }
}
Hinno Saad
  • 48
  • 3