about summary refs log tree commit diff
path: root/src/lib/hooks/useEnableKeyboardController.tsx
blob: c7205d0160fa3878e0557ad9497c42d7ae722351 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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]),
  )
}