feat: incremental focus ladder + a deeper Better Stats window - #513
Open
gluansinha-star wants to merge 8 commits into
Open
gluansinha-star wants to merge 8 commits into
gluansinha-star wants to merge 8 commits into
Conversation
Adds two opt-in features on top of upstream Pomotroid, plus a fix for a date-arithmetic bug that made several statistics render as zeros. Incremental Focus - New settings: incremental_work_enabled, time_work_increment_secs, time_work_max_secs (MIGRATION_7 seeds them, so existing DBs upgrade cleanly). - SequenceState owns the ladder: a work round is lengthened by the increment for every work round already completed in the cycle, capped at the ceiling and never shorter than the configured base duration. The first round uses the base duration as-is, breaks are never escalated, and the ladder resets after a long break and on manual Reset. - TimerSnapshot carries the ladder state to the frontend so the UI can show the current step, and Settings -> Timer gains controls plus a live ladder preview. Better Stats - New "better-stats" window, opened from the titlebar, alongside the original Statistics window which is untouched. - Backend: stats_get_insights returns everything in one IPC round-trip — today's activity, trailing 7/28/90-day windows, week-over-week comparisons, a 28-day trend with a 7-day moving average, a 12-week rollup, a 120-day heatmap, full daily history, an all-time weekday x hour grid, a session-length histogram, 30-day consistency metrics, streaks, and personal bests. - Frontend: hand-rolled SVG charts (area/line, ring, donut, bars, heatmap, weekday x hour grid, ranked bars) in src/lib/components/better-stats. - Heatmap has Recent / Month / Year scopes; the month view renders a real calendar with day numbers and navigation. - Durations read naturally: 45m, then 1h 30m, and whole hours past ten (12h). Fixes - day_num_to_date was shifted by one day and weekday_index was misaligned, so the 28-day trend and weekly rollup produced dates that matched no session and rendered as zeros. Both are corrected and pinned by tests, along with the exact day numbers for known dates. Tooling - scripts/seed-demo-data.mjs generates realistic history for reviewing the stats windows; scripts/sync-messages.mjs keeps locale files in sync with en.json. - src/lib/dev/mockTauri.js lets the UI run under plain `npm run dev` in a browser by standing in for the Rust backend. Guarded by import.meta.env.DEV, so it never ships in a production build. README documents the fork, both features, and the development helpers.
Adds four screenshots to the README, captured from a running build: - incremental-focus-settings.png — Settings -> Timer, showing the Incremental Focus toggle, the Add per Round and Maximum Focus controls, and the live focus-ladder preview. - better-stats-momentum.png — today's ring against the trailing 7-day average, the streak strip, week-over-week comparisons, the rolling window cards, and the 28-day trend with its 7-day moving average plus the weekly bar charts. - better-stats-consistency.png — the 120-day heatmap with its Recent/Month/Year scopes, the habit-strength donut and steadiness figures, the focus window, and the round-length mix. - better-stats-rhythm.png — the weekday x hour rhythm grid, focus-by-weekday and focus-by-hour breakdowns, and personal bests. Each image is referenced next to the feature it documents rather than dropped into a single gallery. Also adds scripts/capture-screenshots.mjs, which drives Edge over the DevTools Protocol to capture full-page PNGs at 2x from the running dev server. Its browser profile is created under the OS temp directory on purpose: keeping it inside the project tree makes Vite's file watcher fail with EBUSY on the browser's locked SQLite files. For the same reason .tmp/ is now gitignored.
scripts/publish-release.mjs creates the release on this fork and attaches the NSIS installer, the MSI and a portable zip built from the release binary. It reuses the credential Git Credential Manager already stores for github.com and reads the release body from ../release-notes.md. Done in Node rather than PowerShell on purpose: ConvertTo-Json serialised the FileInfo object instead of the release-notes text, so the API rejected the payload with a 422. Also documents the script in the development-helpers section.
The ladder used to restart at every long break. Both reset triggers are now
settings, and the ladder is persisted so it survives an app restart:
- incremental_reset_on_long_break: restart when a long break begins
(default on, so the previous behaviour is unchanged)
- incremental_reset_daily: restart when the local calendar day changes
(default on)
With both off the ladder keeps climbing until it is reset by hand. A manual
Reset Focus Ladder action (new timer_reset_increment command) drops the ladder
back to the base duration without touching the round, cycle or session
counters; the footer Reset still clears it along with the session.
The day is read through SQLite's date('now','localtime') so it matches the
stats queries, and a rollover only applies while the timer is idle: a round
that is already running keeps the duration it was primed with, and a work
round that finishes just after midnight is credited to the day it started in.
Adds MIGRATION_8 for the two settings, stores the ladder in the settings
key/value table under ladder_steps/ladder_day, reflects it in the settings UI
and the dev mock, and covers it with unit tests.
Second Windows build of the fork: configurable incremental focus ladder resets on top of the Incremental Focus and Better Stats features.
The bundle directory keeps the installers of earlier releases, so globbing for the first *-setup.exe could attach the previous version's file. Match on the version from package.json and fail loudly when it is missing.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
Two opt-in features on top of upstream Pomotroid 1.7.1. Both are off by default, so the app behaves
exactly like upstream until you turn them on.
1. Incremental Focus
Each completed focus round makes the next one longer, up to a ceiling you choose.
Configured in Settings → Timer → Incremental Focus:
With a 25-minute focus and a 5-minute increment capped at 45 minutes the ladder runs
25 → 30 → 35 → 40 → 45 → 45 → …, and the settings panel renders a live preview of it.
Behaviour:
Focus time.
25m +10m · step 3,plus
· cappedonce the ceiling is reached.The ladder lives in
SequenceStateand reaches the frontend through six newTimerSnapshotfields.Three new settings persist via MIGRATION_7, so existing databases upgrade without data loss.
2. Better Stats
A new window opened from the titlebar, sitting next to the original Statistics window (which is
untouched and still works exactly as before).
verdict, a streak strip that warns when a live streak has nothing logged today, week-over-week
comparisons for rounds / focus time / active days / average per active day, and rolling 7, 28 and
90-day windows.
day/week toggle; 12-week focus-minutes and rounds bar charts.
calendar with day numbers, today outlined, future days dashed and
‹ ›navigation) and Yearscopes; a habit-strength donut splitting the last 30 days into strong / light / rest; steadiness
(standard deviation of daily rounds), best run, your focus window, and a round-length histogram.
plus ranked focus-by-weekday and focus-by-hour breakdowns.
length, tracked days, streaks.
Everything arrives in a single IPC call (
stats_get_insights) so there is no staggered loading, andcharts are hand-rolled SVG with no new dependencies. Durations read naturally:
45m, then1h 30m,and whole hours past ten (
12h).Bug fix
While building the stats window I hit a real bug that made several panels render as zeros:
day_num_to_date()was shifted by one day, so every date it produced missed every real session.weekday_index()was misaligned by one, skewing the weekday profile and the weekday-by-hour grid.Together these made
fill_recent_days()(the 28-day trend) androll_up_weeks()(the weekly chart)build windows containing dates that matched no history. Both are corrected and pinned by tests,
including exact day numbers for known dates and round-trips across leap years,
1970-01-01and2100-03-01.Screenshots
| Better Stats — consistency | Better Stats — rhythm |
Testing
npm run check— 0 errors, 0 warnings.npm run tauri build— produces the NSIS installer and MSI successfully.break and on Reset; the stats window renders all sections and the heatmap navigates across months
and years.
Not yet run:
cargo test. Tests are written for the new ladder logic, the date fix and the newquery helpers, but the suite has not been executed. Worth running before merge.
Notes for reviewers
src-tauri/src/db/queries.rscarries most of the new Rust; the insights layer pulls the fullhistory once and derives every metric in Rust, which keeps the SQL simple and the snapshot
consistent.
src/lib/dev/mockTauri.jsis a dev-only IPC stand-in so the UI can be previewed under plainnpm run devin a browser. It is guarded byimport.meta.env.DEVand never enters a productionbuild, but it is the one addition worth a deliberate look if you'd rather not carry it.
scripts/sync-messages.mjs; real translations are still needed for the non-English locales.