Skip to content

Commit 07e2614

Browse files
committed
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
1 parent 53c623a commit 07e2614

6 files changed

Lines changed: 27 additions & 1 deletion

File tree

app/javascript/mastodon/actions/timelines.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ export const TIMELINE_LOAD_PENDING = 'TIMELINE_LOAD_PENDING';
1717
export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT';
1818
export const TIMELINE_CONNECT = 'TIMELINE_CONNECT';
1919

20+
export const CURRENTLY_VIEWING = 'CURRENTLY_VIEWING';
21+
22+
export const updateCurrentlyViewing = (timeline, id) => ({
23+
type: CURRENTLY_VIEWING,
24+
timeline,
25+
id,
26+
});
27+
2028
export const loadPending = timeline => ({
2129
type: TIMELINE_LOAD_PENDING,
2230
timeline,

app/javascript/mastodon/components/intersection_observer_article.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export default class IntersectionObserverArticle extends React.Component {
2020
cachedHeight: PropTypes.number,
2121
onHeightChange: PropTypes.func,
2222
children: PropTypes.node,
23+
currentlyViewing: PropTypes.number,
24+
updateCurrentlyViewing: PropTypes.func,
2325
};
2426

2527
state = {
@@ -48,6 +50,8 @@ export default class IntersectionObserverArticle extends React.Component {
4850
);
4951

5052
this.componentMounted = true;
53+
54+
if(id === this.props.currentlyViewing) this.node.scrollIntoView();
5155
}
5256

5357
componentWillUnmount () {
@@ -60,6 +64,8 @@ export default class IntersectionObserverArticle extends React.Component {
6064
handleIntersection = (entry) => {
6165
this.entry = entry;
6266

67+
if(entry.intersectionRatio > 0.75 && this.props.updateCurrentlyViewing) this.props.updateCurrentlyViewing(this.id);
68+
6369
scheduleIdleTask(this.calculateHeight);
6470
this.setState(this.updateStateAfterIntersection);
6571
}

app/javascript/mastodon/components/scrollable_list.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ export default class ScrollableList extends PureComponent {
3636
emptyMessage: PropTypes.node,
3737
children: PropTypes.node,
3838
bindToDocument: PropTypes.bool,
39+
currentlyViewing: PropTypes.number,
40+
updateCurrentlyViewing: PropTypes.func,
3941
};
4042

4143
static defaultProps = {
@@ -309,6 +311,8 @@ export default class ScrollableList extends PureComponent {
309311
listLength={childrenCount}
310312
intersectionObserverWrapper={this.intersectionObserverWrapper}
311313
saveHeightKey={trackScroll ? `${this.context.router.route.location.key}:${scrollKey}` : null}
314+
currentlyViewing={this.props.currentlyViewing}
315+
updateCurrentlyViewing={this.props.updateCurrentlyViewing}
312316
>
313317
{React.cloneElement(child, {
314318
getScrollPosition: this.getScrollPosition,

app/javascript/mastodon/components/status_list.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export default class StatusList extends ImmutablePureComponent {
2626
emptyMessage: PropTypes.node,
2727
alwaysPrepend: PropTypes.bool,
2828
timelineId: PropTypes.string,
29+
currentlyViewing: PropTypes.number,
30+
updateCurrentlyViewing: PropTypes.func,
2931
};
3032

3133
static defaultProps = {

app/javascript/mastodon/features/ui/containers/status_list_container.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { connect } from 'react-redux';
22
import StatusList from '../../../components/status_list';
3-
import { scrollTopTimeline, loadPending } from '../../../actions/timelines';
3+
import { scrollTopTimeline, loadPending, updateCurrentlyViewing } from '../../../actions/timelines';
44
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
55
import { createSelector } from 'reselect';
66
import { debounce } from 'lodash';
@@ -39,6 +39,7 @@ const makeMapStateToProps = () => {
3939
isPartial: state.getIn(['timelines', timelineId, 'isPartial'], false),
4040
hasMore: state.getIn(['timelines', timelineId, 'hasMore']),
4141
numPending: getPendingStatusIds(state, { type: timelineId }).size,
42+
currentlyViewing: state.getIn(['timelines', timelineId, 'currentlyViewing'], -1),
4243
});
4344

4445
return mapStateToProps;
@@ -56,6 +57,7 @@ const mapDispatchToProps = (dispatch, { timelineId }) => ({
5657

5758
onLoadPending: () => dispatch(loadPending(timelineId)),
5859

60+
updateCurrentlyViewing: id => dispatch(updateCurrentlyViewing(timelineId, id)),
5961
});
6062

6163
export default connect(makeMapStateToProps, mapDispatchToProps)(StatusList);

app/javascript/mastodon/reducers/timelines.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
TIMELINE_CONNECT,
1010
TIMELINE_DISCONNECT,
1111
TIMELINE_LOAD_PENDING,
12+
CURRENTLY_VIEWING,
1213
} from '../actions/timelines';
1314
import {
1415
ACCOUNT_BLOCK_SUCCESS,
@@ -28,6 +29,7 @@ const initialTimeline = ImmutableMap({
2829
hasMore: true,
2930
pendingItems: ImmutableList(),
3031
items: ImmutableList(),
32+
currentlyViewing: -1,
3133
});
3234

3335
const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, isLoadingRecent, usePendingItems) => {
@@ -168,6 +170,8 @@ export default function timelines(state = initialState, action) {
168170
initialTimeline,
169171
map => map.set('online', false).update(action.usePendingItems ? 'pendingItems' : 'items', items => items.first() ? items.unshift(null) : items)
170172
);
173+
case CURRENTLY_VIEWING:
174+
return state.update(action.timeline, initialTimeline, map => map.set('currentlyViewing', action.id));
171175
default:
172176
return state;
173177
}

0 commit comments

Comments
 (0)