Skip to content

Commit

Permalink
[Mobile] Video block ui/ux enhancements (#15551)
Browse files Browse the repository at this point in the history
* Pass media type to bridge

* Add video block

* Add media upload ui

* Add video block

* Extract media upload

* Fix lint issues

* Integrate RN video

* Integrate RN video

* Fix lint issues

* Rename MediaUploadUI

* Separate Android and iOS video player configs

* Fix lint issues

* Revert unwanted auto linter fix

* Update order of video block

* Fix typo

* Enhance placeholder

* Add retry action for video block

* Remove unused state property

* Fixed problem with cancel/retry uploading of video

* Set proper bottom sheet icons for video block

* Make sure that icon block has latest value of isUploadingInProgress

* Remove unnecessary code for video copy/paste handling

We are not supporting video copy paste, that code was copy/paste from image block

* Removing poster support

poster support isn't present on wp.com yet and react-native-video has an ugly bug
about posters so we'll need to solve that first, after that we'll re-add this.

* Implemented latest ui-ux on video block

* Aligned image block with video block

* Fixed logic on iOS when selecting video block first time, avoid to play a video

* Fixed crash when opening the post which previously had cancelled image/video upload

* Set black background for uploaded video

* Fixed retry icon color on image upload failed state

* Avoid loading video before it's uploaded
Fixes failing tests

* Fixed failed tests

* Set image background as black color with 50% alpha when image is in failed state

* Make sure that image/video block is selected when user taps on it

* Fixed issue with missing placeholder while image is uploading

* Reuse Icon function in image/video block and block picker

* Fixes issue with retry state background

* Fix icon crash and inject props to SVG icons

* Update video upload icon color and size, also caption padding

* Update Icon to accept a style prop

* Revert "Update Icon to accept a style prop"

This reverts commit a5bf475.

* Fix retry icon size
  • Loading branch information
marecar3 authored and pinarol committed May 21, 2019
1 parent c38327d commit 0773762
Show file tree
Hide file tree
Showing 15 changed files with 184 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { View, Text, TouchableWithoutFeedback } from 'react-native';
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { Dashicon } from '@wordpress/components';
import { MediaUpload, MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO } from '@wordpress/block-editor';

/**
Expand All @@ -31,21 +30,12 @@ function MediaPlaceholder( props ) {
}
}

let placeholderIcon = icon;
if ( placeholderIcon === undefined ) {
if ( isImage ) {
placeholderIcon = 'format-image';
} else if ( isVideo ) {
placeholderIcon = 'format-video';
}
}

let instructions = labels.instructions;
if ( instructions === undefined ) {
if ( isImage ) {
instructions = __( 'CHOOSE IMAGE' );
instructions = __( 'ADD IMAGE' );
} else if ( isVideo ) {
instructions = __( 'CHOOSE VIDEO' );
instructions = __( 'ADD VIDEO' );
}
}

Expand All @@ -70,11 +60,16 @@ function MediaPlaceholder( props ) {
) }
accessibilityRole={ 'button' }
accessibilityHint={ accessibilityHint }
onPress={ open }
onPress={ ( event ) => {
props.onFocus( event );
open();
} }
>
<View style={ styles.emptyStateContainer }>
{ getMediaOptions() }
<Dashicon icon={ placeholderIcon } />
<View style={ styles.modalIcon }>
{ icon }
</View>
<Text style={ styles.emptyStateTitle }>
{ placeholderTitle }
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #e9eff3;
background-color: $gray-light;
padding-left: 12;
padding-right: 12;
padding-top: 12;
Expand All @@ -21,7 +21,15 @@

.emptyStateDescription {
text-align: center;
color: #0087be;
color: $blue-wordpress;
font-size: 14;
font-weight: 500;
}

.modalIcon {
width: 24px;
height: 24px;
justify-content: center;
align-items: center;
fill: $gray-dark;
}
38 changes: 31 additions & 7 deletions packages/block-library/src/image/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* External dependencies
*/
import React from 'react';
import { View, ImageBackground, Text, TouchableWithoutFeedback } from 'react-native';
import { View, ImageBackground, Text, TouchableWithoutFeedback, Dimensions } from 'react-native';
import {
requestMediaImport,
mediaUploadSync,
Expand All @@ -17,7 +17,6 @@ import { isEmpty } from 'lodash';
import {
Toolbar,
ToolbarButton,
Dashicon,
} from '@wordpress/components';
import {
MediaPlaceholder,
Expand All @@ -37,10 +36,15 @@ import { doAction, hasAction } from '@wordpress/hooks';
*/
import styles from './styles.scss';
import MediaUploadProgress from './media-upload-progress';
import SvgIcon from './icon';
import SvgIconRetry from './icon-retry';

const LINK_DESTINATION_CUSTOM = 'custom';
const LINK_DESTINATION_NONE = 'none';

// Default Image ratio 4:3
const IMAGE_ASPECT_RATIO = 4 / 3;

class ImageEdit extends React.Component {
constructor( props ) {
super( props );
Expand Down Expand Up @@ -187,6 +191,14 @@ class ImageEdit extends React.Component {
}
}

getIcon( isRetryIcon ) {
if ( isRetryIcon ) {
return <SvgIconRetry fill={ styles.iconRetry.fill } />;
}

return <SvgIcon fill={ styles.icon.fill } />;
}

render() {
const { attributes, isSelected, setAttributes } = this.props;
const { url, caption, height, width, alt, href, id } = attributes;
Expand Down Expand Up @@ -256,11 +268,15 @@ class ImageEdit extends React.Component {
<MediaPlaceholder
mediaType={ MEDIA_TYPE_IMAGE }
onSelectURL={ this.onSelectMediaUploadOption }
icon={ this.getIcon( false ) }
onFocus={ this.props.onFocus }
/>
</View>
);
}

const imageContainerHeight = Dimensions.get( 'window' ).width / IMAGE_ASPECT_RATIO;

return (
<TouchableWithoutFeedback
accessible={ ! isSelected }
Expand Down Expand Up @@ -298,12 +314,20 @@ class ImageEdit extends React.Component {
onFinishMediaUploadWithSuccess={ this.finishMediaUploadWithSuccess }
onFinishMediaUploadWithFailure={ this.finishMediaUploadWithFailure }
onMediaUploadStateReset={ this.mediaUploadStateReset }
renderContent={ ( { isUploadInProgress, isUploadFailed, finalWidth, finalHeight, imageWidthWithinContainer, retryIconName, retryMessage } ) => {
renderContent={ ( { isUploadInProgress, isUploadFailed, finalWidth, finalHeight, imageWidthWithinContainer, retryMessage } ) => {
const opacity = isUploadInProgress ? 0.3 : 1;
const icon = this.getIcon( isUploadFailed );

const iconContainer = (
<View style={ styles.modalIcon }>
{ icon }
</View>
);

return (
<View style={ { flex: 1 } } >
{ ! imageWidthWithinContainer && <View style={ styles.imageContainer } >
<Dashicon icon={ 'format-image' } size={ 300 } />
{ ! imageWidthWithinContainer && <View style={ [ styles.imageContainer, { height: imageContainerHeight } ] } >
{ this.getIcon( false ) }
</View> }
<ImageBackground
style={ { width: finalWidth, height: finalHeight, opacity } }
Expand All @@ -314,8 +338,8 @@ class ImageEdit extends React.Component {
accessibilityLabel={ alt }
>
{ isUploadFailed &&
<View style={ styles.imageContainer } >
<Dashicon icon={ retryIconName } ariaPressed={ 'dashicon-active' } />
<View style={ [ styles.imageContainer, { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.5)' } ] } >
{ iconContainer }
<Text style={ styles.uploadFailedText }>{ retryMessage }</Text>
</View>
}
Expand Down
10 changes: 10 additions & 0 deletions packages/block-library/src/image/icon-retry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* WordPress dependencies
*/
import { Path, SVG } from '@wordpress/components';

function svg( props ) {
return <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" { ...props }><Path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" /><Path d="M0 0h24v24H0z" fill={ 'none' } /></SVG>;
}

export default svg;
6 changes: 5 additions & 1 deletion packages/block-library/src/image/icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@
*/
import { Path, SVG } from '@wordpress/components';

export default <SVG viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><Path d="M0,0h24v24H0V0z" fill="none" /><Path d="m19 5v14h-14v-14h14m0-2h-14c-1.1 0-2 0.9-2 2v14c0 1.1 0.9 2 2 2h14c1.1 0 2-0.9 2-2v-14c0-1.1-0.9-2-2-2z" /><Path d="m14.14 11.86l-3 3.87-2.14-2.59-3 3.86h12l-3.86-5.14z" /></SVG>;
function svg( props ) {
return <SVG viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" { ...props }><Path d="M0,0h24v24H0V0z" fill="none" /><Path d="m19 5v14h-14v-14h14m0-2h-14c-1.1 0-2 0.9-2 2v14c0 1.1 0.9 2 2 2h14c1.1 0 2-0.9 2-2v-14c0-1.1-0.9-2-2-2z" /><Path d="m14.14 11.86l-3 3.87-2.14-2.59-3 3.86h12l-3.86-5.14z" /></SVG>;
}

export default svg;
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { __ } from '@wordpress/i18n';
* Internal dependencies
*/
import ImageSize from './image-size';
import styles from './styles.scss';

export const MEDIA_UPLOAD_STATE_UPLOADING = 1;
export const MEDIA_UPLOAD_STATE_SUCCEEDED = 2;
Expand Down Expand Up @@ -118,11 +119,10 @@ export class MediaUploadProgress extends React.Component {
const { isUploadInProgress, isUploadFailed } = this.state;
const showSpinner = this.state.isUploadInProgress;
const progress = this.state.progress * 100;
const retryIconName = 'image-rotate';
const retryMessage = __( 'Failed to insert media.\nPlease tap for options.' );

return (
<View style={ { flex: 1 } }>
<View style={ styles.mediaUploadProgress }>
{ showSpinner && <Spinner progress={ progress } /> }
{ coverUrl &&
<ImageSize src={ coverUrl } >
Expand All @@ -147,7 +147,6 @@ export class MediaUploadProgress extends React.Component {
finalWidth,
finalHeight,
imageWidthWithinContainer,
retryIconName,
retryMessage,
} ) );
} }
Expand All @@ -156,7 +155,6 @@ export class MediaUploadProgress extends React.Component {
{ ! coverUrl && this.props.renderContent( {
isUploadInProgress,
isUploadFailed,
retryIconName,
retryMessage,
} ) }
</View>
Expand Down
22 changes: 21 additions & 1 deletion packages/block-library/src/image/styles.native.scss
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// @format

.imageContainer {
flex: 1;
justify-content: center;
align-items: center;
background-color: $gray-lighten-30;
}

.uploadFailedText {
Expand All @@ -21,3 +21,23 @@
.clearSettingsButton {
color: $alert-red;
}

.mediaUploadProgress {
flex: 1;
background-color: $gray-lighten-30;
}

.modalIcon {
width: 80px;
height: 80px;
justify-content: center;
align-items: center;
}

.iconRetry {
fill: #fff;
}

.icon {
fill: $gray-dark;
}
40 changes: 30 additions & 10 deletions packages/block-library/src/video/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
import {
Toolbar,
ToolbarButton,
Dashicon,
} from '@wordpress/components';
import {
MediaPlaceholder,
Expand All @@ -38,6 +37,8 @@ import { doAction, hasAction } from '@wordpress/hooks';
*/
import MediaUploadProgress from '../image/media-upload-progress';
import style from './style.scss';
import SvgIcon from './icon';
import SvgIconRetry from './icon-retry';

const VIDEO_ASPECT_RATIO = 1.7;

Expand Down Expand Up @@ -127,6 +128,14 @@ class VideoEdit extends React.Component {
}
}

getIcon( isRetryIcon, isUploadInProgress ) {
if ( isRetryIcon ) {
return <SvgIconRetry fill={ style.icon.fill } />;
}

return <SvgIcon fill={ isUploadInProgress ? style.iconUploading.fill : style.icon.fill } />;
}

render() {
const { attributes, isSelected, setAttributes } = this.props;
const { caption, id, src } = attributes;
Expand Down Expand Up @@ -156,6 +165,8 @@ class VideoEdit extends React.Component {
<MediaPlaceholder
mediaType={ MEDIA_TYPE_VIDEO }
onSelectURL={ this.onSelectMediaUploadOption }
icon={ this.getIcon( false ) }
onFocus={ this.props.onFocus }
/>
</View>
);
Expand All @@ -180,29 +191,38 @@ class VideoEdit extends React.Component {
onFinishMediaUploadWithFailure={ this.finishMediaUploadWithFailure }
onUpdateMediaProgress={ this.updateMediaProgress }
onMediaUploadStateReset={ this.mediaUploadStateReset }
renderContent={ ( { isUploadInProgress, isUploadFailed, retryIconName, retryMessage } ) => {
const opacity = ( isUploadInProgress || isUploadFailed ) ? 0.3 : 1;
renderContent={ ( { isUploadInProgress, isUploadFailed, retryMessage } ) => {
const showVideo = src && ! isUploadInProgress && ! isUploadFailed;
const iconName = isUploadFailed ? retryIconName : 'format-video';
const icon = this.getIcon( isUploadFailed, isUploadInProgress );
const styleIconContainer = isUploadFailed ? style.modalIconRetry : style.modalIcon;

const iconContainer = (
<View style={ styleIconContainer }>
{ icon }
</View>
);

const videoStyle = {
height: videoContainerHeight,
...style.video,
};

const containerStyle = showVideo && isSelected ? style.containerFocused : style.container;

return (
<View onLayout={ this.onVideoContanerLayout } style={ { flex: 1 } }>
{ showVideo &&
<View onLayout={ this.onVideoContanerLayout } style={ containerStyle }>
{ showVideo && isURL( src ) &&
<Video
isSelected={ isSelected }
style={ [ videoStyle, { backgroundColor: 'black' } ] }
source={ { uri: src } }
style={ videoStyle }
paused={ true }
muted={ true }
/>
}
{ ! showVideo &&
<View style={ { ...videoStyle, ...style.placeholder, opacity } }>
{ videoContainerHeight > 0 && <Dashicon icon={ iconName } size={ 80 } style={ style.placeholderIcon } /> }
<View style={ { ...videoStyle, ...style.placeholder } }>
{ videoContainerHeight > 0 && iconContainer }
{ isUploadFailed && <Text style={ style.uploadFailedText }>{ retryMessage }</Text> }
</View>
}
Expand All @@ -211,7 +231,7 @@ class VideoEdit extends React.Component {
} }
/>
{ ( ! RichText.isEmpty( caption ) > 0 || isSelected ) && (
<View style={ { padding: 12, flex: 1 } }>
<View style={ { paddingTop: 8, paddingBottom: 0, flex: 1 } }>
<TextInput
style={ { textAlign: 'center' } }
fontFamily={ this.props.fontFamily || ( style[ 'caption-text' ].fontFamily ) }
Expand Down
10 changes: 10 additions & 0 deletions packages/block-library/src/video/icon-retry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* WordPress dependencies
*/
import { Path, SVG } from '@wordpress/components';

function svg( props ) {
return <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" { ...props }><Path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" /><Path d="M0 0h24v24H0z" fill="none" /></SVG>;
}

export default svg;
6 changes: 5 additions & 1 deletion packages/block-library/src/video/icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@
*/
import { Path, SVG } from '@wordpress/components';

export default <SVG viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><Path fill="none" d="M0 0h24v24H0V0z" /><Path d="M4 6.47L5.76 10H20v8H4V6.47M22 4h-4l2 4h-3l-2-4h-2l2 4h-3l-2-4H8l2 4H7L5 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4z" /></SVG>;
function svg( props ) {
return <SVG viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" { ...props }><Path fill="none" d="M0 0h24v24H0V0z" /><Path d="M4 6.47L5.76 10H20v8H4V6.47M22 4h-4l2 4h-3l-2-4h-2l2 4h-3l-2-4H8l2 4H7L5 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4z" /></SVG>;
}

export default svg;
Loading

0 comments on commit 0773762

Please sign in to comment.