Allow clients to fetch statuses made while they were offline (#6876)
This commit is contained in:
		
							parent
							
								
									42786040d1
								
							
						
					
					
						commit
						34cb1a5461
					
				
					 22 changed files with 191 additions and 259 deletions
				
			
		| 
						 | 
					@ -5,13 +5,7 @@ import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light
 | 
				
			||||||
import { tagHistory } from '../settings';
 | 
					import { tagHistory } from '../settings';
 | 
				
			||||||
import { useEmoji } from './emojis';
 | 
					import { useEmoji } from './emojis';
 | 
				
			||||||
import { importFetchedAccounts } from './importer';
 | 
					import { importFetchedAccounts } from './importer';
 | 
				
			||||||
 | 
					import { updateTimeline } from './timelines';
 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  updateTimeline,
 | 
					 | 
				
			||||||
  refreshHomeTimeline,
 | 
					 | 
				
			||||||
  refreshCommunityTimeline,
 | 
					 | 
				
			||||||
  refreshPublicTimeline,
 | 
					 | 
				
			||||||
} from './timelines';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
let cancelFetchComposeSuggestionsAccounts;
 | 
					let cancelFetchComposeSuggestionsAccounts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,19 +119,17 @@ export function submitCompose() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // To make the app more responsive, immediately get the status into the columns
 | 
					      // To make the app more responsive, immediately get the status into the columns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const insertOrRefresh = (timelineId, refreshAction) => {
 | 
					      const insertIfOnline = (timelineId) => {
 | 
				
			||||||
        if (getState().getIn(['timelines', timelineId, 'online'])) {
 | 
					        if (getState().getIn(['timelines', timelineId, 'items', 0]) !== null) {
 | 
				
			||||||
          dispatch(updateTimeline(timelineId, { ...response.data }));
 | 
					          dispatch(updateTimeline(timelineId, { ...response.data }));
 | 
				
			||||||
        } else if (getState().getIn(['timelines', timelineId, 'loaded'])) {
 | 
					 | 
				
			||||||
          dispatch(refreshAction());
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      insertOrRefresh('home', refreshHomeTimeline);
 | 
					      insertIfOnline('home');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
 | 
					      if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
 | 
				
			||||||
        insertOrRefresh('community', refreshCommunityTimeline);
 | 
					        insertIfOnline('community');
 | 
				
			||||||
        insertOrRefresh('public', refreshPublicTimeline);
 | 
					        insertIfOnline('public');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }).catch(function (error) {
 | 
					    }).catch(function (error) {
 | 
				
			||||||
      dispatch(submitComposeFail(error));
 | 
					      dispatch(submitComposeFail(error));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,8 +2,7 @@ import { connectStream } from '../stream';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  updateTimeline,
 | 
					  updateTimeline,
 | 
				
			||||||
  deleteFromTimelines,
 | 
					  deleteFromTimelines,
 | 
				
			||||||
  refreshHomeTimeline,
 | 
					  expandHomeTimeline,
 | 
				
			||||||
  connectTimeline,
 | 
					 | 
				
			||||||
  disconnectTimeline,
 | 
					  disconnectTimeline,
 | 
				
			||||||
} from './timelines';
 | 
					} from './timelines';
 | 
				
			||||||
import { updateNotifications, refreshNotifications } from './notifications';
 | 
					import { updateNotifications, refreshNotifications } from './notifications';
 | 
				
			||||||
| 
						 | 
					@ -16,10 +15,6 @@ export function connectTimelineStream (timelineId, path, pollingRefresh = null)
 | 
				
			||||||
  return connectStream (path, pollingRefresh, (dispatch, getState) => {
 | 
					  return connectStream (path, pollingRefresh, (dispatch, getState) => {
 | 
				
			||||||
    const locale = getState().getIn(['meta', 'locale']);
 | 
					    const locale = getState().getIn(['meta', 'locale']);
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      onConnect() {
 | 
					 | 
				
			||||||
        dispatch(connectTimeline(timelineId));
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      onDisconnect() {
 | 
					      onDisconnect() {
 | 
				
			||||||
        dispatch(disconnectTimeline(timelineId));
 | 
					        dispatch(disconnectTimeline(timelineId));
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
| 
						 | 
					@ -42,7 +37,7 @@ export function connectTimelineStream (timelineId, path, pollingRefresh = null)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function refreshHomeTimelineAndNotification (dispatch) {
 | 
					function refreshHomeTimelineAndNotification (dispatch) {
 | 
				
			||||||
  dispatch(refreshHomeTimeline());
 | 
					  dispatch(expandHomeTimeline());
 | 
				
			||||||
  dispatch(refreshNotifications());
 | 
					  dispatch(refreshNotifications());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,36 +1,20 @@
 | 
				
			||||||
import { importFetchedStatus, importFetchedStatuses } from './importer';
 | 
					import { importFetchedStatus, importFetchedStatuses } from './importer';
 | 
				
			||||||
import api, { getLinks } from '../api';
 | 
					import api, { getLinks } from '../api';
 | 
				
			||||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
 | 
					import { Map as ImmutableMap } from 'immutable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const TIMELINE_UPDATE  = 'TIMELINE_UPDATE';
 | 
					export const TIMELINE_UPDATE  = 'TIMELINE_UPDATE';
 | 
				
			||||||
export const TIMELINE_DELETE  = 'TIMELINE_DELETE';
 | 
					export const TIMELINE_DELETE  = 'TIMELINE_DELETE';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const TIMELINE_REFRESH_REQUEST = 'TIMELINE_REFRESH_REQUEST';
 | 
					 | 
				
			||||||
export const TIMELINE_REFRESH_SUCCESS = 'TIMELINE_REFRESH_SUCCESS';
 | 
					 | 
				
			||||||
export const TIMELINE_REFRESH_FAIL    = 'TIMELINE_REFRESH_FAIL';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const TIMELINE_EXPAND_REQUEST = 'TIMELINE_EXPAND_REQUEST';
 | 
					export const TIMELINE_EXPAND_REQUEST = 'TIMELINE_EXPAND_REQUEST';
 | 
				
			||||||
export const TIMELINE_EXPAND_SUCCESS = 'TIMELINE_EXPAND_SUCCESS';
 | 
					export const TIMELINE_EXPAND_SUCCESS = 'TIMELINE_EXPAND_SUCCESS';
 | 
				
			||||||
export const TIMELINE_EXPAND_FAIL    = 'TIMELINE_EXPAND_FAIL';
 | 
					export const TIMELINE_EXPAND_FAIL    = 'TIMELINE_EXPAND_FAIL';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP';
 | 
					export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const TIMELINE_CONNECT    = 'TIMELINE_CONNECT';
 | 
					 | 
				
			||||||
export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT';
 | 
					export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const TIMELINE_CONTEXT_UPDATE = 'CONTEXT_UPDATE';
 | 
					export const TIMELINE_CONTEXT_UPDATE = 'CONTEXT_UPDATE';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function refreshTimelineSuccess(timeline, statuses, skipLoading, next, partial) {
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    type: TIMELINE_REFRESH_SUCCESS,
 | 
					 | 
				
			||||||
    timeline,
 | 
					 | 
				
			||||||
    statuses,
 | 
					 | 
				
			||||||
    skipLoading,
 | 
					 | 
				
			||||||
    next,
 | 
					 | 
				
			||||||
    partial,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function updateTimeline(timeline, status) {
 | 
					export function updateTimeline(timeline, status) {
 | 
				
			||||||
  return (dispatch, getState) => {
 | 
					  return (dispatch, getState) => {
 | 
				
			||||||
    const references = status.reblog ? getState().get('statuses').filter((item, itemId) => (itemId === status.reblog.id || item.get('reblog') === status.reblog.id)).map((_, itemId) => itemId) : [];
 | 
					    const references = status.reblog ? getState().get('statuses').filter((item, itemId) => (itemId === status.reblog.id || item.get('reblog') === status.reblog.id)).map((_, itemId) => itemId) : [];
 | 
				
			||||||
| 
						 | 
					@ -80,97 +64,34 @@ export function deleteFromTimelines(id) {
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function refreshTimelineRequest(timeline, skipLoading) {
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    type: TIMELINE_REFRESH_REQUEST,
 | 
					 | 
				
			||||||
    timeline,
 | 
					 | 
				
			||||||
    skipLoading,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function refreshTimeline(timelineId, path, params = {}) {
 | 
					 | 
				
			||||||
  return function (dispatch, getState) {
 | 
					 | 
				
			||||||
    const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (timeline.get('isLoading') || (timeline.get('online') && !timeline.get('isPartial'))) {
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const ids      = timeline.get('items', ImmutableList());
 | 
					 | 
				
			||||||
    const newestId = ids.size > 0 ? ids.first() : null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let skipLoading = timeline.get('loaded');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (newestId !== null) {
 | 
					 | 
				
			||||||
      params.since_id = newestId;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dispatch(refreshTimelineRequest(timelineId, skipLoading));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    api(getState).get(path, { params }).then(response => {
 | 
					 | 
				
			||||||
      if (response.status === 206) {
 | 
					 | 
				
			||||||
        dispatch(refreshTimelineSuccess(timelineId, [], skipLoading, null, true));
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        const next = getLinks(response).refs.find(link => link.rel === 'next');
 | 
					 | 
				
			||||||
        dispatch(importFetchedStatuses(response.data));
 | 
					 | 
				
			||||||
        dispatch(refreshTimelineSuccess(timelineId, response.data, skipLoading, next ? next.uri : null, false));
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }).catch(error => {
 | 
					 | 
				
			||||||
      dispatch(refreshTimelineFail(timelineId, error, skipLoading));
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const refreshHomeTimeline            = () => refreshTimeline('home', '/api/v1/timelines/home');
 | 
					 | 
				
			||||||
export const refreshPublicTimeline          = () => refreshTimeline('public', '/api/v1/timelines/public');
 | 
					 | 
				
			||||||
export const refreshCommunityTimeline       = () => refreshTimeline('community', '/api/v1/timelines/public', { local: true });
 | 
					 | 
				
			||||||
export const refreshAccountTimeline         = (accountId, withReplies) => refreshTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies });
 | 
					 | 
				
			||||||
export const refreshAccountFeaturedTimeline = accountId => refreshTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
 | 
					 | 
				
			||||||
export const refreshAccountMediaTimeline    = accountId => refreshTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { only_media: true });
 | 
					 | 
				
			||||||
export const refreshHashtagTimeline         = hashtag => refreshTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`);
 | 
					 | 
				
			||||||
export const refreshListTimeline            = id => refreshTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function refreshTimelineFail(timeline, error, skipLoading) {
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    type: TIMELINE_REFRESH_FAIL,
 | 
					 | 
				
			||||||
    timeline,
 | 
					 | 
				
			||||||
    error,
 | 
					 | 
				
			||||||
    skipLoading,
 | 
					 | 
				
			||||||
    skipAlert: error.response && error.response.status === 404,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function expandTimeline(timelineId, path, params = {}) {
 | 
					export function expandTimeline(timelineId, path, params = {}) {
 | 
				
			||||||
  return (dispatch, getState) => {
 | 
					  return (dispatch, getState) => {
 | 
				
			||||||
    const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
 | 
					    const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
 | 
				
			||||||
    const ids      = timeline.get('items', ImmutableList());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (timeline.get('isLoading') || ids.size === 0) {
 | 
					    if (timeline.get('isLoading')) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    params.max_id = ids.last();
 | 
					 | 
				
			||||||
    params.limit  = 10;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dispatch(expandTimelineRequest(timelineId));
 | 
					    dispatch(expandTimelineRequest(timelineId));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    api(getState).get(path, { params }).then(response => {
 | 
					    api(getState).get(path, { params }).then(response => {
 | 
				
			||||||
      const next = getLinks(response).refs.find(link => link.rel === 'next');
 | 
					      const next = getLinks(response).refs.find(link => link.rel === 'next');
 | 
				
			||||||
      dispatch(importFetchedStatuses(response.data));
 | 
					      dispatch(importFetchedStatuses(response.data));
 | 
				
			||||||
      dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null));
 | 
					      dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.code === 206));
 | 
				
			||||||
    }).catch(error => {
 | 
					    }).catch(error => {
 | 
				
			||||||
      dispatch(expandTimelineFail(timelineId, error));
 | 
					      dispatch(expandTimelineFail(timelineId, error));
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const expandHomeTimeline         = () => expandTimeline('home', '/api/v1/timelines/home');
 | 
					export const expandHomeTimeline         = ({ maxId } = {}) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId });
 | 
				
			||||||
export const expandPublicTimeline       = () => expandTimeline('public', '/api/v1/timelines/public');
 | 
					export const expandPublicTimeline       = ({ maxId } = {}) => expandTimeline('public', '/api/v1/timelines/public', { max_id: maxId });
 | 
				
			||||||
export const expandCommunityTimeline    = () => expandTimeline('community', '/api/v1/timelines/public', { local: true });
 | 
					export const expandCommunityTimeline    = ({ maxId } = {}) => expandTimeline('community', '/api/v1/timelines/public', { local: true, max_id: maxId });
 | 
				
			||||||
export const expandAccountTimeline      = (accountId, withReplies) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies });
 | 
					export const expandAccountTimeline      = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId });
 | 
				
			||||||
export const expandAccountMediaTimeline = accountId => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { only_media: true });
 | 
					export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
 | 
				
			||||||
export const expandHashtagTimeline      = hashtag => expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`);
 | 
					export const expandAccountMediaTimeline = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true });
 | 
				
			||||||
export const expandListTimeline         = id => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`);
 | 
					export const expandHashtagTimeline      = (hashtag, { maxId } = {}) => expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`, { max_id: maxId });
 | 
				
			||||||
 | 
					export const expandListTimeline         = (id, { maxId } = {}) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function expandTimelineRequest(timeline) {
 | 
					export function expandTimelineRequest(timeline) {
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
| 
						 | 
					@ -179,12 +100,13 @@ export function expandTimelineRequest(timeline) {
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function expandTimelineSuccess(timeline, statuses, next) {
 | 
					export function expandTimelineSuccess(timeline, statuses, next, partial) {
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    type: TIMELINE_EXPAND_SUCCESS,
 | 
					    type: TIMELINE_EXPAND_SUCCESS,
 | 
				
			||||||
    timeline,
 | 
					    timeline,
 | 
				
			||||||
    statuses,
 | 
					    statuses,
 | 
				
			||||||
    next,
 | 
					    next,
 | 
				
			||||||
 | 
					    partial,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -204,13 +126,6 @@ export function scrollTopTimeline(timeline, top) {
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function connectTimeline(timeline) {
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    type: TIMELINE_CONNECT,
 | 
					 | 
				
			||||||
    timeline,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function disconnectTimeline(timeline) {
 | 
					export function disconnectTimeline(timeline) {
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    type: TIMELINE_DISCONNECT,
 | 
					    type: TIMELINE_DISCONNECT,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ export default class LoadMore extends React.PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
    onClick: PropTypes.func,
 | 
					    onClick: PropTypes.func,
 | 
				
			||||||
 | 
					    disabled: PropTypes.bool,
 | 
				
			||||||
    visible: PropTypes.bool,
 | 
					    visible: PropTypes.bool,
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,10 +15,10 @@ export default class LoadMore extends React.PureComponent {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render() {
 | 
					  render() {
 | 
				
			||||||
    const { visible } = this.props;
 | 
					    const { disabled, visible } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <button className='load-more' disabled={!visible} style={{ visibility: visible ? 'visible' : 'hidden' }} onClick={this.props.onClick}>
 | 
					      <button className='load-more' disabled={disabled || !visible} style={{ visibility: visible ? 'visible' : 'hidden' }} onClick={this.props.onClick}>
 | 
				
			||||||
        <FormattedMessage id='status.load_more' defaultMessage='Load more' />
 | 
					        <FormattedMessage id='status.load_more' defaultMessage='Load more' />
 | 
				
			||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,7 @@ export default class ScrollableList extends PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
    scrollKey: PropTypes.string.isRequired,
 | 
					    scrollKey: PropTypes.string.isRequired,
 | 
				
			||||||
    onLoadMore: PropTypes.func.isRequired,
 | 
					    onLoadMore: PropTypes.func,
 | 
				
			||||||
    onScrollToTop: PropTypes.func,
 | 
					    onScrollToTop: PropTypes.func,
 | 
				
			||||||
    onScroll: PropTypes.func,
 | 
					    onScroll: PropTypes.func,
 | 
				
			||||||
    trackScroll: PropTypes.bool,
 | 
					    trackScroll: PropTypes.bool,
 | 
				
			||||||
| 
						 | 
					@ -148,11 +148,11 @@ export default class ScrollableList extends PureComponent {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { children, scrollKey, trackScroll, shouldUpdateScroll, isLoading, hasMore, prepend, emptyMessage } = this.props;
 | 
					    const { children, scrollKey, trackScroll, shouldUpdateScroll, isLoading, hasMore, prepend, emptyMessage, onLoadMore } = this.props;
 | 
				
			||||||
    const { fullscreen } = this.state;
 | 
					    const { fullscreen } = this.state;
 | 
				
			||||||
    const childrenCount = React.Children.count(children);
 | 
					    const childrenCount = React.Children.count(children);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const loadMore     = (hasMore && childrenCount > 0) ? <LoadMore visible={!isLoading} onClick={this.handleLoadMore} /> : null;
 | 
					    const loadMore     = (hasMore && childrenCount > 0 && onLoadMore) ? <LoadMore visible={!isLoading} onClick={this.handleLoadMore} /> : null;
 | 
				
			||||||
    let scrollableArea = null;
 | 
					    let scrollableArea = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (isLoading || childrenCount > 0 || !emptyMessage) {
 | 
					    if (isLoading || childrenCount > 0 || !emptyMessage) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,31 @@
 | 
				
			||||||
 | 
					import { debounce } from 'lodash';
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import StatusContainer from '../containers/status_container';
 | 
					import StatusContainer from '../containers/status_container';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					import LoadMore from './load_more';
 | 
				
			||||||
import ScrollableList from './scrollable_list';
 | 
					import ScrollableList from './scrollable_list';
 | 
				
			||||||
import { FormattedMessage } from 'react-intl';
 | 
					import { FormattedMessage } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LoadGap extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static propTypes = {
 | 
				
			||||||
 | 
					    disabled: PropTypes.bool,
 | 
				
			||||||
 | 
					    maxId: PropTypes.string,
 | 
				
			||||||
 | 
					    onClick: PropTypes.func.isRequired,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleClick = () => {
 | 
				
			||||||
 | 
					    this.props.onClick(this.props.maxId);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  render () {
 | 
				
			||||||
 | 
					    return <LoadMore onClick={this.handleClick} disabled={this.props.disabled} />;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class StatusList extends ImmutablePureComponent {
 | 
					export default class StatusList extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
| 
						 | 
					@ -38,6 +58,10 @@ export default class StatusList extends ImmutablePureComponent {
 | 
				
			||||||
    this._selectChild(elementIndex);
 | 
					    this._selectChild(elementIndex);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleLoadOlder = debounce(() => {
 | 
				
			||||||
 | 
					    this.props.onLoadMore(this.props.statusIds.last());
 | 
				
			||||||
 | 
					  }, 300, { leading: true })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _selectChild (index) {
 | 
					  _selectChild (index) {
 | 
				
			||||||
    const element = this.node.node.querySelector(`article:nth-of-type(${index + 1}) .focusable`);
 | 
					    const element = this.node.node.querySelector(`article:nth-of-type(${index + 1}) .focusable`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,7 +75,7 @@ export default class StatusList extends ImmutablePureComponent {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { statusIds, featuredStatusIds, ...other }  = this.props;
 | 
					    const { statusIds, featuredStatusIds, onLoadMore, ...other }  = this.props;
 | 
				
			||||||
    const { isLoading, isPartial } = other;
 | 
					    const { isLoading, isPartial } = other;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (isPartial) {
 | 
					    if (isPartial) {
 | 
				
			||||||
| 
						 | 
					@ -70,7 +94,14 @@ export default class StatusList extends ImmutablePureComponent {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let scrollableContent = (isLoading || statusIds.size > 0) ? (
 | 
					    let scrollableContent = (isLoading || statusIds.size > 0) ? (
 | 
				
			||||||
      statusIds.map(statusId => (
 | 
					      statusIds.map((statusId, index) => statusId === null ? (
 | 
				
			||||||
 | 
					        <LoadGap
 | 
				
			||||||
 | 
					          key={'gap:' + statusIds.get(index + 1)}
 | 
				
			||||||
 | 
					          disabled={isLoading}
 | 
				
			||||||
 | 
					          maxId={index > 0 ? statusIds.get(index - 1) : null}
 | 
				
			||||||
 | 
					          onClick={onLoadMore}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      ) : (
 | 
				
			||||||
        <StatusContainer
 | 
					        <StatusContainer
 | 
				
			||||||
          key={statusId}
 | 
					          key={statusId}
 | 
				
			||||||
          id={statusId}
 | 
					          id={statusId}
 | 
				
			||||||
| 
						 | 
					@ -93,7 +124,7 @@ export default class StatusList extends ImmutablePureComponent {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <ScrollableList {...other} ref={this.setRef}>
 | 
					      <ScrollableList {...other} onLoadMore={onLoadMore && this.handleLoadOlder} ref={this.setRef}>
 | 
				
			||||||
        {scrollableContent}
 | 
					        {scrollableContent}
 | 
				
			||||||
      </ScrollableList>
 | 
					      </ScrollableList>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@ import { connect } from 'react-redux';
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import { fetchAccount } from '../../actions/accounts';
 | 
					import { fetchAccount } from '../../actions/accounts';
 | 
				
			||||||
import { refreshAccountMediaTimeline, expandAccountMediaTimeline } from '../../actions/timelines';
 | 
					import { expandAccountMediaTimeline } from '../../actions/timelines';
 | 
				
			||||||
import LoadingIndicator from '../../components/loading_indicator';
 | 
					import LoadingIndicator from '../../components/loading_indicator';
 | 
				
			||||||
import Column from '../ui/components/column';
 | 
					import Column from '../ui/components/column';
 | 
				
			||||||
import ColumnBackButton from '../../components/column_back_button';
 | 
					import ColumnBackButton from '../../components/column_back_button';
 | 
				
			||||||
| 
						 | 
					@ -17,9 +17,31 @@ import LoadMore from '../../components/load_more';
 | 
				
			||||||
const mapStateToProps = (state, props) => ({
 | 
					const mapStateToProps = (state, props) => ({
 | 
				
			||||||
  medias: getAccountGallery(state, props.params.accountId),
 | 
					  medias: getAccountGallery(state, props.params.accountId),
 | 
				
			||||||
  isLoading: state.getIn(['timelines', `account:${props.params.accountId}:media`, 'isLoading']),
 | 
					  isLoading: state.getIn(['timelines', `account:${props.params.accountId}:media`, 'isLoading']),
 | 
				
			||||||
  hasMore: !!state.getIn(['timelines', `account:${props.params.accountId}:media`, 'next']),
 | 
					  hasMore:   state.getIn(['timelines', `account:${props.params.accountId}:media`, 'hasMore']),
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LoadMoreMedia extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static propTypes = {
 | 
				
			||||||
 | 
					    maxId: PropTypes.string,
 | 
				
			||||||
 | 
					    onLoadMore: PropTypes.func.isRequired,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleLoadMore = () => {
 | 
				
			||||||
 | 
					    this.props.onLoadMore(this.props.maxId);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  render () {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <LoadMore
 | 
				
			||||||
 | 
					        disabled={this.props.disabled}
 | 
				
			||||||
 | 
					        onLoadMore={this.handleLoadMore}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@connect(mapStateToProps)
 | 
					@connect(mapStateToProps)
 | 
				
			||||||
export default class AccountGallery extends ImmutablePureComponent {
 | 
					export default class AccountGallery extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,19 +55,19 @@ export default class AccountGallery extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentDidMount () {
 | 
					  componentDidMount () {
 | 
				
			||||||
    this.props.dispatch(fetchAccount(this.props.params.accountId));
 | 
					    this.props.dispatch(fetchAccount(this.props.params.accountId));
 | 
				
			||||||
    this.props.dispatch(refreshAccountMediaTimeline(this.props.params.accountId));
 | 
					    this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentWillReceiveProps (nextProps) {
 | 
					  componentWillReceiveProps (nextProps) {
 | 
				
			||||||
    if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) {
 | 
					    if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) {
 | 
				
			||||||
      this.props.dispatch(fetchAccount(nextProps.params.accountId));
 | 
					      this.props.dispatch(fetchAccount(nextProps.params.accountId));
 | 
				
			||||||
      this.props.dispatch(refreshAccountMediaTimeline(this.props.params.accountId));
 | 
					      this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleScrollToBottom = () => {
 | 
					  handleScrollToBottom = () => {
 | 
				
			||||||
    if (this.props.hasMore) {
 | 
					    if (this.props.hasMore) {
 | 
				
			||||||
      this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId));
 | 
					      this.handleLoadMore(this.props.medias.last().get('id'));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,7 +80,11 @@ export default class AccountGallery extends ImmutablePureComponent {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleLoadMore = (e) => {
 | 
					  handleLoadMore = maxId => {
 | 
				
			||||||
 | 
					    this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId, { maxId }));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleLoadOlder = (e) => {
 | 
				
			||||||
    e.preventDefault();
 | 
					    e.preventDefault();
 | 
				
			||||||
    this.handleScrollToBottom();
 | 
					    this.handleScrollToBottom();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -66,7 +92,7 @@ export default class AccountGallery extends ImmutablePureComponent {
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { medias, isLoading, hasMore } = this.props;
 | 
					    const { medias, isLoading, hasMore } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let loadMore = null;
 | 
					    let loadOlder = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!medias && isLoading) {
 | 
					    if (!medias && isLoading) {
 | 
				
			||||||
      return (
 | 
					      return (
 | 
				
			||||||
| 
						 | 
					@ -77,7 +103,7 @@ export default class AccountGallery extends ImmutablePureComponent {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!isLoading && medias.size > 0 && hasMore) {
 | 
					    if (!isLoading && medias.size > 0 && hasMore) {
 | 
				
			||||||
      loadMore = <LoadMore onClick={this.handleLoadMore} />;
 | 
					      loadOlder = <LoadMore onClick={this.handleLoadOlder} />;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
| 
						 | 
					@ -89,13 +115,18 @@ export default class AccountGallery extends ImmutablePureComponent {
 | 
				
			||||||
            <HeaderContainer accountId={this.props.params.accountId} />
 | 
					            <HeaderContainer accountId={this.props.params.accountId} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <div className='account-gallery__container'>
 | 
					            <div className='account-gallery__container'>
 | 
				
			||||||
              {medias.map(media => (
 | 
					              {medias.map((media, index) => media === null ? (
 | 
				
			||||||
 | 
					                <LoadMoreMedia
 | 
				
			||||||
 | 
					                  key={'more:' + medias.getIn(index + 1, 'id')}
 | 
				
			||||||
 | 
					                  maxId={index > 0 ? medias.getIn(index - 1, 'id') : null}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              ) : (
 | 
				
			||||||
                <MediaItem
 | 
					                <MediaItem
 | 
				
			||||||
                  key={media.get('id')}
 | 
					                  key={media.get('id')}
 | 
				
			||||||
                  media={media}
 | 
					                  media={media}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
              ))}
 | 
					              ))}
 | 
				
			||||||
              {loadMore}
 | 
					              {loadOlder}
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </ScrollContainer>
 | 
					        </ScrollContainer>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@ import { connect } from 'react-redux';
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import { fetchAccount } from '../../actions/accounts';
 | 
					import { fetchAccount } from '../../actions/accounts';
 | 
				
			||||||
import { refreshAccountTimeline, refreshAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines';
 | 
					import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines';
 | 
				
			||||||
import StatusList from '../../components/status_list';
 | 
					import StatusList from '../../components/status_list';
 | 
				
			||||||
import LoadingIndicator from '../../components/loading_indicator';
 | 
					import LoadingIndicator from '../../components/loading_indicator';
 | 
				
			||||||
import Column from '../ui/components/column';
 | 
					import Column from '../ui/components/column';
 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,7 @@ const mapStateToProps = (state, { params: { accountId }, withReplies = false })
 | 
				
			||||||
    statusIds: state.getIn(['timelines', `account:${path}`, 'items'], ImmutableList()),
 | 
					    statusIds: state.getIn(['timelines', `account:${path}`, 'items'], ImmutableList()),
 | 
				
			||||||
    featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], ImmutableList()),
 | 
					    featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], ImmutableList()),
 | 
				
			||||||
    isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
 | 
					    isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
 | 
				
			||||||
    hasMore: !!state.getIn(['timelines', `account:${path}`, 'next']),
 | 
					    hasMore:   state.getIn(['timelines', `account:${path}`, 'hasMore']),
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,25 +41,23 @@ export default class AccountTimeline extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.props.dispatch(fetchAccount(accountId));
 | 
					    this.props.dispatch(fetchAccount(accountId));
 | 
				
			||||||
    if (!withReplies) {
 | 
					    if (!withReplies) {
 | 
				
			||||||
      this.props.dispatch(refreshAccountFeaturedTimeline(accountId));
 | 
					      this.props.dispatch(expandAccountFeaturedTimeline(accountId));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.props.dispatch(refreshAccountTimeline(accountId, withReplies));
 | 
					    this.props.dispatch(expandAccountTimeline(accountId, { withReplies }));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentWillReceiveProps (nextProps) {
 | 
					  componentWillReceiveProps (nextProps) {
 | 
				
			||||||
    if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) {
 | 
					    if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) {
 | 
				
			||||||
      this.props.dispatch(fetchAccount(nextProps.params.accountId));
 | 
					      this.props.dispatch(fetchAccount(nextProps.params.accountId));
 | 
				
			||||||
      if (!nextProps.withReplies) {
 | 
					      if (!nextProps.withReplies) {
 | 
				
			||||||
        this.props.dispatch(refreshAccountFeaturedTimeline(nextProps.params.accountId));
 | 
					        this.props.dispatch(expandAccountFeaturedTimeline(nextProps.params.accountId));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      this.props.dispatch(refreshAccountTimeline(nextProps.params.accountId, nextProps.params.withReplies));
 | 
					      this.props.dispatch(expandAccountTimeline(nextProps.params.accountId, { withReplies: nextProps.params.withReplies }));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleLoadMore = () => {
 | 
					  handleLoadMore = maxId => {
 | 
				
			||||||
    if (!this.props.isLoading && this.props.hasMore) {
 | 
					    this.props.dispatch(expandAccountTimeline(this.props.params.accountId, { maxId, withReplies: this.props.withReplies }));
 | 
				
			||||||
      this.props.dispatch(expandAccountTimeline(this.props.params.accountId, this.props.withReplies));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,10 +4,7 @@ import PropTypes from 'prop-types';
 | 
				
			||||||
import StatusListContainer from '../ui/containers/status_list_container';
 | 
					import StatusListContainer from '../ui/containers/status_list_container';
 | 
				
			||||||
import Column from '../../components/column';
 | 
					import Column from '../../components/column';
 | 
				
			||||||
import ColumnHeader from '../../components/column_header';
 | 
					import ColumnHeader from '../../components/column_header';
 | 
				
			||||||
import {
 | 
					import { expandCommunityTimeline } from '../../actions/timelines';
 | 
				
			||||||
  refreshCommunityTimeline,
 | 
					 | 
				
			||||||
  expandCommunityTimeline,
 | 
					 | 
				
			||||||
} from '../../actions/timelines';
 | 
					 | 
				
			||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
 | 
					import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
 | 
				
			||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
					import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
				
			||||||
import ColumnSettingsContainer from './containers/column_settings_container';
 | 
					import ColumnSettingsContainer from './containers/column_settings_container';
 | 
				
			||||||
| 
						 | 
					@ -55,7 +52,7 @@ export default class CommunityTimeline extends React.PureComponent {
 | 
				
			||||||
  componentDidMount () {
 | 
					  componentDidMount () {
 | 
				
			||||||
    const { dispatch } = this.props;
 | 
					    const { dispatch } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dispatch(refreshCommunityTimeline());
 | 
					    dispatch(expandCommunityTimeline());
 | 
				
			||||||
    this.disconnect = dispatch(connectCommunityStream());
 | 
					    this.disconnect = dispatch(connectCommunityStream());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,8 +67,8 @@ export default class CommunityTimeline extends React.PureComponent {
 | 
				
			||||||
    this.column = c;
 | 
					    this.column = c;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleLoadMore = () => {
 | 
					  handleLoadMore = maxId => {
 | 
				
			||||||
    this.props.dispatch(expandCommunityTimeline());
 | 
					    this.props.dispatch(expandCommunityTimeline({ maxId }));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
| 
						 | 
					@ -97,7 +94,7 @@ export default class CommunityTimeline extends React.PureComponent {
 | 
				
			||||||
          trackScroll={!pinned}
 | 
					          trackScroll={!pinned}
 | 
				
			||||||
          scrollKey={`community_timeline-${columnId}`}
 | 
					          scrollKey={`community_timeline-${columnId}`}
 | 
				
			||||||
          timelineId='community'
 | 
					          timelineId='community'
 | 
				
			||||||
          loadMore={this.handleLoadMore}
 | 
					          onLoadMore={this.handleLoadMore}
 | 
				
			||||||
          emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
 | 
					          emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </Column>
 | 
					      </Column>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,10 +4,7 @@ import PropTypes from 'prop-types';
 | 
				
			||||||
import StatusListContainer from '../ui/containers/status_list_container';
 | 
					import StatusListContainer from '../ui/containers/status_list_container';
 | 
				
			||||||
import Column from '../../components/column';
 | 
					import Column from '../../components/column';
 | 
				
			||||||
import ColumnHeader from '../../components/column_header';
 | 
					import ColumnHeader from '../../components/column_header';
 | 
				
			||||||
import {
 | 
					import { expandHashtagTimeline } from '../../actions/timelines';
 | 
				
			||||||
  refreshHashtagTimeline,
 | 
					 | 
				
			||||||
  expandHashtagTimeline,
 | 
					 | 
				
			||||||
} from '../../actions/timelines';
 | 
					 | 
				
			||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
 | 
					import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
 | 
				
			||||||
import { FormattedMessage } from 'react-intl';
 | 
					import { FormattedMessage } from 'react-intl';
 | 
				
			||||||
import { connectHashtagStream } from '../../actions/streaming';
 | 
					import { connectHashtagStream } from '../../actions/streaming';
 | 
				
			||||||
| 
						 | 
					@ -61,13 +58,13 @@ export default class HashtagTimeline extends React.PureComponent {
 | 
				
			||||||
    const { dispatch } = this.props;
 | 
					    const { dispatch } = this.props;
 | 
				
			||||||
    const { id } = this.props.params;
 | 
					    const { id } = this.props.params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dispatch(refreshHashtagTimeline(id));
 | 
					    dispatch(expandHashtagTimeline(id));
 | 
				
			||||||
    this._subscribe(dispatch, id);
 | 
					    this._subscribe(dispatch, id);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentWillReceiveProps (nextProps) {
 | 
					  componentWillReceiveProps (nextProps) {
 | 
				
			||||||
    if (nextProps.params.id !== this.props.params.id) {
 | 
					    if (nextProps.params.id !== this.props.params.id) {
 | 
				
			||||||
      this.props.dispatch(refreshHashtagTimeline(nextProps.params.id));
 | 
					      this.props.dispatch(expandHashtagTimeline(nextProps.params.id));
 | 
				
			||||||
      this._unsubscribe();
 | 
					      this._unsubscribe();
 | 
				
			||||||
      this._subscribe(this.props.dispatch, nextProps.params.id);
 | 
					      this._subscribe(this.props.dispatch, nextProps.params.id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -81,8 +78,8 @@ export default class HashtagTimeline extends React.PureComponent {
 | 
				
			||||||
    this.column = c;
 | 
					    this.column = c;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleLoadMore = () => {
 | 
					  handleLoadMore = maxId => {
 | 
				
			||||||
    this.props.dispatch(expandHashtagTimeline(this.props.params.id));
 | 
					    this.props.dispatch(expandHashtagTimeline(this.props.params.id, { maxId }));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
| 
						 | 
					@ -108,7 +105,7 @@ export default class HashtagTimeline extends React.PureComponent {
 | 
				
			||||||
          trackScroll={!pinned}
 | 
					          trackScroll={!pinned}
 | 
				
			||||||
          scrollKey={`hashtag_timeline-${columnId}`}
 | 
					          scrollKey={`hashtag_timeline-${columnId}`}
 | 
				
			||||||
          timelineId={`hashtag:${id}`}
 | 
					          timelineId={`hashtag:${id}`}
 | 
				
			||||||
          loadMore={this.handleLoadMore}
 | 
					          onLoadMore={this.handleLoadMore}
 | 
				
			||||||
          emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />}
 | 
					          emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </Column>
 | 
					      </Column>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import { expandHomeTimeline, refreshHomeTimeline } from '../../actions/timelines';
 | 
					import { expandHomeTimeline } from '../../actions/timelines';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import StatusListContainer from '../ui/containers/status_list_container';
 | 
					import StatusListContainer from '../ui/containers/status_list_container';
 | 
				
			||||||
import Column from '../../components/column';
 | 
					import Column from '../../components/column';
 | 
				
			||||||
| 
						 | 
					@ -16,7 +16,7 @@ const messages = defineMessages({
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapStateToProps = state => ({
 | 
					const mapStateToProps = state => ({
 | 
				
			||||||
  hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0,
 | 
					  hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0,
 | 
				
			||||||
  isPartial: state.getIn(['timelines', 'home', 'isPartial'], false),
 | 
					  isPartial: state.getIn(['timelines', 'home', 'items', 0], null) === null,
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@connect(mapStateToProps)
 | 
					@connect(mapStateToProps)
 | 
				
			||||||
| 
						 | 
					@ -55,8 +55,8 @@ export default class HomeTimeline extends React.PureComponent {
 | 
				
			||||||
    this.column = c;
 | 
					    this.column = c;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleLoadMore = () => {
 | 
					  handleLoadMore = maxId => {
 | 
				
			||||||
    this.props.dispatch(expandHomeTimeline());
 | 
					    this.props.dispatch(expandHomeTimeline({ maxId }));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentDidMount () {
 | 
					  componentDidMount () {
 | 
				
			||||||
| 
						 | 
					@ -78,7 +78,7 @@ export default class HomeTimeline extends React.PureComponent {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    } else if (!wasPartial && isPartial) {
 | 
					    } else if (!wasPartial && isPartial) {
 | 
				
			||||||
      this.polling = setInterval(() => {
 | 
					      this.polling = setInterval(() => {
 | 
				
			||||||
        dispatch(refreshHomeTimeline());
 | 
					        dispatch(expandHomeTimeline());
 | 
				
			||||||
      }, 3000);
 | 
					      }, 3000);
 | 
				
			||||||
    } else if (wasPartial && !isPartial) {
 | 
					    } else if (wasPartial && !isPartial) {
 | 
				
			||||||
      this._stopPolling();
 | 
					      this._stopPolling();
 | 
				
			||||||
| 
						 | 
					@ -114,7 +114,7 @@ export default class HomeTimeline extends React.PureComponent {
 | 
				
			||||||
        <StatusListContainer
 | 
					        <StatusListContainer
 | 
				
			||||||
          trackScroll={!pinned}
 | 
					          trackScroll={!pinned}
 | 
				
			||||||
          scrollKey={`home_timeline-${columnId}`}
 | 
					          scrollKey={`home_timeline-${columnId}`}
 | 
				
			||||||
          loadMore={this.handleLoadMore}
 | 
					          onLoadMore={this.handleLoadMore}
 | 
				
			||||||
          timelineId='home'
 | 
					          timelineId='home'
 | 
				
			||||||
          emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage='Your home timeline is empty! Visit {public} or use search to get started and meet other users.' values={{ public: <Link to='/timelines/public'><FormattedMessage id='empty_column.home.public_timeline' defaultMessage='the public timeline' /></Link> }} />}
 | 
					          emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage='Your home timeline is empty! Visit {public} or use search to get started and meet other users.' values={{ public: <Link to='/timelines/public'><FormattedMessage id='empty_column.home.public_timeline' defaultMessage='the public timeline' /></Link> }} />}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ import ColumnHeader from '../../components/column_header';
 | 
				
			||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
 | 
					import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
 | 
				
			||||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
 | 
					import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
 | 
				
			||||||
import { connectListStream } from '../../actions/streaming';
 | 
					import { connectListStream } from '../../actions/streaming';
 | 
				
			||||||
import { refreshListTimeline, expandListTimeline } from '../../actions/timelines';
 | 
					import { expandListTimeline } from '../../actions/timelines';
 | 
				
			||||||
import { fetchList, deleteList } from '../../actions/lists';
 | 
					import { fetchList, deleteList } from '../../actions/lists';
 | 
				
			||||||
import { openModal } from '../../actions/modal';
 | 
					import { openModal } from '../../actions/modal';
 | 
				
			||||||
import MissingIndicator from '../../components/missing_indicator';
 | 
					import MissingIndicator from '../../components/missing_indicator';
 | 
				
			||||||
| 
						 | 
					@ -67,7 +67,7 @@ export default class ListTimeline extends React.PureComponent {
 | 
				
			||||||
    const { id } = this.props.params;
 | 
					    const { id } = this.props.params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dispatch(fetchList(id));
 | 
					    dispatch(fetchList(id));
 | 
				
			||||||
    dispatch(refreshListTimeline(id));
 | 
					    dispatch(expandListTimeline(id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.disconnect = dispatch(connectListStream(id));
 | 
					    this.disconnect = dispatch(connectListStream(id));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -83,9 +83,9 @@ export default class ListTimeline extends React.PureComponent {
 | 
				
			||||||
    this.column = c;
 | 
					    this.column = c;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleLoadMore = () => {
 | 
					  handleLoadMore = maxId => {
 | 
				
			||||||
    const { id } = this.props.params;
 | 
					    const { id } = this.props.params;
 | 
				
			||||||
    this.props.dispatch(expandListTimeline(id));
 | 
					    this.props.dispatch(expandListTimeline(id, { maxId }));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleEditClick = () => {
 | 
					  handleEditClick = () => {
 | 
				
			||||||
| 
						 | 
					@ -164,7 +164,7 @@ export default class ListTimeline extends React.PureComponent {
 | 
				
			||||||
          trackScroll={!pinned}
 | 
					          trackScroll={!pinned}
 | 
				
			||||||
          scrollKey={`list_timeline-${columnId}`}
 | 
					          scrollKey={`list_timeline-${columnId}`}
 | 
				
			||||||
          timelineId={`list:${id}`}
 | 
					          timelineId={`list:${id}`}
 | 
				
			||||||
          loadMore={this.handleLoadMore}
 | 
					          onLoadMore={this.handleLoadMore}
 | 
				
			||||||
          emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet. When members of this list post new statuses, they will appear here.' />}
 | 
					          emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet. When members of this list post new statuses, they will appear here.' />}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </Column>
 | 
					      </Column>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,10 +4,7 @@ import PropTypes from 'prop-types';
 | 
				
			||||||
import StatusListContainer from '../ui/containers/status_list_container';
 | 
					import StatusListContainer from '../ui/containers/status_list_container';
 | 
				
			||||||
import Column from '../../components/column';
 | 
					import Column from '../../components/column';
 | 
				
			||||||
import ColumnHeader from '../../components/column_header';
 | 
					import ColumnHeader from '../../components/column_header';
 | 
				
			||||||
import {
 | 
					import { expandPublicTimeline } from '../../actions/timelines';
 | 
				
			||||||
  refreshPublicTimeline,
 | 
					 | 
				
			||||||
  expandPublicTimeline,
 | 
					 | 
				
			||||||
} from '../../actions/timelines';
 | 
					 | 
				
			||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
 | 
					import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
 | 
				
			||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
					import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
				
			||||||
import ColumnSettingsContainer from './containers/column_settings_container';
 | 
					import ColumnSettingsContainer from './containers/column_settings_container';
 | 
				
			||||||
| 
						 | 
					@ -55,7 +52,7 @@ export default class PublicTimeline extends React.PureComponent {
 | 
				
			||||||
  componentDidMount () {
 | 
					  componentDidMount () {
 | 
				
			||||||
    const { dispatch } = this.props;
 | 
					    const { dispatch } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dispatch(refreshPublicTimeline());
 | 
					    dispatch(expandPublicTimeline());
 | 
				
			||||||
    this.disconnect = dispatch(connectPublicStream());
 | 
					    this.disconnect = dispatch(connectPublicStream());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,8 +67,8 @@ export default class PublicTimeline extends React.PureComponent {
 | 
				
			||||||
    this.column = c;
 | 
					    this.column = c;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleLoadMore = () => {
 | 
					  handleLoadMore = maxId => {
 | 
				
			||||||
    this.props.dispatch(expandPublicTimeline());
 | 
					    this.props.dispatch(expandPublicTimeline({ maxId }));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
| 
						 | 
					@ -95,7 +92,7 @@ export default class PublicTimeline extends React.PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <StatusListContainer
 | 
					        <StatusListContainer
 | 
				
			||||||
          timelineId='public'
 | 
					          timelineId='public'
 | 
				
			||||||
          loadMore={this.handleLoadMore}
 | 
					          onLoadMore={this.handleLoadMore}
 | 
				
			||||||
          trackScroll={!pinned}
 | 
					          trackScroll={!pinned}
 | 
				
			||||||
          scrollKey={`public_timeline-${columnId}`}
 | 
					          scrollKey={`public_timeline-${columnId}`}
 | 
				
			||||||
          emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other instances to fill it up' />}
 | 
					          emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other instances to fill it up' />}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,7 @@ import React from 'react';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import StatusListContainer from '../../ui/containers/status_list_container';
 | 
					import StatusListContainer from '../../ui/containers/status_list_container';
 | 
				
			||||||
import {
 | 
					import { expandCommunityTimeline } from '../../../actions/timelines';
 | 
				
			||||||
  refreshCommunityTimeline,
 | 
					 | 
				
			||||||
  expandCommunityTimeline,
 | 
					 | 
				
			||||||
} from '../../../actions/timelines';
 | 
					 | 
				
			||||||
import Column from '../../../components/column';
 | 
					import Column from '../../../components/column';
 | 
				
			||||||
import ColumnHeader from '../../../components/column_header';
 | 
					import ColumnHeader from '../../../components/column_header';
 | 
				
			||||||
import { defineMessages, injectIntl } from 'react-intl';
 | 
					import { defineMessages, injectIntl } from 'react-intl';
 | 
				
			||||||
| 
						 | 
					@ -35,7 +32,7 @@ export default class CommunityTimeline extends React.PureComponent {
 | 
				
			||||||
  componentDidMount () {
 | 
					  componentDidMount () {
 | 
				
			||||||
    const { dispatch } = this.props;
 | 
					    const { dispatch } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dispatch(refreshCommunityTimeline());
 | 
					    dispatch(expandCommunityTimeline());
 | 
				
			||||||
    this.disconnect = dispatch(connectCommunityStream());
 | 
					    this.disconnect = dispatch(connectCommunityStream());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,8 +43,8 @@ export default class CommunityTimeline extends React.PureComponent {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleLoadMore = () => {
 | 
					  handleLoadMore = maxId => {
 | 
				
			||||||
    this.props.dispatch(expandCommunityTimeline());
 | 
					    this.props.dispatch(expandCommunityTimeline({ maxId }));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
| 
						 | 
					@ -63,7 +60,7 @@ export default class CommunityTimeline extends React.PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <StatusListContainer
 | 
					        <StatusListContainer
 | 
				
			||||||
          timelineId='community'
 | 
					          timelineId='community'
 | 
				
			||||||
          loadMore={this.handleLoadMore}
 | 
					          onLoadMore={this.handleLoadMore}
 | 
				
			||||||
          scrollKey='standalone_public_timeline'
 | 
					          scrollKey='standalone_public_timeline'
 | 
				
			||||||
          trackScroll={false}
 | 
					          trackScroll={false}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,7 @@ import React from 'react';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import StatusListContainer from '../../ui/containers/status_list_container';
 | 
					import StatusListContainer from '../../ui/containers/status_list_container';
 | 
				
			||||||
import {
 | 
					import { expandHashtagTimeline } from '../../../actions/timelines';
 | 
				
			||||||
  refreshHashtagTimeline,
 | 
					 | 
				
			||||||
  expandHashtagTimeline,
 | 
					 | 
				
			||||||
} from '../../../actions/timelines';
 | 
					 | 
				
			||||||
import Column from '../../../components/column';
 | 
					import Column from '../../../components/column';
 | 
				
			||||||
import ColumnHeader from '../../../components/column_header';
 | 
					import ColumnHeader from '../../../components/column_header';
 | 
				
			||||||
import { connectHashtagStream } from '../../../actions/streaming';
 | 
					import { connectHashtagStream } from '../../../actions/streaming';
 | 
				
			||||||
| 
						 | 
					@ -29,7 +26,7 @@ export default class HashtagTimeline extends React.PureComponent {
 | 
				
			||||||
  componentDidMount () {
 | 
					  componentDidMount () {
 | 
				
			||||||
    const { dispatch, hashtag } = this.props;
 | 
					    const { dispatch, hashtag } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dispatch(refreshHashtagTimeline(hashtag));
 | 
					    dispatch(expandHashtagTimeline(hashtag));
 | 
				
			||||||
    this.disconnect = dispatch(connectHashtagStream(hashtag));
 | 
					    this.disconnect = dispatch(connectHashtagStream(hashtag));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,8 +37,8 @@ export default class HashtagTimeline extends React.PureComponent {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleLoadMore = () => {
 | 
					  handleLoadMore = maxId => {
 | 
				
			||||||
    this.props.dispatch(expandHashtagTimeline(this.props.hashtag));
 | 
					    this.props.dispatch(expandHashtagTimeline(this.props.hashtag, { maxId }));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
| 
						 | 
					@ -59,7 +56,7 @@ export default class HashtagTimeline extends React.PureComponent {
 | 
				
			||||||
          trackScroll={false}
 | 
					          trackScroll={false}
 | 
				
			||||||
          scrollKey='standalone_hashtag_timeline'
 | 
					          scrollKey='standalone_hashtag_timeline'
 | 
				
			||||||
          timelineId={`hashtag:${hashtag}`}
 | 
					          timelineId={`hashtag:${hashtag}`}
 | 
				
			||||||
          loadMore={this.handleLoadMore}
 | 
					          onLoadMore={this.handleLoadMore}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </Column>
 | 
					      </Column>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,7 @@ import React from 'react';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import StatusListContainer from '../../ui/containers/status_list_container';
 | 
					import StatusListContainer from '../../ui/containers/status_list_container';
 | 
				
			||||||
import {
 | 
					import { expandPublicTimeline } from '../../../actions/timelines';
 | 
				
			||||||
  refreshPublicTimeline,
 | 
					 | 
				
			||||||
  expandPublicTimeline,
 | 
					 | 
				
			||||||
} from '../../../actions/timelines';
 | 
					 | 
				
			||||||
import Column from '../../../components/column';
 | 
					import Column from '../../../components/column';
 | 
				
			||||||
import ColumnHeader from '../../../components/column_header';
 | 
					import ColumnHeader from '../../../components/column_header';
 | 
				
			||||||
import { defineMessages, injectIntl } from 'react-intl';
 | 
					import { defineMessages, injectIntl } from 'react-intl';
 | 
				
			||||||
| 
						 | 
					@ -35,7 +32,7 @@ export default class PublicTimeline extends React.PureComponent {
 | 
				
			||||||
  componentDidMount () {
 | 
					  componentDidMount () {
 | 
				
			||||||
    const { dispatch } = this.props;
 | 
					    const { dispatch } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dispatch(refreshPublicTimeline());
 | 
					    dispatch(expandPublicTimeline());
 | 
				
			||||||
    this.disconnect = dispatch(connectPublicStream());
 | 
					    this.disconnect = dispatch(connectPublicStream());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,8 +43,8 @@ export default class PublicTimeline extends React.PureComponent {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleLoadMore = () => {
 | 
					  handleLoadMore = maxId => {
 | 
				
			||||||
    this.props.dispatch(expandPublicTimeline());
 | 
					    this.props.dispatch(expandPublicTimeline({ maxId }));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
| 
						 | 
					@ -63,7 +60,7 @@ export default class PublicTimeline extends React.PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <StatusListContainer
 | 
					        <StatusListContainer
 | 
				
			||||||
          timelineId='public'
 | 
					          timelineId='public'
 | 
				
			||||||
          loadMore={this.handleLoadMore}
 | 
					          onLoadMore={this.handleLoadMore}
 | 
				
			||||||
          scrollKey='standalone_public_timeline'
 | 
					          scrollKey='standalone_public_timeline'
 | 
				
			||||||
          trackScroll={false}
 | 
					          trackScroll={false}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import { changeReportComment, changeReportForward, submitReport } from '../../../actions/reports';
 | 
					import { changeReportComment, changeReportForward, submitReport } from '../../../actions/reports';
 | 
				
			||||||
import { refreshAccountTimeline } from '../../../actions/timelines';
 | 
					import { expandAccountTimeline } from '../../../actions/timelines';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import { makeGetAccount } from '../../../selectors';
 | 
					import { makeGetAccount } from '../../../selectors';
 | 
				
			||||||
| 
						 | 
					@ -64,12 +64,12 @@ export default class ReportModal extends ImmutablePureComponent {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentDidMount () {
 | 
					  componentDidMount () {
 | 
				
			||||||
    this.props.dispatch(refreshAccountTimeline(this.props.account.get('id')));
 | 
					    this.props.dispatch(expandAccountTimeline(this.props.account.get('id')));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentWillReceiveProps (nextProps) {
 | 
					  componentWillReceiveProps (nextProps) {
 | 
				
			||||||
    if (this.props.account !== nextProps.account && nextProps.account) {
 | 
					    if (this.props.account !== nextProps.account && nextProps.account) {
 | 
				
			||||||
      this.props.dispatch(refreshAccountTimeline(nextProps.account.get('id')));
 | 
					      this.props.dispatch(expandAccountTimeline(nextProps.account.get('id')));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,15 +48,13 @@ const makeMapStateToProps = () => {
 | 
				
			||||||
    statusIds: getStatusIds(state, { type: timelineId }),
 | 
					    statusIds: getStatusIds(state, { type: timelineId }),
 | 
				
			||||||
    isLoading: state.getIn(['timelines', timelineId, 'isLoading'], true),
 | 
					    isLoading: state.getIn(['timelines', timelineId, 'isLoading'], true),
 | 
				
			||||||
    isPartial: state.getIn(['timelines', timelineId, 'isPartial'], false),
 | 
					    isPartial: state.getIn(['timelines', timelineId, 'isPartial'], false),
 | 
				
			||||||
    hasMore: !!state.getIn(['timelines', timelineId, 'next']),
 | 
					    hasMore:   state.getIn(['timelines', timelineId, 'hasMore']),
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return mapStateToProps;
 | 
					  return mapStateToProps;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapDispatchToProps = (dispatch, { timelineId, loadMore }) => ({
 | 
					const mapDispatchToProps = (dispatch, { timelineId }) => ({
 | 
				
			||||||
 | 
					 | 
				
			||||||
  onLoadMore: debounce(loadMore, 300, { leading: true }),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onScrollToTop: debounce(() => {
 | 
					  onScrollToTop: debounce(() => {
 | 
				
			||||||
    dispatch(scrollTopTimeline(timelineId, true));
 | 
					    dispatch(scrollTopTimeline(timelineId, true));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@ import { Redirect, withRouter } from 'react-router-dom';
 | 
				
			||||||
import { isMobile } from '../../is_mobile';
 | 
					import { isMobile } from '../../is_mobile';
 | 
				
			||||||
import { debounce } from 'lodash';
 | 
					import { debounce } from 'lodash';
 | 
				
			||||||
import { uploadCompose, resetCompose } from '../../actions/compose';
 | 
					import { uploadCompose, resetCompose } from '../../actions/compose';
 | 
				
			||||||
import { refreshHomeTimeline } from '../../actions/timelines';
 | 
					import { expandHomeTimeline } from '../../actions/timelines';
 | 
				
			||||||
import { refreshNotifications } from '../../actions/notifications';
 | 
					import { refreshNotifications } from '../../actions/notifications';
 | 
				
			||||||
import { clearHeight } from '../../actions/height_cache';
 | 
					import { clearHeight } from '../../actions/height_cache';
 | 
				
			||||||
import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers';
 | 
					import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers';
 | 
				
			||||||
| 
						 | 
					@ -284,7 +284,7 @@ export default class UI extends React.PureComponent {
 | 
				
			||||||
      navigator.serviceWorker.addEventListener('message', this.handleServiceWorkerPostMessage);
 | 
					      navigator.serviceWorker.addEventListener('message', this.handleServiceWorkerPostMessage);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.props.dispatch(refreshHomeTimeline());
 | 
					    this.props.dispatch(expandHomeTimeline());
 | 
				
			||||||
    this.props.dispatch(refreshNotifications());
 | 
					    this.props.dispatch(refreshNotifications());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,9 +10,7 @@ import {
 | 
				
			||||||
  STATUS_REVEAL,
 | 
					  STATUS_REVEAL,
 | 
				
			||||||
  STATUS_HIDE,
 | 
					  STATUS_HIDE,
 | 
				
			||||||
} from '../actions/statuses';
 | 
					} from '../actions/statuses';
 | 
				
			||||||
import {
 | 
					import { TIMELINE_DELETE } from '../actions/timelines';
 | 
				
			||||||
  TIMELINE_DELETE,
 | 
					 | 
				
			||||||
} from '../actions/timelines';
 | 
					 | 
				
			||||||
import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer';
 | 
					import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer';
 | 
				
			||||||
import { Map as ImmutableMap, fromJS } from 'immutable';
 | 
					import { Map as ImmutableMap, fromJS } from 'immutable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,14 +1,10 @@
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  TIMELINE_REFRESH_REQUEST,
 | 
					 | 
				
			||||||
  TIMELINE_REFRESH_SUCCESS,
 | 
					 | 
				
			||||||
  TIMELINE_REFRESH_FAIL,
 | 
					 | 
				
			||||||
  TIMELINE_UPDATE,
 | 
					  TIMELINE_UPDATE,
 | 
				
			||||||
  TIMELINE_DELETE,
 | 
					  TIMELINE_DELETE,
 | 
				
			||||||
  TIMELINE_EXPAND_SUCCESS,
 | 
					  TIMELINE_EXPAND_SUCCESS,
 | 
				
			||||||
  TIMELINE_EXPAND_REQUEST,
 | 
					  TIMELINE_EXPAND_REQUEST,
 | 
				
			||||||
  TIMELINE_EXPAND_FAIL,
 | 
					  TIMELINE_EXPAND_FAIL,
 | 
				
			||||||
  TIMELINE_SCROLL_TOP,
 | 
					  TIMELINE_SCROLL_TOP,
 | 
				
			||||||
  TIMELINE_CONNECT,
 | 
					 | 
				
			||||||
  TIMELINE_DISCONNECT,
 | 
					  TIMELINE_DISCONNECT,
 | 
				
			||||||
} from '../actions/timelines';
 | 
					} from '../actions/timelines';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
| 
						 | 
					@ -22,37 +18,33 @@ const initialState = ImmutableMap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const initialTimeline = ImmutableMap({
 | 
					const initialTimeline = ImmutableMap({
 | 
				
			||||||
  unread: 0,
 | 
					  unread: 0,
 | 
				
			||||||
  online: false,
 | 
					 | 
				
			||||||
  top: true,
 | 
					  top: true,
 | 
				
			||||||
  loaded: false,
 | 
					 | 
				
			||||||
  isLoading: false,
 | 
					  isLoading: false,
 | 
				
			||||||
  next: false,
 | 
					  hasMore: true,
 | 
				
			||||||
  items: ImmutableList(),
 | 
					  items: ImmutableList(),
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const normalizeTimeline = (state, timeline, statuses, next, isPartial) => {
 | 
					const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial) => {
 | 
				
			||||||
  const oldIds    = state.getIn([timeline, 'items'], ImmutableList());
 | 
					 | 
				
			||||||
  const ids       = ImmutableList(statuses.map(status => status.get('id'))).filter(newId => !oldIds.includes(newId));
 | 
					 | 
				
			||||||
  const wasLoaded = state.getIn([timeline, 'loaded']);
 | 
					 | 
				
			||||||
  const hadNext   = state.getIn([timeline, 'next']);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return state.update(timeline, initialTimeline, map => map.withMutations(mMap => {
 | 
					 | 
				
			||||||
    mMap.set('loaded', true);
 | 
					 | 
				
			||||||
    mMap.set('isLoading', false);
 | 
					 | 
				
			||||||
    if (!hadNext) mMap.set('next', next);
 | 
					 | 
				
			||||||
    mMap.set('items', wasLoaded ? ids.concat(oldIds) : oldIds.concat(ids));
 | 
					 | 
				
			||||||
    mMap.set('isPartial', isPartial);
 | 
					 | 
				
			||||||
  }));
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const appendNormalizedTimeline = (state, timeline, statuses, next) => {
 | 
					 | 
				
			||||||
  const oldIds = state.getIn([timeline, 'items'], ImmutableList());
 | 
					 | 
				
			||||||
  const ids    = ImmutableList(statuses.map(status => status.get('id'))).filter(newId => !oldIds.includes(newId));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return state.update(timeline, initialTimeline, map => map.withMutations(mMap => {
 | 
					  return state.update(timeline, initialTimeline, map => map.withMutations(mMap => {
 | 
				
			||||||
    mMap.set('isLoading', false);
 | 
					    mMap.set('isLoading', false);
 | 
				
			||||||
    mMap.set('next', next);
 | 
					    if (!next) mMap.set('hasMore', false);
 | 
				
			||||||
    mMap.set('items', oldIds.concat(ids));
 | 
					
 | 
				
			||||||
 | 
					    if (!statuses.isEmpty()) {
 | 
				
			||||||
 | 
					      mMap.update('items', ImmutableList(), oldIds => {
 | 
				
			||||||
 | 
					        const newIds = statuses.map(status => status.get('id'));
 | 
				
			||||||
 | 
					        const lastIndex = oldIds.findLastIndex(id => id !== null && id >= newIds.last()) + 1;
 | 
				
			||||||
 | 
					        const firstIndex = oldIds.take(lastIndex).findLastIndex(id => id !== null && id > newIds.first());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (firstIndex < 0) {
 | 
				
			||||||
 | 
					          return (isPartial ? newIds.unshift(null) : newIds).concat(oldIds.skip(lastIndex));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return oldIds.take(firstIndex + 1).concat(
 | 
				
			||||||
 | 
					          isPartial && oldIds.get(firstIndex) !== null ? newIds.unshift(null) : newIds,
 | 
				
			||||||
 | 
					          oldIds.skip(lastIndex)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -118,16 +110,12 @@ const updateTop = (state, timeline, top) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function timelines(state = initialState, action) {
 | 
					export default function timelines(state = initialState, action) {
 | 
				
			||||||
  switch(action.type) {
 | 
					  switch(action.type) {
 | 
				
			||||||
  case TIMELINE_REFRESH_REQUEST:
 | 
					 | 
				
			||||||
  case TIMELINE_EXPAND_REQUEST:
 | 
					  case TIMELINE_EXPAND_REQUEST:
 | 
				
			||||||
    return state.update(action.timeline, initialTimeline, map => map.set('isLoading', true));
 | 
					    return state.update(action.timeline, initialTimeline, map => map.set('isLoading', true));
 | 
				
			||||||
  case TIMELINE_REFRESH_FAIL:
 | 
					 | 
				
			||||||
  case TIMELINE_EXPAND_FAIL:
 | 
					  case TIMELINE_EXPAND_FAIL:
 | 
				
			||||||
    return state.update(action.timeline, initialTimeline, map => map.set('isLoading', false));
 | 
					    return state.update(action.timeline, initialTimeline, map => map.set('isLoading', false));
 | 
				
			||||||
  case TIMELINE_REFRESH_SUCCESS:
 | 
					 | 
				
			||||||
    return normalizeTimeline(state, action.timeline, fromJS(action.statuses), action.next, action.partial);
 | 
					 | 
				
			||||||
  case TIMELINE_EXPAND_SUCCESS:
 | 
					  case TIMELINE_EXPAND_SUCCESS:
 | 
				
			||||||
    return appendNormalizedTimeline(state, action.timeline, fromJS(action.statuses), action.next);
 | 
					    return expandNormalizedTimeline(state, action.timeline, fromJS(action.statuses), action.next, action.partial);
 | 
				
			||||||
  case TIMELINE_UPDATE:
 | 
					  case TIMELINE_UPDATE:
 | 
				
			||||||
    return updateTimeline(state, action.timeline, fromJS(action.status));
 | 
					    return updateTimeline(state, action.timeline, fromJS(action.status));
 | 
				
			||||||
  case TIMELINE_DELETE:
 | 
					  case TIMELINE_DELETE:
 | 
				
			||||||
| 
						 | 
					@ -139,10 +127,15 @@ export default function timelines(state = initialState, action) {
 | 
				
			||||||
    return filterTimeline('home', state, action.relationship, action.statuses);
 | 
					    return filterTimeline('home', state, action.relationship, action.statuses);
 | 
				
			||||||
  case TIMELINE_SCROLL_TOP:
 | 
					  case TIMELINE_SCROLL_TOP:
 | 
				
			||||||
    return updateTop(state, action.timeline, action.top);
 | 
					    return updateTop(state, action.timeline, action.top);
 | 
				
			||||||
  case TIMELINE_CONNECT:
 | 
					 | 
				
			||||||
    return state.update(action.timeline, initialTimeline, map => map.set('online', true));
 | 
					 | 
				
			||||||
  case TIMELINE_DISCONNECT:
 | 
					  case TIMELINE_DISCONNECT:
 | 
				
			||||||
    return state.update(action.timeline, initialTimeline, map => map.set('online', false));
 | 
					    return state.update(
 | 
				
			||||||
 | 
					      action.timeline,
 | 
				
			||||||
 | 
					      initialTimeline,
 | 
				
			||||||
 | 
					      map => map.update(
 | 
				
			||||||
 | 
					        'items',
 | 
				
			||||||
 | 
					        items => items.first() ? items : items.unshift(null)
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
  default:
 | 
					  default:
 | 
				
			||||||
    return state;
 | 
					    return state;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,10 @@
 | 
				
			||||||
import WebSocketClient from 'websocket.js';
 | 
					import WebSocketClient from 'websocket.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function connectStream(path, pollingRefresh = null, callbacks = () => ({ onConnect() {}, onDisconnect() {}, onReceive() {} })) {
 | 
					export function connectStream(path, pollingRefresh = null, callbacks = () => ({ onDisconnect() {}, onReceive() {} })) {
 | 
				
			||||||
  return (dispatch, getState) => {
 | 
					  return (dispatch, getState) => {
 | 
				
			||||||
    const streamingAPIBaseURL = getState().getIn(['meta', 'streaming_api_base_url']);
 | 
					    const streamingAPIBaseURL = getState().getIn(['meta', 'streaming_api_base_url']);
 | 
				
			||||||
    const accessToken = getState().getIn(['meta', 'access_token']);
 | 
					    const accessToken = getState().getIn(['meta', 'access_token']);
 | 
				
			||||||
    const { onConnect, onDisconnect, onReceive } = callbacks(dispatch, getState);
 | 
					    const { onDisconnect, onReceive } = callbacks(dispatch, getState);
 | 
				
			||||||
    let polling = null;
 | 
					    let polling = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const setupPolling = () => {
 | 
					    const setupPolling = () => {
 | 
				
			||||||
| 
						 | 
					@ -25,7 +25,6 @@ export function connectStream(path, pollingRefresh = null, callbacks = () => ({
 | 
				
			||||||
        if (pollingRefresh) {
 | 
					        if (pollingRefresh) {
 | 
				
			||||||
          clearPolling();
 | 
					          clearPolling();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        onConnect();
 | 
					 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      disconnected () {
 | 
					      disconnected () {
 | 
				
			||||||
| 
						 | 
					@ -44,7 +43,6 @@ export function connectStream(path, pollingRefresh = null, callbacks = () => ({
 | 
				
			||||||
          clearPolling();
 | 
					          clearPolling();
 | 
				
			||||||
          pollingRefresh(dispatch);
 | 
					          pollingRefresh(dispatch);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        onConnect();
 | 
					 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue