Issue
In my app I am using a Bottom Sheet with few widgets on it. It look like this:
When user clicks on My Documents I am calling a saveToMyDocs function which will check if 'enable password' switch is on, it will encrypt the pdf file with the password provided and if 'create zip file' switch is enabled, it will then create a zip of the encrypted file. Here is my 'saveToMyDocs' function:
Future saveToMyDocs(BuildContext context, bool savePDF, bool encrypt, String password, bool zip, String sourceFile, String fileName) async {
ProgressDialog pd = ProgressDialog(context: context);
pd.show(max: 100, msg: "Saving file\nPlease wait...", progressBgColor: Color.fromARGB(255, 224, 224, 224), progressValueColor: Color.fromARGB(255, 2, 136, 209));
String sourceFilePath = sourceFile;
Directory appDocDir = await getApplicationDocumentsDirectory();
String tempPath = appDocDir.path;
var now = DateTime.now();
String name = now.day.toString() + now.month.toString() + now.year.toString() + now.hour.toString() + now.minute.toString() + now.second.toString();
String tempFilePath = tempPath + "/" + name;
String destinationFilePath = await ExternalPath.getExternalStoragePublicDirectory(ExternalPath.DIRECTORY_DOCUMENTS);
if (savePDF) {
if (encrypt) {
final PdfDocument document = PdfDocument(inputBytes: File(sourceFilePath).readAsBytesSync());
final PdfSecurity security = document.security;
security.userPassword = password;
security.ownerPassword = password;
security.algorithm = PdfEncryptionAlgorithm.aesx256Bit;
await File(tempFilePath + ".pdf").writeAsBytes(document.save());
document.dispose();
sourceFilePath = tempFilePath + ".pdf";
}
if (zip) {
var encoder = ZipFileEncoder();
encoder.create(tempFilePath + ".zip");
encoder.addFile(File(sourceFilePath));
encoder.close();
sourceFilePath = tempFilePath + ".zip";
}
try {
if (sourceFilePath.endsWith(".pdf")) {
await File(sourceFilePath).rename(destinationFilePath + "/" + fileName + ".pdf");
}
else {
await File(sourceFilePath).rename(destinationFilePath + "/" + fileName + ".zip");
}
} on FileSystemException catch (e) {
if (sourceFilePath.endsWith(".pdf")) {
final newFile = await File(sourceFilePath).copy(destinationFilePath + "/" + fileName + ".pdf");
await File(sourceFilePath).delete();
}
else {
final newFile = await File(sourceFilePath).copy(destinationFilePath + "/" + fileName + ".zip");
await File(sourceFilePath).delete();
}
}
if(pd.isOpen()) {
pd.close();
}
}
}
This all works fine, but the problem is, if any of the switches ('enable password' or 'create zip') is enabled then the app stucks. It means if any of these switches is enabled and if I click on 'My Documents' which calls 'saveToMyDocs' then that progress dialog does not appear and I can't interact with my bottom sheet or any elements either. The progress dialog shows up after a long time and just for a second and then closes suddenly. The encryption and creating zip file is carried out without any error but the whole app stucks (freezes) is the problem. The problem won't arise if both of these switches are off. And there is no warning or error message either.
In simple words if the whole saving process takes n seconds then my app will freeze for ~(n-1)seconds and then in the last 1 second the progress dialog will open and close instantly.
If create zip file and enable password is not enabled then it works smoothly. What could be the problem.
Any help would be much appreciated. Thank you.
Solution
The actual problem here is
document.save() in line
await File(tempPath + "/" + fileName + ".pdf").writeAsBytes(document.save());
If you try to write it separately it'll be list of bytes. Meaning your input file is converted in bytes into the memory and not in a file in storage which is the reason while your ui freezes. I guess something similar is happening for the zip as well. As of now I don't think there is any solution to this because for the bytes to be saved in storage instead would take time and major portion of the library has to be written again.
For creating zip files you can use "flutter_archive" instead. Just add:
dependencies:
flutter_archive: ^4.1.1
in your pubsec.yaml and then run pub get and now you can import it like this:
import 'package:flutter_archive/flutter_archive.dart';
And to create zip file you can use the following code:
final sourceDir = Directory("source_dir");
final files = [
File(sourceDir.path + "file1"),
File(sourceDir.path + "file2")
];
final zipFile = File("zip_file_path");
try {
await ZipFile.createFromFiles(
sourceDir: sourceDir, files: files, zipFile: zipFile);
} catch (e) {
print(e);
}
Here first line takes a directory in which all the files to be archived are present.
NOTE: All files should be present in the same directory.
After that files = []; takes list of files to be added to the archive.
And finally final zipFile = File("zip_file_path"); is the place where your archive will be stored.
If you want you can read more about this package on its official page https://pub.dev/packages/flutter_archive
For the encryption part I will try to come up for a solution as soon as possible.
Answered By - Handsome Hunk
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.