diff --git a/pkg/interface/src/views/apps/chat/components/lib/ChatMessage.tsx b/pkg/interface/src/views/apps/chat/components/lib/ChatMessage.tsx index 30ab082f9..3c87a08aa 100644 --- a/pkg/interface/src/views/apps/chat/components/lib/ChatMessage.tsx +++ b/pkg/interface/src/views/apps/chat/components/lib/ChatMessage.tsx @@ -1,6 +1,7 @@ import React, { Component, PureComponent } from "react"; import moment from "moment"; import _ from "lodash"; +import { Box } from "@tlon/indigo-react"; import { OverlaySigil } from './overlay-sigil'; import { uxToHex, cite, writeText } from '~/logic/lib/util'; @@ -12,14 +13,10 @@ import RemoteContent from '~/views/components/RemoteContent'; export const DATESTAMP_FORMAT = '[~]YYYY.M.D'; -export const UnreadMarker = React.forwardRef(({ dayBreak, when, style }, ref) => ( -
{ - setTimeout(() => { - element.style.opacity = '1'; - }, 250); - }} className="green2 flex items-center f9 absolute w-100" style={{...style, opacity: '0'}}> +export const UnreadMarker = React.forwardRef(({ dayBreak, when }, ref) => ( +

-

New messages below

+

New messages below


{dayBreak ?

{moment(when).calendar()}

@@ -39,18 +36,19 @@ interface ChatMessageProps { msg: Envelope | IMessage; previousMsg: Envelope | IMessage | undefined; nextMsg: Envelope | IMessage | undefined; - isFirstUnread: boolean; + isLastRead: boolean; group: Group; association: Association; contacts: Contacts; - unreadRef: React.RefObject; hideAvatars: boolean; hideNicknames: boolean; remoteContentPolicy: LocalUpdateRemoteContentPolicy; - className: string; + className?: string; isPending: boolean; style?: any; scrollWindow: HTMLDivElement; + isLastMessage?: boolean; + unreadMarkerRef: React.RefObject; } export default class ChatMessage extends Component { @@ -72,11 +70,10 @@ export default class ChatMessage extends Component { msg, previousMsg, nextMsg, - isFirstUnread, + isLastRead, group, association, contacts, - unreadRef, hideAvatars, hideNicknames, remoteContentPolicy, @@ -84,7 +81,9 @@ export default class ChatMessage extends Component { isPending, style, measure, - scrollWindow + scrollWindow, + isLastMessage, + unreadMarkerRef } = this.props; const renderSigil = Boolean((nextMsg && msg.author !== nextMsg.author) || !nextMsg || msg.number === 1); @@ -92,7 +91,7 @@ export default class ChatMessage extends Component { const containerClass = `${renderSigil ? `w-100 flex flex-wrap cf pr3 f7 pt4 pl3 lh-copy` - : `w-100 flex flex-wrap cf pr3 hide-child`} ${isPending ? ' o-40' : ''} ${className}` + : `w-100 flex flex-wrap cf pr3 hide-child`} ${isPending ? 'o-40' : ''} ${isLastMessage ? 'pb3' : ''} ${className}` const timestamp = moment.unix(msg.when / 1000).format(renderSigil ? 'hh:mm a' : 'hh:mm'); @@ -116,15 +115,19 @@ export default class ChatMessage extends Component { scrollWindow }; + const unreadContainerStyle = { + height: isLastRead ? '1.66em' : '0', + }; + return (
- {dayBreak && !isFirstUnread ? : null} + {dayBreak && !isLastRead ? : null} {renderSigil ? : } - {isFirstUnread - ? - : null} + {isLastRead + ? + : null}
); } diff --git a/pkg/interface/src/views/apps/chat/components/lib/ChatWindow.tsx b/pkg/interface/src/views/apps/chat/components/lib/ChatWindow.tsx index 4724a94bf..bc3f9270b 100644 --- a/pkg/interface/src/views/apps/chat/components/lib/ChatWindow.tsx +++ b/pkg/interface/src/views/apps/chat/components/lib/ChatWindow.tsx @@ -48,10 +48,12 @@ interface ChatWindowState { fetchPending: boolean; idle: boolean; initialized: boolean; + lastRead: number; } export default class ChatWindow extends Component { private virtualList: VirtualScroller | null; + private unreadMarkerRef: React.RefObject; INITIALIZATION_MAX_TIME = 1500; @@ -61,18 +63,20 @@ export default class ChatWindow extends Component 0) { @@ -112,17 +108,9 @@ export default class ChatWindow extends Component { if (!this.virtualList) return; - const initialIndex = this.initialIndex(); - this.virtualList.scrollToData(initialIndex).then(() => { - if ( - initialIndex === mailboxSize - || (this.virtualList && this.virtualList.window && this.virtualList.window.scrollTop === 0) - ) { - this.setState({ idle: false }); - this.dismissUnread(); - } - this.setState({ initialized: true }); - }); + this.setState({ idle: false }); + this.setState({ initialized: true }); + this.dismissIfLineVisible(); }); } else { setTimeout(() => { @@ -195,9 +183,31 @@ export default class ChatWindow extends Component IDLE_THRESHOLD) { + this.setState({ idle: true }); + } + + this.dismissIfLineVisible(); + } + + dismissIfLineVisible() { + if (this.props.unreadCount === 0) return; + if (!this.unreadMarkerRef.current || !this.virtualList?.window) return; + const parent = this.unreadMarkerRef.current.parentElement?.parentElement; + if (!parent) return; + const { scrollTop, scrollHeight, offsetHeight } = this.virtualList.window; + if ( + (scrollHeight - parent.offsetTop > scrollTop) + && (scrollHeight - parent.offsetTop < scrollTop + offsetHeight) + ) { + this.dismissUnread(); + } } render() { @@ -220,6 +230,8 @@ export default class ChatWindow extends Component @@ -258,11 +270,7 @@ export default class ChatWindow extends Component { - if (!this.state.idle && scrollTop > IDLE_THRESHOLD) { - this.setState({ idle: true }); - } - }} + onScroll={this.onScroll.bind(this)} data={messages} size={mailboxSize + stationPendingMessages.length} renderer={({ index, measure, scrollWindow }) => { @@ -272,15 +280,14 @@ export default class ChatWindow extends Component; } const isPending: boolean = 'pending' in msg && Boolean(msg.pending); - const isFirstUnread: boolean = Boolean(unreadCount && index === this.firstUnread()); const isLastMessage: boolean = Boolean(index === lastMessage) - const props = { measure, scrollWindow, isPending, isFirstUnread, msg, ...messageProps }; + const isLastRead: boolean = Boolean(!isLastMessage && index === this.state.lastRead); + const props = { measure, scrollWindow, isPending, isLastRead, isLastMessage, msg, ...messageProps }; return ( );