Skip to content

Feeds: fix pull-to-refresh cancellation

jedmund requested to merge jedmund/fix-refresh into main

Created by: jedmund

Summary

Pull-to-refresh on Tag feed, Bookmarks tab, and pushed Profile was surfacing URLError.cancelled ("Failed to Load / Network error: cancelled"). Home worked because it's the nav-stack root; the cancellation only reproduced on pushed/tab-root hosting controllers. SwiftUI was cancelling the .refreshable action Task before the network round-trip completed, and the cancellation propagated into URLSession.data(for:).

Changes

  • IllustFeedViewModel.refresh runs the fetch inside Task.detached so caller-task cancellation can't reach URLSession.data(for:). Still awaits fetch.value to keep the spinner up through the round-trip. Also keeps existing illusts visible during the fetch and swaps atomically on success — matches Mail / Twitter UX and avoids a mid-gesture view-tree collapse.
  • ProfileView.refresh no longer re-fetches userDetail. Profile metadata is stable; blanking it and re-awaiting loadUserDetail reproduced the same cancellation against a different endpoint and flashed "Failed to Load" over a perfectly valid header.
  • TagFeedView / ProfileView now keep their scroll-reactive scrollOffset / showsCenterTitle state in a nested body subview, so scroll ticks no longer re-render the view that owns .refreshable. (Precautionary refactor; reduces body re-evaluation on scroll regardless.)

Test plan

  • Home tab: pull-to-refresh still works (regression check).
  • Bookmarks tab (iPhone + iPad): pull-to-refresh; grid reloads, no error banner.
  • Bookmarks: toggle Public Private, then pull-to-refresh on the new feed.
  • Search → tap a tag → pull-to-refresh TagFeedView; grid reloads.
  • Detail → tap user row → pushed ProfileView → pull-to-refresh; feed reloads, header stays intact.
  • Scroll-reactive chrome still animates: TagFeedView title pill on scroll; pushed ProfileView center pill reveals past ~185pt.
  • Pagination still works on all feeds (scroll to tail loads more pages).

🤖 Generated with Claude Code

Merge request reports

Loading