// SPDX-FileCopyrightText: 2026 FocusFlow contributors // SPDX-License-Identifier: AGPL-3.0-only /// Renders the Today Pane widget for the FocusFlow Flutter UI. library; import 'package:flutter/material.dart'; import 'package:scheduler_core/scheduler_core.dart'; import '../controllers/scheduler_command_controller.dart'; import '../controllers/scheduler_read_controller.dart'; import 'read_state_view.dart'; import 'schedule_components.dart'; /// Read-driven pane that renders the Today view and optional commands. class TodayPane extends StatelessWidget { /// Creates a Today pane from a read [controller]. const TodayPane({ required this.controller, this.commandController, super.key, }); /// Controller that loads Today state. final UiReadController controller; /// Optional command controller for Today actions. final SchedulerCommandController? commandController; /// Builds the widget subtree for this component. /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return ReadStateView( controller: controller, title: 'Today', emptyTitle: 'Today is clear', emptyMessage: 'No scheduled work is waiting in this view.', dataBuilder: (context, state) => TodayContent(state: state, commandController: commandController), ); } } /// Populated Today view for a loaded Today state. class TodayContent extends StatelessWidget { /// Creates Today content for [state]. const TodayContent({required this.state, this.commandController, super.key}); /// Loaded Today state to display. final TodayState state; /// Optional command controller for completing tasks. final SchedulerCommandController? commandController; /// Builds the widget subtree for this component. /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return ListView( padding: const EdgeInsets.all(16), children: [ Text('Today', style: Theme.of(context).textTheme.headlineMedium), const SizedBox(height: 12), for (final notice in state.pendingNotices) NoticeBanner(message: notice.message), CompactPanel(items: state.compactState.compactItems), Text('Timeline', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 8), for (final item in state.timelineItems) TimelineRow( item: item, onDone: _canComplete(item) && commandController != null ? () { return commandController!.completeFlexibleTask( taskId: item.taskId!, ); } : null, ), ], ); } /// Runs the `_canComplete` helper used inside this library. /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. bool _canComplete(TodayTimelineItem item) { return item.taskType == TaskType.flexible && item.taskStatus == TaskStatus.planned && item.taskId != null; } }