Fetch scrollback messages earlier, add them when ready

This commit is contained in:
Ken-Håvard Lieng 2017-06-07 00:04:37 +02:00
parent e5c5938414
commit b6e92d6add
8 changed files with 93 additions and 32 deletions

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@ import debounce from 'lodash/debounce';
import Message from './Message'; import Message from './Message';
import { getScrollPos, saveScrollPos } from '../util/scrollPosition'; import { getScrollPos, saveScrollPos } from '../util/scrollPosition';
const fetchThreshold = 100; const fetchThreshold = 500;
export default class MessageBox extends PureComponent { export default class MessageBox extends PureComponent {
componentWillMount() { componentWillMount() {
@ -39,6 +39,7 @@ export default class MessageBox extends PureComponent {
} }
this.loading = false; this.loading = false;
this.ready = false;
} }
} }
@ -108,21 +109,32 @@ export default class MessageBox extends PureComponent {
} }
}; };
fetchMore = debounce(() => { fetchMore = () => {
this.loading = true; this.loading = true;
this.props.onFetchMore(); this.props.onFetchMore();
};
addMore = debounce(() => {
const { tab, onAddMore } = this.props;
this.ready = true;
onAddMore(tab.server, tab.name);
}, 100); }, 100);
handleScroll = ({ scrollTop, clientHeight, scrollHeight }) => { handleScroll = ({ scrollTop, clientHeight, scrollHeight }) => {
if (this.mounted) { if (this.mounted) {
if (this.props.hasMoreMessages && if (!this.loading &&
this.props.hasMoreMessages &&
scrollTop <= fetchThreshold && scrollTop <= fetchThreshold &&
scrollTop < this.prevScrollTop && scrollTop < this.prevScrollTop) {
!this.loading) { this.fetchMore();
}
if (this.loading && !this.ready) {
if (this.mouseDown) { if (this.mouseDown) {
this.shouldFetch = true; this.ready = true;
this.shouldAdd = true;
} else { } else {
this.fetchMore(); this.addMore();
} }
} }
@ -138,10 +150,10 @@ export default class MessageBox extends PureComponent {
handleMouseUp = () => { handleMouseUp = () => {
this.mouseDown = false; this.mouseDown = false;
if (this.shouldFetch) { if (this.shouldAdd) {
this.shouldFetch = false; const { tab, onAddMore } = this.props;
this.loading = true; this.shouldAdd = false;
this.props.onFetchMore(); onAddMore(tab.server, tab.name);
} }
}; };

View File

@ -44,6 +44,7 @@ export default class Chat extends Component {
title, title,
users, users,
addFetchedMessages,
fetchMessages, fetchMessages,
inputActions, inputActions,
runCommand, runCommand,
@ -79,6 +80,7 @@ export default class Chat extends Component {
hasMoreMessages={hasMoreMessages} hasMoreMessages={hasMoreMessages}
messages={messages} messages={messages}
tab={tab} tab={tab}
onAddMore={addFetchedMessages}
onFetchMore={fetchMessages} onFetchMore={fetchMessages}
onNickClick={this.handleNickClick} onNickClick={this.handleNickClick}
/> />

View File

@ -7,7 +7,7 @@ import { getSelectedChannel, getSelectedChannelUsers, part } from '../state/chan
import { getCurrentInputHistoryEntry, addInputHistory, resetInputHistory, import { getCurrentInputHistoryEntry, addInputHistory, resetInputHistory,
incrementInputHistory, decrementInputHistory } from '../state/input'; incrementInputHistory, decrementInputHistory } from '../state/input';
import { getSelectedMessages, getHasMoreMessages, import { getSelectedMessages, getHasMoreMessages,
runCommand, sendMessage, fetchMessages } from '../state/messages'; runCommand, sendMessage, fetchMessages, addFetchedMessages } from '../state/messages';
import { openPrivateChat, closePrivateChat } from '../state/privateChats'; import { openPrivateChat, closePrivateChat } from '../state/privateChats';
import { getSearch, searchMessages, toggleSearch } from '../state/search'; import { getSearch, searchMessages, toggleSearch } from '../state/search';
import { getCurrentNick, disconnect } from '../state/servers'; import { getCurrentNick, disconnect } from '../state/servers';
@ -29,6 +29,7 @@ const mapState = createStructuredSelector({
const mapDispatch = dispatch => ({ const mapDispatch = dispatch => ({
...bindActionCreators({ ...bindActionCreators({
addFetchedMessages,
closePrivateChat, closePrivateChat,
disconnect, disconnect,
fetchMessages, fetchMessages,

View File

@ -0,0 +1,35 @@
import * as actions from '../state/actions';
//
// This middleware handles waiting until MessageBox
// is ready before adding messages to the top
//
const message = store => next => {
const ready = {};
const cache = {};
return action => {
if (action.type === actions.ADD_MESSAGES && action.prepend) {
const key = `${action.server} ${action.channel}`;
if (ready[key]) {
ready[key] = false;
return next(action);
}
cache[key] = action;
} else if (action.type === actions.ADD_FETCHED_MESSAGES) {
const key = `${action.server} ${action.channel}`;
ready[key] = true;
if (cache[key]) {
store.dispatch(cache[key]);
cache[key] = undefined;
}
} else {
return next(action);
}
};
};
export default message;

View File

@ -11,6 +11,7 @@ export const INPUT_HISTORY_DECREMENT = 'INPUT_HISTORY_DECREMENT';
export const INPUT_HISTORY_INCREMENT = 'INPUT_HISTORY_INCREMENT'; export const INPUT_HISTORY_INCREMENT = 'INPUT_HISTORY_INCREMENT';
export const INPUT_HISTORY_RESET = 'INPUT_HISTORY_RESET'; export const INPUT_HISTORY_RESET = 'INPUT_HISTORY_RESET';
export const ADD_FETCHED_MESSAGES = 'ADD_FETCHED_MESSAGES';
export const ADD_MESSAGE = 'ADD_MESSAGE'; export const ADD_MESSAGE = 'ADD_MESSAGE';
export const ADD_MESSAGES = 'ADD_MESSAGES'; export const ADD_MESSAGES = 'ADD_MESSAGES';
export const COMMAND = 'COMMAND'; export const COMMAND = 'COMMAND';

View File

@ -152,6 +152,14 @@ export function fetchMessages() {
}; };
} }
export function addFetchedMessages(server, tab) {
return {
type: actions.ADD_FETCHED_MESSAGES,
server,
tab
};
}
export function updateMessageHeight(wrapWidth, charWidth, windowWidth) { export function updateMessageHeight(wrapWidth, charWidth, windowWidth) {
return { return {
type: actions.UPDATE_MESSAGE_HEIGHT, type: actions.UPDATE_MESSAGE_HEIGHT,

View File

@ -2,6 +2,7 @@ import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk'; import thunk from 'redux-thunk';
import createReducer from './state'; import createReducer from './state';
import { routeReducer, routeMiddleware } from './util/router'; import { routeReducer, routeMiddleware } from './util/router';
import message from './middleware/message';
import createSocketMiddleware from './middleware/socket'; import createSocketMiddleware from './middleware/socket';
import commands from './commands'; import commands from './commands';
@ -13,9 +14,10 @@ export default function configureStore(socket) {
const store = createStore(reducer, composeEnhancers( const store = createStore(reducer, composeEnhancers(
applyMiddleware( applyMiddleware(
routeMiddleware,
thunk, thunk,
routeMiddleware,
createSocketMiddleware(socket), createSocketMiddleware(socket),
message,
commands commands
) )
)); ));