Skip to content

Add Saved as a main tab - #5

Merged
simonhamp merged 3 commits into
mainfrom
feat/saved-tab
Oct 18, 2026
Merged

simonhamp merged 3 commits into
mainfrom
feat/saved-tab

Conversation

@simonhamp

@simonhamp simonhamp commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

Adds Saved as a main tab, between Notifications and Profile, copying the web's /saved page.

What changed

  • The tab bar is now Log, Notifications, Saved, Profile. Saved uses the Lucide bookmark. TabsLayout::Tabs has /saved, so commits and profiles opened from it push onto the Saved tab like the other tabs.
  • New Saved screen at /saved, reading GET /api/v1/saved (already on feat/mobile-api-reactions, no API changes). It uses the Log's rows (ShowsCommits, ExpandsThreads, the feed partial), last saved first, with day markers as the web's CommitFeed draws them. Above the list are the web's "Only you" line, with a new lock-keyhole icon from lucide-react 1.57.0, and its description. The end line and the empty state are the web's. Explore Trending switches to the Log tab, open on Trending.
  • Unsaving a commit on Saved removes its row once devnull confirms, as the web does. If that was the last row and there are more, the list loads again from the top. Unsaving a reply shown under a saved commit leaves the row alone.
  • Pull to refresh and load more work like the other screens. The first page is kept in the ResponseCache, so the tab opens on what it showed last time and refreshes behind it.
  • Saving elsewhere: Client::bookmark() and unbookmark() now also patch the kept saved page (ResponseCache::commitSaved()). A save puts the commit on top and an unsave takes it out. A tab tap mounts the screen afresh, so the change is there the moment you open Saved. Stars leave the saved list alone, even though their answer carries is_saved.
  • The cache also remembers commits unsaved on this phone (unsavedIds(), like deletedIds()). Coming back to Saved from a commit page drops those rows, even from pages loaded past the first.
  • empty.blade.php takes an optional link line.

What to check

  • Saved::takeFresh() doesn't use FreshPage. Saved is ordered by when you saved, and saving again moves a commit to the top, so FreshPage's "newer commits wait in the pill" doesn't fit. A fresh page replaces the top of the list and the pages loaded below it stay, matched from the last commit the fresh page shares with the list. A page with no next cursor is the whole list.
  • The screen uses $forceFullFrames like Log and Notifications, since rows leave from the middle.
  • Rows past the first page don't pick up star counts changed elsewhere until you pull to refresh. That's how Log and Profile behave today.
  • This will conflict with any other PR that touches TabsLayout, routes/mobile.php or ResponseCache::Cacheable.

How it was verified

php artisan test: 706 passed after the rebase. Pint is clean.

On an iPhone 17 Pro simulator (iOS 27.0) against mobile-api-integration, signed in as local_dev:

Saved two commits on the Log Saved opens with them on top, no spinner Unsaved "Hey world" on Saved
Pull to refresh after a save on the server Back from unsaving on the commit page Empty state
Explore Trending Load more, to the end iPhone SE, four tabs fit Dark

Frames from the pull to refresh recording: the list drags down, the spinner holds, and the commit saved on the server lands on top.

Opening a commit from Saved slides it in on the Saved tab. On the iPhone SE (375pt wide) all four labels fit, Notifications included. Android wasn't run; its Material bar has the same four items.

After phone testing, 3fd4022 tightens the space under the description. The hairline under it was a list row of its own, which iOS laid out far taller than 1pt, so it now sits in the description's row and the gaps match the web (after).

Rebased onto main after #3, #4, #7, #8 and #9 (59b2407). Save and Unsave now live in the commit's More menu, so the tests tap its items. Unsaving from the menu on Saved still removes the row, and deleting your own saved commit from it removes the row too. Saved now passes $myColour to its view, without which the quote and report sheets failed to render there. Checked again on a fresh simulator: saved from the Log's menu, unsaved from Saved's menu (after), and deleted from Saved.

The screenshots live on the orphan branch saved-tab-screenshots, which can go once this merges.

🤖 Generated with Claude Code

simonhamp and others added 3 commits October 18, 2026 19:32
The Saved tab lists the commits you saved, last saved first, in the
Log's rows, as the web's Saved page does. It has the web's "Only you"
line, end line and empty state. Explore Trending opens the Log on
Trending.

Unsaving a commit there takes its row away once devnull says so. Saving
or unsaving anywhere else patches the kept first page, so the change
shows the next time Saved opens. Commits unsaved on this phone are
remembered too, so rows on later pages go when you come back to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The hairline under the description was a list row of its own, and iOS
laid it out far taller than 1pt, which left a big gap above and below
it. It now sits in the description's row, so the spacing matches the
web's Saved page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Save and Unsave are in a commit's More menu now, so the Saved tests tap
its items. Unsaving from the menu still takes the row away, and deleting
your own saved commit from it lets the row go.

The quote and report sheets draw their button in your lane colour, so
Saved hands the view $myColour like the other screens. Without it,
quoting or reporting from Saved failed to render.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@simonhamp
simonhamp merged commit 3a714d7 into main Oct 18, 2026
1 check passed
@simonhamp
simonhamp deleted the feat/saved-tab branch October 19, 2026 09:26
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