UNPKG

@gechiui/block-editor

Version:
316 lines (281 loc) 7.71 kB
/** * External dependencies */ import { Platform } from 'react-native'; import { delay } from 'lodash'; import prompt from 'react-native-prompt-android'; /** * GeChiUI dependencies */ import { Component, React } from '@gechiui/element'; import { __ } from '@gechiui/i18n'; import { Picker } from '@gechiui/components'; import { getOtherMediaOptions, requestMediaPicker, mediaSources, } from '@gechiui/react-native-bridge'; import { capturePhoto, captureVideo, image, gechiui, mobile, globe, } from '@gechiui/icons'; import { store as blockEditorStore } from '@gechiui/block-editor'; import { compose } from '@gechiui/compose'; import { withSelect } from '@gechiui/data'; 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' ); export const OPTION_TAKE_PHOTO = __( 'Take a Photo' ); export const OPTION_TAKE_PHOTO_OR_VIDEO = __( 'Take a Photo or Video' ); export const OPTION_INSERT_FROM_URL = __( '从URL插入' ); const URL_MEDIA_SOURCE = 'URL'; const PICKER_OPENING_DELAY = 200; export class MediaUpload extends Component { constructor( props ) { super( props ); this.onPickerPresent = this.onPickerPresent.bind( this ); this.onPickerSelect = this.onPickerSelect.bind( this ); this.getAllSources = this.getAllSources.bind( this ); this.state = { otherMediaOptions: [], }; } componentDidMount() { const { allowedTypes = [], autoOpen } = this.props; getOtherMediaOptions( allowedTypes, ( otherMediaOptions ) => { const otherMediaOptionsWithIcons = otherMediaOptions.map( ( option ) => { return { ...option, requiresModal: true, types: allowedTypes, id: option.value, }; } ); this.setState( { otherMediaOptions: otherMediaOptionsWithIcons } ); } ); if ( autoOpen ) { this.onPickerPresent(); } } getAllSources() { 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' ), requiresModal: true, types: [ MEDIA_TYPE_IMAGE ], icon: capturePhoto, }; const cameraVideoSource = { id: mediaSources.deviceCamera, value: mediaSources.deviceCamera, label: __( 'Take a Video' ), requiresModal: true, types: [ MEDIA_TYPE_VIDEO ], icon: captureVideo, }; const deviceLibrarySource = { id: mediaSources.deviceLibrary, value: mediaSources.deviceLibrary, label: __( 'Choose from device' ), requiresModal: true, types: [ MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO ], icon: image, }; const siteLibrarySource = { id: mediaSources.siteMediaLibrary, value: mediaSources.siteMediaLibrary, label: __( 'GeChiUI Media Library' ), requiresModal: true, types: [ MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO, MEDIA_TYPE_AUDIO, MEDIA_TYPE_ANY, ], icon: gechiui, mediaLibrary: true, }; const urlSource = { id: URL_MEDIA_SOURCE, value: URL_MEDIA_SOURCE, label: __( '从URL插入' ), types: [ MEDIA_TYPE_AUDIO ], icon: globe, }; const internalSources = [ deviceLibrarySource, cameraImageSource, cameraVideoSource, siteLibrarySource, urlSource, ]; return internalSources.concat( this.state.otherMediaOptions ); } getMediaOptionsItems() { const { allowedTypes = [], __experimentalOnlyMediaLibrary, isAudioBlockMediaUploadEnabled, } = this.props; return this.getAllSources() .filter( ( source ) => { if ( __experimentalOnlyMediaLibrary ) { return source.mediaLibrary; } else if ( allowedTypes.every( ( allowedType ) => allowedType === MEDIA_TYPE_AUDIO && source.types.includes( allowedType ) ) && source.id !== URL_MEDIA_SOURCE ) { return isAudioBlockMediaUploadEnabled === true; } return allowedTypes.some( ( allowedType ) => source.types.includes( allowedType ) ); } ) .map( ( source ) => { return { ...source, icon: source.icon || this.getChooseFromDeviceIcon(), }; } ); } getChooseFromDeviceIcon() { return mobile; } onPickerPresent() { const { autoOpen } = this.props; const isIOS = Platform.OS === 'ios'; if ( this.picker ) { // the delay below is required because on iOS this action sheet gets dismissed by the close event of the Inserter // so this delay allows the Inserter to be closed fully before presenting action sheet. if ( autoOpen && isIOS ) { delay( () => this.picker.presentPicker(), PICKER_OPENING_DELAY ); } else { this.picker.presentPicker(); } } } onPickerSelect( value ) { const { allowedTypes = [], onSelect, onSelectURL, multiple = false, } = this.props; if ( value === URL_MEDIA_SOURCE ) { prompt( __( 'Type a URL' ), // title undefined, // message [ { text: __( '取消' ), style: 'cancel', }, { text: __( '应用' ), onPress: onSelectURL, }, ], // buttons 'plain-text', // type undefined, // defaultValue 'url' // keyboardType ); return; } 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 ); } } ); } render() { const { allowedTypes = [], isReplacingMedia, multiple } = this.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 ); const isAnyType = isOneType && allowedTypes.includes( MEDIA_TYPE_ANY ); const isImageOrVideo = allowedTypes.length === 2 && allowedTypes.includes( MEDIA_TYPE_IMAGE ) && allowedTypes.includes( MEDIA_TYPE_VIDEO ); let pickerTitle; if ( isImage ) { if ( isReplacingMedia ) { pickerTitle = __( '更换图片' ); } else { pickerTitle = multiple ? __( 'Choose images' ) : __( '选择图片' ); } } else if ( isVideo ) { if ( isReplacingMedia ) { pickerTitle = __( '替换视频' ); } else { pickerTitle = __( '选择视频' ); } } else if ( isImageOrVideo ) { if ( isReplacingMedia ) { pickerTitle = __( 'Replace image or video' ); } else { pickerTitle = __( 'Choose image or video' ); } } else if ( isAudio ) { if ( isReplacingMedia ) { pickerTitle = __( '替换音频' ); } else { pickerTitle = __( '选择音频' ); } } else if ( isAnyType ) { pickerTitle = __( '选择文件' ); if ( isReplacingMedia ) { pickerTitle = __( 'Replace file' ); } else { pickerTitle = __( '选择文件' ); } } const getMediaOptions = () => ( <Picker title={ pickerTitle } hideCancelButton ref={ ( instance ) => ( this.picker = instance ) } options={ this.getMediaOptionsItems() } onChange={ this.onPickerSelect } /> ); return this.props.render( { open: this.onPickerPresent, getMediaOptions, } ); } } export default compose( [ withSelect( ( select ) => { return { isAudioBlockMediaUploadEnabled: select( blockEditorStore ).getSettings( 'capabilities' ) .isAudioBlockMediaUploadEnabled === true, }; } ), ] )( MediaUpload );