Group Typing Bubble Animations

This commit is contained in:
ayumi-signal
2023-09-27 17:23:52 -04:00
committed by GitHub
parent 88df942029
commit 283ef57779
14 changed files with 565 additions and 209 deletions

View File

@@ -298,7 +298,7 @@ export type ConversationType = ReadonlyDeep<
unreadMentionsCount?: number;
isSelected?: boolean;
isFetchingUUID?: boolean;
typingContactIds?: Array<string>;
typingContactIdTimestamps?: Record<string, number>;
recentMediaItems?: ReadonlyArray<MediaItemType>;
profileSharing?: boolean;

View File

@@ -241,14 +241,16 @@ const mapStateToProps = (state: StateType, props: ExternalProps) => {
'unreadCount',
'unreadMentionsCount',
'isGroupV1AndDisabled',
'typingContactIds',
'typingContactIdTimestamps',
]),
isConversationSelected: state.conversations.selectedConversationId === id,
isIncomingMessageRequest: Boolean(
conversation.messageRequestsEnabled &&
!conversation.acceptedMessageRequest
),
isSomeoneTyping: Boolean(conversation.typingContactIds?.[0]),
isSomeoneTyping: Boolean(
Object.keys(conversation.typingContactIdTimestamps ?? {}).length > 0
),
...conversationMessages,
invitedContactsForNewlyCreatedGroup:

View File

@@ -1,23 +1,28 @@
// Copyright 2019 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { last } from 'lodash';
import React from 'react';
import { useSelector } from 'react-redux';
import { TypingBubble } from '../../components/conversation/TypingBubble';
import { strictAssert } from '../../util/assert';
import { TypingBubble } from '../../components/conversation/TypingBubble';
import { useGlobalModalActions } from '../ducks/globalModals';
import { useProxySelector } from '../../hooks/useProxySelector';
import { getIntl, getTheme } from '../selectors/user';
import { getConversationSelector } from '../selectors/conversations';
import { getTimelineItem } from '../selectors/timeline';
import {
getConversationSelector,
getConversationMessagesSelector,
} from '../selectors/conversations';
import { getPreferredBadgeSelector } from '../selectors/badges';
import { isInternalUser } from '../selectors/items';
type ExternalProps = {
conversationId: string;
};
export function SmartTypingBubble(props: ExternalProps): JSX.Element {
const { conversationId } = props;
export function SmartTypingBubble({
conversationId,
}: ExternalProps): JSX.Element {
const i18n = useSelector(getIntl);
const theme = useSelector(getTheme);
const getConversation = useSelector(getConversationSelector);
@@ -26,37 +31,39 @@ export function SmartTypingBubble(props: ExternalProps): JSX.Element {
throw new Error(`Did not find conversation ${conversationId} in state!`);
}
strictAssert(
conversation.typingContactIds?.[0],
'Missing typing contact IDs'
const typingContactIdTimestamps =
conversation.typingContactIdTimestamps ?? {};
const conversationMessages = useSelector(getConversationMessagesSelector)(
conversationId
);
const lastMessageId = last(conversationMessages.items);
const lastItem = useProxySelector(getTimelineItem, lastMessageId);
let lastItemAuthorId: string | undefined;
let lastItemTimestamp: number | undefined;
if (lastItem?.data) {
if ('author' in lastItem.data) {
lastItemAuthorId = lastItem.data.author?.id;
}
if ('timestamp' in lastItem.data) {
lastItemTimestamp = lastItem.data.timestamp;
}
}
const { showContactModal } = useGlobalModalActions();
const preferredBadgeSelector = useSelector(getPreferredBadgeSelector);
const internalUser = useSelector(isInternalUser);
const typingContactIdsVisible = internalUser
? conversation.typingContactIds
: conversation.typingContactIds.slice(0, 1);
const typingContacts = typingContactIdsVisible
.map(contactId => getConversation(contactId))
.map(typingConversation => {
return {
...typingConversation,
badge: preferredBadgeSelector(typingConversation.badges),
};
});
const getPreferredBadge = useSelector(getPreferredBadgeSelector);
return (
<TypingBubble
showContactModal={showContactModal}
conversationId={conversationId}
conversationType={conversation.type}
typingContactIdTimestamps={typingContactIdTimestamps}
lastItemAuthorId={lastItemAuthorId}
lastItemTimestamp={lastItemTimestamp}
i18n={i18n}
theme={theme}
typingContacts={typingContacts}
getConversation={getConversation}
getPreferredBadge={getPreferredBadge}
showContactModal={showContactModal}
/>
);
}