focus-flow/apps/focus_flow_flutter
pyr0ball 6f0da3c8aa feat(ui): wire Settings dialog to persisted OwnerSettings
Adds a getOwnerSettings read query to scheduler_core (previously only
an internal helper existed) and an updateOwnerSettings command on the
Flutter command controller, then builds a shared Settings dialog
surfacing timezone, day window, compact mode, and backlog staleness
thresholds. Both existing no-op entry points (sidebar nav item, top
bar button) now open the same dialog and persist edits through the
existing OwnerSettings/BacklogStalenessSettings backend.

Per the design spec (circuitforge-plans/focus-flow/superpowers/specs/
2026-07-07-settings-screen-design.md), the compact-mode toggle
persists but is disclosed in-UI as not yet affecting Today rendering,
since that wiring is separate scope (#11).

Closes: #16
2026-07-07 14:38:16 -07:00
..
lib feat(ui): wire Settings dialog to persisted OwnerSettings 2026-07-07 14:38:16 -07:00
linux feat: add timeline task context menu 2026-07-01 20:22:06 -07:00
test feat(ui): wire Settings dialog to persisted OwnerSettings 2026-07-07 14:38:16 -07:00
windows feat: complete sqlite runtime persistence plan 2026-07-01 19:40:56 -07:00
.gitignore feat: add flutter ui foundation 2026-06-27 18:41:36 -07:00
.metadata feat: add timeline task context menu 2026-07-01 20:22:06 -07:00
analysis_options.yaml docs: expand dartdocs and add compliance hooks 2026-07-01 13:36:12 -07:00
config.example.json feat(scheduler): support timezone-aware commands and task removal 2026-07-04 22:16:02 -07:00
LICENSE.md docs: expand dartdocs and add compliance hooks 2026-07-01 13:36:12 -07:00
pubspec.lock feat: complete sqlite runtime persistence plan 2026-07-01 19:40:56 -07:00
pubspec.yaml feat: complete sqlite runtime persistence plan 2026-07-01 19:40:56 -07:00
README.md feat(ui): wire timeline card Break up quick action 2026-07-07 13:45:04 -07:00

FocusFlow Flutter

Flutter desktop app target for the FocusFlow UI work.

Current Scope

The app launches into the compact Today timeline. Normal startup now opens an on-disk SQLite database and bootstraps owner settings plus the default Home project when they are missing.

The compact Today screen can toggle completion for currently rendered task cards. The sidebar switches between the Today and Backlog screens, and the Backlog screen supports quick capture and scheduling backlog items.

Runtime Data

Normal runtime uses lib/app/persistent_scheduler_composition.dart, which reads SCHEDULER_SQLITE_PATH from a Dart define. If no define is present, it uses the local dev convention:

~/ADHD_Scheduler/scheduler.sqlite

Static demo data still lives in lib/app/demo_scheduler_composition.dart, but it is for deterministic widget/visual tests and explicit demo composition only. It is not inserted during normal startup.

Widgets consume TodayScreenData from lib/models/today_screen_models.dart. Scheduler core remains the source of truth for task state and Today ordering.

Runtime Config

The app optionally reads a JSON config file from:

~/ADHD_Scheduler/config.json

Override the config path with:

flutter run -d linux --dart-define=FOCUS_FLOW_CONFIG_PATH=/tmp/focus_flow_config.json

Supported optional keys:

{
  "Timezone": "UTC",
  "LogLevel": "fine",
  "LogfileLocation": "~/ADHD_Scheduler/debug/"
}

Timezone accepts a three-letter time-zone code without regard to character case, such as UTC, GMT, PST, or PDT. Common daylight-saving pairs such as PST/PDT, MST/MDT, CST/CDT, and EST/EDT are resolved once when the config loads, so either seasonal abbreviation uses the correct current offset for that zone during the app session. The setting is an app/UI reference only: it controls wall-clock timeline display, selected-day startup, and time-relative actions such as pushing a task to the next slot or tomorrow. Task instants and all persistence data remain stored as UTC/GMT values.

LogLevel accepts finest, finer, fine, debug, info, warn, or error. LogfileLocation is treated as a directory, and the app writes focus_flow.log inside it. If either key is absent or invalid, file logging is not enabled and the app ignores that setting.

Verbose log levels can include automatic caller information without requiring each call site to pass it manually. finest includes caller frames for every written message. fine, finer, and finest include caller frames for warnings and errors. This caller lookup is skipped when the configured level does not require it.

For expensive debug/detail messages, pass a lazy closure so work is skipped when the configured level would not write the log:

logger.debug(() => 'state=${expensiveStateDump()}');

Package Boundary

Allowed app imports include public scheduler APIs such as:

import 'package:scheduler_core/scheduler_core.dart';

The persistent composition root may import package:scheduler_persistence_sqlite/sqlite.dart and dart:io for runtime path resolution. Widgets/controllers must not import scheduler src/ files, Drift, SQLite adapters, desktop notification implementations, backup/export packages, or direct OS APIs. test/forbidden_imports_test.dart enforces that boundary.

Intentionally No-op

  • Compact/Normal toggle.
  • Settings button.
  • Timeline card Schedule and Protect time icons.

Persistence Proof

Current focused tests prove:

  • first run opens an empty SQLite file without seeded task rows,
  • quick capture writes a backlog task,
  • scheduling writes planned Today placement,
  • done and not-done state persists,
  • closing and reopening the same SQLite file reloads the task state.

Manual verification:

scripts/bootstrap_dev.sh
scripts/dev.sh --sqlite /tmp/focus_flow_persistence_plan_1.sqlite

Use the same --sqlite path after closing the app to confirm state persists. To reset local dev data, close the app and delete the chosen .sqlite file. This is only a dev reset; backup/restore UI remains out of scope.

Commands

Run scripts/bootstrap_dev.sh once from the repository root to create the default SQLite directory.

Run the desktop UI from this directory:

flutter pub get
flutter run -d linux

Replace linux with macos or windows on those hosts. The default database path is ~/ADHD_Scheduler/scheduler.sqlite. If Flutter reports that the desktop project is not configured for that platform, generate the missing runner from this directory:

flutter create --platforms=linux .

Use --platforms=macos or --platforms=windows for those hosts.

Use a disposable dev database when needed:

flutter run -d linux --dart-define=SCHEDULER_SQLITE_PATH=/tmp/focus_flow_dev.sqlite

Check the app from this directory:

flutter analyze
flutter test

Run these from apps/focus_flow_flutter/.

Next Plans

  • Give the Compact/Normal toggle real backing state (the live Today pipeline has no compact-mode concept yet; see Forgejo issue #11).
  • Add a real Settings screen bound to existing OwnerSettings/ BacklogStalenessSettings persistence.
  • Add Shield/Recovery only in a later scope.