Page MenuHomePhabricator

D9496.id32010.diff
No OneTemporary

D9496.id32010.diff

diff --git a/web/media/multimedia-modal.react.js b/web/media/multimedia-modal.react.js
--- a/web/media/multimedia-modal.react.js
+++ b/web/media/multimedia-modal.react.js
@@ -1,13 +1,18 @@
// @flow
+import invariant from 'invariant';
import * as React from 'react';
+import { fetchableMediaURI } from 'lib/media/media-utils.js';
import type {
EncryptedMediaType,
MediaType,
Dimensions,
} from 'lib/types/media-types.js';
+import EncryptedMultimedia from './encrypted-multimedia.react.js';
+import LoadableVideo from './loadable-video.react.js';
+import { usePlaceholder } from './media-utils.js';
import FullScreenViewModal from '../modals/full-screen-view-modal.react.js';
type MediaInfo =
@@ -33,7 +38,87 @@
};
function MultimediaModal(props: Props): React.Node {
- return <FullScreenViewModal {...props} />;
+ const { media } = props;
+
+ const thumbHashEncryptionKey =
+ media.thumbnailEncryptionKey ?? media.encryptionKey;
+
+ const placeholderImage = usePlaceholder(
+ media.thumbHash,
+ thumbHashEncryptionKey,
+ );
+
+ const [dimensions, setDimensions] = React.useState<?Dimensions>(null);
+
+ const mediaModalItem = React.useMemo(() => {
+ if (media.type === 'photo') {
+ const uri = fetchableMediaURI(media.uri);
+ const style = {
+ backgroundImage: placeholderImage
+ ? `url(${placeholderImage})`
+ : undefined,
+ };
+
+ return <img src={uri} style={style} />;
+ }
+
+ if (media.type === 'video') {
+ const uri = fetchableMediaURI(media.uri);
+
+ const { thumbnailURI } = media;
+ invariant(thumbnailURI, 'video missing thumbnail');
+
+ return (
+ <LoadableVideo
+ uri={uri}
+ thumbnailSource={{ thumbnailURI }}
+ thumbHashDataURL={placeholderImage}
+ />
+ );
+ }
+
+ invariant(
+ media.type === 'encrypted_photo' || media.type === 'encrypted_video',
+ 'invalid media type',
+ );
+
+ const {
+ type,
+ blobURI,
+ encryptionKey,
+ thumbnailBlobURI,
+ thumbnailEncryptionKey,
+ } = media;
+
+ const contentDimensions = dimensions ?? media.dimensions;
+ const elementStyle = contentDimensions
+ ? {
+ width: `${contentDimensions.width}px`,
+ height: `${contentDimensions.height}px`,
+ }
+ : undefined;
+
+ return (
+ <EncryptedMultimedia
+ type={type}
+ blobURI={blobURI}
+ encryptionKey={encryptionKey}
+ thumbnailBlobURI={thumbnailBlobURI}
+ thumbnailEncryptionKey={thumbnailEncryptionKey}
+ placeholderSrc={placeholderImage}
+ elementStyle={elementStyle}
+ />
+ );
+ }, [dimensions, media, placeholderImage]);
+
+ return (
+ <FullScreenViewModal
+ contentDimensions={dimensions}
+ setContentDimensions={setDimensions}
+ >
+ {mediaModalItem}
+ </FullScreenViewModal>
+ );
}
export default MultimediaModal;
diff --git a/web/modals/full-screen-view-modal.css b/web/modals/full-screen-view-modal.css
--- a/web/modals/full-screen-view-modal.css
+++ b/web/modals/full-screen-view-modal.css
@@ -1,4 +1,4 @@
-div.multimediaModalOverlay .loadingIndicator {
+div.fullScreenModalOverlay .loadingIndicator {
position: absolute;
top: 0;
bottom: 0;
@@ -9,7 +9,7 @@
height: 25px;
}
-div.multimediaModalOverlay {
+div.fullScreenModalOverlay {
position: fixed;
left: 0;
top: 0;
@@ -24,18 +24,21 @@
justify-content: center;
-webkit-app-region: no-drag;
}
-div.multimediaModalOverlay > .mediaContainer {
+
+div.fullScreenModalOverlay > .contentContainer {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
-div.multimediaModalOverlay > .mediaContainer:focus {
+
+div.fullScreenModalOverlay > .contentContainer:focus {
outline: none;
}
-div.mediaContainer > img,
-div.mediaContainer > video {
+
+div.contentContainer > img,
+div.contentContainer > video {
width: auto;
height: auto;
max-width: 100%;
@@ -46,7 +49,8 @@
background-size: cover;
background-repeat: no-repeat;
}
-svg.closeMultimediaModal {
+
+svg.closeFullScreenModal {
position: absolute;
cursor: pointer;
top: 15px;
diff --git a/web/modals/full-screen-view-modal.react.js b/web/modals/full-screen-view-modal.react.js
--- a/web/modals/full-screen-view-modal.react.js
+++ b/web/modals/full-screen-view-modal.react.js
@@ -5,58 +5,25 @@
import { XCircle as XCircleIcon } from 'react-feather';
import { useModalContext } from 'lib/components/modal-provider.react.js';
-import { fetchableMediaURI } from 'lib/media/media-utils.js';
-import type {
- EncryptedMediaType,
- MediaType,
- Dimensions,
-} from 'lib/types/media-types.js';
+import type { SetState } from 'lib/types/hook-types.js';
+import type { Dimensions } from 'lib/types/media-types.js';
import css from './full-screen-view-modal.css';
-import EncryptedMultimedia from '../media/encrypted-multimedia.react.js';
-import LoadableVideo from '../media/loadable-video.react.js';
-import { usePlaceholder } from '../media/media-utils.js';
-
-type MediaInfo =
- | {
- +type: MediaType,
- +uri: string,
- +dimensions: ?Dimensions,
- +thumbHash: ?string,
- +thumbnailURI: ?string,
- }
- | {
- +type: EncryptedMediaType,
- +blobURI: string,
- +encryptionKey: string,
- +dimensions: ?Dimensions,
- +thumbHash: ?string,
- +thumbnailBlobURI: ?string,
- +thumbnailEncryptionKey: ?string,
- };
type BaseProps = {
- +media: MediaInfo,
+ +children: React.Node,
+ +contentDimensions: ?Dimensions,
+ +setContentDimensions: SetState<?Dimensions>,
};
type Props = {
...BaseProps,
+popModal: (modal: ?React.Node) => void,
- +placeholderImage: ?string,
-};
-
-type State = {
- +dimensions: ?Dimensions,
};
-class MultimediaModal extends React.PureComponent<Props, State> {
+class FullScreenModal extends React.PureComponent<Props> {
overlay: ?HTMLDivElement;
- constructor(props: Props) {
- super(props);
- this.state = { dimensions: null };
- }
-
componentDidMount() {
invariant(this.overlay, 'overlay ref unset');
this.overlay.focus();
@@ -69,75 +36,22 @@
}
render(): React.Node {
- let mediaModalItem;
- const { media, placeholderImage } = this.props;
- const style = {
- backgroundImage: placeholderImage
- ? `url(${placeholderImage})`
- : undefined,
- };
- if (media.type === 'photo') {
- const uri = fetchableMediaURI(media.uri);
- mediaModalItem = <img src={uri} style={style} />;
- } else if (media.type === 'video') {
- const uri = fetchableMediaURI(media.uri);
- const { thumbnailURI } = media;
- invariant(thumbnailURI, 'video missing thumbnail');
- mediaModalItem = (
- <LoadableVideo
- uri={uri}
- thumbnailSource={{ thumbnailURI }}
- thumbHashDataURL={placeholderImage}
- />
- );
- } else {
- invariant(
- media.type === 'encrypted_photo' || media.type === 'encrypted_video',
- 'invalid media type',
- );
- const {
- type,
- blobURI,
- encryptionKey,
- thumbnailBlobURI,
- thumbnailEncryptionKey,
- } = media;
- const dimensions = this.state.dimensions ?? media.dimensions;
- const elementStyle = dimensions
- ? {
- width: `${dimensions.width}px`,
- height: `${dimensions.height}px`,
- }
- : undefined;
- mediaModalItem = (
- <EncryptedMultimedia
- type={type}
- blobURI={blobURI}
- encryptionKey={encryptionKey}
- thumbnailBlobURI={thumbnailBlobURI}
- thumbnailEncryptionKey={thumbnailEncryptionKey}
- placeholderSrc={placeholderImage}
- elementStyle={elementStyle}
- />
- );
- }
-
return (
<div
- className={css.multimediaModalOverlay}
+ className={css.fullScreenModalOverlay}
onClick={this.onBackgroundClick}
>
<div
ref={this.overlayRef}
- className={css.mediaContainer}
+ className={css.contentContainer}
tabIndex={0}
onKeyDown={this.onKeyDown}
>
- {mediaModalItem}
+ {this.props.children}
</div>
<XCircleIcon
onClick={this.props.popModal}
- className={css.closeMultimediaModal}
+ className={css.closeFullScreenModal}
/>
</div>
);
@@ -162,7 +76,7 @@
};
calculateMediaDimensions: () => void = () => {
- if (!this.overlay || !this.props.media.dimensions) {
+ if (!this.overlay || !this.props.contentDimensions) {
return;
}
const containerWidth = this.overlay.clientWidth;
@@ -170,7 +84,7 @@
const containerAspectRatio = containerWidth / containerHeight;
const { width: mediaWidth, height: mediaHeight } =
- this.props.media.dimensions;
+ this.props.contentDimensions;
const mediaAspectRatio = mediaWidth / mediaHeight;
let newWidth, newHeight;
@@ -181,28 +95,17 @@
newHeight = Math.min(mediaHeight, containerWidth / mediaAspectRatio);
newWidth = newHeight * mediaAspectRatio;
}
- this.setState({
- dimensions: {
- width: newWidth,
- height: newHeight,
- },
+ this.props.setContentDimensions({
+ width: newWidth,
+ height: newHeight,
});
};
}
-function ConnectedMultiMediaModal(props: BaseProps): React.Node {
+function ConnectedFullScreenModal(props: BaseProps): React.Node {
const modalContext = useModalContext();
- const { thumbHash, encryptionKey, thumbnailEncryptionKey } = props.media;
- const thumbHashEncryptionKey = thumbnailEncryptionKey ?? encryptionKey;
- const placeholderImage = usePlaceholder(thumbHash, thumbHashEncryptionKey);
-
- return (
- <MultimediaModal
- {...props}
- popModal={modalContext.popModal}
- placeholderImage={placeholderImage}
- />
- );
+
+ return <FullScreenModal {...props} popModal={modalContext.popModal} />;
}
-export default ConnectedMultiMediaModal;
+export default ConnectedFullScreenModal;

File Metadata

Mime Type
text/plain
Expires
Sun, Oct 6, 10:55 PM (21 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2251242
Default Alt Text
D9496.id32010.diff (9 KB)

Event Timeline