Added pull to refresh / PullToRefresher in StatusList for timelines

• Added:
- pull to refresh / PullToRefresher in StatusList for timelines
- styles for pull to refresh module in PullToRefresher component
This commit is contained in:
mgabdev 2020-11-04 21:33:58 -06:00
parent 2d6cfeedeb
commit 26bb93c7c4
2 changed files with 45 additions and 13 deletions
app/javascript
gabsocial/components
styles

@ -1,7 +1,7 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { Map as ImmutableMap, List as ImmutableList } from 'immutable' import { Map as ImmutableMap, List as ImmutableList, is } from 'immutable'
import ImmutablePropTypes from 'react-immutable-proptypes' import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component' import ImmutablePureComponent from 'react-immutable-pure-component'
import { createSelector } from 'reselect' import { createSelector } from 'reselect'
@ -12,7 +12,11 @@ import {
TIMELINE_INJECTION_GROUP_CATEGORIES, TIMELINE_INJECTION_GROUP_CATEGORIES,
TIMELINE_INJECTION_USER_SUGGESTIONS, TIMELINE_INJECTION_USER_SUGGESTIONS,
} from '../constants' } from '../constants'
import { dequeueTimeline, scrollTopTimeline } from '../actions/timelines' import {
dequeueTimeline,
scrollTopTimeline,
forceDequeueTimeline,
} from '../actions/timelines'
import { showTimelineInjection } from '../actions/timeline_injections' import { showTimelineInjection } from '../actions/timeline_injections'
import { fetchStatus, fetchContext } from '../actions/statuses' import { fetchStatus, fetchContext } from '../actions/statuses'
import StatusContainer from '../containers/status_container' import StatusContainer from '../containers/status_container'
@ -21,11 +25,12 @@ import ScrollableList from './scrollable_list'
import TimelineQueueButtonHeader from './timeline_queue_button_header' import TimelineQueueButtonHeader from './timeline_queue_button_header'
import TimelineInjectionBase from './timeline_injections/timeline_injection_base' import TimelineInjectionBase from './timeline_injections/timeline_injection_base'
import TimelineInjectionRoot from './timeline_injections/timeline_injection_root' import TimelineInjectionRoot from './timeline_injections/timeline_injection_root'
import PullToRefresher from './pull_to_refresher'
class StatusList extends ImmutablePureComponent { class StatusList extends ImmutablePureComponent {
state = { state = {
refreshing: false, isRefreshing: false,
fetchedContext: false, fetchedContext: false,
} }
@ -56,8 +61,9 @@ class StatusList extends ImmutablePureComponent {
} }
componentDidUpdate(prevProps, prevState) { componentDidUpdate(prevProps, prevState) {
if (prevState.refreshing) { if (this.state.isRefreshing) {
this.setState({ refreshing: false }) this.setState({ isRefreshing: false })
this.props.onForceDequeueTimeline(this.props.timelineId)
} }
if (prevProps.statusIds.count() < this.props.statusIds.count()) { if (prevProps.statusIds.count() < this.props.statusIds.count()) {
@ -107,11 +113,8 @@ class StatusList extends ImmutablePureComponent {
}, 300, { leading: true }) }, 300, { leading: true })
handleOnReload = debounce(() => { handleOnReload = debounce(() => {
// Only pull to refresh on home timeline for now
if (this.props.scrollKey === 'home_timeline' && !this.state.refreshing) {
this.props.onLoadMore() this.props.onLoadMore()
this.setState({ refreshing: true }) this.setState({ isRefreshing: true })
}
}, 300, { trailing: true }) }, 300, { trailing: true })
_selectChild(index, align_top) { _selectChild(index, align_top) {
@ -156,7 +159,7 @@ class StatusList extends ImmutablePureComponent {
onScrollToTop, onScrollToTop,
onScroll, onScroll,
} = this.props } = this.props
const { fetchedContext, refreshing } = this.state const { fetchedContext, isRefreshing } = this.state
if (isPartial || (isLoading && statusIds.size === 0)) { if (isPartial || (isLoading && statusIds.size === 0)) {
return ( return (
@ -279,10 +282,14 @@ class StatusList extends ImmutablePureComponent {
count={totalQueuedItemsCount} count={totalQueuedItemsCount}
itemType='gab' itemType='gab'
/> />
<PullToRefresher
onRefresh={this.handleOnReload}
hasMore={hasMore}
/>
<ScrollableList <ScrollableList
ref={this.setRef} ref={this.setRef}
isLoading={isLoading} isLoading={isLoading || isRefreshing}
showLoading={(isLoading && statusIds.size === 0)} showLoading={isRefreshing || (isLoading && statusIds.size === 0)}
onLoadMore={onLoadMore && this.handleLoadOlder} onLoadMore={onLoadMore && this.handleLoadOlder}
placeholderComponent={StatusPlaceholder} placeholderComponent={StatusPlaceholder}
placeholderCount={1} placeholderCount={1}
@ -357,6 +364,9 @@ const mapStateToProps = (state, { timelineId }) => {
} }
const mapDispatchToProps = (dispatch, ownProps) => ({ const mapDispatchToProps = (dispatch, ownProps) => ({
onForceDequeueTimeline(timelineId) {
dispatch(forceDequeueTimeline(timelineId))
},
onDequeueTimeline(timelineId) { onDequeueTimeline(timelineId) {
dispatch(dequeueTimeline(timelineId, ownProps.onLoadMore)) dispatch(dequeueTimeline(timelineId, ownProps.onLoadMore))
}, },
@ -387,6 +397,7 @@ StatusList.propTypes = {
timelineId: PropTypes.string, timelineId: PropTypes.string,
queuedItemSize: PropTypes.number, queuedItemSize: PropTypes.number,
onDequeueTimeline: PropTypes.func.isRequired, onDequeueTimeline: PropTypes.func.isRequired,
onClearTimeline: PropTypes.func.isRequired,
onScrollToTop: PropTypes.func.isRequired, onScrollToTop: PropTypes.func.isRequired,
onScroll: PropTypes.func.isRequired, onScroll: PropTypes.func.isRequired,
onFetchContext: PropTypes.func.isRequired, onFetchContext: PropTypes.func.isRequired,

@ -932,6 +932,27 @@ pre {
appearance: none; appearance: none;
} }
:global(.ptr--ptr) {
background-color: var(--solid_color_block) !important;
border-bottom: 1px solid var(--border_color_secondary) !important;
}
:global(.ptr--ptr.ptr--refresh) {
min-height: 110px !important;
}
:global(.ptr--ptr.ptr--pull.ptr--release) {
padding-top: 15px !important;
padding-bottom: 5px !important;
min-height: 110px;
box-shadow: none !important;
}
:global(.ptr--icon) {
font-size: var(--fs_m) !important;
color: var(--text_color_secondary) !important;
}
:global(.emojione) { :global(.emojione) {
margin: -3px 0 0; margin: -3px 0 0;
height: 20px; height: 20px;