docs: expand dartdocs and add compliance hooks
This commit is contained in:
parent
2485e10873
commit
ec19dd498d
571 changed files with 7637 additions and 30 deletions
15
.githooks/pre-commit
Executable file
15
.githooks/pre-commit
Executable 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
|
||||||
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
|
@ -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.
|
# Runs analyzer, tests, coverage, docs, and tagged desktop packaging.
|
||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
|
|
|
||||||
17
REUSE.toml
Normal file
17
REUSE.toml
Normal 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
17
analysis_options.yaml
Normal 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
|
||||||
6
apps/focus_flow_flutter/LICENSE.md
Normal file
6
apps/focus_flow_flutter/LICENSE.md
Normal 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).
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
|
||||||
|
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
|
||||||
|
|
||||||
# FocusFlow Flutter
|
# FocusFlow Flutter
|
||||||
|
|
||||||
Flutter desktop app target for the FocusFlow UI work.
|
Flutter desktop app target for the FocusFlow UI work.
|
||||||
|
|
|
||||||
|
|
@ -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
|
# This file configures the analyzer, which statically analyzes Dart code to
|
||||||
# check for errors, warnings, and lints.
|
# check for errors, warnings, and lints.
|
||||||
#
|
#
|
||||||
|
|
@ -9,6 +12,12 @@
|
||||||
# packages, and plugins designed to encourage good coding practices.
|
# packages, and plugins designed to encourage good coding practices.
|
||||||
include: package:flutter_lints/flutter.yaml
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
analyzer:
|
||||||
|
language:
|
||||||
|
strict-casts: true
|
||||||
|
strict-inference: true
|
||||||
|
strict-raw-types: true
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
# The lint rules applied to this project can be customized in the
|
# The lint rules applied to this project can be customized in the
|
||||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||||
|
|
@ -22,6 +31,9 @@ linter:
|
||||||
# producing the lint.
|
# producing the lint.
|
||||||
rules:
|
rules:
|
||||||
public_member_api_docs: true
|
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
|
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
/// Exports the FocusFlow Flutter application entry points.
|
/// Exports the FocusFlow Flutter application entry points.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../demo_scheduler_composition.dart';
|
part of '../demo_scheduler_composition.dart';
|
||||||
|
|
||||||
/// Formats a civil date as a long month/day/year label.
|
/// 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}';
|
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]) {
|
DateTime _instant(CivilDate date, int hour, [int minute = 0]) {
|
||||||
return DateTime.utc(date.year, date.month, date.day, hour, minute);
|
return DateTime.utc(date.year, date.month, date.day, hour, minute);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../demo_scheduler_composition.dart';
|
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) {
|
List<Task> _todaySeedTasks(CivilDate date, DateTime createdAt) {
|
||||||
return [
|
return [
|
||||||
_seedTask(
|
_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({
|
Task _seedTask({
|
||||||
required String id,
|
required String id,
|
||||||
required String title,
|
required String title,
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Composes the FocusFlow Flutter application around Demo Scheduler Composition.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -12,6 +15,8 @@ part 'demo/demo_seed_tasks.dart';
|
||||||
|
|
||||||
/// Wires the Flutter demo UI to in-memory scheduler application use cases.
|
/// Wires the Flutter demo UI to in-memory scheduler application use cases.
|
||||||
class DemoSchedulerComposition {
|
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._({
|
DemoSchedulerComposition._({
|
||||||
required this.store,
|
required this.store,
|
||||||
required this.todayQuery,
|
required this.todayQuery,
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Composes the FocusFlow Flutter application around Focus Flow App.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -30,6 +33,8 @@ class FocusFlowApp extends StatelessWidget {
|
||||||
/// Factory and controller bundle used by the app tree.
|
/// Factory and controller bundle used by the app tree.
|
||||||
final DemoSchedulerComposition composition;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../focus_flow_app.dart';
|
part of '../focus_flow_app.dart';
|
||||||
|
|
||||||
/// Stateful home screen that owns the Today controller lifecycle.
|
/// 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.
|
/// Factory and controller bundle used by the home screen.
|
||||||
final DemoSchedulerComposition composition;
|
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
|
@override
|
||||||
State<FocusFlowHome> createState() => _FocusFlowHomeState();
|
State<FocusFlowHome> createState() => _FocusFlowHomeState();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,21 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../focus_flow_app.dart';
|
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> {
|
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;
|
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;
|
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
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
@ -14,6 +26,8 @@ class _FocusFlowHomeState extends State<FocusFlowHome> {
|
||||||
controller.load();
|
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
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
commandController.dispose();
|
commandController.dispose();
|
||||||
|
|
@ -21,6 +35,8 @@ class _FocusFlowHomeState extends State<FocusFlowHome> {
|
||||||
super.dispose();
|
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 {
|
Future<void> _toggleCardCompletion(TimelineCardModel card) async {
|
||||||
if (!card.canToggleCompletion) {
|
if (!card.canToggleCompletion) {
|
||||||
return;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,21 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../focus_flow_app.dart';
|
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 {
|
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});
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Center(
|
return Center(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../focus_flow_app.dart';
|
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 {
|
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({
|
const _TodayScreenScaffold({
|
||||||
required this.data,
|
required this.data,
|
||||||
required this.selectedCard,
|
required this.selectedCard,
|
||||||
|
|
@ -9,12 +16,28 @@ class _TodayScreenScaffold extends StatefulWidget {
|
||||||
required this.onClearSelection,
|
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;
|
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;
|
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;
|
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;
|
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;
|
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
|
@override
|
||||||
State<_TodayScreenScaffold> createState() => _TodayScreenScaffoldState();
|
State<_TodayScreenScaffold> createState() => _TodayScreenScaffoldState();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,21 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../focus_flow_app.dart';
|
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> {
|
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;
|
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;
|
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() {
|
void _showUpcomingRequiredTask() {
|
||||||
final targetCardId = widget.data.requiredBanner?.timelineCardId;
|
final targetCardId = widget.data.requiredBanner?.timelineCardId;
|
||||||
if (targetCardId == null) {
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(
|
return Stack(
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
/// Provides compatibility composition exports for FocusFlow Flutter.
|
/// Provides compatibility composition exports for FocusFlow Flutter.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../scheduler_command_controller.dart';
|
part of '../scheduler_command_controller.dart';
|
||||||
|
|
||||||
/// Builds an application operation context for a UI command operation.
|
/// Builds an application operation context for a UI command operation.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../scheduler_command_controller.dart';
|
part of '../scheduler_command_controller.dart';
|
||||||
|
|
||||||
/// Runs scheduler write commands and exposes command state to widgets.
|
/// 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.
|
/// Clock used by direct UI commands such as marking a task complete.
|
||||||
final DateTime Function() now;
|
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;
|
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();
|
SchedulerCommandState _state = const SchedulerCommandIdle();
|
||||||
|
|
||||||
/// Current command execution state.
|
/// 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({
|
Future<void> _run({
|
||||||
required String label,
|
required String label,
|
||||||
required String successMessage,
|
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() {
|
String _nextOperationId() {
|
||||||
_sequence += 1;
|
_sequence += 1;
|
||||||
return 'ui-command-$_sequence';
|
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) {
|
void _setState(SchedulerCommandState next) {
|
||||||
_state = next;
|
_state = next;
|
||||||
notifyListeners();
|
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();
|
static DateTime _utcNow() => DateTime.now().toUtc();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../scheduler_command_controller.dart';
|
part of '../scheduler_command_controller.dart';
|
||||||
|
|
||||||
/// Base state for scheduler command execution in the UI.
|
/// Base state for scheduler command execution in the UI.
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Coordinates Scheduler Command Controller state for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Coordinates Scheduler Read Controller state for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -84,6 +87,8 @@ class ApplicationReadController<T> extends UiReadController<T> {
|
||||||
/// Predicate used to classify a successful value as empty or populated.
|
/// Predicate used to classify a successful value as empty or populated.
|
||||||
final EmptyPredicate<T> isEmpty;
|
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>();
|
SchedulerReadState<T> _state = SchedulerReadLoading<T>();
|
||||||
|
|
||||||
/// Current read state.
|
/// Current read state.
|
||||||
|
|
@ -116,6 +121,8 @@ class ApplicationReadController<T> extends UiReadController<T> {
|
||||||
@override
|
@override
|
||||||
Future<void> retry() => load();
|
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) {
|
void _setState(SchedulerReadState<T> next) {
|
||||||
_state = next;
|
_state = next;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Coordinates Today Screen Controller state for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -53,7 +56,12 @@ class TodayScreenController extends ChangeNotifier {
|
||||||
/// Callback used to read Today state.
|
/// Callback used to read Today state.
|
||||||
final TodayStateReader read;
|
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();
|
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;
|
TimelineCardModel? _selectedCard;
|
||||||
|
|
||||||
/// Current Today screen loading/data/failure state.
|
/// Current Today screen loading/data/failure state.
|
||||||
|
|
@ -105,6 +113,8 @@ class TodayScreenController extends ChangeNotifier {
|
||||||
notifyListeners();
|
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) {
|
void _syncSelectedCard(TodayScreenData data) {
|
||||||
final selected = _selectedCard;
|
final selected = _selectedCard;
|
||||||
if (selected == null) {
|
if (selected == null) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
/// Launches the FocusFlow Flutter desktop application.
|
/// Launches the FocusFlow Flutter desktop application.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../today_screen_models.dart';
|
part of '../today_screen_models.dart';
|
||||||
|
|
||||||
/// Presentation model for the next-required-task banner.
|
/// Presentation model for the next-required-task banner.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../today_screen_models.dart';
|
part of '../today_screen_models.dart';
|
||||||
|
|
||||||
/// Visual category used to style timeline cards.
|
/// Visual category used to style timeline cards.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../../today_screen_models.dart';
|
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) {
|
String _dateLabel(CivilDate date) {
|
||||||
const months = [
|
const months = [
|
||||||
'January',
|
'January',
|
||||||
|
|
@ -18,6 +23,8 @@ String _dateLabel(CivilDate date) {
|
||||||
return '${months[date.month - 1]} ${date.day}, ${date.year}';
|
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) {
|
int _minutesSinceMidnight(DateTime? value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -25,6 +32,8 @@ int _minutesSinceMidnight(DateTime? value) {
|
||||||
return value.hour * 60 + value.minute;
|
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) {
|
String _formatTime(DateTime? value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return '';
|
return '';
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../today_screen_models.dart';
|
part of '../today_screen_models.dart';
|
||||||
|
|
||||||
/// Presentation model for a single compact timeline card.
|
/// Presentation model for a single compact timeline card.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../today_screen_models.dart';
|
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) {
|
TaskVisualKind _visualKindFor(TodayTimelineItem item) {
|
||||||
if (item.taskStatus == TaskStatus.completed ||
|
if (item.taskStatus == TaskStatus.completed ||
|
||||||
(item.taskType == TaskType.surprise &&
|
(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) {
|
String _typeLabelFor(TaskType taskType, TaskVisualKind visualKind) {
|
||||||
if (visualKind == TaskVisualKind.completedSurprise) {
|
if (visualKind == TaskVisualKind.completedSurprise) {
|
||||||
return 'Completed';
|
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(
|
String _subtitleFor(
|
||||||
TodayTimelineItem item,
|
TodayTimelineItem item,
|
||||||
TaskVisualKind visualKind,
|
TaskVisualKind visualKind,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../today_screen_models.dart';
|
part of '../today_screen_models.dart';
|
||||||
|
|
||||||
/// Visible timeline range expressed as minutes since midnight.
|
/// Visible timeline range expressed as minutes since midnight.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../today_screen_models.dart';
|
part of '../today_screen_models.dart';
|
||||||
|
|
||||||
/// Presentation model for the compact Today screen.
|
/// Presentation model for the compact Today screen.
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Defines Today Screen Models models for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Defines Focus Flow Theme styling for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Defines Focus Flow Tokens styling for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Defines Scheduler Visual Tokens styling for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders the App Shell widget for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -16,6 +19,8 @@ class AppShell extends StatelessWidget {
|
||||||
/// Primary content widget displayed beside the sidebar.
|
/// Primary content widget displayed beside the sidebar.
|
||||||
final Widget child;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ColoredBox(
|
return ColoredBox(
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders the Backlog Pane widget for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -24,6 +27,8 @@ class BacklogPane extends StatelessWidget {
|
||||||
/// Optional command controller for mutating backlog items.
|
/// Optional command controller for mutating backlog items.
|
||||||
final SchedulerCommandController? commandController;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ReadStateView<BacklogQueryResult>(
|
return ReadStateView<BacklogQueryResult>(
|
||||||
|
|
@ -52,6 +57,8 @@ class BacklogContent extends StatelessWidget {
|
||||||
/// Optional command controller for capture and scheduling actions.
|
/// Optional command controller for capture and scheduling actions.
|
||||||
final SchedulerCommandController? commandController;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView(
|
return ListView(
|
||||||
|
|
@ -91,19 +98,29 @@ class QuickCaptureForm extends StatefulWidget {
|
||||||
/// Command controller used to submit captured task titles.
|
/// Command controller used to submit captured task titles.
|
||||||
final SchedulerCommandController commandController;
|
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
|
@override
|
||||||
State<QuickCaptureForm> createState() => _QuickCaptureFormState();
|
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> {
|
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();
|
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
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
titleController.dispose();
|
titleController.dispose();
|
||||||
super.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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
|
|
@ -142,6 +159,8 @@ class CommandStatusBanner extends StatelessWidget {
|
||||||
/// Command controller whose state should be rendered.
|
/// Command controller whose state should be rendered.
|
||||||
final SchedulerCommandController controller;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnimatedBuilder(
|
return AnimatedBuilder(
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders the Read State View widget for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -32,6 +35,8 @@ class ReadStateView<T> extends StatelessWidget {
|
||||||
/// Builds the populated content for a read value.
|
/// Builds the populated content for a read value.
|
||||||
final Widget Function(BuildContext context, T value) dataBuilder;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnimatedBuilder(
|
return AnimatedBuilder(
|
||||||
|
|
@ -82,6 +87,8 @@ class EmptyStatePanel extends StatelessWidget {
|
||||||
/// Optional content shown alongside the empty-state panel.
|
/// Optional content shown alongside the empty-state panel.
|
||||||
final Widget? child;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final panel = Padding(
|
final panel = Padding(
|
||||||
|
|
@ -138,6 +145,8 @@ class FailureStatePanel extends StatelessWidget {
|
||||||
/// Callback invoked when the user retries the read.
|
/// Callback invoked when the user retries the read.
|
||||||
final Future<void> Function() onRetry;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Center(
|
return Center(
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders the Required Banner widget for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -17,6 +20,8 @@ class RequiredBanner extends StatelessWidget {
|
||||||
/// Callback invoked when the highlighted required task should be shown.
|
/// Callback invoked when the highlighted required task should be shown.
|
||||||
final VoidCallback? onShowUpcoming;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final banner = model;
|
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 {
|
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);
|
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;
|
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;
|
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;
|
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) {
|
factory _RequiredBannerMetrics.fromWidth(double width) {
|
||||||
final safeWidth = width.isFinite ? width : _referenceWidth;
|
final safeWidth = width.isFinite ? width : _referenceWidth;
|
||||||
final scale = (safeWidth / _referenceWidth).clamp(_minimumScale, 1.0);
|
final scale = (safeWidth / _referenceWidth).clamp(_minimumScale, 1.0);
|
||||||
return _RequiredBannerMetrics(scale.toDouble());
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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();
|
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;
|
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;
|
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;
|
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();
|
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;
|
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;
|
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);
|
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 {
|
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});
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return OutlinedButton(
|
return OutlinedButton(
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders the Schedule Components widget for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -14,6 +17,8 @@ class CompactPanel extends StatelessWidget {
|
||||||
/// Timeline items to display in compact form.
|
/// Timeline items to display in compact form.
|
||||||
final List<TodayTimelineItem> items;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (items.isEmpty) {
|
if (items.isEmpty) {
|
||||||
|
|
@ -42,6 +47,8 @@ class TimelineRow extends StatelessWidget {
|
||||||
/// Optional completion callback for eligible tasks.
|
/// Optional completion callback for eligible tasks.
|
||||||
final Future<void> Function()? onDone;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
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.
|
/// Optional callback that schedules the item for a duration in minutes.
|
||||||
final Future<void> Function(int durationMinutes)? onSchedule;
|
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
|
@override
|
||||||
State<BacklogRow> createState() => _BacklogRowState();
|
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> {
|
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();
|
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
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
durationController.dispose();
|
durationController.dispose();
|
||||||
super.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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
|
@ -175,6 +192,8 @@ class StalenessMarker extends StatelessWidget {
|
||||||
/// Staleness marker value to render.
|
/// Staleness marker value to render.
|
||||||
final BacklogStalenessMarker marker;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Icon(
|
return Icon(
|
||||||
|
|
@ -192,6 +211,8 @@ class NoticeBanner extends StatelessWidget {
|
||||||
/// Notice message to display.
|
/// Notice message to display.
|
||||||
final String message;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
|
|
@ -216,6 +237,8 @@ String timeText(TimelineItem item) {
|
||||||
return '${_clockText(start)}-${_clockText(end)}';
|
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) {
|
String _clockText(DateTime value) {
|
||||||
final hour = value.hour.toString().padLeft(2, '0');
|
final hour = value.hour.toString().padLeft(2, '0');
|
||||||
final minute = value.minute.toString().padLeft(2, '0');
|
final minute = value.minute.toString().padLeft(2, '0');
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders the Sidebar widget for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -10,6 +13,8 @@ class Sidebar extends StatelessWidget {
|
||||||
/// Creates the FocusFlow sidebar.
|
/// Creates the FocusFlow sidebar.
|
||||||
const Sidebar({super.key});
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DecoratedBox(
|
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 {
|
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();
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const Row(
|
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 {
|
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});
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DecoratedBox(
|
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 {
|
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();
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
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 {
|
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({
|
const _NavItem({
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
|
|
@ -119,11 +148,24 @@ class _NavItem extends StatelessWidget {
|
||||||
this.active = false,
|
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;
|
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;
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final color = active
|
final color = active
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,25 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_selection_modal.dart';
|
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 {
|
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});
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return OutlinedButton.icon(
|
return OutlinedButton.icon(
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,21 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_selection_modal.dart';
|
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 {
|
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});
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const metadataStyle = TextStyle(
|
const metadataStyle = TextStyle(
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,25 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_selection_modal.dart';
|
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 {
|
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});
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_selection_modal.dart';
|
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) {
|
Color _accentFor(TaskVisualKind kind) {
|
||||||
return switch (kind) {
|
return switch (kind) {
|
||||||
TaskVisualKind.flexible => FocusFlowTokens.flexibleGreen,
|
TaskVisualKind.flexible => FocusFlowTokens.flexibleGreen,
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,33 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_selection_modal.dart';
|
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 {
|
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({
|
const _ModalStatusButton({
|
||||||
required this.card,
|
required this.card,
|
||||||
required this.color,
|
required this.color,
|
||||||
required this.onPressed,
|
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;
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ring = Container(
|
final ring = Container(
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders the Task Selection Modal widget for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -33,6 +36,8 @@ class TaskSelectionModal extends StatelessWidget {
|
||||||
/// Callback invoked when the status circle should toggle completion.
|
/// Callback invoked when the status circle should toggle completion.
|
||||||
final VoidCallback? onStatusPressed;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final accent = _accentFor(card.visualKind);
|
final accent = _accentFor(card.visualKind);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../timeline_axis.dart';
|
part of '../timeline_axis.dart';
|
||||||
|
|
||||||
/// Background grid aligned to timeline tick marks.
|
/// Background grid aligned to timeline tick marks.
|
||||||
|
|
@ -11,6 +14,8 @@ class TimelineGrid extends StatelessWidget {
|
||||||
/// Vertical inset before the first timeline tick.
|
/// Vertical inset before the first timeline tick.
|
||||||
final double topInset;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CustomPaint(
|
return CustomPaint(
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,25 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../timeline_axis.dart';
|
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 {
|
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});
|
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;
|
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;
|
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
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
final paint = Paint()
|
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
|
@override
|
||||||
bool shouldRepaint(covariant _TimelineGridPainter oldDelegate) {
|
bool shouldRepaint(covariant _TimelineGridPainter oldDelegate) {
|
||||||
return oldDelegate.geometry != geometry || oldDelegate.topInset != topInset;
|
return oldDelegate.geometry != geometry || oldDelegate.topInset != topInset;
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders Difficulty Bars pieces for the FocusFlow Flutter timeline.
|
||||||
library;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CustomPaint(
|
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 {
|
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({
|
const _DifficultyBarsPainter({
|
||||||
required this.filledCount,
|
required this.filledCount,
|
||||||
required this.color,
|
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;
|
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;
|
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
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
final gap = size.width * 0.08;
|
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
|
@override
|
||||||
bool shouldRepaint(covariant _DifficultyBarsPainter oldDelegate) {
|
bool shouldRepaint(covariant _DifficultyBarsPainter oldDelegate) {
|
||||||
return oldDelegate.filledCount != filledCount || oldDelegate.color != color;
|
return oldDelegate.filledCount != filledCount || oldDelegate.color != color;
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders Reward Icon pieces for the FocusFlow Flutter timeline.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -20,6 +23,8 @@ class RewardIcon extends StatelessWidget {
|
||||||
/// Square size of the painted icon.
|
/// Square size of the painted icon.
|
||||||
final double size;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CustomPaint(
|
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 {
|
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);
|
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;
|
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
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
final paint = Paint()
|
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) {
|
void _drawSparkle(Canvas canvas, Paint paint, Offset center, double radius) {
|
||||||
final path = Path()
|
final path = Path()
|
||||||
..moveTo(center.dx, center.dy - radius)
|
..moveTo(center.dx, center.dy - radius)
|
||||||
|
|
@ -73,6 +88,8 @@ class _RewardIconPainter extends CustomPainter {
|
||||||
canvas.drawPath(path, paint);
|
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
|
@override
|
||||||
bool shouldRepaint(covariant _RewardIconPainter oldDelegate) {
|
bool shouldRepaint(covariant _RewardIconPainter oldDelegate) {
|
||||||
return oldDelegate.color != color;
|
return oldDelegate.color != color;
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,33 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_timeline_card.dart';
|
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 {
|
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({
|
const _CardColors({
|
||||||
required this.accent,
|
required this.accent,
|
||||||
required this.background,
|
required this.background,
|
||||||
required this.reward,
|
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;
|
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;
|
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;
|
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) {
|
factory _CardColors.forKind(TaskVisualKind kind) {
|
||||||
return switch (kind) {
|
return switch (kind) {
|
||||||
TaskVisualKind.flexible => const _CardColors(
|
TaskVisualKind.flexible => const _CardColors(
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,37 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_timeline_card.dart';
|
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 {
|
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});
|
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;
|
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;
|
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;
|
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;
|
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;
|
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(
|
factory _CardMetrics.fromConstraints(
|
||||||
BoxConstraints constraints, {
|
BoxConstraints constraints, {
|
||||||
required TaskVisualKind kind,
|
required TaskVisualKind kind,
|
||||||
|
|
@ -29,42 +52,122 @@ class _CardMetrics {
|
||||||
return _CardMetrics(scale: scale.toDouble(), height: height);
|
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;
|
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;
|
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;
|
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 =>
|
double get cardRadius =>
|
||||||
math.min(FocusFlowTokens.cardRadius * scale, height / 2);
|
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);
|
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;
|
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;
|
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 {
|
double get statusRingSize {
|
||||||
final availableHeight = math.max(8, height - padding.vertical);
|
final availableHeight = math.max(8, height - padding.vertical);
|
||||||
return math.min(24, availableHeight * 0.78).toDouble();
|
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);
|
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;
|
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;
|
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();
|
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();
|
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);
|
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;
|
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);
|
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);
|
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;
|
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;
|
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;
|
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;
|
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;
|
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);
|
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 =>
|
double get indicatorWidth =>
|
||||||
rewardIconSize + indicatorGap + difficultySize.width;
|
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 =>
|
double get expandedTrailingReserve =>
|
||||||
indicatorWidth + math.max(8, 12 * scale);
|
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);
|
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);
|
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 {
|
EdgeInsets get padding {
|
||||||
if (isCompact) {
|
if (isCompact) {
|
||||||
return EdgeInsets.symmetric(
|
return EdgeInsets.symmetric(
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,33 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_timeline_card.dart';
|
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 {
|
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({
|
const _CardText({
|
||||||
required this.card,
|
required this.card,
|
||||||
required this.color,
|
required this.color,
|
||||||
required this.metrics,
|
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;
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final titleStyle = TextStyle(
|
final titleStyle = TextStyle(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_timeline_card.dart';
|
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 {
|
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({
|
const _CompactCardText({
|
||||||
required this.card,
|
required this.card,
|
||||||
required this.color,
|
required this.color,
|
||||||
|
|
@ -8,11 +15,24 @@ class _CompactCardText extends StatelessWidget {
|
||||||
required this.onStatusPressed,
|
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;
|
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;
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final metaText = _compactMetaText(card);
|
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) {
|
String _compactMetaText(TimelineCardModel card) {
|
||||||
if (card.visualKind == TaskVisualKind.freeSlot &&
|
if (card.visualKind == TaskVisualKind.freeSlot &&
|
||||||
card.timeText.isNotEmpty) {
|
card.timeText.isNotEmpty) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_timeline_card.dart';
|
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 {
|
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({
|
const _ExpandedCardContent({
|
||||||
required this.card,
|
required this.card,
|
||||||
required this.colors,
|
required this.colors,
|
||||||
|
|
@ -8,11 +15,24 @@ class _ExpandedCardContent extends StatelessWidget {
|
||||||
required this.onStatusPressed,
|
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;
|
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;
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,33 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_timeline_card.dart';
|
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 {
|
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({
|
const _NoOpIcon({
|
||||||
required this.icon,
|
required this.icon,
|
||||||
required this.color,
|
required this.color,
|
||||||
required this.metrics,
|
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;
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Tooltip(
|
return Tooltip(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_timeline_card.dart';
|
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 {
|
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({
|
const _QuickActions({
|
||||||
required this.color,
|
required this.color,
|
||||||
required this.backgroundColor,
|
required this.backgroundColor,
|
||||||
|
|
@ -8,11 +15,24 @@ class _QuickActions extends StatelessWidget {
|
||||||
required this.visible,
|
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;
|
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;
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ExcludeSemantics(
|
return ExcludeSemantics(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_timeline_card.dart';
|
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 {
|
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({
|
const _StatusRing({
|
||||||
required this.card,
|
required this.card,
|
||||||
required this.color,
|
required this.color,
|
||||||
|
|
@ -8,11 +15,24 @@ class _StatusRing extends StatelessWidget {
|
||||||
this.onPressed,
|
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;
|
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;
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final border = Border.all(color: color, width: metrics.statusBorderWidth);
|
final border = Border.all(color: color, width: metrics.statusBorderWidth);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,17 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_timeline_card.dart';
|
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> {
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final card = widget.card;
|
final card = widget.card;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../task_timeline_card.dart';
|
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 {
|
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({
|
const _TrailingControls({
|
||||||
required this.card,
|
required this.card,
|
||||||
required this.colors,
|
required this.colors,
|
||||||
|
|
@ -8,11 +15,24 @@ class _TrailingControls extends StatelessWidget {
|
||||||
required this.actionsVisible,
|
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;
|
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;
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders Task Timeline Card pieces for the FocusFlow Flutter timeline.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -40,6 +43,8 @@ class TaskTimelineCard extends StatefulWidget {
|
||||||
/// Callback invoked when the left status control is clicked.
|
/// Callback invoked when the left status control is clicked.
|
||||||
final VoidCallback? onStatusPressed;
|
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
|
@override
|
||||||
State<TaskTimelineCard> createState() => _TaskTimelineCardState();
|
State<TaskTimelineCard> createState() => _TaskTimelineCardState();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders Timeline Axis pieces for the FocusFlow Flutter timeline.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -20,6 +23,8 @@ class TimelineAxis extends StatelessWidget {
|
||||||
/// Vertical inset before the first timeline tick.
|
/// Vertical inset before the first timeline tick.
|
||||||
final double topInset;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ticks = geometry.ticks();
|
final ticks = geometry.ticks();
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders Timeline Geometry pieces for the FocusFlow Flutter timeline.
|
||||||
library;
|
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
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) ||
|
return identical(this, other) ||
|
||||||
|
|
@ -70,6 +75,8 @@ class TimelineGeometry {
|
||||||
other.minCardHeight == minCardHeight;
|
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
|
@override
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
return Object.hash(
|
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) {
|
static String _labelFor(int minutes) {
|
||||||
final hour24 = (minutes ~/ 60) % 24;
|
final hour24 = (minutes ~/ 60) % 24;
|
||||||
final minute = minutes % 60;
|
final minute = minutes % 60;
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders Timeline View pieces for the FocusFlow Flutter timeline.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -49,6 +52,8 @@ class TimelineView extends StatefulWidget {
|
||||||
/// Monotonic request number that allows repeated jumps to the same card.
|
/// Monotonic request number that allows repeated jumps to the same card.
|
||||||
final int scrollRequest;
|
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
|
@override
|
||||||
State<TimelineView> createState() => _TimelineViewState();
|
State<TimelineView> createState() => _TimelineViewState();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../timeline_view.dart';
|
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 {
|
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({
|
const _TimelineCardPlacement({
|
||||||
required this.card,
|
required this.card,
|
||||||
required this.lane,
|
required this.lane,
|
||||||
|
|
@ -9,14 +16,32 @@ class _TimelineCardPlacement {
|
||||||
required this.height,
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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) {
|
_TimelineCardPlacement withCard(TimelineCardModel nextCard) {
|
||||||
if (identical(card, nextCard)) {
|
if (identical(card, nextCard)) {
|
||||||
return this;
|
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(
|
static List<_TimelineCardPlacement> pack(
|
||||||
List<TimelineCardModel> cards, {
|
List<TimelineCardModel> cards, {
|
||||||
required TimelineGeometry geometry,
|
required TimelineGeometry geometry,
|
||||||
|
|
@ -74,6 +101,8 @@ class _TimelineCardPlacement {
|
||||||
return placements;
|
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(
|
static List<_TimelineCardPlacement> _packGroup(
|
||||||
List<TimelineCardModel> group, {
|
List<TimelineCardModel> group, {
|
||||||
required TimelineGeometry geometry,
|
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(
|
static double _visualStart(
|
||||||
TimelineCardModel card,
|
TimelineCardModel card,
|
||||||
TimelineGeometry geometry,
|
TimelineGeometry geometry,
|
||||||
|
|
@ -120,21 +151,29 @@ class _TimelineCardPlacement {
|
||||||
return geometry.yForMinutesSinceMidnight(card.startMinutes);
|
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) {
|
static double _visualEnd(TimelineCardModel card, TimelineGeometry geometry) {
|
||||||
final duration = card.endMinutes - card.startMinutes;
|
final duration = card.endMinutes - card.startMinutes;
|
||||||
return _visualStart(card, geometry) + geometry.heightForDuration(duration);
|
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) {
|
double left(double trackWidth) {
|
||||||
final laneWidth = _laneWidth(trackWidth);
|
final laneWidth = _laneWidth(trackWidth);
|
||||||
final laneGap = _laneGapForWidth(trackWidth);
|
final laneGap = _laneGapForWidth(trackWidth);
|
||||||
return FocusFlowTokens.cardHorizontalPadding + lane * (laneWidth + laneGap);
|
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) {
|
double width(double trackWidth) {
|
||||||
return _laneWidth(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) {
|
double _availableWidth(double trackWidth) {
|
||||||
final availableWidth = trackWidth - FocusFlowTokens.cardHorizontalPadding;
|
final availableWidth = trackWidth - FocusFlowTokens.cardHorizontalPadding;
|
||||||
if (availableWidth < 0) {
|
if (availableWidth < 0) {
|
||||||
|
|
@ -143,12 +182,16 @@ class _TimelineCardPlacement {
|
||||||
return availableWidth;
|
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) {
|
double _laneWidth(double trackWidth) {
|
||||||
final availableWidth = _availableWidth(trackWidth);
|
final availableWidth = _availableWidth(trackWidth);
|
||||||
final laneGap = _laneGapForWidth(trackWidth);
|
final laneGap = _laneGapForWidth(trackWidth);
|
||||||
return (availableWidth - laneGap * (laneCount - 1)) / laneCount;
|
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) {
|
double _laneGapForWidth(double trackWidth) {
|
||||||
if (laneCount == 1) {
|
if (laneCount == 1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,17 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../timeline_view.dart';
|
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 {
|
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();
|
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
|
@override
|
||||||
Set<PointerDeviceKind> get dragDevices {
|
Set<PointerDeviceKind> get dragDevices {
|
||||||
return {...super.dragDevices, PointerDeviceKind.mouse};
|
return {...super.dragDevices, PointerDeviceKind.mouse};
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,53 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../timeline_view.dart';
|
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> {
|
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;
|
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();
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_updateLayoutCache();
|
_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
|
@override
|
||||||
void didUpdateWidget(covariant TimelineView oldWidget) {
|
void didUpdateWidget(covariant TimelineView oldWidget) {
|
||||||
super.didUpdateWidget(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
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_scrollController.dispose();
|
_scrollController.dispose();
|
||||||
super.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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return LayoutBuilder(
|
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() {
|
void _updateLayoutCache() {
|
||||||
_geometry = TimelineGeometry(
|
_geometry = TimelineGeometry(
|
||||||
startMinutes: widget.range.startMinutes,
|
startMinutes: widget.range.startMinutes,
|
||||||
|
|
@ -125,6 +162,8 @@ class _TimelineViewState extends State<TimelineView> {
|
||||||
_cardsLayoutHash = _layoutHashFor(widget.cards);
|
_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) {
|
int _layoutHashFor(List<TimelineCardModel> cards) {
|
||||||
return Object.hashAll(
|
return Object.hashAll(
|
||||||
cards.map(
|
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() {
|
void _refreshPlacementCards() {
|
||||||
final cardsById = {for (final card in widget.cards) card.id: card};
|
final cardsById = {for (final card in widget.cards) card.id: card};
|
||||||
_placements = [
|
_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(
|
void _scheduleInitialScroll(
|
||||||
TimelineGeometry geometry,
|
TimelineGeometry geometry,
|
||||||
double viewportHeight,
|
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) {
|
void _scheduleTargetScroll(TimelineGeometry geometry) {
|
||||||
final targetCardId = widget.scrollTargetCardId;
|
final targetCardId = widget.scrollTargetCardId;
|
||||||
if (targetCardId == null || widget.scrollRequest == _handledScrollRequest) {
|
if (targetCardId == null || widget.scrollRequest == _handledScrollRequest) {
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders the Today Pane widget for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -24,6 +27,8 @@ class TodayPane extends StatelessWidget {
|
||||||
/// Optional command controller for Today actions.
|
/// Optional command controller for Today actions.
|
||||||
final SchedulerCommandController? commandController;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ReadStateView<TodayState>(
|
return ReadStateView<TodayState>(
|
||||||
|
|
@ -48,6 +53,8 @@ class TodayContent extends StatelessWidget {
|
||||||
/// Optional command controller for completing tasks.
|
/// Optional command controller for completing tasks.
|
||||||
final SchedulerCommandController? commandController;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView(
|
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) {
|
bool _canComplete(TodayTimelineItem item) {
|
||||||
return item.taskType == TaskType.flexible &&
|
return item.taskType == TaskType.flexible &&
|
||||||
item.taskStatus == TaskStatus.planned &&
|
item.taskStatus == TaskStatus.planned &&
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Renders the Top Bar widget for the FocusFlow Flutter UI.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -18,6 +21,8 @@ class TopBar extends StatelessWidget {
|
||||||
/// Date label shown beside the date navigation controls.
|
/// Date label shown beside the date navigation controls.
|
||||||
final String dateLabel;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,33 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../top_bar.dart';
|
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 {
|
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({
|
const _IconButton({
|
||||||
required this.icon,
|
required this.icon,
|
||||||
required this.metrics,
|
required this.metrics,
|
||||||
required this.onPressed,
|
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;
|
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;
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return IconButton(
|
return IconButton(
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,116 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../top_bar.dart';
|
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 {
|
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);
|
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;
|
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;
|
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;
|
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) {
|
factory _TopBarMetrics.fromWidth(double width) {
|
||||||
final safeWidth = width.isFinite ? width : _referenceWidth;
|
final safeWidth = width.isFinite ? width : _referenceWidth;
|
||||||
final scale = (safeWidth / _referenceWidth).clamp(_minimumScale, 1.0);
|
final scale = (safeWidth / _referenceWidth).clamp(_minimumScale, 1.0);
|
||||||
return _TopBarMetrics(scale.toDouble());
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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);
|
EdgeInsets get buttonPadding => EdgeInsets.symmetric(horizontal: 12 * scale);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,21 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../top_bar.dart';
|
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 {
|
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});
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,21 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../top_bar.dart';
|
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 {
|
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});
|
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;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return OutlinedButton(
|
return OutlinedButton(
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
name: focus_flow_flutter
|
name: focus_flow_flutter
|
||||||
description: Provisional Flutter UI foundation for FocusFlow.
|
description: Provisional Flutter UI foundation for FocusFlow.
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Tests Forbidden Imports behavior in the FocusFlow Flutter app.
|
||||||
library;
|
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) {
|
Iterable<File> _dartFiles(Directory directory) {
|
||||||
if (!directory.existsSync()) {
|
if (!directory.existsSync()) {
|
||||||
return const <File>[];
|
return const <File>[];
|
||||||
|
|
@ -43,6 +48,8 @@ Iterable<File> _dartFiles(Directory directory) {
|
||||||
.where((file) => file.path.endsWith('.dart'));
|
.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) {
|
List<_ForbiddenImport> _forbiddenImportsFor(String relativePath) {
|
||||||
return [
|
return [
|
||||||
const _ForbiddenImport(
|
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 {
|
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);
|
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;
|
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;
|
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) {
|
bool matches(String contents) {
|
||||||
return RegExp(
|
return RegExp(
|
||||||
r'''import\s+['"]''' + RegExp.escape(pattern),
|
r'''import\s+['"]''' + RegExp.escape(pattern),
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
/// Tests Widget behavior in the FocusFlow Flutter app.
|
/// Tests Widget behavior in the FocusFlow Flutter app.
|
||||||
library;
|
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(
|
Future<void> _pumpPlanApp(
|
||||||
WidgetTester tester, {
|
WidgetTester tester, {
|
||||||
DemoSchedulerComposition? composition,
|
DemoSchedulerComposition? composition,
|
||||||
|
|
@ -637,10 +642,14 @@ Future<void> _pumpPlanApp(
|
||||||
await tester.pumpAndSettle();
|
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() {
|
DemoSchedulerComposition _composition() {
|
||||||
return DemoSchedulerComposition.seeded(selectedDate: CivilDate(2025, 5, 20));
|
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 {
|
Future<TodayState> _readSeededToday() async {
|
||||||
final composition = _composition();
|
final composition = _composition();
|
||||||
final result = await composition.todayQuery.execute(
|
final result = await composition.todayQuery.execute(
|
||||||
|
|
@ -652,15 +661,21 @@ Future<TodayState> _readSeededToday() async {
|
||||||
return result.requireValue;
|
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) {
|
TaskVisualKind _kindFor(TodayScreenData data, String id) {
|
||||||
return data.cards.singleWhere((card) => card.id == id).visualKind;
|
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 {
|
Future<void> _scrollIntoView(WidgetTester tester, ValueKey<String> key) async {
|
||||||
await tester.ensureVisible(find.byKey(key));
|
await tester.ensureVisible(find.byKey(key));
|
||||||
await tester.pumpAndSettle();
|
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(
|
Future<void> _pumpTimelineCard(
|
||||||
WidgetTester tester, {
|
WidgetTester tester, {
|
||||||
required TimelineCardModel card,
|
required TimelineCardModel card,
|
||||||
|
|
@ -688,6 +703,8 @@ Future<void> _pumpTimelineCard(
|
||||||
await tester.pumpAndSettle();
|
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(
|
Future<void> _pumpConstrainedWidget(
|
||||||
WidgetTester tester, {
|
WidgetTester tester, {
|
||||||
required Size size,
|
required Size size,
|
||||||
|
|
@ -708,6 +725,8 @@ Future<void> _pumpConstrainedWidget(
|
||||||
await tester.pumpAndSettle();
|
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({
|
TimelineCardModel _timelineCard({
|
||||||
required String id,
|
required String id,
|
||||||
required String title,
|
required String title,
|
||||||
|
|
|
||||||
6
packages/scheduler_backup/LICENSE.md
Normal file
6
packages/scheduler_backup/LICENSE.md
Normal 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).
|
||||||
|
|
@ -1 +1,4 @@
|
||||||
include: package:lints/recommended.yaml
|
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
include: ../../analysis_options.yaml
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Runs the Backup command for the Scheduler Backup package.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -5,6 +8,8 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:scheduler_backup/backup.dart';
|
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 {
|
Future<void> main(List<String> arguments) async {
|
||||||
final passphrase = _option(arguments, '--passphrase') ??
|
final passphrase = _option(arguments, '--passphrase') ??
|
||||||
Platform.environment['SCHEDULER_BACKUP_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) {
|
String? _option(List<String> arguments, String name) {
|
||||||
final index = arguments.indexOf(name);
|
final index = arguments.indexOf(name);
|
||||||
if (index == -1 || index + 1 >= arguments.length) {
|
if (index == -1 || index + 1 >= arguments.length) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
/// Encrypted SQLite backup helpers.
|
/// Encrypted SQLite backup helpers.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
/// Package-name entry point for scheduler backup helpers.
|
/// Package-name entry point for scheduler backup helpers.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Implements Encrypted Backup behavior for the Scheduler Backup package.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -23,11 +26,30 @@ const defaultSchedulerDatabaseFileName = 'scheduler.sqlite';
|
||||||
/// Default encrypted backup directory name under the scheduler data directory.
|
/// Default encrypted backup directory name under the scheduler data directory.
|
||||||
const defaultSchedulerBackupDirectoryName = 'backups';
|
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';
|
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';
|
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;
|
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;
|
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;
|
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;
|
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;
|
final _utf8 = utf8.encoder;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../../encrypted_backup.dart';
|
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({
|
Future<List<int>> _encryptBytes({
|
||||||
required String passphrase,
|
required String passphrase,
|
||||||
required List<int> plaintext,
|
required List<int> plaintext,
|
||||||
|
|
@ -26,6 +31,8 @@ Future<List<int>> _encryptBytes({
|
||||||
return _utf8.convert(jsonEncode(envelope));
|
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({
|
Future<List<int>> _decryptBytes({
|
||||||
required String passphrase,
|
required String passphrase,
|
||||||
required List<int> encoded,
|
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({
|
Future<SecretKey> _deriveKey({
|
||||||
required String passphrase,
|
required String passphrase,
|
||||||
required List<int> salt,
|
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) {
|
List<int> _randomBytes(int length) {
|
||||||
final random = Random.secure();
|
final random = Random.secure();
|
||||||
return Uint8List.fromList(
|
return Uint8List.fromList(
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../../encrypted_backup.dart';
|
part of '../../encrypted_backup.dart';
|
||||||
|
|
||||||
/// Thrown when an encrypted backup cannot be decrypted with the passphrase.
|
/// 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.
|
/// Diagnostic text for logs and tests.
|
||||||
final String message;
|
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
|
@override
|
||||||
String toString() => 'BackupDecryptionException: $message';
|
String toString() => 'BackupDecryptionException: $message';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../../encrypted_backup.dart';
|
part of '../../encrypted_backup.dart';
|
||||||
|
|
||||||
/// Thrown when backup input paths or file contents are invalid.
|
/// 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.
|
/// Diagnostic text for logs and tests.
|
||||||
final String message;
|
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
|
@override
|
||||||
String toString() => 'BackupException: $message';
|
String toString() => 'BackupException: $message';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../../encrypted_backup.dart';
|
part of '../../encrypted_backup.dart';
|
||||||
|
|
||||||
/// Create an encrypted backup of the scheduler SQLite file.
|
/// Create an encrypted backup of the scheduler SQLite file.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../../encrypted_backup.dart';
|
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 {
|
Future<File> _nextAvailableBackupFile(Directory directory, String name) async {
|
||||||
final preferred = File(_joinPath(directory.path, name));
|
final preferred = File(_joinPath(directory.path, name));
|
||||||
if (!await preferred.exists()) {
|
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) {
|
String _backupTimestamp(DateTime value) {
|
||||||
final local = value.toLocal();
|
final local = value.toLocal();
|
||||||
return '${_four(local.year)}${_two(local.month)}${_two(local.day)}_'
|
return '${_four(local.year)}${_two(local.month)}${_two(local.day)}_'
|
||||||
'${_two(local.hour)}${_two(local.minute)}';
|
'${_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');
|
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');
|
String _two(int value) => value.toString().padLeft(2, '0');
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../../encrypted_backup.dart';
|
part of '../../encrypted_backup.dart';
|
||||||
|
|
||||||
/// Default scheduler SQLite database path.
|
/// 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() {
|
Directory _homeDirectory() {
|
||||||
final home = Platform.environment['HOME'] ??
|
final home = Platform.environment['HOME'] ??
|
||||||
Platform.environment['USERPROFILE'] ??
|
Platform.environment['USERPROFILE'] ??
|
||||||
|
|
@ -28,6 +33,8 @@ Directory _homeDirectory() {
|
||||||
return Directory(home);
|
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]) {
|
String _joinPath(String first, String second, [String? third]) {
|
||||||
final separator = Platform.pathSeparator;
|
final separator = Platform.pathSeparator;
|
||||||
final left = first.endsWith(separator)
|
final left = first.endsWith(separator)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
name: scheduler_backup
|
name: scheduler_backup
|
||||||
description: Encrypted SQLite backup and restore helpers for the ADHD scheduler.
|
description: Encrypted SQLite backup and restore helpers for the ADHD scheduler.
|
||||||
version: 0.1.0
|
version: 0.1.0
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Tests Encrypted Backup behavior for the Scheduler Backup package.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
@ -7,6 +10,8 @@ import 'dart:io';
|
||||||
import 'package:scheduler_backup/backup.dart';
|
import 'package:scheduler_backup/backup.dart';
|
||||||
import 'package:test/test.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() {
|
void main() {
|
||||||
test('encrypted backup round trips a SQLite file using temp paths', () async {
|
test('encrypted backup round trips a SQLite file using temp paths', () async {
|
||||||
final temp =
|
final temp =
|
||||||
|
|
|
||||||
6
packages/scheduler_core/LICENSE.md
Normal file
6
packages/scheduler_core/LICENSE.md
Normal 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).
|
||||||
|
|
@ -1,13 +1,4 @@
|
||||||
include: package:lints/recommended.yaml
|
# SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
analyzer:
|
include: ../../analysis_options.yaml
|
||||||
language:
|
|
||||||
strict-casts: true
|
|
||||||
strict-inference: true
|
|
||||||
strict-raw-types: true
|
|
||||||
|
|
||||||
linter:
|
|
||||||
rules:
|
|
||||||
prefer_final_locals: true
|
|
||||||
prefer_final_fields: true
|
|
||||||
avoid_print: true
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Defines the Scheduler Core public library for the Scheduler Core package.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// Implements Application Commands behavior for the Scheduler Core package.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,75 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../../application_commands.dart';
|
part of '../../application_commands.dart';
|
||||||
|
|
||||||
/// Stable V1 application command identifiers.
|
/// Stable V1 application command identifiers.
|
||||||
enum ApplicationCommandCode {
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
completeParentFromChild,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../../application_commands.dart';
|
part of '../../application_commands.dart';
|
||||||
|
|
||||||
/// Draft row for creating one child task from an application command.
|
/// Draft row for creating one child task from an application command.
|
||||||
class ApplicationChildTaskDraft {
|
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({
|
const ApplicationChildTaskDraft({
|
||||||
required this.title,
|
required this.title,
|
||||||
this.priority,
|
this.priority,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../../application_commands.dart';
|
part of '../../application_commands.dart';
|
||||||
|
|
||||||
/// Hint for read models that should be refreshed after a command.
|
/// Hint for read models that should be refreshed after a command.
|
||||||
class ApplicationCommandReadHint {
|
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({
|
ApplicationCommandReadHint({
|
||||||
CivilDate? localDate,
|
CivilDate? localDate,
|
||||||
Iterable<CivilDate> affectedDates = const <CivilDate>[],
|
Iterable<CivilDate> affectedDates = const <CivilDate>[],
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 FocusFlow contributors
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
part of '../../application_commands.dart';
|
part of '../../application_commands.dart';
|
||||||
|
|
||||||
/// Structured result returned by V1 application commands.
|
/// Structured result returned by V1 application commands.
|
||||||
class ApplicationCommandResult {
|
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({
|
ApplicationCommandResult({
|
||||||
required this.commandCode,
|
required this.commandCode,
|
||||||
required String operationId,
|
required String operationId,
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue