Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bring changes from rnmobile/release-v1.17.0 back to master #18588

Merged
merged 1 commit into from
Nov 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

123 changes: 58 additions & 65 deletions packages/block-editor/src/components/media-upload/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
*/
import React from 'react';
import {
requestMediaPickFromMediaLibrary,
requestMediaPickFromDeviceLibrary,
requestMediaPickFromDeviceCamera,
getOtherMediaOptions,
requestOtherMediaPickFrom,
requestMediaPicker,
mediaSources,
} from 'react-native-gutenberg-bridge';

/**
Expand All @@ -19,23 +17,52 @@ import { Picker } from '@wordpress/components';
export const MEDIA_TYPE_IMAGE = 'image';
export const MEDIA_TYPE_VIDEO = 'video';

export const MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_CHOOSE_FROM_DEVICE = 'choose_from_device';
export const MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_TAKE_MEDIA = 'take_media';
export const MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_WORD_PRESS_LIBRARY = 'wordpress_media_library';

export const OPTION_TAKE_VIDEO = __( 'Take a Video' );
export const OPTION_TAKE_PHOTO = __( 'Take a Photo' );
export const OPTION_TAKE_PHOTO_OR_VIDEO = __( 'Take a Photo or Video' );

const cameraImageSource = {
id: mediaSources.deviceCamera, // ID is the value sent to native
value: mediaSources.deviceCamera + '-IMAGE', // This is needed to diferenciate image-camera from video-camera sources.
label: __( 'Take a Photo' ),
types: [ MEDIA_TYPE_IMAGE ],
icon: 'camera',
};

const cameraVideoSource = {
id: mediaSources.deviceCamera,
value: mediaSources.deviceCamera,
label: __( 'Take a Video' ),
types: [ MEDIA_TYPE_VIDEO ],
icon: 'camera',
};

const deviceLibrarySource = {
id: mediaSources.deviceLibrary,
value: mediaSources.deviceLibrary,
label: __( 'Choose from device' ),
types: [ MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO ],
};

const siteLibrarySource = {
id: mediaSources.siteMediaLibrary,
value: mediaSources.siteMediaLibrary,
label: __( 'WordPress Media Library' ),
types: [ MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO ],
icon: 'wordpress-alt',
};

const internalSources = [ deviceLibrarySource, cameraImageSource, cameraVideoSource, siteLibrarySource ];

export class MediaUpload extends React.Component {
constructor( props ) {
super( props );
this.onPickerPresent = this.onPickerPresent.bind( this );
this.onPickerChange = this.onPickerChange.bind( this );
this.onPickerSelect = this.onPickerSelect.bind( this );
this.getAllSources = this.getAllSources.bind( this );

this.state = {
otherMediaOptions: undefined,
otherMediaOptions: [],
};
}

Expand All @@ -44,36 +71,31 @@ export class MediaUpload extends React.Component {
getOtherMediaOptions( allowedTypes, ( otherMediaOptions ) => {
const otherMediaOptionsWithIcons = otherMediaOptions.map( ( option ) => {
return {
icon: this.getChooseFromDeviceIcon(),
value: option.value,
label: option.label,
...option,
types: allowedTypes,
id: option.value,
};
} );

this.setState( { otherMediaOptions: otherMediaOptionsWithIcons } );
} );
}

getTakeMediaLabel() {
const { allowedTypes = [] } = this.props;

const isOneType = allowedTypes.length === 1;
const isImage = isOneType && allowedTypes.includes( MEDIA_TYPE_IMAGE );
const isVideo = isOneType && allowedTypes.includes( MEDIA_TYPE_VIDEO );

if ( isImage ) {
return OPTION_TAKE_PHOTO;
} else if ( isVideo ) {
return OPTION_TAKE_VIDEO;
} return OPTION_TAKE_PHOTO_OR_VIDEO;
getAllSources() {
return internalSources.concat( this.state.otherMediaOptions );
}

getMediaOptionsItems() {
return [
{ icon: this.getChooseFromDeviceIcon(), value: MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_CHOOSE_FROM_DEVICE, label: __( 'Choose from device' ) },
{ icon: this.getTakeMediaIcon(), value: MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_TAKE_MEDIA, label: this.getTakeMediaLabel() },
{ icon: this.getWordPressLibraryIcon(), value: MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_WORD_PRESS_LIBRARY, label: __( 'WordPress Media Library' ) },
];
const { allowedTypes = [] } = this.props;

return this.getAllSources().filter( ( source ) => {
return allowedTypes.filter( ( allowedType ) => source.types.includes( allowedType ) ).length > 0;
} ).map( ( source ) => {
return {
...source,
icon: source.icon || this.getChooseFromDeviceIcon(),
};
} );
}

getChooseFromDeviceIcon() {
Expand All @@ -90,59 +112,30 @@ export class MediaUpload extends React.Component {
}
}

getTakeMediaIcon() {
return 'camera';
}

getWordPressLibraryIcon() {
return 'wordpress-alt';
}

onPickerPresent() {
if ( this.picker ) {
this.picker.presentPicker();
}
}

onPickerSelect( requestFunction ) {
onPickerSelect( value ) {
const { allowedTypes = [], onSelect, multiple = false } = this.props;
requestFunction( allowedTypes, multiple, ( media ) => {
const mediaSource = this.getAllSources().filter( ( source ) => source.value === value ).shift();
const types = allowedTypes.filter( ( type ) => mediaSource.types.includes( type ) );
requestMediaPicker( mediaSource.id, types, multiple, ( media ) => {
if ( ( multiple && media ) || ( media && media.id ) ) {
onSelect( media );
}
} );
}

onPickerChange( value ) {
if ( value === MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_CHOOSE_FROM_DEVICE ) {
this.onPickerSelect( requestMediaPickFromDeviceLibrary );
} else if ( value === MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_TAKE_MEDIA ) {
this.onPickerSelect( requestMediaPickFromDeviceCamera );
} else if ( value === MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_WORD_PRESS_LIBRARY ) {
this.onPickerSelect( requestMediaPickFromMediaLibrary );
} else {
const { onSelect, multiple = false } = this.props;
requestOtherMediaPickFrom( value, multiple, ( media ) => {
if ( ( multiple && media ) || ( media && media.id ) ) {
onSelect( media );
}
} );
}
}

render() {
let mediaOptions = this.getMediaOptionsItems();

if ( this.state.otherMediaOptions ) {
mediaOptions = [ ...mediaOptions, ...this.state.otherMediaOptions ];
}

const getMediaOptions = () => (
<Picker
hideCancelButton
ref={ ( instance ) => this.picker = instance }
options={ mediaOptions }
onChange={ this.onPickerChange }
options={ this.getMediaOptionsItems() }
onChange={ this.onPickerSelect }
/>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,15 @@
import { shallow } from 'enzyme';
import { TouchableWithoutFeedback } from 'react-native';
import {
requestMediaPickFromMediaLibrary,
requestMediaPickFromDeviceLibrary,
requestMediaPickFromDeviceCamera,
requestMediaPicker,
mediaSources,
} from 'react-native-gutenberg-bridge';

/**
* Internal dependencies
*/
import {
MediaUpload,
MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_CHOOSE_FROM_DEVICE,
MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_TAKE_MEDIA,
MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_WORD_PRESS_LIBRARY,
MEDIA_TYPE_IMAGE,
MEDIA_TYPE_VIDEO,
OPTION_TAKE_VIDEO,
Expand Down Expand Up @@ -67,7 +63,7 @@ describe( 'MediaUpload component', () => {
} );

const expectMediaPickerForOption = ( option, allowMultiple, requestFunction ) => {
requestFunction.mockImplementation( ( mediaTypes, multiple, callback ) => {
requestFunction.mockImplementation( ( source, mediaTypes, multiple, callback ) => {
expect( mediaTypes[ 0 ] ).toEqual( MEDIA_TYPE_VIDEO );
if ( multiple ) {
callback( [ { id: MEDIA_ID, url: MEDIA_URL } ] );
Expand Down Expand Up @@ -101,22 +97,22 @@ describe( 'MediaUpload component', () => {
};

it( 'can select media from device library', () => {
expectMediaPickerForOption( MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_CHOOSE_FROM_DEVICE, false, requestMediaPickFromDeviceLibrary );
expectMediaPickerForOption( mediaSources.deviceLibrary, false, requestMediaPicker );
} );

it( 'can select media from WP media library', () => {
expectMediaPickerForOption( MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_WORD_PRESS_LIBRARY, false, requestMediaPickFromMediaLibrary );
expectMediaPickerForOption( mediaSources.siteMediaLibrary, false, requestMediaPicker );
} );

it( 'can select media by capturig', () => {
expectMediaPickerForOption( MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_TAKE_MEDIA, false, requestMediaPickFromDeviceCamera );
expectMediaPickerForOption( mediaSources.deviceCamera, false, requestMediaPicker );
} );

it( 'can select multiple media from device library', () => {
expectMediaPickerForOption( MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_CHOOSE_FROM_DEVICE, true, requestMediaPickFromDeviceLibrary );
expectMediaPickerForOption( mediaSources.deviceLibrary, true, requestMediaPicker );
} );

it( 'can select multiple media from WP media library', () => {
expectMediaPickerForOption( MEDIA_UPLOAD_BOTTOM_SHEET_VALUE_WORD_PRESS_LIBRARY, true, requestMediaPickFromMediaLibrary );
expectMediaPickerForOption( mediaSources.siteMediaLibrary, true, requestMediaPicker );
} );
} );
2 changes: 2 additions & 0 deletions packages/block-editor/src/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ class RichTextWrapper extends Component {
// To do: find a better way to implicitly inherit props.
start,
reversed,
style,
// From experimental filter. To do: pick props instead.
...experimentalProps
} = this.props;
Expand Down Expand Up @@ -396,6 +397,7 @@ class RichTextWrapper extends Component {
__unstableMarkAutomaticChange={ markAutomaticChange }
__unstableDidAutomaticChange={ didAutomaticChange }
__unstableUndo={ undo }
style={ style }
>
{ ( { isSelected, value, onChange, Editable } ) =>
<>
Expand Down
9 changes: 7 additions & 2 deletions packages/block-library/src/image/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
* 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,
requestImageFailedRetryDialog,
requestImageUploadCancelDialog,
requestImageFullscreenPreview,
} from 'react-native-gutenberg-bridge';
import { isEmpty, map } from 'lodash';

Expand Down Expand Up @@ -142,6 +143,8 @@ export class ImageEdit extends React.Component {
requestImageUploadCancelDialog( attributes.id );
} else if ( attributes.id && ! isURL( attributes.url ) ) {
requestImageFailedRetryDialog( attributes.id );
} else if ( Platform.OS === 'android' ) {
requestImageFullscreenPreview( attributes.url );
}

this.setState( {
Expand Down Expand Up @@ -334,6 +337,7 @@ export class ImageEdit extends React.Component {
};

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

const getImageComponent = ( openMediaOptions, getMediaOptions ) => (
<TouchableWithoutFeedback
accessible={ ! isSelected }
Expand All @@ -359,6 +363,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 && ! ( isUploadInProgress || isUploadFailed ) ? styles.imageBorder : '';

const iconContainer = (
<View style={ styles.modalIcon }>
Expand All @@ -378,7 +383,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 }
Expand Down
6 changes: 6 additions & 0 deletions packages/block-library/src/image/styles.native.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions packages/block-library/src/index.native.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
* External dependencies
*/
import { Platform } from 'react-native';
/**
* WordPress dependencies
*/
Expand Down Expand Up @@ -143,6 +147,8 @@ export const registerCoreBlocks = () => {
quote,
mediaText,
// eslint-disable-next-line no-undef
( ( Platform.OS === 'ios' ) || ( !! __DEV__ ) ) ? preformatted : null,
// eslint-disable-next-line no-undef
!! __DEV__ ? group : null,
// eslint-disable-next-line no-undef
!! __DEV__ ? spacer : null,
Expand Down
15 changes: 13 additions & 2 deletions packages/block-library/src/paragraph/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { View } from 'react-native';
import { __ } from '@wordpress/i18n';
import { Component } from '@wordpress/element';
import { createBlock } from '@wordpress/blocks';
import { RichText } from '@wordpress/block-editor';
import { AlignmentToolbar, BlockControls, RichText } from '@wordpress/block-editor';

/**
* Internal dependencies
Expand Down Expand Up @@ -47,12 +47,22 @@ class ParagraphEdit extends Component {
} = this.props;

const {
placeholder,
align,
content,
placeholder,
} = attributes;

return (
<View>
<BlockControls>
<AlignmentToolbar
isCollapsed={ false }
value={ align }
onChange={ ( nextAlign ) => {
setAttributes( { align: nextAlign } );
} }
/>
</BlockControls>
<RichText
identifier="content"
tagName="p"
Expand All @@ -78,6 +88,7 @@ class ParagraphEdit extends Component {
onReplace={ onReplace }
onRemove={ onReplace ? () => onReplace( [] ) : undefined }
placeholder={ placeholder || __( 'Start writing…' ) }
textAlign={ align }
/>
</View>
);
Expand Down
Loading