diff options
Diffstat (limited to 'src/screens/Profile/Header/Shell.tsx')
-rw-r--r-- | src/screens/Profile/Header/Shell.tsx | 100 |
1 files changed, 78 insertions, 22 deletions
diff --git a/src/screens/Profile/Header/Shell.tsx b/src/screens/Profile/Header/Shell.tsx index a3efdedf5..9e868c474 100644 --- a/src/screens/Profile/Header/Shell.tsx +++ b/src/screens/Profile/Header/Shell.tsx @@ -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, |