feat(flutter): cosmetic reveal animations (Slice F)
Final slice of the per-item rendering pass. Wraps every tile widget in an AnimatedSwitcher between the skeleton placeholder and the real card. 220ms cross-fade with easeOut: tiles "settle into place" rather than hard-cutting from shimmer to content. Since each tile fades independently as its data lands — and the HydrationQueue's concurrency cap drains in a natural cascade — the overall feel is the staged "page builds piece by piece" effect we wanted, with no per-tile position math required. Bumps CachedNetworkImage fadeInDuration from zero to 120ms (server_ image.dart, discover_screen.dart). Imperceptible on cache hits since the image decodes synchronously; on cache misses the bytes fade in smoothly instead of popping. Slice 1's "zero fade" call was right about the 500ms default being a regression, but 120ms threads the needle. Playlist detail wraps its body in the same AnimatedSwitcher so the cold-load skeleton page cross-fades into the real track list. Tiles affected: home _AlbumTile / _ArtistTile / _TrackTile + liked _LikedAlbumTile / _LikedArtistTile / _LikedTrackRow + playlist _SkeletonBody / _Body. All keyed via ValueKey so AnimatedSwitcher detects the transition. End of the per-item pass. Net behavior: cold visits paint shaped pages instantly with skeletons, content cascades in as hydration lands; warm visits paint fully from drift in the first frame.
This commit is contained in:
@@ -61,10 +61,12 @@ class ServerImage extends ConsumerWidget {
|
||||
imageUrl: resolved,
|
||||
httpHeaders: headers,
|
||||
fit: fit,
|
||||
// No fadeIn — covers paint instantly once cached, and the
|
||||
// default 500ms fade looks like a regression on a populated
|
||||
// grid.
|
||||
fadeInDuration: Duration.zero,
|
||||
// 120ms feels like cover bytes settling in on a cache miss
|
||||
// (smoother than the abrupt zero-fade); on cache hits the
|
||||
// image is decoded synchronously so the fade is imperceptible.
|
||||
// The default 500ms is too long — looks like a regression on
|
||||
// a populated grid.
|
||||
fadeInDuration: const Duration(milliseconds: 120),
|
||||
fadeOutDuration: Duration.zero,
|
||||
// Keep failures local — a single 401/timeout shouldn't dump
|
||||
// a stack trace or replace the parent Container's background.
|
||||
|
||||
Reference in New Issue
Block a user