diff --git a/app/soapbox/components/status.js b/app/soapbox/components/status.js index bc0dc1cbc..9c308c2f2 100644 --- a/app/soapbox/components/status.js +++ b/app/soapbox/components/status.js @@ -12,7 +12,7 @@ import AttachmentList from './attachment_list'; import Card from '../features/status/components/card'; import { injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { MediaGallery, Video } from '../features/ui/util/async-components'; +import { MediaGallery, Video, Audio } from '../features/ui/util/async-components'; import { HotKeys } from 'react-hotkeys'; import classNames from 'classnames'; import Icon from 'soapbox/components/icon'; @@ -73,6 +73,7 @@ class Status extends ImmutablePureComponent { onPin: PropTypes.func, onOpenMedia: PropTypes.func, onOpenVideo: PropTypes.func, + onOpenAudio: PropTypes.func, onBlock: PropTypes.func, onEmbed: PropTypes.func, onHeightChange: PropTypes.func, @@ -194,10 +195,18 @@ class Status extends ImmutablePureComponent { return
; } + renderLoadingAudioPlayer() { + return
; + } + handleOpenVideo = (media, startTime) => { this.props.onOpenVideo(media, startTime); } + handleOpenAudio = (media, startTime) => { + this.props.OnOpenAudio(media, startTime); + } + handleHotkeyReply = e => { e.preventDefault(); this.props.onReply(this._properStatus(), this.context.router.history); @@ -356,6 +365,23 @@ class Status extends ImmutablePureComponent { )} ); + } else if (status.getIn(['media_attachments', 0, 'type']) === 'audio') { + const audio = status.getIn(['media_attachments', 0]); + + media = ( + + {Component => ( + + )} + + ); } else { media = ( diff --git a/app/soapbox/containers/status_container.js b/app/soapbox/containers/status_container.js index 0e25f9e65..d84141165 100644 --- a/app/soapbox/containers/status_container.js +++ b/app/soapbox/containers/status_container.js @@ -146,6 +146,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ dispatch(openModal('VIDEO', { media, time })); }, + onOpenAudio(media, time) { + dispatch(openModal('AUDIO', { media, time })); + }, + onBlock(status) { const account = status.get('account'); dispatch(openModal('CONFIRM', { diff --git a/app/soapbox/features/account_gallery/index.js b/app/soapbox/features/account_gallery/index.js index de2213b07..4736f48aa 100644 --- a/app/soapbox/features/account_gallery/index.js +++ b/app/soapbox/features/account_gallery/index.js @@ -133,6 +133,8 @@ class AccountGallery extends ImmutablePureComponent { handleOpenMedia = attachment => { if (attachment.get('type') === 'video') { this.props.dispatch(openModal('VIDEO', { media: attachment, status: attachment.get('status') })); + } else if (attachment.get('type') === 'audio') { + this.props.dispatch(openModal('AUDIO', { media: attachment, status: attachment.get('status') })); } else { const media = attachment.getIn(['status', 'media_attachments']); const index = media.findIndex(x => x.get('id') === attachment.get('id')); diff --git a/app/soapbox/features/audio/index.js b/app/soapbox/features/audio/index.js index 3d35a2e96..256fa4ab9 100644 --- a/app/soapbox/features/audio/index.js +++ b/app/soapbox/features/audio/index.js @@ -2,7 +2,7 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import { fromJS, is } from 'immutable'; +import { is } from 'immutable'; import { throttle } from 'lodash'; import classNames from 'classnames'; import Icon from 'soapbox/components/icon'; @@ -11,7 +11,11 @@ import { getSettings } from 'soapbox/actions/settings'; const messages = defineMessages({ play: { id: 'audio.play', defaultMessage: 'Play' }, pause: { id: 'audio.pause', defaultMessage: 'Pause' }, - hide: { id: 'video.hide', defaultMessage: 'Hide audio' }, + mute: { id: 'audio.mute', defaultMessage: 'Mute' }, + unmute: { id: 'audio.unmute', defaultMessage: 'Unmute' }, + hide: { id: 'audio.hide', defaultMessage: 'Hide audio' }, + expand: { id: 'audio.expand', defaultMessage: 'Expand audio' }, + close: { id: 'audio.close', defaultMessage: 'Close audio' }, }); const formatTime = secondsNum => { @@ -20,7 +24,7 @@ const formatTime = secondsNum => { let seconds = secondsNum - (hours * 3600) - (minutes * 60); if (hours < 10) hours = '0' + hours; - if (minutes < 10) minutes = '0' + minutes; + if (minutes < 10 && hours >= 1) minutes = '0' + minutes; if (seconds < 10) seconds = '0' + seconds; return (hours === '00' ? '' : `${hours}:`) + `${minutes}:${seconds}`; @@ -92,8 +96,6 @@ class Audio extends React.PureComponent { alt: PropTypes.string, sensitive: PropTypes.bool, startTime: PropTypes.number, - onOpenAudio: PropTypes.func, - onCloseAudio: PropTypes.func, detailed: PropTypes.bool, inline: PropTypes.bool, cacheWidth: PropTypes.func, @@ -110,7 +112,6 @@ class Audio extends React.PureComponent { volume: 0.5, paused: true, dragging: false, - hovered: false, muted: false, revealed: this.props.visible !== undefined ? this.props.visible : (this.props.displayMedia !== 'hide_all' && !this.props.sensitive || this.props.displayMedia === 'show_all'), }; @@ -118,10 +119,10 @@ class Audio extends React.PureComponent { // hard coded in components.scss // any way to get ::before values programatically? volWidth = 50; - volOffset = 70; + volOffset = 85; volHandleOffset = v => { const offset = v * this.volWidth + this.volOffset; - return (offset > 110) ? 110 : offset; + return (offset > 125) ? 125 : offset; } setPlayerRef = c => { @@ -233,7 +234,7 @@ class Audio extends React.PureComponent { handleMouseMove = throttle(e => { const { x } = getPointerPosition(this.seek, e); - const currentTime = Math.floor(this.video.duration * x); + const currentTime = Math.floor(this.audio.duration * x); if (!isNaN(currentTime)) { this.audio.currentTime = currentTime; @@ -261,14 +262,6 @@ class Audio extends React.PureComponent { } } - handleMouseEnter = () => { - this.setState({ hovered: true }); - } - - handleMouseLeave = () => { - this.setState({ hovered: false }); - } - toggleMute = () => { this.audio.muted = !this.audio.muted; this.setState({ muted: this.audio.muted }); @@ -299,24 +292,6 @@ class Audio extends React.PureComponent { this.setState({ volume: this.audio.volume, muted: this.audio.muted }); } - handleOpenAudio = () => { - const { src, alt } = this.props; - - const media = fromJS({ - type: 'audio', - url: src, - description: alt, - }); - - this.audio.pause(); - this.props.onOpenAudio(media, this.audio.currentTime); - } - - handleCloseAudio = () => { - this.audio.pause(); - this.props.onCloseAudio(); - } - getPreload = () => { const { startTime, detailed } = this.props; const { dragging } = this.state; @@ -331,8 +306,8 @@ class Audio extends React.PureComponent { } render() { - const { src, inline, onOpenAudio, onCloseAudio, intl, alt, detailed, sensitive, link } = this.props; - const { currentTime, duration, volume, buffer, dragging, paused, hovered, muted, revealed } = this.state; + const { src, inline, intl, alt, detailed, sensitive, link } = this.props; + const { currentTime, duration, volume, buffer, dragging, paused, muted, revealed } = this.state; const progress = (currentTime / duration) * 100; const volumeWidth = (muted) ? 0 : volume * this.volWidth; @@ -361,6 +336,7 @@ class Audio extends React.PureComponent { {revealed &&
-
+
@@ -409,21 +385,17 @@ class Audio extends React.PureComponent { />
- {detailed && ( - - {formatTime(currentTime)} - / - {formatTime(duration)} - - )} + + {formatTime(currentTime)} + / + {formatTime(duration)} + {link && {link}}
- {(onOpenAudio) && } - {!onCloseAudio && } - {onCloseAudio && } + {}
@@ -431,4 +403,4 @@ class Audio extends React.PureComponent { ); } -} \ No newline at end of file +} diff --git a/app/soapbox/features/compose/components/upload_button.js b/app/soapbox/features/compose/components/upload_button.js index 989a75c7c..6e8f5b82e 100644 --- a/app/soapbox/features/compose/components/upload_button.js +++ b/app/soapbox/features/compose/components/upload_button.js @@ -52,7 +52,7 @@ class UploadButton extends ImmutablePureComponent { } render() { - const { intl, resetFileKey, unavailable, disabled, acceptContentTypes } = this.props; + const { intl, resetFileKey, unavailable, disabled } = this.props; if (unavailable) { return null; @@ -68,7 +68,8 @@ class UploadButton extends ImmutablePureComponent { ref={this.setRef} type='file' multiple - accept={acceptContentTypes.toArray().join(',')} + accept='*.*' + //accept={acceptContentTypes.toArray().join(',')} onChange={this.handleChange} disabled={disabled} style={{ display: 'none' }} diff --git a/app/soapbox/features/status/components/detailed_status.js b/app/soapbox/features/status/components/detailed_status.js index 558c6d9b7..6d38e06e9 100644 --- a/app/soapbox/features/status/components/detailed_status.js +++ b/app/soapbox/features/status/components/detailed_status.js @@ -10,6 +10,7 @@ import { FormattedDate, FormattedNumber } from 'react-intl'; import Card from './card'; import ImmutablePureComponent from 'react-immutable-pure-component'; import Video from '../../video'; +import Audio from '../../audio'; import scheduleIdleTask from '../../ui/util/schedule_idle_task'; import classNames from 'classnames'; import Icon from 'soapbox/components/icon'; @@ -120,6 +121,19 @@ export default class DetailedStatus extends ImmutablePureComponent { onToggleVisibility={this.props.onToggleMediaVisibility} /> ); + } else if (status.getIn(['media_attachments', 0, 'type']) === 'audio') { + const audio = status.getIn(['media_attachments', 0]); + + media = ( +