@planningcenter/chat-react-native 4.4.0-rc.0 → 4.4.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/conversation/message.d.ts +3 -1
- package/build/components/conversation/message.d.ts.map +1 -1
- package/build/components/conversation/message.js +183 -158
- package/build/components/conversation/message.js.map +1 -1
- package/build/components/conversation/message_list.d.ts.map +1 -1
- package/build/components/conversation/message_list.js +143 -88
- package/build/components/conversation/message_list.js.map +1 -1
- package/build/hooks/use_animated_message_background_color.d.ts +1 -0
- package/build/hooks/use_animated_message_background_color.d.ts.map +1 -1
- package/build/hooks/use_animated_message_background_color.js +26 -9
- package/build/hooks/use_animated_message_background_color.js.map +1 -1
- package/package.json +2 -2
- package/src/components/conversation/__tests__/message_list.test.tsx +71 -3
- package/src/components/conversation/message.tsx +12 -1
- package/src/components/conversation/message_list.tsx +26 -1
- package/src/hooks/use_animated_message_background_color.ts +37 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message_list.js","names":["date","formatDate","noop","React","useRef","FlatList","StyleSheet","View","useTheme","getRelativeDateStatus","groupMessages","CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL","isSystemMessage","Text","ConversationStartBanner","Message","MissingMessage","ReplyShadowMessage","SystemMessage","jsx","_jsx","jsxs","_jsxs","HOLD_AND_FOLLOW","minIndexForVisible","autoscrollToTopThreshold","HOLD_ONLY","ANCHOR_CLEARS_JUMP_BUTTON","MessageList","t0","$","_c","listRef","conversation","conversationId","messages","replyRootId","anchorMessageId","behind","t1","hasNextPage","onEndReached","onStartReached","onScroll","onLayout","onContentSizeChange","onScrollBeginDrag","onScrollEndDrag","onMomentumScrollEnd","undefined","styles","useStyles","inReplyScreen","canDeleteNonAuthoredMessages","memberAbility","latestRead","latestReadMessageSortKey","messagesWithSeparators","t2","ms","findIndex","item","id","anchorIndex","layoutHeight","contentHeight","userHasScrolled","draggedSinceStartReached","t3","anchorIsLoaded","current","scrollable","scrollToIndex","index","viewPosition","viewOffset","animated","pinAnchorToBottomEdge","t4","event","nativeEvent","layout","height","handleLayout","t5","width","handleContentSizeChange","t6","event_0","handleScrollBeginDrag","t7","handleStartReached","t8","t9","hasMessages","t10","t11","item_1","type","InlineDateSeparator","deletedAt","readByOthers","mine","listHeader","style","t12","listContainer","inverted","contentContainerStyle","keyExtractor","_temp","scrollEventThrottle","maintainVisibleContentPosition","ListFooterComponent","renderItem","ListHeaderComponent","item_0","useDateSeparatorStyles","isThisYear","showYear","year","dateStamp","separator","dateText","variant","children","container","theme","colors","borderColorDefaultBase","create","alignItems","flexDirection","paddingHorizontal","paddingVertical","flex","borderTopWidth","borderTopColor"],"sources":["../../../src/components/conversation/message_list.tsx"],"sourcesContent":["import { date as formatDate } from '@planningcenter/datetime-fmt'\nimport { noop } from 'lodash'\nimport React, { RefObject, useRef } from 'react'\nimport { FlatList, FlatListProps, StyleSheet, View } from 'react-native'\nimport { useTheme } from '../../hooks'\nimport { ConversationResource } from '../../types/resources/conversation'\nimport { MessageResource } from '../../types/resources/message'\nimport { getRelativeDateStatus } from '../../utils/date'\nimport { groupMessages, type DateSeparator, type EnrichedMessage } from '../../utils/group_messages'\nimport { CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL } from '../../utils/styles'\nimport { isSystemMessage } from '../../utils/system_messages'\nimport { Text } from '../display'\nimport { ConversationStartBanner } from './conversation_start_banner'\nimport { Message } from './message'\nimport { MissingMessage } from './missing_message'\nimport { ReplyShadowMessage } from './reply_shadow_message'\nimport { SystemMessage } from './system_message'\n\n// While behind, the bottom of the window isn't the live edge. Following there pulls\n// each newly paged-in page into view and chains the next fetch.\nconst HOLD_AND_FOLLOW = { minIndexForVisible: 0, autoscrollToTopThreshold: 100 }\nconst HOLD_ONLY = { minIndexForVisible: 0 }\n\ntype ScrollHandlers = Pick<\n FlatListProps<EnrichedMessage>,\n | 'onScroll'\n | 'onLayout'\n | 'onContentSizeChange'\n | 'onScrollBeginDrag'\n | 'onScrollEndDrag'\n | 'onMomentumScrollEnd'\n>\n\ninterface MessageListProps extends ScrollHandlers {\n listRef: RefObject<FlatList | null>\n conversation: ConversationResource\n conversationId: number\n messages: MessageResource[]\n replyRootId?: string | null\n anchorMessageId?: string | null\n behind?: boolean\n hasNextPage: boolean\n onEndReached: () => void\n onStartReached?: () => void\n}\n\nconst ANCHOR_CLEARS_JUMP_BUTTON = 56\n\n/** MessageList\n * The inverted list of messages, reply previews, and date separators for a conversation\n */\nexport function MessageList({\n listRef,\n conversation,\n conversationId,\n messages,\n replyRootId,\n anchorMessageId,\n behind = false,\n hasNextPage,\n onEndReached,\n onStartReached,\n onScroll,\n onLayout,\n onContentSizeChange,\n onScrollBeginDrag,\n onScrollEndDrag,\n onMomentumScrollEnd,\n}: MessageListProps) {\n const styles = useStyles()\n const inReplyScreen = !!replyRootId\n const canDeleteNonAuthoredMessages =\n conversation.memberAbility?.canDeleteNonAuthoredMessages ?? false\n const latestRead = conversation.latestReadMessageSortKey\n const messagesWithSeparators = groupMessages({ ms: messages, inReplyScreen })\n const anchorIndex = anchorMessageId\n ? messagesWithSeparators.findIndex(item => item.id === anchorMessageId)\n : -1\n const layoutHeight = useRef(0)\n const contentHeight = useRef(0)\n const userHasScrolled = useRef(false)\n const draggedSinceStartReached = useRef(false)\n\n // Row heights keep settling after the first layout (images, attachments), so we\n // re-pin on every layout pass until the reader takes over with a drag.\n const pinAnchorToBottomEdge = () => {\n const anchorIsLoaded = anchorIndex >= 0\n if (!anchorIsLoaded || userHasScrolled.current) return\n\n const scrollable = layoutHeight.current > 0 && contentHeight.current > layoutHeight.current\n if (!scrollable) return\n\n listRef.current?.scrollToIndex({\n index: anchorIndex,\n viewPosition: 0,\n viewOffset: ANCHOR_CLEARS_JUMP_BUTTON,\n animated: false,\n })\n }\n\n const handleLayout: FlatListProps<EnrichedMessage>['onLayout'] = event => {\n onLayout?.(event)\n layoutHeight.current = event.nativeEvent.layout.height\n pinAnchorToBottomEdge()\n }\n\n const handleContentSizeChange: FlatListProps<EnrichedMessage>['onContentSizeChange'] = (\n width,\n height\n ) => {\n onContentSizeChange?.(width, height)\n contentHeight.current = height\n pinAnchorToBottomEdge()\n }\n\n const handleScrollBeginDrag: FlatListProps<EnrichedMessage>['onScrollBeginDrag'] = event => {\n userHasScrolled.current = true\n draggedSinceStartReached.current = true\n onScrollBeginDrag?.(event)\n }\n\n // VirtualizedList re-checks its edges on every content size change using a JS offset\n // the native hold never updates, so without this each merged page re-fires it.\n const handleStartReached = () => {\n if (!draggedSinceStartReached.current) return\n\n draggedSinceStartReached.current = false\n onStartReached?.()\n }\n\n return (\n <FlatList\n inverted\n ref={listRef}\n contentContainerStyle={styles.listContainer}\n data={messagesWithSeparators}\n keyExtractor={item => item.id}\n onScroll={onScroll}\n onLayout={handleLayout}\n onContentSizeChange={handleContentSizeChange}\n onScrollBeginDrag={handleScrollBeginDrag}\n // Expected while rows are still measuring; the next layout pass pins again.\n onScrollToIndexFailed={noop}\n onScrollEndDrag={onScrollEndDrag}\n onMomentumScrollEnd={onMomentumScrollEnd}\n scrollEventThrottle={10}\n maintainVisibleContentPosition={behind ? HOLD_ONLY : HOLD_AND_FOLLOW}\n ListFooterComponent={\n hasNextPage ? null : (\n <ConversationStartBanner conversation={conversation} hasMessages={true} />\n )\n }\n renderItem={({ item }) => {\n if (item.type === 'DateSeparator') {\n return <InlineDateSeparator {...item} />\n }\n\n if (item.type === 'Message' && item.deletedAt && !item.replyRootId) {\n return <MissingMessage />\n }\n\n if (item.type === 'ReplyShadowMessage') {\n return (\n <ReplyShadowMessage\n {...(item as any)}\n conversation_id={conversationId}\n inReplyScreen={inReplyScreen}\n />\n )\n }\n\n if (isSystemMessage(item)) {\n return <SystemMessage message={item} conversationId={conversationId} />\n }\n\n const readByOthers = item.mine && !!latestRead && item.id <= latestRead\n return (\n <Message\n {...item}\n canDeleteNonAuthoredMessages={canDeleteNonAuthoredMessages}\n conversation_id={conversationId}\n readByOthers={readByOthers}\n inReplyScreen={inReplyScreen}\n />\n )\n }}\n onEndReached={onEndReached}\n onStartReached={handleStartReached}\n ListHeaderComponent={<View style={styles.listHeader} />}\n />\n )\n}\n\nfunction InlineDateSeparator({ date }: DateSeparator) {\n const styles = useDateSeparatorStyles()\n const { isThisYear } = getRelativeDateStatus(date)\n const showYear = !isThisYear\n const dateStamp = formatDate(date, { style: 'long', year: showYear })\n\n return (\n <View style={styles.container}>\n <View style={styles.separator} />\n <Text variant=\"footnote\" style={styles.dateText}>\n {dateStamp}\n </Text>\n <View style={styles.separator} />\n </View>\n )\n}\n\nconst useDateSeparatorStyles = () => {\n const theme = useTheme()\n return StyleSheet.create({\n container: {\n alignItems: 'center',\n flexDirection: 'row',\n paddingHorizontal: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n paddingVertical: 16,\n },\n separator: {\n flex: 1,\n height: 1,\n borderTopWidth: 1,\n borderTopColor: theme.colors.borderColorDefaultBase,\n },\n dateText: {\n paddingHorizontal: 8,\n },\n })\n}\n\nconst useStyles = () =>\n StyleSheet.create({\n listContainer: {\n paddingVertical: 12,\n },\n listHeader: {\n // Just whitespace to provide space where the typing indicator can be\n height: 16,\n },\n })\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"message_list.js","names":["date","formatDate","noop","React","useCallback","useEffect","useRef","useState","FlatList","StyleSheet","View","useTheme","getRelativeDateStatus","groupMessages","CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL","isSystemMessage","Text","ConversationStartBanner","Message","MissingMessage","ReplyShadowMessage","SystemMessage","jsx","_jsx","jsxs","_jsxs","HOLD_AND_FOLLOW","minIndexForVisible","autoscrollToTopThreshold","HOLD_ONLY","ANCHOR_CLEARS_JUMP_BUTTON","ANCHOR_VIEWABILITY","itemVisiblePercentThreshold","MessageList","t0","$","_c","listRef","conversation","conversationId","messages","replyRootId","anchorMessageId","behind","t1","hasNextPage","onEndReached","onStartReached","onScroll","onLayout","onContentSizeChange","onScrollBeginDrag","onScrollEndDrag","onMomentumScrollEnd","undefined","styles","useStyles","inReplyScreen","canDeleteNonAuthoredMessages","memberAbility","latestRead","latestReadMessageSortKey","messagesWithSeparators","t2","ms","findIndex","item","id","anchorIndex","layoutHeight","contentHeight","userHasScrolled","draggedSinceStartReached","latestAnchorMessageId","flashedAnchorId","highlightedMessageId","setHighlightedMessageId","t3","t4","current","t5","anchorIsLoaded","scrollable","scrollToIndex","index","viewPosition","viewOffset","animated","pinAnchorToBottomEdge","t6","event","nativeEvent","layout","height","handleLayout","t7","width","handleContentSizeChange","t8","event_0","handleScrollBeginDrag","t9","Symbol","for","t10","viewableItems","anchorId","some","token","flashAnchorOnceViewable","clearHighlight","t11","handleStartReached","t12","t13","hasMessages","t14","t15","item_1","type","InlineDateSeparator","deletedAt","readByOthers","mine","highlighted","listHeader","style","t16","listContainer","inverted","contentContainerStyle","keyExtractor","_temp","scrollEventThrottle","maintainVisibleContentPosition","ListFooterComponent","renderItem","ListHeaderComponent","item_0","useDateSeparatorStyles","isThisYear","showYear","year","dateStamp","separator","dateText","variant","children","container","theme","colors","borderColorDefaultBase","create","alignItems","flexDirection","paddingHorizontal","paddingVertical","flex","borderTopWidth","borderTopColor"],"sources":["../../../src/components/conversation/message_list.tsx"],"sourcesContent":["import { date as formatDate } from '@planningcenter/datetime-fmt'\nimport { noop } from 'lodash'\nimport React, { RefObject, useCallback, useEffect, useRef, useState } from 'react'\nimport { FlatList, FlatListProps, StyleSheet, View } from 'react-native'\nimport { useTheme } from '../../hooks'\nimport { ConversationResource } from '../../types/resources/conversation'\nimport { MessageResource } from '../../types/resources/message'\nimport { getRelativeDateStatus } from '../../utils/date'\nimport { groupMessages, type DateSeparator, type EnrichedMessage } from '../../utils/group_messages'\nimport { CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL } from '../../utils/styles'\nimport { isSystemMessage } from '../../utils/system_messages'\nimport { Text } from '../display'\nimport { ConversationStartBanner } from './conversation_start_banner'\nimport { Message } from './message'\nimport { MissingMessage } from './missing_message'\nimport { ReplyShadowMessage } from './reply_shadow_message'\nimport { SystemMessage } from './system_message'\n\n// While behind, the bottom of the window isn't the live edge. Following there pulls\n// each newly paged-in page into view and chains the next fetch.\nconst HOLD_AND_FOLLOW = { minIndexForVisible: 0, autoscrollToTopThreshold: 100 }\nconst HOLD_ONLY = { minIndexForVisible: 0 }\n\ntype ScrollHandlers = Pick<\n FlatListProps<EnrichedMessage>,\n | 'onScroll'\n | 'onLayout'\n | 'onContentSizeChange'\n | 'onScrollBeginDrag'\n | 'onScrollEndDrag'\n | 'onMomentumScrollEnd'\n>\n\ninterface MessageListProps extends ScrollHandlers {\n listRef: RefObject<FlatList | null>\n conversation: ConversationResource\n conversationId: number\n messages: MessageResource[]\n replyRootId?: string | null\n anchorMessageId?: string | null\n behind?: boolean\n hasNextPage: boolean\n onEndReached: () => void\n onStartReached?: () => void\n}\n\nconst ANCHOR_CLEARS_JUMP_BUTTON = 56\nconst ANCHOR_VIEWABILITY = { itemVisiblePercentThreshold: 50 }\n\n/** MessageList\n * The inverted list of messages, reply previews, and date separators for a conversation\n */\nexport function MessageList({\n listRef,\n conversation,\n conversationId,\n messages,\n replyRootId,\n anchorMessageId,\n behind = false,\n hasNextPage,\n onEndReached,\n onStartReached,\n onScroll,\n onLayout,\n onContentSizeChange,\n onScrollBeginDrag,\n onScrollEndDrag,\n onMomentumScrollEnd,\n}: MessageListProps) {\n const styles = useStyles()\n const inReplyScreen = !!replyRootId\n const canDeleteNonAuthoredMessages =\n conversation.memberAbility?.canDeleteNonAuthoredMessages ?? false\n const latestRead = conversation.latestReadMessageSortKey\n const messagesWithSeparators = groupMessages({ ms: messages, inReplyScreen })\n const anchorIndex = anchorMessageId\n ? messagesWithSeparators.findIndex(item => item.id === anchorMessageId)\n : -1\n const layoutHeight = useRef(0)\n const contentHeight = useRef(0)\n const userHasScrolled = useRef(false)\n const draggedSinceStartReached = useRef(false)\n const latestAnchorMessageId = useRef(anchorMessageId)\n const flashedAnchorId = useRef<string | null>(null)\n const [highlightedMessageId, setHighlightedMessageId] = useState<string | null>(null)\n\n useEffect(() => {\n latestAnchorMessageId.current = anchorMessageId\n }, [anchorMessageId])\n\n // Row heights keep settling after the first layout (images, attachments), so we\n // re-pin on every layout pass until the reader takes over with a drag.\n const pinAnchorToBottomEdge = () => {\n const anchorIsLoaded = anchorIndex >= 0\n if (!anchorIsLoaded || userHasScrolled.current) return\n\n const scrollable = layoutHeight.current > 0 && contentHeight.current > layoutHeight.current\n if (!scrollable) return\n\n listRef.current?.scrollToIndex({\n index: anchorIndex,\n viewPosition: 0,\n viewOffset: ANCHOR_CLEARS_JUMP_BUTTON,\n animated: false,\n })\n }\n\n const handleLayout: FlatListProps<EnrichedMessage>['onLayout'] = event => {\n onLayout?.(event)\n layoutHeight.current = event.nativeEvent.layout.height\n pinAnchorToBottomEdge()\n }\n\n const handleContentSizeChange: FlatListProps<EnrichedMessage>['onContentSizeChange'] = (\n width,\n height\n ) => {\n onContentSizeChange?.(width, height)\n contentHeight.current = height\n pinAnchorToBottomEdge()\n }\n\n const handleScrollBeginDrag: FlatListProps<EnrichedMessage>['onScrollBeginDrag'] = event => {\n userHasScrolled.current = true\n draggedSinceStartReached.current = true\n onScrollBeginDrag?.(event)\n }\n\n const flashAnchorOnceViewable: FlatListProps<EnrichedMessage>['onViewableItemsChanged'] = ({\n viewableItems,\n }) => {\n const anchorId = latestAnchorMessageId.current\n if (!anchorId || anchorId === flashedAnchorId.current) return\n if (!viewableItems.some(token => token.item.id === anchorId)) return\n\n flashedAnchorId.current = anchorId\n setHighlightedMessageId(anchorId)\n }\n\n const clearHighlight = useCallback(() => setHighlightedMessageId(null), [])\n\n // VirtualizedList re-checks its edges on every content size change using a JS offset\n // the native hold never updates, so without this each merged page re-fires it.\n const handleStartReached = () => {\n if (!draggedSinceStartReached.current) return\n\n draggedSinceStartReached.current = false\n onStartReached?.()\n }\n\n return (\n <FlatList\n inverted\n ref={listRef}\n contentContainerStyle={styles.listContainer}\n data={messagesWithSeparators}\n keyExtractor={item => item.id}\n onScroll={onScroll}\n onLayout={handleLayout}\n onContentSizeChange={handleContentSizeChange}\n onScrollBeginDrag={handleScrollBeginDrag}\n // Expected while rows are still measuring; the next layout pass pins again.\n onScrollToIndexFailed={noop}\n onScrollEndDrag={onScrollEndDrag}\n onMomentumScrollEnd={onMomentumScrollEnd}\n onViewableItemsChanged={flashAnchorOnceViewable}\n viewabilityConfig={ANCHOR_VIEWABILITY}\n scrollEventThrottle={10}\n maintainVisibleContentPosition={behind ? HOLD_ONLY : HOLD_AND_FOLLOW}\n ListFooterComponent={\n hasNextPage ? null : (\n <ConversationStartBanner conversation={conversation} hasMessages={true} />\n )\n }\n renderItem={({ item }) => {\n if (item.type === 'DateSeparator') {\n return <InlineDateSeparator {...item} />\n }\n\n if (item.type === 'Message' && item.deletedAt && !item.replyRootId) {\n return <MissingMessage />\n }\n\n if (item.type === 'ReplyShadowMessage') {\n return (\n <ReplyShadowMessage\n {...(item as any)}\n conversation_id={conversationId}\n inReplyScreen={inReplyScreen}\n />\n )\n }\n\n if (isSystemMessage(item)) {\n return <SystemMessage message={item} conversationId={conversationId} />\n }\n\n const readByOthers = item.mine && !!latestRead && item.id <= latestRead\n return (\n <Message\n {...item}\n canDeleteNonAuthoredMessages={canDeleteNonAuthoredMessages}\n conversation_id={conversationId}\n readByOthers={readByOthers}\n inReplyScreen={inReplyScreen}\n highlighted={item.id === highlightedMessageId}\n onHighlightShown={clearHighlight}\n />\n )\n }}\n onEndReached={onEndReached}\n onStartReached={handleStartReached}\n ListHeaderComponent={<View style={styles.listHeader} />}\n />\n )\n}\n\nfunction InlineDateSeparator({ date }: DateSeparator) {\n const styles = useDateSeparatorStyles()\n const { isThisYear } = getRelativeDateStatus(date)\n const showYear = !isThisYear\n const dateStamp = formatDate(date, { style: 'long', year: showYear })\n\n return (\n <View style={styles.container}>\n <View style={styles.separator} />\n <Text variant=\"footnote\" style={styles.dateText}>\n {dateStamp}\n </Text>\n <View style={styles.separator} />\n </View>\n )\n}\n\nconst useDateSeparatorStyles = () => {\n const theme = useTheme()\n return StyleSheet.create({\n container: {\n alignItems: 'center',\n flexDirection: 'row',\n paddingHorizontal: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n paddingVertical: 16,\n },\n separator: {\n flex: 1,\n height: 1,\n borderTopWidth: 1,\n borderTopColor: theme.colors.borderColorDefaultBase,\n },\n dateText: {\n paddingHorizontal: 8,\n },\n })\n}\n\nconst useStyles = () =>\n StyleSheet.create({\n listContainer: {\n paddingVertical: 12,\n },\n listHeader: {\n // Just whitespace to provide space where the typing indicator can be\n height: 16,\n },\n })\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -2,6 +2,7 @@ export declare function useAnimatedMessageBackgroundColor(): {
|
|
|
2
2
|
animatedBackgroundColor: import("react-native-reanimated/lib/typescript/hook/commonTypes").AnimatedStyleHandle<{
|
|
3
3
|
backgroundColor: string;
|
|
4
4
|
}>;
|
|
5
|
+
flash: () => void;
|
|
5
6
|
handleMessagePressIn: () => void;
|
|
6
7
|
handleMessagePressOut: () => void;
|
|
7
8
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use_animated_message_background_color.d.ts","sourceRoot":"","sources":["../../src/hooks/use_animated_message_background_color.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use_animated_message_background_color.d.ts","sourceRoot":"","sources":["../../src/hooks/use_animated_message_background_color.ts"],"names":[],"mappings":"AAkBA,wBAAgB,iCAAiC;;;;;;;EAkDhD"}
|
|
@@ -1,35 +1,52 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
1
2
|
import { Platform } from 'react-native';
|
|
2
|
-
import { useSharedValue, useAnimatedStyle, withTiming, interpolateColor, Easing } from 'react-native-reanimated';
|
|
3
|
+
import { useSharedValue, useAnimatedStyle, withDelay, withSequence, withTiming, interpolateColor, Easing, ReduceMotion } from 'react-native-reanimated';
|
|
3
4
|
import { useTheme } from './use_theme';
|
|
5
|
+
const FLASH_IN_MS = 150;
|
|
6
|
+
const FLASH_HOLD_MS = 500;
|
|
7
|
+
const FLASH_OUT_MS = 1500;
|
|
4
8
|
export function useAnimatedMessageBackgroundColor() {
|
|
5
9
|
const {
|
|
6
10
|
colors
|
|
7
11
|
} = useTheme();
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
});
|
|
12
|
+
const pressProgress = useSharedValue(0);
|
|
13
|
+
const flashProgress = useSharedValue(0);
|
|
14
|
+
const tintColor = colors.fillColorNeutral050Base;
|
|
15
|
+
const tintsOnPress = Platform.OS === 'ios';
|
|
13
16
|
const animatedBackgroundColor = useAnimatedStyle(() => {
|
|
14
|
-
const
|
|
17
|
+
const pressTint = tintsOnPress ? pressProgress.value : 0;
|
|
18
|
+
const progress = Math.max(pressTint, flashProgress.value);
|
|
19
|
+
const backgroundColor = interpolateColor(progress, [0, 1], ['transparent', tintColor]);
|
|
15
20
|
return {
|
|
16
21
|
backgroundColor
|
|
17
22
|
};
|
|
18
23
|
});
|
|
19
24
|
const handleMessagePressIn = () => {
|
|
20
|
-
|
|
25
|
+
pressProgress.value = withTiming(1, {
|
|
21
26
|
duration: 300,
|
|
22
27
|
easing: Easing.inOut(Easing.ease)
|
|
23
28
|
});
|
|
24
29
|
};
|
|
25
30
|
const handleMessagePressOut = () => {
|
|
26
|
-
|
|
31
|
+
pressProgress.value = withTiming(0, {
|
|
27
32
|
duration: 300,
|
|
28
33
|
easing: Easing.inOut(Easing.ease)
|
|
29
34
|
});
|
|
30
35
|
};
|
|
36
|
+
const flash = useCallback(() => {
|
|
37
|
+
flashProgress.value = withSequence(withTiming(1, {
|
|
38
|
+
duration: FLASH_IN_MS,
|
|
39
|
+
easing: Easing.out(Easing.ease),
|
|
40
|
+
reduceMotion: ReduceMotion.Never
|
|
41
|
+
}), withDelay(FLASH_HOLD_MS, withTiming(0, {
|
|
42
|
+
duration: FLASH_OUT_MS,
|
|
43
|
+
easing: Easing.out(Easing.ease),
|
|
44
|
+
reduceMotion: ReduceMotion.System
|
|
45
|
+
}), ReduceMotion.Never));
|
|
46
|
+
}, [flashProgress]);
|
|
31
47
|
return {
|
|
32
48
|
animatedBackgroundColor,
|
|
49
|
+
flash,
|
|
33
50
|
handleMessagePressIn,
|
|
34
51
|
handleMessagePressOut
|
|
35
52
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use_animated_message_background_color.js","names":["Platform","useSharedValue","useAnimatedStyle","withTiming","interpolateColor","Easing","useTheme","useAnimatedMessageBackgroundColor","colors","
|
|
1
|
+
{"version":3,"file":"use_animated_message_background_color.js","names":["useCallback","Platform","useSharedValue","useAnimatedStyle","withDelay","withSequence","withTiming","interpolateColor","Easing","ReduceMotion","useTheme","FLASH_IN_MS","FLASH_HOLD_MS","FLASH_OUT_MS","useAnimatedMessageBackgroundColor","colors","pressProgress","flashProgress","tintColor","fillColorNeutral050Base","tintsOnPress","OS","animatedBackgroundColor","pressTint","value","progress","Math","max","backgroundColor","handleMessagePressIn","duration","easing","inOut","ease","handleMessagePressOut","flash","out","reduceMotion","Never","System"],"sources":["../../src/hooks/use_animated_message_background_color.ts"],"sourcesContent":["import { useCallback } from 'react'\nimport { Platform } from 'react-native'\nimport {\n useSharedValue,\n useAnimatedStyle,\n withDelay,\n withSequence,\n withTiming,\n interpolateColor,\n Easing,\n ReduceMotion,\n} from 'react-native-reanimated'\nimport { useTheme } from './use_theme'\n\nconst FLASH_IN_MS = 150\nconst FLASH_HOLD_MS = 500\nconst FLASH_OUT_MS = 1500\n\nexport function useAnimatedMessageBackgroundColor() {\n const { colors } = useTheme()\n const pressProgress = useSharedValue(0)\n const flashProgress = useSharedValue(0)\n\n const tintColor = colors.fillColorNeutral050Base\n const tintsOnPress = Platform.OS === 'ios'\n\n const animatedBackgroundColor = useAnimatedStyle(() => {\n const pressTint = tintsOnPress ? pressProgress.value : 0\n const progress = Math.max(pressTint, flashProgress.value)\n const backgroundColor = interpolateColor(progress, [0, 1], ['transparent', tintColor])\n return {\n backgroundColor,\n }\n })\n\n const handleMessagePressIn = () => {\n pressProgress.value = withTiming(1, { duration: 300, easing: Easing.inOut(Easing.ease) })\n }\n\n const handleMessagePressOut = () => {\n pressProgress.value = withTiming(0, { duration: 300, easing: Easing.inOut(Easing.ease) })\n }\n\n const flash = useCallback(() => {\n flashProgress.value = withSequence(\n withTiming(1, {\n duration: FLASH_IN_MS,\n easing: Easing.out(Easing.ease),\n reduceMotion: ReduceMotion.Never,\n }),\n withDelay(\n FLASH_HOLD_MS,\n withTiming(0, {\n duration: FLASH_OUT_MS,\n easing: Easing.out(Easing.ease),\n reduceMotion: ReduceMotion.System,\n }),\n ReduceMotion.Never\n )\n )\n }, [flashProgress])\n\n return {\n animatedBackgroundColor,\n flash,\n handleMessagePressIn,\n handleMessagePressOut,\n }\n}\n"],"mappings":"AAAA,SAASA,WAAW,QAAQ,OAAO;AACnC,SAASC,QAAQ,QAAQ,cAAc;AACvC,SACEC,cAAc,EACdC,gBAAgB,EAChBC,SAAS,EACTC,YAAY,EACZC,UAAU,EACVC,gBAAgB,EAChBC,MAAM,EACNC,YAAY,QACP,yBAAyB;AAChC,SAASC,QAAQ,QAAQ,aAAa;AAEtC,MAAMC,WAAW,GAAG,GAAG;AACvB,MAAMC,aAAa,GAAG,GAAG;AACzB,MAAMC,YAAY,GAAG,IAAI;AAEzB,OAAO,SAASC,iCAAiCA,CAAA,EAAG;EAClD,MAAM;IAAEC;EAAO,CAAC,GAAGL,QAAQ,CAAC,CAAC;EAC7B,MAAMM,aAAa,GAAGd,cAAc,CAAC,CAAC,CAAC;EACvC,MAAMe,aAAa,GAAGf,cAAc,CAAC,CAAC,CAAC;EAEvC,MAAMgB,SAAS,GAAGH,MAAM,CAACI,uBAAuB;EAChD,MAAMC,YAAY,GAAGnB,QAAQ,CAACoB,EAAE,KAAK,KAAK;EAE1C,MAAMC,uBAAuB,GAAGnB,gBAAgB,CAAC,MAAM;IACrD,MAAMoB,SAAS,GAAGH,YAAY,GAAGJ,aAAa,CAACQ,KAAK,GAAG,CAAC;IACxD,MAAMC,QAAQ,GAAGC,IAAI,CAACC,GAAG,CAACJ,SAAS,EAAEN,aAAa,CAACO,KAAK,CAAC;IACzD,MAAMI,eAAe,GAAGrB,gBAAgB,CAACkB,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,aAAa,EAAEP,SAAS,CAAC,CAAC;IACtF,OAAO;MACLU;IACF,CAAC;EACH,CAAC,CAAC;EAEF,MAAMC,oBAAoB,GAAGA,CAAA,KAAM;IACjCb,aAAa,CAACQ,KAAK,GAAGlB,UAAU,CAAC,CAAC,EAAE;MAAEwB,QAAQ,EAAE,GAAG;MAAEC,MAAM,EAAEvB,MAAM,CAACwB,KAAK,CAACxB,MAAM,CAACyB,IAAI;IAAE,CAAC,CAAC;EAC3F,CAAC;EAED,MAAMC,qBAAqB,GAAGA,CAAA,KAAM;IAClClB,aAAa,CAACQ,KAAK,GAAGlB,UAAU,CAAC,CAAC,EAAE;MAAEwB,QAAQ,EAAE,GAAG;MAAEC,MAAM,EAAEvB,MAAM,CAACwB,KAAK,CAACxB,MAAM,CAACyB,IAAI;IAAE,CAAC,CAAC;EAC3F,CAAC;EAED,MAAME,KAAK,GAAGnC,WAAW,CAAC,MAAM;IAC9BiB,aAAa,CAACO,KAAK,GAAGnB,YAAY,CAChCC,UAAU,CAAC,CAAC,EAAE;MACZwB,QAAQ,EAAEnB,WAAW;MACrBoB,MAAM,EAAEvB,MAAM,CAAC4B,GAAG,CAAC5B,MAAM,CAACyB,IAAI,CAAC;MAC/BI,YAAY,EAAE5B,YAAY,CAAC6B;IAC7B,CAAC,CAAC,EACFlC,SAAS,CACPQ,aAAa,EACbN,UAAU,CAAC,CAAC,EAAE;MACZwB,QAAQ,EAAEjB,YAAY;MACtBkB,MAAM,EAAEvB,MAAM,CAAC4B,GAAG,CAAC5B,MAAM,CAACyB,IAAI,CAAC;MAC/BI,YAAY,EAAE5B,YAAY,CAAC8B;IAC7B,CAAC,CAAC,EACF9B,YAAY,CAAC6B,KACf,CACF,CAAC;EACH,CAAC,EAAE,CAACrB,aAAa,CAAC,CAAC;EAEnB,OAAO;IACLK,uBAAuB;IACvBa,KAAK;IACLN,oBAAoB;IACpBK;EACF,CAAC;AACH","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "4.4.0-rc.
|
|
3
|
+
"version": "4.4.0-rc.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"sf-symbols-typescript": "^2.2.0",
|
|
85
85
|
"typescript": "~6.0.3"
|
|
86
86
|
},
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "a40755076aae4b6a23343cc70d5d62108f98f3e9"
|
|
88
88
|
}
|
|
@@ -28,6 +28,15 @@ import { getMessagesQueryKey } from '../../../utils/request/get_messages'
|
|
|
28
28
|
import { MessageList } from '../message_list'
|
|
29
29
|
|
|
30
30
|
jest.mock('../../../hooks/use_api_client')
|
|
31
|
+
const mockFlash = jest.fn()
|
|
32
|
+
jest.mock('../../../hooks/use_animated_message_background_color', () => ({
|
|
33
|
+
useAnimatedMessageBackgroundColor: () => ({
|
|
34
|
+
animatedBackgroundColor: {},
|
|
35
|
+
flash: mockFlash,
|
|
36
|
+
handleMessagePressIn: jest.fn(),
|
|
37
|
+
handleMessagePressOut: jest.fn(),
|
|
38
|
+
}),
|
|
39
|
+
}))
|
|
31
40
|
jest.mock('@react-navigation/native', () => ({
|
|
32
41
|
...jest.requireActual('@react-navigation/native'),
|
|
33
42
|
useNavigation: () => ({ navigate: jest.fn() }),
|
|
@@ -105,7 +114,7 @@ let queryClient: QueryClient
|
|
|
105
114
|
// A top-level rerender would rebuild the wrapper context and redraw every row.
|
|
106
115
|
let setHarnessConversation: (next: ConversationResource) => void = () => {}
|
|
107
116
|
|
|
108
|
-
function Harness() {
|
|
117
|
+
function Harness({ anchorMessageId }: { anchorMessageId?: string }) {
|
|
109
118
|
const [current, setCurrent] = React.useState(conversation)
|
|
110
119
|
React.useEffect(() => {
|
|
111
120
|
setHarnessConversation = setCurrent
|
|
@@ -117,6 +126,7 @@ function Harness() {
|
|
|
117
126
|
conversation={current}
|
|
118
127
|
conversationId={CONVERSATION_ID}
|
|
119
128
|
messages={loaded}
|
|
129
|
+
anchorMessageId={anchorMessageId}
|
|
120
130
|
hasNextPage
|
|
121
131
|
onEndReached={() => {}}
|
|
122
132
|
/>
|
|
@@ -151,16 +161,24 @@ const renderedRowIds = () => {
|
|
|
151
161
|
return Array.from(new Set(ids)).sort()
|
|
152
162
|
}
|
|
153
163
|
|
|
154
|
-
const renderList = (seed: MessageResource[] = messages) => {
|
|
164
|
+
const renderList = (seed: MessageResource[] = messages, anchorMessageId?: string) => {
|
|
155
165
|
queryClient.setQueryData<MessagesQueryData>(messagesQueryKey, {
|
|
156
166
|
pages: [{ data: seed, links: {}, meta: { count: seed.length, totalCount: seed.length } }],
|
|
157
167
|
pageParams: [{}],
|
|
158
168
|
})
|
|
159
|
-
render(<Harness />, { wrapper: Wrapper })
|
|
169
|
+
render(<Harness anchorMessageId={anchorMessageId} />, { wrapper: Wrapper })
|
|
160
170
|
seed.forEach(m => screen.getByTestId(`message-${m.id}`))
|
|
161
171
|
renderSpy.mockClear()
|
|
162
172
|
}
|
|
163
173
|
|
|
174
|
+
const reportViewable = (items: MessageResource[]) =>
|
|
175
|
+
act(() =>
|
|
176
|
+
screen.UNSAFE_getByType(FlatList).props.onViewableItemsChanged({
|
|
177
|
+
viewableItems: items.map(item => ({ item, key: item.id, index: null, isViewable: true })),
|
|
178
|
+
changed: [],
|
|
179
|
+
})
|
|
180
|
+
)
|
|
181
|
+
|
|
164
182
|
// TanStack notifies observers on a setTimeout; deliver inline so one write is one act().
|
|
165
183
|
beforeAll(() => notifyManager.setScheduler(callback => callback()))
|
|
166
184
|
afterAll(() => notifyManager.setScheduler(callback => setTimeout(callback, 0)))
|
|
@@ -274,4 +292,54 @@ describe('MessageList', () => {
|
|
|
274
292
|
expect(screen.queryByTestId(`message-${target.id}`)).toBeNull()
|
|
275
293
|
expect(renderedRowIds()).toEqual([])
|
|
276
294
|
})
|
|
295
|
+
|
|
296
|
+
describe('opened at an anchor message', () => {
|
|
297
|
+
const anchor = messages[4]
|
|
298
|
+
|
|
299
|
+
it('flashes the anchor row once it comes into view, redrawing only that row', () => {
|
|
300
|
+
renderList(messages, anchor.id)
|
|
301
|
+
|
|
302
|
+
reportViewable([messages[1], messages[2]])
|
|
303
|
+
expect(mockFlash).not.toHaveBeenCalled()
|
|
304
|
+
expect(renderedRowIds()).toEqual([])
|
|
305
|
+
|
|
306
|
+
reportViewable([messages[3], anchor])
|
|
307
|
+
expect(mockFlash).toHaveBeenCalledTimes(1)
|
|
308
|
+
expect(renderedRowIds()).toEqual([anchor.id])
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
it('flashes only once, through later viewability changes, redraws, and a remount', () => {
|
|
312
|
+
renderList(messages, anchor.id)
|
|
313
|
+
reportViewable([anchor])
|
|
314
|
+
expect(mockFlash).toHaveBeenCalledTimes(1)
|
|
315
|
+
|
|
316
|
+
reportViewable([anchor, messages[5]])
|
|
317
|
+
act(() => updateCacheWithReaction(queryClient, messagesQueryKey, reactionEvent(anchor), ME))
|
|
318
|
+
expect(screen.getByTestId(`reaction-${anchor.id}-heart`)).toBeTruthy()
|
|
319
|
+
|
|
320
|
+
act(() =>
|
|
321
|
+
queryClient.setQueryData<MessagesQueryData>(messagesQueryKey, prev =>
|
|
322
|
+
deleteRecordInPagesData({ data: prev, record: anchor })
|
|
323
|
+
)
|
|
324
|
+
)
|
|
325
|
+
expect(screen.queryByTestId(`message-${anchor.id}`)).toBeNull()
|
|
326
|
+
act(() =>
|
|
327
|
+
queryClient.setQueryData<MessagesQueryData>(messagesQueryKey, prev =>
|
|
328
|
+
addRecordInPagesData({ data: prev, record: anchor })
|
|
329
|
+
)
|
|
330
|
+
)
|
|
331
|
+
expect(screen.getByTestId(`message-${anchor.id}`)).toBeTruthy()
|
|
332
|
+
reportViewable([anchor])
|
|
333
|
+
|
|
334
|
+
expect(mockFlash).toHaveBeenCalledTimes(1)
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('never flashes when there is no anchor', () => {
|
|
338
|
+
renderList()
|
|
339
|
+
|
|
340
|
+
reportViewable([messages[0], messages[1]])
|
|
341
|
+
|
|
342
|
+
expect(mockFlash).not.toHaveBeenCalled()
|
|
343
|
+
})
|
|
344
|
+
})
|
|
277
345
|
})
|
|
@@ -46,6 +46,8 @@ interface MessageProps extends MessageResource {
|
|
|
46
46
|
conversation_id: number
|
|
47
47
|
readByOthers?: boolean
|
|
48
48
|
inReplyScreen?: boolean
|
|
49
|
+
highlighted?: boolean
|
|
50
|
+
onHighlightShown?: () => void
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
export const Message = memo(function MessageRow({
|
|
@@ -53,6 +55,8 @@ export const Message = memo(function MessageRow({
|
|
|
53
55
|
conversation_id,
|
|
54
56
|
readByOthers,
|
|
55
57
|
inReplyScreen,
|
|
58
|
+
highlighted = false,
|
|
59
|
+
onHighlightShown,
|
|
56
60
|
...message
|
|
57
61
|
}: MessageProps) {
|
|
58
62
|
const { reactionCounts, pending, error, attachments, author } = message
|
|
@@ -71,7 +75,7 @@ export const Message = memo(function MessageRow({
|
|
|
71
75
|
const isPersisted = !isNewMessage(message)
|
|
72
76
|
const [temporarilyHidePendingState, setTemporarilyHidePendingState] = React.useState(true)
|
|
73
77
|
const [messageBubbleHeight, setMessageBubbleHeight] = React.useState(0)
|
|
74
|
-
const { animatedBackgroundColor, handleMessagePressIn, handleMessagePressOut } =
|
|
78
|
+
const { animatedBackgroundColor, flash, handleMessagePressIn, handleMessagePressOut } =
|
|
75
79
|
useAnimatedMessageBackgroundColor()
|
|
76
80
|
const isReplyRootMessage = message.replyRootId === message.id
|
|
77
81
|
const isDeletedReplyRootMessage = isReplyRootMessage && !!message.deletedAt
|
|
@@ -116,6 +120,13 @@ export const Message = memo(function MessageRow({
|
|
|
116
120
|
messageText || ''
|
|
117
121
|
} ${saveStatusLabel} ${timestamp} ${replyCountLabel}`
|
|
118
122
|
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
if (!highlighted) return
|
|
125
|
+
|
|
126
|
+
flash()
|
|
127
|
+
onHighlightShown?.()
|
|
128
|
+
}, [highlighted, flash, onHighlightShown])
|
|
129
|
+
|
|
119
130
|
useEffect(() => {
|
|
120
131
|
if (pending) {
|
|
121
132
|
const timer = setTimeout(() => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { date as formatDate } from '@planningcenter/datetime-fmt'
|
|
2
2
|
import { noop } from 'lodash'
|
|
3
|
-
import React, { RefObject, useRef } from 'react'
|
|
3
|
+
import React, { RefObject, useCallback, useEffect, useRef, useState } from 'react'
|
|
4
4
|
import { FlatList, FlatListProps, StyleSheet, View } from 'react-native'
|
|
5
5
|
import { useTheme } from '../../hooks'
|
|
6
6
|
import { ConversationResource } from '../../types/resources/conversation'
|
|
@@ -45,6 +45,7 @@ interface MessageListProps extends ScrollHandlers {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const ANCHOR_CLEARS_JUMP_BUTTON = 56
|
|
48
|
+
const ANCHOR_VIEWABILITY = { itemVisiblePercentThreshold: 50 }
|
|
48
49
|
|
|
49
50
|
/** MessageList
|
|
50
51
|
* The inverted list of messages, reply previews, and date separators for a conversation
|
|
@@ -80,6 +81,13 @@ export function MessageList({
|
|
|
80
81
|
const contentHeight = useRef(0)
|
|
81
82
|
const userHasScrolled = useRef(false)
|
|
82
83
|
const draggedSinceStartReached = useRef(false)
|
|
84
|
+
const latestAnchorMessageId = useRef(anchorMessageId)
|
|
85
|
+
const flashedAnchorId = useRef<string | null>(null)
|
|
86
|
+
const [highlightedMessageId, setHighlightedMessageId] = useState<string | null>(null)
|
|
87
|
+
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
latestAnchorMessageId.current = anchorMessageId
|
|
90
|
+
}, [anchorMessageId])
|
|
83
91
|
|
|
84
92
|
// Row heights keep settling after the first layout (images, attachments), so we
|
|
85
93
|
// re-pin on every layout pass until the reader takes over with a drag.
|
|
@@ -119,6 +127,19 @@ export function MessageList({
|
|
|
119
127
|
onScrollBeginDrag?.(event)
|
|
120
128
|
}
|
|
121
129
|
|
|
130
|
+
const flashAnchorOnceViewable: FlatListProps<EnrichedMessage>['onViewableItemsChanged'] = ({
|
|
131
|
+
viewableItems,
|
|
132
|
+
}) => {
|
|
133
|
+
const anchorId = latestAnchorMessageId.current
|
|
134
|
+
if (!anchorId || anchorId === flashedAnchorId.current) return
|
|
135
|
+
if (!viewableItems.some(token => token.item.id === anchorId)) return
|
|
136
|
+
|
|
137
|
+
flashedAnchorId.current = anchorId
|
|
138
|
+
setHighlightedMessageId(anchorId)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const clearHighlight = useCallback(() => setHighlightedMessageId(null), [])
|
|
142
|
+
|
|
122
143
|
// VirtualizedList re-checks its edges on every content size change using a JS offset
|
|
123
144
|
// the native hold never updates, so without this each merged page re-fires it.
|
|
124
145
|
const handleStartReached = () => {
|
|
@@ -143,6 +164,8 @@ export function MessageList({
|
|
|
143
164
|
onScrollToIndexFailed={noop}
|
|
144
165
|
onScrollEndDrag={onScrollEndDrag}
|
|
145
166
|
onMomentumScrollEnd={onMomentumScrollEnd}
|
|
167
|
+
onViewableItemsChanged={flashAnchorOnceViewable}
|
|
168
|
+
viewabilityConfig={ANCHOR_VIEWABILITY}
|
|
146
169
|
scrollEventThrottle={10}
|
|
147
170
|
maintainVisibleContentPosition={behind ? HOLD_ONLY : HOLD_AND_FOLLOW}
|
|
148
171
|
ListFooterComponent={
|
|
@@ -181,6 +204,8 @@ export function MessageList({
|
|
|
181
204
|
conversation_id={conversationId}
|
|
182
205
|
readByOthers={readByOthers}
|
|
183
206
|
inReplyScreen={inReplyScreen}
|
|
207
|
+
highlighted={item.id === highlightedMessageId}
|
|
208
|
+
onHighlightShown={clearHighlight}
|
|
184
209
|
/>
|
|
185
210
|
)
|
|
186
211
|
}}
|
|
@@ -1,43 +1,68 @@
|
|
|
1
|
+
import { useCallback } from 'react'
|
|
1
2
|
import { Platform } from 'react-native'
|
|
2
3
|
import {
|
|
3
4
|
useSharedValue,
|
|
4
5
|
useAnimatedStyle,
|
|
6
|
+
withDelay,
|
|
7
|
+
withSequence,
|
|
5
8
|
withTiming,
|
|
6
9
|
interpolateColor,
|
|
7
10
|
Easing,
|
|
11
|
+
ReduceMotion,
|
|
8
12
|
} from 'react-native-reanimated'
|
|
9
13
|
import { useTheme } from './use_theme'
|
|
10
14
|
|
|
15
|
+
const FLASH_IN_MS = 150
|
|
16
|
+
const FLASH_HOLD_MS = 500
|
|
17
|
+
const FLASH_OUT_MS = 1500
|
|
18
|
+
|
|
11
19
|
export function useAnimatedMessageBackgroundColor() {
|
|
12
20
|
const { colors } = useTheme()
|
|
13
|
-
const
|
|
21
|
+
const pressProgress = useSharedValue(0)
|
|
22
|
+
const flashProgress = useSharedValue(0)
|
|
14
23
|
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
default: 'transparent',
|
|
18
|
-
})
|
|
24
|
+
const tintColor = colors.fillColorNeutral050Base
|
|
25
|
+
const tintsOnPress = Platform.OS === 'ios'
|
|
19
26
|
|
|
20
27
|
const animatedBackgroundColor = useAnimatedStyle(() => {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
['transparent', pressedColor]
|
|
25
|
-
)
|
|
28
|
+
const pressTint = tintsOnPress ? pressProgress.value : 0
|
|
29
|
+
const progress = Math.max(pressTint, flashProgress.value)
|
|
30
|
+
const backgroundColor = interpolateColor(progress, [0, 1], ['transparent', tintColor])
|
|
26
31
|
return {
|
|
27
32
|
backgroundColor,
|
|
28
33
|
}
|
|
29
34
|
})
|
|
30
35
|
|
|
31
36
|
const handleMessagePressIn = () => {
|
|
32
|
-
|
|
37
|
+
pressProgress.value = withTiming(1, { duration: 300, easing: Easing.inOut(Easing.ease) })
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
const handleMessagePressOut = () => {
|
|
36
|
-
|
|
41
|
+
pressProgress.value = withTiming(0, { duration: 300, easing: Easing.inOut(Easing.ease) })
|
|
37
42
|
}
|
|
38
43
|
|
|
44
|
+
const flash = useCallback(() => {
|
|
45
|
+
flashProgress.value = withSequence(
|
|
46
|
+
withTiming(1, {
|
|
47
|
+
duration: FLASH_IN_MS,
|
|
48
|
+
easing: Easing.out(Easing.ease),
|
|
49
|
+
reduceMotion: ReduceMotion.Never,
|
|
50
|
+
}),
|
|
51
|
+
withDelay(
|
|
52
|
+
FLASH_HOLD_MS,
|
|
53
|
+
withTiming(0, {
|
|
54
|
+
duration: FLASH_OUT_MS,
|
|
55
|
+
easing: Easing.out(Easing.ease),
|
|
56
|
+
reduceMotion: ReduceMotion.System,
|
|
57
|
+
}),
|
|
58
|
+
ReduceMotion.Never
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
}, [flashProgress])
|
|
62
|
+
|
|
39
63
|
return {
|
|
40
64
|
animatedBackgroundColor,
|
|
65
|
+
flash,
|
|
41
66
|
handleMessagePressIn,
|
|
42
67
|
handleMessagePressOut,
|
|
43
68
|
}
|