[client] Show failed actions

This commit is contained in:
Abhishek Shroff
2024-09-30 11:04:31 +05:30
parent 9692ec6957
commit 9ca9d50eaa
8 changed files with 75 additions and 27 deletions
+15 -3
View File
@@ -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
+1 -1
View File
@@ -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(
-4
View File
@@ -157,10 +157,6 @@ class $ResourcesTable extends Resources
@override
Set<GeneratedColumn> get $primaryKey => {id};
@override
List<Set<GeneratedColumn>> get uniqueKeys => [
{parent, name},
];
@override
Resource map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
return Resource(
+4 -4
View File
@@ -15,8 +15,8 @@ class Resources extends Table {
@override
Set<Column> get primaryKey => {id};
@override
List<Set<Column<Object>>>? get uniqueKeys => [
{parent, name}
];
// @override
// List<Set<Column<Object>>>? get uniqueKeys => [
// {parent, name}
// ];
}
@@ -6,32 +6,39 @@ import 'package:provider/provider.dart';
import 'package:state_notifier/state_notifier.dart';
class ActionQueueStatusNotifier extends ChangeNotifier {
final Map<StateNotifier<ActionStatus>, RemoveListener> _listeners = {};
final Map<StateNotifier<ActionStatus>, ActionStatus> _statusMap = {};
final Map<QueuedAction<PhylumAccount>, RemoveListener> _listeners = {};
final Map<QueuedAction<PhylumAccount>, ActionStatus> _statusMap = {};
List<QueuedAction<PhylumAccount>>? last;
late final RemoveListener removeListenerCallback;
bool paused = false;
bool unreachable = false;
int get submitting => _count<ActionStatusUploading>();
int get error => _count<ActionStatusError>();
int get submittingCount => _count<ActionStatusUploading>();
int get errorCount => _count<ActionStatusError>();
int _count<T extends ActionStatus>() => _statusMap.values.fold(0, (acc, status) => status is T ? acc + 1 : acc);
List<QueuedAction<PhylumAccount>>? _failedActions;
List<QueuedAction<PhylumAccount>> 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<PhylumActionQueue>().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();
+2 -2
View File
@@ -43,8 +43,8 @@ class _ServerStatusButtonState extends State<ServerStatusButton> {
final notifier = context.watch<ActionQueueStatusNotifier>();
_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),
+31
View File
@@ -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<ActionQueueStatusNotifier, List<QueuedAction<PhylumAccount>>>((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,
),
);
}
}
+3 -1
View File
@@ -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()],
);
}