Story tray/creation/viewer with PawRing seen/unseen indicator, expo-video
playback for VIDEO posts (replacing the static placeholder), and a
pets/people/hashtags search screen reachable from the Explore tab header.
Extracts FollowButton from the pet-profile screen since search results
need the same follow/unfollow toggle.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PawBackButton toggles reposts.create/delete with an isReposted-backed
optimistic state, mirroring web's PawBackButton — replaces the static
repost count in PostCard's action row. RepostCard renders a REPOST
post as a read-only "Paw-Back von {name}" attribution wrapper around
the original post's pet header, image, and caption, ported from web's
RepostCard with no action row (matches web: only the original post is
reactable/commentable).
Post creation: gallery/camera picker (expo-image-picker) uploads each
image straight to Supabase Storage via a presigned PUT
(posts.getPresignedUrl + expo-file-system), then posts.create with the
resulting storage keys — reachable via a new "+" header button on the
Feed tab. No client-side blurhash (browser Canvas API, no RN
equivalent) or AI-disclosure/mention support yet, matching the rest of
mobile's plain-text captions.
Comments: a dedicated screen (posts/[postId]/comments) for reading,
posting, and deleting one's own comments, reachable by tapping the
comment icon on a PostCard. Ported from web's PostDetailDialog comment
panel, scoped down to just that panel since mobile's image full-view
already has its own route.
Header now shows the PawFeed paw+text logo on the Feed tab (matching
web's Sidebar wordmark). Tapping a post image opens a full-screen
viewer as a route-based fullScreenModal, with a blurred edge-to-edge
copy of the same photo behind the sharp foreground image instead of a
flat black backdrop, for a more dynamic Photos-app-style lightbox.
Fixes from user testing on a real device:
- Feed: replaced an invisible spacing-only separator with an actual
hairline divider between posts.
- Android launcher icon showed Expo's default placeholder (a blue arrow)
because the app icon and the Android adaptive-icon layers
(foreground/background/monochrome) are two separate asset sets — only
icon.png/favicon.png had been replaced. Added scripts/derive-adaptive-
icon.js to crop the paw glyph out of icon.png (detected by its marigold
color) and generate all three adaptive-icon layers plus the splash icon;
this is an explicit placeholder per user's own call, not final art.
New: full pet profile (app/(app)/pets/[petId]/), matching web's
src/app/(app)/pets/[petId]/page.tsx:
- View: identity, species, bio/adoption story, follower/following counts
(tappable → list screens), the pet's own posts below.
- Follow/unfollow with real initial state (follows.isFollowing) and
optimistic toggle — unlike feed reactions, this endpoint actually
exists, so no need to fake an initial state.
- Edit screen (name/nickname/bio/adoption story via pets.update) for the
owner's own pets.
- Tapping a pet (feed header, Explore card, Pets-tab row) now opens this
profile instead of nowhere; the Pets tab's active-pet switch is now a
separate checkmark control instead of overloading the whole row tap.
PostCard's post-shape prop is now structural rather than tied to
feed.getFeed's output type, since posts.byPetId selects `pet` via the
narrower petIdentitySelect (no isVerified/owner) — both need to satisfy
the same component.
Verified end-to-end on-device: feed separator visible, own-pet profile
shows a working Bearbeiten button whose form is correctly prefilled (a
stray edit was made to Bianca's nickname field by mistake during testing
and was discarded via back-navigation without saving — never sent to the
server), someone else's pet profile shows a working Follow/Unfollow
toggle, followers list navigates correctly, and the home-screen launcher
icon now shows the paw instead of the default Expo icon.
Moves the mobile app from a connectivity scaffold to a real Phase 1 app:
- Migrate off Expo Go onto a local custom dev client (expo-dev-client,
built via expo prebuild + expo run:android against the local Android
SDK — no EAS account needed). Needed because react-native-mmkv requires
native code Expo Go doesn't ship.
- Persisted, MMKV-backed TanStack Query cache (PersistQueryClientProvider)
plus expo-image, so a relaunch renders the last-known feed/pets/
notifications instantly instead of a blank screen while refetching.
- ActivePetContext: every pet-scoped procedure requires an explicit petId
server-side (no server-side "current pet"), ported from web's
ActivePetContext, MMKV-backed instead of localStorage.
- Bottom Tabs (Feed/Explore/Notifications/Pets) mirroring the web app's
actual mobile nav, with Messages as a header button rather than a tab
(matches web). Feed, PostCard, PawButton reactions, pet discovery grid,
notifications list, and a conversations list are all wired to the real
backend and verified against the live database.
- Design tokens/components extended with PostCard/PawButton/PetAvatar/
PetIdentityBadges, all styled from the existing src/theme/tokens.ts.
- Fixed a react/react-dom version mismatch surfaced along the way, and
handle Clerk's needs_client_trust (Device Trust) sign-in status with an
email-code step.
Verified end-to-end in the Android emulator against pawfeed.org: feed
scrolls and paginates with real posts/images, paw reactions toggle
optimistically and persist, pet switching updates every screen, and
notifications/explore show live data.
- Add design tokens (colors, radii, typography) mirroring DESIGN.md's
"Spotlight Porch" system, plus Button/TextField/Card components built
on them. Restyle the sign-in and placeholder home screens to match.
- Load Inter via @expo-google-fonts/inter, gate rendering on fonts +
Clerk being ready instead of a blank screen.
- Pin react-dom to match react's version — Metro/Hermes hard-require
exact equality, and react-dom wasn't pinned anywhere before.
- Handle Clerk's `needs_client_trust` status (Device Trust, tied to the
dashboard's Native Applications API): send/verify an email code
before finalizing sign-in.
Verified end-to-end in the Android emulator against the live backend:
sign-in, device-trust code verification, and the home screen showing
real stats.getPublicStats data.
Connectivity + auth scaffold only: Expo Router, Clerk session auth via
expo-secure-store, and a type-only tRPC AppRouter import from the web
app's router — no backend changes needed. See mobile/README.md.