import React, { useState, useEffect } from 'react'; import { KeyboardAvoidingView, NativeModules, Keyboard } from 'react-native'; import { AmountAccessoryView } from 'loot-design/src/components/mobile/AmountInput'; import { BudgetAccessoryView } from 'loot-design/src/components/mobile/budget'; let { StatusBarHeight } = NativeModules; export let AccessoryIdContext = React.createContext(); function renderAccessoryView(id) { switch (id) { case 'budget': return <BudgetAccessoryView />; case 'amount': return <AmountAccessoryView />; default: } throw new Error('Unknown accessory view: ' + id); } export default function AndroidKeyboardAvoidingView({ children, behavior = 'height', enabled = true, keyboardVerticalOffset = 0, includeStatusBar, style }) { let [keyboard, setKeyboard] = useState(false); let [accessoryId, setAccessoryId] = useState(null); useEffect(() => { let cleanups = [ Keyboard.addListener('keyboardDidShow', e => { setKeyboard(true); }), Keyboard.addListener('keyboardDidHide', e => { setKeyboard(false); // TODO: This is wrong. In Android, the user can hide the // keyboard and bring it back up again all while never losing // focus of the input. This means we'll render the accessory // view the first time but never again. Need to figure out a // better solution. setAccessoryId(null); }) ]; return () => cleanups.forEach(handler => handler.remove()); }, []); return ( <AccessoryIdContext.Provider value={setAccessoryId}> <KeyboardAvoidingView style={[{ flex: 1 }, style]} behavior={behavior} keyboardVerticalOffset={ keyboardVerticalOffset + (includeStatusBar ? StatusBarHeight.statusBarHeight : 0) } enabled={enabled} > <> {children} {keyboard && accessoryId && renderAccessoryView(accessoryId)} </> </KeyboardAvoidingView> </AccessoryIdContext.Provider> ); }