简体   繁体   中英

how can I send data from one class to a stateful widget in Flutter

I want to be able to make progress bar where the value changes based on a function. My problem is I am working with 3 different files. The first file main_page_test.dart where the code for calling the function is held. enigma_test.dart where the code for the function is held. Finally, loading_alert_dialog.dart where I keep the code for the AlertDialog containing the ProgressBar

To clarify, I want the application to display the AlertDialog when the function is called in main_page_test.dart . While the function is running I want it to update the ProgressBar and pass the filename of the file it is working on encrypting.

If there is anything else I can clarify on please let me know.

Here is the relevant code for main_page_test.dart :

import 'dart:io';

import 'package:fluent_ui/fluent_ui.dart';
import 'package:file_picker/file_picker.dart';

import '../functions/enigma_test.dart';

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

  @override
  State<MainPageTest> createState() => _MainPageTestState();
}

class _MainPageTestState extends State<MainPageTest> {
  final double _buttonTextSize = 20.0;
  final double _widgetWidth = 200.0;

  List<File>? _files;

  late final TextEditingController _textController;
  late final FlyoutController _flyoutController;

  @override
  void initState() {
    super.initState();
    _textController = TextEditingController();
    _flyoutController = FlyoutController();
  }

  @override
  void dispose() {
    _textController.dispose();
    _flyoutController.dispose();
    super.dispose();
  }

  void pickFiles() async {
    FilePickerResult? result = await FilePicker.platform.pickFiles(
      type: FileType.custom,
      allowedExtensions: ['txt'],
      allowMultiple: true,
    );

    if (result != null) {
      setState(() {
        _files = result.paths.map((path) => File(path!)).toList();
      });
    } else {
      setState(() {
        _files = null;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: SizedBox(
              width: _widgetWidth,
              child: Button(
                onPressed: () {
                  pickFiles();
                },
                child: Padding(
                  padding: const EdgeInsets.symmetric(vertical: 12.0),
                  child: Text(
                    'Choose Files',
                    style: TextStyle(
                      fontSize: _buttonTextSize,
                    ),
                  ),
                ),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 12.0),
            child: SizedBox(
              width: _widgetWidth,
              child: Button(
                onPressed: () async {
                  await EnigmaTest().encrypt(_files!);
                },
                child: Padding(
                  padding: const EdgeInsets.symmetric(vertical: 12.0),
                  child: Text(
                    'Encrypt',
                    style: TextStyle(
                      fontSize: _buttonTextSize,
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Here is the relevant code for enigma_test.dart :

import 'dart:developer';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;

import 'package:encrypt/encrypt.dart';

class EnigmaTest {
  Future<void> encrypt(List<File> files) async {
    const String keyAsString = '123';
    final String encryptedPath = p.join(await _localPath, 'encrypted');
    final Key key = Key.fromUtf8(keyAsString.padRight(32, ' '));

    try {
      for (File file in files) {
        final contents = await file.readAsLines();
        // getting the name of the file without the extension
        final filename = p.basename(file.path);

        File encrypedFile =
            await File(p.join(encryptedPath, filename)).create(recursive: true);

        var sink = encrypedFile.openWrite();

        for (String line in contents) {
          if (line == '') {
            sink.writeln();
          } else {
            var encryptedLine = _aesEncryption(line, key);
            sink.writeln(encryptedLine);
          }
        }

        await sink.flush();
        await sink.close();
      }
    } catch (e) {
      //somethibng
      inspect(e);
    }
  }

  String _aesEncryption(String line, Key key) {
    final iv = IV.fromLength(16);
    final encrypter = Encrypter(AES(key));
    final encrypted = encrypter.encrypt(line, iv: iv);
    return encrypted.base16;
  }

  Future<String> get _localPath async {
    final documentsDirectory = await getApplicationDocumentsDirectory();
    final encyptedFilesDirectory =
        p.join(documentsDirectory.path, "Dead Man's Enigma Output");

    return encyptedFilesDirectory;
  }
}

Here is the code for loading_alert_dialog.dart :

import 'package:fluent_ui/fluent_ui.dart';

class MyLoadingAlertDialog {
  static showLoadingAlert(
      BuildContext context, String filename, double progress) {
    showDialog(
      context: context,
      builder: (context) {
        return ContentDialog(
          title: const Text('Progress'),
          content: Column(
            children: [
              SizedBox(
                width: double.infinity,
                child: ProgressBar(value: progress, strokeWidth: 8),
              ),
              Padding(
                padding: const EdgeInsets.all(4.0),
                child: Text(
                  'currently encrypting $filename...',
                  style: const TextStyle(
                      fontSize: 10.0, fontStyle: FontStyle.italic),
                ),
              ),
            ],
          ),
        );
      },
    );
  }
}

Well, that looks like a job for a simple state management solution; the simplest one you could go would be Provider and using something as simple as a ValueNotifier and a ValueListenableBuilder , that way you can have the main class trigger notifications to another class (in your case, the dialog) via the ValueNotifier .

I did a simple example of how this would play out in a Gist . Run it through DartPad and see how it works.

Pretty much is creating a provided service FileProcessingService that serves as the inter-widget communication. The MainPageTest class picks the files, launches the encryption logic ( EnigmaTest ) as well as the dialog MyLoadingAlertDialog ; the EnigmaTest , as it processes each file, sends notifications via a ValueNotifier of type String representing the current file being processed, while the MyLoadingAlertDialog has a ValueListenableBuilder widget listening on that ValueNotifier and updating accordingly, all via the FileProcessingService provided service.

Check out the bottom animation of when you run the Gist on DartPad and how the communication goes. Hope this works for your purposes.

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM