diff --git a/packages/block-library/src/image/edit.native.js b/packages/block-library/src/image/edit.native.js
index 476dea2981b15..eb73ef558542d 100644
--- a/packages/block-library/src/image/edit.native.js
+++ b/packages/block-library/src/image/edit.native.js
@@ -1,68 +1,167 @@
/**
* External dependencies
*/
+import React from 'react';
import { View, Image, TextInput } from 'react-native';
-import RNReactNativeGutenbergBridge from 'react-native-gutenberg-bridge';
+import {
+ subscribeMediaUpload,
+ onMediaLibraryPressed,
+ onUploadMediaPressed,
+ onCapturePhotoPressed,
+ onImageQueryReattach,
+} from 'react-native-gutenberg-bridge';
/**
* Internal dependencies
*/
import { MediaPlaceholder, RichText, BlockControls } from '@wordpress/editor';
-import { Toolbar, ToolbarButton } from '@wordpress/components';
-import { Component } from '@wordpress/element';
+import { Toolbar, ToolbarButton, Spinner } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import ImageSize from './image-size';
+import { isURL } from '@wordpress/url';
-class ImageEdit extends Component {
- constructor() {
- super( ...arguments );
- this.onMediaLibraryPress = this.onMediaLibraryPress.bind( this );
+const MEDIA_ULOAD_STATE_UPLOADING = 1;
+const MEDIA_ULOAD_STATE_SUCCEEDED = 2;
+const MEDIA_ULOAD_STATE_FAILED = 3;
+
+export default class ImageEdit extends React.Component {
+ constructor( props ) {
+ super( props );
+
+ this.state = {
+ progress: 0,
+ isUploadInProgress: false,
+ };
+
+ this.mediaUpload = this.mediaUpload.bind( this );
+ this.addMediaUploadListener = this.addMediaUploadListener.bind( this );
+ this.removeMediaUploadListener = this.removeMediaUploadListener.bind( this );
+ this.finishMediaUploadWithSuccess = this.finishMediaUploadWithSuccess.bind( this );
+ this.finishMediaUploadWithFailure = this.finishMediaUploadWithFailure.bind( this );
+ }
+
+ componentDidMount() {
+ const { attributes } = this.props;
+
+ if ( attributes.id && ! isURL( attributes.url ) ) {
+ this.addMediaUploadListener();
+ onImageQueryReattach();
+ }
+ }
+
+ componentWillUnmount() {
+ this.removeMediaUploadListener();
+ }
+
+ mediaUpload( payload ) {
+ const { attributes } = this.props;
+
+ if ( payload.mediaId !== attributes.id ) {
+ return;
+ }
+
+ switch ( payload.state ) {
+ case MEDIA_ULOAD_STATE_UPLOADING:
+ this.setState( { progress: payload.progress, isUploadInProgress: true } );
+ break;
+ case MEDIA_ULOAD_STATE_SUCCEEDED:
+ this.finishMediaUploadWithSuccess( payload );
+ break;
+ case MEDIA_ULOAD_STATE_FAILED:
+ this.finishMediaUploadWithFailure( payload );
+ break;
+ }
}
- onUploadPress() {
- // This method should present an image picker from
- // the device.
- //TODO: Implement upload image method.
+ finishMediaUploadWithSuccess( payload ) {
+ const { setAttributes } = this.props;
+
+ setAttributes( { url: payload.mediaUrl, id: payload.mediaServerId } );
+ this.setState( { isUploadInProgress: false } );
+
+ this.removeMediaUploadListener();
}
- onMediaLibraryPress() {
- RNReactNativeGutenbergBridge.onMediaLibraryPress( ( mediaUrl ) => {
- if ( mediaUrl ) {
- this.props.setAttributes( { url: mediaUrl } );
- }
+ finishMediaUploadWithFailure( payload ) {
+ const { setAttributes } = this.props;
+
+ setAttributes( { url: payload.mediaUrl, id: payload.mediaId } );
+ this.setState( { isUploadInProgress: false } );
+
+ this.removeMediaUploadListener();
+ }
+
+ addMediaUploadListener() {
+ this.subscriptionParentMediaUpload = subscribeMediaUpload( ( payload ) => {
+ this.mediaUpload( payload );
} );
}
- toolbarEditButton() {
- return (
-
-
-
- );
+ removeMediaUploadListener() {
+ if ( this.subscriptionParentMediaUpload ) {
+ this.subscriptionParentMediaUpload.remove();
+ }
}
render() {
const { attributes, isSelected, setAttributes } = this.props;
const { url, caption, height, width } = attributes;
+ const onMediaLibraryButtonPressed = () => {
+ onMediaLibraryPressed( ( mediaId, mediaUrl ) => {
+ if ( mediaUrl ) {
+ setAttributes( { id: mediaId, url: mediaUrl } );
+ }
+ } );
+ };
+
if ( ! url ) {
+ const onUploadMediaButtonPressed = () => {
+ onUploadMediaPressed( ( mediaId, mediaUri ) => {
+ if ( mediaUri ) {
+ this.addMediaUploadListener( );
+ setAttributes( { url: mediaUri, id: mediaId } );
+ }
+ } );
+ };
+
+ const onCapturePhotoButtonPressed = () => {
+ onCapturePhotoPressed( ( mediaId, mediaUri ) => {
+ if ( mediaUri ) {
+ this.addMediaUploadListener( );
+ setAttributes( { url: mediaUri, id: mediaId } );
+ }
+ } );
+ };
+
return (
);
}
+ const toolbarEditButton = (
+
+
+
+ );
+
+ const showSpinner = this.state.isUploadInProgress;
+ const opacity = this.state.isUploadInProgress ? 0.3 : 1;
+ const progress = this.state.progress * 100;
+
return (
+ { showSpinner && }
- { this.toolbarEditButton() }
+ { toolbarEditButton }
{ ( sizes ) => {
@@ -84,7 +183,7 @@ class ImageEdit extends Component {
return (
setAttributes( { caption: newCaption } ) }
/>
@@ -108,5 +207,3 @@ class ImageEdit extends Component {
);
}
}
-
-export default ImageEdit;
diff --git a/packages/components/src/index.native.js b/packages/components/src/index.native.js
index cbaae28e089bd..65dd41e713fa3 100644
--- a/packages/components/src/index.native.js
+++ b/packages/components/src/index.native.js
@@ -5,6 +5,7 @@ export { default as Toolbar } from './toolbar';
export { default as ToolbarButton } from './toolbar-button';
export { default as withSpokenMessages } from './higher-order/with-spoken-messages';
export { default as IconButton } from './icon-button';
+export { default as Spinner } from './spinner';
export { createSlotFill, Slot, Fill, Provider as SlotFillProvider } from './slot-fill';
// Higher-Order Components
diff --git a/packages/components/src/spinner/index.native.js b/packages/components/src/spinner/index.native.js
new file mode 100644
index 0000000000000..305019bc8b40d
--- /dev/null
+++ b/packages/components/src/spinner/index.native.js
@@ -0,0 +1,13 @@
+import { View } from 'react-native';
+
+export default function Spinner( props ) {
+ const { progress } = props;
+
+ const width = progress + '%';
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/editor/src/components/media-placeholder/index.native.js b/packages/editor/src/components/media-placeholder/index.native.js
index 6a64523a43962..0b70472c2407f 100644
--- a/packages/editor/src/components/media-placeholder/index.native.js
+++ b/packages/editor/src/components/media-placeholder/index.native.js
@@ -5,18 +5,22 @@ import { View, Text, Button } from 'react-native';
import styles from './styles.scss';
+import { __ } from '@wordpress/i18n';
+
function MediaPlaceholder( props ) {
return (
- Image
+ { __( 'Image' ) }
- Select an image from your library.
+ { __( 'Upload a new image or select a file from your library.' ) }
-
+
+
+
);
}
diff --git a/packages/editor/src/components/media-placeholder/styles.native.scss b/packages/editor/src/components/media-placeholder/styles.native.scss
index e05681743ee96..0014afe089ac5 100644
--- a/packages/editor/src/components/media-placeholder/styles.native.scss
+++ b/packages/editor/src/components/media-placeholder/styles.native.scss
@@ -18,6 +18,9 @@
}
.emptyStateButtonsContainer {
+ margin-top: 15;
+ margin-bottom: 15;
flex-direction: row;
- align-items: center;
+ justify-content: space-evenly;
+ width: 100%;
}