feat: redesign library card to vertical spec layout with star rating + tooltip #37
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/flutter-card-redesign"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Redesigns the library card to the vertical spec layout from Björn's comment (#586), and addresses jibril's non-blocking suggestions (#583).
Card layout (per spec)
The card is now a vertical Column:
Changes
Backend (3 files):
RatingtoDoujinSummaryDtoso the card can show star ratingsMapToSummaryin bothDoujinEndpointsandSearchEndpointsFlutter library page (1 file):
_DoujinCardfrom horizontal Row → vertical ColumnExpandedto fill available space, bordered, with semi-transparent tooltip bubble overlaydoujin.ratingspaceBetweenwith date on left, page count + info icon on rightmaxCrossAxisExtent200→180,childAspectRatio1.4→0.62, spacing 8→4_normalizeUrl()helper to strip trailing slash from serverUrlFlutter detail page (1 file):
_normalizeThumbnailUrl()helper (same trailing-slash fix)Tests (1 file):
2vassertion (variant count no longer shown on card)All 180 Flutter tests pass, 268 backend tests pass,
flutter analyze— 0 issues.1. Models: DoujinSummary now has coverImageId + links (self, thumbnail). DoujinDetail has coverImageId. Regenerated freezed/json files. 2. CoverThumbnail widget: loads thumbnails from /api/thumbnails/{id} with bearer token auth header, loading spinner, error fallback. 3. Library page: _DoujinCard now shows a thumbnail on the left side when a cover image exists (via links['thumbnail'].href), with a placeholder when no cover. Card meta labels shortened (30p, 2v) to make room for the thumbnail. 4. Detail page: metadata panel shows a larger cover image at the top (using coverImageId from DoujinDetail) before the titles section. 5. StoreConnector updated to pass serverUrl + authToken from settings state to the widgets that need to build image URLs. All 180 Flutter tests pass.Flutter Coverage
Total: 77.0% (1279 of 1662)
Summary
Summary
Coverage
DoujinManager.ApplicationCore - 85.2%
DoujinManager.Infrastructure - 93%
pshot
E20E2ABA2099901FFAB4904C0513DF077BA6D6CA374__CoverImageHelper
DoujinManager.RestAdapter - 85%
E5CB12CEAC5BBBEA65844E1C05F9ADA4DA38B848075C41304FC6A1ABF77__ValidationAttr
ibuteCache
DoujinManager.Server - 21.8%
Simplified per your feedback
Stripped it back to a dead-simple 3-row Column:
Changes:
_CoverImagewrapper,DateLabelwidget, info icon — all goneYYYY-MM-DD(with year)NoCoverPlaceholderwhich naturally fills theExpandedwidthmaxCrossAxisExtent: 200,childAspectRatio: 1.2, spacing4180 tests pass, 0 analyzer issues. 137 lines deleted, 24 added.
Fixed — aspect ratio inverted to portrait (0.714 = 1/1.4). Cards are now taller than wide. 180 tests pass.
Changed
CoverThumbnaildefault fit fromBoxFit.cover(crops) toBoxFit.contain(scales to fit, no cropping). The full image now shows inside the card.🔮 fufu~ Jibril reviewed your code!
Ohhh, a vertical card redesign~! ♪ I watched the whole evolution — from the tooltip-bubble version to the simplified 3-row column after Björn's feedback. Iterating cleanly on review notes is wonderful to see, you know? The backend
Ratingwire-up on bothDoujinEndpointsandSearchEndpointsis perfectly aligned positionally with the DTO, and the generated freezed/g.dart files are in sync. The_normalizeUrltrailing-slash fix addresses my #583 concern from #35 nicely. ♡Verdict: ✅ Looks good to me~
No blockers! Static scan is clean (no secrets, injection, eval, or SQL). CI evidence is current for head
78d929f— backend coverage #593 (line 85.5%, branch 50.5%) generated 19:42 UTC ~1.5min after the head commit, Flutter coverage #592 (76.2%, 180/180 tests) updated 19:41 UTC — both posted only on successful build+test, so I skipped local runs per my CI-evidence policy. ♪💡 Little ideas (non-blocking)~
detail_page.dart:271vslibrary_page.dart:304— fufu~ you have two URL strategies living side by side here.library_pageconsumes the HATEOASlinks['thumbnail']?.href(the proper way~), butdetail_pagehardcodes the path/api/thumbnails/{imageId}. That's becauseDoujinDetaildoesn't carry alinksmap whileDoujinSummarydoes. Not broken — the endpoint is correct (verifiedImageEndpointsmaps/api/thumbnails/{id:guid}) — but it's a small architectural inconsistency. Consider givingDoujinDetailalinksfield too, so the detail page doesn't have to know the URL scheme. ♡library_page.dart:310—_formatDate— oh? Björn asked (#594) for the datetime to be "encapsulated in a stateless widget for future localization settings," but after the simplification pass this is back to being a plainstatic String _formatDate()method inside_DoujinCard. The year is now showing (YYYY-MM-DD), so the visible ask is met — but the localization-ready widget wrapper is still pending. Worth a follow-up ticket so it doesn't get lost? ♪cover_thumbnail.dart(0% dedicated tests, CI 36.4% 12/33) — the loading/error/placeholder states inCoverThumbnailandNoCoverPlaceholderhave no widget tests, andlibrary_page_test.dartonly asserts the'30p'string — no assertion on the new date format, theCoverThumbnailrendering, orNoCoverPlaceholder. The test fixture (kTestDoujinSummary) has no thumbnail link, so the cover path is never exercised. A golden/widget test for both states would be lovely~ ♡Automated review by Jibril · 2026-06-30
CI/CD: passed (backend #593 + Flutter #592 current for head
78d929f) · Local checks: skipped per CI-evidence policyStatic scan: clean (Dart+C#; no secrets, injection, eval/exec, pickle, or SQL injection in added lines)
ca63b0170ba6859ef0b3Working on jibril's feedback (#603). Files being pushed:
DoujinDetailDto— addedCoverImageId+Links(HATEOAS on detail endpoint too)MapToDetail— emitsBuildDoujinItemLinksDoujinDetailFlutter model — addedlinksfielddetail_page.dart— useslinks['thumbnail'].href(no more hardcoded URL)library_page.dart—DateLabelstateless widget (jibril #603.2, Björn #594)cover_thumbnail_test.dart— 3 widget tests (jibril #603.3)Also: freezed/g.dart regenerated for the new
linksfield onDoujinDetail.0c915ed) 9a1a18353f0c915ed)' (#38) from matikane/freezed-fix into feat/flutter-card-redesign