[client] Unified list of all actions

This commit is contained in:
Abhishek Shroff
2024-12-11 22:46:58 +05:30
parent 7a64d70c86
commit 6a989ff18b
6 changed files with 33 additions and 129 deletions

View File

@@ -4,6 +4,14 @@ import 'package:phylum/libphylum/phylum_account.dart';
import 'package:phylum/libphylum/phylum_api_types.dart';
import 'package:state_notifier/state_notifier.dart';
const _order = {
ActionStatusDone: 0,
ActionStatusError: 1,
ActionStatusUploading: 2,
ActionStatusReady: 3,
ActionStatusWaiting: 4,
};
class ActionQueueStatusNotifier extends ChangeNotifier {
final Map<QueuedAction<PhylumAccount>, RemoveListener> _listeners = {};
final Map<QueuedAction<PhylumAccount>, ActionStatus> _statusMap = {};
@@ -16,28 +24,16 @@ class ActionQueueStatusNotifier extends ChangeNotifier {
int get errorCount => _count<ActionStatusError>();
int _count<T extends ActionStatus>() => _statusMap.values.fold(0, (acc, status) => status is T ? acc + 1 : acc);
final _statusActionsMap = <Type, List<QueuedAction<PhylumAccount>>>{};
List<QueuedAction<PhylumAccount>> _actionsByStatus(Type t) {
return _statusActionsMap.putIfAbsent(
t,
() => List.of(_statusMap.entries.where((e) => e.value.runtimeType == t).map((e) => e.key), growable: false),
);
}
List<QueuedAction<PhylumAccount>> get failedActions {
return _actionsByStatus(ActionStatusError);
}
List<QueuedAction<PhylumAccount>> get submittingActions {
return _actionsByStatus(ActionStatusUploading);
}
List<QueuedAction<PhylumAccount>> get readyActions {
return _actionsByStatus(ActionStatusReady);
}
List<QueuedAction<PhylumAccount>> get waitingActions {
return _actionsByStatus(ActionStatusWaiting);
List<QueuedAction<PhylumAccount>>? _orderedActions;
List<QueuedAction<PhylumAccount>> get orderedActions {
_orderedActions ??= List.of(_statusMap.keys, growable: false)
..sort((a, b) {
if (_statusMap[a] == _statusMap[b]) {
return a.id.compareTo(b.id);
}
return _order[_statusMap[a].runtimeType]! - _order[_statusMap[b].runtimeType]!;
});
return _orderedActions!;
}
ActionQueueStatusNotifier(PhylumActionQueue queue) {
@@ -48,15 +44,12 @@ class ActionQueueStatusNotifier extends ChangeNotifier {
_listeners[action] = action.statusNotifier.addListener((status) {
// Ignore progress updates
if (_statusMap[action].runtimeType != status.runtimeType) {
_statusActionsMap.remove(status.runtimeType);
_statusActionsMap.remove(_statusMap[action].runtimeType);
_statusMap[action] = status;
_orderedActions = null;
if (status is ActionStatusDone) {
Future.microtask(() {
_listeners[action]?.call();
_listeners.remove(action);
_statusMap.remove(action);
});
_listeners.remove(action)?.call();
_statusMap.remove(action);
} else {
_statusMap[action] = status;
}
notifyListeners();
}

View File

@@ -6,20 +6,20 @@ import 'package:provider/provider.dart';
import 'action_view.dart';
class SubmittingSliver extends StatelessWidget {
const SubmittingSliver({super.key});
class ActionsSliver extends StatelessWidget {
const ActionsSliver({super.key});
@override
Widget build(BuildContext context) {
final actions = context.select<ActionQueueStatusNotifier, List<QueuedAction<PhylumAccount>>>((state) {
return state.readyActions;
return state.orderedActions;
});
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, i) {
if (i == 0) {
return const ListTile(dense: true, title: Text('Ready'));
return const ListTile(dense: true, title: Text('Pending Updates'));
}
return ActionView(action: actions[i - 1]);
},

View File

@@ -1,31 +0,0 @@
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 ErrorsSliver extends StatelessWidget {
const ErrorsSliver({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,
),
);
}
}

View File

@@ -1,30 +0,0 @@
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 SubmittingSliver extends StatelessWidget {
const SubmittingSliver({super.key});
@override
Widget build(BuildContext context) {
final actions = context.select<ActionQueueStatusNotifier, List<QueuedAction<PhylumAccount>>>((state) {
return state.submittingActions;
});
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, i) {
if (i == 0) {
return const ListTile(dense: true, title: Text('Submitting'));
}
return ActionView(action: actions[i - 1]);
},
childCount: actions.isEmpty ? 0 : actions.length + 1,
),
);
}
}

View File

@@ -1,30 +0,0 @@
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 SubmittingSliver extends StatelessWidget {
const SubmittingSliver({super.key});
@override
Widget build(BuildContext context) {
final actions = context.select<ActionQueueStatusNotifier, List<QueuedAction<PhylumAccount>>>((state) {
return state.waitingActions;
});
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, i) {
if (i == 0) {
return const ListTile(dense: true, title: Text('Waiting'));
}
return ActionView(action: actions[i - 1]);
},
childCount: actions.isEmpty ? 0 : actions.length + 1,
),
);
}
}

View File

@@ -1,10 +1,8 @@
import 'package:flutter/material.dart';
import 'package:phylum/ui/sync/sliver_submitting.dart';
import 'package:phylum/ui/sync/sliver_offline.dart';
import 'package:phylum/ui/sync/sliver_uploads.dart';
import 'package:phylum/ui/sync/sliver_downloads.dart';
import 'sliver_errors.dart';
import 'sliver_actions.dart';
class SyncDialog extends StatelessWidget {
const SyncDialog({super.key});
@@ -42,6 +40,10 @@ class SyncDialog extends StatelessWidget {
}
Widget buildContents(BuildContext context) => const CustomScrollView(
slivers: [OfflineSliver(), DownloadsSliver(), ErrorsSliver(), UploadsSliver(), SubmittingSliver()],
slivers: [
OfflineSliver(),
DownloadsSliver(),
ActionsSliver(),
],
);
}