155 lines
4 KiB
Dart
155 lines
4 KiB
Dart
/// Coordinates Scheduler Command Controller state for the FocusFlow Flutter UI.
|
|
library;
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:scheduler_core/scheduler_core.dart';
|
|
|
|
typedef OperationContextFactory =
|
|
ApplicationOperationContext Function(String operationId);
|
|
|
|
typedef ReadRefresh = Future<void> Function();
|
|
|
|
sealed class SchedulerCommandState {
|
|
const SchedulerCommandState();
|
|
}
|
|
|
|
class SchedulerCommandIdle extends SchedulerCommandState {
|
|
const SchedulerCommandIdle();
|
|
}
|
|
|
|
class SchedulerCommandRunning extends SchedulerCommandState {
|
|
const SchedulerCommandRunning(this.label);
|
|
|
|
final String label;
|
|
}
|
|
|
|
class SchedulerCommandSuccess extends SchedulerCommandState {
|
|
const SchedulerCommandSuccess(this.message);
|
|
|
|
final String message;
|
|
}
|
|
|
|
class SchedulerCommandFailure extends SchedulerCommandState {
|
|
const SchedulerCommandFailure({this.failure, this.error});
|
|
|
|
final ApplicationFailure? failure;
|
|
final Object? error;
|
|
|
|
String get codeLabel {
|
|
final typed = failure;
|
|
if (typed != null) {
|
|
return typed.detailCode ?? typed.code.name;
|
|
}
|
|
return 'unexpected';
|
|
}
|
|
}
|
|
|
|
class SchedulerCommandController extends ChangeNotifier {
|
|
SchedulerCommandController({
|
|
required this.commands,
|
|
required this.contextFor,
|
|
required this.localDate,
|
|
required this.refreshReads,
|
|
});
|
|
|
|
final V1ApplicationCommandUseCases commands;
|
|
final OperationContextFactory contextFor;
|
|
final CivilDate localDate;
|
|
final ReadRefresh refreshReads;
|
|
var _sequence = 0;
|
|
SchedulerCommandState _state = const SchedulerCommandIdle();
|
|
|
|
SchedulerCommandState get state => _state;
|
|
|
|
Future<void> quickCaptureToBacklog(String title) async {
|
|
await _run(
|
|
label: 'Capturing task',
|
|
successMessage: 'Task captured',
|
|
refreshAfterSuccess: true,
|
|
action: (operationId) {
|
|
return commands.quickCaptureToBacklog(
|
|
context: contextFor(operationId),
|
|
title: title,
|
|
projectId: 'home',
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Future<void> scheduleBacklogItem({
|
|
required String taskId,
|
|
required int durationMinutes,
|
|
required DateTime expectedUpdatedAt,
|
|
}) async {
|
|
await _run(
|
|
label: 'Scheduling task',
|
|
successMessage: 'Task scheduled',
|
|
refreshAfterSuccess: true,
|
|
action: (operationId) {
|
|
return commands.scheduleBacklogItemToNextAvailableSlot(
|
|
context: contextFor(operationId),
|
|
localDate: localDate,
|
|
taskId: taskId,
|
|
durationMinutes: durationMinutes,
|
|
expectedUpdatedAt: expectedUpdatedAt,
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Future<void> completeFlexibleTask({
|
|
required String taskId,
|
|
DateTime? expectedUpdatedAt,
|
|
}) async {
|
|
await _run(
|
|
label: 'Completing task',
|
|
successMessage: 'Task completed',
|
|
refreshAfterSuccess: true,
|
|
action: (operationId) {
|
|
return commands.completeFlexibleTask(
|
|
context: contextFor(operationId),
|
|
localDate: localDate,
|
|
taskId: taskId,
|
|
expectedUpdatedAt: expectedUpdatedAt,
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Future<void> _run({
|
|
required String label,
|
|
required String successMessage,
|
|
required bool refreshAfterSuccess,
|
|
required Future<ApplicationResult<ApplicationCommandResult>> Function(
|
|
String operationId,
|
|
)
|
|
action,
|
|
}) async {
|
|
final operationId = _nextOperationId();
|
|
_setState(SchedulerCommandRunning(label));
|
|
try {
|
|
final result = await action(operationId);
|
|
final failure = result.failure;
|
|
if (failure != null) {
|
|
_setState(SchedulerCommandFailure(failure: failure));
|
|
return;
|
|
}
|
|
if (refreshAfterSuccess) {
|
|
await refreshReads();
|
|
}
|
|
_setState(SchedulerCommandSuccess(successMessage));
|
|
} on Object catch (error) {
|
|
_setState(SchedulerCommandFailure(error: error));
|
|
}
|
|
}
|
|
|
|
String _nextOperationId() {
|
|
_sequence += 1;
|
|
return 'ui-command-$_sequence';
|
|
}
|
|
|
|
void _setState(SchedulerCommandState next) {
|
|
_state = next;
|
|
notifyListeners();
|
|
}
|
|
}
|