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] Add badges on gifs #19111

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
kmdupr33 marked this conversation as resolved.
Show resolved Hide resolved
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;
}