feat: add timeline task context menu

This commit is contained in:
Ashley Venn 2026-07-01 20:22:06 -07:00
parent 94e39545fa
commit 0c1731003f
124 changed files with 2343 additions and 1524 deletions

View file

@ -0,0 +1,129 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Date Selection 01 Block 01 — Scope and Baseline
**Status:** Planned.
**Goal:** Verify the persistence-backed app baseline and lock the exact semantics
for date selection before implementing UI callbacks.
---
## Block outcome
After this block, the repo state and product behavior for date navigation should
be explicit. Later blocks should be able to implement date switching without
reopening architectural decisions.
---
## Chunk 1.1 — Confirm persistence prerequisite
### Tasks
1. Confirm Persistence Plan 1 is complete in the current branch.
2. Verify normal app startup no longer inserts arbitrary demo timeline tasks.
3. Verify app startup opens an on-disk SQLite database through the approved
runtime composition.
4. Verify quick capture, schedule-from-backlog, complete, uncomplete, close, and
reopen already work for the default selected date.
5. Record any missing persistence behavior as a blocker before continuing.
### Acceptance criteria
- Date Selection 01 does not start from demo seed runtime.
- The app has one durable persistence path for normal startup.
- Any missing Persistence Plan 1 behavior is documented and fixed before Block 02.
---
## Chunk 1.2 — Reconcile current composition and controller boundaries
### Tasks
1. Inspect the current post-persistence composition root.
2. Identify the object that owns:
- `GetTodayStateQuery`,
- `V1ApplicationCommandUseCases`,
- `V1ApplicationManagementUseCases`,
- owner id,
- owner timezone,
- runtime clock,
- SQLite lifecycle/disposal.
3. Identify whether `DemoSchedulerComposition` still exists only for tests or
explicit demo mode.
4. Decide whether selected date should live in:
- a dedicated `SelectedDateController`,
- an expanded `TodayScreenController`, or
- parent `FocusFlowHome` state that reconfigures date-aware controllers.
5. Prefer the smallest design that keeps date behavior testable and does not
force widgets to know scheduler internals.
### Acceptance criteria
- The selected-date owner is named in the implementation notes for this block.
- Composition APIs can create reads/commands for arbitrary `CivilDate` values.
- No widget is planned to instantiate repositories, Drift classes, or scheduler
engine objects.
---
## Chunk 1.3 — Lock selected-date semantics
### Tasks
1. Define selected date as the currently visible planning day in the owner's
timezone.
2. Confirm selected date changes are read-only until the user runs a command.
3. Confirm arrows move exactly one civil day at a time.
4. Confirm the date picker jumps directly to the chosen civil date.
5. Confirm command timestamps use the real runtime clock, not the selected date
as a fake `now`.
6. Confirm scheduling a backlog task while viewing a selected day targets that
selected day's planning window.
7. Confirm completing a future/past selected-day task records the actual
completion instant from the runtime clock.
### Acceptance criteria
- Date navigation cannot itself create, move, complete, or delete tasks.
- Date navigation uses `CivilDate` at app boundaries.
- Instant/date conversion happens through existing owner timezone utilities.
---
## Chunk 1.4 — Identify tests to preserve before edits
### Tasks
1. Locate existing Flutter widget tests for the top bar, timeline, modal, and
Today screen controller.
2. Locate persistence lifecycle tests added by Persistence Plan 1.
3. Locate scheduler-core tests for `GetTodayStateQuery` and command use cases.
4. Add a small checklist of tests that must still pass after this plan.
### Acceptance criteria
- The validation targets for later blocks are known before code changes begin.
- Existing tests are not deleted or weakened to make date selection pass.
---
## Block acceptance criteria
- Persistence prerequisite is verified.
- Selected-date state ownership is decided.
- Selected-date behavior is documented.
- Tests and validation commands for the plan are known.
## Validation after block
```sh
scripts/test.sh
cd apps/focus_flow_flutter
flutter test
```
If Flutter tooling is unavailable, run all non-Flutter package tests and document
that Flutter validation is blocked by environment setup.

View file

@ -0,0 +1,119 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Date Selection 01 Block 02 — Selected-Date State and Reads
**Status:** Planned.
**Goal:** Make Today screen loading date-aware without changing task state.
---
## Block outcome
After this block, app/controller code can load Today data for any selected
`CivilDate`. The visual top-bar buttons may still be disabled until Block 03.
---
## Chunk 2.1 — Add selected-date state API
### Tasks
1. Add the selected-date owner chosen in Block 01.
2. Expose the current selected `CivilDate`.
3. Expose commands to:
- select a specific date,
- move to previous day,
- move to next day,
- optionally return to current owner-local day if the current UI has a
calendar/today affordance.
4. Ensure repeated selection of the current date is a no-op.
5. Ensure date changes notify exactly the controllers/widgets that need a
reload.
### Acceptance criteria
- Date state can be tested without rendering the full app.
- Date mutation does not call scheduler command use cases.
- Date mutation can trigger read refresh in one predictable place.
---
## Chunk 2.2 — Make Today reads accept a date parameter
### Tasks
1. Replace fixed-date read callbacks with date-aware read callbacks, for example:
`Future<ApplicationResult<TodayState>> Function(CivilDate date)`.
2. Update `TodayScreenController.load` or equivalent to load the selected date.
3. Keep `GetTodayStateRequest.date` as the canonical read parameter.
4. Preserve `includeNextFlexibleItem: true` unless a later product decision
changes it.
5. Avoid filtering persisted tasks in widgets to simulate a day switch.
### Acceptance criteria
- Loading July 2 and July 3 calls the backend query twice with distinct
`CivilDate` values.
- The controller maps each returned `TodayState` into `TodayScreenData` normally.
- Empty state for a selected date still shows the selected date label.
---
## Chunk 2.3 — Sync modal selection and timeline scroll state on date changes
### Tasks
1. Decide whether selected task modals should close on date change or resync only
if the same task still appears on the new day.
2. Preferred V1 behavior: clear selected card when selected date changes.
3. Reset timeline scroll target/request state when switching days unless a
specific target is requested after read refresh.
4. Ensure date changes cannot leave a modal open for a task that is no longer in
`TodayScreenData.cards`.
### Acceptance criteria
- Open task modal closes when moving to another date.
- Timeline cards from the previous date are not reused after reload.
- No stale selected-card exception appears during rapid date changes.
---
## Chunk 2.4 — Preserve loading, empty, and failure states per selected date
### Tasks
1. Show loading while the selected date's read is in progress.
2. Show empty state if the selected date has no timeline cards.
3. Show failure state with the selected date unchanged if the read fails.
4. Avoid falling back to the previous date's data after a failed new-date read.
5. Prevent older in-flight reads from overwriting newer selected-date results.
### Acceptance criteria
- Rapid previous/next clicks settle on the latest selected date.
- Failure for one date does not corrupt the selected-date controller.
- Empty selected dates remain navigable.
---
## Block acceptance criteria
- Today reads are selected-date aware.
- Date changes are read-only state transitions.
- Modal/selection state cannot leak across dates.
- Controller tests cover previous, next, direct jump, empty date, and read
failure.
## Validation after block
```sh
cd apps/focus_flow_flutter
flutter test test/controllers
flutter test test/app
```
If tests are organized differently after Persistence Plan 1, run the nearest
controller/app tests and document the command used.

View file

@ -0,0 +1,122 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Date Selection 01 Block 03 — Top-Bar Navigation and Date Picker
**Status:** Planned.
**Goal:** Wire the visible top-bar controls to selected-date state while
preserving the compact dark UI.
---
## Block outcome
After this block, the user can click previous/next day arrows and open a date
picker from the displayed date.
---
## Chunk 3.1 — Refactor `TopBar` callback API
### Tasks
1. Add `onPreviousDate`, `onNextDate`, and `onDatePressed` callbacks to `TopBar`.
2. Keep callbacks nullable only if tests/demo previews need disabled controls.
3. Convert current placeholder `onPressed: () {}` values into real callback
invocations.
4. Preserve the current metrics and layout unless a callback affordance requires
minor spacing updates.
5. Add tooltips/accessibility labels:
- Previous day,
- Next day,
- Choose date.
### Acceptance criteria
- `TopBar` no longer contains inert date controls in normal app mode.
- Button hit targets remain usable at compact width.
- Existing top-bar visual snapshots/widget tests are updated only for intentional
changes.
---
## Chunk 3.2 — Make the date label a button
### Tasks
1. Replace the static date label area with an accessible button-like control.
2. Keep the visual treatment calm and compact; avoid bright native-calendar
styling that clashes with the dark theme.
3. Ensure the button still scales/truncates cleanly at the current compact
breakpoint.
4. Preserve keyboard focus and screen-reader semantics.
5. Keep the top-left `Today` title as the surface name unless product direction
explicitly changes it.
### Acceptance criteria
- Clicking the displayed date opens the picker callback.
- Keyboard users can focus and activate the date control.
- The date label still renders correctly for long month names.
---
## Chunk 3.3 — Implement date picker presentation
### Tasks
1. Use Flutter's date picker if it can be themed cleanly for the current dark UI;
otherwise implement a small scoped picker surface.
2. Initialize the picker to the currently selected date.
3. On selection, convert the picked date to `CivilDate` without accidentally
shifting it through UTC/local-time conversions.
4. On cancel, leave selected date unchanged.
5. Boundaries can remain broad in V1 unless existing product rules define a
scheduling horizon.
6. Keep date picker state outside scheduler core.
### Acceptance criteria
- Picking a date reloads the timeline for that exact civil date.
- Canceling the picker performs no read refresh and no task mutation.
- Date conversion tests cover at least one non-UTC owner timezone if timezone
test utilities are available.
---
## Chunk 3.4 — Wire top-bar controls through the screen scaffold
### Tasks
1. Thread date callbacks from the selected-date owner through
`_TodayScreenScaffold` into `TopBar`.
2. Ensure empty/loading/failure states still render top-bar date controls where
appropriate.
3. Ensure date switching while a modal is open clears selection before or during
reload.
4. Keep `TimelineView` unaware of date-picker mechanics.
### Acceptance criteria
- Previous/next/date-picker interactions work from ready and empty states.
- Timeline widgets continue to receive only card/range/selection inputs.
- No scheduler/domain imports are added to presentational top-bar widgets unless
already required by app-layer boundaries.
---
## Block acceptance criteria
- The top-bar date controls are interactive.
- The date label opens a picker.
- UI remains compact and dark-themed.
- Date controls are accessible and test-covered.
## Validation after block
```sh
cd apps/focus_flow_flutter
flutter test test/widgets
flutter test test/app
```

View file

@ -0,0 +1,131 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Date Selection 01 Block 04 — Date-Aware Commands and Persistence
**Status:** Planned.
**Goal:** Ensure task commands run against the currently selected date and persist
correctly across multiple days.
---
## Block outcome
After this block, a user can switch days, add/schedule/complete tasks on that
visible day, close the app, reopen it, and see the expected state on the same
selected day.
---
## Chunk 4.1 — Make command controller date-aware
### Tasks
1. Replace fixed `SchedulerCommandController.localDate` construction with a
current-date provider or recreate command controllers when selected date
changes.
2. Ensure these commands use the selected date at execution time:
- schedule backlog item to next available slot,
- complete flexible task,
- complete required visible task,
- uncomplete task.
3. Keep quick capture to backlog date-neutral unless the current capture UI adds
an explicit schedule-now option.
4. Include the selected date in command read hints when relevant.
5. Preserve stale-revision checks by passing `expectedUpdatedAt` unchanged.
### Acceptance criteria
- Scheduling from Backlog while viewing tomorrow places the task in tomorrow's
planning window when a valid slot exists.
- Completing a task while viewing a non-current day runs the command against
that visible day's planning state.
- Command code does not read date labels from widgets.
---
## Chunk 4.2 — Refresh the right read models after date-aware commands
### Tasks
1. After a successful command, reload the currently selected date.
2. If a command's read hint references another affected date, decide whether to:
- reload only the selected date for V1, or
- add a small future-proof invalidation hook.
3. For this plan, prefer reloading the selected date only unless tests prove the
UI needs immediate cross-date refresh.
4. Make sure moving a task into a different day removes it from the current
selected-day timeline after refresh.
### Acceptance criteria
- After schedule/complete/uncomplete, visible cards match persisted backend
state for the selected date.
- No stale card stays visible after a successful command that removes it from the
selected day.
---
## Chunk 4.3 — Persist tasks on previous and future days
### Tasks
1. Add lifecycle tests using a temp SQLite file:
- open app/runtime on date A,
- capture a task,
- schedule it into date A,
- close database/runtime,
- reopen with date A selected,
- assert task placement remains.
2. Repeat for a future date relative to the test clock.
3. Repeat for a previous date if the scheduler permits scheduling into a past
selected day; otherwise document the validation failure and expected UX.
4. Verify Backlog remains unified across date changes.
### Acceptance criteria
- Future-day scheduled task persists after close/reopen.
- Previous-day task behavior is explicitly tested or explicitly rejected by
backend validation.
- Backlog tasks are not duplicated across date navigation.
---
## Chunk 4.4 — Persist done/not-done state across selected dates
### Tasks
1. Add lifecycle tests for completing a task while viewing a future date.
2. Add lifecycle tests for completing a task while viewing a previous date if the
backend allows it.
3. Close and reopen the database/runtime after completion.
4. Assert `TaskStatus.completed`, `completedAt`, actual times where present, and
updated metadata reload.
5. Uncomplete the same task, close/reopen, and assert planned/not-done state
reloads.
### Acceptance criteria
- Done state persists per task regardless of which selected date initiated the
command.
- Uncomplete state persists and returns the card to normal planned state.
- Completion timestamp remains the real command clock instant.
---
## Block acceptance criteria
- Reads and commands use the selected date consistently.
- Date-specific schedule placement persists across app restarts.
- Done/not-done state persists across app restarts.
- Backlog remains unified and durable.
## Validation after block
```sh
cd packages/scheduler_persistence_sqlite
dart test
cd ../../apps/focus_flow_flutter
flutter test
```

View file

@ -0,0 +1,134 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Date Selection 01 Block 05 — Completion Date Presentation
**Status:** Planned.
**Goal:** Show enough completion timestamp context when the completed date and
scheduled date differ.
---
## Block outcome
After this block, completed timeline cards still look compact for normal same-day
completion, but they show date context when completion happened on a different
local date than the scheduled slot.
---
## Chunk 5.1 — Add completion date fields to presentation models
### Tasks
1. Extend `TimelineCardModel` or an equivalent presentation model with one or
more explicit completion fields:
- completed local date,
- completed time text,
- display-ready completed date/time text,
- whether date context is required.
2. Keep raw `DateTime` handling out of leaf widgets where possible.
3. Use owner timezone/local-date semantics rather than comparing UTC calendar
days directly.
4. Preserve existing `completedTimeText` behavior for same-day cards if it is
still useful.
### Acceptance criteria
- Presentation mapper can decide whether date context is required.
- Widgets receive display-ready text or simple presentation flags.
- Existing same-day completed card tests continue to pass with minimal changes.
---
## Chunk 5.2 — Define date-context display rules
### Required V1 rule
Show date + time when:
1. `completedAt` local date differs from the scheduled local date, or
2. actual completion interval local date differs from the scheduled local date.
### Optional V1-friendly rule
Also show date + time when the selected date is not the current owner-local day,
if testing shows users need that context while reviewing previous/future days.
Keep this optional rule behind a clearly named mapper helper so it can be changed
without rewriting widgets.
### Tasks
1. Implement a single helper that compares scheduled and completed local dates.
2. Prefer exact labels like `Completed Jul 2, 8:05 AM` over vague labels like
`Completed yesterday` for V1.
3. Keep same-day labels compact, for example `Completed at: 8:05 AM`.
4. Add tests for:
- scheduled and completed same date,
- scheduled date differs from completed date,
- completed timestamp present but actual interval absent,
- actual interval present but completed timestamp absent if the domain can
produce that state.
### Acceptance criteria
- Cross-date completion never renders as time-only.
- Same-day completion remains compact.
- Date formatting is deterministic in tests.
---
## Chunk 5.3 — Update compact card and modal text
### Tasks
1. Update timeline card subtitle text to include completion date context when
required.
2. Update selected-task modal metadata if it repeats completion time.
3. Ensure long date/time strings fit in compact card constraints without
overflowing over reward/difficulty controls.
4. Add tooltip/semantic label if the visible compact text must be shortened.
### Acceptance criteria
- Completed cross-date cards are readable in compact timeline mode.
- The selected-task modal shows the same completion date truth as the card.
- Text overflow behavior is intentional and tested.
---
## Chunk 5.4 — Add persistence-backed presentation tests
### Tasks
1. Create or reuse a temp SQLite runtime test that schedules a task on one day
and completes it on another command clock day.
2. Reopen the database/runtime.
3. Load the scheduled day.
4. Assert the card contains completion date + time.
5. Load the completion day if the task also appears there by backend design;
assert presentation remains consistent.
### Acceptance criteria
- Cross-date completion display survives close/reopen.
- UI presentation is based on persisted task timestamps, not transient widget
state.
---
## Block acceptance criteria
- Completion-date presentation covers cross-date completion.
- Same-day completion remains compact.
- Card and modal text agree.
- Presentation tests cover persisted reload.
## Validation after block
```sh
cd apps/focus_flow_flutter
flutter test test/models
flutter test test/widgets
```

View file

@ -0,0 +1,111 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Date Selection 01 Block 06 — Validation and Handoff
**Status:** Planned.
**Goal:** Prove date selection is stable, persisted, and ready for Task Pushing 01.
---
## Block outcome
After this block, Date Selection 01 should be complete and Task Pushing 01 can
begin from a date-aware, persistence-backed UI.
---
## Chunk 6.1 — Add end-to-end date navigation tests
### Required tests
1. Initial load shows the runtime-selected/current day.
2. Previous arrow changes the date label and reloads that day.
3. Next arrow changes the date label and reloads that day.
4. Date picker jumps directly to a chosen date.
5. Empty selected dates show empty state with the correct date label.
6. Rapid navigation settles on the final selected date.
7. Open modal closes when changing dates.
### Acceptance criteria
- Date navigation is covered by widget/controller tests.
- Tests do not depend on arbitrary demo seed tasks.
---
## Chunk 6.2 — Add persistence lifecycle tests across dates
### Required tests
1. Schedule a backlog task into tomorrow, close/reopen, reload tomorrow, assert
it remains planned there.
2. Complete that tomorrow task, close/reopen, reload tomorrow, assert done state
remains.
3. Uncomplete it, close/reopen, reload tomorrow, assert planned state remains.
4. Schedule or load a previous-day task if supported, close/reopen, assert its
state remains.
5. Verify Backlog is still unified and not duplicated by date navigation.
### Acceptance criteria
- Multi-day persistence is proven using on-disk temp SQLite files.
- The test explicitly closes database/runtime handles before reopen assertions.
---
## Chunk 6.3 — Run validation gates
### Commands
Run the strongest available validation set:
```sh
scripts/test.sh
cd packages/scheduler_core
dart analyze
dart test
cd ../scheduler_persistence_sqlite
dart analyze
dart test
cd ../../apps/focus_flow_flutter
flutter analyze
flutter test
```
### Acceptance criteria
- All available gates pass.
- If a command is unavailable in the environment, record the exact command and
failure reason in the plan handoff notes.
---
## Chunk 6.4 — Update minimal handoff/status docs
### Tasks
1. Update the plan summary/status to indicate completion.
2. Move the plan folder only if the project's completed-plan workflow calls for
it.
3. Update `Codex Documentation/Current Software Plan/README.md` so Task Pushing
01 is the next incomplete plan.
4. Do not create a broad overall report.
### Acceptance criteria
- Handoff docs identify Date Selection 01 as complete.
- Task Pushing 01 is clearly next.
- No unrelated planning docs are rewritten.
---
## Final plan acceptance criteria
- Previous/next/date-picker controls work.
- Selected date drives Today reads and relevant commands.
- Multi-day schedule and done state persist across restarts.
- Cross-date completion displays date + time.
- UI remains backend-driven.
- Validation status is documented.

View file

@ -0,0 +1,43 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Date Selection 01 Execution Order
**Status:** Planned.
Run these files in order. All chunks are intended for `XHIGH` execution unless a
chunk explicitly says otherwise.
1. `DATE_SELECTION_01_BLOCK_01_SCOPE_AND_BASELINE.md`
- Confirm Persistence Plan 1 is complete.
- Reconcile current app composition after persistence wiring.
- Lock selected-date semantics before touching UI code.
2. `DATE_SELECTION_01_BLOCK_02_SELECTED_DATE_STATE_AND_READS.md`
- Add selected-date state/controller behavior.
- Make Today reads date-aware.
- Clear or resync selected card state when the visible day changes.
3. `DATE_SELECTION_01_BLOCK_03_TOP_BAR_NAVIGATION_AND_PICKER.md`
- Wire previous/next day buttons.
- Convert the date label into an accessible date-picker button.
- Preserve compact dark-theme visuals.
4. `DATE_SELECTION_01_BLOCK_04_DATE_AWARE_COMMANDS_AND_PERSISTENCE.md`
- Pass the selected date into command use cases.
- Validate add/schedule/complete/uncomplete across multiple persisted days.
- Ensure close/reopen loads the same date-specific state.
5. `DATE_SELECTION_01_BLOCK_05_COMPLETION_DATE_PRESENTATION.md`
- Add completion date context to read/presentation models.
- Show date + time when completed local date differs from scheduled local
date.
- Keep same-day completion compact.
6. `DATE_SELECTION_01_BLOCK_06_VALIDATION_HANDOFF.md`
- Add widget/controller/lifecycle tests.
- Run validation gates.
- Update only handoff/status docs required by this plan.
Do not begin Task Pushing 01 until this plan passes its validation handoff.

View file

@ -0,0 +1,112 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Date Selection 01 Summary — Day Navigation and Date Picker
**Status:** Planned.
**Scope level:** XHIGH implementation plan.
**Primary outcome:** The Flutter desktop app can switch the visible planning day,
load the correct persisted timeline for that day, and keep date-specific task
state durable across app restarts.
---
## Current repo facts this plan is based on
1. The compact Flutter UI already has top-bar calendar, left-arrow, and
right-arrow controls, but their callbacks are placeholders.
2. The top bar currently receives only a display-ready `dateLabel`.
3. `TodayScreenController` currently reads one fixed day through a callback.
4. The composition currently owns a single `CivilDate` and creates command
controllers with that fixed local date.
5. `GetTodayStateQuery.execute` already accepts a requested `CivilDate`.
6. Scheduler commands such as scheduling, completing, and uncompleting already
accept a local date for planning context.
7. After Persistence Plan 1, app state should be backed by an on-disk SQLite
`ApplicationUnitOfWork`, not static demo seed data.
---
## Product behavior
1. Clicking the left arrow moves the selected date back one day.
2. Clicking the right arrow moves the selected date forward one day.
3. Clicking the displayed date opens a date picker.
4. Choosing a date immediately reloads the Today timeline for that date.
5. Date switching does not mutate tasks by itself.
6. Scheduling a backlog task while viewing a future or past date schedules into
the selected date's planning window, subject to backend scheduling rules.
7. Completing a task uses the real current clock for completion metadata, not
the selected date as fake time.
8. Date-specific task placement and done/not-done state survive close/reopen.
9. If completion happened on a different local date than the scheduled slot, the
card must show the completion date, not only the completion time.
---
## Definition of done
Date Selection 01 is complete when all of the following are true:
1. `TopBar` exposes working previous-day, next-day, and date-picker callbacks.
2. The displayed date is an accessible button, not static text.
3. The selected date is owned by controller/composition state and is not hardcoded
into demo composition.
4. Switching dates reloads `GetTodayStateQuery` with the selected `CivilDate`.
5. Command controllers run schedule/complete/uncomplete actions against the
current selected date.
6. Any selected modal card is cleared or resynced safely when the date changes.
7. Tasks scheduled on tomorrow or a previous day persist and reload on that day.
8. Completed state persists when completion happens from a non-current selected
day.
9. Completion presentation includes date context whenever completed local date
differs from scheduled local date.
10. Widgets do not contain Drift, SQL, repository, or scheduling-engine logic.
11. Existing compact timeline visuals remain stable except for the intended date
controls and completion-date text.
12. Backend, Flutter, and lifecycle validation gates pass, or unavailable gates
are documented.
---
## Non-goals
1. No week/month calendar view.
2. No drag-and-drop scheduling.
3. No recurring task support.
4. No calendar sync.
5. No changes to the scheduling algorithm except bug fixes discovered while
validating selected-date command behavior.
6. No broad redesign of the compact timeline.
7. No task-pushing menu; that is handled by Task Pushing 01.
8. No backup/restore or export/import UI.
---
## Architecture rule
Date selection is UI/session state. Scheduling truth remains in the backend
read/command layer:
```text
TopBar date controls
-> selected-date controller/state
-> Today read controller executes GetTodayStateQuery(date)
-> command controller passes selected CivilDate to use cases
-> ApplicationUnitOfWork persists domain changes
-> UI refreshes from read models
```
The selected date may choose which read model to request. It must not cause UI
widgets to compute task placement or conflict resolution.
---
## Important implementation decision
Do not make `DemoSchedulerComposition.date` the durable date-navigation model.
After Persistence Plan 1, the app should have a real runtime composition that can
create read and command controllers for whichever date is currently selected.
Use a selected-date controller or date-aware Today controller so date changes are
explicit, testable, and not hidden in widget-local rebuilds.

View file

@ -0,0 +1,32 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Date Selection 01 — Day Navigation and Date Picker
**Status:** Planned. Execute after `Persistence Plan 1 - SQLite Runtime Persistence`.
**Scope level:** XHIGH implementation plan.
This plan makes the compact Today timeline date-aware. The top-bar arrows move
backward and forward by day. The displayed date becomes a button that opens a
date picker so the user can jump directly to another day.
The selected day must flow through the existing backend read and command
boundaries. The UI must not duplicate scheduling rules or create a second source
of task state.
## Files in this plan
1. `DATE_SELECTION_01_SUMMARY.md`
2. `DATE_SELECTION_01_EXECUTION_ORDER.md`
3. `DATE_SELECTION_01_BLOCK_01_SCOPE_AND_BASELINE.md`
4. `DATE_SELECTION_01_BLOCK_02_SELECTED_DATE_STATE_AND_READS.md`
5. `DATE_SELECTION_01_BLOCK_03_TOP_BAR_NAVIGATION_AND_PICKER.md`
6. `DATE_SELECTION_01_BLOCK_04_DATE_AWARE_COMMANDS_AND_PERSISTENCE.md`
7. `DATE_SELECTION_01_BLOCK_05_COMPLETION_DATE_PRESENTATION.md`
8. `DATE_SELECTION_01_BLOCK_06_VALIDATION_HANDOFF.md`
## Dependency
Persistence Plan 1 must be complete first so this plan can validate real
close/reopen behavior across multiple dates instead of demo seed data.

View file

@ -0,0 +1,43 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Task Pushing 01 — Past Task Push Controls
**Status:** Planned. Execute after Date Selection 01.
**Scope level:** XHIGH implementation plan.
This plan adds the push affordance for scheduled tasks that are in the past and
not complete. The push button replaces hover quick actions while visible and
opens a destination menu with:
1. Push to next,
2. Push to tomorrow,
3. Push to backlog.
Push behavior must go through the existing scheduler command/use-case layer and
persist through SQLite. The UI must not compute or save canonical schedule
placement.
## Files in this plan
1. `TASK_PUSHING_01_SUMMARY.md`
2. `TASK_PUSHING_01_EXECUTION_ORDER.md`
3. `TASK_PUSHING_01_BLOCK_01_SCOPE_AND_DOMAIN_SEMANTICS.md`
4. `TASK_PUSHING_01_BLOCK_02_PAST_TASK_READ_MODEL.md`
5. `TASK_PUSHING_01_BLOCK_03_PUSH_BUTTON_CARD_UI.md`
6. `TASK_PUSHING_01_BLOCK_04_PUSH_MENU_DESTINATIONS.md`
7. `TASK_PUSHING_01_BLOCK_05_COMMAND_WIRING_AND_PERSISTENCE.md`
8. `TASK_PUSHING_01_BLOCK_06_DESTINATION_SCHEDULING_RULES.md`
9. `TASK_PUSHING_01_BLOCK_07_BACKLOG_FRESHNESS_RESET.md`
10. `TASK_PUSHING_01_BLOCK_08_VALIDATION_HANDOFF.md`
## Dependency
Task Pushing 01 requires:
1. Persistence Plan 1 complete.
2. Date Selection 01 complete.
The push menu depends on multi-day reads because push destinations can move a
task away from the currently visible day.

View file

@ -0,0 +1,125 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Task Pushing 01 Block 01 — Scope and Domain Semantics
**Status:** Planned.
**Goal:** Confirm the exact pushable task scope and lock destination semantics
before adding visible controls.
---
## Block outcome
After this block, the implementation should know which cards can show `Push`,
what `past` means, and what each destination must do.
---
## Chunk 1.1 — Confirm prerequisites
### Tasks
1. Confirm Persistence Plan 1 is complete.
2. Confirm Date Selection 01 is complete.
3. Verify the app can load arbitrary selected dates from persisted SQLite state.
4. Verify command controllers refresh the selected date after mutations.
5. Verify task completion and uncompletion persist across close/reopen.
### Acceptance criteria
- Task Pushing 01 starts from a date-aware, persistence-backed UI.
- Any missing prerequisite behavior is fixed before continuing.
---
## Chunk 1.2 — Verify pushable task types
### Tasks
1. Inspect current scheduler-core command support for push destinations.
2. Confirm that V1 push support is planned flexible tasks only unless explicitly
expanded in this block.
3. Decide how to present past incomplete non-flexible tasks for this plan:
- preferred V1: keep normal non-push UI and do not show the Push button,
- alternative: add backend-supported required-task push semantics with tests
before exposing UI.
4. Document the decision in the block handoff notes.
### Acceptance criteria
- The UI never calls a flexible-task-only command for non-flexible tasks.
- Unsupported task types do not show the Push button.
- Any expanded support is backed by scheduler-core tests first.
---
## Chunk 1.3 — Define `past incomplete` precisely
### Tasks
1. Use owner-local current time as the clock reference.
2. A planned flexible task is past/incomplete when:
- it is not completed,
- it has scheduled placement,
- its scheduled end is before the current owner-local instant, or the selected
date is before the current owner-local date and the scheduled task remains
incomplete.
3. Future selected-day tasks are not past unless the real current time is already
after their scheduled end.
4. A completed task is never in push-button state.
5. A backlog task is never in push-button state because it is not on the
timeline.
### Acceptance criteria
- Detection works for earlier-today tasks.
- Detection works for previous-day incomplete tasks.
- Detection does not trigger for future tasks.
- Detection clears immediately after completion refresh.
---
## Chunk 1.4 — Lock push destination semantics
### Tasks
1. Define Push to next:
- schedule the task into the next valid no-overlap slot after current
owner-local time,
- use later today when a valid slot exists,
- otherwise move to the next future valid slot allowed by backend rules.
2. Define Push to tomorrow:
- target the next owner-local civil day relative to current owner-local date,
- schedule into the first valid no-overlap slot for that day.
3. Define Push to backlog:
- set task status to Backlog,
- clear scheduled start/end,
- reset backlog freshness anchor to current time,
- preserve original creation timestamp.
4. Confirm no destination uses widget-side slot calculation.
### Acceptance criteria
- Destination semantics are testable in core/application tests.
- Current selected date does not override the meaning of current time.
- Push to tomorrow is relative to the real owner-local current date, not the
historical selected date being reviewed.
---
## Block acceptance criteria
- Pushable scope is explicit.
- Past/incomplete detection rules are explicit.
- Destination semantics are explicit.
- Any required core behavior changes are identified before UI work.
## Validation after block
```sh
cd packages/scheduler_core
dart analyze
dart test
```

View file

@ -0,0 +1,118 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Task Pushing 01 Block 02 — Past Task Read Model
**Status:** Planned.
**Goal:** Add presentation-model state that tells widgets when to show the full
Push button.
---
## Block outcome
After this block, `TimelineCardModel` or its successor exposes a clear push-state
field. Leaf widgets should not recompute past/incomplete scheduling conditions.
---
## Chunk 2.1 — Add push-state presentation fields
### Tasks
1. Add a compact, explicit card field such as:
- `pastActionState`,
- `showPastTaskPushButton`, or
- `pushControlState`.
2. Include enough information for UI callbacks:
- task id,
- expected updated timestamp/revision input if available,
- enabled/disabled state,
- semantic label.
3. Keep the field false/null for completed tasks.
4. Keep the field false/null for unsupported task types.
5. Keep the field false/null for backlog/free-slot/locked cards.
### Acceptance criteria
- Widgets can render the Push button from presentation data alone.
- Presentation data does not expose Drift rows or repository records.
- Completed cards cannot accidentally show the Push button.
---
## Chunk 2.2 — Provide clock and selected-date context to the mapper
### Tasks
1. Update Today-state-to-card mapping to receive current owner-local clock
context, if it does not already have it.
2. Avoid using `DateTime.now()` directly inside presentation mappers unless a
testable clock is injected.
3. Compare scheduled instants with current owner-local time using existing time
conversion utilities.
4. Make selected date available to the mapper only if needed for previous-day
detection.
### Acceptance criteria
- Mapper tests can freeze time.
- Past detection is deterministic.
- UTC/local date boundaries are handled through project time semantics.
---
## Chunk 2.3 — Add mapper tests
### Required tests
1. Flexible planned task earlier today and incomplete shows Push state.
2. Flexible planned task later today does not show Push state.
3. Flexible planned task on a previous selected date and incomplete shows Push
state.
4. Flexible planned task on a future selected date does not show Push state.
5. Completed flexible task in the past does not show Push state.
6. Required/locked/free-slot/surprise cards do not show Push state unless Block
01 explicitly expanded support.
7. Task without valid schedule placement does not show Push state.
### Acceptance criteria
- Tests cover each state branch.
- No widget test is needed to prove core push-state calculation.
---
## Chunk 2.4 — Connect push state to quick-action suppression
### Tasks
1. Update `TimelineCardModel.showsQuickActions` or equivalent to return false
when the full Push button should show.
2. Ensure hover actions remain available for normal planned flexible tasks.
3. Ensure completed cards continue to use completed behavior, not push behavior.
4. Keep the selected-task modal behavior unchanged unless the modal also needs a
push menu later.
### Acceptance criteria
- Past incomplete cards expose Push state and suppress hover actions.
- Non-past flexible cards keep existing hover quick actions.
- Completed cards do not show push controls or hover quick actions intended for
planned tasks.
---
## Block acceptance criteria
- Past-task push state exists in presentation models.
- Detection is deterministic and test-covered.
- Hover quick-action suppression is model-driven.
## Validation after block
```sh
cd apps/focus_flow_flutter
flutter test test/models
```

View file

@ -0,0 +1,104 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Task Pushing 01 Block 03 — Push Button Card UI
**Status:** Planned.
**Goal:** Render the full right-side Push button on past incomplete cards.
---
## Block outcome
After this block, past incomplete planned flexible cards visibly show a `Push`
button beside the reward/difficulty icons. The menu may still be stubbed until
Block 04.
---
## Chunk 3.1 — Place the Push button in trailing controls
### Tasks
1. Add a compact `Push` button component in the timeline card trailing-controls
area.
2. Position it next to reward and difficulty icons as requested.
3. Give it visual priority over time text if the layout overlaps.
4. Keep card height and density consistent with the compact timeline.
5. Use calm styling that reads as actionable without becoming visually loud.
### Acceptance criteria
- Push button appears at the right side of eligible cards.
- Reward/difficulty icons remain visible and aligned.
- The time label does not visually cover the button.
---
## Chunk 3.2 — Implement z-order and hover suppression
### Tasks
1. Ensure the Push button is painted above any time text or hover affordance that
would otherwise overlap it.
2. Disable hover quick-action rendering while the Push button is visible.
3. Confirm normal hover actions still appear on non-past eligible flexible tasks.
4. Confirm the Push button remains clickable when the card is selected/hovered.
### Acceptance criteria
- The Push button wins hit testing in its visible area.
- Hover controls do not appear over or under the Push button.
- No double-action UI appears for the same card.
---
## Chunk 3.3 — Add accessibility and keyboard behavior
### Tasks
1. Add a tooltip and semantic label such as `Push overdue task`.
2. Ensure the button can receive keyboard focus.
3. Ensure pressing Enter/Space triggers the same callback as clicking.
4. Ensure disabled/unavailable push state, if any, is announced correctly.
### Acceptance criteria
- Keyboard and screen-reader users can discover and activate Push.
- The button label is specific enough to distinguish it from hover quick actions.
---
## Chunk 3.4 — Add visual/widget tests
### Required tests
1. Past incomplete flexible card renders Push.
2. Completed past flexible card does not render Push.
3. Future flexible card does not render Push.
4. Past incomplete flexible card does not render hover quick actions.
5. Normal planned flexible card still renders hover quick actions when hovered.
6. Push button callback fires once when tapped.
### Acceptance criteria
- UI behavior is covered without requiring real SQLite.
- Tests use presentation models rather than hand-building domain scheduler state
inside widgets.
---
## Block acceptance criteria
- Push button renders in the correct card state.
- Push button placement and z-order satisfy the visual requirement.
- Hover quick actions are suppressed only while Push is visible.
- Accessibility behavior is covered.
## Validation after block
```sh
cd apps/focus_flow_flutter
flutter test test/widgets/timeline
```

View file

@ -0,0 +1,115 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Task Pushing 01 Block 04 — Push Menu Destinations
**Status:** Planned.
**Goal:** Open a destination menu from the Push button and route each choice to a
callback.
---
## Block outcome
After this block, clicking `Push` opens a menu with the three requested choices.
The choices may call stubbed/controller callbacks until Block 05 wires real
commands.
---
## Chunk 4.1 — Add destination menu UI
### Tasks
1. Add a small menu anchored to the Push button.
2. Include exactly these visible labels:
- `Push to next`,
- `Push to tomorrow`,
- `Push to backlog`.
3. Keep menu styling consistent with the dark compact UI.
4. Use enough spacing for desktop pointer targets without making the card feel
heavy.
5. Ensure the menu can open above/below the card depending on available space.
### Acceptance criteria
- Menu opens from the Push button.
- Menu contains all three requested labels.
- Menu does not obscure the button in a way that prevents closing/reopening.
---
## Chunk 4.2 — Add destination callback surface
### Tasks
1. Add callback signatures to the card/timeline path for:
- push to next,
- push to tomorrow,
- push to backlog.
2. Pass task id and expected update metadata required for stale-write protection.
3. Keep callbacks nullable only for tests/previews that intentionally disable
command wiring.
4. Do not pass raw domain `Task` objects into leaf widgets unless existing
architecture already does.
### Acceptance criteria
- Each menu item calls the correct destination callback.
- Callback payload includes enough task identity/update metadata to run a safe
command.
- Widgets do not know command-use-case class names.
---
## Chunk 4.3 — Handle menu dismissal and command-running state
### Tasks
1. Close the menu when a destination is selected.
2. Close the menu on outside click or Escape.
3. Decide whether command-running state disables menu re-entry globally or per
card.
4. Prevent double-submission if the user rapidly clicks a destination twice.
5. Show existing command failure/success UI if available; do not add a new
notification framework in this plan.
### Acceptance criteria
- Destination selection is one-shot until the command result returns.
- Cancel/dismiss performs no task mutation.
- Existing command state surfaces are reused.
---
## Chunk 4.4 — Add menu widget tests
### Required tests
1. Tap Push opens menu.
2. Menu has exactly the three destination labels.
3. Tapping each item invokes the matching callback.
4. Escape/outside click closes menu without callback.
5. Rapid double tap does not invoke duplicate commands if command-running state
is available at this layer.
### Acceptance criteria
- Destination menu behavior is covered before backend wiring.
- Tests do not require a live scheduler engine.
---
## Block acceptance criteria
- Push menu appears and dismisses correctly.
- Each destination has a distinct callback path.
- No backend scheduling logic is introduced into widgets.
## Validation after block
```sh
cd apps/focus_flow_flutter
flutter test test/widgets/timeline
```

View file

@ -0,0 +1,133 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Task Pushing 01 Block 05 — Command Wiring and Persistence
**Status:** Planned.
**Goal:** Connect push menu destinations to application commands and prove their
results persist.
---
## Block outcome
After this block, selecting a push destination runs the backend command through
`SchedulerCommandController`, refreshes the selected date, and persists the
result through SQLite.
---
## Chunk 5.1 — Add command-controller push methods
### Tasks
1. Add command-controller methods for:
- `pushTaskToNextAvailableSlot`,
- `pushTaskToTomorrow`,
- `pushTaskToBacklog`.
2. Use current owner-local time from the runtime clock for command context.
3. Pass selected/current planning dates according to Block 01 semantics.
4. Preserve stale-write checks using card metadata where available.
5. Reuse existing `_run` command-state handling and read refresh behavior.
### Acceptance criteria
- Push methods expose no Flutter widget dependencies.
- Push methods call application use cases, not scheduler engine directly.
- Push command failures flow through existing command failure state.
---
## Chunk 5.2 — Wire menu callbacks through the screen tree
### Tasks
1. Thread push callbacks from `FocusFlowHome` or equivalent through
`_TodayScreenScaffold`, `TimelineView`, and card widgets.
2. Keep callback names destination-specific.
3. Refresh the currently selected date after a successful command.
4. Clear selected card/modal if the pushed task leaves the selected day.
5. Keep Backlog refresh behavior aligned with existing Backlog controller if one
is visible in this UI slice.
### Acceptance criteria
- Each menu item reaches the correct command-controller method.
- The visible timeline refreshes after success.
- A task pushed out of the current date disappears or moves according to backend
read state.
---
## Chunk 5.3 — Use existing application use cases where semantics match
### Tasks
1. For Push to next, prefer `pushFlexibleToNextAvailableSlot` if Block 06
confirms it honors no-before-now semantics.
2. For Push to tomorrow, prefer `pushFlexibleToTomorrowTopOfQueue` if Block 06
confirms it places into the first valid no-overlap slot on the next day.
3. For Push to backlog, choose one path and document it:
- use existing `moveFlexibleToBacklog`, or
- add a command that routes through `PushDestination.backlog` for consistent
push-destination accounting.
4. Do not add duplicate command implementations if existing use cases already
satisfy the product behavior.
### Acceptance criteria
- Command wiring uses the smallest backend surface that satisfies the requested
behavior.
- Any semantic gap is moved to Block 06 or Block 07 rather than patched in UI.
---
## Chunk 5.4 — Add close/reopen persistence tests for destinations
### Required tests
1. Push to next:
- start with an incomplete past flexible task,
- push to next,
- close/reopen,
- assert the task is planned in the persisted new slot.
2. Push to tomorrow:
- start with an incomplete past flexible task,
- push to tomorrow,
- close/reopen,
- load tomorrow,
- assert the task is planned there.
3. Push to backlog:
- start with an incomplete past flexible task,
- push to backlog,
- close/reopen,
- assert status is Backlog and schedule fields are cleared.
4. Completion after push:
- push a task,
- complete it,
- assert Push button disappears after refresh.
### Acceptance criteria
- Every destination persists through SQLite.
- Tests use on-disk temp SQLite and close handles before reopen assertions.
- UI/controller tests and backend persistence tests agree on destination results.
---
## Block acceptance criteria
- Push menu destinations are wired to backend commands.
- Results persist and reload.
- Selected-date read refresh shows the backend result.
- No widget computes or saves canonical schedule placement.
## Validation after block
```sh
cd packages/scheduler_persistence_sqlite
dart test
cd ../../apps/focus_flow_flutter
flutter test
```

View file

@ -0,0 +1,119 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Task Pushing 01 Block 06 — Destination Scheduling Rules
**Status:** Planned.
**Goal:** Verify or adjust backend push scheduling so destination behavior exactly
matches the requested product rules.
---
## Block outcome
After this block, the scheduler/application layer should guarantee no-overlap,
no-before-now push placement. UI tests should not need to compensate for backend
semantics.
---
## Chunk 6.1 — Verify Push to next behavior
### Tasks
1. Add scheduler-core/application tests for a past incomplete flexible task with
an open slot later today.
2. Assert Push to next places the task in the later-today slot.
3. Add a test where no later-today slot exists.
4. Assert the result is either the next backend-supported future slot or a clear
no-fit result, depending on confirmed scheduler horizon rules.
5. Assert placement never overlaps required, locked, or already-planned tasks.
6. Assert placement never lands before current owner-local time.
### Acceptance criteria
- Push to next satisfies same-day-if-available behavior.
- Push to next never moves into the past.
- Any no-fit response keeps the original task safe and persisted.
---
## Chunk 6.2 — Verify Push to tomorrow behavior
### Tasks
1. Add tests for targeting the next owner-local civil day relative to current
time.
2. Assert placement uses the first valid no-overlap slot on that day.
3. Add locked/required-time conflicts and assert they are skipped.
4. Add a no-fit tomorrow case and assert the task remains safe with a clear
failure/no-fit result.
5. Confirm selected historical/future date does not accidentally redefine
`tomorrow` for overdue recovery.
### Acceptance criteria
- Push to tomorrow targets real owner-local tomorrow.
- Push to tomorrow avoids overlaps.
- Push to tomorrow does not depend on the currently selected review date unless
Block 01 deliberately chose that behavior.
---
## Chunk 6.3 — Adjust backend only if tests reveal semantic gaps
### Tasks
1. If existing commands already pass the tests, do not rewrite them.
2. If Push to next can place before current time, add an application/core anchor
parameter rather than filtering in UI.
3. If Push to tomorrow means top-of-queue but not first open slot, update core
semantics or add a clearly named command matching the requested behavior.
4. If no-fit behavior is ambiguous, return an `ApplicationFailure`/notice that
the existing UI can show calmly.
5. Update command/read-hint behavior only as needed to refresh affected dates.
### Acceptance criteria
- Any semantic fix lives in scheduler/application code, not widgets.
- Existing push tests still pass or are updated for the new explicit semantics.
- New behavior is covered before UI integration is considered complete.
---
## Chunk 6.4 — Verify scheduling-change accounting
### Tasks
1. Assert manually pushed selected task records the correct activity/statistics.
2. Assert automatically moved downstream tasks record automatic-push activity.
3. Assert Push to backlog records moved-to-backlog activity and any explicit
freshness reset metadata added in Block 07.
4. Ensure duplicate operation ids remain idempotent/rejected according to the
application command contract.
### Acceptance criteria
- Push activity/statistics remain durable and consistent.
- Downstream movement is auditable.
- Duplicate operation behavior remains safe across close/reopen.
---
## Block acceptance criteria
- Push destination scheduling rules are guaranteed by backend tests.
- No-overlap and no-before-now behavior is proven.
- No-fit behavior keeps tasks safe.
- Activity/statistics accounting remains consistent.
## Validation after block
```sh
cd packages/scheduler_core
dart analyze
dart test
cd ../scheduler_persistence_sqlite
dart test
```

View file

@ -0,0 +1,139 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Task Pushing 01 Block 07 — Backlog Freshness Reset
**Status:** Planned.
**Goal:** Make Push to backlog reset the backlog freshness timer without losing
original task creation history.
---
## Block outcome
After this block, a task pushed to Backlog appears fresh in Backlog even if it
was originally created long ago.
---
## Current issue
Current backlog staleness behavior uses task creation age. That cannot satisfy
`Push to backlog` freshness reset because changing `createdAt` would erase useful
history/reporting truth.
This block should introduce or verify a separate backlog freshness anchor.
---
## Chunk 7.1 — Choose freshness-anchor model
### Preferred model
Add an explicit domain/app field such as `backlogEnteredAt` or
`backlogFreshnessAnchorAt`.
### Tasks
1. Choose a name that expresses UI freshness without pretending to be original
creation time.
2. Store the value when:
- task is quick-captured into Backlog,
- scheduled task is pushed/moved to Backlog,
- any future command deliberately re-enters Backlog.
3. Clear or ignore the value when a task is planned/completed, depending on the
simplest domain invariant.
4. Update `BacklogView` and staleness marker logic to use the freshness anchor
when present, falling back to `createdAt` for older data.
### Acceptance criteria
- Original `createdAt` remains unchanged when pushing to Backlog.
- Backlog staleness marker can become fresh after push-to-backlog.
- Older persisted tasks without the new field still load safely.
---
## Chunk 7.2 — Update persistence mapping and migrations
### Tasks
1. Add the freshness-anchor field to persistence contracts/mappers.
2. If schema v1 has not shipped yet, include the field in the current task schema
with tests.
3. If schema v1 has already landed, add a Drift migration to the next schema
version.
4. Add round-trip tests for:
- null freshness anchor,
- quick-captured freshness anchor,
- push-to-backlog freshness anchor.
5. Ensure JSON/CSV export behavior is not silently broken if export packages map
task fields.
### Acceptance criteria
- SQLite persists the freshness anchor.
- Migration or schema tests cover existing databases.
- Domain-to-row and row-to-domain mapping are symmetric.
---
## Chunk 7.3 — Update transition services
### Tasks
1. Update quick capture to initialize the freshness anchor to capture time for
backlog tasks.
2. Update move/push-to-backlog transitions to set freshness anchor to command
time.
3. Update restore-from-backlog/scheduling transitions to clear or preserve the
anchor according to the invariant chosen in Chunk 7.1.
4. Ensure accounting/statistics still records moved-to-backlog separately from
freshness.
### Acceptance criteria
- Push to backlog sets freshness anchor to current command time.
- Repeated push-to-backlog operations do not corrupt task statistics.
- Scheduling a backlog task still clears schedule/backlog state consistently.
---
## Chunk 7.4 — Add freshness tests
### Required tests
1. Old task created 60 days ago is stale in Backlog before push-reset behavior.
2. Same old task pushed to Backlog now becomes fresh.
3. Close/reopen preserves the fresh marker.
4. Original `createdAt` is unchanged after push to Backlog.
5. Sorting/filtering by age uses the chosen freshness behavior consistently.
### Acceptance criteria
- Backlog marker and stale filter do not disagree.
- Freshness reset survives persistence.
- No report/history field is overwritten to fake freshness.
---
## Block acceptance criteria
- Push to Backlog resets backlog freshness.
- Original creation time is preserved.
- Persistence and migrations support the freshness anchor.
- Backlog read models use the new freshness semantics consistently.
## Validation after block
```sh
cd packages/scheduler_core
dart test
cd ../scheduler_persistence_sqlite
dart test
cd ../scheduler_export
dart test
```
Run export package tests only if task-field mapping is touched there.

View file

@ -0,0 +1,115 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Task Pushing 01 Block 08 — Validation and Handoff
**Status:** Planned.
**Goal:** Prove task pushing works end to end and close the plan cleanly.
---
## Block outcome
After this block, Task Pushing 01 should be complete. Past incomplete planned
flexible tasks can be pushed to next, tomorrow, or Backlog with durable results.
---
## Chunk 8.1 — Add end-to-end UI flow tests
### Required tests
1. Load a selected date with an incomplete past flexible task.
2. Assert the card shows `Push` and suppresses hover quick actions.
3. Open the Push menu and choose `Push to next`.
4. Assert the selected-date timeline refreshes with the backend result.
5. Repeat for `Push to tomorrow` and assert the task appears when tomorrow is
selected.
6. Repeat for `Push to backlog` and assert the task leaves the timeline and
appears in Backlog as fresh where Backlog UI is covered.
7. Complete a past task and assert the Push button disappears.
### Acceptance criteria
- UI flow tests cover all three destinations.
- Tests use command-controller seams or a temp runtime, not widget-side schedule
mutation.
---
## Chunk 8.2 — Add lifecycle persistence tests
### Required tests
1. Push to next, close/reopen, load destination date, assert task placement.
2. Push to tomorrow, close/reopen, load tomorrow, assert task placement.
3. Push to backlog, close/reopen, load Backlog, assert status, cleared schedule,
and fresh staleness marker.
4. Attempt no-fit push, close/reopen, assert the original task remains safe and
unchanged except for any explicitly intended notice/operation record.
5. Attempt duplicate operation id after reopen and assert duplicate behavior is
safe.
### Acceptance criteria
- Persistence is proven through on-disk temp SQLite files.
- Database/runtime handles are explicitly closed before reopen assertions.
- No destination relies on in-memory-only state.
---
## Chunk 8.3 — Run validation gates
### Commands
Run the strongest available validation set:
```sh
scripts/test.sh
cd packages/scheduler_core
dart analyze
dart test
cd ../scheduler_persistence_sqlite
dart analyze
dart test
cd ../../apps/focus_flow_flutter
flutter analyze
flutter test
```
### Acceptance criteria
- All available gates pass.
- If a command is unavailable in the environment, record the exact command and
failure reason in the plan handoff notes.
---
## Chunk 8.4 — Update minimal handoff/status docs
### Tasks
1. Update this plan's summary/status when complete.
2. Move the plan folder only if the project's completed-plan workflow calls for
it.
3. Update `Codex Documentation/Current Software Plan/README.md` to identify the
next planned implementation area, if known.
4. Do not create a broad overall report.
### Acceptance criteria
- The handoff records changed files, decisions, validation, and unverified gates.
- No unrelated docs are rewritten.
---
## Final plan acceptance criteria
- Past incomplete planned flexible cards show a full Push button.
- Push button suppresses hover quick actions.
- Push menu exposes the three requested destinations.
- Push destinations go through backend commands.
- Push results persist through SQLite.
- Push to Backlog resets freshness without rewriting creation history.
- Validation status is documented.

View file

@ -0,0 +1,55 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Task Pushing 01 Execution Order
**Status:** Planned.
Run these files in order. All chunks are intended for `XHIGH` execution unless a
chunk explicitly says otherwise.
1. `TASK_PUSHING_01_BLOCK_01_SCOPE_AND_DOMAIN_SEMANTICS.md`
- Confirm Date Selection 01 and persistence prerequisites.
- Verify flexible-task-only scope or explicitly expand backend support.
- Lock current-time and destination semantics.
2. `TASK_PUSHING_01_BLOCK_02_PAST_TASK_READ_MODEL.md`
- Add past/incomplete push state to read/presentation models.
- Keep detection out of leaf widgets.
- Add mapper tests for today, previous day, future day, completed, and
unsupported task types.
3. `TASK_PUSHING_01_BLOCK_03_PUSH_BUTTON_CARD_UI.md`
- Add the full right-side Push button.
- Place it beside reward/difficulty icons with higher z priority than time
text.
- Suppress hover quick actions while visible.
4. `TASK_PUSHING_01_BLOCK_04_PUSH_MENU_DESTINATIONS.md`
- Add the destination menu.
- Wire menu selection to controller callbacks.
- Preserve keyboard and click-away behavior.
5. `TASK_PUSHING_01_BLOCK_05_COMMAND_WIRING_AND_PERSISTENCE.md`
- Add Flutter command-controller push methods.
- Call application use cases through the selected-date/runtime context.
- Validate close/reopen persistence after each destination.
6. `TASK_PUSHING_01_BLOCK_06_DESTINATION_SCHEDULING_RULES.md`
- Verify or adjust core command behavior for next/tomorrow placement.
- Ensure no-overlap and no-before-now behavior.
- Add backend tests before relying on UI tests.
7. `TASK_PUSHING_01_BLOCK_07_BACKLOG_FRESHNESS_RESET.md`
- Add or verify a separate backlog freshness anchor.
- Reset it when pushing to Backlog.
- Preserve original task creation time for history/reporting.
8. `TASK_PUSHING_01_BLOCK_08_VALIDATION_HANDOFF.md`
- Add end-to-end widget/controller/lifecycle tests.
- Run validation gates.
- Update minimal status docs.
Do not implement broad task editing, drag/drop, Shield, or week/month planning in
this plan.

View file

@ -0,0 +1,127 @@
<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Task Pushing 01 Summary — Past Task Push Controls
**Status:** Planned.
**Scope level:** XHIGH implementation plan.
**Primary outcome:** Past, incomplete scheduled tasks expose a persistent push
control that can move the task to the next available slot, tomorrow's first open
slot, or Backlog.
---
## Current repo facts this plan is based on
1. Scheduler core already has flexible-task push destinations:
`nextAvailableSlot`, `tomorrowTopOfQueue`, and `backlog`.
2. `V1ApplicationCommandUseCases` already exposes push-related commands for
planned flexible tasks:
- `pushFlexibleToNextAvailableSlot`,
- `pushFlexibleToTomorrowTopOfQueue`,
- `moveFlexibleToBacklog`.
3. The Flutter command controller currently wires completion and scheduling, but
push methods are not exposed to card widgets.
4. Timeline cards already have reward and difficulty controls in the trailing
area.
5. Timeline cards already have `showsQuickActions`, but the new past-task push
state must suppress hover actions while the full push button is visible.
6. Current backlog staleness uses task creation age; this does not satisfy the
requested behavior that pushing to Backlog resets the backlog freshness timer.
7. Date Selection 01 should make selected-day reloads and cross-date persistence
reliable before this plan starts.
---
## Product behavior
1. A task that is scheduled in the past and not complete still uses its normal
card styling.
2. While in this past/incomplete state, the card shows a right-side `Push`
button next to reward and difficulty icons.
3. The push button has visual priority over the card time text and sits on a
higher layer if layout overlaps.
4. Hover quick-action buttons do not show while the full `Push` button is shown.
5. Marking the task complete removes the push button and returns the card to
normal completed behavior.
6. Clicking `Push` opens a menu with:
- `Push to next`,
- `Push to tomorrow`,
- `Push to backlog`.
7. Push to next moves the task to the next available no-overlap slot after the
current owner-local time. If a valid slot exists later today, use that.
8. Push to tomorrow moves the task to the first valid no-overlap slot on the next
owner-local day.
9. Push to backlog removes schedule placement and marks the backlog freshness
timer as fresh regardless of the task's original age.
10. All push results persist and survive close/reopen.
---
## Scope assumption to verify in Block 01
V1 core push commands are currently flexible-task oriented. This plan should
apply the push button to planned flexible tasks first. Required, locked,
surprise, and free-slot cards must not receive unsupported push commands unless
Block 01 deliberately expands backend support with tests.
---
## Definition of done
Task Pushing 01 is complete when all of the following are true:
1. The read/presentation model can identify a past, incomplete, planned flexible
task.
2. Past incomplete planned flexible cards show a full `Push` button beside the
reward/difficulty icons.
3. The full push button suppresses hover quick actions.
4. Completed cards never show the full push button.
5. Clicking the push button opens a menu with exactly the three requested
destinations.
6. Push to next uses backend scheduling and never places the task before current
owner-local time.
7. Push to next uses a same-day slot when one is available later today.
8. Push to tomorrow uses the next owner-local day and places into the first valid
no-overlap slot.
9. Push to backlog clears scheduled start/end and resets backlog freshness to
fresh without rewriting original task creation truth.
10. Push commands are persisted through SQLite and survive close/reopen.
11. UI widgets do not contain scheduling, Drift, SQL, or repository logic.
12. Validation gates pass, or unavailable commands are documented.
---
## Non-goals
1. No drag-and-drop push behavior.
2. No schedule review modal unless existing backend result UX already requires
it.
3. No week/month views.
4. No Shield/Recovery flow.
5. No recurring task rollover.
6. No calendar sync.
7. No redesign of reward/difficulty icons beyond layout needed for the Push
button.
8. No frontend-only task movement.
---
## Architecture rule
The push flow must be command-driven:
```text
Past-task presentation flag
-> card Push button
-> push destination menu
-> SchedulerCommandController method
-> V1ApplicationCommandUseCases
-> scheduling core / ApplicationUnitOfWork
-> SQLite persistence
-> selected-date read refresh
```
The card may decide whether to show a button from presentation flags. It must not
calculate canonical new slots or mutate task times.

View file

@ -130,6 +130,36 @@ The provisional UI app lives outside the root Dart workspace at
`apps/focus_flow_flutter` so backend package gates can stay Dart-only while the
Flutter foundation settles.
From the repository root, start the desktop UI with the default local SQLite
database:
```sh
scripts/bootstrap_dev.sh
cd apps/focus_flow_flutter
flutter pub get
flutter run -d linux
```
Replace `linux` with `macos` or `windows` on those hosts. Use `flutter devices`
to list available device IDs. If Flutter reports that the desktop project is
not configured for that platform, generate the missing runner from
`apps/focus_flow_flutter`:
```sh
flutter create --platforms=linux .
```
Use `--platforms=macos` or `--platforms=windows` for those hosts.
For a disposable dev database, pass an explicit SQLite path:
```sh
flutter run -d linux --dart-define=SCHEDULER_SQLITE_PATH=/tmp/focus_flow_dev.sqlite
```
The default database path is `~/ADHD_Scheduler/scheduler.sqlite`. To reset local
UI data, close the app and delete the SQLite file you used.
```sh
cd apps/focus_flow_flutter
flutter analyze

View file

@ -18,12 +18,6 @@ migration:
- platform: linux
create_revision: e1fd963c6f6922bd32afde2e9698a363cd0406d2
base_revision: e1fd963c6f6922bd32afde2e9698a363cd0406d2
- platform: macos
create_revision: e1fd963c6f6922bd32afde2e9698a363cd0406d2
base_revision: e1fd963c6f6922bd32afde2e9698a363cd0406d2
- platform: windows
create_revision: e1fd963c6f6922bd32afde2e9698a363cd0406d2
base_revision: e1fd963c6f6922bd32afde2e9698a363cd0406d2
# User provided section

View file

@ -81,8 +81,36 @@ 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:
```sh
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:
```sh
flutter create --platforms=linux .
```
Use `--platforms=macos` or `--platforms=windows` for those hosts.
Use a disposable dev database when needed:
```sh
flutter run -d linux --dart-define=SCHEDULER_SQLITE_PATH=/tmp/focus_flow_dev.sqlite
```
Check the app from this directory:
```sh
flutter analyze
flutter test
```

View file

@ -52,6 +52,11 @@ class _FocusFlowHomeState extends State<FocusFlowHome> {
}
}
/// Adds a generic filler task from the timeline context menu.
Future<void> _addGenericFlexibleTask() async {
await commandController.addGenericFlexibleTask();
}
/// 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
@ -77,6 +82,7 @@ class _FocusFlowHomeState extends State<FocusFlowHome> {
selectedCard: controller.selectedCard,
onSelectCard: controller.selectCard,
onCompleteCard: _toggleCardCompletion,
onAddTask: _addGenericFlexibleTask,
onClearSelection: controller.clearSelection,
),
TodayScreenReady(:final data) => _TodayScreenScaffold(
@ -84,6 +90,7 @@ class _FocusFlowHomeState extends State<FocusFlowHome> {
selectedCard: controller.selectedCard,
onSelectCard: controller.selectCard,
onCompleteCard: _toggleCardCompletion,
onAddTask: _addGenericFlexibleTask,
onClearSelection: controller.clearSelection,
),
};

View file

@ -13,6 +13,7 @@ class _TodayScreenScaffold extends StatefulWidget {
required this.selectedCard,
required this.onSelectCard,
required this.onCompleteCard,
required this.onAddTask,
required this.onClearSelection,
});
@ -32,6 +33,10 @@ class _TodayScreenScaffold extends StatefulWidget {
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Future<void> Function(TimelineCardModel card) onCompleteCard;
/// Stores the `onAddTask` 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() onAddTask;
/// 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;

View file

@ -61,6 +61,7 @@ class _TodayScreenScaffoldState extends State<_TodayScreenScaffold> {
scrollTargetCardId: _timelineScrollTargetCardId,
scrollRequest: _timelineScrollRequest,
onCardSelected: widget.onSelectCard,
onAddTask: widget.onAddTask,
onCardCompleted: widget.onCompleteCard,
),
),

View file

@ -33,6 +33,12 @@ class SchedulerCommandController extends ChangeNotifier {
/// Clock used by direct UI commands such as marking a task complete.
final DateTime Function() now;
/// Filler title used by the temporary timeline add-task action.
static const _genericFlexibleTaskTitle = 'New flexible task';
/// Filler duration used by the temporary timeline add-task action.
static const _genericFlexibleTaskDurationMinutes = 30;
/// 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;
@ -60,6 +66,24 @@ class SchedulerCommandController extends ChangeNotifier {
);
}
/// Adds a generic flexible task to the next available Today slot.
Future<void> addGenericFlexibleTask() async {
await _run(
label: 'Adding task',
successMessage: 'Task added',
refreshAfterSuccess: true,
action: (operationId) {
return commands.quickCaptureToNextAvailableSlot(
context: contextFor(operationId),
localDate: localDate,
title: _genericFlexibleTaskTitle,
durationMinutes: _genericFlexibleTaskDurationMinutes,
projectId: quickCaptureProjectId,
);
},
);
}
/// Schedules a backlog task into the next available slot.
Future<void> scheduleBacklogItem({
required String taskId,

View file

@ -24,8 +24,6 @@ class Sidebar extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const _WindowControls(),
const SizedBox(height: 34),
const _BrandRow(),
const SizedBox(height: 34),
_NavItem(
@ -51,51 +49,6 @@ class Sidebar extends StatelessWidget {
}
}
/// Private implementation type for `_WindowControls` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _WindowControls extends StatelessWidget {
/// Creates a `_WindowControls` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _WindowControls();
/// Builds the widget subtree for this component.
/// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
@override
Widget build(BuildContext context) {
return const Row(
children: [
_WindowDot(color: Color(0xFFFF5F57)),
SizedBox(width: 12),
_WindowDot(color: Color(0xFFFFBD2E)),
SizedBox(width: 12),
_WindowDot(color: Color(0xFF28C840)),
],
);
}
}
/// Private implementation type for `_WindowDot` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _WindowDot extends StatelessWidget {
/// Creates a `_WindowDot` instance with the values required by its invariants.
/// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
const _WindowDot({required this.color});
/// Stores the `color` value for this object.
/// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
final Color color;
/// Builds the widget subtree for this component.
/// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
@override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
child: const SizedBox(width: 16, height: 16),
);
}
}
/// 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 {

View file

@ -24,6 +24,7 @@ class TimelineView extends StatefulWidget {
required this.cards,
required this.range,
required this.onCardSelected,
this.onAddTask,
this.onCardCompleted,
this.now,
this.scrollTargetCardId,
@ -40,6 +41,9 @@ class TimelineView extends StatefulWidget {
/// Callback invoked when a card is selected.
final ValueChanged<TimelineCardModel> onCardSelected;
/// Callback invoked when the timeline context menu requests a new task.
final Future<void> Function()? onAddTask;
/// Callback invoked when a task card status control requests completion.
final ValueChanged<TimelineCardModel>? onCardCompleted;

View file

@ -3,6 +3,12 @@
part of '../timeline_view.dart';
/// Actions exposed by the timeline context menu.
enum _TimelineMenuAction {
/// Adds a generic flexible task to the timeline.
addTask,
}
/// 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> {
@ -83,6 +89,11 @@ class _TimelineViewState extends State<TimelineView> {
_scheduleTargetScroll(_geometry);
return ScrollConfiguration(
behavior: const _TimelineScrollBehavior(),
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onSecondaryTapDown: widget.onAddTask == null
? null
: _showTimelineMenu,
child: SingleChildScrollView(
controller: _scrollController,
child: SizedBox(
@ -141,11 +152,38 @@ class _TimelineViewState extends State<TimelineView> {
),
),
),
),
);
},
);
}
/// Shows the timeline context menu and dispatches the selected action.
Future<void> _showTimelineMenu(TapDownDetails details) async {
final overlay = Overlay.of(context).context.findRenderObject();
if (overlay is! RenderBox) {
return;
}
final position = RelativeRect.fromRect(
details.globalPosition & Size.zero,
Offset.zero & overlay.size,
);
final action = await showMenu<_TimelineMenuAction>(
context: context,
position: position,
items: const [
PopupMenuItem<_TimelineMenuAction>(
value: _TimelineMenuAction.addTask,
child: Text('Add new task'),
),
],
);
if (!mounted || action != _TimelineMenuAction.addTask) {
return;
}
await widget.onAddTask?.call();
}
/// 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() {

View file

@ -6,6 +6,10 @@
#include "generated_plugin_registrant.h"
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar);
}

View file

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
sqlite3_flutter_libs
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST

View file

@ -1,7 +0,0 @@
# Flutter-related
**/Flutter/ephemeral/
**/Pods/
# Xcode-related
**/dgph
**/xcuserdata/

View file

@ -1 +0,0 @@
#include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -1 +0,0 @@
#include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -1,10 +0,0 @@
//
// Generated file. Do not edit.
//
import FlutterMacOS
import Foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
}

View file

@ -1,729 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXAggregateTarget section */
33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
buildPhases = (
33CC111E2044C6BF0003C045 /* ShellScript */,
);
dependencies = (
);
name = "Flutter Assemble";
productName = FLX;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 33CC10EC2044A3C60003C045;
remoteInfo = Runner;
};
33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 33CC111A2044C6BA0003C045;
remoteInfo = FLX;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
33CC110E2044A8840003C045 /* Bundle Framework */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Bundle Framework";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* focus_flow_flutter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "focus_flow_flutter.app"; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
331C80D2294CF70F00263BE5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
33CC10EA2044A3C60003C045 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C80D6294CF71000263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C80D7294CF71000263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
33BA886A226E78AF003329D5 /* Configs */ = {
isa = PBXGroup;
children = (
33E5194F232828860026EE4D /* AppInfo.xcconfig */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
);
path = Configs;
sourceTree = "<group>";
};
33CC10E42044A3C60003C045 = {
isa = PBXGroup;
children = (
33FAB671232836740065AC1E /* Runner */,
33CEB47122A05771004F2AC0 /* Flutter */,
331C80D6294CF71000263BE5 /* RunnerTests */,
33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */,
);
sourceTree = "<group>";
};
33CC10EE2044A3C60003C045 /* Products */ = {
isa = PBXGroup;
children = (
33CC10ED2044A3C60003C045 /* focus_flow_flutter.app */,
331C80D5294CF71000263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
33CC11242044D66E0003C045 /* Resources */ = {
isa = PBXGroup;
children = (
33CC10F22044A3C60003C045 /* Assets.xcassets */,
33CC10F42044A3C60003C045 /* MainMenu.xib */,
33CC10F72044A3C60003C045 /* Info.plist */,
);
name = Resources;
path = ..;
sourceTree = "<group>";
};
33CEB47122A05771004F2AC0 /* Flutter */ = {
isa = PBXGroup;
children = (
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
);
path = Flutter;
sourceTree = "<group>";
};
33FAB671232836740065AC1E /* Runner */ = {
isa = PBXGroup;
children = (
33CC10F02044A3C60003C045 /* AppDelegate.swift */,
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
33E51913231747F40026EE4D /* DebugProfile.entitlements */,
33E51914231749380026EE4D /* Release.entitlements */,
33CC11242044D66E0003C045 /* Resources */,
33BA886A226E78AF003329D5 /* Configs */,
);
path = Runner;
sourceTree = "<group>";
};
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C80D4294CF70F00263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
331C80D1294CF70F00263BE5 /* Sources */,
331C80D2294CF70F00263BE5 /* Frameworks */,
331C80D3294CF70F00263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C80DA294CF71000263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
33CC10EC2044A3C60003C045 /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
);
buildRules = (
);
dependencies = (
33CC11202044C79F0003C045 /* PBXTargetDependency */,
);
name = Runner;
packageProductDependencies = (
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
);
productName = Runner;
productReference = 33CC10ED2044A3C60003C045 /* focus_flow_flutter.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
33CC10E52044A3C60003C045 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C80D4294CF70F00263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 33CC10EC2044A3C60003C045;
};
33CC10EC2044A3C60003C045 = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 1100;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Sandbox = {
enabled = 1;
};
};
};
33CC111A2044C6BA0003C045 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Manual;
};
};
};
buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 33CC10E42044A3C60003C045;
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
);
productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
33CC10EC2044A3C60003C045 /* Runner */,
331C80D4294CF70F00263BE5 /* RunnerTests */,
33CC111A2044C6BA0003C045 /* Flutter Assemble */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C80D3294CF70F00263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
33CC10EB2044A3C60003C045 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
};
33CC111E2044C6BF0003C045 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
Flutter/ephemeral/FlutterInputs.xcfilelist,
);
inputPaths = (
Flutter/ephemeral/tripwire,
);
outputFileListPaths = (
Flutter/ephemeral/FlutterOutputs.xcfilelist,
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C80D1294CF70F00263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
33CC10E92044A3C60003C045 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C80DA294CF71000263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 33CC10EC2044A3C60003C045 /* Runner */;
targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */;
};
33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
33CC10F52044A3C60003C045 /* Base */,
);
name = MainMenu.xib;
path = Runner;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
331C80DB294CF71000263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.focusFlowFlutter.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/focus_flow_flutter.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/focus_flow_flutter";
};
name = Debug;
};
331C80DC294CF71000263BE5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.focusFlowFlutter.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/focus_flow_flutter.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/focus_flow_flutter";
};
name = Release;
};
331C80DD294CF71000263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.focusFlowFlutter.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/focus_flow_flutter.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/focus_flow_flutter";
};
name = Profile;
};
338D0CE9231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Profile;
};
338D0CEA231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Profile;
};
338D0CEB231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Profile;
};
33CC10F92044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
33CC10FA2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
33CC10FC2044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
33CC10FD2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Release;
};
33CC111C2044C6BA0003C045 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
33CC111D2044C6BA0003C045 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C80DB294CF71000263BE5 /* Debug */,
331C80DC294CF71000263BE5 /* Release */,
331C80DD294CF71000263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10F92044A3C60003C045 /* Debug */,
33CC10FA2044A3C60003C045 /* Release */,
338D0CE9231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10FC2044A3C60003C045 /* Debug */,
33CC10FD2044A3C60003C045 /* Release */,
338D0CEA231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC111C2044C6BA0003C045 /* Debug */,
33CC111D2044C6BA0003C045 /* Release */,
338D0CEB231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
/* End XCLocalSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
isa = XCSwiftPackageProductDependency;
productName = FlutterGeneratedPluginSwiftPackage;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 33CC10E52044A3C60003C045 /* Project object */;
}

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -1,117 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Prepare Flutter Framework Script"
scriptText = "&quot;$FLUTTER_ROOT&quot;/packages/flutter_tools/bin/macos_assemble.sh prepare&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "focus_flow_flutter.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PreActions>
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "focus_flow_flutter.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "focus_flow_flutter.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C80D4294CF70F00263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "focus_flow_flutter.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "focus_flow_flutter.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -1,13 +0,0 @@
import Cocoa
import FlutterMacOS
@main
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
}

View file

@ -1,68 +0,0 @@
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_1024.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -1,343 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target">
<connections>
<outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
<outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="APP_NAME" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About APP_NAME" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="EPT-qC-fAb">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/>
</menuItem>
</items>
<point key="canvasLocation" x="142" y="-258"/>
</menu>
<window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="335" y="390" width="800" height="600"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</window>
</objects>
</document>

View file

@ -1,14 +0,0 @@
// Application-level settings for the Runner target.
//
// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
// future. If not, the values below would default to using the project name when this becomes a
// 'flutter create' template.
// The application's name. By default this is also the title of the Flutter window.
PRODUCT_NAME = focus_flow_flutter
// The application's bundle identifier
PRODUCT_BUNDLE_IDENTIFIER = com.example.focusFlowFlutter
// The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2026 com.example. All rights reserved.

View file

@ -1,2 +0,0 @@
#include "../../Flutter/Flutter-Debug.xcconfig"
#include "Warnings.xcconfig"

View file

@ -1,2 +0,0 @@
#include "../../Flutter/Flutter-Release.xcconfig"
#include "Warnings.xcconfig"

View file

@ -1,13 +0,0 @@
WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
GCC_WARN_UNDECLARED_SELECTOR = YES
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
CLANG_WARN_PRAGMA_PACK = YES
CLANG_WARN_STRICT_PROTOTYPES = YES
CLANG_WARN_COMMA = YES
GCC_WARN_STRICT_SELECTOR_MATCH = YES
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
GCC_WARN_SHADOW = YES
CLANG_WARN_UNREACHABLE_CODE = YES

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

View file

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_COPYRIGHT)</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View file

@ -1,15 +0,0 @@
import Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
override func awakeFromNib() {
let flutterViewController = FlutterViewController()
let windowFrame = self.frame
self.contentViewController = flutterViewController
self.setFrame(windowFrame, display: true)
RegisterGeneratedPlugins(registry: flutterViewController)
super.awakeFromNib()
}
}

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
</plist>

View file

@ -1,12 +0,0 @@
import Cocoa
import FlutterMacOS
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}

View file

@ -276,6 +276,32 @@ void main() {
expect(scrollable.position.pixels, greaterThan(beforeDrag + 80));
});
testWidgets('timeline context menu adds a generic flexible task', (
tester,
) async {
final composition = _composition();
await _pumpPlanApp(tester, composition: composition);
await tester.tapAt(
tester.getCenter(find.byType(TimelineView)),
buttons: kSecondaryMouseButton,
);
await tester.pumpAndSettle();
expect(find.text('Add new task'), findsOneWidget);
await tester.tap(find.text('Add new task'));
await tester.pumpAndSettle();
final addedTask = composition.store.currentTasks.singleWhere(
(task) => task.title == 'New flexible task',
);
expect(addedTask.type, TaskType.flexible);
expect(addedTask.status, TaskStatus.planned);
expect(addedTask.durationMinutes, 30);
expect(find.text('New flexible task'), findsOneWidget);
});
testWidgets('timeline splits partial overlaps and reuses empty lanes', (
tester,
) async {

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