Home > other >  How to implement Navigator.push action after loading file (using CircularProgressIndicator() during
How to implement Navigator.push action after loading file (using CircularProgressIndicator() during

Time:05-31

What is the "best practice" way to implement a background downloading of a file while displaying the CircularProgressIndicator() and using the Navigator.pushNamedAndRemoveUntil afterwards on successful file loading?

This is a sample of my code:

class Downloader extends StatefulWidget {
  const Downloader({Key? key}) : super(key: key);

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

class DownloaderState extends State<Downloader> {
  Future<Directory?>? _appDocumentsDirectory;
  bool _isDownloaded = false;

  @override
  void initState() {
    super.initState();
    _initDownloader();
  }

  _initDownloader() async {
    setState(() {
        _appDocumentsDirectory = getApplicationDocumentsDirectory();
      });
  }

  Future<void> _downloadJson(String localPath) async {
    if ( === WE CHECK FOR CREDENTIALS HERE === ) {
      FTPConnect ftpConnect = FTPConnect(
          BaseAPI.ftpServerAddress,
          port: BaseAPI.ftpServerPort,
          user: _login,
          pass: _passwd);
      try {
        String fileName = 'filename.json';
        String localFileName = localPath   "/filename.json";

        print(" localFileName: $localFileName");

        await ftpConnect.connect();
        await ftpConnect.changeDirectory('ftp');
        bool res = await ftpConnect.downloadFileWithRetry(
            fileName, File(localFileName));
        await ftpConnect.disconnect();

        print("is downloaded? $res");

      } catch (e) {

        print("=== ERROR ===\n${e.toString()}");

      }
      _isDownloaded = true;

    } else {
      _isDownloaded = false;
    }
  }

Widget _buildDirectory(
      BuildContext context, AsyncSnapshot<Directory?> snapshot) {
    Text text = const Text('');
    if (snapshot.connectionState == ConnectionState.done) {
      if (snapshot.hasError) {
        text = Text('Error: ${snapshot.error}');
      } else if (snapshot.hasData) {

        String _s = snapshot.data!.path   "/filename.json";
        String _z = "File downloaded";

        _downloadJson(snapshot.data!.path);    //////////////  <= downloading here

        if (!_isDownloaded) {
          _z = "Failed to download file";
        }
        text = Text('Path to a file: \n$_s\n\npath: \n${snapshot.data!.path}\n\nFile downloaded: $_isDownloaded');

      } else {
        text = const Text('path unavailable');
      }
    }
    return text;
  }

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Loading data"),
        foregroundColor: Colors.black,
        backgroundColor: Colors.redAccent,
      ),
      body: Center(
        child: Column(
              children: <Widget>[
                FutureBuilder<Directory?>(
                  future: _appDocumentsDirectory,
                  builder: _buildDirectory,
/// I need to redirect to another page here
                ),
              ],
            ),
        ),
      );
  }
}

So my main problems are:

  1. How to properly 'catch' the moment when file is downloaded? I can only see in console (Android Studio) when "is downloaded? true" is printed but I fail to understand how to catch this moment and link some actions to it...

The workflow, as far as I understand, is like that:

1. initialize the `_appDocumentsDirectory`;
2. on initialization start the `FutureBuilder` logic:

 2.1 - checking if `_appDocumentsDirectory` has data and

 2.2 - calling the `_downloadJson`
  1. Can (or should) I wrap the logic inside the _downloadJson function in the FutureBuilder too?

  2. If I will resolve somehow first and second questions - how do you usually perform the required Navigator.pushNamedAndRemoveUntil() when needed?

CodePudding user response:

First to answer the following question,

How to display a CircularProgressIndicator while the file is downloading, you can simply introduce a variable isDownloading like below,

bool isDownloading = false;

And while downloading i.e.,

setState(() => isDownloading = true);
bool res = await ftpConnect.downloadFileWithRetry(
        fileName, File(localFileName));
setState(() => isDownloading = false);

and since setState once called will rebuild the body, in the body use something like this,

Scaffold(
  body: isDownloading ? CircularProgressIndicator() : ..[your code],
);

Next to get the local push notification you can simple use the flutter_local_notifications: ^9.5.3 1

This should definitely resolve the issue

  • Related