Skip to content

fix(ui): recount failed-download aggregates and restore card icon colors - #1201

Merged
everpcpc merged 2 commits into
mainfrom
fix/download-aggregate-followups
Oct 4, 2026
Merged

everpcpc merged 2 commits into
mainfrom
fix/download-aggregate-followups

Conversation

@everpcpc

@everpcpc everpcpc commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

Problem

Follow-up to the four-batch UI review (#1197–#1200), fixing two regressions that round introduced, plus the nits called out in the post-merge review:

  • Stuck red failure state after Cancel/Retry All Failed. retryFailedBooks/cancelFailedBooks rewrite book-level downloadStatusRaw in bulk without recounting the series/read-list rollups. With the new aggregate failed state, Cancel All Failed left the aggregate pinned at failed (red icon stuck until some unrelated download event happened to trigger a recount), and Retry All Failed violated the "any pending → pending" rule until each book's next status change.
  • Gray download icons on tinted/overlay cards. DownloadStatus.displayColor is non-optional (.secondary for everything but failures), so the downloadColor ?? palette.metaColor / ?? style.secondaryColor fallbacks in HorizontalCardSkeleton and GridCardView never fired — horizontal cards on a cover tint lost their white-70% accessory color, and overlay-mode grid cards lost their white-85% icon color.
  • Dashboard section detail pages for local sections (Keep Reading, On Deck) told users to "Try selecting a different library." when empty, which makes no sense for server-independent sections.
  • The macOS EPUB theme page still used the old combined-label sliders (the iOS page was unified in the earlier batch), which also forced the old Label: %@x keys to stay.
  • The DIVINA page-transition picker's caption swap lost its animation when the broad Form-level animations were scoped down.
  • macOS scroll arrows advanced only about half a page from the second click on (index computed from the leading edge while scrolling anchored to the center).
  • Heatmap hit containers (28pt on a 17pt pitch) overlapped by 11pt, so each tile's trailing edge selected its neighbor.
  • A failed book's download action read "Make Offline", indistinguishable from a never-downloaded book.

Fix

  • After the bulk status writes, recount the rollups for every affected series and every read list containing the books, inside the same transaction (shared recountDownloadAggregates helper; bulk writes bypass the per-book delta path).
  • Add failureColor: Color? (red only on failure, nil otherwise) to DownloadStatus/SeriesDownloadStatus and pass it at the five palette-surface call sites, so tinted/overlay cards keep their palette colors and only failures turn red. Concrete surfaces (chips, rows, status lines) keep the non-optional displayColor.
  • Local dashboard sections now show "Nothing here yet." when empty (new key, translated for all 10 languages).
  • Both EPUB theme pages share one LabeledSliderRow component (label + trailing value above, slider below); the seven stale Label: %@x keys are removed.
  • The page-transition picker animates its caption swap via an explicit withAnimation binding (the border-cropping picker needs none — its caption is static).
  • Scroll-arrow index is computed from the viewport center with truncation, so every click advances a full page.
  • Heatmap hit containers now span exactly one grid pitch (17pt) with zero overlap — gaps stay tappable and no tap can select the wrong day.
  • A failed download's action reads "Retry Download" (new key, translated for all 10 languages), keeping the button's action-color semantics intact.

Validation

  • make format
  • make build — iOS, macOS, tvOS all pass
  • make localize + misc/translate.py list — no missing translations

@everpcpc
everpcpc merged commit 76cb855 into main Oct 4, 2026
3 checks passed
@everpcpc
everpcpc deleted the fix/download-aggregate-followups branch October 4, 2026 10:51
everpcpc added a commit that referenced this pull request Oct 4, 2026
## Problem

The library add/edit form's Scanner tab holds its "add exclusion" text field state locally. On iOS/macOS the form's sections are swapped by a segmented tab picker, so leaving the Scanner tab destroys the section view and any half-typed exclusion text with it. (Missed from the nit batch in #1201.)

## Fix

Hoist `newExclusion` from `LibraryFormScannerSection` to `LibraryFormSections`, which persists across tab switches, and pass it down as a binding. No behavior change otherwise.

## Validation

- `make format`
- `make build` — iOS, macOS, tvOS all pass
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