Skip to content

Commit

Permalink
Remember scroll position when navigating back, do not needlessly reload
Browse files Browse the repository at this point in the history
entire timelines (only fetch since last known ID). Side effect: account
timelines no longer update in real-time
  • Loading branch information
Gargron committed Oct 18, 2016
1 parent 1d2175f commit 8698cd3
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 20 deletions.
11 changes: 10 additions & 1 deletion app/assets/javascripts/components/actions/accounts.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,16 @@ export function fetchAccountTimeline(id) {
return (dispatch, getState) => {
dispatch(fetchAccountTimelineRequest(id));

api(getState).get(`/api/v1/accounts/${id}/statuses`).then(response => {
const ids = getState().getIn(['timelines', 'accounts_timelines', id], Immutable.List());
const newestId = ids.size > 0 ? ids.first() : null;

let params = '';

if (newestId !== null) {
params = `?since_id=${newestId}`;
}

api(getState).get(`/api/v1/accounts/${id}/statuses${params}`).then(response => {
dispatch(fetchAccountTimelineSuccess(id, response.data));
}).catch(error => {
dispatch(fetchAccountTimelineFail(id, error));
Expand Down
11 changes: 10 additions & 1 deletion app/assets/javascripts/components/actions/timelines.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,16 @@ export function refreshTimeline(timeline) {
return function (dispatch, getState) {
dispatch(refreshTimelineRequest(timeline));

api(getState).get(`/api/v1/statuses/${timeline}`).then(function (response) {
const ids = getState().getIn(['timelines', timeline]);
const newestId = ids.size > 0 ? ids.first() : null;

let params = '';

if (newestId !== null) {
params = `?since_id=${newestId}`;
}

api(getState).get(`/api/v1/statuses/${timeline}${params}`).then(function (response) {
dispatch(refreshTimelineSuccess(timeline, response.data));
}).catch(function (error) {
dispatch(refreshTimelineFail(timeline, error));
Expand Down
28 changes: 23 additions & 5 deletions app/assets/javascripts/components/components/status_list.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Status from './status';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import Status from './status';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import { ScrollContainer } from 'react-router-scroll';

const StatusList = React.createClass({

Expand All @@ -11,9 +12,16 @@ const StatusList = React.createClass({
onFavourite: React.PropTypes.func,
onDelete: React.PropTypes.func,
onScrollToBottom: React.PropTypes.func,
trackScroll: React.PropTypes.bool,
me: React.PropTypes.number
},

getDefaultProps () {
return {
trackScroll: true
};
},

mixins: [PureRenderMixin],

handleScroll (e) {
Expand All @@ -25,9 +33,9 @@ const StatusList = React.createClass({
},

render () {
const { statuses, onScrollToBottom, ...other } = this.props;
const { statuses, onScrollToBottom, trackScroll, ...other } = this.props;

return (
const scrollableArea = (
<div style={{ overflowY: 'scroll', flex: '1 1 auto', overflowX: 'hidden' }} className='scrollable' onScroll={this.handleScroll}>
<div>
{statuses.map((status) => {
Expand All @@ -36,6 +44,16 @@ const StatusList = React.createClass({
</div>
</div>
);

if (trackScroll) {
return (
<ScrollContainer scrollKey='status-list'>
{scrollableArea}
</ScrollContainer>
);
} else {
return scrollableArea;
}
}

});
Expand Down
4 changes: 3 additions & 1 deletion app/assets/javascripts/components/containers/mastodon.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import { setAccessToken } from '../actions/meta';
import { setAccountSelf } from '../actions/accounts';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import {
applyRouterMiddleware,
Router,
Route,
hashHistory,
IndexRoute
} from 'react-router';
import { useScroll } from 'react-router-scroll';
import UI from '../features/ui';
import Account from '../features/account';
import Status from '../features/status';
Expand Down Expand Up @@ -71,7 +73,7 @@ const Mastodon = React.createClass({
render () {
return (
<Provider store={store}>
<Router history={hashHistory}>
<Router history={hashHistory} render={applyRouterMiddleware(useScroll())}>
<Route path='/' component={UI}>
<IndexRoute component={GettingStarted} />
<Route path='/statuses/new' component={Compose} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const HomeTimeline = React.createClass({
render () {
return (
<Column icon='home' heading='Home'>
<StatusListContainer type='home' />
<StatusListContainer {...this.props} type='home' />
</Column>
);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const MentionsTimeline = React.createClass({
render () {
return (
<Column icon='at' heading='Mentions'>
<StatusListContainer type='mentions' />
<StatusListContainer {...this.props} type='mentions' />
</Column>
);
},
Expand Down
4 changes: 2 additions & 2 deletions app/assets/javascripts/components/features/ui/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ const UI = React.createClass({
<MediaQuery minWidth={layoutBreakpoint}>
<ColumnsArea>
<Compose />
<HomeTimeline />
<MentionsTimeline />
<HomeTimeline trackScroll={false} />
<MentionsTimeline trackScroll={false} />
{this.props.children}
</ColumnsArea>
</MediaQuery>
Expand Down
12 changes: 5 additions & 7 deletions app/assets/javascripts/components/reducers/timelines.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ function normalizeTimeline(state, timeline, statuses) {
ids = ids.set(i, status.get('id'));
});

return state.set(timeline, ids);
return state.update(timeline, list => list.unshift(...ids));
};

function appendNormalizedTimeline(state, timeline, statuses) {
Expand All @@ -100,16 +100,14 @@ function appendNormalizedTimeline(state, timeline, statuses) {
};

function normalizeAccountTimeline(state, accountId, statuses) {
state = state.updateIn(['accounts_timelines', accountId], Immutable.List([]), list => {
return (list.size > 0) ? list.clear() : list;
});
let ids = Immutable.List([]);

statuses.forEach((status, i) => {
state = normalizeStatus(state, status);
state = state.updateIn(['accounts_timelines', accountId], Immutable.List([]), list => list.set(i, status.get('id')));
ids = ids.set(i, status.get('id'));
});

return state;
return state.updateIn(['accounts_timelines', accountId], Immutable.List([]), list => list.unshift(...ids));
};

function appendNormalizedAccountTimeline(state, accountId, statuses) {
Expand Down Expand Up @@ -137,7 +135,7 @@ function updateTimeline(state, timeline, status) {
return list.unshift(status.get('id'));
});

state = state.updateIn(['accounts_timelines', status.getIn(['account', 'id'])], Immutable.List([]), list => (list.includes(status.get('id')) ? list : list.unshift(status.get('id'))));
//state = state.updateIn(['accounts_timelines', status.getIn(['account', 'id'])], Immutable.List([]), list => (list.includes(status.get('id')) ? list : list.unshift(status.get('id'))));

return state;
};
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"sinon": "^1.17.6"
},
"dependencies": {
"react-responsive": "^1.1.5"
"react-responsive": "^1.1.5",
"react-router-scroll": "^0.3.2"
}
}
19 changes: 19 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1743,6 +1743,10 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"

dom-helpers@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-2.4.0.tgz#9bb4b245f637367b1fa670274272aa28fe06c367"

dom-serializer@~0.1.0, dom-serializer@0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
Expand Down Expand Up @@ -3892,6 +3896,14 @@ react-responsive:
matchmedia "^0.1.2"
object-assign "^4.0.1"

react-router-scroll:
version "0.3.2"
resolved "https://registry.yarnpkg.com/react-router-scroll/-/react-router-scroll-0.3.2.tgz#ba8b1d01b3681dc5a68d72865d35c10e84065e52"
dependencies:
history "^2.1.2"
scroll-behavior "^0.8.0"
warning "^3.0.0"

react-router@^2.8.0:
version "2.8.1"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-2.8.1.tgz#73e9491f6ceb316d0f779829081863e378ee4ed7"
Expand Down Expand Up @@ -4147,6 +4159,13 @@ sax@^1.1.4, sax@~1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"

scroll-behavior@^0.8.0:
version "0.8.2"
resolved "https://registry.yarnpkg.com/scroll-behavior/-/scroll-behavior-0.8.2.tgz#ace13e40b001d8d4d007aec0e7fb668cf9043546"
dependencies:
dom-helpers "^2.4.0"
invariant "^2.2.1"

semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
Expand Down

0 comments on commit 8698cd3

Please sign in to comment.