Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Remove Profile Preview modal (#2790)

authored by

dan and committed by
GitHub
d9b62955 06f81d69

+14 -211
-1
src/Navigation.tsx
··· 144 144 getComponent={() => ProfileScreen} 145 145 options={({route}) => ({ 146 146 title: bskyTitle(`@${route.params.name}`, unreadCountLabel), 147 - animation: 'none', 148 147 })} 149 148 /> 150 149 <Stack.Screen
-6
src/state/modals/index.tsx
··· 26 26 onUpdate?: () => void 27 27 } 28 28 29 - export interface ProfilePreviewModal { 30 - name: 'profile-preview' 31 - did: string 32 - } 33 - 34 29 export interface ServerInputModal { 35 30 name: 'server-input' 36 31 initialService: string ··· 202 197 | ChangeHandleModal 203 198 | DeleteAccountModal 204 199 | EditProfileModal 205 - | ProfilePreviewModal 206 200 | BirthDateSettingsModal 207 201 | VerifyEmailModal 208 202 | ChangeEmailModal
+2 -35
src/view/com/modals/Modal.tsx
··· 1 1 import React, {useRef, useEffect} from 'react' 2 2 import {StyleSheet} from 'react-native' 3 - import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context' 3 + import {SafeAreaView} from 'react-native-safe-area-context' 4 4 import BottomSheet from '@gorhom/bottom-sheet' 5 5 import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop' 6 6 import {usePalette} from 'lib/hooks/usePalette' 7 - import {timeout} from 'lib/async/timeout' 8 - import {navigate} from '../../../Navigation' 9 - import once from 'lodash.once' 10 7 11 8 import {useModals, useModalControls} from '#/state/modals' 12 - import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' 13 9 import * as ConfirmModal from './Confirm' 14 10 import * as EditProfileModal from './EditProfile' 15 - import * as ProfilePreviewModal from './ProfilePreview' 16 11 import * as ServerInputModal from './ServerInput' 17 12 import * as RepostModal from './Repost' 18 13 import * as SelfLabelModal from './SelfLabel' ··· 50 45 const {closeModal} = useModalControls() 51 46 const bottomSheetRef = useRef<BottomSheet>(null) 52 47 const pal = usePalette('default') 53 - const safeAreaInsets = useSafeAreaInsets() 54 - 55 48 const activeModal = activeModals[activeModals.length - 1] 56 49 57 - const navigateOnce = once(navigate) 58 - 59 - // It seems like the bottom sheet bugs out when this callback changes. 60 - const onBottomSheetAnimate = useNonReactiveCallback( 61 - (_fromIndex: number, toIndex: number) => { 62 - if (activeModal?.name === 'profile-preview' && toIndex === 1) { 63 - // begin loading the profile screen behind the scenes 64 - navigateOnce('Profile', {name: activeModal.did}) 65 - } 66 - }, 67 - ) 68 50 const onBottomSheetChange = async (snapPoint: number) => { 69 51 if (snapPoint === -1) { 70 52 closeModal() 71 - } else if (activeModal?.name === 'profile-preview' && snapPoint === 1) { 72 - await navigateOnce('Profile', {name: activeModal.did}) 73 - // There is no particular callback for when the view has actually been presented. 74 - // This delay gives us a decent chance the navigation has flushed *and* images have loaded. 75 - // It's acceptable because the data is already being fetched + it usually takes longer anyway. 76 - // TODO: Figure out why avatar/cover don't always show instantly from cache. 77 - await timeout(200) 78 - closeModal() 79 53 } 80 54 } 55 + 81 56 const onClose = () => { 82 57 bottomSheetRef.current?.close() 83 58 closeModal() ··· 91 66 } 92 67 }, [isModalActive, bottomSheetRef, activeModal?.name]) 93 68 94 - let needsSafeTopInset = false 95 69 let snapPoints: (string | number)[] = DEFAULT_SNAPPOINTS 96 70 let element 97 71 if (activeModal?.name === 'confirm') { ··· 100 74 } else if (activeModal?.name === 'edit-profile') { 101 75 snapPoints = EditProfileModal.snapPoints 102 76 element = <EditProfileModal.Component {...activeModal} /> 103 - } else if (activeModal?.name === 'profile-preview') { 104 - snapPoints = ProfilePreviewModal.snapPoints 105 - element = <ProfilePreviewModal.Component {...activeModal} /> 106 - needsSafeTopInset = true // Need to align with the target profile screen. 107 77 } else if (activeModal?.name === 'server-input') { 108 78 snapPoints = ServerInputModal.snapPoints 109 79 element = <ServerInputModal.Component {...activeModal} /> ··· 200 170 ) 201 171 } 202 172 203 - const topInset = needsSafeTopInset ? safeAreaInsets.top - HANDLE_HEIGHT : 0 204 173 return ( 205 174 <BottomSheet 206 175 ref={bottomSheetRef} 207 176 snapPoints={snapPoints} 208 - topInset={topInset} 209 177 handleHeight={HANDLE_HEIGHT} 210 178 index={isModalActive ? 0 : -1} 211 179 enablePanDownToClose ··· 216 184 } 217 185 handleIndicatorStyle={{backgroundColor: pal.text.color}} 218 186 handleStyle={[styles.handle, pal.view]} 219 - onAnimate={onBottomSheetAnimate} 220 187 onChange={onBottomSheetChange}> 221 188 {element} 222 189 </BottomSheet>
-3
src/view/com/modals/Modal.web.tsx
··· 9 9 import type {Modal as ModalIface} from '#/state/modals' 10 10 import * as ConfirmModal from './Confirm' 11 11 import * as EditProfileModal from './EditProfile' 12 - import * as ProfilePreviewModal from './ProfilePreview' 13 12 import * as ServerInputModal from './ServerInput' 14 13 import * as ReportModal from './report/Modal' 15 14 import * as AppealLabelModal from './AppealLabel' ··· 85 84 element = <ConfirmModal.Component {...modal} /> 86 85 } else if (modal.name === 'edit-profile') { 87 86 element = <EditProfileModal.Component {...modal} /> 88 - } else if (modal.name === 'profile-preview') { 89 - element = <ProfilePreviewModal.Component {...modal} /> 90 87 } else if (modal.name === 'server-input') { 91 88 element = <ServerInputModal.Component {...modal} /> 92 89 } else if (modal.name === 'report') {
-134
src/view/com/modals/ProfilePreview.tsx
··· 1 - import React, {useState, useEffect} from 'react' 2 - import {ActivityIndicator, StyleSheet, View} from 'react-native' 3 - import {AppBskyActorDefs, ModerationOpts, moderateProfile} from '@atproto/api' 4 - import {ThemedText} from '../util/text/ThemedText' 5 - import {usePalette} from 'lib/hooks/usePalette' 6 - import {useAnalytics} from 'lib/analytics/analytics' 7 - import {ProfileHeader} from '../profile/ProfileHeader' 8 - import {InfoCircleIcon} from 'lib/icons' 9 - import {useNavigationState} from '@react-navigation/native' 10 - import {s} from 'lib/styles' 11 - import {useModerationOpts} from '#/state/queries/preferences' 12 - import {useProfileQuery} from '#/state/queries/profile' 13 - import {ErrorScreen} from '../util/error/ErrorScreen' 14 - import {CenteredView} from '../util/Views' 15 - import {cleanError} from '#/lib/strings/errors' 16 - import {useProfileShadow} from '#/state/cache/profile-shadow' 17 - import {Trans, msg} from '@lingui/macro' 18 - import {useLingui} from '@lingui/react' 19 - 20 - export const snapPoints = [520, '100%'] 21 - 22 - export function Component({did}: {did: string}) { 23 - const pal = usePalette('default') 24 - const {_} = useLingui() 25 - const moderationOpts = useModerationOpts() 26 - const { 27 - data: profile, 28 - error: profileError, 29 - refetch: refetchProfile, 30 - isLoading: isLoadingProfile, 31 - } = useProfileQuery({ 32 - did: did, 33 - }) 34 - 35 - if (isLoadingProfile || !moderationOpts) { 36 - return ( 37 - <CenteredView style={[pal.view, s.flex1]}> 38 - <ProfileHeader 39 - profile={null} 40 - moderation={null} 41 - isProfilePreview={true} 42 - /> 43 - </CenteredView> 44 - ) 45 - } 46 - if (profileError) { 47 - return ( 48 - <ErrorScreen 49 - title={_(msg`Not Found`)} 50 - message={cleanError(profileError)} 51 - onPressTryAgain={refetchProfile} 52 - /> 53 - ) 54 - } 55 - if (profile && moderationOpts) { 56 - return <ComponentLoaded profile={profile} moderationOpts={moderationOpts} /> 57 - } 58 - // should never happen 59 - return ( 60 - <ErrorScreen 61 - title={_(msg`Oops!`)} 62 - message={_(msg`Something went wrong and we're not sure what.`)} 63 - onPressTryAgain={refetchProfile} 64 - /> 65 - ) 66 - } 67 - 68 - function ComponentLoaded({ 69 - profile: profileUnshadowed, 70 - moderationOpts, 71 - }: { 72 - profile: AppBskyActorDefs.ProfileViewDetailed 73 - moderationOpts: ModerationOpts 74 - }) { 75 - const pal = usePalette('default') 76 - const profile = useProfileShadow(profileUnshadowed) 77 - const {screen} = useAnalytics() 78 - const moderation = React.useMemo( 79 - () => moderateProfile(profile, moderationOpts), 80 - [profile, moderationOpts], 81 - ) 82 - 83 - // track the navigator state to detect if a page-load occurred 84 - const navState = useNavigationState(state => state) 85 - const [initNavState] = useState(navState) 86 - const isLoading = initNavState !== navState 87 - 88 - useEffect(() => { 89 - screen('Profile:Preview') 90 - }, [screen]) 91 - 92 - return ( 93 - <View testID="profilePreview" style={[pal.view, s.flex1]}> 94 - <View style={[styles.headerWrapper]}> 95 - <ProfileHeader 96 - profile={profile} 97 - moderation={moderation} 98 - hideBackButton 99 - isProfilePreview 100 - /> 101 - </View> 102 - <View style={[styles.hintWrapper, pal.view]}> 103 - <View style={styles.hint}> 104 - {isLoading ? ( 105 - <ActivityIndicator /> 106 - ) : ( 107 - <> 108 - <InfoCircleIcon size={21} style={pal.textLight} /> 109 - <ThemedText type="xl" fg="light"> 110 - <Trans>Swipe up to see more</Trans> 111 - </ThemedText> 112 - </> 113 - )} 114 - </View> 115 - </View> 116 - </View> 117 - ) 118 - } 119 - 120 - const styles = StyleSheet.create({ 121 - headerWrapper: { 122 - height: 440, 123 - }, 124 - hintWrapper: { 125 - height: 80, 126 - }, 127 - hint: { 128 - flexDirection: 'row', 129 - justifyContent: 'center', 130 - gap: 8, 131 - paddingHorizontal: 14, 132 - borderRadius: 6, 133 - }, 134 - })
+12 -32
src/view/com/util/UserPreviewLink.tsx
··· 1 1 import React from 'react' 2 - import {Pressable, StyleProp, ViewStyle} from 'react-native' 2 + import {StyleProp, ViewStyle} from 'react-native' 3 3 import {Link} from './Link' 4 - import {isAndroid, isWeb} from 'platform/detection' 4 + import {isWeb} from 'platform/detection' 5 5 import {makeProfileLink} from 'lib/routes/links' 6 - import {useModalControls} from '#/state/modals' 7 6 import {usePrefetchProfileQuery} from '#/state/queries/profile' 8 7 9 8 interface UserPreviewLinkProps { ··· 14 13 export function UserPreviewLink( 15 14 props: React.PropsWithChildren<UserPreviewLinkProps>, 16 15 ) { 17 - const {openModal} = useModalControls() 18 16 const prefetchProfileQuery = usePrefetchProfileQuery() 19 - 20 - if (isWeb || isAndroid) { 21 - return ( 22 - <Link 23 - onPointerEnter={() => { 24 - if (isWeb) { 25 - prefetchProfileQuery(props.did) 26 - } 27 - }} 28 - href={makeProfileLink(props)} 29 - title={props.handle} 30 - asAnchor 31 - style={props.style}> 32 - {props.children} 33 - </Link> 34 - ) 35 - } 36 17 return ( 37 - <Pressable 38 - onPress={() => 39 - openModal({ 40 - name: 'profile-preview', 41 - did: props.did, 42 - }) 43 - } 44 - accessibilityRole="button" 45 - accessibilityLabel={props.handle} 46 - accessibilityHint="" 18 + <Link 19 + onPointerEnter={() => { 20 + if (isWeb) { 21 + prefetchProfileQuery(props.did) 22 + } 23 + }} 24 + href={makeProfileLink(props)} 25 + title={props.handle} 26 + asAnchor 47 27 style={props.style}> 48 28 {props.children} 49 - </Pressable> 29 + </Link> 50 30 ) 51 31 }