mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-10 20:27:13 +01:00
Renames this repo's markdown onto README.md / CLAUDE*.md / DOCS*.md / TODO*.md so a future session can tell a live task from a finished record without reading the file to find out. TODO files carry the literal "REMOVE ME AFTER FINISH" and are deleted when the work lands. Enforced by the md-naming pre-commit hook and CI workflow, both delegating to the shared gate in kuhyx/utils so this repo's idea of a valid name cannot drift from every other repo's. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A47aX5DJwmA3QFn3pkEWi7
8.8 KiB
8.8 KiB
Flutter app (stronglift_replacement/workout_app/)
Design-token entry point: lib/main.dart:68-74 declares
ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo, brightness: Brightness.dark), useMaterial3: true) — a real Material 3 seed
theme exists. However, Theme.of(context) / colorScheme is referenced
zero times anywhere in lib/screens/ or lib/widgets/ (confirmed via
repo-wide grep). The theme is declared but never consumed — every one of the
24 .dart files under lib/ hardcodes colors directly instead.
Colors.*literals: ~210 occurrences acrossscreens/andwidgets/, 27 distinct named colors. Most common:Colors.white(98×),Colors.grey.shade800(18×),Colors.redAccent(12×),Colors.greenAccent(11×),Colors.grey.shade900(10×).- Raw hex
Color(0xFF...)literals bypassingColors.*entirely:manual_workout_screen.dart:173,201(Color(0xFFFF4444)) andmanual_workout_screen.dart:238,246(Color(0xFF88CCFF)) — these are the exact same hex values independently hardcoded on the Python/Tkinter side (#ff4444and#88ccff, see e.g._sick_dialog.py:70,_manual_workout_dialog.py:58), coincidentally kept in sync only because no one has touched either yet. fontSize:/fontWeight:literals: 72 occurrences;history_screen.dartalone uses 12 distinct font sizes (9, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 26).
Violations
- Rule 4 (everything deliberate / single source of truth) —
main.dartbuilds aColorScheme.fromSeed, but it is dead code from a theming standpoint: no screen or widget reads it. Every screen re-derives its own ad hoc dark palette fromColors.grey.shade900/800/700plus assorted accent colors, so a single rebrand (e.g. changing the seed color) would require manually editing all 24 files instead of one. - Rule 1 (near-black/white, not pure) —
Colors.white(pure#FFFFFF) used 98 times for primary text/icons, e.g.home_screen.dart:113,122,128, 211,248,267,settings_screen.dart:231,278,430,history_screen.dart:209,410.Colors.blackalso appears atrep_circle.dart:76(Colors.black87, near-pure) as text-on-white in the neutral rep-circle state. None of these are the theme's actual near-white/near-black — they're Flutter's pure-value constants. - Rule 2 (saturate your neutrals) —
Colors.grey.shade900/800/700/400are Material's standard zero-saturation grays (equal R=G=B), used as the entire background/surface system in place ofcolorScheme.surface(which, being seeded from indigo, would be saturated). Bypassing the theme produces exactly the generic-gray outcome the theme was set up to avoid. - Rule 9 (distinct brightness values) —
Colors.redAccent(errors) andColors.orangeAccent/Colors.orange.shade800(pending/resume state) are both used as status-signal colors of similar brightness in adjacent UI (e.g.home_screen.dart:222orangeAccent for active-session text next toColors.greenAccentfor success at line 200 — three status colors of comparable weight competing in one card). - Rule 18 (container brightness limits, dark ≤~12%) — The repeated
Scaffold(backgroundColor: Colors.grey.shade900)/AppBar(backgroundColor: Colors.grey.shade800)pairing (Materialshade900=#212121, luma 12.9%;shade800=#424242, luma 25.9% — a ~13-point jump) appears in every screen'sScaffold/AppBar:home_screen.dart:104,106,settings_screen.dart:275,277,history_screen.dart:206,208,workout_screen.dart:495,498,manual_workout_screen.dart:154,156. This exceeds the ~12% dark-interface guideline every time it's used. - Rule 20 (body text ≥16px) — Extensive small body text below 16px:
fontSize: 9athistory_screen.dart:612,fontSize: 11(11 occurrences, e.g.home_screen.dart:311,history_screen.dart:333,486,612,settings_screen.dart:388),fontSize: 12(14 occurrences),fontSize: 13(7 occurrences) — well under the 16px minimum for supporting/secondary text throughout. - Rule 22 (button padding: horizontal ≈2x vertical) —
home_screen.dart: 242and:261setpadding: const EdgeInsets.symmetric(vertical: 14)on full-widthElevatedButtons with nohorizontal:argument, which defaultshorizontalto0.0— the inverse of "horizontal ≈2x vertical". - Rule 26 (no shadows in dark interfaces) — The app declares
brightness: Brightness.dark(main.dart:71), yetrep_circle.dart: 105-111adds an explicitBoxShadow(color: Colors.black26, blurRadius: 4, offset: Offset(0, 2))to the rep-tracking circle — the one shadow in the whole app, in a UI this rule says shouldn't have any.
Not applicable
- Rule 5 (optical alignment) — standard Material icons/widgets are already optically centered by the framework; no custom asymmetric glyphs.
- Rule 6 (letter-spacing/line-height by size) — the only
letterSpacinguses found (home_screen.dart:311→ 1.1,history_screen.dart:333→ 1.3,settings_screen.dart:388→ 1.4) are all on the same smallfontSize: 11eyebrow-label text, consistently given positive tracking as the rule recommends for small text — no counter-example at larger sizes to check against, so marked N/A rather than a forced Pass. - Rule 7 (border contrast) —
Border.all(color: color.withValues(alpha: 0.4))(settings_screen.dart:491) derives border color from the same status color as the fill, by design (a tinted pill), not a container-edge border this rule targets. - Rule 8 (align with something else) — standard
Column/Row/ListViewlayouts; no cross-screen alignment grid to check. - Rule 12 (order by visual weight) — screens are single-column flows (cards stacked top-to-bottom); no left/right or center/edge weight arrangement to evaluate.
- Rule 13 (12-column grid) — mobile single-column layouts throughout; no multi-column grid system in use.
- Rule 14 (space between contrast edges) — cannot be verified statically without rendering the widget tree.
- Rule 15 (closer elements lighter) —
Cards atshade800sit onshade900backgrounds (lighter-on-darker as they "lift"), which is directionally correct, but see Rule 18 above for the magnitude issue. - Rule 17 (simple on complex) — flat-colored cards/containers throughout; nothing complex to conflict with.
- Rule 19 (outer padding ≥ inner padding) — spot-checked
home_screen.dart:143(EdgeInsets.all(24)outer) vs. its nested_WorkoutCardinternal padding (EdgeInsets.all(16),home_screen.dart:188) — outer ≥ inner, consistent with the rule; not exhaustively checked across all 24 files. - Rule 21 (line length ~70 chars) — Flutter
Textwraps by default at widget width; no unbounded-line risk equivalent to the Tk surface. - Rule 23 (two typefaces max) — no custom
fontFamilyset anywhere; the whole app uses the Material/system default typeface. Trivially compliant. - Rule 24 (nest corners) —
BorderRadius.circular(8)is reused verbatim across unrelated containers (home_screen.dart:301,calendar_widget.dart:63,history_screen.dart:402,643,705,772,settings_screen.dart:490,548,587) but none of these visibly nest inside another rounded container in the surrounding code, so there's no outer/inner radius relationship to check. - Rule 25 (avoid adjacent hard divides) — only one
Dividerfound (exercise_tile.dart:115), not adjacent to another border/divide. - Rule 27 (don't mix depth techniques) — the app consistently uses flat
Container/Cardfills with no shadow except the single instance flagged under Rule 26; effectively one depth style (none) throughout, so no mixing to flag. - Rule 28 (lower icon contrast next to text) — icons consistently use
Colors.white54/Colors.white38/Colors.white70(already lower-contrast than adjacent full-white/near-white text) rather than fullColors.white, e.g.exercise_tile.dart:150,160,167,177,248,252,history_screen.dart:331,486,507— this one is actually already followed reasonably consistently. Pass.
Notes
- Rule 4 is the dominant finding for this surface too: an unused
ColorScheme.fromSeedplus ~210 ad hocColors.*/Color(0x...)literals means every other color/contrast rule (1, 2, 9, 18) is failing as a direct consequence of the same root cause, not independently. Routing all 24 files throughTheme.of(context).colorScheme(or a small sharedAppColors/AppTextStylesclass) would be the highest-leverage single fix. - The coincidental hex overlap between
Color(0xFFFF4444)/Color(0xFF88CCFF)(Flutter) and#ff4444/#88ccff(Python/Tkinter) shows the two UI surfaces are visually related by convention only — there is no shared token file either could import from, on either language side.