Skip to content

Commit

Permalink
[Lightbox] Open animation (#6159)
Browse files Browse the repository at this point in the history
* Measure all rects for embeds

* Measure avi rects too

* Animate lightbox in and out

* Account for safe area in the animation

* Tune spring times

* Remove null checks for measurements

* Remove superfluous view

* Block swipe while opening

* Interpolate width/height on native side for Android

* Make it fast by animating only affine transforms

* Fix tall image final state

The initial animation frame is still off on both platforms.

* Try to squeeze perf

* Avoid blank images during animation on iOS

* Fix bad rebase

* Fix a huge memory issue due to expo/expo#24894

* Fix last frame flash

* Fix thum dim calculation for tall images
  • Loading branch information
gaearon authored Nov 9, 2024
1 parent e73d5c6 commit 2d73c5a
Show file tree
Hide file tree
Showing 12 changed files with 629 additions and 192 deletions.
48 changes: 35 additions & 13 deletions src/screens/Profile/Header/Shell.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import React, {memo} from 'react'
import {StyleSheet, TouchableWithoutFeedback, View} from 'react-native'
import Animated, {
measure,
MeasuredDimensions,
runOnJS,
runOnUI,
useAnimatedRef,
} from 'react-native-reanimated'
import {AppBskyActorDefs, ModerationDecision} from '@atproto/api'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {msg} from '@lingui/macro'
Expand Down Expand Up @@ -42,6 +49,7 @@ let ProfileHeaderShell = ({
const {openLightbox} = useLightboxControls()
const navigation = useNavigation<NavigationProp>()
const {isDesktop} = useWebMediaQueries()
const aviRef = useAnimatedRef()

const onPressBack = React.useCallback(() => {
if (navigation.canGoBack()) {
Expand All @@ -51,14 +59,14 @@ let ProfileHeaderShell = ({
}
}, [navigation])

const onPressAvi = React.useCallback(() => {
const modui = moderation.ui('avatar')
if (profile.avatar && !(modui.blur && modui.noOverride)) {
const _openLightbox = React.useCallback(
(uri: string, thumbRect: MeasuredDimensions | null) => {
openLightbox({
images: [
{
uri: profile.avatar,
thumbUri: profile.avatar,
uri,
thumbUri: uri,
thumbRect,
dimensions: {
// It's fine if it's actually smaller but we know it's 1:1.
height: 1000,
Expand All @@ -68,10 +76,22 @@ let ProfileHeaderShell = ({
},
],
index: 0,
thumbDims: null,
})
},
[openLightbox],
)

const onPressAvi = React.useCallback(() => {
const modui = moderation.ui('avatar')
const avatar = profile.avatar
if (avatar && !(modui.blur && modui.noOverride)) {
runOnUI(() => {
'worklet'
const rect = measure(aviRef)
runOnJS(_openLightbox)(avatar, rect)
})()
}
}, [openLightbox, profile, moderation])
}, [profile, moderation, _openLightbox, aviRef])

const isMe = React.useMemo(
() => currentAccount?.did === profile.did,
Expand Down Expand Up @@ -149,12 +169,14 @@ let ProfileHeaderShell = ({
styles.avi,
profile.associated?.labeler && styles.aviLabeler,
]}>
<UserAvatar
type={profile.associated?.labeler ? 'labeler' : 'user'}
size={90}
avatar={profile.avatar}
moderation={moderation.ui('avatar')}
/>
<Animated.View ref={aviRef} collapsable={false}>
<UserAvatar
type={profile.associated?.labeler ? 'labeler' : 'user'}
size={90}
avatar={profile.avatar}
moderation={moderation.ui('avatar')}
/>
</Animated.View>
</View>
</TouchableWithoutFeedback>
</GrowableAvatar>
Expand Down
2 changes: 0 additions & 2 deletions src/state/lightbox.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react'
import type {MeasuredDimensions} from 'react-native-reanimated'
import {nanoid} from 'nanoid/non-secure'

import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
Expand All @@ -8,7 +7,6 @@ import {ImageSource} from '#/view/com/lightbox/ImageViewing/@types'
export type Lightbox = {
id: string
images: ImageSource[]
thumbDims: MeasuredDimensions | null
index: number
}

Expand Down
9 changes: 9 additions & 0 deletions src/view/com/lightbox/ImageViewing/@types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
*
*/

import {TransformsStyle} from 'react-native'
import {MeasuredDimensions} from 'react-native-reanimated'

export type Dimensions = {
width: number
height: number
Expand All @@ -19,7 +22,13 @@ export type Position = {
export type ImageSource = {
uri: string
thumbUri: string
thumbRect: MeasuredDimensions | null
alt?: string
dimensions: Dimensions | null
type: 'image' | 'circle-avi' | 'rect-avi'
}

export type Transform = Exclude<
TransformsStyle['transform'],
string | undefined
>
Loading

0 comments on commit 2d73c5a

Please sign in to comment.