docs: expand dartdocs and add compliance hooks

This commit is contained in:
Ashley Venn 2026-07-01 13:36:12 -07:00
parent 2485e10873
commit ec19dd498d
571 changed files with 7637 additions and 30 deletions

15
.githooks/pre-commit Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
# SPDX-License-Identifier: AGPL-3.0-only
# Blocks commits that do not meet the repository's formatting, analyzer,
# documentation, or SPDX/REUSE metadata gates.
set -euo pipefail
root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$root_dir"
dart format --set-exit-if-changed packages apps scripts tool test
dart analyze
dart run tool/check_reuse.dart
dart run tool/check_docs.dart --skip-dartdoc

View file

@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
# SPDX-License-Identifier: AGPL-3.0-only
# Runs analyzer, tests, coverage, docs, and tagged desktop packaging.
name: CI

17
REUSE.toml Normal file
View file

@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
# SPDX-License-Identifier: AGPL-3.0-only
version = 1
# The project license text is intentionally kept in the repository root as
# LICENSE.md. These annotations cover package and app files that cannot safely
# carry inline SPDX comments, such as generated platform files, binary icons,
# JSON manifests, Xcode project files, and XML/plist resources.
[[annotations]]
path = [
"packages/**",
"apps/focus_flow_flutter/**",
]
precedence = "aggregate"
SPDX-FileCopyrightText = "2026 FocusFlow contributors"
SPDX-License-Identifier = "AGPL-3.0-only"

17
analysis_options.yaml Normal file
View file

@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
# SPDX-License-Identifier: AGPL-3.0-only
include: package:lints/recommended.yaml
analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true
linter:
rules:
public_member_api_docs: true
prefer_final_locals: true
prefer_final_fields: true
avoid_print: true

View file

@ -0,0 +1,6 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# License
This app uses the repository-level license at [../../LICENSE.md](../../LICENSE.md).

View file

@ -1,3 +1,6 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# FocusFlow Flutter
Flutter desktop app target for the FocusFlow UI work.

View file

@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
# SPDX-License-Identifier: AGPL-3.0-only
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
@ -9,6 +12,12 @@
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
@ -22,6 +31,9 @@ linter:
# producing the lint.
rules:
public_member_api_docs: true
prefer_final_locals: true
prefer_final_fields: true
avoid_print: true
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Exports the FocusFlow Flutter application entry points.
library;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../demo_scheduler_composition.dart';
/// Formats a civil date as a long month/day/year label.
@ -19,6 +22,8 @@ String _formatDateLabel(CivilDate date) {
return '${months[date.month - 1]} ${date.day}, ${date.year}';
}
/// Top-level helper that performs the `_instant` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
DateTime _instant(CivilDate date, int hour, [int minute = 0]) {
return DateTime.utc(date.year, date.month, date.day, hour, minute);
}

View file

@ -1,5 +1,10 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../demo_scheduler_composition.dart';
/// Top-level helper that performs the `_todaySeedTasks` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
List<Task> _todaySeedTasks(CivilDate date, DateTime createdAt) {
return [
_seedTask(
@ -118,6 +123,8 @@ List<Task> _todaySeedTasks(CivilDate date, DateTime createdAt) {
];
}
/// Top-level helper that performs the `_seedTask` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Task _seedTask({
required String id,
required String title,

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Composes the FocusFlow Flutter application around Demo Scheduler Composition.
library;
@ -12,6 +15,8 @@ part 'demo/demo_seed_tasks.dart';
/// Wires the Flutter demo UI to in-memory scheduler application use cases.
class DemoSchedulerComposition {
/// Creates a `DemoSchedulerComposition._` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
DemoSchedulerComposition._({
required this.store,
required this.todayQuery,

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Composes the FocusFlow Flutter application around Focus Flow App.
library;
@ -30,6 +33,8 @@ class FocusFlowApp extends StatelessWidget {
/// Factory and controller bundle used by the app tree.
final DemoSchedulerComposition composition;
/// 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 MaterialApp(

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../focus_flow_app.dart';
/// Stateful home screen that owns the Today controller lifecycle.
@ -8,6 +11,8 @@ class FocusFlowHome extends StatefulWidget {
/// Factory and controller bundle used by the home screen.
final DemoSchedulerComposition composition;
/// Creates the mutable state object used by this stateful widget.
/// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin.
@override
State<FocusFlowHome> createState() => _FocusFlowHomeState();
}

View file

@ -1,9 +1,21 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../focus_flow_app.dart';
/// Private implementation type for `_FocusFlowHomeState` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _FocusFlowHomeState extends State<FocusFlowHome> {
/// Stores the `controller` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
late final TodayScreenController controller;
/// Stores the `commandController` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
late final SchedulerCommandController commandController;
/// Initializes state owned by this object before the first build.
/// Use this lifecycle point for controller setup, initial reads, and listener wiring that must happen once per mounted instance.
@override
void initState() {
super.initState();
@ -14,6 +26,8 @@ class _FocusFlowHomeState extends State<FocusFlowHome> {
controller.load();
}
/// Releases resources owned by this object before it leaves the tree.
/// Controllers, listeners, and other disposable collaborators should be cleaned up here to avoid stale callbacks.
@override
void dispose() {
commandController.dispose();
@ -21,6 +35,8 @@ class _FocusFlowHomeState extends State<FocusFlowHome> {
super.dispose();
}
/// Runs the `_toggleCardCompletion` operation and completes after its asynchronous work finishes.
/// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order.
Future<void> _toggleCardCompletion(TimelineCardModel card) async {
if (!card.canToggleCompletion) {
return;
@ -35,6 +51,8 @@ class _FocusFlowHomeState extends State<FocusFlowHome> {
}
}
/// 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 Scaffold(

View file

@ -1,10 +1,21 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../focus_flow_app.dart';
/// Private implementation type for `_PlanIssue` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _PlanIssue extends StatelessWidget {
/// Creates a `_PlanIssue` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _PlanIssue({required this.message});
/// Stores the `message` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final String message;
/// 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 Center(

View file

@ -1,6 +1,13 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../focus_flow_app.dart';
/// Private implementation type for `_TodayScreenScaffold` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _TodayScreenScaffold extends StatefulWidget {
/// Creates a `_TodayScreenScaffold` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _TodayScreenScaffold({
required this.data,
required this.selectedCard,
@ -9,12 +16,28 @@ class _TodayScreenScaffold extends StatefulWidget {
required this.onClearSelection,
});
/// Stores the `data` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final TodayScreenData data;
/// Stores the `selectedCard` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final TimelineCardModel? selectedCard;
/// Stores the `onSelectCard` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final ValueChanged<TimelineCardModel> onSelectCard;
/// Stores the `onCompleteCard` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Future<void> Function(TimelineCardModel card) onCompleteCard;
/// Stores the `onClearSelection` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final VoidCallback onClearSelection;
/// Creates the mutable state object used by this stateful widget.
/// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin.
@override
State<_TodayScreenScaffold> createState() => _TodayScreenScaffoldState();
}

View file

@ -1,9 +1,21 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../focus_flow_app.dart';
/// Private implementation type for `_TodayScreenScaffoldState` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _TodayScreenScaffoldState extends State<_TodayScreenScaffold> {
/// Private state stored as `_timelineScrollTargetCardId` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
String? _timelineScrollTargetCardId;
/// Private state stored as `_timelineScrollRequest` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
var _timelineScrollRequest = 0;
/// Runs the `_showUpcomingRequiredTask` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
void _showUpcomingRequiredTask() {
final targetCardId = widget.data.requiredBanner?.timelineCardId;
if (targetCardId == null) {
@ -15,6 +27,8 @@ class _TodayScreenScaffoldState extends State<_TodayScreenScaffold> {
});
}
/// 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 Stack(

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Provides compatibility composition exports for FocusFlow Flutter.
library;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../scheduler_command_controller.dart';
/// Builds an application operation context for a UI command operation.

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../scheduler_command_controller.dart';
/// Runs scheduler write commands and exposes command state to widgets.
@ -25,7 +28,13 @@ class SchedulerCommandController extends ChangeNotifier {
/// Clock used by direct UI commands such as marking a task complete.
final DateTime Function() now;
/// Private state stored as `_sequence` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
var _sequence = 0;
/// Private state stored as `_state` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
SchedulerCommandState _state = const SchedulerCommandIdle();
/// Current command execution state.
@ -146,6 +155,8 @@ class SchedulerCommandController extends ChangeNotifier {
);
}
/// Runs the `_run` operation and completes after its asynchronous work finishes.
/// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order.
Future<void> _run({
required String label,
required String successMessage,
@ -173,15 +184,21 @@ class SchedulerCommandController extends ChangeNotifier {
}
}
/// Runs the `_nextOperationId` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
String _nextOperationId() {
_sequence += 1;
return 'ui-command-$_sequence';
}
/// Runs the `_setState` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
void _setState(SchedulerCommandState next) {
_state = next;
notifyListeners();
}
/// Runs the `_utcNow` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
static DateTime _utcNow() => DateTime.now().toUtc();
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../scheduler_command_controller.dart';
/// Base state for scheduler command execution in the UI.

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Coordinates Scheduler Command Controller state for the FocusFlow Flutter UI.
library;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Coordinates Scheduler Read Controller state for the FocusFlow Flutter UI.
library;
@ -84,6 +87,8 @@ class ApplicationReadController<T> extends UiReadController<T> {
/// Predicate used to classify a successful value as empty or populated.
final EmptyPredicate<T> isEmpty;
/// Private state stored as `_state` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
SchedulerReadState<T> _state = SchedulerReadLoading<T>();
/// Current read state.
@ -116,6 +121,8 @@ class ApplicationReadController<T> extends UiReadController<T> {
@override
Future<void> retry() => load();
/// Runs the `_setState` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
void _setState(SchedulerReadState<T> next) {
_state = next;
notifyListeners();

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Coordinates Today Screen Controller state for the FocusFlow Flutter UI.
library;
@ -53,7 +56,12 @@ class TodayScreenController extends ChangeNotifier {
/// Callback used to read Today state.
final TodayStateReader read;
/// Private state stored as `_state` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
TodayScreenState _state = const TodayScreenLoading();
/// Private state stored as `_selectedCard` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
TimelineCardModel? _selectedCard;
/// Current Today screen loading/data/failure state.
@ -105,6 +113,8 @@ class TodayScreenController extends ChangeNotifier {
notifyListeners();
}
/// Runs the `_syncSelectedCard` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
void _syncSelectedCard(TodayScreenData data) {
final selected = _selectedCard;
if (selected == null) {

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Launches the FocusFlow Flutter desktop application.
library;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../today_screen_models.dart';
/// Presentation model for the next-required-task banner.

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../today_screen_models.dart';
/// Visual category used to style timeline cards.

View file

@ -1,5 +1,10 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../../today_screen_models.dart';
/// Top-level helper that performs the `_dateLabel` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _dateLabel(CivilDate date) {
const months = [
'January',
@ -18,6 +23,8 @@ String _dateLabel(CivilDate date) {
return '${months[date.month - 1]} ${date.day}, ${date.year}';
}
/// Top-level helper that performs the `_minutesSinceMidnight` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
int _minutesSinceMidnight(DateTime? value) {
if (value == null) {
return 0;
@ -25,6 +32,8 @@ int _minutesSinceMidnight(DateTime? value) {
return value.hour * 60 + value.minute;
}
/// Top-level helper that performs the `_formatTime` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _formatTime(DateTime? value) {
if (value == null) {
return '';

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../today_screen_models.dart';
/// Presentation model for a single compact timeline card.

View file

@ -1,5 +1,10 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../today_screen_models.dart';
/// Top-level helper that performs the `_visualKindFor` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
TaskVisualKind _visualKindFor(TodayTimelineItem item) {
if (item.taskStatus == TaskStatus.completed ||
(item.taskType == TaskType.surprise &&
@ -16,6 +21,8 @@ TaskVisualKind _visualKindFor(TodayTimelineItem item) {
};
}
/// Top-level helper that performs the `_typeLabelFor` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _typeLabelFor(TaskType taskType, TaskVisualKind visualKind) {
if (visualKind == TaskVisualKind.completedSurprise) {
return 'Completed';
@ -30,6 +37,8 @@ String _typeLabelFor(TaskType taskType, TaskVisualKind visualKind) {
};
}
/// Top-level helper that performs the `_subtitleFor` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _subtitleFor(
TodayTimelineItem item,
TaskVisualKind visualKind,

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../today_screen_models.dart';
/// Visible timeline range expressed as minutes since midnight.

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../today_screen_models.dart';
/// Presentation model for the compact Today screen.

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Defines Today Screen Models models for the FocusFlow Flutter UI.
library;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Defines Focus Flow Theme styling for the FocusFlow Flutter UI.
library;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Defines Focus Flow Tokens styling for the FocusFlow Flutter UI.
library;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Defines Scheduler Visual Tokens styling for the FocusFlow Flutter UI.
library;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders the App Shell widget for the FocusFlow Flutter UI.
library;
@ -16,6 +19,8 @@ class AppShell extends StatelessWidget {
/// Primary content widget displayed beside the sidebar.
final Widget child;
/// 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 ColoredBox(

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders the Backlog Pane widget for the FocusFlow Flutter UI.
library;
@ -24,6 +27,8 @@ class BacklogPane extends StatelessWidget {
/// Optional command controller for mutating backlog items.
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<BacklogQueryResult>(
@ -52,6 +57,8 @@ class BacklogContent extends StatelessWidget {
/// Optional command controller for capture and scheduling 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 ListView(
@ -91,19 +98,29 @@ class QuickCaptureForm extends StatefulWidget {
/// Command controller used to submit captured task titles.
final SchedulerCommandController commandController;
/// Creates the mutable state object used by this stateful widget.
/// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin.
@override
State<QuickCaptureForm> createState() => _QuickCaptureFormState();
}
/// Private implementation type for `_QuickCaptureFormState` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _QuickCaptureFormState extends State<QuickCaptureForm> {
/// Stores the `titleController` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final titleController = TextEditingController();
/// Releases resources owned by this object before it leaves the tree.
/// Controllers, listeners, and other disposable collaborators should be cleaned up here to avoid stale callbacks.
@override
void dispose() {
titleController.dispose();
super.dispose();
}
/// 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 Row(
@ -142,6 +159,8 @@ class CommandStatusBanner extends StatelessWidget {
/// Command controller whose state should be rendered.
final SchedulerCommandController controller;
/// 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 AnimatedBuilder(

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders the Read State View widget for the FocusFlow Flutter UI.
library;
@ -32,6 +35,8 @@ class ReadStateView<T> extends StatelessWidget {
/// Builds the populated content for a read value.
final Widget Function(BuildContext context, T value) dataBuilder;
/// 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 AnimatedBuilder(
@ -82,6 +87,8 @@ class EmptyStatePanel extends StatelessWidget {
/// Optional content shown alongside the empty-state panel.
final Widget? child;
/// 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) {
final panel = Padding(
@ -138,6 +145,8 @@ class FailureStatePanel extends StatelessWidget {
/// Callback invoked when the user retries the read.
final Future<void> Function() onRetry;
/// 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 Center(

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders the Required Banner widget for the FocusFlow Flutter UI.
library;
@ -17,6 +20,8 @@ class RequiredBanner extends StatelessWidget {
/// Callback invoked when the highlighted required task should be shown.
final VoidCallback? onShowUpcoming;
/// 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) {
final banner = model;
@ -97,44 +102,115 @@ class RequiredBanner extends StatelessWidget {
}
}
/// Private implementation type for `_RequiredBannerMetrics` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _RequiredBannerMetrics {
/// Creates a `_RequiredBannerMetrics` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _RequiredBannerMetrics(this.scale);
/// Shared constant value for `referenceHeight`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const referenceHeight = 72.0;
/// Shared constant value for `_referenceWidth`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const _referenceWidth = 760.0;
/// Shared constant value for `_minimumScale`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const _minimumScale = 0.5;
/// Creates a `_RequiredBannerMetrics.fromWidth` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
factory _RequiredBannerMetrics.fromWidth(double width) {
final safeWidth = width.isFinite ? width : _referenceWidth;
final scale = (safeWidth / _referenceWidth).clamp(_minimumScale, 1.0);
return _RequiredBannerMetrics(scale.toDouble());
}
/// Stores the `scale` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final double scale;
/// Returns the derived `horizontalPadding` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get horizontalPadding => 18 * scale;
/// Returns the derived `bannerRadius` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get bannerRadius => FocusFlowTokens.bannerRadius * scale;
/// Returns the derived `borderWidth` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get borderWidth => scale < 0.7 ? 0.8 : 1;
/// Returns the derived `iconCircleSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get iconCircleSize => 48 * scale;
/// Returns the derived `iconSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get iconSize => 24 * scale;
/// Returns the derived `iconGap` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get iconGap => 26 * scale;
/// Returns the derived `buttonGap` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get buttonGap => 20 * scale;
/// Returns the derived `textSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get textSize => (19 * scale).clamp(13.0, 14.0).toDouble();
/// Returns the derived `buttonWidth` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get buttonWidth => 176 * scale;
/// Returns the derived `buttonHeight` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get buttonHeight => 46 * scale;
/// Returns the derived `buttonRadius` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get buttonRadius => FocusFlowTokens.smallButtonRadius * scale;
/// Returns the derived `buttonTextSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get buttonTextSize => (16 * scale).clamp(11.0, 12.5).toDouble();
/// Returns the derived `buttonIconSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get buttonIconSize => 20 * scale;
/// Returns the derived `buttonTextGap` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get buttonTextGap => 6 * scale;
/// Returns the derived `buttonPadding` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
EdgeInsets get buttonPadding => EdgeInsets.symmetric(horizontal: 12 * scale);
}
/// Private implementation type for `_UpcomingButton` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _UpcomingButton extends StatelessWidget {
/// Creates a `_UpcomingButton` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _UpcomingButton({required this.metrics, required this.onPressed});
/// Stores the `metrics` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _RequiredBannerMetrics metrics;
/// Stores the `onPressed` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final VoidCallback? onPressed;
/// 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 OutlinedButton(

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders the Schedule Components widget for the FocusFlow Flutter UI.
library;
@ -14,6 +17,8 @@ class CompactPanel extends StatelessWidget {
/// Timeline items to display in compact form.
final List<TodayTimelineItem> items;
/// 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) {
if (items.isEmpty) {
@ -42,6 +47,8 @@ class TimelineRow extends StatelessWidget {
/// Optional completion callback for eligible tasks.
final Future<void> Function()? onDone;
/// 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) {
final scheme = Theme.of(context).colorScheme;
@ -104,19 +111,29 @@ class BacklogRow extends StatefulWidget {
/// Optional callback that schedules the item for a duration in minutes.
final Future<void> Function(int durationMinutes)? onSchedule;
/// Creates the mutable state object used by this stateful widget.
/// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin.
@override
State<BacklogRow> createState() => _BacklogRowState();
}
/// Private implementation type for `_BacklogRowState` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _BacklogRowState extends State<BacklogRow> {
/// Stores the `durationController` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final durationController = TextEditingController();
/// Releases resources owned by this object before it leaves the tree.
/// Controllers, listeners, and other disposable collaborators should be cleaned up here to avoid stale callbacks.
@override
void dispose() {
durationController.dispose();
super.dispose();
}
/// 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) {
final scheme = Theme.of(context).colorScheme;
@ -175,6 +192,8 @@ class StalenessMarker extends StatelessWidget {
/// Staleness marker value to render.
final BacklogStalenessMarker marker;
/// 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 Icon(
@ -192,6 +211,8 @@ class NoticeBanner extends StatelessWidget {
/// Notice message to display.
final String message;
/// 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 Container(
@ -216,6 +237,8 @@ String timeText(TimelineItem item) {
return '${_clockText(start)}-${_clockText(end)}';
}
/// Top-level helper that performs the `_clockText` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _clockText(DateTime value) {
final hour = value.hour.toString().padLeft(2, '0');
final minute = value.minute.toString().padLeft(2, '0');

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders the Sidebar widget for the FocusFlow Flutter UI.
library;
@ -10,6 +13,8 @@ class Sidebar extends StatelessWidget {
/// Creates the FocusFlow sidebar.
const Sidebar({super.key});
/// 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 DecoratedBox(
@ -46,9 +51,15 @@ class Sidebar extends StatelessWidget {
}
}
/// Private implementation type for `_WindowControls` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _WindowControls extends StatelessWidget {
/// Creates a `_WindowControls` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _WindowControls();
/// 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 const Row(
@ -63,11 +74,19 @@ class _WindowControls extends StatelessWidget {
}
}
/// Private implementation type for `_WindowDot` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _WindowDot extends StatelessWidget {
/// Creates a `_WindowDot` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _WindowDot({required this.color});
/// Stores the `color` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color color;
/// 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 DecoratedBox(
@ -77,9 +96,15 @@ class _WindowDot extends StatelessWidget {
}
}
/// Private implementation type for `_BrandRow` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _BrandRow extends StatelessWidget {
/// Creates a `_BrandRow` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _BrandRow();
/// 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 Row(
@ -111,7 +136,11 @@ class _BrandRow extends StatelessWidget {
}
}
/// Private implementation type for `_NavItem` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _NavItem extends StatelessWidget {
/// Creates a `_NavItem` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _NavItem({
required this.label,
required this.icon,
@ -119,11 +148,24 @@ class _NavItem extends StatelessWidget {
this.active = false,
});
/// Stores the `label` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final String label;
/// Stores the `icon` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final IconData icon;
/// Stores the `onTap` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final VoidCallback onTap;
/// Stores the `active` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final bool active;
/// 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) {
final color = active

View file

@ -1,11 +1,25 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_selection_modal.dart';
/// Private implementation type for `_ActionButton` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _ActionButton extends StatelessWidget {
/// Creates a `_ActionButton` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _ActionButton({required this.icon, required this.label});
/// Stores the `icon` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final IconData icon;
/// Stores the `label` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final String label;
/// 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 OutlinedButton.icon(

View file

@ -1,10 +1,21 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_selection_modal.dart';
/// Private implementation type for `_HeaderMetadata` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _HeaderMetadata extends StatelessWidget {
/// Creates a `_HeaderMetadata` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _HeaderMetadata({required this.card});
/// Stores the `card` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final TimelineCardModel card;
/// 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) {
const metadataStyle = TextStyle(

View file

@ -1,11 +1,25 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_selection_modal.dart';
/// Private implementation type for `_InfoTile` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _InfoTile extends StatelessWidget {
/// Creates a `_InfoTile` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _InfoTile({required this.child, required this.label});
/// Stores the `child` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Widget child;
/// Stores the `label` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final String label;
/// 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 Container(

View file

@ -1,5 +1,10 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_selection_modal.dart';
/// Top-level helper that performs the `_accentFor` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Color _accentFor(TaskVisualKind kind) {
return switch (kind) {
TaskVisualKind.flexible => FocusFlowTokens.flexibleGreen,

View file

@ -1,16 +1,33 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_selection_modal.dart';
/// Private implementation type for `_ModalStatusButton` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _ModalStatusButton extends StatelessWidget {
/// Creates a `_ModalStatusButton` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _ModalStatusButton({
required this.card,
required this.color,
required this.onPressed,
});
/// Stores the `card` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final TimelineCardModel card;
/// Stores the `color` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color color;
/// Stores the `onPressed` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final VoidCallback? onPressed;
/// 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) {
final ring = Container(

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders the Task Selection Modal widget for the FocusFlow Flutter UI.
library;
@ -33,6 +36,8 @@ class TaskSelectionModal extends StatelessWidget {
/// Callback invoked when the status circle should toggle completion.
final VoidCallback? onStatusPressed;
/// 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) {
final accent = _accentFor(card.visualKind);

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../timeline_axis.dart';
/// Background grid aligned to timeline tick marks.
@ -11,6 +14,8 @@ class TimelineGrid extends StatelessWidget {
/// Vertical inset before the first timeline tick.
final double topInset;
/// 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 CustomPaint(

View file

@ -1,11 +1,25 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../timeline_axis.dart';
/// Private implementation type for `_TimelineGridPainter` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _TimelineGridPainter extends CustomPainter {
/// Creates a `_TimelineGridPainter` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _TimelineGridPainter({required this.geometry, required this.topInset});
/// Stores the `geometry` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final TimelineGeometry geometry;
/// Stores the `topInset` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final double topInset;
/// Performs the `paint` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
@ -23,6 +37,8 @@ class _TimelineGridPainter extends CustomPainter {
}
}
/// Performs the `shouldRepaint` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
@override
bool shouldRepaint(covariant _TimelineGridPainter oldDelegate) {
return oldDelegate.geometry != geometry || oldDelegate.topInset != topInset;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders Difficulty Bars pieces for the FocusFlow Flutter timeline.
library;
@ -49,6 +52,8 @@ class DifficultyBars extends StatelessWidget {
};
}
/// 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 CustomPaint(
@ -61,15 +66,26 @@ class DifficultyBars extends StatelessWidget {
}
}
/// Private implementation type for `_DifficultyBarsPainter` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _DifficultyBarsPainter extends CustomPainter {
/// Creates a `_DifficultyBarsPainter` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _DifficultyBarsPainter({
required this.filledCount,
required this.color,
});
/// Stores the `filledCount` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final int filledCount;
/// Stores the `color` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color color;
/// Performs the `paint` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
@override
void paint(Canvas canvas, Size size) {
final gap = size.width * 0.08;
@ -98,6 +114,8 @@ class _DifficultyBarsPainter extends CustomPainter {
}
}
/// Performs the `shouldRepaint` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
@override
bool shouldRepaint(covariant _DifficultyBarsPainter oldDelegate) {
return oldDelegate.filledCount != filledCount || oldDelegate.color != color;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders Reward Icon pieces for the FocusFlow Flutter timeline.
library;
@ -20,6 +23,8 @@ class RewardIcon extends StatelessWidget {
/// Square size of the painted icon.
final double size;
/// 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 CustomPaint(
@ -29,11 +34,19 @@ class RewardIcon extends StatelessWidget {
}
}
/// Private implementation type for `_RewardIconPainter` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _RewardIconPainter extends CustomPainter {
/// Creates a `_RewardIconPainter` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _RewardIconPainter(this.color);
/// Stores the `color` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color color;
/// Performs the `paint` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
@ -59,6 +72,8 @@ class _RewardIconPainter extends CustomPainter {
);
}
/// Runs the `_drawSparkle` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
void _drawSparkle(Canvas canvas, Paint paint, Offset center, double radius) {
final path = Path()
..moveTo(center.dx, center.dy - radius)
@ -73,6 +88,8 @@ class _RewardIconPainter extends CustomPainter {
canvas.drawPath(path, paint);
}
/// Performs the `shouldRepaint` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
@override
bool shouldRepaint(covariant _RewardIconPainter oldDelegate) {
return oldDelegate.color != color;

View file

@ -1,16 +1,33 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_timeline_card.dart';
/// Private implementation type for `_CardColors` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _CardColors {
/// Creates a `_CardColors` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _CardColors({
required this.accent,
required this.background,
required this.reward,
});
/// Stores the `accent` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color accent;
/// Stores the `background` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color background;
/// Stores the `reward` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color reward;
/// Creates a `_CardColors.forKind` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
factory _CardColors.forKind(TaskVisualKind kind) {
return switch (kind) {
TaskVisualKind.flexible => const _CardColors(

View file

@ -1,14 +1,37 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_timeline_card.dart';
/// Private implementation type for `_CardMetrics` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _CardMetrics {
/// Creates a `_CardMetrics` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _CardMetrics({required this.scale, required this.height});
/// Shared constant value for `_referenceWidth`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const _referenceWidth = 640.0;
/// Shared constant value for `_referenceHeight`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const _referenceHeight = 88.0;
/// Shared constant value for `_freeSlotReferenceHeight`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const _freeSlotReferenceHeight = 108.0;
/// Shared constant value for `_compactHeightThreshold`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const _compactHeightThreshold = 56.0;
/// Shared constant value for `_minimumScale`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const _minimumScale = 0.16;
/// Creates a `_CardMetrics.fromConstraints` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
factory _CardMetrics.fromConstraints(
BoxConstraints constraints, {
required TaskVisualKind kind,
@ -29,42 +52,122 @@ class _CardMetrics {
return _CardMetrics(scale: scale.toDouble(), height: height);
}
/// Stores the `scale` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final double scale;
/// Stores the `height` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final double height;
/// Returns the derived `isCompact` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
bool get isCompact => height < _compactHeightThreshold;
/// Returns the derived `cardRadius` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get cardRadius =>
math.min(FocusFlowTokens.cardRadius * scale, height / 2);
/// Returns the derived `borderWidth` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get borderWidth => math.max(0.75, 1.2 * scale);
/// Returns the derived `shadowBlur` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get shadowBlur => isCompact ? 0 : 18 * scale;
/// Returns the derived `shadowSpread` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get shadowSpread => isCompact ? 0 : scale;
/// Returns the derived `statusRingSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get statusRingSize {
final availableHeight = math.max(8, height - padding.vertical);
return math.min(24, availableHeight * 0.78).toDouble();
}
/// Returns the derived `statusBorderWidth` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get statusBorderWidth => math.max(1.4, statusRingSize * 0.08);
/// Returns the derived `statusIconSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get statusIconSize => statusRingSize * 0.58;
/// Returns the derived `statusGap` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get statusGap => isCompact ? 7 : 22 * scale;
/// Returns the derived `actionButtonSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get actionButtonSize => (30 * scale).clamp(14.0, 22.0).toDouble();
/// Returns the derived `actionIconSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get actionIconSize => (16 * scale).clamp(9.0, 13.0).toDouble();
/// Returns the derived `actionGap` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get actionGap => math.max(3, 5 * scale);
/// Returns the derived `actionsWidth` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get actionsWidth => actionButtonSize * 4 + actionGap;
/// Returns the derived `indicatorTop` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get indicatorTop => isCompact ? 0 : math.max(1, 2 * scale);
/// Returns the derived `indicatorGap` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get indicatorGap => math.max(3, 5 * scale);
/// Returns the derived `rewardIconSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get rewardIconSize => 14;
/// Returns the derived `titleSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get titleSize => 10;
/// Returns the derived `metaSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get metaSize => 7;
/// Returns the derived `titleMetaGap` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get titleMetaGap => 4 * scale;
/// Returns the derived `freeSlotTimeGap` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get freeSlotTimeGap => 10 * scale;
/// Returns the derived `compactTextGap` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get compactTextGap => math.max(3, 8 * scale);
/// Returns the derived `indicatorWidth` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get indicatorWidth =>
rewardIconSize + indicatorGap + difficultySize.width;
/// Returns the derived `expandedTrailingReserve` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get expandedTrailingReserve =>
indicatorWidth + math.max(8, 12 * scale);
/// Returns the derived `compactTrailingReserve` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get compactTrailingReserve => indicatorWidth + math.max(6, 8 * scale);
/// Returns the derived `difficultySize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
Size get difficultySize => Size(26, 14);
/// Returns the derived `padding` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
EdgeInsets get padding {
if (isCompact) {
return EdgeInsets.symmetric(

View file

@ -1,16 +1,33 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_timeline_card.dart';
/// Private implementation type for `_CardText` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _CardText extends StatelessWidget {
/// Creates a `_CardText` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _CardText({
required this.card,
required this.color,
required this.metrics,
});
/// Stores the `card` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final TimelineCardModel card;
/// Stores the `color` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color color;
/// Stores the `metrics` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _CardMetrics metrics;
/// 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) {
final titleStyle = TextStyle(

View file

@ -1,6 +1,13 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_timeline_card.dart';
/// Private implementation type for `_CompactCardText` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _CompactCardText extends StatelessWidget {
/// Creates a `_CompactCardText` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _CompactCardText({
required this.card,
required this.color,
@ -8,11 +15,24 @@ class _CompactCardText extends StatelessWidget {
required this.onStatusPressed,
});
/// Stores the `card` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final TimelineCardModel card;
/// Stores the `color` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color color;
/// Stores the `metrics` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _CardMetrics metrics;
/// Stores the `onStatusPressed` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final VoidCallback? onStatusPressed;
/// 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) {
final metaText = _compactMetaText(card);
@ -83,6 +103,8 @@ class _CompactCardText extends StatelessWidget {
);
}
/// Runs the `_compactMetaText` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
String _compactMetaText(TimelineCardModel card) {
if (card.visualKind == TaskVisualKind.freeSlot &&
card.timeText.isNotEmpty) {

View file

@ -1,6 +1,13 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_timeline_card.dart';
/// Private implementation type for `_ExpandedCardContent` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _ExpandedCardContent extends StatelessWidget {
/// Creates a `_ExpandedCardContent` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _ExpandedCardContent({
required this.card,
required this.colors,
@ -8,11 +15,24 @@ class _ExpandedCardContent extends StatelessWidget {
required this.onStatusPressed,
});
/// Stores the `card` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final TimelineCardModel card;
/// Stores the `colors` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _CardColors colors;
/// Stores the `metrics` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _CardMetrics metrics;
/// Stores the `onStatusPressed` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final VoidCallback? onStatusPressed;
/// 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 Row(

View file

@ -1,16 +1,33 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_timeline_card.dart';
/// Private implementation type for `_NoOpIcon` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _NoOpIcon extends StatelessWidget {
/// Creates a `_NoOpIcon` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _NoOpIcon({
required this.icon,
required this.color,
required this.metrics,
});
/// Stores the `icon` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final IconData icon;
/// Stores the `color` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color color;
/// Stores the `metrics` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _CardMetrics metrics;
/// 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 Tooltip(

View file

@ -1,6 +1,13 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_timeline_card.dart';
/// Private implementation type for `_QuickActions` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _QuickActions extends StatelessWidget {
/// Creates a `_QuickActions` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _QuickActions({
required this.color,
required this.backgroundColor,
@ -8,11 +15,24 @@ class _QuickActions extends StatelessWidget {
required this.visible,
});
/// Stores the `color` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color color;
/// Stores the `backgroundColor` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color backgroundColor;
/// Stores the `metrics` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _CardMetrics metrics;
/// Stores the `visible` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final bool visible;
/// 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 ExcludeSemantics(

View file

@ -1,6 +1,13 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_timeline_card.dart';
/// Private implementation type for `_StatusRing` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _StatusRing extends StatelessWidget {
/// Creates a `_StatusRing` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _StatusRing({
required this.card,
required this.color,
@ -8,11 +15,24 @@ class _StatusRing extends StatelessWidget {
this.onPressed,
});
/// Stores the `card` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final TimelineCardModel card;
/// Stores the `color` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color color;
/// Stores the `metrics` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _CardMetrics metrics;
/// Stores the `onPressed` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final VoidCallback? onPressed;
/// 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) {
final border = Border.all(color: color, width: metrics.statusBorderWidth);

View file

@ -1,8 +1,17 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_timeline_card.dart';
/// Private implementation type for `_TaskTimelineCardState` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _TaskTimelineCardState extends State<TaskTimelineCard> {
/// Private state stored as `_isHovered` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
bool _isHovered = false;
/// 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) {
final card = widget.card;

View file

@ -1,6 +1,13 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../task_timeline_card.dart';
/// Private implementation type for `_TrailingControls` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _TrailingControls extends StatelessWidget {
/// Creates a `_TrailingControls` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _TrailingControls({
required this.card,
required this.colors,
@ -8,11 +15,24 @@ class _TrailingControls extends StatelessWidget {
required this.actionsVisible,
});
/// Stores the `card` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final TimelineCardModel card;
/// Stores the `colors` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _CardColors colors;
/// Stores the `metrics` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _CardMetrics metrics;
/// Stores the `actionsVisible` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final bool actionsVisible;
/// 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 Row(

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders Task Timeline Card pieces for the FocusFlow Flutter timeline.
library;
@ -40,6 +43,8 @@ class TaskTimelineCard extends StatefulWidget {
/// Callback invoked when the left status control is clicked.
final VoidCallback? onStatusPressed;
/// Creates the mutable state object used by this stateful widget.
/// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin.
@override
State<TaskTimelineCard> createState() => _TaskTimelineCardState();
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders Timeline Axis pieces for the FocusFlow Flutter timeline.
library;
@ -20,6 +23,8 @@ class TimelineAxis extends StatelessWidget {
/// Vertical inset before the first timeline tick.
final double topInset;
/// 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) {
final ticks = geometry.ticks();

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders Timeline Geometry pieces for the FocusFlow Flutter timeline.
library;
@ -60,6 +63,8 @@ class TimelineGeometry {
];
}
/// Performs the `operator ==` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
@override
bool operator ==(Object other) {
return identical(this, other) ||
@ -70,6 +75,8 @@ class TimelineGeometry {
other.minCardHeight == minCardHeight;
}
/// Returns the derived `hashCode` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
@override
int get hashCode {
return Object.hash(
@ -80,6 +87,8 @@ class TimelineGeometry {
);
}
/// Runs the `_labelFor` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
static String _labelFor(int minutes) {
final hour24 = (minutes ~/ 60) % 24;
final minute = minutes % 60;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders Timeline View pieces for the FocusFlow Flutter timeline.
library;
@ -49,6 +52,8 @@ class TimelineView extends StatefulWidget {
/// Monotonic request number that allows repeated jumps to the same card.
final int scrollRequest;
/// Creates the mutable state object used by this stateful widget.
/// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin.
@override
State<TimelineView> createState() => _TimelineViewState();
}

View file

@ -1,6 +1,13 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../timeline_view.dart';
/// Private implementation type for `_TimelineCardPlacement` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _TimelineCardPlacement {
/// Creates a `_TimelineCardPlacement` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _TimelineCardPlacement({
required this.card,
required this.lane,
@ -9,14 +16,32 @@ class _TimelineCardPlacement {
required this.height,
});
/// Shared constant value for `_laneGap`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const _laneGap = 8.0;
/// Stores the `card` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final TimelineCardModel card;
/// Stores the `lane` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final int lane;
/// Stores the `laneCount` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final int laneCount;
/// Stores the `top` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final double top;
/// Stores the `height` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final double height;
/// Performs the `withCard` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
_TimelineCardPlacement withCard(TimelineCardModel nextCard) {
if (identical(card, nextCard)) {
return this;
@ -30,6 +55,8 @@ class _TimelineCardPlacement {
);
}
/// Performs the `pack` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
static List<_TimelineCardPlacement> pack(
List<TimelineCardModel> cards, {
required TimelineGeometry geometry,
@ -74,6 +101,8 @@ class _TimelineCardPlacement {
return placements;
}
/// Runs the `_packGroup` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
static List<_TimelineCardPlacement> _packGroup(
List<TimelineCardModel> group, {
required TimelineGeometry geometry,
@ -113,6 +142,8 @@ class _TimelineCardPlacement {
];
}
/// Runs the `_visualStart` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
static double _visualStart(
TimelineCardModel card,
TimelineGeometry geometry,
@ -120,21 +151,29 @@ class _TimelineCardPlacement {
return geometry.yForMinutesSinceMidnight(card.startMinutes);
}
/// Runs the `_visualEnd` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
static double _visualEnd(TimelineCardModel card, TimelineGeometry geometry) {
final duration = card.endMinutes - card.startMinutes;
return _visualStart(card, geometry) + geometry.heightForDuration(duration);
}
/// Performs the `left` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
double left(double trackWidth) {
final laneWidth = _laneWidth(trackWidth);
final laneGap = _laneGapForWidth(trackWidth);
return FocusFlowTokens.cardHorizontalPadding + lane * (laneWidth + laneGap);
}
/// Performs the `width` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
double width(double trackWidth) {
return _laneWidth(trackWidth);
}
/// Runs the `_availableWidth` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
double _availableWidth(double trackWidth) {
final availableWidth = trackWidth - FocusFlowTokens.cardHorizontalPadding;
if (availableWidth < 0) {
@ -143,12 +182,16 @@ class _TimelineCardPlacement {
return availableWidth;
}
/// Runs the `_laneWidth` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
double _laneWidth(double trackWidth) {
final availableWidth = _availableWidth(trackWidth);
final laneGap = _laneGapForWidth(trackWidth);
return (availableWidth - laneGap * (laneCount - 1)) / laneCount;
}
/// Runs the `_laneGapForWidth` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
double _laneGapForWidth(double trackWidth) {
if (laneCount == 1) {
return 0;

View file

@ -1,8 +1,17 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../timeline_view.dart';
/// Private implementation type for `_TimelineScrollBehavior` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _TimelineScrollBehavior extends MaterialScrollBehavior {
/// Creates a `_TimelineScrollBehavior` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _TimelineScrollBehavior();
/// Returns the derived `dragDevices` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
@override
Set<PointerDeviceKind> get dragDevices {
return {...super.dragDevices, PointerDeviceKind.mouse};

View file

@ -1,22 +1,53 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../timeline_view.dart';
/// Private implementation type for `_TimelineViewState` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _TimelineViewState extends State<TimelineView> {
/// Shared constant value for `_topInset`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const _topInset = 12.0;
/// Private state stored as `_scrollController` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
final _scrollController = ScrollController();
/// Private state stored as `_didSetInitialScroll` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
bool _didSetInitialScroll = false;
/// Private state stored as `_handledScrollRequest` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
var _handledScrollRequest = 0;
/// Private state stored as `_geometry` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
late TimelineGeometry _geometry;
/// Private state stored as `_contentHeight` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
late double _contentHeight;
/// Private state stored as `_placements` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
late List<_TimelineCardPlacement> _placements;
/// Private state stored as `_cardsLayoutHash` for this implementation.
/// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
late int _cardsLayoutHash;
/// Initializes state owned by this object before the first build.
/// Use this lifecycle point for controller setup, initial reads, and listener wiring that must happen once per mounted instance.
@override
void initState() {
super.initState();
_updateLayoutCache();
}
/// Performs the `didUpdateWidget` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
@override
void didUpdateWidget(covariant TimelineView oldWidget) {
super.didUpdateWidget(oldWidget);
@ -34,12 +65,16 @@ class _TimelineViewState extends State<TimelineView> {
}
}
/// Releases resources owned by this object before it leaves the tree.
/// Controllers, listeners, and other disposable collaborators should be cleaned up here to avoid stale callbacks.
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
/// 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 LayoutBuilder(
@ -111,6 +146,8 @@ class _TimelineViewState extends State<TimelineView> {
);
}
/// Runs the `_updateLayoutCache` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
void _updateLayoutCache() {
_geometry = TimelineGeometry(
startMinutes: widget.range.startMinutes,
@ -125,6 +162,8 @@ class _TimelineViewState extends State<TimelineView> {
_cardsLayoutHash = _layoutHashFor(widget.cards);
}
/// Runs the `_layoutHashFor` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
int _layoutHashFor(List<TimelineCardModel> cards) {
return Object.hashAll(
cards.map(
@ -133,6 +172,8 @@ class _TimelineViewState extends State<TimelineView> {
);
}
/// Runs the `_refreshPlacementCards` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
void _refreshPlacementCards() {
final cardsById = {for (final card in widget.cards) card.id: card};
_placements = [
@ -141,6 +182,8 @@ class _TimelineViewState extends State<TimelineView> {
];
}
/// Runs the `_scheduleInitialScroll` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
void _scheduleInitialScroll(
TimelineGeometry geometry,
double viewportHeight,
@ -168,6 +211,8 @@ class _TimelineViewState extends State<TimelineView> {
});
}
/// Runs the `_scheduleTargetScroll` helper used inside this library.
/// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
void _scheduleTargetScroll(TimelineGeometry geometry) {
final targetCardId = widget.scrollTargetCardId;
if (targetCardId == null || widget.scrollRequest == _handledScrollRequest) {

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders the Today Pane widget for the FocusFlow Flutter UI.
library;
@ -24,6 +27,8 @@ class TodayPane extends StatelessWidget {
/// 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>(
@ -48,6 +53,8 @@ class TodayContent extends StatelessWidget {
/// 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(
@ -75,6 +82,8 @@ class TodayContent extends StatelessWidget {
);
}
/// 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 &&

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Renders the Top Bar widget for the FocusFlow Flutter UI.
library;
@ -18,6 +21,8 @@ class TopBar extends StatelessWidget {
/// Date label shown beside the date navigation controls.
final String dateLabel;
/// 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 LayoutBuilder(

View file

@ -1,16 +1,33 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../top_bar.dart';
/// Private implementation type for `_IconButton` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _IconButton extends StatelessWidget {
/// Creates a `_IconButton` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _IconButton({
required this.icon,
required this.metrics,
required this.onPressed,
});
/// Stores the `icon` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final IconData icon;
/// Stores the `metrics` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _TopBarMetrics metrics;
/// Stores the `onPressed` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final VoidCallback onPressed;
/// 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 IconButton(

View file

@ -1,38 +1,116 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../top_bar.dart';
/// Private implementation type for `_TopBarMetrics` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _TopBarMetrics {
/// Creates a `_TopBarMetrics` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _TopBarMetrics(this.scale);
/// Shared constant value for `referenceHeight`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const referenceHeight = 48.0;
/// Shared constant value for `_referenceWidth`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const _referenceWidth = 900.0;
/// Shared constant value for `_minimumScale`.
/// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites.
static const _minimumScale = 0.44;
/// Creates a `_TopBarMetrics.fromWidth` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
factory _TopBarMetrics.fromWidth(double width) {
final safeWidth = width.isFinite ? width : _referenceWidth;
final scale = (safeWidth / _referenceWidth).clamp(_minimumScale, 1.0);
return _TopBarMetrics(scale.toDouble());
}
/// Stores the `scale` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final double scale;
/// Returns the derived `titleWidth` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get titleWidth => 112 * scale;
/// Returns the derived `titleSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get titleSize => FocusFlowTokens.pageTitleSize * scale;
/// Returns the derived `titleGap` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get titleGap => 30 * scale;
/// Returns the derived `controlHeight` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get controlHeight => referenceHeight * scale;
/// Returns the derived `iconButtonSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get iconButtonSize => referenceHeight * scale;
/// Returns the derived `iconSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get iconSize => 24 * scale;
/// Returns the derived `dateWidth` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get dateWidth => 144 * scale;
/// Returns the derived `dateSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get dateSize => 17 * scale;
/// Returns the derived `modeWidth` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get modeWidth => 220 * scale;
/// Returns the derived `modeHeight` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get modeHeight => referenceHeight * scale;
/// Returns the derived `modeLabelSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get modeLabelSize => 17 * scale;
/// Returns the derived `settingsGap` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get settingsGap => 28 * scale;
/// Returns the derived `settingsWidth` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get settingsWidth => 136 * scale;
/// Returns the derived `settingsHeight` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get settingsHeight => referenceHeight * scale;
/// Returns the derived `settingsIconSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get settingsIconSize => 20 * scale;
/// Returns the derived `settingsTextSize` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get settingsTextSize => 15 * scale;
/// Returns the derived `settingsTextGap` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get settingsTextGap => 8 * scale;
/// Returns the derived `borderRadius` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get borderRadius => FocusFlowTokens.smallButtonRadius * scale;
/// Returns the derived `borderWidth` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
double get borderWidth => scale < 0.7 ? 0.8 : 1;
/// Returns the derived `buttonPadding` value for this object.
/// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated.
EdgeInsets get buttonPadding => EdgeInsets.symmetric(horizontal: 12 * scale);
}

View file

@ -1,10 +1,21 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../top_bar.dart';
/// Private implementation type for `_ModeToggle` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _ModeToggle extends StatelessWidget {
/// Creates a `_ModeToggle` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _ModeToggle({required this.metrics});
/// Stores the `metrics` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _TopBarMetrics metrics;
/// 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 Container(

View file

@ -1,10 +1,21 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../top_bar.dart';
/// Private implementation type for `_SettingsButton` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _SettingsButton extends StatelessWidget {
/// Creates a `_SettingsButton` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _SettingsButton({required this.metrics});
/// Stores the `metrics` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final _TopBarMetrics metrics;
/// 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 OutlinedButton(

View file

@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
# SPDX-License-Identifier: AGPL-3.0-only
name: focus_flow_flutter
description: Provisional Flutter UI foundation for FocusFlow.
publish_to: 'none'

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Tests Forbidden Imports behavior in the FocusFlow Flutter app.
library;
@ -33,6 +36,8 @@ void main() {
});
}
/// Top-level helper that performs the `_dartFiles` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Iterable<File> _dartFiles(Directory directory) {
if (!directory.existsSync()) {
return const <File>[];
@ -43,6 +48,8 @@ Iterable<File> _dartFiles(Directory directory) {
.where((file) => file.path.endsWith('.dart'));
}
/// Top-level helper that performs the `_forbiddenImportsFor` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
List<_ForbiddenImport> _forbiddenImportsFor(String relativePath) {
return [
const _ForbiddenImport(
@ -69,12 +76,23 @@ List<_ForbiddenImport> _forbiddenImportsFor(String relativePath) {
];
}
/// Private implementation type for `_ForbiddenImport` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _ForbiddenImport {
/// Creates a `_ForbiddenImport` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _ForbiddenImport(this.pattern, this.label);
/// Stores the `pattern` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final String pattern;
/// Stores the `label` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final String label;
/// Performs the `matches` behavior for this scheduler component.
/// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
bool matches(String contents) {
return RegExp(
r'''import\s+['"]''' + RegExp.escape(pattern),

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Tests Widget behavior in the FocusFlow Flutter app.
library;
@ -625,6 +628,8 @@ void main() {
});
}
/// Top-level helper that performs the `_pumpPlanApp` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<void> _pumpPlanApp(
WidgetTester tester, {
DemoSchedulerComposition? composition,
@ -637,10 +642,14 @@ Future<void> _pumpPlanApp(
await tester.pumpAndSettle();
}
/// Top-level helper that performs the `_composition` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
DemoSchedulerComposition _composition() {
return DemoSchedulerComposition.seeded(selectedDate: CivilDate(2025, 5, 20));
}
/// Top-level helper that performs the `_readSeededToday` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<TodayState> _readSeededToday() async {
final composition = _composition();
final result = await composition.todayQuery.execute(
@ -652,15 +661,21 @@ Future<TodayState> _readSeededToday() async {
return result.requireValue;
}
/// Top-level helper that performs the `_kindFor` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
TaskVisualKind _kindFor(TodayScreenData data, String id) {
return data.cards.singleWhere((card) => card.id == id).visualKind;
}
/// Top-level helper that performs the `_scrollIntoView` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<void> _scrollIntoView(WidgetTester tester, ValueKey<String> key) async {
await tester.ensureVisible(find.byKey(key));
await tester.pumpAndSettle();
}
/// Top-level helper that performs the `_pumpTimelineCard` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<void> _pumpTimelineCard(
WidgetTester tester, {
required TimelineCardModel card,
@ -688,6 +703,8 @@ Future<void> _pumpTimelineCard(
await tester.pumpAndSettle();
}
/// Top-level helper that performs the `_pumpConstrainedWidget` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<void> _pumpConstrainedWidget(
WidgetTester tester, {
required Size size,
@ -708,6 +725,8 @@ Future<void> _pumpConstrainedWidget(
await tester.pumpAndSettle();
}
/// Top-level helper that performs the `_timelineCard` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
TimelineCardModel _timelineCard({
required String id,
required String title,

View file

@ -0,0 +1,6 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# License
This package uses the repository-level license at [../../LICENSE.md](../../LICENSE.md).

View file

@ -1 +1,4 @@
include: package:lints/recommended.yaml
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
# SPDX-License-Identifier: AGPL-3.0-only
include: ../../analysis_options.yaml

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Runs the Backup command for the Scheduler Backup package.
library;
@ -5,6 +8,8 @@ import 'dart:io';
import 'package:scheduler_backup/backup.dart';
/// Entry point for this executable Dart file.
/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API.
Future<void> main(List<String> arguments) async {
final passphrase = _option(arguments, '--passphrase') ??
Platform.environment['SCHEDULER_BACKUP_PASSPHRASE'];
@ -25,6 +30,8 @@ Future<void> main(List<String> arguments) async {
}
}
/// Top-level helper that performs the `_option` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String? _option(List<String> arguments, String name) {
final index = arguments.indexOf(name);
if (index == -1 || index + 1 >= arguments.length) {

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Encrypted SQLite backup helpers.
library;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Package-name entry point for scheduler backup helpers.
library;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Implements Encrypted Backup behavior for the Scheduler Backup package.
library;
@ -23,11 +26,30 @@ const defaultSchedulerDatabaseFileName = 'scheduler.sqlite';
/// Default encrypted backup directory name under the scheduler data directory.
const defaultSchedulerBackupDirectoryName = 'backups';
/// Private file-level value for `_formatMagic`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _formatMagic = 'ADHD_SCHEDULER_BACKUP_V1';
/// Private file-level value for `_fileExtension`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _fileExtension = '.db.enc';
/// Private file-level value for `_kdfIterations`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _kdfIterations = 200000;
/// Private file-level value for `_saltLength`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _saltLength = 16;
/// Private file-level value for `_nonceLength`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _nonceLength = 12;
/// Private file-level value for `_keyLength`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _keyLength = 32;
/// Private file-level value for `_utf8`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
final _utf8 = utf8.encoder;

View file

@ -1,5 +1,10 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../../encrypted_backup.dart';
/// Top-level helper that performs the `_encryptBytes` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<List<int>> _encryptBytes({
required String passphrase,
required List<int> plaintext,
@ -26,6 +31,8 @@ Future<List<int>> _encryptBytes({
return _utf8.convert(jsonEncode(envelope));
}
/// Top-level helper that performs the `_decryptBytes` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<List<int>> _decryptBytes({
required String passphrase,
required List<int> encoded,
@ -56,6 +63,8 @@ Future<List<int>> _decryptBytes({
}
}
/// Top-level helper that performs the `_deriveKey` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<SecretKey> _deriveKey({
required String passphrase,
required List<int> salt,
@ -71,6 +80,8 @@ Future<SecretKey> _deriveKey({
);
}
/// Top-level helper that performs the `_randomBytes` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
List<int> _randomBytes(int length) {
final random = Random.secure();
return Uint8List.fromList(

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../../encrypted_backup.dart';
/// Thrown when an encrypted backup cannot be decrypted with the passphrase.
@ -10,6 +13,8 @@ final class BackupDecryptionException implements Exception {
/// Diagnostic text for logs and tests.
final String message;
/// Converts scheduler data for `toString` without changing the source object.
/// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details.
@override
String toString() => 'BackupDecryptionException: $message';
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../../encrypted_backup.dart';
/// Thrown when backup input paths or file contents are invalid.
@ -8,6 +11,8 @@ final class BackupException implements Exception {
/// Diagnostic text for logs and tests.
final String message;
/// Converts scheduler data for `toString` without changing the source object.
/// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details.
@override
String toString() => 'BackupException: $message';
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../../encrypted_backup.dart';
/// Create an encrypted backup of the scheduler SQLite file.

View file

@ -1,5 +1,10 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../../encrypted_backup.dart';
/// Top-level helper that performs the `_nextAvailableBackupFile` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<File> _nextAvailableBackupFile(Directory directory, String name) async {
final preferred = File(_joinPath(directory.path, name));
if (!await preferred.exists()) {
@ -19,12 +24,18 @@ Future<File> _nextAvailableBackupFile(Directory directory, String name) async {
}
}
/// Top-level helper that performs the `_backupTimestamp` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _backupTimestamp(DateTime value) {
final local = value.toLocal();
return '${_four(local.year)}${_two(local.month)}${_two(local.day)}_'
'${_two(local.hour)}${_two(local.minute)}';
}
/// Top-level helper that performs the `_four` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _four(int value) => value.toString().padLeft(4, '0');
/// Top-level helper that performs the `_two` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _two(int value) => value.toString().padLeft(2, '0');

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../../encrypted_backup.dart';
/// Default scheduler SQLite database path.
@ -18,6 +21,8 @@ Directory defaultSchedulerBackupDirectory() {
));
}
/// Top-level helper that performs the `_homeDirectory` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Directory _homeDirectory() {
final home = Platform.environment['HOME'] ??
Platform.environment['USERPROFILE'] ??
@ -28,6 +33,8 @@ Directory _homeDirectory() {
return Directory(home);
}
/// Top-level helper that performs the `_joinPath` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _joinPath(String first, String second, [String? third]) {
final separator = Platform.pathSeparator;
final left = first.endsWith(separator)

View file

@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
# SPDX-License-Identifier: AGPL-3.0-only
name: scheduler_backup
description: Encrypted SQLite backup and restore helpers for the ADHD scheduler.
version: 0.1.0

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Tests Encrypted Backup behavior for the Scheduler Backup package.
library;
@ -7,6 +10,8 @@ import 'dart:io';
import 'package:scheduler_backup/backup.dart';
import 'package:test/test.dart';
/// Entry point for this executable Dart file.
/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API.
void main() {
test('encrypted backup round trips a SQLite file using temp paths', () async {
final temp =

View file

@ -0,0 +1,6 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# License
This package uses the repository-level license at [../../LICENSE.md](../../LICENSE.md).

View file

@ -1,13 +1,4 @@
include: package:lints/recommended.yaml
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
# SPDX-License-Identifier: AGPL-3.0-only
analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true
linter:
rules:
prefer_final_locals: true
prefer_final_fields: true
avoid_print: true
include: ../../analysis_options.yaml

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Defines the Scheduler Core public library for the Scheduler Core package.
library;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
/// Implements Application Commands behavior for the Scheduler Core package.
library;

View file

@ -1,22 +1,75 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../../application_commands.dart';
/// Stable V1 application command identifiers.
enum ApplicationCommandCode {
/// Selects the `quickCaptureToBacklog` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
quickCaptureToBacklog,
/// Selects the `quickCaptureToNextAvailableSlot` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
quickCaptureToNextAvailableSlot,
/// Selects the `scheduleBacklogItemToNextAvailableSlot` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
scheduleBacklogItemToNextAvailableSlot,
/// Selects the `pushFlexibleToNextAvailableSlot` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
pushFlexibleToNextAvailableSlot,
/// Selects the `pushFlexibleToTomorrowTopOfQueue` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
pushFlexibleToTomorrowTopOfQueue,
/// Selects the `moveFlexibleToBacklog` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
moveFlexibleToBacklog,
/// Selects the `completeFlexibleTask` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
completeFlexibleTask,
/// Selects the `uncompleteTask` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
uncompleteTask,
/// Selects the `applyRequiredTaskAction` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
applyRequiredTaskAction,
/// Selects the `logSurpriseTask` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
logSurpriseTask,
/// Selects the `createProtectedFreeSlot` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
createProtectedFreeSlot,
/// Selects the `updateProtectedFreeSlot` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
updateProtectedFreeSlot,
/// Selects the `removeProtectedFreeSlot` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
removeProtectedFreeSlot,
/// Selects the `breakUpTask` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
breakUpTask,
/// Selects the `completeChildTask` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
completeChildTask,
/// Selects the `completeParentTask` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
completeParentTask,
/// Selects the `completeParentFromChild` option from this enum.
/// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning.
completeParentFromChild,
}

View file

@ -1,7 +1,12 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../../application_commands.dart';
/// Draft row for creating one child task from an application command.
class ApplicationChildTaskDraft {
/// Creates a `ApplicationChildTaskDraft` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const ApplicationChildTaskDraft({
required this.title,
this.priority,

View file

@ -1,7 +1,12 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../../application_commands.dart';
/// Hint for read models that should be refreshed after a command.
class ApplicationCommandReadHint {
/// Creates a `ApplicationCommandReadHint` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
ApplicationCommandReadHint({
CivilDate? localDate,
Iterable<CivilDate> affectedDates = const <CivilDate>[],

View file

@ -1,7 +1,12 @@
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only
part of '../../application_commands.dart';
/// Structured result returned by V1 application commands.
class ApplicationCommandResult {
/// Creates a `ApplicationCommandResult` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
ApplicationCommandResult({
required this.commandCode,
required String operationId,

Some files were not shown because too many files have changed in this diff Show more