use contentInset
This commit is contained in:
@@ -26,7 +26,7 @@ import {
|
|||||||
} from '#/state/messages/message-drafts'
|
} from '#/state/messages/message-drafts'
|
||||||
import {type EmojiPickerPosition} from '#/view/com/composer/text-input/web/EmojiPicker'
|
import {type EmojiPickerPosition} from '#/view/com/composer/text-input/web/EmojiPicker'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
import {android, atoms as a, useTheme} from '#/alf'
|
import {android, atoms as a, useTheme, web} from '#/alf'
|
||||||
import {useSharedInputStyles} from '#/components/forms/TextField'
|
import {useSharedInputStyles} from '#/components/forms/TextField'
|
||||||
import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlane} from '#/components/icons/PaperPlane'
|
import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlane} from '#/components/icons/PaperPlane'
|
||||||
import {useExtractEmbedFromFacets} from './MessageInputEmbed'
|
import {useExtractEmbedFromFacets} from './MessageInputEmbed'
|
||||||
@@ -132,7 +132,7 @@ export function MessageInput({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[a.px_md, a.pb_sm, a.pt_xs]}>
|
<View style={[a.px_md, a.pb_sm, web([a.pt_xs])]}>
|
||||||
{children}
|
{children}
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import {useKeyboardHandler} from 'react-native-keyboard-controller'
|
|||||||
import Animated, {
|
import Animated, {
|
||||||
runOnJS,
|
runOnJS,
|
||||||
scrollTo,
|
scrollTo,
|
||||||
|
useAnimatedProps,
|
||||||
useAnimatedRef,
|
useAnimatedRef,
|
||||||
useAnimatedStyle,
|
useAnimatedStyle,
|
||||||
useSharedValue,
|
useSharedValue,
|
||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
import {type ReanimatedScrollEvent} from 'react-native-reanimated/lib/typescript/hook/commonTypes'
|
import {type ReanimatedScrollEvent} from 'react-native-reanimated/lib/typescript/hook/commonTypes'
|
||||||
|
import {LinearGradient} from 'expo-linear-gradient'
|
||||||
import {
|
import {
|
||||||
type $Typed,
|
type $Typed,
|
||||||
type AppBskyEmbedRecord,
|
type AppBskyEmbedRecord,
|
||||||
@@ -24,7 +26,7 @@ import {
|
|||||||
isBskyPostUrl,
|
isBskyPostUrl,
|
||||||
} from '#/lib/strings/url-helpers'
|
} from '#/lib/strings/url-helpers'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {isNative} from '#/platform/detection'
|
import {isIOS, isNative} from '#/platform/detection'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isWeb} from '#/platform/detection'
|
||||||
import {
|
import {
|
||||||
type ActiveConvoStates,
|
type ActiveConvoStates,
|
||||||
@@ -43,10 +45,12 @@ import {
|
|||||||
EmojiPicker,
|
EmojiPicker,
|
||||||
type EmojiPickerState,
|
type EmojiPickerState,
|
||||||
} from '#/view/com/composer/text-input/web/EmojiPicker'
|
} from '#/view/com/composer/text-input/web/EmojiPicker'
|
||||||
import {List, type ListMethods} from '#/view/com/util/List'
|
import {List, type ListMethods, type ListProps} from '#/view/com/util/List'
|
||||||
import {ChatDisabled} from '#/screens/Messages/components/ChatDisabled'
|
import {ChatDisabled} from '#/screens/Messages/components/ChatDisabled'
|
||||||
import {MessageInput} from '#/screens/Messages/components/MessageInput'
|
import {MessageInput} from '#/screens/Messages/components/MessageInput'
|
||||||
import {MessageListError} from '#/screens/Messages/components/MessageListError'
|
import {MessageListError} from '#/screens/Messages/components/MessageListError'
|
||||||
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import {transparentifyColor} from '#/alf/util/colorGeneration'
|
||||||
import {ChatEmptyPill} from '#/components/dms/ChatEmptyPill'
|
import {ChatEmptyPill} from '#/components/dms/ChatEmptyPill'
|
||||||
import {MessageItem} from '#/components/dms/MessageItem'
|
import {MessageItem} from '#/components/dms/MessageItem'
|
||||||
import {NewMessagesPill} from '#/components/dms/NewMessagesPill'
|
import {NewMessagesPill} from '#/components/dms/NewMessagesPill'
|
||||||
@@ -102,6 +106,7 @@ export function MessagesList({
|
|||||||
footer?: React.ReactNode
|
footer?: React.ReactNode
|
||||||
hasAcceptOverride?: boolean
|
hasAcceptOverride?: boolean
|
||||||
}) {
|
}) {
|
||||||
|
const t = useTheme()
|
||||||
const convoState = useConvoActive()
|
const convoState = useConvoActive()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const getPost = useGetPost()
|
const getPost = useGetPost()
|
||||||
@@ -134,6 +139,9 @@ export function MessagesList({
|
|||||||
const prevContentHeight = useRef(0)
|
const prevContentHeight = useRef(0)
|
||||||
const prevItemCount = useRef(0)
|
const prevItemCount = useRef(0)
|
||||||
|
|
||||||
|
// Keep track of the message input height
|
||||||
|
const messageInputHeight = useSharedValue(52)
|
||||||
|
|
||||||
// -- Keep track of background state and positioning for new pill
|
// -- Keep track of background state and positioning for new pill
|
||||||
const layoutHeight = useSharedValue(0)
|
const layoutHeight = useSharedValue(0)
|
||||||
const didBackground = useRef(false)
|
const didBackground = useRef(false)
|
||||||
@@ -294,10 +302,41 @@ export function MessagesList({
|
|||||||
},
|
},
|
||||||
[footerHeight],
|
[footerHeight],
|
||||||
)
|
)
|
||||||
|
const animatedListStyle = useAnimatedStyle(() => {
|
||||||
|
if (!isIOS) {
|
||||||
|
return {
|
||||||
|
marginBottom: Math.max(
|
||||||
|
keyboardHeight.get(),
|
||||||
|
footerHeight + messageInputHeight.get(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
})
|
||||||
|
|
||||||
const animatedListStyle = useAnimatedStyle(() => ({
|
const animatedProps: Partial<ListProps> = useAnimatedProps(() => {
|
||||||
marginBottom: Math.max(keyboardHeight.get(), footerHeight),
|
if (isIOS) {
|
||||||
}))
|
return {
|
||||||
|
scrollIndicatorInsets: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 1,
|
||||||
|
bottom:
|
||||||
|
Math.max(keyboardHeight.get(), footerHeight) +
|
||||||
|
messageInputHeight.get(),
|
||||||
|
},
|
||||||
|
contentInset: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom:
|
||||||
|
Math.max(keyboardHeight.get(), footerHeight) +
|
||||||
|
messageInputHeight.get(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
})
|
||||||
|
|
||||||
const animatedStickyViewStyle = useAnimatedStyle(() => ({
|
const animatedStickyViewStyle = useAnimatedStyle(() => ({
|
||||||
transform: [{translateY: -Math.max(keyboardHeight.get(), footerHeight)}],
|
transform: [{translateY: -Math.max(keyboardHeight.get(), footerHeight)}],
|
||||||
@@ -431,9 +470,7 @@ export function MessagesList({
|
|||||||
maxToRenderPerBatch={isWeb ? 32 : 62}
|
maxToRenderPerBatch={isWeb ? 32 : 62}
|
||||||
keyboardDismissMode="on-drag"
|
keyboardDismissMode="on-drag"
|
||||||
keyboardShouldPersistTaps="handled"
|
keyboardShouldPersistTaps="handled"
|
||||||
maintainVisibleContentPosition={{
|
maintainVisibleContentPosition={{minIndexForVisible: 0}}
|
||||||
minIndexForVisible: 0,
|
|
||||||
}}
|
|
||||||
removeClippedSubviews={false}
|
removeClippedSubviews={false}
|
||||||
sideBorders={false}
|
sideBorders={false}
|
||||||
onContentSizeChange={onContentSizeChange}
|
onContentSizeChange={onContentSizeChange}
|
||||||
@@ -444,28 +481,52 @@ export function MessagesList({
|
|||||||
ListHeaderComponent={
|
ListHeaderComponent={
|
||||||
<MaybeLoader isLoading={convoState.isFetchingHistory} />
|
<MaybeLoader isLoading={convoState.isFetchingHistory} />
|
||||||
}
|
}
|
||||||
contentInset={{bottom: 0}}
|
animatedProps={animatedProps}
|
||||||
contentContainerStyle={{paddingBottom: 0}}
|
automaticallyAdjustKeyboardInsets={false}
|
||||||
scrollIndicatorInsets={{bottom: 0}}
|
automaticallyAdjustContentInsets={false}
|
||||||
/>
|
/>
|
||||||
</ScrollProvider>
|
</ScrollProvider>
|
||||||
<Animated.View style={animatedStickyViewStyle}>
|
<Animated.View
|
||||||
|
style={[
|
||||||
|
a.absolute,
|
||||||
|
{bottom: 0, left: 0, right: 0},
|
||||||
|
animatedStickyViewStyle,
|
||||||
|
]}>
|
||||||
|
<LinearGradient
|
||||||
|
key={t.name} // android does not update when you change the colors. sigh.
|
||||||
|
start={[0.5, 0]}
|
||||||
|
end={[0.5, 1]}
|
||||||
|
colors={[
|
||||||
|
transparentifyColor(t.atoms.bg.backgroundColor, 0),
|
||||||
|
t.atoms.bg.backgroundColor,
|
||||||
|
]}
|
||||||
|
locations={[0.15, 0.4]}
|
||||||
|
style={[a.absolute, a.inset_0]}
|
||||||
|
/>
|
||||||
{convoState.status === ConvoStatus.Disabled ? (
|
{convoState.status === ConvoStatus.Disabled ? (
|
||||||
<ChatDisabled />
|
<ChatDisabled />
|
||||||
) : blocked ? (
|
) : blocked ? (
|
||||||
footer
|
footer
|
||||||
) : (
|
) : (
|
||||||
<ConversationFooter
|
<View
|
||||||
convoState={convoState}
|
onLayout={evt => {
|
||||||
hasAcceptOverride={hasAcceptOverride}>
|
const height = evt.nativeEvent.layout.height
|
||||||
<MessageInput
|
if (height) {
|
||||||
onSendMessage={onSendMessage}
|
messageInputHeight.set(height)
|
||||||
hasEmbed={!!embedUri}
|
}
|
||||||
setEmbed={setEmbed}
|
}}>
|
||||||
openEmojiPicker={onOpenEmojiPicker}>
|
<ConversationFooter
|
||||||
<MessageInputEmbed embedUri={embedUri} setEmbed={setEmbed} />
|
convoState={convoState}
|
||||||
</MessageInput>
|
hasAcceptOverride={hasAcceptOverride}>
|
||||||
</ConversationFooter>
|
<MessageInput
|
||||||
|
onSendMessage={onSendMessage}
|
||||||
|
hasEmbed={!!embedUri}
|
||||||
|
setEmbed={setEmbed}
|
||||||
|
openEmojiPicker={onOpenEmojiPicker}>
|
||||||
|
<MessageInputEmbed embedUri={embedUri} setEmbed={setEmbed} />
|
||||||
|
</MessageInput>
|
||||||
|
</ConversationFooter>
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user