Skip to content

Instantly share code, notes, and snippets.

@faceleg
Created February 9, 2020 03:07
Show Gist options
  • Save faceleg/bac8458f6cd3fb014101a0eadf43986e to your computer and use it in GitHub Desktop.
Save faceleg/bac8458f6cd3fb014101a0eadf43986e to your computer and use it in GitHub Desktop.
import React from "react";
import Constants from "expo-constants";
import PropTypes from "prop-types";
import { TouchableOpacity } from "react-native-gesture-handler";
import {
Icon,
Text,
Item,
Label,
Button,
ActionSheet,
Thumbnail
} from "native-base";
import * as ImagePicker from "expo-image-picker";
import * as Permissions from "expo-permissions";
import { i18n } from "../i18n";
import {
I18N_ADD_IMAGE,
I18N_REQUIRE_CAMERA_PERMISSIONS,
I18N_REQUIRE_CAMERA_ROLL_PERMISSIONS,
I18N_CAMERA,
I18N_CANCEL,
I18N_CAMERA_OR_CAMERA_ROLL,
I18N_CAMERA_ROLL,
I18N_REMOVE_ALL_IMAGES
} from "../i18n/strings";
import { COLOR_SEPARATOR_BORDER } from "../shared/constants";
import { FoodImageViewConsumer } from "../store/foods/FoodImageViewProvider";
const createNewFoodImage = ({ uri, width, height }) => ({
foodId: null,
createdAt: new Date(),
uri,
thumbnailUri: uri,
width,
height
});
export default class FoodImageControls extends React.Component {
static propTypes = {
images: PropTypes.array.isRequired,
itemStyles: PropTypes.object.isRequired,
itemLabelStyles: PropTypes.object.isRequired,
itemLabelTextStyles: PropTypes.object.isRequired,
addImage: PropTypes.func.isRequired,
deleteImage: PropTypes.func.isRequired,
deleteAllImages: PropTypes.func.isRequired
};
async _getImage() {
ActionSheet.show(
{
options: [
i18n.t(I18N_CAMERA),
i18n.t(I18N_CAMERA_ROLL),
i18n.t(I18N_CANCEL)
],
cancelButtonIndex: 2,
title: i18n.t(I18N_CAMERA_OR_CAMERA_ROLL)
},
buttonIndex => {
switch (buttonIndex) {
case 0:
return this._takePhoto();
case 1:
return this._pickImage();
default:
return;
}
}
);
}
async _takePhoto() {
// Android and iOS require both CAMERA and CAMERA_ROLL permission
if (!(await this._getCameraPermission())) {
return;
}
if (!(await this._getCameraRollPermission())) {
return;
}
let result = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
aspect: [4, 3],
allowsEditing: false,
quality: 1
});
if (!result.cancelled) {
this.props.addImage(
createNewFoodImage({
uri: result.uri,
height: result.height,
width: result.width
})
);
}
}
async _pickImage() {
// Only iOS requires permission to access CAMERA_ROLL
if (Constants.platform.ios && !(await this._getCameraRollPermission())) {
return;
}
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
aspect: [4, 3],
allowsEditing: false,
quality: 1
});
if (!result.cancelled) {
this.props.addImage(
createNewFoodImage({
uri: result.uri,
height: result.height,
width: result.width
})
);
}
}
async _getPermission(permission, failureMessage) {
const permissions = await Permissions.askAsync(permission);
const { status } = permissions;
if (status === "granted") {
return true;
}
alert(failureMessage);
return false;
}
async _getCameraRollPermission() {
return this._getPermission(
Permissions.CAMERA_ROLL,
i18n.t(I18N_REQUIRE_CAMERA_ROLL_PERMISSIONS)
);
}
async _getCameraPermission() {
if (Constants.platform.android) {
return true;
}
return this._getPermission(
Permissions.CAMERA,
i18n.t(I18N_REQUIRE_CAMERA_PERMISSIONS)
);
}
render() {
const { itemLabelStyles, itemLabelTextStyles, itemStyles } = this.props;
return (
<FoodImageViewConsumer>
{context => {
return (
<React.Fragment>
<Item style={itemStyles}>
<Label style={itemLabelStyles}>
<Text style={itemLabelTextStyles}>
{i18n.t(I18N_ADD_IMAGE)}
</Text>
</Label>
</Item>
{this.renderImages(context)}
{this.renderButton(context)}
</React.Fragment>
);
}}
</FoodImageViewConsumer>
);
}
renderButton() {
const { deleteAllImages, itemStyles, images } = this.props;
return (
<Item
style={[
itemStyles,
{
flexDirection: "row",
justifyContent: "center",
justifyItems: "center",
alignItems: "center"
}
]}
>
{images.length >= 3 && (
<Button
style={{
marginTop: 20,
borderColor: COLOR_SEPARATOR_BORDER,
borderWidth: 1
}}
light
small
onPress={() => deleteAllImages()}
>
<Text>{i18n.t(I18N_REMOVE_ALL_IMAGES)}</Text>
</Button>
)}
{images.length < 3 && (
<Button
style={{ alignSelf: "center" }}
primary
onPress={() => this._getImage()}
>
<Icon
type="MaterialCommunityIcons"
name="camera"
style={{ color: "black" }}
/>
</Button>
)}
</Item>
);
}
renderImages(foodImageViewContext) {
const { images, itemStyles } = this.props;
if (!images || !images.length) {
return null;
}
return (
<Item
style={[
itemStyles,
{
flexDirection: "row",
justifyContent: "center",
marginBottom: 20
}
]}
>
{images.map((image, imageIndex) => {
return this.renderImage({
image,
imageIndex,
images,
foodImageViewContext
});
})}
</Item>
);
}
renderImage({ image, imageIndex, images, foodImageViewContext }) {
const { deleteImage } = this.props;
return (
<TouchableOpacity
key={image.uri}
onPress={() => {
foodImageViewContext.showImageAtIndex({
imageViewImageIndex: imageIndex,
imageViewImages: images,
isImageDeletable: true,
imageDeleteCallback: deleteImage
});
}}
>
<Thumbnail
large
square
style={{ marginLeft: 20, marginRight: 20 }}
source={{ uri: image.thumbnailUri }}
/>
</TouchableOpacity>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment