mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-02 01:29:42 -06:00
[client] Unified list of all actions
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
},
|
||||
@@ -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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user