mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-09 16:14:40 +00:00
Fixes the perceptual "stale feed on launch" bug: on cold launch the desktop feed paints with whatever local cache had (up to 7 days old) before relays catch up. The live updateFeedWith() path already prepends fresh events silently, but users had no signal that fresh content arrived unless they were already at the top of the feed (auto-snap via StickToTopOnPrepend). This adds a Twitter/Mastodon-style floating pill chip that slides down from above the search header when fresh events have prepended AND the user is scrolled below position 0. Tapping it smooth-scrolls to top and slides the chip back up off-screen. Scrolling to top manually also dismisses it. Implementation: - NewPostsChip + rememberNewPostsChipState in commons/commonMain so any future feed surface (incl. Android, iOS) can adopt it. Desktop wires it today; Android continues with the existing auto-stick + bottom-nav dot pattern. - Visibility predicate is pure-function and unit-tested (5 cases). - Predicate mirrors the inverse of StickToTopOnPrepend's "at top" check so the two systems are mutually exclusive — auto-snap when at top, chip when not. - Chip placement: floating Alignment.TopCenter inside FeedScreen's outer Box, offset by the animated headerSpacerHeight (60.dp normal, 300.dp when search is expanded) so it tracks the header card. - Hoisted lazyListState + headerSpacerHeight one level so the chip can share scroll state with the LazyColumn. Existing viewport-aware metadata loading is unchanged (same lazyListState reference). - Animation: slideInVertically(tween(280, FastOutSlowInEasing)) + fadeIn for enter; slideOutVertically(tween(220, FastOutLinearInEasing)) + fadeOut for exit. Initial/target offset of -fullHeight-16 guarantees the chip is fully off-screen above its rest position. - Per-column scope by construction: each FeedScreen instance has its own chip state (deck mode shows one chip per column). - Resets cleanly on feed mode switch (Following ↔ Global ↔ Custom) because rememberNewPostsChipState is keyed on FeedContentState, which is recreated when viewModel = remember(feedMode, activeFeedId) recomposes. Plan: docs/plans/2026-06-02-feat-new-posts-chip-desktop-feed-plan.md