mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-06 08:30:29 +00:00
fix(flutter): drop action buttons from error notifications
A failed download has no usable output file, so error notifications now carry no buttons at all; only the done event offers open file / open folder actions.
This commit is contained in:
1 parent
6f4635e2eb
commit
014221a1a7
2 files changed
+23
-34
No files matched your search
@@ -27,10 +27,10 @@ const _openFileAction = 'open_file';
|
||||
const _openFolderAction = 'open_folder';
|
||||
|
||||
// macOS resolves buttons through pre-registered notification categories, one
|
||||
// per action combination a terminal task event can offer.
|
||||
// per action combination a done task event can offer. Error notifications
|
||||
// carry no buttons at all.
|
||||
const _categoryDoneSingleFile = 'taskDoneSingleFile';
|
||||
const _categoryDoneFolder = 'taskDoneFolder';
|
||||
const _categoryTaskError = 'taskTaskError';
|
||||
|
||||
/// A notification button resolved for one task event.
|
||||
///
|
||||
@@ -105,7 +105,6 @@ class AppNotificationController extends AsyncNotifier<AppNotificationState> {
|
||||
notificationCategories: [
|
||||
DarwinNotificationCategory(_categoryDoneSingleFile, actions: [openFileAction, openFolderAction]),
|
||||
DarwinNotificationCategory(_categoryDoneFolder, actions: [openFolderAction]),
|
||||
DarwinNotificationCategory(_categoryTaskError, actions: [openFolderAction]),
|
||||
],
|
||||
);
|
||||
final linux = LinuxInitializationSettings(
|
||||
@@ -164,16 +163,16 @@ class AppNotificationController extends AsyncNotifier<AppNotificationState> {
|
||||
title: locale.notificationTaskDone,
|
||||
body: event.name,
|
||||
taskId: event.taskId,
|
||||
allowOpenFile: true,
|
||||
withActions: true,
|
||||
);
|
||||
case TaskEventType.error:
|
||||
// A failed download has no usable output to open, so no buttons.
|
||||
await _showNotification(
|
||||
locale: locale,
|
||||
title: locale.notificationTaskError,
|
||||
body: event.name,
|
||||
taskId: event.taskId,
|
||||
// A failed download rarely has a usable output file to open.
|
||||
allowOpenFile: false,
|
||||
withActions: false,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -184,17 +183,16 @@ class AppNotificationController extends AsyncNotifier<AppNotificationState> {
|
||||
required String title,
|
||||
required String body,
|
||||
required String taskId,
|
||||
required bool allowOpenFile,
|
||||
required bool withActions,
|
||||
}) async {
|
||||
final target = await resolveTaskTarget(taskId, allowOpenFile: allowOpenFile);
|
||||
final target = withActions ? await resolveTaskTarget(taskId) : null;
|
||||
final payload = target == null ? '' : jsonEncode({'path': target.path});
|
||||
final details = NotificationDetails(
|
||||
macOS: DarwinNotificationDetails(
|
||||
categoryIdentifier: switch (target) {
|
||||
null => null,
|
||||
_ when target.canOpenFile => _categoryDoneSingleFile,
|
||||
_ when allowOpenFile => _categoryDoneFolder,
|
||||
_ => _categoryTaskError,
|
||||
_ => _categoryDoneFolder,
|
||||
},
|
||||
),
|
||||
linux: LinuxNotificationDetails(
|
||||
@@ -216,19 +214,16 @@ class AppNotificationController extends AsyncNotifier<AppNotificationState> {
|
||||
await _plugin.show(id: _notificationId++, title: title, body: body, notificationDetails: details, payload: payload);
|
||||
}
|
||||
|
||||
/// Resolves the download target a terminal task event points at, following
|
||||
/// the same rule as the task details page: only single-file tasks offer
|
||||
/// "open file", folder tasks (e.g. multi-file torrents) can only reveal the
|
||||
/// Resolves the download target a done task event points at, following the
|
||||
/// same rule as the task details page: only single-file tasks offer "open
|
||||
/// file", folder tasks (e.g. multi-file torrents) can only reveal the
|
||||
/// folder. Returns null when the task is already gone.
|
||||
@visibleForTesting
|
||||
Future<({String path, bool canOpenFile})?> resolveTaskTarget(
|
||||
String taskId, {
|
||||
required bool allowOpenFile,
|
||||
}) async {
|
||||
Future<({String path, bool canOpenFile})?> resolveTaskTarget(String taskId) async {
|
||||
final apiTask = await findTask(taskId);
|
||||
if (apiTask == null) return null;
|
||||
final record = TaskRecord.fromApi(apiTask);
|
||||
return (path: record.storagePath, canOpenFile: allowOpenFile && !record.isFolder);
|
||||
return (path: record.storagePath, canOpenFile: !record.isFolder);
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
|
||||
@@ -122,12 +122,12 @@ void main() {
|
||||
expect(calls.where((call) => call.method == 'show'), hasLength(2));
|
||||
});
|
||||
|
||||
test('macOS registers action categories for every terminal event combination', () async {
|
||||
test('macOS registers action categories for done task combinations', () async {
|
||||
await start(enabled: true);
|
||||
|
||||
final categories = initialization()['notificationCategories'] as List<dynamic>;
|
||||
final identifiers = categories.map((category) => (category as Map)['identifier']).toList();
|
||||
expect(identifiers, containsAll(['taskDoneSingleFile', 'taskDoneFolder', 'taskTaskError']));
|
||||
expect(identifiers, ['taskDoneSingleFile', 'taskDoneFolder']);
|
||||
final singleFile = categories.firstWhere((c) => c['identifier'] == 'taskDoneSingleFile') as Map;
|
||||
final singleActions = (singleFile['actions'] as List).cast<Map>();
|
||||
expect(singleActions.map((action) => action['identifier']), ['open_file', 'open_folder']);
|
||||
@@ -138,7 +138,7 @@ void main() {
|
||||
final container = await start(enabled: true);
|
||||
final notifier = container.read(appNotificationControllerProvider.notifier) as _TestNotificationController;
|
||||
|
||||
final target = await notifier.resolveTaskTarget('single', allowOpenFile: true);
|
||||
final target = await notifier.resolveTaskTarget('single');
|
||||
|
||||
expect(target?.path, '/downloads/archive.zip');
|
||||
expect(target?.canOpenFile, isTrue);
|
||||
@@ -148,21 +148,12 @@ void main() {
|
||||
final container = await start(enabled: true);
|
||||
final notifier = container.read(appNotificationControllerProvider.notifier) as _TestNotificationController;
|
||||
|
||||
final target = await notifier.resolveTaskTarget('folder', allowOpenFile: true);
|
||||
final target = await notifier.resolveTaskTarget('folder');
|
||||
|
||||
expect(target?.path, '/downloads/torrent-bundle');
|
||||
expect(target?.canOpenFile, isFalse);
|
||||
});
|
||||
|
||||
test('an errored task never resolves an open-file target', () async {
|
||||
final container = await start(enabled: true);
|
||||
final notifier = container.read(appNotificationControllerProvider.notifier) as _TestNotificationController;
|
||||
|
||||
final target = await notifier.resolveTaskTarget('single', allowOpenFile: false);
|
||||
|
||||
expect(target?.canOpenFile, isFalse);
|
||||
});
|
||||
|
||||
test('a done single-file task notification selects the single-file category and payload path', () async {
|
||||
await start(enabled: true);
|
||||
events.add(const TaskEvent(type: TaskEventType.done, taskId: 'single', name: 'archive.zip'));
|
||||
@@ -184,13 +175,16 @@ void main() {
|
||||
expect(platformSpecifics['categoryIdentifier'], 'taskDoneFolder');
|
||||
});
|
||||
|
||||
test('an errored task notification selects the error category', () async {
|
||||
test('an errored task notification carries no actions at all', () async {
|
||||
await start(enabled: true);
|
||||
events.add(const TaskEvent(type: TaskEventType.error, taskId: 'single', name: 'archive.zip'));
|
||||
await Future<void>.delayed(Duration.zero);
|
||||
|
||||
final platformSpecifics = shownNotifications()[0]['platformSpecifics'] as Map<dynamic, dynamic>;
|
||||
expect(platformSpecifics['categoryIdentifier'], 'taskTaskError');
|
||||
final notifications = shownNotifications();
|
||||
expect(notifications, hasLength(1));
|
||||
final platformSpecifics = notifications[0]['platformSpecifics'] as Map<dynamic, dynamic>;
|
||||
expect(platformSpecifics['categoryIdentifier'], isNull);
|
||||
expect(notifications[0]['payload'], '');
|
||||
});
|
||||
|
||||
test('action responses route to file and folder handlers by encoded spec', () async {
|
||||
|
||||
Reference in new issue
Block a user