/// Coordinates Today Screen Controller state for the FocusFlow Flutter UI. library; import 'package:flutter/foundation.dart'; import 'package:scheduler_core/scheduler_core.dart'; import '../models/today_screen_models.dart'; /// Reads Today state from the scheduler application layer. typedef TodayStateReader = Future> Function(); /// Base state for the compact Today screen. sealed class TodayScreenState { /// Creates a Today screen state. const TodayScreenState(); } /// Indicates that the Today screen is loading. class TodayScreenLoading extends TodayScreenState { /// Creates a loading Today screen state. const TodayScreenLoading(); } /// Indicates that the Today screen has renderable timeline data. class TodayScreenReady extends TodayScreenState { /// Creates a ready state with mapped screen [data]. const TodayScreenReady(this.data); /// Presentation model for the Today screen. final TodayScreenData data; } /// Indicates that the Today screen loaded successfully with no cards. class TodayScreenEmpty extends TodayScreenState { /// Creates an empty Today screen state. const TodayScreenEmpty(); } /// Indicates that the Today screen failed to load. class TodayScreenFailure extends TodayScreenState { /// Creates a failure state with a displayable [message]. const TodayScreenFailure(this.message); /// User-facing failure message or code. final String message; } /// Loads Today screen data and tracks selected timeline cards. class TodayScreenController extends ChangeNotifier { /// Creates a Today screen controller from a read callback. TodayScreenController({required this.read}); /// Callback used to read Today state. final TodayStateReader read; TodayScreenState _state = const TodayScreenLoading(); TimelineCardModel? _selectedCard; /// Current Today screen loading/data/failure state. TodayScreenState get state => _state; /// Currently selected timeline card, if a modal should be visible. TimelineCardModel? get selectedCard => _selectedCard; /// Loads Today state and maps it into presentation data. Future load() async { _state = const TodayScreenLoading(); notifyListeners(); try { final result = await read(); final failure = result.failure; if (failure != null) { _state = TodayScreenFailure(failure.detailCode ?? failure.code.name); notifyListeners(); return; } final data = TodayScreenData.fromTodayState(result.requireValue); _state = data.cards.isEmpty ? const TodayScreenEmpty() : TodayScreenReady(data); notifyListeners(); } on Object catch (error) { _state = TodayScreenFailure(error.toString()); notifyListeners(); } } /// Selects [card] when the card allows selection. void selectCard(TimelineCardModel card) { if (!card.isSelectable) { return; } _selectedCard = card; notifyListeners(); } /// Clears the selected timeline card. void clearSelection() { if (_selectedCard == null) { return; } _selectedCard = null; notifyListeners(); } }