From 3d112714712f6702743187b3b18cc4a4199d90d0 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 5 Nov 2020 12:11:03 +1100 Subject: [PATCH] fix position of unread banner on conversation (search for first read) --- .../conversation/SessionConversation.tsx | 26 ++++++------ .../SessionConversationMessagesList.tsx | 40 +++++++++++++------ .../conversation/SessionLastSeedIndicator.tsx | 24 ++++++++--- 3 files changed, 57 insertions(+), 33 deletions(-) diff --git a/ts/components/session/conversation/SessionConversation.tsx b/ts/components/session/conversation/SessionConversation.tsx index b8e2614e8..543ae159c 100644 --- a/ts/components/session/conversation/SessionConversation.tsx +++ b/ts/components/session/conversation/SessionConversation.tsx @@ -154,7 +154,6 @@ export class SessionConversation extends React.Component { public async componentWillMount() { await this.loadInitialMessages(); - this.setState({ initialFetchComplete: true }); } public componentWillUnmount() { @@ -331,15 +330,20 @@ export class SessionConversation extends React.Component { // After the inital fetch, all new messages are automatically added from onNewMessage // in the conversation model. // The only time we need to call getMessages() is to grab more messages on scroll. - const { initialFetchComplete } = this.state; - if (initialFetchComplete) { + if (this.state.initialFetchComplete) { return; } - return this.getMessages(Constants.CONVERSATION.DEFAULT_MESSAGE_FETCH_COUNT); + return this.getMessages( + Constants.CONVERSATION.DEFAULT_MESSAGE_FETCH_COUNT, + () => { + this.setState({ initialFetchComplete: true }); + } + ); } - public async getMessages(numMessages?: number) { + // tslint:disable-next-line: no-empty + public async getMessages(numMessages?: number, callback: any = () => {}) { const { unreadCount } = this.state; const { conversationKey } = this.props; let msgCount = @@ -365,7 +369,7 @@ export class SessionConversation extends React.Component { const messages = []; // no need to do that `firstMessageOfSeries` on a private chat if (this.props.conversation.type === 'direct') { - this.setState({ messages: messageSet.models }); + this.setState({ messages: messageSet.models }, callback); return; } @@ -386,7 +390,7 @@ export class SessionConversation extends React.Component { messages.push({ ...messageModels[i], firstMessageOfSeries }); } - this.setState({ messages }); + this.setState({ messages }, callback); } public getHeaderProps() { @@ -494,19 +498,13 @@ export class SessionConversation extends React.Component { public getMessagesListProps() { const { conversation } = this.props; - const { - messages, - initialFetchComplete, - quotedMessageTimestamp, - selectedMessages, - } = this.state; + const { messages, quotedMessageTimestamp, selectedMessages } = this.state; return { selectedMessages, conversationKey: conversation.id, messages, resetSelection: this.resetSelection, - initialFetchComplete, quotedMessageTimestamp, conversation, selectMessage: this.selectMessage, diff --git a/ts/components/session/conversation/SessionConversationMessagesList.tsx b/ts/components/session/conversation/SessionConversationMessagesList.tsx index 090e73d20..f35635cf7 100644 --- a/ts/components/session/conversation/SessionConversationMessagesList.tsx +++ b/ts/components/session/conversation/SessionConversationMessagesList.tsx @@ -27,7 +27,6 @@ interface Props { selectedMessages: Array; conversationKey: string; messages: Array; - initialFetchComplete: boolean; conversation: ConversationType; messageContainerRef: React.RefObject; selectMessage: (messageId: string) => void; @@ -116,12 +115,16 @@ export class SessionConversationMessagesList extends React.Component< } public renderMessages(messages: Array) { - const { conversation } = this.props; const { isScrolledToBottom } = this.state; - const { unreadCount } = conversation; const multiSelectMode = Boolean(this.props.selectedMessages.length); let currentMessageIndex = 0; + // find the first unread message in the list of messages. We use this to display the + // unread banner so this is at all times at the correct index. + const findFirstUnreadIndex = messages.findIndex( + message => + !(message?.attributes?.unread && message?.attributes?.unread !== false) + ); return ( <> {messages.map((message: MessageModel) => { @@ -134,16 +137,18 @@ export class SessionConversationMessagesList extends React.Component< const propsForGroupInvitation = message.propsForGroupInvitation; const groupNotificationProps = message.propsForGroupNotification; - let unreadIndicator = null; - - // if there is some unread messages - if ( - unreadCount > 0 && - currentMessageIndex === unreadCount && - !isScrolledToBottom - ) { - unreadIndicator = ; - } + + // if there are some unread messages + const showUnreadIndicator = + !isScrolledToBottom && + findFirstUnreadIndex > 0 && + currentMessageIndex === findFirstUnreadIndex; + const unreadIndicator = ( + + ); currentMessageIndex = currentMessageIndex + 1; @@ -391,6 +396,15 @@ export class SessionConversationMessagesList extends React.Component< if (scrollOffsetPc === 0 && this.state.doneInitialScroll) { this.setState({ isScrolledToBottom: true }); + } else if ( + scrollHeight !== 0 && + scrollHeight === clientHeight && + !this.state.isScrolledToBottom + ) { + this.setState({ isScrolledToBottom: true }, () => { + // Mark messages read + this.updateReadMessages(); + }); } } diff --git a/ts/components/session/conversation/SessionLastSeedIndicator.tsx b/ts/components/session/conversation/SessionLastSeedIndicator.tsx index 78418af2c..59ad74ed1 100644 --- a/ts/components/session/conversation/SessionLastSeedIndicator.tsx +++ b/ts/components/session/conversation/SessionLastSeedIndicator.tsx @@ -1,11 +1,17 @@ import React from 'react'; import styled from 'styled-components'; -const LastSeenBarContainer = styled.div` - padding-top: 25px; - padding-bottom: 35px; +interface LastSeenProps { + show: boolean; +} + +const LastSeenBarContainer = styled.div` + padding-bottom: ${props => (props.show ? '35px' : 0)}; margin-inline-start: 28px; - padding-top: 28px; + padding-top: ${props => (props.show ? '28px' : 0)}; + transition: ${props => props.theme.common.animations.defaultDuration}; + overflow: hidden; + height: ${props => (props.show ? 'auto' : 0)}; `; const LastSeenBar = styled.div` @@ -25,12 +31,18 @@ const LastSeenText = styled.div` color: ${props => props.theme.colors.lastSeenIndicatorTextColor}; `; -export const SessionLastSeenIndicator = ({ count }: { count: number }) => { +export const SessionLastSeenIndicator = ({ + count, + show, +}: { + count: number; + show: boolean; +}) => { const { i18n } = window; const text = count > 1 ? i18n('unreadMessages', count) : i18n('unreadMessage', count); return ( - + {text}