use react-intersection to accurately mark messages as read

pull/1381/head
Audric Ackermann 5 years ago
parent d533a3aca5
commit d0043ca245
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -596,6 +596,7 @@
quote: this.getPropsForQuote(options), quote: this.getPropsForQuote(options),
authorAvatarPath, authorAvatarPath,
isExpired: this.hasExpired, isExpired: this.hasExpired,
isUnread: this.isUnread(),
expirationLength, expirationLength,
expirationTimestamp, expirationTimestamp,
isPublic: !!this.get('isPublic'), isPublic: !!this.get('isPublic'),
@ -618,6 +619,7 @@
onRetrySend: () => this.retrySend(), onRetrySend: () => this.retrySend(),
onShowDetail: () => this.trigger('show-message-detail', this), onShowDetail: () => this.trigger('show-message-detail', this),
onClickLinkPreview: url => this.trigger('navigate-to', url), onClickLinkPreview: url => this.trigger('navigate-to', url),
markRead: readAt => this.markRead(readAt),
onShowUserDetails: pubkey => onShowUserDetails: pubkey =>
window.Whisper.events.trigger('onShowUserDetails', { window.Whisper.events.trigger('onShowUserDetails', {

@ -111,6 +111,7 @@
"react-emoji": "^0.5.0", "react-emoji": "^0.5.0",
"react-emoji-render": "^1.2.4", "react-emoji-render": "^1.2.4",
"react-h5-audio-player": "^3.2.0", "react-h5-audio-player": "^3.2.0",
"react-intersection-observer": "^8.30.3",
"react-mentions": "^4.0.2", "react-mentions": "^4.0.2",
"react-portal": "^4.2.0", "react-portal": "^4.2.0",
"react-qr-svg": "^2.2.1", "react-qr-svg": "^2.2.1",

@ -37,6 +37,7 @@ import { SessionIcon, SessionIconSize, SessionIconType } from '../session/icon';
import _ from 'lodash'; import _ from 'lodash';
import { animation, contextMenu, Item, Menu } from 'react-contexify'; import { animation, contextMenu, Item, Menu } from 'react-contexify';
import uuid from 'uuid'; import uuid from 'uuid';
import { InView } from 'react-intersection-observer';
// Same as MIN_WIDTH in ImageGrid.tsx // Same as MIN_WIDTH in ImageGrid.tsx
const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200; const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200;
@ -97,6 +98,7 @@ export interface Props {
// whether or not to show check boxes // whether or not to show check boxes
multiSelectMode: boolean; multiSelectMode: boolean;
firstMessageOfSeries: boolean; firstMessageOfSeries: boolean;
isUnread: boolean;
onClickAttachment?: (attachment: AttachmentType) => void; onClickAttachment?: (attachment: AttachmentType) => void;
onClickLinkPreview?: (url: string) => void; onClickLinkPreview?: (url: string) => void;
@ -110,6 +112,7 @@ export interface Props {
onBanUser?: () => void; onBanUser?: () => void;
onShowDetail: () => void; onShowDetail: () => void;
onShowUserDetails: (userPubKey: string) => void; onShowUserDetails: (userPubKey: string) => void;
markRead: (readAt: number) => Promise<void>;
} }
interface State { interface State {
@ -987,7 +990,8 @@ export class Message extends React.PureComponent<Props, State> {
conversationType, conversationType,
isPublic, isPublic,
text, text,
firstMessageOfSeries, isUnread,
markRead,
} = this.props; } = this.props;
const { expired, expiring } = this.state; const { expired, expiring } = this.state;
@ -1008,6 +1012,7 @@ export class Message extends React.PureComponent<Props, State> {
const isIncoming = direction === 'incoming'; const isIncoming = direction === 'incoming';
const shouldHightlight = mentionMe && isIncoming && isPublic; const shouldHightlight = mentionMe && isIncoming && isPublic;
const shouldMarkReadWhenVisible = isIncoming && isUnread;
const divClasses = ['session-message-wrapper']; const divClasses = ['session-message-wrapper'];
if (shouldHightlight) { if (shouldHightlight) {
@ -1021,10 +1026,23 @@ export class Message extends React.PureComponent<Props, State> {
divClasses.push('public-chat-message-wrapper'); divClasses.push('public-chat-message-wrapper');
} }
const onVisible = (inView: boolean) => {
if (inView && shouldMarkReadWhenVisible) {
// mark the message as read.
// this will trigger the expire timer.
void markRead(Date.now());
}
};
return ( return (
<div <InView
id={id} id={id}
as="div"
className={classNames(divClasses)} className={classNames(divClasses)}
onChange={onVisible}
threshold={1}
delay={200}
triggerOnce={true}
onContextMenu={this.handleContextMenu} onContextMenu={this.handleContextMenu}
> >
{this.renderAvatar()} {this.renderAvatar()}
@ -1099,7 +1117,7 @@ export class Message extends React.PureComponent<Props, State> {
{this.renderError(!isIncoming)} {this.renderError(!isIncoming)}
{this.renderContextMenu()} {this.renderContextMenu()}
</div> </div>
</div> </InView>
); );
} }

@ -8778,6 +8778,11 @@ react-icons@^2.2.7:
dependencies: dependencies:
react-icon-base "2.1.0" react-icon-base "2.1.0"
react-intersection-observer@^8.30.3:
version "8.30.3"
resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-8.30.3.tgz#99850f0aacc5b474dddb04976e58d7ee9315ba19"
integrity sha512-hKYTJUrU99hAf7h1lNY3pjYXt+09BaPNC6fcLw1B8OLJJUDXTWrwzu4hRuztougeRgPYpxmNaTn1FS4F3EQnhA==
react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1: react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1:
version "16.13.0" version "16.13.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.0.tgz#0f37c3613c34fe6b37cd7f763a0d6293ab15c527" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.0.tgz#0f37c3613c34fe6b37cd7f763a0d6293ab15c527"

Loading…
Cancel
Save