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

Rnmobile/upload media file #13128

Merged
merged 56 commits into from
Jan 28, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
49bb394
temporarily disable link formatting
mzorz Dec 20, 2018
96a73c5
Make sure RichText resigns focus when unmounted (#13048)
koke Dec 20, 2018
93057b2
Implemented react native spinner
marecar3 Dec 28, 2018
0a0764e
Add upload button in media placeholder
marecar3 Dec 28, 2018
1876d22
Transform ImageEdit from function to class
marecar3 Dec 28, 2018
8a363f9
Fixed lint issues
marecar3 Dec 28, 2018
db23d43
Fixed lint errors
marecar3 Dec 28, 2018
ff11770
Put some space between components in media-placeholder
marecar3 Dec 28, 2018
704b755
Rename state constants to match style convention
marecar3 Dec 28, 2018
e2b08e1
Implements a native version of post-title.
diegoreymendez Jan 4, 2019
40b7c9c
Merge branch 'master' into mobileissue/372-add-title-to-gutenberg-mobile
diegoreymendez Jan 4, 2019
d5910a8
Removes some unnecessary log calls.
diegoreymendez Jan 4, 2019
08108a0
Merge branch 'master' into rnmobile/372-add-title-to-gutenberg-mobile
diegoreymendez Jan 10, 2019
047f1d8
Submits a few lint fixes.
diegoreymendez Jan 10, 2019
4f55ba9
Fixes a linting issue.
diegoreymendez Jan 10, 2019
7b823ec
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 16, 2019
e5d8d3f
Rename callback methods to follow naming convention
marecar3 Jan 16, 2019
2668862
Updated spinner to match the specs
marecar3 Jan 16, 2019
408cb1e
Moved placeholder string to localization format
marecar3 Jan 16, 2019
50c9a12
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 16, 2019
d840e30
Added isURL method to check if passed url is local or web url
marecar3 Jan 16, 2019
5f2889f
Removed duplicated code
marecar3 Jan 16, 2019
21920fd
Add missing attributes
marecar3 Jan 16, 2019
4f4d5f6
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 16, 2019
876b445
Revert missing opacity
marecar3 Jan 16, 2019
d436e9b
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 16, 2019
4c27638
When focusing the title, any focused block loses its focus.
diegoreymendez Jan 16, 2019
0ab5a1b
FocusOut is now wired for post-title for mobile.
diegoreymendez Jan 16, 2019
1f9c722
Removes unused some code.
diegoreymendez Jan 16, 2019
e54d5b9
Added a file I failed to commit.
diegoreymendez Jan 16, 2019
e2cb5c9
Revert media upload event to be non dynamic
marecar3 Jan 17, 2019
046213a
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 17, 2019
7f05b9c
Fixes a linting issue.
diegoreymendez Jan 17, 2019
b94bede
Merge branch 'master' into rnmobile/372-add-title-to-gutenberg-mobile
diegoreymendez Jan 17, 2019
77a1fbe
Make sure that we are receiving events for current media image
marecar3 Jan 17, 2019
8264c52
Renamed constants to follow naming convention
marecar3 Jan 17, 2019
c2a8cf5
Wrap RNReactNativeGutenbergBridge calls inside react-native-gutenberg…
marecar3 Jan 17, 2019
2e7267b
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 17, 2019
08f5cc2
Add state isUploadInProgress instead of checking isUrl is valid
marecar3 Jan 17, 2019
9b2f540
Removed private variable so that can pass
marecar3 Jan 18, 2019
f3b9607
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 18, 2019
5814a4c
Fixed lint tests
marecar3 Jan 18, 2019
e0d5d9b
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 18, 2019
a5a200b
Start listen for progress media upload if it's didn't finish
marecar3 Jan 18, 2019
c9d7b9f
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 18, 2019
9ea8f39
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 21, 2019
b822344
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 22, 2019
e4bf38e
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 23, 2019
6129033
RN Mobile - Upload media file ios (#13421)
SergioEstevao Jan 23, 2019
b5e679b
Merge branch 'master' of https://github.com/WordPress/gutenberg into …
daniloercoli Jan 24, 2019
74aeb23
Merge branch 'rnmobile/372-add-title-to-gutenberg-mobile' into rnmobi…
SergioEstevao Jan 24, 2019
345d356
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 25, 2019
9fecd69
Fix lint errors.
SergioEstevao Jan 25, 2019
028ab55
Rnmobile/upload captured photo (#13450)
marecar3 Jan 25, 2019
93e6e95
using onImageQueryReattach (#13516)
mzorz Jan 28, 2019
2fc48c9
Merge branch 'master' into rnmobile/upload_media_file
marecar3 Jan 28, 2019
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
175 changes: 115 additions & 60 deletions packages/block-library/src/image/edit.native.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,130 @@
/**
* External dependencies
*/
import { View, Image, TextInput } from 'react-native';
import React from 'react';
import { View, Image, TextInput, NativeEventEmitter } from 'react-native';
import RNReactNativeGutenbergBridge from 'react-native-gutenberg-bridge';

const gutenbergBridgeEvents = new NativeEventEmitter( RNReactNativeGutenbergBridge );

/**
* Internal dependencies
*/
import { MediaPlaceholder, RichText, BlockControls } from '@wordpress/editor';
import { Toolbar, ToolbarButton } from '@wordpress/components';
import { Toolbar, ToolbarButton, Spinner } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

export default function ImageEdit( props ) {
const { attributes, isSelected, setAttributes } = props;
const { url, caption } = attributes;

const onUploadPress = () => {
// This method should present an image picker from
// the device.
//TODO: Implement upload image method.
};

const onMediaLibraryPress = () => {
RNReactNativeGutenbergBridge.onMediaLibraryPress( ( mediaUrl ) => {
if ( mediaUrl ) {
setAttributes( { url: mediaUrl } );
}
} );
};

if ( ! url ) {
const mediaUploadStateUploading = 1;
SergioEstevao marked this conversation as resolved.
Show resolved Hide resolved
const mediaUploadStateSucceeded = 2;
const mediaUploadStateFailed = 3;

export default class ImageEdit extends React.Component {
constructor( props ) {
super( props );

this.state = {
progress: 0,
};

this.mediaUpload = this.mediaUpload.bind( this );
this.addMediaUploadListener = this.addMediaUploadListener.bind( this );
this.removeMediaUploadListener = this.removeMediaUploadListener.bind( this );
this.finishMediaUploading = this.finishMediaUploading.bind( this );
}

mediaUpload( payload ) {
if ( payload.state === mediaUploadStateUploading ) {
this.setState( { progress: payload.progress } );
} else if ( payload.state === mediaUploadStateSucceeded || payload.state === mediaUploadStateFailed ) {
this.finishMediaUploading( payload );
}
SergioEstevao marked this conversation as resolved.
Show resolved Hide resolved
}

finishMediaUploading( payload ) {
const { setAttributes } = this.props;

setAttributes( { url: payload.mediaUrl, id: payload.mediaId } );
this.setState( { progress: payload.progress } );
this.removeMediaUploadListener( payload.mediaId );
}

addMediaUploadListener( mediaId ) {
gutenbergBridgeEvents.addListener( 'mediaUpload' + mediaId, this.mediaUpload );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we will have a problem here with iOS. As you can see here, on iOS we need to know ahead of time what events do we support by overriding - (NSArray<NSString *> *)supportedEvents and returning an array with the event names.

Because of that, we can not have dynamic events names like appending the media id to it.

Do you think it would be possible to send the media id as a parameter instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it would be possible to send the media id as a parameter instead?

Good call there 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @etoledom, thanks for the update. I wasn't aware of this one as this approach was working in some lower version. I will fix this. Thanks for letting me know.

cc: @SergioEstevao

}

removeMediaUploadListener( mediaId ) {
gutenbergBridgeEvents.removeListener( 'mediaUpload' + mediaId, this.mediaUpload );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to hide the implementation of adding/removing listeners inside the react-native-gutenberg-bridge module. Something similar to what we already have in here.

If we can also hide the RNReactNativeGutenbergBridge.onMediaLibraryPress it would be great too. Even though we didn't do it before, probably is good to have all the available communication methods in one place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @etoledom, thanks for the comments. I have changed the code as we discussed.

}

render() {
const { attributes, isSelected, setAttributes } = this.props;
const { url, caption } = attributes;

const onMediaLibraryPress = () => {
RNReactNativeGutenbergBridge.onMediaLibraryPress( ( mediaUrl ) => {
if ( mediaUrl ) {
setAttributes( { url: mediaUrl } );
}
} );
};

if ( ! url ) {
const onUploadMediaPress = () => {
RNReactNativeGutenbergBridge.onUploadMediaPress( ( mediaId, mediaUri ) => {
if ( mediaUri ) {
this.addMediaUploadListener( mediaId );
setAttributes( { url: mediaUri, id: mediaId } );
}
} );
};

return (
<MediaPlaceholder
onUploadMediaPress={ onUploadMediaPress }
onMediaLibraryPress={ onMediaLibraryPress }
/>
);
}

const toolbarEditButton = (
<Toolbar>
<ToolbarButton
className="components-toolbar__control"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason for having a double underscore "__" in this name? should it be a normal dash?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is part of the CSS coding standards for Gutenberg. I would ask if we actually need the className in the native implementation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, thanks @koke. We don't need that one, I removed it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is part of the CSS coding standards for Gutenberg.

TIL - thanks @koke

label={ __( 'Edit image' ) }
icon="edit"
onClick={ onMediaLibraryPress }
/>
</Toolbar>
);

const http = 'http';
const showSpinner = url !== undefined ? ! url.includes( http ) : false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we perhaps extend this logic to a more generic Utils class or if not, at least method on its own? I'm thinking something more explicit like isRemoteUrl() that hides the logic inside to determine whether an URI is a remote resource or not, etc. Such const http constant should belong within the scope of such function only, etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mzorz , @koke . I have updated the code to use isURL method like @koke suggested.

const progress = this.state.progress * 100;
const opacity = showSpinner ? 0.3 : 1;

return (
<MediaPlaceholder
onUploadPress={ onUploadPress }
onMediaLibraryPress={ onMediaLibraryPress }
/>
<View style={ { flex: 1 } }>
{ showSpinner && <Spinner progress={ progress } /> }
<BlockControls>
{ toolbarEditButton }
</BlockControls>
<Image
style={ { width: '100%', height: 200, opacity: opacity } }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see this value was there before this change, but wondering why height: 200, is there anything specific to that value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can ask @etoledom about this one, as this change was made a long time ago?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw that this was changed with this PR #13096
so @etoledom , you can ignore above question :) Thanks.

resizeMethod="scale"
source={ { uri: url } }
/>
{ ( ! RichText.isEmpty( caption ) > 0 || isSelected ) && (
<View style={ { padding: 12, flex: 1 } }>
<TextInput
style={ { textAlign: 'center' } }
underlineColorAndroid="transparent"
value={ caption }
placeholder={ 'Write caption…' }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be passed through i18n, like _( 'Write caption...' )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mzorz ! Fixed and pushed.

onChangeText={ ( newCaption ) => setAttributes( { caption: newCaption } ) }
/>
</View>
) }
</View>
);
}

const toolbarEditButton = (
<Toolbar>
<ToolbarButton
className="components-toolbar__control"
label={ __( 'Edit image' ) }
icon="edit"
onClick={ onMediaLibraryPress }
/>
</Toolbar>
);

return (
<View style={ { flex: 1 } }>
<BlockControls>
{ toolbarEditButton }
</BlockControls>
<Image
style={ { width: '100%', height: 200 } }
resizeMethod="scale"
source={ { uri: url } }
/>
{ ( ! RichText.isEmpty( caption ) > 0 || isSelected ) && (
<View style={ { padding: 12, flex: 1 } }>
<TextInput
style={ { textAlign: 'center' } }
underlineColorAndroid="transparent"
value={ caption }
placeholder={ 'Write caption…' }
onChangeText={ ( newCaption ) => setAttributes( { caption: newCaption } ) }
/>
</View>
) }
</View>
);
}
1 change: 1 addition & 0 deletions packages/components/src/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions packages/components/src/spinner/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { View } from 'react-native';

export default function Spinner( props ) {
const { progress } = props;

const width = progress + '%';

return (
<View style={ { flex: 1, height: 5, backgroundColor: '#a8bece' } }>
<View style={ { width: width, height: 5, backgroundColor: '#0087be' } } />
</View>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@ import { View, Text, Button } from 'react-native';

import styles from './styles.scss';

import { __ } from '@wordpress/i18n';

function MediaPlaceholder( props ) {
return (
<View style={ styles.emptyStateContainer }>
<Text style={ styles.emptyStateTitle }>
Image
{ __( 'Image' ) }
</Text>
<Text style={ styles.emptyStateDescription }>
Select an image from your library.
{ __( 'Upload a new image or select a file from your library.' ) }
</Text>
<View style={ styles.emptyStateButtonsContainer }>
<Button title="Media Library" onPress={ props.onMediaLibraryPress } />
<Button title={ __( 'Upload' ) } onPress={ props.onUploadMediaPress } />
<Button title={ __( 'Media Library' ) } onPress={ props.onMediaLibraryPress } />
</View>
</View>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
}

.emptyStateButtonsContainer {
margin-top: 15;
flex-direction: row;
align-items: center;
justify-content: space-evenly;
width: 100%;
}