Skip to content

feat: polish dashboard usage animations - #44

Merged
bubbleptr merged 4 commits into
mainfrom
feature/dashboard-usage-animations
Jun 12, 2026
Merged

bubbleptr merged 4 commits into
mainfrom
feature/dashboard-usage-animations

Conversation

@bubbleptr

Copy link
Copy Markdown
Owner

Summary

  • Limit the home dashboard app distribution donut to four primary apps plus an Others bucket.
  • Add the counterclockwise donut reveal with rounded moving and terminal caps, including the early terminal cap fix so no lighter color leaks at the start point.
  • Align the Swift app and website dashboard animation timing with a shared closing-slow easing curve, while keeping the hourly bars growing left-to-right.

Validation

  • xcodebuild -project Voily.xcodeproj -scheme Voily -configuration Debug -derivedDataPath .xcodebuild -only-testing:VoilyTests/DashboardHomePageTests test
  • bun test src/components/DashboardWindow.test.ts
  • bun run build
  • make build
  • Browser check on http://127.0.0.1:5173/: verified no console warnings/errors, shared cubic-bezier(0.24, 0.72, 0.22, 1) timing, and 45ms left-to-right bar delay steps.

@github-actions

github-actions Bot commented Jun 12, 2026 •

Copy link
Copy Markdown

🤖 Open Code Review

Model deepseek-v4-flash · 9 comments · 0 warnings

  • Tests/VoilyTests/App/DashboardHomePageTests.swift:33 — The test hardcodes the raw string "__other__" instead of referencing the production constant FrontApplicationDistributionDisplay.otherBundleID. If this constant is ever changed (e.g., to a different sentinel value), the tests will silently use the old value and may produce false passes (or worse, pass with incorrect data). Consider using FrontApplicationDistributionDisplay.otherBundleID to keep the test in sync with production.
  • Tests/VoilyTests/App/DashboardHomePageTests.swift:59 — Same issue — hardcoded "__other__" string should reference the production constant for consistency and maintainability.
  • Tests/VoilyTests/App/DashboardHomePageTests.swift:59 — Same issue — hardcoded "__other__" string in the unattributed total test.
  • Sources/VoilyApp/Features/Settings/DashboardHomePage.swift:565 — Dead onChange wiring – The onChange(of: animationToken) triggers animateReveal() on every data change, but shouldStartDonutReveal(currentProgress:) returns false once revealProgress > 0.02 (i.e., after the initial animation completes). This means subsequent calls are silently no-ops. The animationToken property exists solely to drive this onChange, making both the property and the modifier dead code after the first animation. The test `testUsageDashboardAnimationsDoNotRest...
  • website/src/styles.css:1026 — Consider extracting animation durations into CSS custom properties (e.g., --anim-duration-donut: 960ms; --anim-duration-bars: 580ms) to centralize timing adjustments and improve long-term maintainability.
  • Sources/VoilyApp/Features/Settings/DashboardHomePage.swift:564 — Missing prefers-reduced-motion handling – The website CSS includes a @media (prefers-reduced-motion: reduce) block that disables all donut and bar animations, respecting the user’s accessibility preference. The Swift implementation has no equivalent guard. On macOS 14+, users with Reduce motion enabled in System Settings → Accessibility → Display will still see the reveal animation, which can cause discomfort for users with vestibular disorders. Recommendation: Check `UIAccess...
  • Sources/VoilyApp/Features/Settings/DashboardHomePage.swift:0 — Missing 120ms initial animation delay – The website CSS applies a 120ms delay (animation: scene-donut-counterclockwise-reveal 960ms var(--dashboard-closing-ease) 120ms forwards) before the donut reveal starts. The Swift implementation begins the animation immediately on onAppear with no initial delay. This causes a slight visual desync between the two surfaces – the native chart snaps into animation while the website pauses briefly. The same applies to the terminal cap and moving head...
  • Sources/VoilyApp/Features/Settings/DashboardHomePage.swift:926 — Dead onChange and misleading guard – Same pattern as the donut chart: onChange(of: summaries) calls animateBars() on every data change, but shouldStartHourlyBars(isVisible:) returns false once barsVisible is true. After the initial appearance, all subsequent data updates silently do nothing. The test testUsageDashboardAnimationsDoNotRestartAfterInitialReveal validates this guard behaviour, confirming it is by design. However, the onChange modifier remains as dead code th...
  • Sources/VoilyApp/Features/Settings/DashboardHomePage.swift:595 — Minor code smell: animationToken builds a concatenated string of all summary identifiers and session counts, creating new String allocations on every data change. It is used only to drive the onChange(of:) modifier, which itself is dead code after the first animation (see above). If the onChange is kept and re-animation is implemented, consider a simpler change tracker (e.g., an incremental counter or hashed value) instead of string concatenation.

@bubbleptr
bubbleptr merged commit c451b3b into main Jun 12, 2026
1 check passed
@bubbleptr
bubbleptr deleted the feature/dashboard-usage-animations branch June 12, 2026 17:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant