Skip to content

Commit

Permalink
Add GIF badge to GIFs in editor
Browse files Browse the repository at this point in the history
  • Loading branch information
kmdupr33 committed Jan 4, 2020
1 parent 334b0b2 commit afa2f84
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 85 deletions.
172 changes: 87 additions & 85 deletions packages/block-library/src/image/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
ToggleControl,
ToolbarButton,
ToolbarGroup,
Badgeable,
} from '@wordpress/components';

import {
Expand All @@ -49,7 +50,6 @@ import styles from './styles.scss';
import SvgIcon, { editImageIcon } from './icon';
import SvgIconRetry from './icon-retry';
import { getUpdatedLinkTargetSettings } from './utils';

import {
LINK_DESTINATION_CUSTOM,
LINK_DESTINATION_NONE,
Expand Down Expand Up @@ -382,92 +382,94 @@ export class ImageEdit extends React.Component {
};

const imageContainerHeight = Dimensions.get( 'window' ).width / IMAGE_ASPECT_RATIO;

const getImageComponent = ( openMediaOptions, getMediaOptions ) => (
<TouchableWithoutFeedback
accessible={ ! isSelected }
onPress={ this.onImagePressed }
onLongPress={ openMediaOptions }
disabled={ ! isSelected }
>
<View style={ { flex: 1 } }>
{ getInspectorControls() }
{ getMediaOptions() }
{ ( ! this.state.isCaptionSelected ) &&
getToolbarEditButton( openMediaOptions )
}
<MediaUploadProgress
height={ height }
width={ width }
coverUrl={ url }
mediaId={ id }
onUpdateMediaProgress={ this.updateMediaProgress }
onFinishMediaUploadWithSuccess={ this.finishMediaUploadWithSuccess }
onFinishMediaUploadWithFailure={ this.finishMediaUploadWithFailure }
onMediaUploadStateReset={ this.mediaUploadStateReset }
renderContent={ ( { isUploadInProgress, isUploadFailed, finalWidth, finalHeight, imageWidthWithinContainer, retryMessage } ) => {
const opacity = isUploadInProgress ? 0.3 : 1;
const icon = this.getIcon( isUploadFailed );
const imageBorderOnSelectedStyle = isSelected && ! ( isUploadInProgress || isUploadFailed || this.state.isCaptionSelected ) ? styles.imageBorder : '';

const iconContainer = (
<View style={ styles.modalIcon }>
{ icon }
</View>
);

return (
<View style={ {
flex: 1,
// only set alignSelf if an image exists because alignSelf causes the placeholder
// to disappear when an aligned image can't be downloaded
// https://github.com/wordpress-mobile/gutenberg-mobile/issues/1592
alignSelf: imageWidthWithinContainer && alignToFlex[ align ] }
} >
{ ! imageWidthWithinContainer &&
<View style={ [ styles.imageContainer, { height: imageContainerHeight } ] } >
{ this.getIcon( false ) }
</View> }
<ImageBackground
accessible={ true }
disabled={ ! isSelected }
accessibilityLabel={ alt }
accessibilityHint={ __( 'Double tap and hold to edit' ) }
accessibilityRole={ 'imagebutton' }
style={ [ imageBorderOnSelectedStyle, { width: finalWidth, height: finalHeight, opacity } ] }
resizeMethod="scale"
source={ { uri: url } }
key={ url }
>
{ isUploadFailed &&
<View style={ [ styles.imageContainer, { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.5)' } ] } >
{ iconContainer }
<Text style={ styles.uploadFailedText }>{ retryMessage }</Text>
</View>
}
</ImageBackground>
</View>
);
} }
/>
<Caption
clientId={ this.props.clientId }
isSelected={ this.state.isCaptionSelected }
accessible={ true }
accessibilityLabelCreator={ ( caption ) =>
isEmpty( caption ) ?
/* translators: accessibility text. Empty image caption. */
( 'Image caption. Empty' ) :
sprintf(
/* translators: accessibility text. %s: image caption. */
__( 'Image caption. %s' ),
caption )
<Badgeable text="gif" show={ url.includes( '.gif' ) } >
<TouchableWithoutFeedback
accessible={ ! isSelected }
onPress={ this.onImagePressed }
onLongPress={ openMediaOptions }
disabled={ ! isSelected }
>
<View style={ { flex: 1 } }>
{ getInspectorControls() }
{ getMediaOptions() }
{ ( ! this.state.isCaptionSelected ) &&
getToolbarEditButton( openMediaOptions )
}
onFocus={ this.onFocusCaption }
onBlur={ this.props.onBlur } // always assign onBlur as props
/>
</View>
</TouchableWithoutFeedback>
<MediaUploadProgress
height={ height }
width={ width }
coverUrl={ url }
mediaId={ id }
onUpdateMediaProgress={ this.updateMediaProgress }
onFinishMediaUploadWithSuccess={ this.finishMediaUploadWithSuccess }
onFinishMediaUploadWithFailure={ this.finishMediaUploadWithFailure }
onMediaUploadStateReset={ this.mediaUploadStateReset }
renderContent={ ( { isUploadInProgress, isUploadFailed, finalWidth, finalHeight, imageWidthWithinContainer, retryMessage } ) => {
const opacity = isUploadInProgress ? 0.3 : 1;
const icon = this.getIcon( isUploadFailed );
const imageBorderOnSelectedStyle = isSelected && ! ( isUploadInProgress || isUploadFailed || this.state.isCaptionSelected ) ? styles.imageBorder : '';

const iconContainer = (
<View style={ styles.modalIcon }>
{ icon }
</View>
);

return (
<View style={ {
flex: 1,
// only set alignSelf if an image exists because alignSelf causes the placeholder
// to disappear when an aligned image can't be downloaded
// https://github.com/wordpress-mobile/gutenberg-mobile/issues/1592
alignSelf: imageWidthWithinContainer && alignToFlex[ align ] }
} >
{ ! imageWidthWithinContainer &&
<View style={ [ styles.imageContainer, { height: imageContainerHeight } ] } >
{ this.getIcon( false ) }
</View> }
<ImageBackground
accessible={ true }
disabled={ ! isSelected }
accessibilityLabel={ alt }
accessibilityHint={ __( 'Double tap and hold to edit' ) }
accessibilityRole={ 'imagebutton' }
style={ [ imageBorderOnSelectedStyle, { width: finalWidth, height: finalHeight, opacity } ] }
resizeMethod="scale"
source={ { uri: url } }
key={ url }
>
{ isUploadFailed &&
<View style={ [ styles.imageContainer, { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.5)' } ] } >
{ iconContainer }
<Text style={ styles.uploadFailedText }>{ retryMessage }</Text>
</View>
}
</ImageBackground>
</View>
);
} }
/>
<Caption
clientId={ this.props.clientId }
isSelected={ this.state.isCaptionSelected }
accessible={ true }
accessibilityLabelCreator={ ( caption ) =>
isEmpty( caption ) ?
/* translators: accessibility text. Empty image caption. */
( 'Image caption. Empty' ) :
sprintf(
/* translators: accessibility text. %s: image caption. */
__( 'Image caption. %s' ),
caption )
}
onFocus={ this.onFocusCaption }
onBlur={ this.props.onBlur } // always assign onBlur as props
/>
</View>
</TouchableWithoutFeedback>

</Badgeable>
);

return (
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ export { default as KeyboardAwareFlatList } from './mobile/keyboard-aware-flat-l
export { default as Picker } from './mobile/picker';
export { default as ReadableContentView } from './mobile/readable-content-view';
export { default as StepperControl } from './mobile/stepper-control';
export { default as Badgeable } from './mobile/badgeable';
39 changes: 39 additions & 0 deletions packages/components/src/mobile/badgeable/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Badgeable

Badgeable wraps a component and adds a `Badge` overlay to that component. It looks like this:

![badgeable example](./example.png)

A Badgeable component allows us to easily add badges to existing components without duplicating code for overlaying and positioning the Badge component. Moreover, with this approach, changing the positioning of badges can be done in one place instead of every place where a badge is visible.

## Usage

```jsx
import { Image } from 'react-native';
import { Badgeable } from '@wordpress/components';
const BadgeableImage = () => (
<Badgeable text="gif" show={ url.includes( '.gif' ) }>
<Image
style={ { width: 50, height: 50 } }
source={ { uri: 'https://facebook.github.io/react-native/img/tiny_logo.png' } }
/>
</Badgeable>
)} >
```

### Props

#### text

- Type: `String`
- Required: Yes

The text to display within the badge. An uppercase transform will be applied.

#### show

- Type: `Boolean`
- Required: No
- Default: `true`

Whether to overlay the badge.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions packages/components/src/mobile/badgeable/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* External dependencies
*/
import { Text, View } from 'react-native';

/**
* Internal dependencies
*/
import styles from './styles.scss';

const Badge = ( { text } ) => (
<View style={ styles.badge }>
<Text style={ styles.badgeText }>{ text }</Text>
</View>
);
const Badgeable = ( { text, children, show = true } ) => (
<View>
{ children }
{ show && <Badge text={ text } /> }
</View>
);

export default Badgeable;
15 changes: 15 additions & 0 deletions packages/components/src/mobile/badgeable/styles.native.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.badge {
position: absolute;
top: 10px;
left: 10px;
background-color: rgba(85, 85, 85, 0.7);
border-radius: 6px;
padding: 3px 6px;
}

.badgeText {
text-transform: uppercase;
color: #fff;
font-size: 12px;
font-weight: 500;
}

0 comments on commit afa2f84

Please sign in to comment.