Reputation: 141
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),
),
),
],
),
);
},
);
}
}
Upvotes: 0
Views: 53
Reputation: 2779
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.
Upvotes: 1