diff options
Diffstat (limited to 'app/javascript/flavours/glitch/features')
14 files changed, 90 insertions, 71 deletions
diff --git a/app/javascript/flavours/glitch/features/blocks/index.js b/app/javascript/flavours/glitch/features/blocks/index.js index 4992689ff..4d0f58239 100644 --- a/app/javascript/flavours/glitch/features/blocks/index.js +++ b/app/javascript/flavours/glitch/features/blocks/index.js @@ -19,6 +19,7 @@ const messages = defineMessages({ const mapStateToProps = state => ({ accountIds: state.getIn(['user_lists', 'blocks', 'items']), hasMore: !!state.getIn(['user_lists', 'blocks', 'next']), + isLoading: state.getIn(['user_lists', 'blocks', 'isLoading'], true), }); export default @connect(mapStateToProps) @@ -30,6 +31,7 @@ class Blocks extends ImmutablePureComponent { dispatch: PropTypes.func.isRequired, accountIds: ImmutablePropTypes.list, hasMore: PropTypes.bool, + isLoading: PropTypes.bool, intl: PropTypes.object.isRequired, multiColumn: PropTypes.bool, }; @@ -43,7 +45,7 @@ class Blocks extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, accountIds, hasMore, multiColumn } = this.props; + const { intl, accountIds, hasMore, multiColumn, isLoading } = this.props; if (!accountIds) { return ( @@ -62,6 +64,7 @@ class Blocks extends ImmutablePureComponent { scrollKey='blocks' onLoadMore={this.handleLoadMore} hasMore={hasMore} + isLoading={isLoading} emptyMessage={emptyMessage} bindToDocument={!multiColumn} > diff --git a/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js b/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js index 404504e84..bee06e64c 100644 --- a/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js +++ b/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js @@ -64,9 +64,9 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('touchend', this.handleDocumentClick, withPassive); if (this.focusedItem) { - this.focusedItem.focus(); + this.focusedItem.focus({ preventScroll: true }); } else { - this.node.firstChild.focus(); + this.node.firstChild.focus({ preventScroll: true }); } this.setState({ mounted: true }); } @@ -106,7 +106,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent const index = items.findIndex(item => { return (item.name === name); }); - let element; + let element = null; switch(e.key) { case 'Escape': @@ -117,18 +117,10 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent this.handleClick(e); break; case 'ArrowDown': - element = this.node.childNodes[index + 1]; - if (element) { - element.focus(); - this.handleChange(element.getAttribute('data-index')); - } + element = this.node.childNodes[index + 1] || this.node.firstChild; break; case 'ArrowUp': - element = this.node.childNodes[index - 1]; - if (element) { - element.focus(); - this.handleChange(element.getAttribute('data-index')); - } + element = this.node.childNodes[index - 1] || this.node.lastChild; break; case 'Tab': if (e.shiftKey) { @@ -136,28 +128,21 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent } else { element = this.node.childNodes[index + 1] || this.node.firstChild; } - if (element) { - element.focus(); - this.handleChange(element.getAttribute('data-index')); - e.preventDefault(); - e.stopPropagation(); - } break; case 'Home': element = this.node.firstChild; - if (element) { - element.focus(); - this.handleChange(element.getAttribute('data-index')); - } break; case 'End': element = this.node.lastChild; - if (element) { - element.focus(); - this.handleChange(element.getAttribute('data-index')); - } break; } + + if (element) { + element.focus(); + this.handleChange(element.getAttribute('data-index')); + e.preventDefault(); + e.stopPropagation(); + } } setFocusRef = c => { diff --git a/app/javascript/flavours/glitch/features/follow_requests/index.js b/app/javascript/flavours/glitch/features/follow_requests/index.js index efbe1a23c..36a57d1d6 100644 --- a/app/javascript/flavours/glitch/features/follow_requests/index.js +++ b/app/javascript/flavours/glitch/features/follow_requests/index.js @@ -19,6 +19,7 @@ const messages = defineMessages({ const mapStateToProps = state => ({ accountIds: state.getIn(['user_lists', 'follow_requests', 'items']), + isLoading: state.getIn(['user_lists', 'follow_requests', 'isLoading'], true), hasMore: !!state.getIn(['user_lists', 'follow_requests', 'next']), locked: !!state.getIn(['accounts', me, 'locked']), domain: state.getIn(['meta', 'domain']), @@ -32,6 +33,7 @@ class FollowRequests extends ImmutablePureComponent { params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, hasMore: PropTypes.bool, + isLoading: PropTypes.bool, accountIds: ImmutablePropTypes.list, locked: PropTypes.bool, domain: PropTypes.string, @@ -48,7 +50,7 @@ class FollowRequests extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, accountIds, hasMore, multiColumn, locked, domain } = this.props; + const { intl, accountIds, hasMore, multiColumn, locked, domain, isLoading } = this.props; if (!accountIds) { return ( @@ -77,6 +79,7 @@ class FollowRequests extends ImmutablePureComponent { scrollKey='follow_requests' onLoadMore={this.handleLoadMore} hasMore={hasMore} + isLoading={isLoading} emptyMessage={emptyMessage} bindToDocument={!multiColumn} prepend={unlockedPrependMessage} diff --git a/app/javascript/flavours/glitch/features/followers/index.js b/app/javascript/flavours/glitch/features/followers/index.js index 2b86cc805..bf41f3b98 100644 --- a/app/javascript/flavours/glitch/features/followers/index.js +++ b/app/javascript/flavours/glitch/features/followers/index.js @@ -22,6 +22,7 @@ const mapStateToProps = (state, props) => ({ isAccount: !!state.getIn(['accounts', props.params.accountId]), accountIds: state.getIn(['user_lists', 'followers', props.params.accountId, 'items']), hasMore: !!state.getIn(['user_lists', 'followers', props.params.accountId, 'next']), + isLoading: state.getIn(['user_lists', 'followers', props.params.accountId, 'isLoading'], true), }); export default @connect(mapStateToProps) @@ -32,6 +33,7 @@ class Followers extends ImmutablePureComponent { dispatch: PropTypes.func.isRequired, accountIds: ImmutablePropTypes.list, hasMore: PropTypes.bool, + isLoading: PropTypes.bool, isAccount: PropTypes.bool, multiColumn: PropTypes.bool, }; @@ -54,14 +56,6 @@ class Followers extends ImmutablePureComponent { this.column.scrollTop(); } - handleScroll = (e) => { - const { scrollTop, scrollHeight, clientHeight } = e.target; - - if (scrollTop === scrollHeight - clientHeight && this.props.hasMore) { - this.props.dispatch(expandFollowers(this.props.params.accountId)); - } - } - handleLoadMore = debounce(() => { this.props.dispatch(expandFollowers(this.props.params.accountId)); }, 300, { leading: true }); @@ -71,7 +65,7 @@ class Followers extends ImmutablePureComponent { } render () { - const { accountIds, hasMore, isAccount, multiColumn } = this.props; + const { accountIds, hasMore, isAccount, multiColumn, isLoading } = this.props; if (!isAccount) { return ( @@ -98,6 +92,7 @@ class Followers extends ImmutablePureComponent { <ScrollableList scrollKey='followers' hasMore={hasMore} + isLoading={isLoading} onLoadMore={this.handleLoadMore} prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} alwaysPrepend diff --git a/app/javascript/flavours/glitch/features/following/index.js b/app/javascript/flavours/glitch/features/following/index.js index cf374e494..f090900cc 100644 --- a/app/javascript/flavours/glitch/features/following/index.js +++ b/app/javascript/flavours/glitch/features/following/index.js @@ -22,6 +22,7 @@ const mapStateToProps = (state, props) => ({ isAccount: !!state.getIn(['accounts', props.params.accountId]), accountIds: state.getIn(['user_lists', 'following', props.params.accountId, 'items']), hasMore: !!state.getIn(['user_lists', 'following', props.params.accountId, 'next']), + isLoading: state.getIn(['user_lists', 'following', props.params.accountId, 'isLoading'], true), }); export default @connect(mapStateToProps) @@ -32,6 +33,7 @@ class Following extends ImmutablePureComponent { dispatch: PropTypes.func.isRequired, accountIds: ImmutablePropTypes.list, hasMore: PropTypes.bool, + isLoading: PropTypes.bool, isAccount: PropTypes.bool, multiColumn: PropTypes.bool, }; @@ -54,14 +56,6 @@ class Following extends ImmutablePureComponent { this.column.scrollTop(); } - handleScroll = (e) => { - const { scrollTop, scrollHeight, clientHeight } = e.target; - - if (scrollTop === scrollHeight - clientHeight && this.props.hasMore) { - this.props.dispatch(expandFollowing(this.props.params.accountId)); - } - } - handleLoadMore = debounce(() => { this.props.dispatch(expandFollowing(this.props.params.accountId)); }, 300, { leading: true }); @@ -71,7 +65,7 @@ class Following extends ImmutablePureComponent { } render () { - const { accountIds, hasMore, isAccount, multiColumn } = this.props; + const { accountIds, hasMore, isAccount, multiColumn, isLoading } = this.props; if (!isAccount) { return ( @@ -98,6 +92,7 @@ class Following extends ImmutablePureComponent { <ScrollableList scrollKey='following' hasMore={hasMore} + isLoading={isLoading} onLoadMore={this.handleLoadMore} prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} alwaysPrepend diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js b/app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js index 9c39b158a..956f16734 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js @@ -4,6 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import Toggle from 'react-toggle'; import AsyncSelect from 'react-select/async'; +import SettingToggle from '../../notifications/components/setting_toggle'; const messages = defineMessages({ placeholder: { id: 'hashtag.column_settings.select.placeholder', defaultMessage: 'Enter hashtags…' }, @@ -87,6 +88,8 @@ class ColumnSettings extends React.PureComponent { }; render () { + const { settings, onChange } = this.props; + return ( <div> <div className='column-settings__row'> @@ -106,6 +109,10 @@ class ColumnSettings extends React.PureComponent { {this.modeSelect('none')} </div> )} + + <div className='column-settings__row'> + <SettingToggle settings={settings} settingPath={['local']} onChange={onChange} label={<FormattedMessage id='community.column_settings.local_only' defaultMessage='Local only' />} /> + </div> </div> ); } diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js index 16dd80c4f..e94f36501 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js @@ -97,21 +97,21 @@ class HashtagTimeline extends React.PureComponent { componentDidMount () { const { dispatch } = this.props; - const { id, tags } = this.props.params; + const { id, tags, local } = this.props.params; this._subscribe(dispatch, id, tags); - dispatch(expandHashtagTimeline(id, { tags })); + dispatch(expandHashtagTimeline(id, { tags, local })); } componentWillReceiveProps (nextProps) { const { dispatch, params } = this.props; - const { id, tags } = nextProps.params; + const { id, tags, local } = nextProps.params; - if (id !== params.id || !isEqual(tags, params.tags)) { + if (id !== params.id || !isEqual(tags, params.tags) || !isEqual(local, params.local)) { this._unsubscribe(); this._subscribe(dispatch, id, tags); - this.props.dispatch(clearTimeline(`hashtag:${id}`)); - this.props.dispatch(expandHashtagTimeline(id, { tags })); + dispatch(clearTimeline(`hashtag:${id}`)); + dispatch(expandHashtagTimeline(id, { tags, local })); } } @@ -124,8 +124,8 @@ class HashtagTimeline extends React.PureComponent { } handleLoadMore = maxId => { - const { id, tags } = this.props.params; - this.props.dispatch(expandHashtagTimeline(id, { maxId, tags })); + const { id, tags, local } = this.props.params; + this.props.dispatch(expandHashtagTimeline(id, { maxId, tags, local })); } render () { diff --git a/app/javascript/flavours/glitch/features/mutes/index.js b/app/javascript/flavours/glitch/features/mutes/index.js index 62dccd971..9f0d5a43e 100644 --- a/app/javascript/flavours/glitch/features/mutes/index.js +++ b/app/javascript/flavours/glitch/features/mutes/index.js @@ -19,6 +19,7 @@ const messages = defineMessages({ const mapStateToProps = state => ({ accountIds: state.getIn(['user_lists', 'mutes', 'items']), hasMore: !!state.getIn(['user_lists', 'mutes', 'next']), + isLoading: state.getIn(['user_lists', 'mutes', 'isLoading'], true), }); export default @connect(mapStateToProps) @@ -29,6 +30,7 @@ class Mutes extends ImmutablePureComponent { params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, hasMore: PropTypes.bool, + isLoading: PropTypes.bool, accountIds: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, multiColumn: PropTypes.bool, @@ -43,7 +45,7 @@ class Mutes extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, accountIds, hasMore, multiColumn } = this.props; + const { intl, accountIds, hasMore, multiColumn, isLoading } = this.props; if (!accountIds) { return ( @@ -62,6 +64,7 @@ class Mutes extends ImmutablePureComponent { scrollKey='mutes' onLoadMore={this.handleLoadMore} hasMore={hasMore} + isLoading={isLoading} emptyMessage={emptyMessage} bindToDocument={!multiColumn} > diff --git a/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js index 4fbd504ef..629f5c2ea 100644 --- a/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js +++ b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js @@ -24,19 +24,25 @@ class HashtagTimeline extends React.PureComponent { isLoading: PropTypes.bool.isRequired, hasMore: PropTypes.bool.isRequired, hashtag: PropTypes.string.isRequired, + local: PropTypes.bool.isRequired, + }; + + static defaultProps = { + local: false, }; componentDidMount () { - const { dispatch, hashtag } = this.props; + const { dispatch, hashtag, local } = this.props; - dispatch(expandHashtagTimeline(hashtag)); + dispatch(expandHashtagTimeline(hashtag, { local })); } handleLoadMore = () => { - const maxId = this.props.statusIds.last(); + const { dispatch, hashtag, local, statusIds } = this.props; + const maxId = statusIds.last(); if (maxId) { - this.props.dispatch(expandHashtagTimeline(this.props.hashtag, { maxId })); + dispatch(expandHashtagTimeline(hashtag, { maxId, local })); } } diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js index 180b11a54..17f22a8a2 100644 --- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js +++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js @@ -66,8 +66,8 @@ export default class DetailedStatus extends ImmutablePureComponent { e.stopPropagation(); } - handleOpenVideo = (media, startTime) => { - this.props.onOpenVideo(media, startTime); + handleOpenVideo = (media, options) => { + this.props.onOpenVideo(media, options); } _measureHeight (heightJustChanged) { diff --git a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js index e71803328..9d11f37e0 100644 --- a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js +++ b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js @@ -130,8 +130,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ dispatch(openModal('MEDIA', { media, index })); }, - onOpenVideo (media, time) { - dispatch(openModal('VIDEO', { media, time })); + onOpenVideo (media, options) { + dispatch(openModal('VIDEO', { media, options })); }, onBlock (status) { diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index 411d2a88d..a9abc545e 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -316,8 +316,8 @@ class Status extends ImmutablePureComponent { this.props.dispatch(openModal('MEDIA', { media, index })); } - handleOpenVideo = (media, time) => { - this.props.dispatch(openModal('VIDEO', { media, time })); + handleOpenVideo = (media, options) => { + this.props.dispatch(openModal('VIDEO', { media, options })); } handleHotkeyOpenMedia = e => { @@ -329,7 +329,7 @@ class Status extends ImmutablePureComponent { if (status.getIn(['media_attachments', 0, 'type']) === 'audio') { // TODO: toggle play/paused? } else if (status.getIn(['media_attachments', 0, 'type']) === 'video') { - this.handleOpenVideo(status.getIn(['media_attachments', 0]), 0); + this.handleOpenVideo(status.getIn(['media_attachments', 0]), { startTime: 0 }); } else { this.handleOpenMedia(status.get('media_attachments'), 0); } diff --git a/app/javascript/flavours/glitch/features/ui/components/video_modal.js b/app/javascript/flavours/glitch/features/ui/components/video_modal.js index e7309021e..afeff90a4 100644 --- a/app/javascript/flavours/glitch/features/ui/components/video_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/video_modal.js @@ -16,7 +16,11 @@ export default class VideoModal extends ImmutablePureComponent { static propTypes = { media: ImmutablePropTypes.map.isRequired, status: ImmutablePropTypes.map, - time: PropTypes.number, + options: PropTypes.shape({ + startTime: PropTypes.number, + autoPlay: PropTypes.bool, + defaultVolume: PropTypes.number, + }), onClose: PropTypes.func.isRequired, }; @@ -28,7 +32,8 @@ export default class VideoModal extends ImmutablePureComponent { } render () { - const { media, status, time, onClose } = this.props; + const { media, status, onClose } = this.props; + const options = this.props.options || {}; return ( <div className='modal-root__modal video-modal'> @@ -37,7 +42,9 @@ export default class VideoModal extends ImmutablePureComponent { preview={media.get('preview_url')} blurhash={media.get('blurhash')} src={media.get('url')} - startTime={time} + startTime={options.startTime} + autoPlay={options.autoPlay} + defaultVolume={options.defaultVolume} onCloseVideo={onClose} detailed alt={media.get('description')} diff --git a/app/javascript/flavours/glitch/features/video/index.js b/app/javascript/flavours/glitch/features/video/index.js index 6a8952c8d..a89d9c8b0 100644 --- a/app/javascript/flavours/glitch/features/video/index.js +++ b/app/javascript/flavours/glitch/features/video/index.js @@ -111,6 +111,8 @@ class Video extends React.PureComponent { preventPlayback: PropTypes.bool, blurhash: PropTypes.string, link: PropTypes.node, + autoPlay: PropTypes.bool, + defaultVolume: PropTypes.number, }; state = { @@ -360,6 +362,13 @@ class Video extends React.PureComponent { handleLoadedData = () => { if (this.props.startTime) { this.video.currentTime = this.props.startTime; + } + + if (this.props.defaultVolume !== undefined) { + this.video.volume = this.props.defaultVolume; + } + + if (this.props.autoPlay) { this.video.play(); } } @@ -386,8 +395,14 @@ class Video extends React.PureComponent { height, }); + const options = { + startTime: this.video.currentTime, + autoPlay: !this.state.paused, + defaultVolume: this.state.volume, + }; + this.video.pause(); - this.props.onOpenVideo(media, this.video.currentTime); + this.props.onOpenVideo(media, options); } handleCloseVideo = () => { |