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] Audio block I #27401

Merged
merged 18 commits into from
Jan 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions packages/block-editor/src/components/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export {
default as MediaUpload,
MEDIA_TYPE_IMAGE,
MEDIA_TYPE_VIDEO,
MEDIA_TYPE_AUDIO,
MEDIA_TYPE_ANY,
} from './media-upload';
export { default as MediaUploadProgress } from './media-upload-progress';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
MediaUpload,
MEDIA_TYPE_IMAGE,
MEDIA_TYPE_VIDEO,
MEDIA_TYPE_AUDIO,
} from '@wordpress/block-editor';
import { withPreferredColorScheme } from '@wordpress/compose';
import { useRef } from '@wordpress/element';
Expand Down Expand Up @@ -65,6 +66,7 @@ function MediaPlaceholder( props ) {
const isOneType = allowedTypes.length === 1;
const isImage = isOneType && allowedTypes.includes( MEDIA_TYPE_IMAGE );
const isVideo = isOneType && allowedTypes.includes( MEDIA_TYPE_VIDEO );
const isAudio = isOneType && allowedTypes.includes( MEDIA_TYPE_AUDIO );

let placeholderTitle = labels.title;
if ( placeholderTitle === undefined ) {
Expand All @@ -73,6 +75,8 @@ function MediaPlaceholder( props ) {
placeholderTitle = __( 'Image' );
} else if ( isVideo ) {
placeholderTitle = __( 'Video' );
} else if ( isAudio ) {
placeholderTitle = __( 'Audio' );
}
}

Expand All @@ -82,6 +86,8 @@ function MediaPlaceholder( props ) {
instructions = __( 'ADD IMAGE' );
} else if ( isVideo ) {
instructions = __( 'ADD VIDEO' );
} else if ( isAudio ) {
instructions = __( 'ADD AUDIO' );
} else {
instructions = __( 'ADD IMAGE OR VIDEO' );
}
Expand All @@ -92,6 +98,8 @@ function MediaPlaceholder( props ) {
accessibilityHint = __( 'Double tap to select an image' );
} else if ( isVideo ) {
accessibilityHint = __( 'Double tap to select a video' );
} else if ( isAudio ) {
accessibilityHint = __( 'Double tap to select an audio file' );
}

const emptyStateTitleStyle = getStylesFromColorScheme(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {

export const MEDIA_TYPE_IMAGE = 'image';
export const MEDIA_TYPE_VIDEO = 'video';
export const MEDIA_TYPE_AUDIO = 'audio';
export const MEDIA_TYPE_ANY = 'any';

export const OPTION_TAKE_VIDEO = __( 'Take a Video' );
Expand Down Expand Up @@ -83,7 +84,12 @@ export class MediaUpload extends Component {
id: mediaSources.siteMediaLibrary,
value: mediaSources.siteMediaLibrary,
label: __( 'WordPress Media Library' ),
types: [ MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO, MEDIA_TYPE_ANY ],
types: [
MEDIA_TYPE_IMAGE,
MEDIA_TYPE_VIDEO,
MEDIA_TYPE_AUDIO,
MEDIA_TYPE_ANY,
],
icon: wordpress,
mediaLibrary: true,
};
Expand Down Expand Up @@ -151,6 +157,7 @@ export class MediaUpload extends Component {
const isOneType = allowedTypes.length === 1;
const isImage = isOneType && allowedTypes.includes( MEDIA_TYPE_IMAGE );
const isVideo = isOneType && allowedTypes.includes( MEDIA_TYPE_VIDEO );
const isAudio = isOneType && allowedTypes.includes( MEDIA_TYPE_AUDIO );
const isAnyType = isOneType && allowedTypes.includes( MEDIA_TYPE_ANY );

const isImageOrVideo =
Expand Down Expand Up @@ -179,8 +186,19 @@ export class MediaUpload extends Component {
} else {
pickerTitle = __( 'Choose image or video' );
}
} else if ( isAudio ) {
if ( isReplacingMedia ) {
pickerTitle = __( 'Replace audio' );
} else {
pickerTitle = __( 'Choose audio' );
}
} else if ( isAnyType ) {
pickerTitle = __( 'Choose file' );
if ( isReplacingMedia ) {
pickerTitle = __( 'Replace file' );
} else {
pickerTitle = __( 'Choose file' );
}
}

const getMediaOptions = () => (
Expand Down
220 changes: 220 additions & 0 deletions packages/block-library/src/audio/edit.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/**
* External dependencies
*/
import { Text, TouchableWithoutFeedback } from 'react-native';
import { isEmpty } from 'lodash';

/**
* WordPress dependencies
*/
import { View } from '@wordpress/primitives';
import {
PanelBody,
SelectControl,
ToggleControl,
withNotices,
ToolbarButton,
ToolbarGroup,
} from '@wordpress/components';
import {
BlockCaption,
BlockControls,
BlockIcon,
InspectorControls,
MediaPlaceholder,
MediaUpload,
MediaUploadProgress,
} from '@wordpress/block-editor';
import { __, sprintf } from '@wordpress/i18n';
import { audio as icon, replace } from '@wordpress/icons';
import { useState } from '@wordpress/element';

const ALLOWED_MEDIA_TYPES = [ 'audio' ];

function AudioEdit( {
attributes,
noticeOperations,
setAttributes,
isSelected,
noticeUI,
insertBlocksAfter,
onFocus,
onBlur,
clientId,
} ) {
const { id, autoplay, loop, preload, src } = attributes;

const [ isCaptionSelected, setIsCaptionSelected ] = useState( false );

const onFileChange = ( { mediaId, mediaUrl } ) => {
setAttributes( { id: mediaId, src: mediaUrl } );
};

const onError = () => {
// TODO: Set up error state
onUploadError( __( 'Error' ) );
};

function toggleAttribute( attribute ) {
return ( newValue ) => {
setAttributes( { [ attribute ]: newValue } );
};
}

function onSelectURL() {
// TODO: Set up add audio from URL flow
}

function onUploadError( message ) {
noticeOperations.removeAllNotices();
noticeOperations.createErrorNotice( message );
}

// const { setAttributes, isSelected, noticeUI } = this.props;
function onSelectAudio( media ) {
if ( ! media || ! media.url ) {
// in this case there was an error and we should continue in the editing state
// previous attributes should be removed because they may be temporary blob urls
setAttributes( { src: undefined, id: undefined } );
return;
}
// sets the block's attribute and updates the edit component from the
// selected media, then switches off the editing UI
setAttributes( { src: media.url, id: media.id } );
}

function onAudioPress() {
setIsCaptionSelected( false );
}

function onFocusCaption() {
if ( ! isCaptionSelected ) {
setIsCaptionSelected( true );
}
}

if ( ! src ) {
return (
<View>
<MediaPlaceholder
icon={ <BlockIcon icon={ icon } /> }
onSelect={ onSelectAudio }
onSelectURL={ onSelectURL }
accept="audio/*"
allowedTypes={ ALLOWED_MEDIA_TYPES }
value={ attributes }
notices={ noticeUI }
onError={ onUploadError }
onFocus={ onFocus }
/>
</View>
);
}

function getBlockControls( open ) {
return (
<BlockControls>
<ToolbarGroup>
<ToolbarButton
title={ __( 'Replace audio' ) }
icon={ replace }
onClick={ open }
/>
</ToolbarGroup>
</BlockControls>
);
}

function getBlockUI( open, getMediaOptions ) {
return (
<MediaUploadProgress
mediaId={ id }
onUpdateMediaProgress={ this.updateMediaProgress }
onFinishMediaUploadWithSuccess={ onFileChange }
onFinishMediaUploadWithFailure={ onError }
onMediaUploadStateReset={ onFileChange }
renderContent={ ( { isUploadInProgress, isUploadFailed } ) => {
return (
<View>
{ ! isCaptionSelected && getBlockControls( open ) }
{ getMediaOptions() }
<Text>
⏯ Audio Player goes here.{ ' ' }
{ isUploadInProgress && 'Uploading...' }
{ isUploadFailed && 'ERROR' }
</Text>
</View>
);
} }
/>
);
}

return (
<TouchableWithoutFeedback
accessible={ ! isSelected }
onPress={ onAudioPress }
disabled={ ! isSelected }
>
<View>
<InspectorControls>
<PanelBody title={ __( 'Audio settings' ) }>
<ToggleControl
label={ __( 'Autoplay' ) }
onChange={ toggleAttribute( 'autoplay' ) }
checked={ autoplay }
/>
<ToggleControl
label={ __( 'Loop' ) }
onChange={ toggleAttribute( 'loop' ) }
checked={ loop }
/>
<SelectControl
label={ __( 'Preload' ) }
value={ preload || '' }
// `undefined` is required for the preload attribute to be unset.
onChange={ ( value ) =>
setAttributes( {
preload: value || undefined,
} )
}
options={ [
{ value: '', label: __( 'Browser default' ) },
{ value: 'auto', label: __( 'Auto' ) },
{ value: 'metadata', label: __( 'Metadata' ) },
{ value: 'none', label: __( 'None' ) },
] }
/>
</PanelBody>
</InspectorControls>
<MediaUpload
allowedTypes={ ALLOWED_MEDIA_TYPES }
isReplacingMedia={ true }
onSelect={ onSelectAudio }
render={ ( { open, getMediaOptions } ) => {
return getBlockUI( open, getMediaOptions );
} }
/>
<BlockCaption
accessible={ true }
accessibilityLabelCreator={ ( caption ) =>
isEmpty( caption )
? /* translators: accessibility text. Empty Audio caption. */
__( 'Audio caption. Empty' )
: sprintf(
/* translators: accessibility text. %s: Audio caption. */
__( 'Audio caption. %s' ),
caption
)
}
clientId={ clientId }
isSelected={ isCaptionSelected }
onFocus={ onFocusCaption }
onBlur={ onBlur }
insertBlocksAfter={ insertBlocksAfter }
/>
</View>
</TouchableWithoutFeedback>
);
}
export default withNotices( AudioEdit );
1 change: 1 addition & 0 deletions packages/block-library/src/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ export const registerCoreBlocks = () => {
socialLinks,
pullquote,
file,
devOnly( audio ),
devOnly( reusableBlock ),
].forEach( registerBlock );

Expand Down
Loading