Only enable keyboard controller when necessary (#4483)

* Only enable keyboard controller when necessary

* make it screen only

* rm keyboard padding

* rm keyboardpadding file

* revert using keyboard controller in composer

* remove styles.outer (unnecessary for revert)

* continue to use keyboard padding in the report dialog for dms

---------

Co-authored-by: Hailey <me@haileyok.com>
zio/stable
Samuel Newman 2024-06-11 20:50:56 +01:00 committed by GitHub
parent aca0fa23ec
commit 3d4b390a8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 191 additions and 206 deletions

View File

@ -143,7 +143,7 @@ function App() {
* that is set up in the InnerApp component above. * that is set up in the InnerApp component above.
*/ */
return ( return (
<KeyboardProvider enabled={true} statusBarTranslucent={true}> <KeyboardProvider enabled={false} statusBarTranslucent={true}>
<SessionProvider> <SessionProvider>
<ShellStateProvider> <ShellStateProvider>
<PrefsStateProvider> <PrefsStateProvider>

View File

@ -5,7 +5,7 @@ import Animated, {
useSharedValue, useSharedValue,
} from 'react-native-reanimated' } from 'react-native-reanimated'
export function KeyboardPadding({maxHeight}: {maxHeight?: number}) { export function KeyboardControllerPadding({maxHeight}: {maxHeight?: number}) {
const keyboardHeight = useSharedValue(0) const keyboardHeight = useSharedValue(0)
useKeyboardHandler( useKeyboardHandler(

View File

@ -0,0 +1,7 @@
export function KeyboardControllerPadding({
maxHeight: _,
}: {
maxHeight?: number
}) {
return null
}

View File

@ -1,3 +0,0 @@
export function KeyboardPadding({maxHeight: _}: {maxHeight?: number}) {
return null
}

View File

@ -15,7 +15,6 @@ import * as Dialog from '#/components/Dialog'
import * as Toggle from '#/components/forms/Toggle' import * as Toggle from '#/components/forms/Toggle'
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron' import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron'
import {KeyboardPadding} from '#/components/KeyboardPadding'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {ReportDialogProps} from './types' import {ReportDialogProps} from './types'
@ -222,7 +221,6 @@ export function SubmitView({
{submitting && <ButtonIcon icon={Loader} />} {submitting && <ButtonIcon icon={Loader} />}
</Button> </Button>
</View> </View>
<KeyboardPadding />
</View> </View>
) )
} }

View File

@ -28,7 +28,6 @@ import {Hashtag_Stroke2_Corner0_Rounded as Hashtag} from '#/components/icons/Has
import {PageText_Stroke2_Corner0_Rounded as PageText} from '#/components/icons/PageText' import {PageText_Stroke2_Corner0_Rounded as PageText} from '#/components/icons/PageText'
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
import {KeyboardPadding} from '#/components/KeyboardPadding'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import * as Prompt from '#/components/Prompt' import * as Prompt from '#/components/Prompt'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
@ -257,7 +256,6 @@ function MutedWordsInner() {
</View> </View>
<Dialog.Close /> <Dialog.Close />
<KeyboardPadding maxHeight={100} />
</Dialog.ScrollableInner> </Dialog.ScrollableInner>
) )
} }

View File

@ -16,6 +16,7 @@ import {CharProgress} from '#/view/com/composer/char-progress/CharProgress'
import * as Toast from '#/view/com/util/Toast' import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import * as Dialog from '#/components/Dialog' import * as Dialog from '#/components/Dialog'
import {KeyboardControllerPadding} from '#/components/KeyboardControllerPadding'
import {Button, ButtonIcon, ButtonText} from '../Button' import {Button, ButtonIcon, ButtonText} from '../Button'
import {Divider} from '../Divider' import {Divider} from '../Divider'
import {ChevronLeft_Stroke2_Corner0_Rounded as Chevron} from '../icons/Chevron' import {ChevronLeft_Stroke2_Corner0_Rounded as Chevron} from '../icons/Chevron'
@ -47,6 +48,7 @@ let ReportDialog = ({
<Dialog.ScrollableInner label={_(msg`Report this message`)}> <Dialog.ScrollableInner label={_(msg`Report this message`)}>
<DialogInner params={params} /> <DialogInner params={params} />
<Dialog.Close /> <Dialog.Close />
<KeyboardControllerPadding />
</Dialog.ScrollableInner> </Dialog.ScrollableInner>
</Dialog.Outer> </Dialog.Outer>
) )

View File

@ -14,7 +14,6 @@ import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog' import * as Dialog from '#/components/Dialog'
import {KeyboardPadding} from '#/components/KeyboardPadding'
import {InlineLinkText} from '#/components/Link' import {InlineLinkText} from '#/components/Link'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {Divider} from '../Divider' import {Divider} from '../Divider'
@ -110,7 +109,6 @@ function LabelsOnMeDialogInner(props: LabelsOnMeDialogProps) {
</> </>
)} )}
<Dialog.Close /> <Dialog.Close />
<KeyboardPadding />
</Dialog.ScrollableInner> </Dialog.ScrollableInner>
) )
} }

View File

@ -1,5 +1,6 @@
import React, {useCallback} from 'react' import React, {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {useKeyboardController} from 'react-native-keyboard-controller'
import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api' import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api'
import {msg} from '@lingui/macro' import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
@ -34,6 +35,17 @@ export function MessagesConversationScreen({route}: Props) {
const convoId = route.params.conversation const convoId = route.params.conversation
const {setCurrentConvoId} = useCurrentConvoId() const {setCurrentConvoId} = useCurrentConvoId()
const {setEnabled} = useKeyboardController()
useFocusEffect(
useCallback(() => {
if (isWeb) return
setEnabled(true)
return () => {
setEnabled(false)
}
}, [setEnabled]),
)
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {
setCurrentConvoId(convoId) setCurrentConvoId(convoId)

View File

@ -10,16 +10,12 @@ import {
ActivityIndicator, ActivityIndicator,
BackHandler, BackHandler,
Keyboard, Keyboard,
KeyboardAvoidingView,
LayoutChangeEvent, LayoutChangeEvent,
StyleSheet, StyleSheet,
TouchableOpacity, TouchableOpacity,
View, View,
} from 'react-native' } from 'react-native'
import {
KeyboardAvoidingView,
KeyboardStickyView,
useKeyboardController,
} from 'react-native-keyboard-controller'
import Animated, { import Animated, {
interpolateColor, interpolateColor,
useAnimatedStyle, useAnimatedStyle,
@ -131,17 +127,6 @@ export const ComposePost = observer(function ComposePost({
const {closeAllModals} = useModalControls() const {closeAllModals} = useModalControls()
const t = useTheme() const t = useTheme()
// Disable this in the composer to prevent any extra keyboard height being applied.
// See https://github.com/bluesky-social/social-app/pull/4399
const {setEnabled} = useKeyboardController()
React.useEffect(() => {
if (!isAndroid) return
setEnabled(false)
return () => {
setEnabled(true)
}
}, [setEnabled])
const [isKeyboardVisible] = useIsKeyboardVisible({iosUseWillEvents: true}) const [isKeyboardVisible] = useIsKeyboardVisible({iosUseWillEvents: true})
const [isProcessing, setIsProcessing] = useState(false) const [isProcessing, setIsProcessing] = useState(false)
const [processingState, setProcessingState] = useState('') const [processingState, setProcessingState] = useState('')
@ -431,181 +416,175 @@ export const ComposePost = observer(function ComposePost({
} = useAnimatedBorders() } = useAnimatedBorders()
return ( return (
<> <KeyboardAvoidingView
<KeyboardAvoidingView testID="composePostView"
testID="composePostView" behavior={isIOS ? 'padding' : 'height'}
behavior="padding" keyboardVerticalOffset={isIOS ? 70 : 0}
style={a.flex_1} style={[a.flex_1]}>
keyboardVerticalOffset={replyTo ? 115 : isAndroid ? 180 : 162}> <View style={[a.flex_1, viewStyles]} aria-modal accessibilityViewIsModal>
<View <Animated.View style={topBarAnimatedStyle}>
style={[a.flex_1, viewStyles]} <View style={styles.topbarInner}>
aria-modal <TouchableOpacity
accessibilityViewIsModal> testID="composerDiscardButton"
<Animated.View style={topBarAnimatedStyle}> onPress={onPressCancel}
<View style={styles.topbarInner}> onAccessibilityEscape={onPressCancel}
<TouchableOpacity accessibilityRole="button"
testID="composerDiscardButton" accessibilityLabel={_(msg`Cancel`)}
onPress={onPressCancel} accessibilityHint={_(
onAccessibilityEscape={onPressCancel} msg`Closes post composer and discards post draft`,
accessibilityRole="button" )}
accessibilityLabel={_(msg`Cancel`)} hitSlop={HITSLOP_10}>
accessibilityHint={_( <Text style={[pal.link, s.f18]}>
msg`Closes post composer and discards post draft`, <Trans>Cancel</Trans>
)} </Text>
hitSlop={HITSLOP_10}> </TouchableOpacity>
<Text style={[pal.link, s.f18]}> <View style={a.flex_1} />
<Trans>Cancel</Trans> {isProcessing ? (
</Text> <>
</TouchableOpacity> <Text style={pal.textLight}>{processingState}</Text>
<View style={a.flex_1} /> <View style={styles.postBtn}>
{isProcessing ? ( <ActivityIndicator />
<> </View>
<Text style={pal.textLight}>{processingState}</Text> </>
<View style={styles.postBtn}> ) : (
<ActivityIndicator /> <>
</View> <LabelsBtn
</> labels={labels}
) : ( onChange={setLabels}
<> hasMedia={hasMedia}
<LabelsBtn />
labels={labels} {canPost ? (
onChange={setLabels} <TouchableOpacity
hasMedia={hasMedia} testID="composerPublishBtn"
/> onPress={onPressPublish}
{canPost ? ( accessibilityRole="button"
<TouchableOpacity accessibilityLabel={
testID="composerPublishBtn" replyTo ? _(msg`Publish reply`) : _(msg`Publish post`)
onPress={onPressPublish} }
accessibilityRole="button" accessibilityHint="">
accessibilityLabel={ <LinearGradient
replyTo ? _(msg`Publish reply`) : _(msg`Publish post`) colors={[
} gradients.blueLight.start,
accessibilityHint=""> gradients.blueLight.end,
<LinearGradient ]}
colors={[ start={{x: 0, y: 0}}
gradients.blueLight.start, end={{x: 1, y: 1}}
gradients.blueLight.end, style={styles.postBtn}>
]} <Text style={[s.white, s.f16, s.bold]}>
start={{x: 0, y: 0}} {replyTo ? (
end={{x: 1, y: 1}} <Trans context="action">Reply</Trans>
style={styles.postBtn}> ) : (
<Text style={[s.white, s.f16, s.bold]}> <Trans context="action">Post</Trans>
{replyTo ? ( )}
<Trans context="action">Reply</Trans>
) : (
<Trans context="action">Post</Trans>
)}
</Text>
</LinearGradient>
</TouchableOpacity>
) : (
<View style={[styles.postBtn, pal.btn]}>
<Text style={[pal.textLight, s.f16, s.bold]}>
<Trans context="action">Post</Trans>
</Text> </Text>
</View> </LinearGradient>
)} </TouchableOpacity>
</> ) : (
<View style={[styles.postBtn, pal.btn]}>
<Text style={[pal.textLight, s.f16, s.bold]}>
<Trans context="action">Post</Trans>
</Text>
</View>
)}
</>
)}
</View>
{isAltTextRequiredAndMissing && (
<View style={[styles.reminderLine, pal.viewLight]}>
<View style={styles.errorIcon}>
<FontAwesomeIcon
icon="exclamation"
style={{color: colors.red4}}
size={10}
/>
</View>
<Text style={[pal.text, a.flex_1]}>
<Trans>One or more images is missing alt text.</Trans>
</Text>
</View>
)}
{error !== '' && (
<View style={styles.errorLine}>
<View style={styles.errorIcon}>
<FontAwesomeIcon
icon="exclamation"
style={{color: colors.red4}}
size={10}
/>
</View>
<Text style={[s.red4, a.flex_1]}>{error}</Text>
</View>
)}
</Animated.View>
<Animated.ScrollView
onScroll={scrollHandler}
style={styles.scrollView}
keyboardShouldPersistTaps="always"
onContentSizeChange={onScrollViewContentSizeChange}
onLayout={onScrollViewLayout}>
{replyTo ? <ComposerReplyTo replyTo={replyTo} /> : undefined}
<View
style={[
styles.textInputLayout,
isNative && styles.textInputLayoutMobile,
]}>
<UserAvatar
avatar={currentProfile?.avatar}
size={50}
type={currentProfile?.associated?.labeler ? 'labeler' : 'user'}
/>
<TextInput
ref={textInput}
richtext={richtext}
placeholder={selectTextInputPlaceholder}
autoFocus
setRichText={setRichText}
onPhotoPasted={onPhotoPasted}
onPressPublish={onPressPublish}
onNewLink={onNewLink}
onError={setError}
accessible={true}
accessibilityLabel={_(msg`Write post`)}
accessibilityHint={_(
msg`Compose posts up to ${MAX_GRAPHEME_LENGTH} characters in length`,
)}
/>
</View>
<Gallery gallery={gallery} />
{gallery.isEmpty && extLink && (
<View style={a.relative}>
<ExternalEmbed
link={extLink}
gif={extGif}
onRemove={() => {
setExtLink(undefined)
setExtGif(undefined)
}}
/>
<GifAltText
link={extLink}
gif={extGif}
onSubmit={handleChangeGifAltText}
/>
</View>
)}
{quote ? (
<View style={[s.mt5, s.mb2, isWeb && s.mb10]}>
<View style={{pointerEvents: 'none'}}>
<QuoteEmbed quote={quote} />
</View>
{quote.uri !== initQuote?.uri && (
<QuoteX onRemove={() => setQuote(undefined)} />
)} )}
</View> </View>
) : undefined}
</Animated.ScrollView>
<SuggestedLanguage text={richtext.text} />
{isAltTextRequiredAndMissing && (
<View style={[styles.reminderLine, pal.viewLight]}>
<View style={styles.errorIcon}>
<FontAwesomeIcon
icon="exclamation"
style={{color: colors.red4}}
size={10}
/>
</View>
<Text style={[pal.text, a.flex_1]}>
<Trans>One or more images is missing alt text.</Trans>
</Text>
</View>
)}
{error !== '' && (
<View style={styles.errorLine}>
<View style={styles.errorIcon}>
<FontAwesomeIcon
icon="exclamation"
style={{color: colors.red4}}
size={10}
/>
</View>
<Text style={[s.red4, a.flex_1]}>{error}</Text>
</View>
)}
</Animated.View>
<Animated.ScrollView
onScroll={scrollHandler}
style={styles.scrollView}
keyboardShouldPersistTaps="always"
onContentSizeChange={onScrollViewContentSizeChange}
onLayout={onScrollViewLayout}>
{replyTo ? <ComposerReplyTo replyTo={replyTo} /> : undefined}
<View
style={[
styles.textInputLayout,
isNative && styles.textInputLayoutMobile,
]}>
<UserAvatar
avatar={currentProfile?.avatar}
size={50}
type={currentProfile?.associated?.labeler ? 'labeler' : 'user'}
/>
<TextInput
ref={textInput}
richtext={richtext}
placeholder={selectTextInputPlaceholder}
autoFocus
setRichText={setRichText}
onPhotoPasted={onPhotoPasted}
onPressPublish={onPressPublish}
onNewLink={onNewLink}
onError={setError}
accessible={true}
accessibilityLabel={_(msg`Write post`)}
accessibilityHint={_(
msg`Compose posts up to ${MAX_GRAPHEME_LENGTH} characters in length`,
)}
/>
</View>
<Gallery gallery={gallery} />
{gallery.isEmpty && extLink && (
<View style={a.relative}>
<ExternalEmbed
link={extLink}
gif={extGif}
onRemove={() => {
setExtLink(undefined)
setExtGif(undefined)
}}
/>
<GifAltText
link={extLink}
gif={extGif}
onSubmit={handleChangeGifAltText}
/>
</View>
)}
{quote ? (
<View style={[s.mt5, isWeb && s.mb10]}>
<View style={{pointerEvents: 'none'}}>
<QuoteEmbed quote={quote} />
</View>
{quote.uri !== initQuote?.uri && (
<QuoteX onRemove={() => setQuote(undefined)} />
)}
</View>
) : undefined}
</Animated.ScrollView>
<SuggestedLanguage text={richtext.text} />
</View>
</KeyboardAvoidingView>
<KeyboardStickyView
offset={{closed: isIOS ? -insets.bottom : 0, opened: 0}}>
{replyTo ? null : ( {replyTo ? null : (
<ThreadgateBtn <ThreadgateBtn
threadgate={threadgate} threadgate={threadgate}
@ -644,7 +623,7 @@ export const ComposePost = observer(function ComposePost({
<SelectLangBtn /> <SelectLangBtn />
<CharProgress count={graphemeLength} /> <CharProgress count={graphemeLength} />
</View> </View>
</KeyboardStickyView> </View>
<Prompt.Basic <Prompt.Basic
control={discardPromptControl} control={discardPromptControl}
title={_(msg`Discard draft?`)} title={_(msg`Discard draft?`)}
@ -653,7 +632,7 @@ export const ComposePost = observer(function ComposePost({
confirmButtonCta={_(msg`Discard`)} confirmButtonCta={_(msg`Discard`)}
confirmButtonColor="negative" confirmButtonColor="negative"
/> />
</> </KeyboardAvoidingView>
) )
}) })

View File

@ -20,7 +20,6 @@ import * as Dialog from '#/components/Dialog'
import * as TextField from '#/components/forms/TextField' import * as TextField from '#/components/forms/TextField'
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
import {PlusSmall_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' import {PlusSmall_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {KeyboardPadding} from '#/components/KeyboardPadding'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {GifEmbed} from '../util/post-embeds/GifEmbed' import {GifEmbed} from '../util/post-embeds/GifEmbed'
import {AltTextReminder} from './photos/Gallery' import {AltTextReminder} from './photos/Gallery'
@ -181,7 +180,6 @@ function AltTextInner({
</View> </View>
</View> </View>
<Dialog.Close /> <Dialog.Close />
<KeyboardPadding />
</Dialog.ScrollableInner> </Dialog.ScrollableInner>
) )
} }

View File

@ -22,7 +22,6 @@ import {Text} from '#/view/com/util/text/Text'
import * as Toast from '#/view/com/util/Toast' import * as Toast from '#/view/com/util/Toast'
import {atoms as a} from '#/alf' import {atoms as a} from '#/alf'
import * as Toggle from '#/components/forms/Toggle' import * as Toggle from '#/components/forms/Toggle'
import {KeyboardPadding} from '#/components/KeyboardPadding'
export const snapPoints = ['90%'] export const snapPoints = ['90%']
@ -246,7 +245,6 @@ export function Component({}: {}) {
onPress={!appPassword ? createAppPassword : onDone} onPress={!appPassword ? createAppPassword : onDone}
/> />
</View> </View>
<KeyboardPadding />
</View> </View>
) )
} }

View File

@ -6,7 +6,6 @@ import BottomSheet from '@discord/bottom-sheet/src'
import {useModalControls, useModals} from '#/state/modals' import {useModalControls, useModals} from '#/state/modals'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {FullWindowOverlay} from '#/components/FullWindowOverlay' import {FullWindowOverlay} from '#/components/FullWindowOverlay'
import {KeyboardPadding} from '#/components/KeyboardPadding'
import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop' import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop'
import * as AddAppPassword from './AddAppPasswords' import * as AddAppPassword from './AddAppPasswords'
import * as AltImageModal from './AltImage' import * as AltImageModal from './AltImage'
@ -147,7 +146,6 @@ export function ModalsContainer() {
handleStyle={[styles.handle, pal.view]} handleStyle={[styles.handle, pal.view]}
onChange={onBottomSheetChange}> onChange={onBottomSheetChange}>
{element} {element}
<KeyboardPadding />
</BottomSheet> </BottomSheet>
</Container> </Container>
) )