From b4394ec12954414b7d601473ecb21a49d9558082 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 2 May 2025 18:15:00 +0200 Subject: [PATCH] Change design of audio player in web UI (#34520) --- app/javascript/mastodon/blurhash.ts | 10 +- .../picture_in_picture_placeholder.jsx | 37 - .../picture_in_picture_placeholder.tsx | 46 + app/javascript/mastodon/components/status.jsx | 5 +- .../mastodon/containers/media_container.jsx | 2 +- .../features/alt_text_modal/index.tsx | 4 +- .../mastodon/features/audio/index.jsx | 588 ------------ .../mastodon/features/audio/index.tsx | 840 ++++++++++++++++++ .../mastodon/features/audio/visualizer.js | 136 --- .../components/embedded_status.tsx | 5 +- .../components/notification_mention.tsx | 3 +- .../picture_in_picture/components/footer.jsx | 195 ---- .../picture_in_picture/components/footer.tsx | 255 ++++++ .../features/picture_in_picture/index.tsx | 14 +- .../status/components/detailed_status.tsx | 18 +- .../features/ui/components/audio_modal.jsx | 74 -- .../features/ui/components/audio_modal.tsx | 78 ++ .../features/ui/components/media_modal.jsx | 2 +- .../features/ui/components/video_modal.jsx | 2 +- .../mastodon/features/video/index.tsx | 6 +- .../mastodon/hooks/useAudioVisualizer.ts | 112 +++ app/javascript/mastodon/reducers/statuses.js | 3 +- .../material-icons/400-24px/pip_exit-fill.svg | 1 + .../material-icons/400-24px/pip_exit.svg | 1 + .../styles/mastodon/components.scss | 125 ++- .../styles/mastodon/css_variables.scss | 2 +- 26 files changed, 1476 insertions(+), 1088 deletions(-) delete mode 100644 app/javascript/mastodon/components/picture_in_picture_placeholder.jsx create mode 100644 app/javascript/mastodon/components/picture_in_picture_placeholder.tsx delete mode 100644 app/javascript/mastodon/features/audio/index.jsx create mode 100644 app/javascript/mastodon/features/audio/index.tsx delete mode 100644 app/javascript/mastodon/features/audio/visualizer.js delete mode 100644 app/javascript/mastodon/features/picture_in_picture/components/footer.jsx create mode 100644 app/javascript/mastodon/features/picture_in_picture/components/footer.tsx delete mode 100644 app/javascript/mastodon/features/ui/components/audio_modal.jsx create mode 100644 app/javascript/mastodon/features/ui/components/audio_modal.tsx create mode 100644 app/javascript/mastodon/hooks/useAudioVisualizer.ts create mode 100644 app/javascript/material-icons/400-24px/pip_exit-fill.svg create mode 100644 app/javascript/material-icons/400-24px/pip_exit.svg diff --git a/app/javascript/mastodon/blurhash.ts b/app/javascript/mastodon/blurhash.ts index cafe7b12dc..a1d1a0f4e1 100644 --- a/app/javascript/mastodon/blurhash.ts +++ b/app/javascript/mastodon/blurhash.ts @@ -96,13 +96,19 @@ export const decode83 = (str: string) => { return value; }; -export const intToRGB = (int: number) => ({ +export interface RGB { + r: number; + g: number; + b: number; +} + +export const intToRGB = (int: number): RGB => ({ r: Math.max(0, int >> 16), g: Math.max(0, (int >> 8) & 255), b: Math.max(0, int & 255), }); -export const getAverageFromBlurhash = (blurhash: string) => { +export const getAverageFromBlurhash = (blurhash: string | null) => { if (!blurhash) { return null; } diff --git a/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx b/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx deleted file mode 100644 index 50f91a9275..0000000000 --- a/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx +++ /dev/null @@ -1,37 +0,0 @@ -import PropTypes from 'prop-types'; -import { PureComponent } from 'react'; - -import { FormattedMessage } from 'react-intl'; - -import { connect } from 'react-redux'; - -import CancelPresentationIcon from '@/material-icons/400-24px/cancel_presentation.svg?react'; -import { removePictureInPicture } from 'mastodon/actions/picture_in_picture'; -import { Icon } from 'mastodon/components/icon'; - -class PictureInPicturePlaceholder extends PureComponent { - - static propTypes = { - dispatch: PropTypes.func.isRequired, - aspectRatio: PropTypes.string, - }; - - handleClick = () => { - const { dispatch } = this.props; - dispatch(removePictureInPicture()); - }; - - render () { - const { aspectRatio } = this.props; - - return ( -
- - -
- ); - } - -} - -export default connect()(PictureInPicturePlaceholder); diff --git a/app/javascript/mastodon/components/picture_in_picture_placeholder.tsx b/app/javascript/mastodon/components/picture_in_picture_placeholder.tsx new file mode 100644 index 0000000000..829ab5febd --- /dev/null +++ b/app/javascript/mastodon/components/picture_in_picture_placeholder.tsx @@ -0,0 +1,46 @@ +import { useCallback } from 'react'; + +import { FormattedMessage } from 'react-intl'; + +import PipExitIcon from '@/material-icons/400-24px/pip_exit.svg?react'; +import { removePictureInPicture } from 'mastodon/actions/picture_in_picture'; +import { Icon } from 'mastodon/components/icon'; +import { useAppDispatch } from 'mastodon/store'; + +export const PictureInPicturePlaceholder: React.FC<{ aspectRatio: string }> = ({ + aspectRatio, +}) => { + const dispatch = useAppDispatch(); + + const handleClick = useCallback(() => { + dispatch(removePictureInPicture()); + }, [dispatch]); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + e.stopPropagation(); + handleClick(); + } + }, + [handleClick], + ); + + return ( +
+ + +
+ ); +}; diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index c45942dde4..21d596a58c 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -17,7 +17,7 @@ import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; import { ContentWarning } from 'mastodon/components/content_warning'; import { FilterWarning } from 'mastodon/components/filter_warning'; import { Icon } from 'mastodon/components/icon'; -import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder'; +import { PictureInPicturePlaceholder } from 'mastodon/components/picture_in_picture_placeholder'; import { withOptionalRouter, WithOptionalRouterPropTypes } from 'mastodon/utils/react_router'; import Card from '../features/status/components/card'; @@ -484,9 +484,6 @@ class Status extends ImmutablePureComponent { foregroundColor={attachment.getIn(['meta', 'colors', 'foreground'])} accentColor={attachment.getIn(['meta', 'colors', 'accent'])} duration={attachment.getIn(['meta', 'original', 'duration'], 0)} - width={this.props.cachedMediaWidth} - height={110} - cacheWidth={this.props.cacheMediaWidth} deployPictureInPicture={pictureInPicture.get('available') ? this.handleDeployPictureInPicture : undefined} sensitive={status.get('sensitive')} blurhash={attachment.get('blurhash')} diff --git a/app/javascript/mastodon/containers/media_container.jsx b/app/javascript/mastodon/containers/media_container.jsx index 9c07341faa..e826dbfa96 100644 --- a/app/javascript/mastodon/containers/media_container.jsx +++ b/app/javascript/mastodon/containers/media_container.jsx @@ -8,7 +8,7 @@ import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag'; import MediaGallery from 'mastodon/components/media_gallery'; import ModalRoot from 'mastodon/components/modal_root'; import { Poll } from 'mastodon/components/poll'; -import Audio from 'mastodon/features/audio'; +import { Audio } from 'mastodon/features/audio'; import Card from 'mastodon/features/status/components/card'; import MediaModal from 'mastodon/features/ui/components/media_modal'; import { Video } from 'mastodon/features/video'; diff --git a/app/javascript/mastodon/features/alt_text_modal/index.tsx b/app/javascript/mastodon/features/alt_text_modal/index.tsx index e2d05a99ca..08e4a8917c 100644 --- a/app/javascript/mastodon/features/alt_text_modal/index.tsx +++ b/app/javascript/mastodon/features/alt_text_modal/index.tsx @@ -27,7 +27,7 @@ import { Button } from 'mastodon/components/button'; import { GIFV } from 'mastodon/components/gifv'; import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import { Skeleton } from 'mastodon/components/skeleton'; -import Audio from 'mastodon/features/audio'; +import { Audio } from 'mastodon/features/audio'; import { CharacterCounter } from 'mastodon/features/compose/components/character_counter'; import { Tesseract as fetchTesseract } from 'mastodon/features/ui/util/async-components'; import { Video, getPointerPosition } from 'mastodon/features/video'; @@ -212,11 +212,11 @@ const Preview: React.FC<{ return (