Live (#8354)
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {logger} from '#/logger'
|
||||
@@ -138,6 +139,8 @@ let ProfileHeaderStandard = ({
|
||||
[currentAccount, profile],
|
||||
)
|
||||
|
||||
const {isActive: live} = useActorStatus(profile)
|
||||
|
||||
return (
|
||||
<ProfileHeaderShell
|
||||
profile={profile}
|
||||
@@ -228,7 +231,8 @@ let ProfileHeaderStandard = ({
|
||||
) : null}
|
||||
<ProfileMenu profile={profile} />
|
||||
</View>
|
||||
<View style={[a.flex_col, a.gap_2xs, a.pt_2xs, a.pb_sm]}>
|
||||
<View
|
||||
style={[a.flex_col, a.gap_2xs, a.pb_sm, live ? a.pt_sm : a.pt_2xs]}>
|
||||
<View style={[a.flex_row, a.align_center, a.gap_xs, a.flex_1]}>
|
||||
<Text
|
||||
emoji
|
||||
|
||||
@@ -1,24 +1,35 @@
|
||||
import React, {memo} from 'react'
|
||||
import React, {memo, useEffect} from 'react'
|
||||
import {StyleSheet, TouchableWithoutFeedback, View} from 'react-native'
|
||||
import {MeasuredDimensions, runOnJS, runOnUI} from 'react-native-reanimated'
|
||||
import {
|
||||
type MeasuredDimensions,
|
||||
runOnJS,
|
||||
runOnUI,
|
||||
} from 'react-native-reanimated'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {AppBskyActorDefs, ModerationDecision} from '@atproto/api'
|
||||
import {type AppBskyActorDefs, type ModerationDecision} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {BACK_HITSLOP} from '#/lib/constants'
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {measureHandle, useHandleRef} from '#/lib/hooks/useHandleRef'
|
||||
import {NavigationProp} from '#/lib/routes/types'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {logger} from '#/logger'
|
||||
import {isIOS} from '#/platform/detection'
|
||||
import {Shadow} from '#/state/cache/types'
|
||||
import {type Shadow} from '#/state/cache/types'
|
||||
import {useLightboxControls} from '#/state/lightbox'
|
||||
import {useSession} from '#/state/session'
|
||||
import {LoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {UserBanner} from '#/view/com/util/UserBanner'
|
||||
import {atoms as a, platform, useTheme} from '#/alf'
|
||||
import {useDialogControl} from '#/components/Dialog'
|
||||
import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeftIcon} from '#/components/icons/Arrow'
|
||||
import {EditLiveDialog} from '#/components/live/EditLiveDialog'
|
||||
import {LiveIndicator} from '#/components/live/LiveIndicator'
|
||||
import {LiveStatusDialog} from '#/components/live/LiveStatusDialog'
|
||||
import {LabelsOnMe} from '#/components/moderation/LabelsOnMe'
|
||||
import {ProfileHeaderAlerts} from '#/components/moderation/ProfileHeaderAlerts'
|
||||
import {GrowableAvatar} from './GrowableAvatar'
|
||||
@@ -45,6 +56,8 @@ let ProfileHeaderShell = ({
|
||||
const {openLightbox} = useLightboxControls()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {top: topInset} = useSafeAreaInsets()
|
||||
const playHaptic = useHaptics()
|
||||
const liveStatusControl = useDialogControl()
|
||||
|
||||
const aviRef = useHandleRef()
|
||||
|
||||
@@ -79,24 +92,46 @@ let ProfileHeaderShell = ({
|
||||
[openLightbox],
|
||||
)
|
||||
|
||||
const onPressAvi = React.useCallback(() => {
|
||||
const modui = moderation.ui('avatar')
|
||||
const avatar = profile.avatar
|
||||
if (avatar && !(modui.blur && modui.noOverride)) {
|
||||
const aviHandle = aviRef.current
|
||||
runOnUI(() => {
|
||||
'worklet'
|
||||
const rect = measureHandle(aviHandle)
|
||||
runOnJS(_openLightbox)(avatar, rect)
|
||||
})()
|
||||
}
|
||||
}, [profile, moderation, _openLightbox, aviRef])
|
||||
|
||||
const isMe = React.useMemo(
|
||||
() => currentAccount?.did === profile.did,
|
||||
[currentAccount, profile],
|
||||
)
|
||||
|
||||
const live = useActorStatus(profile)
|
||||
|
||||
useEffect(() => {
|
||||
if (live.isActive) {
|
||||
logger.metric('live:view:profile', {subject: profile.did})
|
||||
}
|
||||
}, [live.isActive, profile.did])
|
||||
|
||||
const onPressAvi = React.useCallback(() => {
|
||||
if (live.isActive) {
|
||||
playHaptic('Light')
|
||||
logger.metric('live:card:open', {subject: profile.did, from: 'profile'})
|
||||
liveStatusControl.open()
|
||||
} else {
|
||||
const modui = moderation.ui('avatar')
|
||||
const avatar = profile.avatar
|
||||
if (avatar && !(modui.blur && modui.noOverride)) {
|
||||
const aviHandle = aviRef.current
|
||||
runOnUI(() => {
|
||||
'worklet'
|
||||
const rect = measureHandle(aviHandle)
|
||||
runOnJS(_openLightbox)(avatar, rect)
|
||||
})()
|
||||
}
|
||||
}
|
||||
}, [
|
||||
profile,
|
||||
moderation,
|
||||
_openLightbox,
|
||||
aviRef,
|
||||
liveStatusControl,
|
||||
live,
|
||||
playHaptic,
|
||||
])
|
||||
|
||||
return (
|
||||
<View style={t.atoms.bg} pointerEvents={isIOS ? 'auto' : 'box-none'}>
|
||||
<View
|
||||
@@ -170,21 +205,44 @@ let ProfileHeaderShell = ({
|
||||
<View
|
||||
style={[
|
||||
t.atoms.bg,
|
||||
{borderColor: t.atoms.bg.backgroundColor},
|
||||
a.rounded_full,
|
||||
{
|
||||
borderWidth: live.isActive ? 3 : 2,
|
||||
borderColor: live.isActive
|
||||
? t.palette.negative_500
|
||||
: t.atoms.bg.backgroundColor,
|
||||
},
|
||||
styles.avi,
|
||||
profile.associated?.labeler && styles.aviLabeler,
|
||||
]}>
|
||||
<View ref={aviRef} collapsable={false}>
|
||||
<UserAvatar
|
||||
type={profile.associated?.labeler ? 'labeler' : 'user'}
|
||||
size={90}
|
||||
size={live.isActive ? 88 : 90}
|
||||
avatar={profile.avatar}
|
||||
moderation={moderation.ui('avatar')}
|
||||
/>
|
||||
{live.isActive && <LiveIndicator size="large" />}
|
||||
</View>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</GrowableAvatar>
|
||||
|
||||
{live.isActive &&
|
||||
(isMe ? (
|
||||
<EditLiveDialog
|
||||
control={liveStatusControl}
|
||||
status={live}
|
||||
embed={live.embed}
|
||||
/>
|
||||
) : (
|
||||
<LiveStatusDialog
|
||||
control={liveStatusControl}
|
||||
status={live}
|
||||
embed={live.embed}
|
||||
profile={profile}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -219,8 +277,6 @@ const styles = StyleSheet.create({
|
||||
avi: {
|
||||
width: 94,
|
||||
height: 94,
|
||||
borderRadius: 47,
|
||||
borderWidth: 2,
|
||||
},
|
||||
aviLabeler: {
|
||||
borderRadius: 10,
|
||||
|
||||
Reference in New Issue
Block a user