Merge branch 'chats-ff' into 'develop'

Chats: FireFox fixes

Closes #399

See merge request soapbox-pub/soapbox-fe!218
better-thread-display
Alex Gleason 2020-09-08 00:27:29 +00:00
commit 8c137b0c3c
3 zmienionych plików z 63 dodań i 33 usunięć

Wyświetl plik

@ -13,8 +13,6 @@ import { escape, throttle } from 'lodash';
import { MediaGallery } from 'soapbox/features/ui/util/async-components'; import { MediaGallery } from 'soapbox/features/ui/util/async-components';
import Bundle from 'soapbox/features/ui/components/bundle'; import Bundle from 'soapbox/features/ui/components/bundle';
const scrollBottom = (elem) => elem.scrollHeight - elem.offsetHeight - elem.scrollTop;
const makeEmojiMap = record => record.get('emojis', ImmutableList()).reduce((map, emoji) => { const makeEmojiMap = record => record.get('emojis', ImmutableList()).reduce((map, emoji) => {
return map.set(`:${emoji.get('shortcode')}:`, emoji); return map.set(`:${emoji.get('shortcode')}:`, emoji);
}, ImmutableMap()); }, ImmutableMap());
@ -45,12 +43,13 @@ class ChatMessageList extends ImmutablePureComponent {
} }
state = { state = {
initialLoad: true,
isLoading: false, isLoading: false,
} }
scrollToBottom = () => { scrollToBottom = () => {
if (!this.messagesEnd) return; if (!this.messagesEnd) return;
this.messagesEnd.scrollIntoView(); this.messagesEnd.scrollIntoView(false);
} }
setMessageEndRef = (el) => { setMessageEndRef = (el) => {
@ -82,22 +81,45 @@ class ChatMessageList extends ImmutablePureComponent {
}); });
} }
isNearBottom = () => {
const elem = this.node;
if (!elem) return false;
const scrollBottom = elem.scrollHeight - elem.offsetHeight - elem.scrollTop;
return scrollBottom < elem.offsetHeight * 1.5;
}
componentDidMount() { componentDidMount() {
const { dispatch, chatId } = this.props; const { dispatch, chatId } = this.props;
dispatch(fetchChatMessages(chatId)); dispatch(fetchChatMessages(chatId));
this.node.addEventListener('scroll', this.handleScroll); this.node.addEventListener('scroll', this.handleScroll);
this.scrollToBottom();
} }
componentDidUpdate(prevProps) { getSnapshotBeforeUpdate(prevProps, prevState) {
const { scrollHeight, scrollTop } = this.node;
return scrollHeight - scrollTop;
}
restoreScrollPosition = (scrollBottom) => {
this.lastComputedScroll = this.node.scrollHeight - scrollBottom;
this.node.scrollTop = this.lastComputedScroll;
}
componentDidUpdate(prevProps, prevState, scrollBottom) {
const { initialLoad } = this.state;
const oldCount = prevProps.chatMessages.count(); const oldCount = prevProps.chatMessages.count();
const newCount = this.props.chatMessages.count(); const newCount = this.props.chatMessages.count();
const isNearBottom = scrollBottom(this.node) < 150; const isNearBottom = this.isNearBottom();
const historyAdded = prevProps.chatMessages.getIn([-1, 'id']) !== this.props.chatMessages.getIn([-1, 'id']); const historyAdded = prevProps.chatMessages.getIn([0, 'id']) !== this.props.chatMessages.getIn([0, 'id']);
// Retain scroll bar position when loading old messages
this.restoreScrollPosition(scrollBottom);
if (oldCount !== newCount) { if (oldCount !== newCount) {
if (isNearBottom) this.scrollToBottom(); if (isNearBottom || initialLoad) this.scrollToBottom();
if (historyAdded) this.setState({ isLoading: false }); if (historyAdded) this.setState({ isLoading: false, initialLoad: false });
} }
} }
@ -107,13 +129,20 @@ class ChatMessageList extends ImmutablePureComponent {
handleLoadMore = () => { handleLoadMore = () => {
const { dispatch, chatId, chatMessages } = this.props; const { dispatch, chatId, chatMessages } = this.props;
const maxId = chatMessages.getIn([-1, 'id']); const maxId = chatMessages.getIn([0, 'id']);
dispatch(fetchChatMessages(chatId, maxId)); dispatch(fetchChatMessages(chatId, maxId));
this.setState({ isLoading: true }); this.setState({ isLoading: true });
} }
handleScroll = throttle(() => { handleScroll = throttle(() => {
if (this.node.scrollTop < 150 && !this.state.isLoading) this.handleLoadMore(); const { lastComputedScroll } = this;
const { isLoading, initialLoad } = this.state;
const { scrollTop, offsetHeight } = this.node;
const computedScroll = lastComputedScroll === scrollTop;
const nearTop = scrollTop < offsetHeight * 2;
if (nearTop && !isLoading && !initialLoad && !computedScroll)
this.handleLoadMore();
}, 150, { }, 150, {
trailing: true, trailing: true,
}); });
@ -126,15 +155,17 @@ class ChatMessageList extends ImmutablePureComponent {
const attachment = chatMessage.get('attachment'); const attachment = chatMessage.get('attachment');
if (!attachment) return null; if (!attachment) return null;
return ( return (
<Bundle fetchComponent={MediaGallery}> <div className='chat-message__media'>
{Component => ( <Bundle fetchComponent={MediaGallery}>
<Component {Component => (
media={ImmutableList([attachment])} <Component
height={120} media={ImmutableList([attachment])}
onOpenMedia={this.onOpenMedia} height={120}
/> onOpenMedia={this.onOpenMedia}
)} />
</Bundle> )}
</Bundle>
</div>
); );
} }
@ -159,7 +190,6 @@ class ChatMessageList extends ImmutablePureComponent {
return ( return (
<div className='chat-messages' ref={this.setRef}> <div className='chat-messages' ref={this.setRef}>
<div style={{ float: 'left', clear: 'both' }} ref={this.setMessageEndRef} />
{chatMessages.map(chatMessage => ( {chatMessages.map(chatMessage => (
<div <div
className={classNames('chat-message', { className={classNames('chat-message', {
@ -181,6 +211,7 @@ class ChatMessageList extends ImmutablePureComponent {
</div> </div>
</div> </div>
))} ))}
<div style={{ float: 'left', clear: 'both' }} ref={this.setMessageEndRef} />
</div> </div>
); );
} }

Wyświetl plik

@ -10,8 +10,8 @@ import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutabl
const initialState = ImmutableMap(); const initialState = ImmutableMap();
const idComparator = (a, b) => { const idComparator = (a, b) => {
if (a < b) return 1; if (a < b) return -1;
if (a > b) return -1; if (a > b) return 1;
return 0; return 0;
}; };

Wyświetl plik

@ -99,18 +99,12 @@
.chat-messages { .chat-messages {
overflow-y: scroll; overflow-y: scroll;
flex: 1; flex: 1;
display: flex;
flex-direction: column-reverse;
} }
.chat-message { .chat-message {
padding: 7px 10px; margin: 14px 10px;
display: flex; display: flex;
&:last-child {
padding-top: 14px;
}
&__bubble { &__bubble {
font-size: 15px; font-size: 15px;
padding: 4px 10px; padding: 4px 10px;
@ -225,9 +219,10 @@
position: relative; position: relative;
.icon-button { .icon-button {
color: var(--primary-text-color--faint);
position: absolute; position: absolute;
right: 10px; right: 10px;
top: 8px; top: calc(50% - 13px);
width: auto; width: auto;
height: auto; height: auto;
background: transparent !important; background: transparent !important;
@ -237,7 +232,7 @@
} }
.chat-box__send .icon-button { .chat-box__send .icon-button {
top: 12px; top: calc(50% - 9px);
} }
textarea { textarea {
@ -347,8 +342,12 @@
} }
} }
.chat-message__media {
height: 120px;
}
.chat-message .media-gallery { .chat-message .media-gallery {
height: auto !important; height: 100% !important;
margin: 4px 0 8px; margin: 4px 0 8px;
.spoiler-button { .spoiler-button {
@ -358,7 +357,7 @@
.media-gallery__item:not(.media-gallery__item--image) { .media-gallery__item:not(.media-gallery__item--image) {
max-width: 100%; max-width: 100%;
width: 120px !important; width: 120px !important;
height: 70px !important; height: 100% !important;
} }
&__preview { &__preview {