From 2bbf987a0a352a36ef0cc7f06fe366b60593e89c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 14 Sep 2017 03:39:10 +0200 Subject: [PATCH] Redesign video player (#4911) * Redesign video player * Use new video player on static public pages too * Use media gallery component on static public pages too * Pause video when hiding it * Full-screen sizing on WebKit * Add aria labels to video player buttons * Display link card on public status page * Fix fullscreen from modal sizing issue * Remove contain: strict property to fix fullscreen from columns --- app/javascript/mastodon/components/status.js | 19 +- .../mastodon/containers/card_container.js | 18 ++ .../containers/media_gallery_container.js | 34 ++ .../mastodon/containers/video_container.js | 26 ++ .../features/status/components/card.js | 10 +- .../status/components/detailed_status.js | 19 +- .../features/ui/components/video_modal.js | 22 +- .../features/ui/util/async-components.js | 4 + .../mastodon/features/video/index.js | 304 ++++++++++++++++++ app/javascript/mastodon/locales/ar.json | 11 + app/javascript/mastodon/locales/bg.json | 11 + app/javascript/mastodon/locales/ca.json | 11 + app/javascript/mastodon/locales/de.json | 11 + .../mastodon/locales/defaultMessages.json | 62 ++++ app/javascript/mastodon/locales/en.json | 13 +- app/javascript/mastodon/locales/eo.json | 11 + app/javascript/mastodon/locales/es.json | 11 + app/javascript/mastodon/locales/fa.json | 13 +- app/javascript/mastodon/locales/fi.json | 11 + app/javascript/mastodon/locales/fr.json | 13 +- app/javascript/mastodon/locales/he.json | 11 + app/javascript/mastodon/locales/hr.json | 12 +- app/javascript/mastodon/locales/hu.json | 11 + app/javascript/mastodon/locales/id.json | 11 + app/javascript/mastodon/locales/io.json | 11 + app/javascript/mastodon/locales/it.json | 11 + app/javascript/mastodon/locales/ja.json | 13 +- app/javascript/mastodon/locales/ko.json | 13 +- app/javascript/mastodon/locales/nl.json | 11 + app/javascript/mastodon/locales/no.json | 11 + app/javascript/mastodon/locales/oc.json | 13 +- app/javascript/mastodon/locales/pl.json | 9 + app/javascript/mastodon/locales/pt-BR.json | 13 +- app/javascript/mastodon/locales/pt.json | 11 + app/javascript/mastodon/locales/ru.json | 11 + app/javascript/mastodon/locales/th.json | 11 + app/javascript/mastodon/locales/tr.json | 11 + app/javascript/mastodon/locales/uk.json | 11 + app/javascript/mastodon/locales/zh-CN.json | 11 + app/javascript/mastodon/locales/zh-HK.json | 11 + app/javascript/mastodon/locales/zh-TW.json | 11 + app/javascript/packs/public.js | 30 +- app/javascript/styles/components.scss | 197 +++++++++++- app/javascript/styles/stream_entries.scss | 150 +-------- .../stream_entries/_detailed_status.html.haml | 15 +- .../stream_entries/_simple_status.html.haml | 17 +- 46 files changed, 1064 insertions(+), 217 deletions(-) create mode 100644 app/javascript/mastodon/containers/card_container.js create mode 100644 app/javascript/mastodon/containers/media_gallery_container.js create mode 100644 app/javascript/mastodon/containers/video_container.js create mode 100644 app/javascript/mastodon/features/video/index.js diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js index 30a0c10cb..82359156d 100644 --- a/app/javascript/mastodon/components/status.js +++ b/app/javascript/mastodon/components/status.js @@ -9,7 +9,7 @@ import StatusContent from './status_content'; import StatusActionBar from './status_action_bar'; import { FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { MediaGallery, VideoPlayer } from '../features/ui/util/async-components'; +import { MediaGallery, Video } from '../features/ui/util/async-components'; // We use the component (and not the container) since we do not want // to use the progress bar to show download progress @@ -88,6 +88,10 @@ export default class Status extends ImmutablePureComponent { return
; } + handleOpenVideo = startTime => { + this.props.onOpenVideo(this.props.status.getIn(['media_attachments', 0]), startTime); + } + render () { let media = null; let statusAvatar; @@ -127,9 +131,18 @@ export default class Status extends ImmutablePureComponent { if (status.get('media_attachments').some(item => item.get('type') === 'unknown')) { } else if (status.getIn(['media_attachments', 0, 'type']) === 'video') { + const video = status.getIn(['media_attachments', 0]); + media = ( - - {Component => } + + {Component => } ); } else { diff --git a/app/javascript/mastodon/containers/card_container.js b/app/javascript/mastodon/containers/card_container.js new file mode 100644 index 000000000..11b9f88d4 --- /dev/null +++ b/app/javascript/mastodon/containers/card_container.js @@ -0,0 +1,18 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Card from '../features/status/components/card'; +import { fromJS } from 'immutable'; + +export default class CardContainer extends React.PureComponent { + + static propTypes = { + locale: PropTypes.string, + card: PropTypes.array.isRequired, + }; + + render () { + const { card, ...props } = this.props; + return ; + } + +} diff --git a/app/javascript/mastodon/containers/media_gallery_container.js b/app/javascript/mastodon/containers/media_gallery_container.js new file mode 100644 index 000000000..812c3d4e5 --- /dev/null +++ b/app/javascript/mastodon/containers/media_gallery_container.js @@ -0,0 +1,34 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { IntlProvider, addLocaleData } from 'react-intl'; +import { getLocale } from '../locales'; +import MediaGallery from '../components/media_gallery'; +import { fromJS } from 'immutable'; + +const { localeData, messages } = getLocale(); +addLocaleData(localeData); + +export default class MediaGalleryContainer extends React.PureComponent { + + static propTypes = { + locale: PropTypes.string.isRequired, + media: PropTypes.array.isRequired, + }; + + handleOpenMedia = () => {} + + render () { + const { locale, media, ...props } = this.props; + + return ( + + + + ); + } + +} diff --git a/app/javascript/mastodon/containers/video_container.js b/app/javascript/mastodon/containers/video_container.js new file mode 100644 index 000000000..2fd353096 --- /dev/null +++ b/app/javascript/mastodon/containers/video_container.js @@ -0,0 +1,26 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { IntlProvider, addLocaleData } from 'react-intl'; +import { getLocale } from '../locales'; +import Video from '../features/video'; + +const { localeData, messages } = getLocale(); +addLocaleData(localeData); + +export default class VideoContainer extends React.PureComponent { + + static propTypes = { + locale: PropTypes.string.isRequired, + }; + + render () { + const { locale, ...props } = this.props; + + return ( + + + ); + } + +} diff --git a/app/javascript/mastodon/features/status/components/card.js b/app/javascript/mastodon/features/status/components/card.js index 6b13e15cc..41c4300d3 100644 --- a/app/javascript/mastodon/features/status/components/card.js +++ b/app/javascript/mastodon/features/status/components/card.js @@ -1,4 +1,5 @@ import React from 'react'; +import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import punycode from 'punycode'; import classnames from 'classnames'; @@ -22,10 +23,15 @@ export default class Card extends React.PureComponent { static propTypes = { card: ImmutablePropTypes.map, + maxDescription: PropTypes.number, + }; + + static defaultProps = { + maxDescription: 50, }; renderLink () { - const { card } = this.props; + const { card, maxDescription } = this.props; let image = ''; let provider = card.get('provider_name'); @@ -52,7 +58,7 @@ export default class Card extends React.PureComponent {
{card.get('title')} -

{(card.get('description') || '').substring(0, 50)}

+

{(card.get('description') || '').substring(0, maxDescription)}

{provider}
diff --git a/app/javascript/mastodon/features/status/components/detailed_status.js b/app/javascript/mastodon/features/status/components/detailed_status.js index 940a2699b..b11b41780 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.js +++ b/app/javascript/mastodon/features/status/components/detailed_status.js @@ -5,12 +5,12 @@ import Avatar from '../../../components/avatar'; import DisplayName from '../../../components/display_name'; import StatusContent from '../../../components/status_content'; import MediaGallery from '../../../components/media_gallery'; -import VideoPlayer from '../../../components/video_player'; import AttachmentList from '../../../components/attachment_list'; import Link from 'react-router-dom/Link'; import { FormattedDate, FormattedNumber } from 'react-intl'; import CardContainer from '../containers/card_container'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import Video from '../../video'; export default class DetailedStatus extends ImmutablePureComponent { @@ -34,6 +34,10 @@ export default class DetailedStatus extends ImmutablePureComponent { e.stopPropagation(); } + handleOpenVideo = startTime => { + this.props.onOpenVideo(this.props.status.getIn(['media_attachments', 0]), startTime); + } + render () { const status = this.props.status.get('reblog') ? this.props.status.get('reblog') : this.props.status; @@ -44,7 +48,18 @@ export default class DetailedStatus extends ImmutablePureComponent { if (status.get('media_attachments').some(item => item.get('type') === 'unknown')) { media = ; } else if (status.getIn(['media_attachments', 0, 'type']) === 'video') { - media = ; + const video = status.getIn(['media_attachments', 0]); + + media = ( +