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