mirror of https://github.com/mastodon/mastodon
persist last-intersected status update and restore when ScrollableList is restored
e.g. when navigating from home-timeline to a status conversational thread and <Back again
This commit is contained in:
parent
53c623a999
commit
07e26142ef
|
@ -17,6 +17,14 @@ export const TIMELINE_LOAD_PENDING = 'TIMELINE_LOAD_PENDING';
|
|||
export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT';
|
||||
export const TIMELINE_CONNECT = 'TIMELINE_CONNECT';
|
||||
|
||||
export const CURRENTLY_VIEWING = 'CURRENTLY_VIEWING';
|
||||
|
||||
export const updateCurrentlyViewing = (timeline, id) => ({
|
||||
type: CURRENTLY_VIEWING,
|
||||
timeline,
|
||||
id,
|
||||
});
|
||||
|
||||
export const loadPending = timeline => ({
|
||||
type: TIMELINE_LOAD_PENDING,
|
||||
timeline,
|
||||
|
|
|
@ -20,6 +20,8 @@ export default class IntersectionObserverArticle extends React.Component {
|
|||
cachedHeight: PropTypes.number,
|
||||
onHeightChange: PropTypes.func,
|
||||
children: PropTypes.node,
|
||||
currentlyViewing: PropTypes.number,
|
||||
updateCurrentlyViewing: PropTypes.func,
|
||||
};
|
||||
|
||||
state = {
|
||||
|
@ -48,6 +50,8 @@ export default class IntersectionObserverArticle extends React.Component {
|
|||
);
|
||||
|
||||
this.componentMounted = true;
|
||||
|
||||
if(id === this.props.currentlyViewing) this.node.scrollIntoView();
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
|
@ -60,6 +64,8 @@ export default class IntersectionObserverArticle extends React.Component {
|
|||
handleIntersection = (entry) => {
|
||||
this.entry = entry;
|
||||
|
||||
if(entry.intersectionRatio > 0.75 && this.props.updateCurrentlyViewing) this.props.updateCurrentlyViewing(this.id);
|
||||
|
||||
scheduleIdleTask(this.calculateHeight);
|
||||
this.setState(this.updateStateAfterIntersection);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ export default class ScrollableList extends PureComponent {
|
|||
emptyMessage: PropTypes.node,
|
||||
children: PropTypes.node,
|
||||
bindToDocument: PropTypes.bool,
|
||||
currentlyViewing: PropTypes.number,
|
||||
updateCurrentlyViewing: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -309,6 +311,8 @@ export default class ScrollableList extends PureComponent {
|
|||
listLength={childrenCount}
|
||||
intersectionObserverWrapper={this.intersectionObserverWrapper}
|
||||
saveHeightKey={trackScroll ? `${this.context.router.route.location.key}:${scrollKey}` : null}
|
||||
currentlyViewing={this.props.currentlyViewing}
|
||||
updateCurrentlyViewing={this.props.updateCurrentlyViewing}
|
||||
>
|
||||
{React.cloneElement(child, {
|
||||
getScrollPosition: this.getScrollPosition,
|
||||
|
|
|
@ -26,6 +26,8 @@ export default class StatusList extends ImmutablePureComponent {
|
|||
emptyMessage: PropTypes.node,
|
||||
alwaysPrepend: PropTypes.bool,
|
||||
timelineId: PropTypes.string,
|
||||
currentlyViewing: PropTypes.number,
|
||||
updateCurrentlyViewing: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { connect } from 'react-redux';
|
||||
import StatusList from '../../../components/status_list';
|
||||
import { scrollTopTimeline, loadPending } from '../../../actions/timelines';
|
||||
import { scrollTopTimeline, loadPending, updateCurrentlyViewing } from '../../../actions/timelines';
|
||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import { createSelector } from 'reselect';
|
||||
import { debounce } from 'lodash';
|
||||
|
@ -39,6 +39,7 @@ const makeMapStateToProps = () => {
|
|||
isPartial: state.getIn(['timelines', timelineId, 'isPartial'], false),
|
||||
hasMore: state.getIn(['timelines', timelineId, 'hasMore']),
|
||||
numPending: getPendingStatusIds(state, { type: timelineId }).size,
|
||||
currentlyViewing: state.getIn(['timelines', timelineId, 'currentlyViewing'], -1),
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
|
@ -56,6 +57,7 @@ const mapDispatchToProps = (dispatch, { timelineId }) => ({
|
|||
|
||||
onLoadPending: () => dispatch(loadPending(timelineId)),
|
||||
|
||||
updateCurrentlyViewing: id => dispatch(updateCurrentlyViewing(timelineId, id)),
|
||||
});
|
||||
|
||||
export default connect(makeMapStateToProps, mapDispatchToProps)(StatusList);
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
TIMELINE_CONNECT,
|
||||
TIMELINE_DISCONNECT,
|
||||
TIMELINE_LOAD_PENDING,
|
||||
CURRENTLY_VIEWING,
|
||||
} from '../actions/timelines';
|
||||
import {
|
||||
ACCOUNT_BLOCK_SUCCESS,
|
||||
|
@ -28,6 +29,7 @@ const initialTimeline = ImmutableMap({
|
|||
hasMore: true,
|
||||
pendingItems: ImmutableList(),
|
||||
items: ImmutableList(),
|
||||
currentlyViewing: -1,
|
||||
});
|
||||
|
||||
const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, isLoadingRecent, usePendingItems) => {
|
||||
|
@ -168,6 +170,8 @@ export default function timelines(state = initialState, action) {
|
|||
initialTimeline,
|
||||
map => map.set('online', false).update(action.usePendingItems ? 'pendingItems' : 'items', items => items.first() ? items.unshift(null) : items)
|
||||
);
|
||||
case CURRENTLY_VIEWING:
|
||||
return state.update(action.timeline, initialTimeline, map => map.set('currentlyViewing', action.id));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue