Replace the navigation model with react-navigation
This commit is contained in:
@@ -46,7 +46,7 @@ export function Component({}: {}) {
|
||||
token: confirmCode,
|
||||
})
|
||||
Toast.show('Your account has been deleted')
|
||||
store.nav.tab.fixedTabReset()
|
||||
// store.nav.tab.fixedTabReset() TODO
|
||||
store.session.clear()
|
||||
store.shell.closeModal()
|
||||
} catch (e: any) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
StyleSheet,
|
||||
ViewStyle,
|
||||
} from 'react-native'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome'
|
||||
import {CenteredView, FlatList} from '../util/Views'
|
||||
@@ -18,10 +19,10 @@ import {FeedModel} from 'state/models/feed-view'
|
||||
import {FeedItem} from './FeedItem'
|
||||
import {OnScrollCb} from 'lib/hooks/useOnMainScroll'
|
||||
import {s} from 'lib/styles'
|
||||
import {useStores} from 'state/index'
|
||||
import {useAnalytics} from 'lib/analytics'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {MagnifyingGlassIcon} from 'lib/icons'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
|
||||
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
|
||||
const ERROR_FEED_ITEM = {_reactKey: '__error__'}
|
||||
@@ -47,9 +48,9 @@ export const Feed = observer(function Feed({
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const palInverted = usePalette('inverted')
|
||||
const store = useStores()
|
||||
const {track} = useAnalytics()
|
||||
const [isRefreshing, setIsRefreshing] = React.useState(false)
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
|
||||
const data = React.useMemo(() => {
|
||||
let feedItems: any[] = []
|
||||
@@ -112,7 +113,12 @@ export const Feed = observer(function Feed({
|
||||
<Button
|
||||
type="inverted"
|
||||
style={styles.emptyBtn}
|
||||
onPress={() => store.nav.navigate('/search')}>
|
||||
onPress={
|
||||
() =>
|
||||
navigation.navigate(
|
||||
'SearchTab',
|
||||
) /* TODO make sure it goes to root of the tab */
|
||||
}>
|
||||
<Text type="lg-medium" style={palInverted.text}>
|
||||
Find accounts
|
||||
</Text>
|
||||
@@ -134,7 +140,7 @@ export const Feed = observer(function Feed({
|
||||
}
|
||||
return <FeedItem item={item} showFollowBtn={showPostFollowBtn} />
|
||||
},
|
||||
[feed, onPressTryAgain, showPostFollowBtn, pal, palInverted, store.nav],
|
||||
[feed, onPressTryAgain, showPostFollowBtn, pal, palInverted, navigation],
|
||||
)
|
||||
|
||||
const FeedFooter = React.useCallback(
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
FontAwesomeIcon,
|
||||
FontAwesomeIconStyle,
|
||||
} from '@fortawesome/react-native-fontawesome'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {BlurView} from '../util/BlurView'
|
||||
import {ProfileViewModel} from 'state/models/profile-view'
|
||||
import {useStores} from 'state/index'
|
||||
@@ -28,6 +29,7 @@ import {UserAvatar} from '../util/UserAvatar'
|
||||
import {UserBanner} from '../util/UserBanner'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useAnalytics} from 'lib/analytics'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
|
||||
const BACK_HITSLOP = {left: 30, top: 30, right: 30, bottom: 30}
|
||||
|
||||
@@ -40,16 +42,17 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {track} = useAnalytics()
|
||||
const onPressBack = () => {
|
||||
store.nav.tab.goBack()
|
||||
}
|
||||
const onPressAvi = () => {
|
||||
const onPressBack = React.useCallback(() => {
|
||||
navigation.goBack()
|
||||
}, [navigation])
|
||||
const onPressAvi = React.useCallback(() => {
|
||||
if (view.avatar) {
|
||||
store.shell.openLightbox(new ProfileImageLightbox(view))
|
||||
}
|
||||
}
|
||||
const onPressToggleFollow = () => {
|
||||
}, [store, view])
|
||||
const onPressToggleFollow = React.useCallback(() => {
|
||||
view?.toggleFollowing().then(
|
||||
() => {
|
||||
Toast.show(
|
||||
@@ -60,28 +63,28 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||
},
|
||||
err => store.log.error('Failed to toggle follow', err),
|
||||
)
|
||||
}
|
||||
const onPressEditProfile = () => {
|
||||
}, [view, store])
|
||||
const onPressEditProfile = React.useCallback(() => {
|
||||
track('ProfileHeader:EditProfileButtonClicked')
|
||||
store.shell.openModal({
|
||||
name: 'edit-profile',
|
||||
profileView: view,
|
||||
onUpdate: onRefreshAll,
|
||||
})
|
||||
}
|
||||
const onPressFollowers = () => {
|
||||
}, [track, store, view, onRefreshAll])
|
||||
const onPressFollowers = React.useCallback(() => {
|
||||
track('ProfileHeader:FollowersButtonClicked')
|
||||
store.nav.navigate(`/profile/${view.handle}/followers`)
|
||||
}
|
||||
const onPressFollows = () => {
|
||||
navigation.push('ProfileFollowers', {name: view.handle})
|
||||
}, [track, navigation, view])
|
||||
const onPressFollows = React.useCallback(() => {
|
||||
track('ProfileHeader:FollowsButtonClicked')
|
||||
store.nav.navigate(`/profile/${view.handle}/follows`)
|
||||
}
|
||||
const onPressShare = () => {
|
||||
navigation.push('ProfileFollows', {name: view.handle})
|
||||
}, [track, navigation, view])
|
||||
const onPressShare = React.useCallback(() => {
|
||||
track('ProfileHeader:ShareButtonClicked')
|
||||
Share.share({url: toShareUrl(`/profile/${view.handle}`)})
|
||||
}
|
||||
const onPressMuteAccount = async () => {
|
||||
}, [track, view])
|
||||
const onPressMuteAccount = React.useCallback(async () => {
|
||||
track('ProfileHeader:MuteAccountButtonClicked')
|
||||
try {
|
||||
await view.muteAccount()
|
||||
@@ -90,8 +93,8 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||
store.log.error('Failed to mute account', e)
|
||||
Toast.show(`There was an issue! ${e.toString()}`)
|
||||
}
|
||||
}
|
||||
const onPressUnmuteAccount = async () => {
|
||||
}, [track, view, store])
|
||||
const onPressUnmuteAccount = React.useCallback(async () => {
|
||||
track('ProfileHeader:UnmuteAccountButtonClicked')
|
||||
try {
|
||||
await view.unmuteAccount()
|
||||
@@ -100,14 +103,14 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||
store.log.error('Failed to unmute account', e)
|
||||
Toast.show(`There was an issue! ${e.toString()}`)
|
||||
}
|
||||
}
|
||||
const onPressReportAccount = () => {
|
||||
}, [track, view, store])
|
||||
const onPressReportAccount = React.useCallback(() => {
|
||||
track('ProfileHeader:ReportAccountButtonClicked')
|
||||
store.shell.openModal({
|
||||
name: 'report-account',
|
||||
did: view.did,
|
||||
})
|
||||
}
|
||||
}, [track, store, view])
|
||||
|
||||
// loading
|
||||
// =
|
||||
|
||||
+77
-37
@@ -2,6 +2,8 @@ import React from 'react'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {
|
||||
Linking,
|
||||
GestureResponderEvent,
|
||||
Platform,
|
||||
StyleProp,
|
||||
TouchableWithoutFeedback,
|
||||
TouchableOpacity,
|
||||
@@ -9,11 +11,18 @@ import {
|
||||
View,
|
||||
ViewStyle,
|
||||
} from 'react-native'
|
||||
import {useLinkProps, useNavigation} from '@react-navigation/native'
|
||||
import {Text} from './text/Text'
|
||||
import {TypographyVariant} from 'lib/ThemeContext'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {matchPath} from 'view/screens'
|
||||
import {useStores, RootStoreModel} from 'state/index'
|
||||
import {convertBskyAppUrlIfNeeded} from 'lib/strings/url-helpers'
|
||||
|
||||
type Event =
|
||||
| React.MouseEvent<HTMLAnchorElement, MouseEvent>
|
||||
| GestureResponderEvent
|
||||
|
||||
export const Link = observer(function Link({
|
||||
style,
|
||||
href,
|
||||
@@ -27,35 +36,30 @@ export const Link = observer(function Link({
|
||||
children?: React.ReactNode
|
||||
noFeedback?: boolean
|
||||
}) {
|
||||
let {...props} = useLinkProps({to: href})
|
||||
const store = useStores()
|
||||
const onPress = () => {
|
||||
if (href) {
|
||||
handleLink(store, href, false)
|
||||
}
|
||||
}
|
||||
const onLongPress = () => {
|
||||
if (href) {
|
||||
handleLink(store, href, true)
|
||||
}
|
||||
}
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
|
||||
props.onPress = React.useCallback(
|
||||
(e?: Event) => {
|
||||
if (typeof href === 'string') {
|
||||
return onPressInner(store, navigation, href, e)
|
||||
}
|
||||
},
|
||||
[store, navigation, href],
|
||||
)
|
||||
|
||||
if (noFeedback) {
|
||||
return (
|
||||
<TouchableWithoutFeedback
|
||||
onPress={onPress}
|
||||
onLongPress={onLongPress}
|
||||
delayPressIn={50}>
|
||||
<View style={style}>
|
||||
<TouchableWithoutFeedback delayPressIn={50} {...props}>
|
||||
<View style={style} {...props}>
|
||||
{children ? children : <Text>{title || 'link'}</Text>}
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
onLongPress={onLongPress}
|
||||
delayPressIn={50}
|
||||
style={style}>
|
||||
<TouchableOpacity delayPressIn={50} style={style} {...props}>
|
||||
{children ? children : <Text>{title || 'link'}</Text>}
|
||||
</TouchableOpacity>
|
||||
)
|
||||
@@ -72,29 +76,65 @@ export const TextLink = observer(function TextLink({
|
||||
href: string
|
||||
text: string
|
||||
}) {
|
||||
const {...props} = useLinkProps({to: href})
|
||||
const store = useStores()
|
||||
const onPress = () => {
|
||||
handleLink(store, href, false)
|
||||
}
|
||||
const onLongPress = () => {
|
||||
handleLink(store, href, true)
|
||||
}
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
|
||||
props.onPress = React.useCallback(
|
||||
(e?: Event) => {
|
||||
return onPressInner(store, navigation, href, e)
|
||||
},
|
||||
[store, navigation, href],
|
||||
)
|
||||
|
||||
return (
|
||||
<Text type={type} style={style} onPress={onPress} onLongPress={onLongPress}>
|
||||
<Text type={type} style={style} {...props}>
|
||||
{text}
|
||||
</Text>
|
||||
)
|
||||
})
|
||||
|
||||
function handleLink(store: RootStoreModel, href: string, longPress: boolean) {
|
||||
href = convertBskyAppUrlIfNeeded(href)
|
||||
if (href.startsWith('http')) {
|
||||
Linking.openURL(href)
|
||||
} else if (longPress) {
|
||||
store.shell.closeModal() // close any active modals
|
||||
store.nav.newTab(href)
|
||||
} else {
|
||||
store.shell.closeModal() // close any active modals
|
||||
store.nav.navigate(href)
|
||||
// NOTE
|
||||
// we can't use the onPress given by useLinkProps because it will
|
||||
// match most paths to the HomeTab routes while we actually want to
|
||||
// preserve the tab the app is currently in
|
||||
//
|
||||
// we also have some additional behaviors - closing the current modal,
|
||||
// converting bsky urls, and opening http/s links in the system browser
|
||||
//
|
||||
// this method copies from the onPress implementation but adds our
|
||||
// needed customizations
|
||||
// -prf
|
||||
function onPressInner(
|
||||
store: RootStoreModel,
|
||||
navigation: NavigationProp,
|
||||
href: string,
|
||||
e?: Event,
|
||||
) {
|
||||
let shouldHandle = false
|
||||
|
||||
if (Platform.OS !== 'web' || !e) {
|
||||
shouldHandle = e ? !e.defaultPrevented : true
|
||||
} else if (
|
||||
!e.defaultPrevented && // onPress prevented default
|
||||
!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) && // ignore clicks with modifier keys
|
||||
(e.button == null || e.button === 0) && // ignore everything but left clicks
|
||||
[undefined, null, '', 'self'].includes(e.currentTarget?.target) // let browser handle "target=_blank" etc.
|
||||
) {
|
||||
e.preventDefault()
|
||||
shouldHandle = true
|
||||
}
|
||||
|
||||
if (shouldHandle) {
|
||||
href = convertBskyAppUrlIfNeeded(href)
|
||||
if (href.startsWith('http')) {
|
||||
Linking.openURL(href)
|
||||
} else {
|
||||
store.shell.closeModal() // close any active modals
|
||||
|
||||
const {name, params} = matchPath(href)
|
||||
// @ts-ignore we're not able to type check on this one -prf
|
||||
navigation.push(name, params)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {Animated, StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {useNavigation, DrawerActions} from '@react-navigation/native'
|
||||
import {UserAvatar} from './UserAvatar'
|
||||
import {Text} from './text/Text'
|
||||
import {useStores} from 'state/index'
|
||||
@@ -9,6 +10,7 @@ import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
|
||||
import {useAnalytics} from 'lib/analytics'
|
||||
import {isDesktopWeb} from '../../../platform/detection'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
|
||||
const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20}
|
||||
|
||||
@@ -23,17 +25,22 @@ export const ViewHeader = observer(function ViewHeader({
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {track} = useAnalytics()
|
||||
const onPressBack = () => {
|
||||
store.nav.tab.goBack()
|
||||
}
|
||||
const onPressMenu = () => {
|
||||
|
||||
const onPressBack = React.useCallback(() => {
|
||||
navigation.goBack()
|
||||
}, [navigation])
|
||||
|
||||
const onPressMenu = React.useCallback(() => {
|
||||
track('ViewHeader:MenuButtonClicked')
|
||||
store.shell.setMainMenuOpen(true)
|
||||
}
|
||||
navigation.dispatch(DrawerActions.openDrawer())
|
||||
}, [track, navigation])
|
||||
|
||||
if (typeof canGoBack === 'undefined') {
|
||||
canGoBack = store.nav.tab.canGoBack
|
||||
canGoBack = navigation.canGoBack()
|
||||
}
|
||||
|
||||
if (isDesktopWeb) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import {Button, ButtonType} from './Button'
|
||||
import {colors} from 'lib/styles'
|
||||
import {toShareUrl} from 'lib/strings/url-helpers'
|
||||
import {useStores} from 'state/index'
|
||||
import {TABS_ENABLED} from 'lib/build-flags'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useTheme} from 'lib/ThemeContext'
|
||||
|
||||
@@ -138,15 +137,6 @@ export function PostDropdownBtn({
|
||||
const store = useStores()
|
||||
|
||||
const dropdownItems: DropdownItem[] = [
|
||||
TABS_ENABLED
|
||||
? {
|
||||
icon: ['far', 'clone'],
|
||||
label: 'Open in new tab',
|
||||
onPress() {
|
||||
store.nav.newTab(itemHref)
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
{
|
||||
icon: 'language',
|
||||
label: 'Translate...',
|
||||
|
||||
Reference in New Issue
Block a user