diff options
author | Reverite <github@reverite.sh> | 2019-07-22 14:48:14 -0700 |
---|---|---|
committer | Reverite <github@reverite.sh> | 2019-07-22 14:48:14 -0700 |
commit | 9148c3e8479e59df9f9a4889ef58a959f60f6606 (patch) | |
tree | e91e1c8646fe36ec42019f65559566844c00904d | |
parent | 266540080ef5659060faa7da502123f45bbc04f2 (diff) | |
parent | 6db5669818cce459b9bb916665541b7b8f5d5155 (diff) |
Merge branch 'glitch' into production
13 files changed, 155 insertions, 160 deletions
diff --git a/app/javascript/flavours/glitch/features/blocks/index.js b/app/javascript/flavours/glitch/features/blocks/index.js index 386a0ce63..2d0f10ae7 100644 --- a/app/javascript/flavours/glitch/features/blocks/index.js +++ b/app/javascript/flavours/glitch/features/blocks/index.js @@ -1,14 +1,15 @@ import React from 'react'; import { connect } from 'react-redux'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import { debounce } from 'lodash'; import PropTypes from 'prop-types'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; -import { ScrollContainer } from 'react-router-scroll-4'; +import ScrollableList from '../../components/scrollable_list'; import Column from 'flavours/glitch/features/ui/components/column'; import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim'; import AccountContainer from 'flavours/glitch/containers/account_container'; import { fetchBlocks, expandBlocks } from 'flavours/glitch/actions/blocks'; -import { defineMessages, injectIntl } from 'react-intl'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; const messages = defineMessages({ @@ -17,6 +18,7 @@ const messages = defineMessages({ const mapStateToProps = state => ({ accountIds: state.getIn(['user_lists', 'blocks', 'items']), + hasMore: !!state.getIn(['user_lists', 'blocks', 'next']), }); @connect(mapStateToProps) @@ -27,6 +29,7 @@ export default class Blocks extends ImmutablePureComponent { params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, accountIds: ImmutablePropTypes.list, + hasMore: PropTypes.bool, intl: PropTypes.object.isRequired, }; @@ -34,21 +37,12 @@ export default class Blocks extends ImmutablePureComponent { this.props.dispatch(fetchBlocks()); } - handleScroll = (e) => { - const { scrollTop, scrollHeight, clientHeight } = e.target; - - if (scrollTop === scrollHeight - clientHeight) { - this.props.dispatch(expandBlocks()); - } - } - - shouldUpdateScroll = (prevRouterProps, { location }) => { - if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false; - return !(location.state && location.state.mastodonModalOpen); - } + handleLoadMore = debounce(() => { + this.props.dispatch(expandBlocks()); + }, 300, { leading: true }); render () { - const { intl, accountIds } = this.props; + const { intl, accountIds, hasMore } = this.props; if (!accountIds) { return ( @@ -58,16 +52,21 @@ export default class Blocks extends ImmutablePureComponent { ); } + const emptyMessage = <FormattedMessage id='empty_column.blocks' defaultMessage="You haven't blocked any users yet." />; + return ( <Column name='blocks' icon='ban' heading={intl.formatMessage(messages.heading)}> <ColumnBackButtonSlim /> - <ScrollContainer scrollKey='blocks' shouldUpdateScroll={this.shouldUpdateScroll}> - <div className='scrollable' onScroll={this.handleScroll}> - {accountIds.map(id => - <AccountContainer key={id} id={id} /> - )} - </div> - </ScrollContainer> + <ScrollableList + scrollKey='blocks' + onLoadMore={this.handleLoadMore} + hasMore={hasMore} + emptyMessage={emptyMessage} + > + {accountIds.map(id => + <AccountContainer key={id} id={id} /> + )} + </ScrollableList> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js b/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js index 9468ad81d..c57aba37b 100644 --- a/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js +++ b/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js @@ -2,14 +2,14 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import { debounce } from 'lodash'; import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'flavours/glitch/actions/bookmarks'; import Column from 'flavours/glitch/features/ui/components/column'; import ColumnHeader from 'flavours/glitch/components/column_header'; import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import StatusList from 'flavours/glitch/components/status_list'; -import { defineMessages, injectIntl } from 'react-intl'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { debounce } from 'lodash'; const messages = defineMessages({ heading: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' }, @@ -70,6 +70,8 @@ export default class Bookmarks extends ImmutablePureComponent { const { intl, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props; const pinned = !!columnId; + const emptyMessage = <FormattedMessage id='empty_column.bookmarked_statuses' defaultMessage="You don't have any bookmarked toots yet. When you bookmark one, it will show up here." />; + return ( <Column ref={this.setRef} name='bookmarks'> <ColumnHeader @@ -90,6 +92,7 @@ export default class Bookmarks extends ImmutablePureComponent { hasMore={hasMore} isLoading={isLoading} onLoadMore={this.handleLoadMore} + emptyMessage={emptyMessage} /> </Column> ); diff --git a/app/javascript/flavours/glitch/features/community_timeline/index.js b/app/javascript/flavours/glitch/features/community_timeline/index.js index 2c0fbff36..24126e5bc 100644 --- a/app/javascript/flavours/glitch/features/community_timeline/index.js +++ b/app/javascript/flavours/glitch/features/community_timeline/index.js @@ -99,10 +99,6 @@ export default class CommunityTimeline extends React.PureComponent { dispatch(expandCommunityTimeline({ maxId, onlyMedia })); } - shouldUpdateScroll = (prevRouterProps, { location }) => { - return !(location.state && location.state.mastodonModalOpen) - } - render () { const { intl, hasUnread, columnId, multiColumn, onlyMedia } = this.props; const pinned = !!columnId; @@ -125,7 +121,6 @@ export default class CommunityTimeline extends React.PureComponent { <StatusListContainer trackScroll={!pinned} scrollKey={`community_timeline-${columnId}`} - shouldUpdateScroll={this.shouldUpdateScroll} timelineId={`community${onlyMedia ? ':media' : ''}`} onLoadMore={this.handleLoadMore} emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />} diff --git a/app/javascript/flavours/glitch/features/domain_blocks/index.js b/app/javascript/flavours/glitch/features/domain_blocks/index.js index 3b29e2a26..f7d93a48e 100644 --- a/app/javascript/flavours/glitch/features/domain_blocks/index.js +++ b/app/javascript/flavours/glitch/features/domain_blocks/index.js @@ -1,16 +1,16 @@ import React from 'react'; import { connect } from 'react-redux'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import { debounce } from 'lodash'; import PropTypes from 'prop-types'; import LoadingIndicator from '../../components/loading_indicator'; import Column from '../ui/components/column'; import ColumnBackButtonSlim from '../../components/column_back_button_slim'; import DomainContainer from '../../containers/domain_container'; import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks'; -import { defineMessages, injectIntl } from 'react-intl'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { debounce } from 'lodash'; -import ScrollableList from '../../components/scrollable_list'; +import ScrollableList from 'flavours/glitch/components/scrollable_list'; const messages = defineMessages({ heading: { id: 'column.domain_blocks', defaultMessage: 'Hidden domains' }, @@ -19,6 +19,7 @@ const messages = defineMessages({ const mapStateToProps = state => ({ domains: state.getIn(['domain_lists', 'blocks', 'items']), + hasMore: !!state.getIn(['domain_lists', 'blocks', 'next']), }); @connect(mapStateToProps) @@ -28,6 +29,7 @@ export default class Blocks extends ImmutablePureComponent { static propTypes = { params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, + hasMore: PropTypes.bool, domains: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, }; @@ -41,7 +43,7 @@ export default class Blocks extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, domains } = this.props; + const { intl, domains, hasMore } = this.props; if (!domains) { return ( @@ -51,10 +53,17 @@ export default class Blocks extends ImmutablePureComponent { ); } + const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no hidden domains yet.' />; + return ( <Column icon='minus-circle' heading={intl.formatMessage(messages.heading)}> <ColumnBackButtonSlim /> - <ScrollableList scrollKey='domain_blocks' onLoadMore={this.handleLoadMore}> + <ScrollableList + scrollKey='domain_blocks' + onLoadMore={this.handleLoadMore} + hasMore={hasMore} + emptyMessage={emptyMessage} + > {domains.map(domain => <DomainContainer key={domain} domain={domain} /> )} diff --git a/app/javascript/flavours/glitch/features/favourited_statuses/index.js b/app/javascript/flavours/glitch/features/favourited_statuses/index.js index 32bf4e71a..0dae7dd53 100644 --- a/app/javascript/flavours/glitch/features/favourited_statuses/index.js +++ b/app/javascript/flavours/glitch/features/favourited_statuses/index.js @@ -2,14 +2,14 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import { debounce } from 'lodash'; import { fetchFavouritedStatuses, expandFavouritedStatuses } from 'flavours/glitch/actions/favourites'; import Column from 'flavours/glitch/features/ui/components/column'; import ColumnHeader from 'flavours/glitch/components/column_header'; import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import StatusList from 'flavours/glitch/components/status_list'; -import { defineMessages, injectIntl } from 'react-intl'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { debounce } from 'lodash'; const messages = defineMessages({ heading: { id: 'column.favourites', defaultMessage: 'Favourites' }, @@ -70,6 +70,8 @@ export default class Favourites extends ImmutablePureComponent { const { intl, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props; const pinned = !!columnId; + const emptyMessage = <FormattedMessage id='empty_column.favourited_statuses' defaultMessage="You don't have any favourite toots yet. When you favourite one, it will show up here." />; + return ( <Column ref={this.setRef} name='favourites' label={intl.formatMessage(messages.heading)}> <ColumnHeader @@ -90,6 +92,7 @@ export default class Favourites extends ImmutablePureComponent { hasMore={hasMore} isLoading={isLoading} onLoadMore={this.handleLoadMore} + emptyMessage={emptyMessage} /> </Column> ); diff --git a/app/javascript/flavours/glitch/features/favourites/index.js b/app/javascript/flavours/glitch/features/favourites/index.js index eb86636c3..81f0b24c4 100644 --- a/app/javascript/flavours/glitch/features/favourites/index.js +++ b/app/javascript/flavours/glitch/features/favourites/index.js @@ -4,12 +4,12 @@ import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import { fetchFavourites } from 'flavours/glitch/actions/interactions'; -import { ScrollContainer } from 'react-router-scroll-4'; import AccountContainer from 'flavours/glitch/containers/account_container'; import Column from 'flavours/glitch/features/ui/components/column'; import ColumnHeader from 'flavours/glitch/components/column_header'; -import { defineMessages, injectIntl } from 'react-intl'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import ScrollableList from '../../components/scrollable_list'; const messages = defineMessages({ heading: { id: 'column.favourited_by', defaultMessage: 'Favourited by' }, @@ -40,11 +40,6 @@ export default class Favourites extends ImmutablePureComponent { } } - shouldUpdateScroll = (prevRouterProps, { location }) => { - if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false; - return !(location.state && location.state.mastodonModalOpen); - } - handleHeaderClick = () => { this.column.scrollTop(); } @@ -64,6 +59,8 @@ export default class Favourites extends ImmutablePureComponent { ); } + const emptyMessage = <FormattedMessage id='empty_column.favourites' defaultMessage='No one has favourited this toot yet. When someone does, they will show up here.' />; + return ( <Column ref={this.setRef}> <ColumnHeader @@ -72,12 +69,14 @@ export default class Favourites extends ImmutablePureComponent { onClick={this.handleHeaderClick} showBackButton /> - - <ScrollContainer scrollKey='favourites' shouldUpdateScroll={this.shouldUpdateScroll}> - <div className='scrollable'> - {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} />)} - </div> - </ScrollContainer> + <ScrollableList + scrollKey='favourites' + emptyMessage={emptyMessage} + > + {accountIds.map(id => + <AccountContainer key={id} id={id} withNote={false} /> + )} + </ScrollableList> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/follow_requests/index.js b/app/javascript/flavours/glitch/features/follow_requests/index.js index d0845769e..89340320e 100644 --- a/app/javascript/flavours/glitch/features/follow_requests/index.js +++ b/app/javascript/flavours/glitch/features/follow_requests/index.js @@ -2,14 +2,15 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import { debounce } from 'lodash'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; -import { ScrollContainer } from 'react-router-scroll-4'; import Column from 'flavours/glitch/features/ui/components/column'; import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim'; import AccountAuthorizeContainer from './containers/account_authorize_container'; import { fetchFollowRequests, expandFollowRequests } from 'flavours/glitch/actions/accounts'; -import { defineMessages, injectIntl } from 'react-intl'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import ScrollableList from 'flavours/glitch/components/scrollable_list'; const messages = defineMessages({ heading: { id: 'column.follow_requests', defaultMessage: 'Follow requests' }, @@ -17,6 +18,7 @@ const messages = defineMessages({ const mapStateToProps = state => ({ accountIds: state.getIn(['user_lists', 'follow_requests', 'items']), + hasMore: !!state.getIn(['user_lists', 'follow_requests', 'next']), }); @connect(mapStateToProps) @@ -26,6 +28,7 @@ export default class FollowRequests extends ImmutablePureComponent { static propTypes = { params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, + hasMore: PropTypes.bool, accountIds: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, }; @@ -34,21 +37,12 @@ export default class FollowRequests extends ImmutablePureComponent { this.props.dispatch(fetchFollowRequests()); } - handleScroll = (e) => { - const { scrollTop, scrollHeight, clientHeight } = e.target; - - if (scrollTop === scrollHeight - clientHeight) { - this.props.dispatch(expandFollowRequests()); - } - } - - shouldUpdateScroll = (prevRouterProps, { location }) => { - if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false; - return !(location.state && location.state.mastodonModalOpen); - } + handleLoadMore = debounce(() => { + this.props.dispatch(expandFollowRequests()); + }, 300, { leading: true }); render () { - const { intl, accountIds } = this.props; + const { intl, accountIds, hasMore } = this.props; if (!accountIds) { return ( @@ -58,17 +52,22 @@ export default class FollowRequests extends ImmutablePureComponent { ); } + const emptyMessage = <FormattedMessage id='empty_column.follow_requests' defaultMessage="You don't have any follow requests yet. When you receive one, it will show up here." />; + return ( <Column name='follow-requests' icon='user-plus' heading={intl.formatMessage(messages.heading)}> <ColumnBackButtonSlim /> - <ScrollContainer scrollKey='follow_requests' shouldUpdateScroll={this.shouldUpdateScroll}> - <div className='scrollable' onScroll={this.handleScroll}> - {accountIds.map(id => - <AccountAuthorizeContainer key={id} id={id} /> - )} - </div> - </ScrollContainer> + <ScrollableList + scrollKey='follow_requests' + onLoadMore={this.handleLoadMore} + hasMore={hasMore} + emptyMessage={emptyMessage} + > + {accountIds.map(id => + <AccountAuthorizeContainer key={id} id={id} /> + )} + </ScrollableList> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/followers/index.js b/app/javascript/flavours/glitch/features/followers/index.js index 2e47ab9b9..c57a2b1a2 100644 --- a/app/javascript/flavours/glitch/features/followers/index.js +++ b/app/javascript/flavours/glitch/features/followers/index.js @@ -2,20 +2,21 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import { debounce } from 'lodash'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import { fetchAccount, fetchFollowers, expandFollowers, } from 'flavours/glitch/actions/accounts'; -import { ScrollContainer } from 'react-router-scroll-4'; +import { FormattedMessage } from 'react-intl'; import AccountContainer from 'flavours/glitch/containers/account_container'; import Column from 'flavours/glitch/features/ui/components/column'; import ProfileColumnHeader from 'flavours/glitch/features/account/components/profile_column_header'; import HeaderContainer from 'flavours/glitch/features/account_timeline/containers/header_container'; -import LoadMore from 'flavours/glitch/components/load_more'; import ImmutablePureComponent from 'react-immutable-pure-component'; import MissingIndicator from 'flavours/glitch/components/missing_indicator'; +import ScrollableList from 'flavours/glitch/components/scrollable_list'; const mapStateToProps = (state, props) => ({ isAccount: !!state.getIn(['accounts', props.params.accountId]), @@ -58,15 +59,10 @@ export default class Followers extends ImmutablePureComponent { } } - handleLoadMore = (e) => { + handleLoadMore = debounce(() => { e.preventDefault(); this.props.dispatch(expandFollowers(this.props.params.accountId)); - } - - shouldUpdateScroll = (prevRouterProps, { location }) => { - if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false; - return !(location.state && location.state.mastodonModalOpen); - } + }, 300, { leading: true }); setRef = c => { this.column = c; @@ -83,8 +79,6 @@ export default class Followers extends ImmutablePureComponent { ); } - let loadMore = null; - if (!accountIds) { return ( <Column> @@ -93,23 +87,24 @@ export default class Followers extends ImmutablePureComponent { ); } - if (hasMore) { - loadMore = <LoadMore onClick={this.handleLoadMore} />; - } + const emptyMessage = <FormattedMessage id='account.followers.empty' defaultMessage='No one follows this user yet.' />; return ( <Column ref={this.setRef}> <ProfileColumnHeader onClick={this.handleHeaderClick} /> - <ScrollContainer scrollKey='followers' shouldUpdateScroll={this.shouldUpdateScroll}> - <div className='scrollable' onScroll={this.handleScroll}> - <div className='followers'> - <HeaderContainer accountId={this.props.params.accountId} hideTabs /> - {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} />)} - {loadMore} - </div> - </div> - </ScrollContainer> + <ScrollableList + scrollKey='followers' + hasMore={hasMore} + onLoadMore={this.handleLoadMore} + prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} + alwaysPrepend + emptyMessage={emptyMessage} + > + {accountIds.map(id => + <AccountContainer key={id} id={id} withNote={false} /> + )} + </ScrollableList> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/following/index.js b/app/javascript/flavours/glitch/features/following/index.js index ad1445f3a..b61f83988 100644 --- a/app/javascript/flavours/glitch/features/following/index.js +++ b/app/javascript/flavours/glitch/features/following/index.js @@ -2,20 +2,21 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import { debounce } from 'lodash'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import { fetchAccount, fetchFollowing, expandFollowing, } from 'flavours/glitch/actions/accounts'; -import { ScrollContainer } from 'react-router-scroll-4'; +import { FormattedMessage } from 'react-intl'; import AccountContainer from 'flavours/glitch/containers/account_container'; import Column from 'flavours/glitch/features/ui/components/column'; import ProfileColumnHeader from 'flavours/glitch/features/account/components/profile_column_header'; import HeaderContainer from 'flavours/glitch/features/account_timeline/containers/header_container'; -import LoadMore from 'flavours/glitch/components/load_more'; import ImmutablePureComponent from 'react-immutable-pure-component'; import MissingIndicator from 'flavours/glitch/components/missing_indicator'; +import ScrollableList from 'flavours/glitch/components/scrollable_list'; const mapStateToProps = (state, props) => ({ isAccount: !!state.getIn(['accounts', props.params.accountId]), @@ -58,15 +59,10 @@ export default class Following extends ImmutablePureComponent { } } - handleLoadMore = (e) => { + handleLoadMore = debounce(() => { e.preventDefault(); this.props.dispatch(expandFollowing(this.props.params.accountId)); - } - - shouldUpdateScroll = (prevRouterProps, { location }) => { - if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false; - return !(location.state && location.state.mastodonModalOpen); - } + }, 300, { leading: true }); setRef = c => { this.column = c; @@ -83,8 +79,6 @@ export default class Following extends ImmutablePureComponent { ); } - let loadMore = null; - if (!accountIds) { return ( <Column> @@ -93,23 +87,24 @@ export default class Following extends ImmutablePureComponent { ); } - if (hasMore) { - loadMore = <LoadMore onClick={this.handleLoadMore} />; - } + const emptyMessage = <FormattedMessage id='account.follows.empty' defaultMessage="This user doesn't follow anyone yet." />; return ( <Column ref={this.setRef}> <ProfileColumnHeader onClick={this.handleHeaderClick} /> - <ScrollContainer scrollKey='following' shouldUpdateScroll={this.shouldUpdateScroll}> - <div className='scrollable' onScroll={this.handleScroll}> - <div className='following'> - <HeaderContainer accountId={this.props.params.accountId} hideTabs /> - {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} />)} - {loadMore} - </div> - </div> - </ScrollContainer> + <ScrollableList + scrollKey='following' + hasMore={hasMore} + onLoadMore={this.handleLoadMore} + prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} + alwaysPrepend + emptyMessage={emptyMessage} + > + {accountIds.map(id => + <AccountContainer key={id} id={id} withNote={false} /> + )} + </ScrollableList> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/lists/index.js b/app/javascript/flavours/glitch/features/lists/index.js index 8b0470c92..bf1b410bb 100644 --- a/app/javascript/flavours/glitch/features/lists/index.js +++ b/app/javascript/flavours/glitch/features/lists/index.js @@ -6,12 +6,13 @@ import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import Column from 'flavours/glitch/features/ui/components/column'; import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim'; import { fetchLists } from 'flavours/glitch/actions/lists'; -import { defineMessages, injectIntl } from 'react-intl'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ColumnLink from 'flavours/glitch/features/ui/components/column_link'; import ColumnSubheading from 'flavours/glitch/features/ui/components/column_subheading'; import NewListForm from './components/new_list_form'; import { createSelector } from 'reselect'; +import ScrollableList from 'flavours/glitch/components/scrollable_list'; const messages = defineMessages({ heading: { id: 'column.lists', defaultMessage: 'Lists' }, @@ -62,13 +63,15 @@ export default class Lists extends ImmutablePureComponent { <NewListForm /> - <div className='scrollable'> - <ColumnSubheading text={intl.formatMessage(messages.subheading)} /> - + <ColumnSubheading text={intl.formatMessage(messages.subheading)} /> + <ScrollableList + scrollKey='lists' + emptyMessage={emptyMessage} + > {lists.map(list => <ColumnLink key={list.get('id')} to={`/timelines/list/${list.get('id')}`} icon='list-ul' text={list.get('title')} /> )} - </div> + </ScrollableList> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/mutes/index.js b/app/javascript/flavours/glitch/features/mutes/index.js index bbcbea701..e5b5bb46d 100644 --- a/app/javascript/flavours/glitch/features/mutes/index.js +++ b/app/javascript/flavours/glitch/features/mutes/index.js @@ -1,15 +1,16 @@ import React from 'react'; import { connect } from 'react-redux'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import { debounce } from 'lodash'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; -import { ScrollContainer } from 'react-router-scroll-4'; import Column from 'flavours/glitch/features/ui/components/column'; import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim'; import AccountContainer from 'flavours/glitch/containers/account_container'; import { fetchMutes, expandMutes } from 'flavours/glitch/actions/mutes'; -import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import ScrollableList from 'flavours/glitch/components/scrollable_list'; const messages = defineMessages({ heading: { id: 'column.mutes', defaultMessage: 'Muted users' }, @@ -17,6 +18,7 @@ const messages = defineMessages({ const mapStateToProps = state => ({ accountIds: state.getIn(['user_lists', 'mutes', 'items']), + hasMore: !!state.getIn(['user_lists', 'mutes', 'next']), }); @connect(mapStateToProps) @@ -26,6 +28,7 @@ export default class Mutes extends ImmutablePureComponent { static propTypes = { params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, + hasMore: PropTypes.bool, accountIds: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, }; @@ -34,21 +37,12 @@ export default class Mutes extends ImmutablePureComponent { this.props.dispatch(fetchMutes()); } - handleScroll = (e) => { - const { scrollTop, scrollHeight, clientHeight } = e.target; - - if (scrollTop === scrollHeight - clientHeight) { - this.props.dispatch(expandMutes()); - } - } - - shouldUpdateScroll = (prevRouterProps, { location }) => { - if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false; - return !(location.state && location.state.mastodonModalOpen); - } + handleLoadMore = debounce(() => { + this.props.dispatch(expandMutes()); + }, 300, { leading: true }); render () { - const { intl, accountIds } = this.props; + const { intl, accountIds, hasMore } = this.props; if (!accountIds) { return ( @@ -58,16 +52,21 @@ export default class Mutes extends ImmutablePureComponent { ); } + const emptyMessage = <FormattedMessage id='empty_column.mutes' defaultMessage="You haven't muted any users yet." />; + return ( <Column name='mutes' icon='volume-off' heading={intl.formatMessage(messages.heading)}> <ColumnBackButtonSlim /> - <ScrollContainer scrollKey='mutes' shouldUpdateScroll={this.shouldUpdateScroll}> - <div className='scrollable mutes' onScroll={this.handleScroll}> - {accountIds.map(id => - <AccountContainer key={id} id={id} /> - )} - </div> - </ScrollContainer> + <ScrollableList + scrollKey='mutes' + onLoadMore={this.handleLoadMore} + hasMore={hasMore} + emptyMessage={emptyMessage} + > + {accountIds.map(id => + <AccountContainer key={id} id={id} /> + )} + </ScrollableList> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/public_timeline/index.js b/app/javascript/flavours/glitch/features/public_timeline/index.js index 7fe472202..e5f5171aa 100644 --- a/app/javascript/flavours/glitch/features/public_timeline/index.js +++ b/app/javascript/flavours/glitch/features/public_timeline/index.js @@ -99,10 +99,6 @@ export default class PublicTimeline extends React.PureComponent { dispatch(expandPublicTimeline({ maxId, onlyMedia })); } - shouldUpdateScroll = (prevRouterProps, { location }) => { - return !(location.state && location.state.mastodonModalOpen) - } - render () { const { intl, columnId, hasUnread, multiColumn, onlyMedia } = this.props; const pinned = !!columnId; diff --git a/app/javascript/flavours/glitch/features/reblogs/index.js b/app/javascript/flavours/glitch/features/reblogs/index.js index e007506b7..14f44a20a 100644 --- a/app/javascript/flavours/glitch/features/reblogs/index.js +++ b/app/javascript/flavours/glitch/features/reblogs/index.js @@ -4,12 +4,12 @@ import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import { fetchReblogs } from 'flavours/glitch/actions/interactions'; -import { ScrollContainer } from 'react-router-scroll-4'; import AccountContainer from 'flavours/glitch/containers/account_container'; import Column from 'flavours/glitch/features/ui/components/column'; import ColumnHeader from 'flavours/glitch/components/column_header'; -import { defineMessages, injectIntl } from 'react-intl'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import ScrollableList from 'flavours/glitch/components/scrollable_list'; const messages = defineMessages({ heading: { id: 'column.reblogged_by', defaultMessage: 'Boosted by' }, @@ -40,11 +40,6 @@ export default class Reblogs extends ImmutablePureComponent { } } - shouldUpdateScroll = (prevRouterProps, { location }) => { - if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false; - return !(location.state && location.state.mastodonModalOpen); - } - handleHeaderClick = () => { this.column.scrollTop(); } @@ -64,6 +59,8 @@ export default class Reblogs extends ImmutablePureComponent { ); } + const emptyMessage = <FormattedMessage id='status.reblogs.empty' defaultMessage='No one has boosted this toot yet. When someone does, they will show up here.' />; + return ( <Column ref={this.setRef}> <ColumnHeader @@ -73,11 +70,14 @@ export default class Reblogs extends ImmutablePureComponent { showBackButton /> - <ScrollContainer scrollKey='reblogs' shouldUpdateScroll={this.shouldUpdateScroll}> - <div className='scrollable reblogs'> - {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} />)} - </div> - </ScrollContainer> + <ScrollableList + scrollKey='reblogs' + emptyMessage={emptyMessage} + > + {accountIds.map(id => + <AccountContainer key={id} id={id} withNote={false} /> + )} + </ScrollableList> </Column> ); } |