92 lines
3.2 KiB
Dart
92 lines
3.2 KiB
Dart
// 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<TodayState> 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<TodayState>(
|
|
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;
|
|
}
|
|
}
|