diff --git a/src/lib/hooks/usePermissions.ts b/src/lib/hooks/usePermissions.ts index 1bb7a01f8e..36a92ac32d 100644 --- a/src/lib/hooks/usePermissions.ts +++ b/src/lib/hooks/usePermissions.ts @@ -38,7 +38,7 @@ export function useCameraPermission() { const [cameraPermissionStatus] = Camera.useCameraPermissions() const requestCameraAccessIfNeeded = async () => { - if (cameraPermissionStatus.granted) { + if (cameraPermissionStatus?.granted) { return true } else { openPermissionAlert('camera') diff --git a/src/lib/routes/helpers.ts b/src/lib/routes/helpers.ts index 6cb5404a64..013569aa65 100644 --- a/src/lib/routes/helpers.ts +++ b/src/lib/routes/helpers.ts @@ -15,7 +15,7 @@ import {State, NavigationProp} from './types' // } export function getCurrentRoute(state: State) { - let node = state.routes[state.index] + let node = state.routes[state.index || 0] while (node.state?.routes && typeof node.state?.index === 'number') { node = node.state?.routes[node.state?.index] } diff --git a/src/lib/routes/types.ts b/src/lib/routes/types.ts index 5506ad9e1a..307bccd630 100644 --- a/src/lib/routes/types.ts +++ b/src/lib/routes/types.ts @@ -19,14 +19,26 @@ export type HomeTabNavigatorParams = CommonNavigatorParams & { Home: undefined } -export type NotificationsTabNavigatorParams = CommonNavigatorParams & { - Notifications: undefined +export type HomeDrawerNavigatorParams = { + HomeInner: undefined } export type SearchTabNavigatorParams = CommonNavigatorParams & { Search: undefined } +export type SearchDrawerNavigatorParams = { + SearchInner: undefined +} + +export type NotificationsTabNavigatorParams = CommonNavigatorParams & { + Notifications: undefined +} + +export type NotificationsDrawerNavigatorParams = { + NotificationsInner: undefined +} + // NOTE // this isn't strictly correct but it should be close enough // a TS wizard might be able to get this 100% diff --git a/src/routes.tsx b/src/routes.tsx index f90ecdc845..6ae6af3bed 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -6,8 +6,11 @@ import {createBottomTabNavigator} from '@react-navigation/bottom-tabs' import { HomeTabNavigatorParams, - NotificationsTabNavigatorParams, + HomeDrawerNavigatorParams, SearchTabNavigatorParams, + SearchDrawerNavigatorParams, + NotificationsTabNavigatorParams, + NotificationsDrawerNavigatorParams, State, } from 'lib/routes/types' @@ -27,11 +30,12 @@ import {PostRepostedByScreen} from './view/screens/PostRepostedBy' import {DebugScreen} from './view/screens/Debug' import {LogScreen} from './view/screens/Log' -const HomeDrawer = createDrawerNavigator() +const HomeDrawer = createDrawerNavigator() const HomeTab = createNativeStackNavigator() -const SearchDrawer = createDrawerNavigator() +const SearchDrawer = createDrawerNavigator() const SearchTab = createNativeStackNavigator() -const NotificationsDrawer = createDrawerNavigator() +const NotificationsDrawer = + createDrawerNavigator() const NotificationsTab = createNativeStackNavigator() const Tab = createBottomTabNavigator() @@ -139,7 +143,7 @@ function buildStateObject(stack: string, route: string, params: RouteParams) { } } -function commonScreens(Stack: ReturnType) { +function commonScreens(Stack: typeof HomeTab) { return ( <> @@ -183,6 +187,31 @@ function HomeTabNavigator() { ) } +function SearchDrawerNavigator() { + const drawerContent = React.useCallback(props => , []) + return ( + + + + ) +} + +function SearchTabNavigator() { + return ( + + + {commonScreens(SearchTab as typeof HomeTab)} + + ) +} + function NotificationsDrawerNavigator() { const drawerContent = React.useCallback(props => , []) return ( @@ -209,36 +238,11 @@ function NotificationsTabNavigator() { name="Notifications" component={NotificationsDrawerNavigator} /> - {commonScreens(NotificationsTab)} + {commonScreens(NotificationsTab as typeof HomeTab)} ) } -function SearchDrawerNavigator() { - const drawerContent = React.useCallback(props => , []) - return ( - - - - ) -} - -function SearchTabNavigator() { - return ( - - - {commonScreens(SearchTab)} - - ) -} - export function TabsNavigator() { const tabBar = React.useCallback(props => , []) return ( diff --git a/src/view/com/util/Link.tsx b/src/view/com/util/Link.tsx index 75a914ae5c..0f4fce02ca 100644 --- a/src/view/com/util/Link.tsx +++ b/src/view/com/util/Link.tsx @@ -117,8 +117,11 @@ function onPressInner( shouldHandle = e ? !e.defaultPrevented : true } else if ( !e.defaultPrevented && // onPress prevented default + // @ts-ignore Web only -prf !(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) && // ignore clicks with modifier keys + // @ts-ignore Web only -prf (e.button == null || e.button === 0) && // ignore everything but left clicks + // @ts-ignore Web only -prf [undefined, null, '', 'self'].includes(e.currentTarget?.target) // let browser handle "target=_blank" etc. ) { e.preventDefault() diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index 505b1fcfe8..1dc5be1052 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -3,7 +3,10 @@ import {FlatList, View} from 'react-native' import {useFocusEffect, useIsFocused} from '@react-navigation/native' import {observer} from 'mobx-react-lite' import useAppState from 'react-native-appstate-hook' -import {NativeStackScreenProps, HomeTabNavigatorParams} from 'lib/routes/types' +import { + NativeStackScreenProps, + HomeDrawerNavigatorParams, +} from 'lib/routes/types' import {ViewHeader} from '../com/util/ViewHeader' import {Feed} from '../com/posts/Feed' import {LoadLatestBtn} from '../com/util/LoadLatestBtn' @@ -17,7 +20,7 @@ import {ComposeIcon2} from 'lib/icons' const HEADER_HEIGHT = 42 -type Props = NativeStackScreenProps +type Props = NativeStackScreenProps export const HomeScreen = observer(function Home(_opts: Props) { const store = useStores() const onMainScroll = useOnMainScroll(store) diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx index bde387e604..bb7225f71d 100644 --- a/src/view/screens/Notifications.tsx +++ b/src/view/screens/Notifications.tsx @@ -4,7 +4,7 @@ import {useFocusEffect} from '@react-navigation/native' import useAppState from 'react-native-appstate-hook' import { NativeStackScreenProps, - NotificationsTabNavigatorParams, + NotificationsDrawerNavigatorParams, } from 'lib/routes/types' import {ViewHeader} from '../com/util/ViewHeader' import {Feed} from '../com/notifications/Feed' @@ -15,10 +15,11 @@ import {useAnalytics} from 'lib/analytics' const NOTIFICATIONS_POLL_INTERVAL = 15e3 -export const NotificationsScreen = ({}: NativeStackScreenProps< - NotificationsTabNavigatorParams, - 'Notifications' ->) => { +type Props = NativeStackScreenProps< + NotificationsDrawerNavigatorParams, + 'NotificationsInner' +> +export const NotificationsScreen = ({}: Props) => { const store = useStores() const onMainScroll = useOnMainScroll(store) const scrollElRef = React.useRef(null) diff --git a/src/view/screens/ProfileFollows.tsx b/src/view/screens/ProfileFollows.tsx index b7bbe89e87..7edf8edba4 100644 --- a/src/view/screens/ProfileFollows.tsx +++ b/src/view/screens/ProfileFollows.tsx @@ -1,4 +1,4 @@ -import React, {useEffect} from 'react' +import React from 'react' import {View} from 'react-native' import {useFocusEffect} from '@react-navigation/native' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' diff --git a/src/view/screens/Search.tsx b/src/view/screens/Search.tsx index ae90bfbe6b..2bcbd722ce 100644 --- a/src/view/screens/Search.tsx +++ b/src/view/screens/Search.tsx @@ -15,7 +15,7 @@ import { import {ScrollView} from '../com/util/Views' import { NativeStackScreenProps, - SearchTabNavigatorParams, + SearchDrawerNavigatorParams, } from 'lib/routes/types' import {observer} from 'mobx-react-lite' import {UserAvatar} from '../com/util/UserAvatar' @@ -34,8 +34,8 @@ import {useAnalytics} from 'lib/analytics' const MENU_HITSLOP = {left: 10, top: 10, right: 30, bottom: 10} const FIVE_MIN = 5 * 60 * 1e3 -type Props = NativeStackScreenProps -export const SearchScreen = observer(({}: Props) => { +type Props = NativeStackScreenProps +export const SearchScreen = observer(({}: Props) => { const pal = usePalette('default') const store = useStores() const {track} = useAnalytics() diff --git a/src/view/screens/Settings.tsx b/src/view/screens/Settings.tsx index 9ba9935f38..7b744af86f 100644 --- a/src/view/screens/Settings.tsx +++ b/src/view/screens/Settings.tsx @@ -32,250 +32,246 @@ import {AccountData} from 'state/models/session' import {useAnalytics} from 'lib/analytics' import {NavigationProp} from 'lib/routes/types' -export const SettingsScreen = observer( - function Settings({}: NativeStackScreenProps< - CommonNavigatorParams, - 'Settings' - >) { - const theme = useTheme() - const pal = usePalette('default') - const store = useStores() - const navigation = useNavigation() - const {screen, track} = useAnalytics() - const [isSwitching, setIsSwitching] = React.useState(false) +type Props = NativeStackScreenProps +export const SettingsScreen = observer(function Settings({}: Props) { + const theme = useTheme() + const pal = usePalette('default') + const store = useStores() + const navigation = useNavigation() + const {screen, track} = useAnalytics() + const [isSwitching, setIsSwitching] = React.useState(false) - useFocusEffect( - React.useCallback(() => { - screen('Settings') - store.shell.setMinimalShellMode(false) - }, [screen, store]), - ) + useFocusEffect( + React.useCallback(() => { + screen('Settings') + store.shell.setMinimalShellMode(false) + }, [screen, store]), + ) - const onPressSwitchAccount = async (acct: AccountData) => { - track('Settings:SwitchAccountButtonClicked') - setIsSwitching(true) - if (await store.session.resumeSession(acct)) { - setIsSwitching(false) - navigation.navigate('HomeTab') - navigation.dispatch(StackActions.popToTop()) - Toast.show(`Signed in as ${acct.displayName || acct.handle}`) - return - } + const onPressSwitchAccount = async (acct: AccountData) => { + track('Settings:SwitchAccountButtonClicked') + setIsSwitching(true) + if (await store.session.resumeSession(acct)) { setIsSwitching(false) - Toast.show('Sorry! We need you to enter your password.') navigation.navigate('HomeTab') navigation.dispatch(StackActions.popToTop()) - store.session.clear() - } - const onPressAddAccount = () => { - track('Settings:AddAccountButtonClicked') - store.session.clear() - } - const onPressChangeHandle = () => { - track('Settings:ChangeHandleButtonClicked') - store.shell.openModal({ - name: 'change-handle', - onChanged() { - setIsSwitching(true) - store.session.reloadFromServer().then( - () => { - setIsSwitching(false) - Toast.show('Your handle has been updated') - }, - err => { - store.log.error( - 'Failed to reload from server after handle update', - {err}, - ) - setIsSwitching(false) - }, - ) - }, - }) - } - const onPressSignout = () => { - track('Settings:SignOutButtonClicked') - store.session.logout() - } - const onPressDeleteAccount = () => { - store.shell.openModal({name: 'delete-account'}) + Toast.show(`Signed in as ${acct.displayName || acct.handle}`) + return } + setIsSwitching(false) + Toast.show('Sorry! We need you to enter your password.') + navigation.navigate('HomeTab') + navigation.dispatch(StackActions.popToTop()) + store.session.clear() + } + const onPressAddAccount = () => { + track('Settings:AddAccountButtonClicked') + store.session.clear() + } + const onPressChangeHandle = () => { + track('Settings:ChangeHandleButtonClicked') + store.shell.openModal({ + name: 'change-handle', + onChanged() { + setIsSwitching(true) + store.session.reloadFromServer().then( + () => { + setIsSwitching(false) + Toast.show('Your handle has been updated') + }, + err => { + store.log.error( + 'Failed to reload from server after handle update', + {err}, + ) + setIsSwitching(false) + }, + ) + }, + }) + } + const onPressSignout = () => { + track('Settings:SignOutButtonClicked') + store.session.logout() + } + const onPressDeleteAccount = () => { + store.shell.openModal({name: 'delete-account'}) + } - return ( - - - - - - - Signed in as - - + return ( + + + + + + + Signed in as + + + + {isSwitching ? ( + + - {isSwitching ? ( + ) : ( + - - - ) : ( - - - - - - - - {store.me.displayName || store.me.handle} - - - {store.me.handle} - - - - - Sign out - - - - - )} - {store.session.switchableAccounts.map(account => ( - onPressSwitchAccount(account) - }> - - {account.displayName || account.handle} + + {store.me.displayName || store.me.handle} - - {account.handle} + + {store.me.handle} - - - ))} + + + Sign out + + + + + )} + {store.session.switchableAccounts.map(account => ( - - onPressSwitchAccount(account) + }> + + - - Add account - + + + {account.displayName || account.handle} + + + {account.handle} + + + - - - - - Advanced + ))} + + + + + + Add account - - - - - - Change my handle - - + - + - - Danger zone + + Advanced + + + + + + + Change my handle - - - - - + + + + + Danger zone + + + + - Delete my account - - - - - - - Developer tools + } + size={21} + /> + + + Delete my account - - - System log - - - - - Storybook - - - - Build version {AppInfo.appVersion} ({AppInfo.buildVersion}) + + + + + + Developer tools + + + + System log - - - - ) - }, -) + + + + Storybook + + + + Build version {AppInfo.appVersion} ({AppInfo.buildVersion}) + + + + + ) +}) function AccountDropdownBtn({handle}: {handle: string}) { const store = useStores()