Skip to content

Commit 713b018

Browse files
committed
fixed an issue that would cause the application to freeze if encryption takes a while
1 parent 45ef088 commit 713b018

File tree

4 files changed

+51
-12
lines changed

4 files changed

+51
-12
lines changed

lib/services/file_upload.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import 'dart:async';
1919
import 'database.dart';
2020

2121
typedef OnUploadProgressCallback = void Function(int sentBytes, int totalBytes);
22+
typedef IsEncryptingCallback = void Function(bool isEncrypting);
2223

2324
class CustomFtpUploadResult {
2425
final bool success;
@@ -107,6 +108,7 @@ class FileService {
107108
static Future<String?> fileUploadMultiPart({
108109
required File file,
109110
required OnUploadProgressCallback setOnUploadProgress,
111+
required IsEncryptingCallback setOnEncrypting,
110112
required BuildContext context,
111113
}) async {
112114
// Fetch selected uploader
@@ -125,7 +127,7 @@ class FileService {
125127
if(uploader != null) {
126128
try {
127129
String mimeType = lookupMimeType(file.path) ?? 'application/octet-stream';
128-
FormData formData = await _buildFormData(uploader, file, mimeType);
130+
FormData formData = await _buildFormData(uploader, file, mimeType, setOnEncrypting);
129131
Map<String, String> headers = await _getHeaders(uploader);
130132

131133
return await _uploadFile(
@@ -159,6 +161,7 @@ class FileService {
159161
final encryptedStream = encryptPgpStream(
160162
file.openRead(),
161163
networkUploader.pgpPublicKey,
164+
setOnEncrypting
162165
);
163166

164167
final encryptedSize = networkUploader.pgpPublicKey != null
@@ -233,9 +236,9 @@ class FileService {
233236
};
234237
}
235238

236-
static Future<FormData> _buildFormData(Share uploader, File file, String mimeType) async {
239+
static Future<FormData> _buildFormData(Share uploader, File file, String mimeType, IsEncryptingCallback setOnEncrypting) async {
237240
Uint8List bytes = await file.readAsBytes();
238-
bytes = await encryptPgpBytes(bytes, uploader.pgpPublicKey);
241+
bytes = await encryptPgpBytes(bytes, uploader.pgpPublicKey, setOnEncrypting);
239242

240243
final filename = uploader.pgpPublicKey != null
241244
? "${file.path.split("/").last}.asc"

lib/services/pgp_service.dart

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'dart:io';
33
import 'dart:typed_data';
44

55
import 'package:file_picker/file_picker.dart';
6+
import 'package:flutter/foundation.dart';
67
import 'package:flutter/material.dart';
78
import 'package:dart_pg/dart_pg.dart';
89

@@ -116,34 +117,58 @@ Future<void> _offerPrivateKeyExport(BuildContext context, String privateKey, Str
116117
Future<Uint8List> encryptPgpBytes(
117118
Uint8List data,
118119
String? armoredPublicKey,
120+
void Function(bool isEncrypting) isEncrypting
119121
) async {
120122
if (armoredPublicKey == null || armoredPublicKey.isEmpty) {
121123
return data;
122124
}
123125

124-
final publicKey = OpenPGP.readPublicKey(armoredPublicKey);
125-
final encrypted = OpenPGP.encryptBinaryData(data, encryptionKeys: [publicKey]);
126-
final armored = encrypted.armor();
127-
return Uint8List.fromList(utf8.encode(armored));
126+
// Offload to background isolate
127+
isEncrypting.call(true);
128+
final result = await compute(_encryptPgpBytesIsolate, {
129+
'data': data,
130+
'publicKey': armoredPublicKey,
131+
});
132+
isEncrypting.call(false);
133+
return result;
128134
}
129135

130136
Stream<List<int>> encryptPgpStream(
131137
Stream<List<int>> data,
132138
String? armoredPublicKey,
139+
void Function(bool isEncrypting) isEncrypting
133140
) async* {
134141
if (armoredPublicKey == null || armoredPublicKey.isEmpty) {
135142
yield* data;
136143
return;
137144
}
138145

146+
// Collect all chunks into a single Uint8List
139147
final buffer = BytesBuilder();
140148
await for (final chunk in data) {
141149
buffer.add(chunk);
142150
}
151+
final bytes = buffer.toBytes();
152+
153+
// Offload encryption to a background isolate
154+
isEncrypting.call(true);
155+
final Uint8List encryptedBytes = await compute(_encryptPgpBytesIsolate, {
156+
'data': bytes,
157+
'publicKey': armoredPublicKey,
158+
});
159+
isEncrypting.call(false);
160+
161+
// Yield the encrypted data as a single chunk
162+
yield encryptedBytes;
163+
}
164+
165+
Future<Uint8List> _encryptPgpBytesIsolate(Map<String, dynamic> args) async {
166+
final Uint8List data = args['data'];
167+
final String armoredPublicKey = args['publicKey'];
143168

144169
final publicKey = OpenPGP.readPublicKey(armoredPublicKey);
145-
final encrypted = OpenPGP.encryptBinaryData(buffer.toBytes(), encryptionKeys: [publicKey]);
170+
final encrypted = OpenPGP.encryptBinaryData(data, encryptionKeys: [publicKey]);
146171
final armored = encrypted.armor();
147-
yield* Stream.fromIterable([utf8.encode(armored)]);
148-
return;
172+
173+
return Uint8List.fromList(utf8.encode(armored));
149174
}

lib/views/components/add_uploader_simple.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ class SimpleViewState extends State<SimpleView> {
222222
onPressed: () async {
223223
final result = await FilePicker.platform.pickFiles(
224224
type: FileType.custom,
225-
allowedExtensions: ['asc', 'pgp', 'txt']
225+
allowedExtensions: ['asc', 'pgp', 'txt', 'key']
226226
);
227227
final key = await importPgpKeyFromFile(result, context);
228228
_pgpKeyController.text = key!.trim();

lib/views/home_page.dart

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
3333
String _fileName = "";
3434
double _progressPercentValue = 0;
3535
bool _hasBeenPressed = false;
36+
bool _isEncrypting = false;
3637
final List<String> _uploadedUrls = [];
3738

3839
void _setUploadProgress(int sentBytes, int totalBytes) {
@@ -98,6 +99,11 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
9899
file: uploadFile,
99100
setOnUploadProgress: _setUploadProgress,
100101
context: context,
102+
setOnEncrypting: (isEncrypting) {
103+
setState(() {
104+
_isEncrypting = isEncrypting;
105+
});
106+
},
101107
);
102108

103109
if (value[i].type == SharedMediaType.TEXT && await uploadFile.exists()) {
@@ -236,6 +242,11 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
236242
file: file,
237243
setOnUploadProgress: _setUploadProgress,
238244
context: context,
245+
setOnEncrypting: (isEncrypting) {
246+
setState(() {
247+
_isEncrypting = isEncrypting;
248+
});
249+
}
239250
);
240251

241252
if (url != null) {
@@ -271,7 +282,7 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
271282
textStyle: const TextStyle(fontSize: 20),
272283
),
273284
child: _hasBeenPressed
274-
? Text(AppLocalizations.of(context)!.uploading)
285+
? Text(_isEncrypting ? "Encrypting...": AppLocalizations.of(context)!.uploading)
275286
: Text(AppLocalizations.of(context)!.choose_files),
276287
),
277288
progressColor: Colors.green[400],

0 commit comments

Comments
 (0)