From 9ca9d50eaa240ffb50073e303742983c7e88fff3 Mon Sep 17 00:00:00 2001 From: Abhishek Shroff Date: Mon, 30 Sep 2024 11:04:31 +0530 Subject: [PATCH] [client] Show failed actions --- README.md | 18 +++++++++-- client/lib/libphylum/db/db.dart | 2 +- client/lib/libphylum/db/db.g.dart | 4 --- client/lib/libphylum/db/resources.dart | 8 ++--- .../ui/app/action_queue_status_notifier.dart | 31 ++++++++++++------- client/lib/ui/app/button_server_status.dart | 4 +-- client/lib/ui/sync/sliver_errors.dart | 31 +++++++++++++++++++ client/lib/ui/sync/sync_dialog.dart | 4 ++- 8 files changed, 75 insertions(+), 27 deletions(-) create mode 100644 client/lib/ui/sync/sliver_errors.dart diff --git a/README.md b/README.md index 8784500d..e0e771db 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,22 @@ Self-hosted cloud file storage [ ] Thumbnails [ ] Sync Manager [x] View List of pending actions - [ ] Retry / Edit / Delete failed actions - [ ] Retry / Edit / Delete failed downloads - [ ] View in-progress downloads + [x] View failed actions + [ ] Actions for failed actions + [x] Delete + [x] Retry + [ ] Edit + [x] View in-progress downloads [ ] View transfer rate and ETA + [ ] View finished downloads (in current session) + [ ] Actions for completed downloads + [ ] Open + [ ] Open Folder + [ ] Actions for failed downloads + [ ] Delete + [ ] Retry + [ ] Edit + [ ] View all past downloads [ ] Public access [ ] Download files [ ] View folders diff --git a/client/lib/libphylum/db/db.dart b/client/lib/libphylum/db/db.dart index 02597837..9fc91bf6 100644 --- a/client/lib/libphylum/db/db.dart +++ b/client/lib/libphylum/db/db.dart @@ -16,7 +16,7 @@ class AppDatabase extends _$AppDatabase { AppDatabase({required this.id}) : super(_openConnection(id)); @override - int get schemaVersion => 5; + int get schemaVersion => 6; @override MigrationStrategy get migration => MigrationStrategy( diff --git a/client/lib/libphylum/db/db.g.dart b/client/lib/libphylum/db/db.g.dart index 277c9fec..e8ab1cda 100644 --- a/client/lib/libphylum/db/db.g.dart +++ b/client/lib/libphylum/db/db.g.dart @@ -157,10 +157,6 @@ class $ResourcesTable extends Resources @override Set get $primaryKey => {id}; @override - List> get uniqueKeys => [ - {parent, name}, - ]; - @override Resource map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return Resource( diff --git a/client/lib/libphylum/db/resources.dart b/client/lib/libphylum/db/resources.dart index 59bd8240..1a05bc2a 100644 --- a/client/lib/libphylum/db/resources.dart +++ b/client/lib/libphylum/db/resources.dart @@ -15,8 +15,8 @@ class Resources extends Table { @override Set get primaryKey => {id}; - @override - List>>? get uniqueKeys => [ - {parent, name} - ]; + // @override + // List>>? get uniqueKeys => [ + // {parent, name} + // ]; } diff --git a/client/lib/ui/app/action_queue_status_notifier.dart b/client/lib/ui/app/action_queue_status_notifier.dart index 58b9d112..63570d08 100644 --- a/client/lib/ui/app/action_queue_status_notifier.dart +++ b/client/lib/ui/app/action_queue_status_notifier.dart @@ -6,32 +6,39 @@ import 'package:provider/provider.dart'; import 'package:state_notifier/state_notifier.dart'; class ActionQueueStatusNotifier extends ChangeNotifier { - final Map, RemoveListener> _listeners = {}; - final Map, ActionStatus> _statusMap = {}; + final Map, RemoveListener> _listeners = {}; + final Map, ActionStatus> _statusMap = {}; List>? last; late final RemoveListener removeListenerCallback; bool paused = false; bool unreachable = false; - int get submitting => _count(); - int get error => _count(); + int get submittingCount => _count(); + int get errorCount => _count(); int _count() => _statusMap.values.fold(0, (acc, status) => status is T ? acc + 1 : acc); + List>? _failedActions; + List> get failedActions { + _failedActions ??= List.of(_statusMap.entries.where((e) => e.value is ActionStatusError).map((e) => e.key), growable: false); + return _failedActions!; + } ActionQueueStatusNotifier(BuildContext context) { removeListenerCallback = context.read().addListener((state) { if (state.actions != last) { for (final action in state.actions) { - final notifier = action.statusNotifier; - if (!_listeners.containsKey(notifier)) { - _listeners[notifier] = notifier.addListener((status) { + if (!_listeners.containsKey(action)) { + _listeners[action] = action.statusNotifier.addListener((status) { // Ignore progress updates - if (_statusMap[notifier].runtimeType != status.runtimeType) { - _statusMap[notifier] = status; + if (_statusMap[action].runtimeType != status.runtimeType) { + if (status is ActionStatusError || _statusMap[action] is ActionStatusError) { + _failedActions = null; + } + _statusMap[action] = status; if (status is ActionStatusDone) { Future.microtask(() { - _listeners[notifier]?.call(); - _listeners.remove(notifier); - _statusMap.remove(notifier); + _listeners[action]?.call(); + _listeners.remove(action); + _statusMap.remove(action); }); } notifyListeners(); diff --git a/client/lib/ui/app/button_server_status.dart b/client/lib/ui/app/button_server_status.dart index 6c0cd075..3918d59b 100644 --- a/client/lib/ui/app/button_server_status.dart +++ b/client/lib/ui/app/button_server_status.dart @@ -43,8 +43,8 @@ class _ServerStatusButtonState extends State { final notifier = context.watch(); _ServerStatus state = _ServerStatus.done; if (notifier.unreachable) state = _ServerStatus.unreachable; - if (notifier.error > 0) state = _ServerStatus.error; - if (notifier.submitting > 0) state = _ServerStatus.syncing; + if (notifier.errorCount > 0) state = _ServerStatus.error; + if (notifier.submittingCount > 0) state = _ServerStatus.syncing; if (notifier.paused) state = _ServerStatus.paused; return ListTile( leading: Icon(state.icon), diff --git a/client/lib/ui/sync/sliver_errors.dart b/client/lib/ui/sync/sliver_errors.dart new file mode 100644 index 00000000..a44ac963 --- /dev/null +++ b/client/lib/ui/sync/sliver_errors.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:offtheline/offtheline.dart'; +import 'package:phylum/libphylum/phylum_account.dart'; +import 'package:phylum/ui/app/action_queue_status_notifier.dart'; +import 'package:provider/provider.dart'; + +import 'action_view.dart'; + +class SliverErrors extends StatelessWidget { + const SliverErrors({super.key}); + + @override + Widget build(BuildContext context) { + final actions = context.select>>((state) { + final failedActions = state.failedActions; + return failedActions; + }); + + return SliverList( + delegate: SliverChildBuilderDelegate( + (context, i) { + if (i == 0) { + return const ListTile(dense: true, title: Text('Errors')); + } + return ActionView(action: actions[i - 1]); + }, + childCount: actions.isEmpty ? 0 : actions.length + 1, + ), + ); + } +} diff --git a/client/lib/ui/sync/sync_dialog.dart b/client/lib/ui/sync/sync_dialog.dart index 52c8cea5..c17788f3 100644 --- a/client/lib/ui/sync/sync_dialog.dart +++ b/client/lib/ui/sync/sync_dialog.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:phylum/ui/sync/sliver_uploads.dart'; import 'package:phylum/ui/sync/sliver_downloads.dart'; +import 'sliver_errors.dart'; + class SyncDialog extends StatelessWidget { const SyncDialog({super.key}); @@ -38,6 +40,6 @@ class SyncDialog extends StatelessWidget { } Widget buildContents(BuildContext context) => const CustomScrollView( - slivers: [DownloadsSliver(), SliverUploads()], + slivers: [DownloadsSliver(), SliverUploads(), SliverErrors()], ); }