feat(mobile): circle-clip avatar viewer + banner viewer on profile cover photo#14445
Merged
Merged
Conversation
…ver photo Follow-ups to #14444: 1. **Avatar viewer keeps the circle.** The avatar on the profile screen is a circle, so the full-screen viewer should clip to a circle too — not a letterboxed square on black. AvatarViewer now renders the image inside a fixed-size square wrapper with `borderRadius: size / 2` + `overflow: 'hidden'` and `resizeMode='cover'`, sized to fit the smaller window dimension minus 24px padding so it doesn't touch the edges. 2. **Banner viewer on the profile cover photo.** Tapping the cover photo at the top of the profile screen now opens a parallel full-screen viewer for the banner. Uses `WidthSizes.SIZE_2000` (the largest cached cover-photo size), `resizeMode='contain'` to preserve the cover photo's aspect ratio on the black backdrop. No circular clip. To avoid duplicating the modal/gesture/close-button machinery, factored the chrome out of the existing AvatarViewer into a shared **FullscreenImageViewer** that owns: - `<Modal transparent animationType='fade' statusBarTranslucent>` - The pan gesture (Reanimated shared values, 120 px / 800 px-s dismiss thresholds, 200 ms spring-back, translation reset on open) - The X close button (top-right, safe-area top inset + 8 px, hitSlop) - The black `#000` backdrop + `StatusBar light-content` AvatarViewer and BannerViewer are now thin wrappers around it that describe their image shape and source. Same dismiss UX in both. ProfileCoverPhoto wraps the existing `<CoverPhoto>` in a `<Pressable>` that opens the BannerViewer; the artist-badge overlay (which has no own press handler) sits absolute on top and stays visually unchanged. Files: - packages/mobile/src/screens/profile-screen/FullscreenImageViewer.tsx (new) - packages/mobile/src/screens/profile-screen/AvatarViewer.tsx (refactor) - packages/mobile/src/screens/profile-screen/BannerViewer.tsx (new) - packages/mobile/src/screens/profile-screen/ProfileCoverPhoto.tsx (tap wiring) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-ups to #14444.
1. Avatar viewer keeps the circle
The avatar on the profile screen is a circle, so the full-screen viewer should match — not a letterboxed square on black.
AvatarViewernow renders the image inside a fixed square wrapper withborderRadius: size / 2+overflow: 'hidden'andresizeMode='cover', sized tomin(windowWidth, windowHeight) - 48 pxso it doesn't touch the screen edges on landscape phones.2. Banner viewer on the profile cover photo
Tapping the cover photo at the top of the profile screen now opens a parallel full-screen viewer for the banner. Uses
WidthSizes.SIZE_2000(the largest cached cover-photo size — the header usesSIZE_640) andresizeMode='contain'to preserve the cover photo's native aspect ratio on the black backdrop. No circular clip.Refactor: shared
FullscreenImageViewerRather than duplicate the modal/gesture/close-button machinery between Avatar and Banner viewers, the chrome is factored into a new
FullscreenImageViewerthat owns:<Modal transparent animationType='fade' statusBarTranslucent>+light-contentStatusBarreact-native-gesture-handler— Reanimated shared values follow the finger in any direction, dismiss thresholds at 120 px distance or 800 px/s velocity, 200 mswithTimingspring-back, translation reset on each openinsets.top + 8 pxwithhitSlop, accessible label/role#000backdropAvatarViewerandBannerViewerare now thin wrappers that supply the image content aschildrenand acloseAccessibilityLabel. Same dismiss UX in both.ProfileCoverPhoto tap wiring
The existing
<CoverPhoto>is wrapped in a<Pressable>that flips localisViewerOpenstate. The artist-badge overlay (which has no ownonPress) sits absolute on top and stays visually unchanged — taps in the badge corner still hit the Pressable underneath.Files
packages/mobile/src/screens/profile-screen/FullscreenImageViewer.tsxpackages/mobile/src/screens/profile-screen/AvatarViewer.tsxpackages/mobile/src/screens/profile-screen/BannerViewer.tsxSIZE_2000,resizeMode='contain', child of FullscreenImageViewerpackages/mobile/src/screens/profile-screen/ProfileCoverPhoto.tsxNet diff: +288 / −144.
Verification
tsc --noEmitclean inpackages/mobilecontainaspect ratio.CoinDetailsScreenwithout opening the avatar viewer.🤖 Generated with Claude Code