Skip to content

Commit

Permalink
Refactor cancelable task logic
Browse files Browse the repository at this point in the history
  • Loading branch information
amake committed Sep 14, 2024
1 parent 323cc5c commit bf6de81
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 46 deletions.
42 changes: 42 additions & 0 deletions lib/src/components/dialogs.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:org_flutter/org_flutter.dart';
import 'package:orgro/src/debug.dart';
import 'package:orgro/src/preferences.dart';
import 'package:orgro/src/serialization.dart';
import 'package:share_plus/share_plus.dart';
Expand Down Expand Up @@ -164,6 +165,47 @@ class InputPasswordDialog extends StatelessWidget {
}
}

Future<({bool succeeded, T? result})> cancelableProgressTask<T>(
BuildContext context, {
required Future<T> task,
required String dialogTitle,
}) async {
var canceled = false;

final dialogFuture = showDialog<(T, Object?)>(
context: context,
builder: (context) => ProgressIndicatorDialog(
title: dialogTitle,
dismissable: true,
),
);

task.then((result) {
if (!canceled && context.mounted) Navigator.pop(context, (result, null));
}).onError((error, stackTrace) {
if (context.mounted) showErrorSnackBar(context, error);
logError(error, stackTrace);
if (!canceled && context.mounted) Navigator.pop(context, (null, error));
});

// Popped will be one of:
// - null if the user closed the dialog by tapping outside or using the back
// button/gesture
// - (task result, null) if completed normally
// - (null, error) if completed with error
final popped = await dialogFuture;

if (popped == null) {
canceled = true;
return (succeeded: false, result: null);
}

final (result, error) = popped;
return error == null
? (succeeded: true, result: result)
: (succeeded: false, result: null);
}

class ProgressIndicatorDialog extends StatelessWidget {
const ProgressIndicatorDialog({
required this.title,
Expand Down
28 changes: 7 additions & 21 deletions lib/src/pages/document/encryption.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,14 @@ extension EncryptionHandler on DocumentPageState {
);
if (password == null) return;
if (!mounted) return;
var canceled = false;
time('decrypt', () => compute(decrypt, (blocks, password)))
.then((decrypted) {
if (!canceled && mounted) Navigator.pop(context, decrypted);
}).onError((error, stackTrace) {
if (mounted) showErrorSnackBar(context, error);
logError(error, stackTrace);
if (!canceled && mounted) Navigator.pop(context);
});
final result = await showDialog<List<String?>>(
context: context,
builder: (context) => ProgressIndicatorDialog(
title: AppLocalizations.of(context)!.decryptingProgressDialogTitle,
dismissable: true,
),

final (succeeded: succeeded, result: result) = await cancelableProgressTask(
context,
task: time('decrypt', () => compute(decrypt, (blocks, password))),
dialogTitle: AppLocalizations.of(context)!.decryptingProgressDialogTitle,
);
if (!mounted) return;
if (result == null) {
// Canceled
canceled = true;
return;
}
if (!succeeded || result == null) return;

OrgTree newDoc = doc;
final toRemember = <OrgroPassword>[];
for (final (i, cleartext) in result.indexed) {
Expand Down
38 changes: 13 additions & 25 deletions lib/src/pages/document/links.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,39 +61,27 @@ extension LinkHandler on DocumentPageState {
final targetId = parseOrgIdUrl(url);
final requestId = Object().hashCode.toString();

var canceled = false;
time(
'find file with ID',
() => findFileForId(
requestId: requestId,
orgId: targetId,
dirIdentifier: dataSource.rootDirIdentifier!,
),
).then((found) {
if (!canceled && mounted) Navigator.pop(context, (found, true));
}).onError((error, stackTrace) {
if (mounted) showErrorSnackBar(context, error);
logError(error, stackTrace);
if (!canceled && mounted) Navigator.pop(context);
});

final result = await showDialog<(NativeDataSource?, bool)>(
context: context,
builder: (context) => ProgressIndicatorDialog(
title: AppLocalizations.of(context)!.searchingProgressDialogTitle,
dismissable: true,
final (succeeded: succeeded, result: foundFile) =
await cancelableProgressTask(
context,
task: time(
'find file with ID',
() => findFileForId(
requestId: requestId,
orgId: targetId,
dirIdentifier: dataSource.rootDirIdentifier!,
),
),
dialogTitle: AppLocalizations.of(context)!.searchingProgressDialogTitle,
);

if (result == null) {
canceled = true;
if (!succeeded) {
cancelFindFileForId(requestId: requestId);
return false;
}

if (!mounted) return false;

final (foundFile, searchCompleted) = result;
assert(searchCompleted);
if (foundFile == null) {
showErrorSnackBar(context,
AppLocalizations.of(context)!.errorExternalIdNotFound(targetId));
Expand Down

0 comments on commit bf6de81

Please sign in to comment.