From 56734383d3c67d5dda1ae25c82c2b5e521fd8861 Mon Sep 17 00:00:00 2001 From: Marko Savic Date: Mon, 28 Jan 2019 15:18:29 +0100 Subject: [PATCH] Rnmobile/upload media file (#13128) Upload media file --- .../block-library/src/image/edit.native.js | 165 ++++++++++++++---- packages/components/src/index.native.js | 1 + .../components/src/spinner/index.native.js | 13 ++ .../media-placeholder/index.native.js | 10 +- .../media-placeholder/styles.native.scss | 5 +- 5 files changed, 156 insertions(+), 38 deletions(-) create mode 100644 packages/components/src/spinner/index.native.js 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.' ) } -