diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/App.native.tsx | 6 | ||||
-rw-r--r-- | src/App.web.tsx | 95 | ||||
-rw-r--r-- | src/components/Dialog/index.tsx | 16 | ||||
-rw-r--r-- | src/lib/hooks/useEnableKeyboardController.tsx | 110 | ||||
-rw-r--r-- | src/screens/Messages/Conversation.tsx | 13 | ||||
-rw-r--r-- | src/screens/StarterPack/Wizard/index.tsx | 13 |
6 files changed, 169 insertions, 84 deletions
diff --git a/src/App.native.tsx b/src/App.native.tsx index 9b2940aa9..69f7faf9e 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -4,7 +4,6 @@ import '#/view/icons' import React, {useEffect, useState} from 'react' import {GestureHandlerRootView} from 'react-native-gesture-handler' -import {KeyboardProvider} from 'react-native-keyboard-controller' import {RootSiblingParent} from 'react-native-root-siblings' import { initialWindowMetrics, @@ -70,6 +69,7 @@ import {Splash} from '#/Splash' import {BottomSheetProvider} from '../modules/bottom-sheet' import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider' import {AppProfiler} from './AppProfiler' +import {KeyboardControllerProvider} from './lib/hooks/useEnableKeyboardController' SplashScreen.preventAutoHideAsync() @@ -188,7 +188,7 @@ function App() { <AppProfiler> <GeolocationProvider> <A11yProvider> - <KeyboardProvider enabled={false} statusBarTranslucent={true}> + <KeyboardControllerProvider> <SessionProvider> <PrefsStateProvider> <I18nProvider> @@ -217,7 +217,7 @@ function App() { </I18nProvider> </PrefsStateProvider> </SessionProvider> - </KeyboardProvider> + </KeyboardControllerProvider> </A11yProvider> </GeolocationProvider> </AppProfiler> diff --git a/src/App.web.tsx b/src/App.web.tsx index 53ca41873..808b0fc27 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -3,7 +3,6 @@ import '#/view/icons' import './style.css' import React, {useEffect, useState} from 'react' -import {KeyboardProvider} from 'react-native-keyboard-controller' import {RootSiblingParent} from 'react-native-root-siblings' import {SafeAreaProvider} from 'react-native-safe-area-context' import {msg} from '@lingui/macro' @@ -102,54 +101,52 @@ function InnerApp() { if (!isReady || !hasCheckedReferrer) return null return ( - <KeyboardProvider enabled={false}> - <Alf theme={theme}> - <ThemeProvider theme={theme}> - <RootSiblingParent> - <VideoVolumeProvider> - <ActiveVideoProvider> - <React.Fragment - // Resets the entire tree below when it changes: - key={currentAccount?.did}> - <QueryProvider currentDid={currentAccount?.did}> - <ComposerProvider> - <StatsigProvider> - <MessagesProvider> - {/* LabelDefsProvider MUST come before ModerationOptsProvider */} - <LabelDefsProvider> - <ModerationOptsProvider> - <LoggedOutViewProvider> - <SelectedFeedProvider> - <HiddenRepliesProvider> - <UnreadNotifsProvider> - <BackgroundNotificationPreferencesProvider> - <MutedThreadsProvider> - <SafeAreaProvider> - <ProgressGuideProvider> - <Shell /> - <NuxDialogs /> - </ProgressGuideProvider> - </SafeAreaProvider> - </MutedThreadsProvider> - </BackgroundNotificationPreferencesProvider> - </UnreadNotifsProvider> - </HiddenRepliesProvider> - </SelectedFeedProvider> - </LoggedOutViewProvider> - </ModerationOptsProvider> - </LabelDefsProvider> - </MessagesProvider> - </StatsigProvider> - </ComposerProvider> - </QueryProvider> - <ToastContainer /> - </React.Fragment> - </ActiveVideoProvider> - </VideoVolumeProvider> - </RootSiblingParent> - </ThemeProvider> - </Alf> - </KeyboardProvider> + <Alf theme={theme}> + <ThemeProvider theme={theme}> + <RootSiblingParent> + <VideoVolumeProvider> + <ActiveVideoProvider> + <React.Fragment + // Resets the entire tree below when it changes: + key={currentAccount?.did}> + <QueryProvider currentDid={currentAccount?.did}> + <ComposerProvider> + <StatsigProvider> + <MessagesProvider> + {/* LabelDefsProvider MUST come before ModerationOptsProvider */} + <LabelDefsProvider> + <ModerationOptsProvider> + <LoggedOutViewProvider> + <SelectedFeedProvider> + <HiddenRepliesProvider> + <UnreadNotifsProvider> + <BackgroundNotificationPreferencesProvider> + <MutedThreadsProvider> + <SafeAreaProvider> + <ProgressGuideProvider> + <Shell /> + <NuxDialogs /> + </ProgressGuideProvider> + </SafeAreaProvider> + </MutedThreadsProvider> + </BackgroundNotificationPreferencesProvider> + </UnreadNotifsProvider> + </HiddenRepliesProvider> + </SelectedFeedProvider> + </LoggedOutViewProvider> + </ModerationOptsProvider> + </LabelDefsProvider> + </MessagesProvider> + </StatsigProvider> + </ComposerProvider> + </QueryProvider> + <ToastContainer /> + </React.Fragment> + </ActiveVideoProvider> + </VideoVolumeProvider> + </RootSiblingParent> + </ThemeProvider> + </Alf> ) } diff --git a/src/components/Dialog/index.tsx b/src/components/Dialog/index.tsx index f16a9925d..c424321be 100644 --- a/src/components/Dialog/index.tsx +++ b/src/components/Dialog/index.tsx @@ -11,7 +11,6 @@ import { } from 'react-native' import { KeyboardAwareScrollView, - useKeyboardController, useKeyboardHandler, } from 'react-native-keyboard-controller' import {runOnJS} from 'react-native-reanimated' @@ -20,6 +19,7 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' +import {useEnableKeyboardController} from '#/lib/hooks/useEnableKeyboardController' import {ScrollProvider} from '#/lib/ScrollContext' import {logger} from '#/logger' import {isAndroid, isIOS} from '#/platform/detection' @@ -199,20 +199,10 @@ export const ScrollableInner = React.forwardRef<ScrollView, DialogInnerProps>( ) { const {nativeSnapPoint, disableDrag, setDisableDrag} = useDialogContext() const insets = useSafeAreaInsets() - const {setEnabled} = useKeyboardController() - const [keyboardHeight, setKeyboardHeight] = React.useState(0) - - React.useEffect(() => { - if (!isIOS) { - return - } + useEnableKeyboardController(isIOS) - setEnabled(true) - return () => { - setEnabled(false) - } - }) + const [keyboardHeight, setKeyboardHeight] = React.useState(0) useKeyboardHandler( { diff --git a/src/lib/hooks/useEnableKeyboardController.tsx b/src/lib/hooks/useEnableKeyboardController.tsx new file mode 100644 index 000000000..c7205d016 --- /dev/null +++ b/src/lib/hooks/useEnableKeyboardController.tsx @@ -0,0 +1,110 @@ +import { + createContext, + useCallback, + useContext, + useEffect, + useMemo, + useRef, +} from 'react' +import { + KeyboardProvider, + useKeyboardController, +} from 'react-native-keyboard-controller' +import {useFocusEffect} from '@react-navigation/native' + +import {IS_DEV} from '#/env' + +const KeyboardControllerRefCountContext = createContext<{ + incrementRefCount: () => void + decrementRefCount: () => void +}>({ + incrementRefCount: () => {}, + decrementRefCount: () => {}, +}) + +export function KeyboardControllerProvider({ + children, +}: { + children: React.ReactNode +}) { + return ( + <KeyboardProvider + enabled={false} + // I don't think this is necessary, but Chesterton's fence and all that -sfn + statusBarTranslucent={true}> + <KeyboardControllerProviderInner> + {children} + </KeyboardControllerProviderInner> + </KeyboardProvider> + ) +} + +function KeyboardControllerProviderInner({ + children, +}: { + children: React.ReactNode +}) { + const {setEnabled} = useKeyboardController() + const refCount = useRef(0) + + const value = useMemo( + () => ({ + incrementRefCount: () => { + refCount.current++ + setEnabled(refCount.current > 0) + }, + decrementRefCount: () => { + refCount.current-- + setEnabled(refCount.current > 0) + + if (IS_DEV && refCount.current < 0) { + console.error('KeyboardController ref count < 0') + } + }, + }), + [setEnabled], + ) + + return ( + <KeyboardControllerRefCountContext.Provider value={value}> + {children} + </KeyboardControllerRefCountContext.Provider> + ) +} + +export function useEnableKeyboardController(shouldEnable: boolean) { + const {incrementRefCount, decrementRefCount} = useContext( + KeyboardControllerRefCountContext, + ) + + useEffect(() => { + if (!shouldEnable) { + return + } + incrementRefCount() + return () => { + decrementRefCount() + } + }, [shouldEnable, incrementRefCount, decrementRefCount]) +} + +/** + * Like `useEnableKeyboardController`, but using `useFocusEffect` + */ +export function useEnableKeyboardControllerScreen(shouldEnable: boolean) { + const {incrementRefCount, decrementRefCount} = useContext( + KeyboardControllerRefCountContext, + ) + + useFocusEffect( + useCallback(() => { + if (!shouldEnable) { + return + } + incrementRefCount() + return () => { + decrementRefCount() + } + }, [shouldEnable, incrementRefCount, decrementRefCount]), + ) +} diff --git a/src/screens/Messages/Conversation.tsx b/src/screens/Messages/Conversation.tsx index ee09adaf0..a2157d2b9 100644 --- a/src/screens/Messages/Conversation.tsx +++ b/src/screens/Messages/Conversation.tsx @@ -1,6 +1,5 @@ import React, {useCallback} from 'react' import {View} from 'react-native' -import {useKeyboardController} from 'react-native-keyboard-controller' import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -8,6 +7,7 @@ import {useFocusEffect, useNavigation} from '@react-navigation/native' import {NativeStackScreenProps} from '@react-navigation/native-stack' import {useEmail} from '#/lib/hooks/useEmail' +import {useEnableKeyboardControllerScreen} from '#/lib/hooks/useEnableKeyboardController' import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types' import {isWeb} from '#/platform/detection' import {useProfileShadow} from '#/state/cache/profile-shadow' @@ -39,16 +39,7 @@ export function MessagesConversationScreen({route}: Props) { const convoId = route.params.conversation const {setCurrentConvoId} = useCurrentConvoId() - const {setEnabled} = useKeyboardController() - useFocusEffect( - useCallback(() => { - if (isWeb) return - setEnabled(true) - return () => { - setEnabled(false) - } - }, [setEnabled]), - ) + useEnableKeyboardControllerScreen(true) useFocusEffect( useCallback(() => { diff --git a/src/screens/StarterPack/Wizard/index.tsx b/src/screens/StarterPack/Wizard/index.tsx index 9a90a1f51..b0d71b929 100644 --- a/src/screens/StarterPack/Wizard/index.tsx +++ b/src/screens/StarterPack/Wizard/index.tsx @@ -1,9 +1,6 @@ import React from 'react' import {Keyboard, TouchableOpacity, View} from 'react-native' -import { - KeyboardAwareScrollView, - useKeyboardController, -} from 'react-native-keyboard-controller' +import {KeyboardAwareScrollView} from 'react-native-keyboard-controller' import {useSafeAreaInsets} from 'react-native-safe-area-context' import {Image} from 'expo-image' import { @@ -20,6 +17,7 @@ import {useFocusEffect, useNavigation} from '@react-navigation/native' import {NativeStackScreenProps} from '@react-navigation/native-stack' import {HITSLOP_10, STARTER_PACK_MAX_SIZE} from '#/lib/constants' +import {useEnableKeyboardControllerScreen} from '#/lib/hooks/useEnableKeyboardController' import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name' import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types' import {logEvent} from '#/lib/statsig/statsig' @@ -151,7 +149,6 @@ function WizardInner({ const {_} = useLingui() const t = useTheme() const setMinimalShellMode = useSetMinimalShellMode() - const {setEnabled} = useKeyboardController() const [state, dispatch] = useWizardState() const {currentAccount} = useSession() const {data: currentProfile} = useProfileQuery({ @@ -166,16 +163,16 @@ function WizardInner({ }) }, [navigation]) + useEnableKeyboardControllerScreen(true) + useFocusEffect( React.useCallback(() => { - setEnabled(true) setMinimalShellMode(true) return () => { setMinimalShellMode(false) - setEnabled(false) } - }, [setMinimalShellMode, setEnabled]), + }, [setMinimalShellMode]), ) const getDefaultName = () => { |