focus-flow/apps/focus_flow_flutter/lib/controllers/scheduler_read_controller.dart

92 lines
2.2 KiB
Dart

/// Coordinates Scheduler Read Controller state for the FocusFlow Flutter UI.
library;
import 'package:flutter/foundation.dart';
import 'package:scheduler_core/scheduler_core.dart';
typedef ApplicationReader<T> = Future<ApplicationResult<T>> Function();
typedef EmptyPredicate<T> = bool Function(T value);
abstract class UiReadController<T> extends ChangeNotifier {
SchedulerReadState<T> get state;
Future<void> load();
Future<void> retry();
}
sealed class SchedulerReadState<T> {
const SchedulerReadState();
}
class SchedulerReadLoading<T> extends SchedulerReadState<T> {
const SchedulerReadLoading();
}
class SchedulerReadData<T> extends SchedulerReadState<T> {
const SchedulerReadData(this.value);
final T value;
}
class SchedulerReadEmpty<T> extends SchedulerReadState<T> {
const SchedulerReadEmpty(this.value);
final T value;
}
class SchedulerReadFailure<T> extends SchedulerReadState<T> {
const SchedulerReadFailure({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 ApplicationReadController<T> extends UiReadController<T> {
ApplicationReadController({required this.read, required this.isEmpty});
final ApplicationReader<T> read;
final EmptyPredicate<T> isEmpty;
SchedulerReadState<T> _state = SchedulerReadLoading<T>();
@override
SchedulerReadState<T> get state => _state;
@override
Future<void> load() async {
_setState(SchedulerReadLoading<T>());
try {
final result = await read();
final failure = result.failure;
if (failure != null) {
_setState(SchedulerReadFailure<T>(failure: failure));
return;
}
final value = result.requireValue;
_setState(
isEmpty(value)
? SchedulerReadEmpty<T>(value)
: SchedulerReadData<T>(value),
);
} on Object catch (error) {
_setState(SchedulerReadFailure<T>(error: error));
}
}
@override
Future<void> retry() => load();
void _setState(SchedulerReadState<T> next) {
_state = next;
notifyListeners();
}
}