diff --git a/packages/block-library/src/image/edit.native.js b/packages/block-library/src/image/edit.native.js index 53334a888dd94..0f2448e64dc2c 100644 --- a/packages/block-library/src/image/edit.native.js +++ b/packages/block-library/src/image/edit.native.js @@ -2,7 +2,7 @@ * External dependencies */ import React from 'react'; -import { View, ImageBackground, Text, TouchableWithoutFeedback, Dimensions } from 'react-native'; +import { View, ImageBackground, Text, TouchableWithoutFeedback, Dimensions, Platform } from 'react-native'; import { requestMediaImport, mediaUploadSync, @@ -15,6 +15,7 @@ import { isEmpty, map } from 'lodash'; * WordPress dependencies */ import { + ImageViewer, TextControl, ToggleControl, SelectControl, @@ -75,6 +76,7 @@ export class ImageEdit extends React.Component { this.state = { isCaptionSelected: false, + showImageViewer: false, }; this.finishMediaUploadWithSuccess = this.finishMediaUploadWithSuccess.bind( this ); @@ -139,9 +141,10 @@ export class ImageEdit extends React.Component { } else if ( attributes.id && ! isURL( attributes.url ) ) { requestImageFailedRetryDialog( attributes.id ); } - + const enableFullscreen = Platform.OS === 'ios'; this.setState( { isCaptionSelected: false, + showImageViewer: enableFullscreen && true, } ); } @@ -249,6 +252,10 @@ export class ImageEdit extends React.Component { const actions = [ { label: __( 'Clear All Settings' ), onPress: this.onClearSettings } ]; + const onImageViewerClose = () => { + this.setState( { showImageViewer: false } ); + }; + const getToolbarEditButton = ( open ) => ( @@ -308,6 +315,14 @@ export class ImageEdit extends React.Component { ); + const getImageViewer = () => ( + + ); + if ( ! url ) { return ( @@ -330,6 +345,7 @@ export class ImageEdit extends React.Component { }; const imageContainerHeight = Dimensions.get( 'window' ).width / IMAGE_ASPECT_RATIO; + const getImageComponent = ( openMediaOptions, getMediaOptions ) => ( { getInspectorControls() } + { getImageViewer() } { getMediaOptions() } { ( ! this.state.isCaptionSelected ) && getToolbarEditButton( openMediaOptions ) @@ -355,6 +372,7 @@ export class ImageEdit extends React.Component { renderContent={ ( { isUploadInProgress, isUploadFailed, finalWidth, finalHeight, imageWidthWithinContainer, retryMessage } ) => { const opacity = isUploadInProgress ? 0.3 : 1; const icon = this.getIcon( isUploadFailed ); + const imageBorderOnSelectedStyle = isSelected ? styles.imageBorder : ''; const iconContainer = ( @@ -374,7 +392,7 @@ export class ImageEdit extends React.Component { accessibilityLabel={ alt } accessibilityHint={ __( 'Double tap and hold to edit' ) } accessibilityRole={ 'imagebutton' } - style={ { width: finalWidth, height: finalHeight, opacity } } + style={ [ imageBorderOnSelectedStyle, { width: finalWidth, height: finalHeight, opacity } ] } resizeMethod="scale" source={ { uri: url } } key={ url } diff --git a/packages/block-library/src/image/styles.native.scss b/packages/block-library/src/image/styles.native.scss index 24b20de69dc8f..e153fae404737 100644 --- a/packages/block-library/src/image/styles.native.scss +++ b/packages/block-library/src/image/styles.native.scss @@ -6,6 +6,12 @@ background-color: $gray-lighten-30; } +.imageBorder { + border-color: $blue-medium; + border-width: 2px; + border-style: solid; +} + .uploadFailedText { color: #fff; font-size: 14; diff --git a/packages/components/src/index.native.js b/packages/components/src/index.native.js index e9aec0ad2fb71..684ac539c0cdd 100644 --- a/packages/components/src/index.native.js +++ b/packages/components/src/index.native.js @@ -30,6 +30,7 @@ export { default as withSpokenMessages } from './higher-order/with-spoken-messag // Mobile Components export { default as BottomSheet } from './mobile/bottom-sheet'; +export { default as ImageViewer } from './mobile/image-viewer'; export { default as HTMLTextInput } from './mobile/html-text-input'; export { default as KeyboardAvoidingView } from './mobile/keyboard-avoiding-view'; export { default as KeyboardAwareFlatList } from './mobile/keyboard-aware-flat-list'; diff --git a/packages/components/src/mobile/image-viewer/index.native.js b/packages/components/src/mobile/image-viewer/index.native.js new file mode 100644 index 0000000000000..a7e8f2eeedd25 --- /dev/null +++ b/packages/components/src/mobile/image-viewer/index.native.js @@ -0,0 +1,104 @@ +/** + * External dependencies + */ +import { View, Dimensions, ImageBackground, Image } from 'react-native'; +import Modal from 'react-native-modal'; + +/** + * WordPress dependencies + */ +import { Component } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import styles from './styles.scss'; + +class ImageViewer extends Component { + constructor() { + super( ...arguments ); + + this.state = { + width: undefined, + height: undefined, + }; + + this.onDimensionsChange = this.onDimensionsChange.bind( this ); + } + + componentDidMount() { + Dimensions.addEventListener( 'change', this.onDimensionsChange ); + this.fetchImageSize( Dimensions.get( 'window' ) ); + } + + componentDidUpdate( prevProps ) { + if ( this.props.url !== prevProps.url ) { + this.fetchImageSize( Dimensions.get( 'window' ) ); + } + } + + componentWillUnmount() { + Dimensions.removeEventListener( 'change', this.onDimensionsChange ); + } + + onDimensionsChange( dimensions ) { + this.fetchImageSize( dimensions.window ); + } + + fetchImageSize( dimensions ) { + Image.getSize( this.props.url, ( width, height ) => { + const { finalWidth, finalHeight } = this.calculateFullscreenImageSize( width, height, dimensions ); + this.setState( { width: finalWidth, height: finalHeight } ); + } ); + } + + calculateFullscreenImageSize( imageWidth, imageHeight, container ) { + const imageRatio = imageWidth / imageHeight; + const screenRatio = container.width / container.height; + let finalWidth = container.width; + let finalHeight = container.height; + const shouldUseContainerHeightForImage = imageRatio < screenRatio; + if ( shouldUseContainerHeightForImage ) { + finalWidth = container.height * imageRatio; + } else { + finalHeight = container.width / imageRatio; + } + return { finalWidth, finalHeight }; + } + + render() { + const { + isVisible, + url = '', + } = this.props; + + return ( + + + + + + ); + } +} + +export default ImageViewer; diff --git a/packages/components/src/mobile/image-viewer/styles.native.scss b/packages/components/src/mobile/image-viewer/styles.native.scss new file mode 100644 index 0000000000000..c66b5500fa09f --- /dev/null +++ b/packages/components/src/mobile/image-viewer/styles.native.scss @@ -0,0 +1,10 @@ +//Image Viewer + +.modal { + justify-content: center; + align-items: center; +} + +.content { + justify-content: center; +}