mirror of
https://gitlab.com/wheres-the-tp/ui-mobile.git
synced 2026-01-25 09:44:55 -06:00
image preview modal
This commit is contained in:
parent
c8ebf2b366
commit
a781ecc8ec
6 changed files with 127 additions and 62 deletions
|
|
@ -4,6 +4,7 @@ import { Text, View, TouchableOpacity, Image } from 'react-native';
|
|||
import { Icon } from 'react-native-material-ui';
|
||||
import uiTheme from '../ui-theme.js';
|
||||
import ReactNativeImagePicker from 'react-native-image-picker';
|
||||
import { type List } from 'immutable';
|
||||
|
||||
const { palette: { accentColor } } = uiTheme;
|
||||
|
||||
|
|
@ -19,12 +20,12 @@ export const ImageThumb = ({ uri, onPress }: { uri?: string, onPress: () => void
|
|||
<Image source={{ uri }} style={{ height: 35, width: 35, margin: 5 }} />
|
||||
</TouchableOpacity>;
|
||||
|
||||
export const ImagePicker = ({ children, onCreateNew }: { children?: any, onCreateNew: Function }) =>
|
||||
export const ImagePicker = ({ children, onCreateNew }: { children?: List<any>, onCreateNew: Function }) =>
|
||||
<View style={{ flexDirection: 'row', marginTop: 10 }}>
|
||||
<TouchableOpacity onPress={openImagePicker(onCreateNew)}>
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
<Icon name="insert-photo" size={35} color={accentColor} style={{ margin: 5 }} />
|
||||
{(!children || !children.length) &&
|
||||
{(!children || !children.size) &&
|
||||
<View style={{ flexDirection: 'column', justifyContent: 'center' }}>
|
||||
<Text style={{ fontSize: 16 }}>Add Images</Text>
|
||||
</View>}
|
||||
|
|
|
|||
38
js/modals/ImagePreviewModal.js
Normal file
38
js/modals/ImagePreviewModal.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { TouchableOpacity, Image } from 'react-native';
|
||||
import { ActionButton } from 'react-native-material-ui';
|
||||
|
||||
const backdropStyle = {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
backgroundColor: 'black',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
};
|
||||
|
||||
const imageStyle = {
|
||||
flex: 2,
|
||||
resizeMode: 'contain',
|
||||
};
|
||||
|
||||
type Props = {
|
||||
onClose: () => void,
|
||||
onDelete: () => void,
|
||||
imageSrc: string,
|
||||
};
|
||||
|
||||
const ImagePreviewModal = ({ onClose, onDelete, imageSrc }: Props) => {
|
||||
return (
|
||||
<TouchableOpacity onPress={onClose} style={backdropStyle}>
|
||||
<Image style={imageStyle} source={{ uri: imageSrc }} />
|
||||
<ActionButton icon="delete" onPress={onDelete} />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
ImagePreviewModal.displayName = 'ImagePreviewModal';
|
||||
|
||||
export default ImagePreviewModal;
|
||||
|
|
@ -6,6 +6,7 @@ import { Divider } from 'react-native-material-ui';
|
|||
import FoodItemRecord from '../records/FoodItemRecord';
|
||||
import PlaceRecord from '../records/PlaceRecord';
|
||||
import NameModal from '../modals/FoodItemNameModal';
|
||||
import ImagePreviewModal from '../modals/ImagePreviewModal';
|
||||
import QuantityPicker from '../components/QuantityPicker';
|
||||
import { compose, branch, withState, withHandlers, renderComponent, mapProps } from 'recompose';
|
||||
import RNGooglePlaces from 'react-native-google-places';
|
||||
|
|
@ -52,12 +53,12 @@ type Props = {
|
|||
setModalsVisible: Function,
|
||||
place: typeof PlaceRecord,
|
||||
setPlace: (place: typeof PlaceRecord) => void,
|
||||
removeImageAtIndex: (i: number) => () => void,
|
||||
updatePlace: (place: GooglePlaceObject) => void,
|
||||
addImage: (uri: string) => void,
|
||||
setImagePreview: (index?: number) => void,
|
||||
};
|
||||
const CreateFoodItem = (props: Props) => {
|
||||
const { foodItem, toggleNameModal, setPropOfFoodItem, place, updatePlace, removeImageAtIndex, addImage } = props;
|
||||
const { foodItem, toggleNameModal, setPropOfFoodItem, place, updatePlace, addImage, setImagePreview } = props;
|
||||
|
||||
return (
|
||||
<View style={{ ...theme.page.container, backgroundColor: 'white', padding: 10 }}>
|
||||
|
|
@ -77,14 +78,14 @@ const CreateFoodItem = (props: Props) => {
|
|||
<Divider />
|
||||
<ImagePicker onCreateNew={addImage}>
|
||||
{foodItem.images.map((image, index) =>
|
||||
<ImageThumb key={index} uri={image} onPress={removeImageAtIndex(index)} />
|
||||
<ImageThumb key={index} uri={image} onPress={() => setImagePreview(index)} />
|
||||
)}
|
||||
</ImagePicker>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const enhanceNameModal = compose(
|
||||
const NameModalComp = compose(
|
||||
renderComponent,
|
||||
mapProps(({ toggleNameModal, setPropOfFoodItem }: Props) => {
|
||||
return {
|
||||
|
|
@ -92,57 +93,73 @@ const enhanceNameModal = compose(
|
|||
onUpdate: setPropOfFoodItem('name'),
|
||||
};
|
||||
})
|
||||
);
|
||||
)(NameModal);
|
||||
|
||||
const ImagePreviewComp = compose(
|
||||
renderComponent,
|
||||
mapProps(({ foodItem, setFoodItem, setImagePreview, imagePreview }) => {
|
||||
return {
|
||||
onClose: () => setImagePreview(-1),
|
||||
onDelete: () => {
|
||||
setFoodItem(foodItem.deleteIn(['images', imagePreview]));
|
||||
setImagePreview(-1);
|
||||
},
|
||||
imageSrc: foodItem.images.get(imagePreview),
|
||||
};
|
||||
})
|
||||
)(ImagePreviewModal);
|
||||
|
||||
const setPropOfFoodItem = ({ foodItem, setFoodItem }: Props) => (prop: string) => (value: any) => {
|
||||
setFoodItem(foodItem.set(prop, value));
|
||||
};
|
||||
|
||||
const addImage = ({ foodItem, setFoodItem }: Props) => (uri: string) => {
|
||||
setFoodItem(foodItem.update('images', images => images.push(uri)));
|
||||
};
|
||||
|
||||
const updatePlace = ({ setPlace, foodItem, setFoodItem }: Props) => ({
|
||||
placeID,
|
||||
latitude,
|
||||
longitude,
|
||||
name,
|
||||
address,
|
||||
phoneNumber,
|
||||
website,
|
||||
}) => {
|
||||
setPlace(
|
||||
new PlaceRecord({
|
||||
id: placeID,
|
||||
name,
|
||||
address,
|
||||
latitude,
|
||||
longitude,
|
||||
phoneNumber,
|
||||
website,
|
||||
})
|
||||
);
|
||||
|
||||
setFoodItem(
|
||||
foodItem.merge({
|
||||
placeId: placeID,
|
||||
latitude,
|
||||
longitude,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const toggleNameModal = ({ nameModalOpen, setNameModalOpen }) => () => setNameModalOpen(!nameModalOpen);
|
||||
|
||||
export default compose(
|
||||
withState('foodItem', 'setFoodItem', new FoodItemRecord()),
|
||||
withState('place', 'setPlace', new PlaceRecord()),
|
||||
withState('nameModalOpen', 'setNameModalOpen', false),
|
||||
withState('imagePreview', 'setImagePreview', -1),
|
||||
withHandlers({
|
||||
setPropOfFoodItem: ({ foodItem, setFoodItem }: Props) => (prop: string) => (value: any) => {
|
||||
setFoodItem(foodItem.set(prop, value));
|
||||
},
|
||||
addImage: ({ foodItem, setFoodItem }: Props) => (uri: string) => {
|
||||
setFoodItem(foodItem.update('images', images => [uri].concat(images)));
|
||||
},
|
||||
removeImageAtIndex: ({ foodItem, setFoodItem }: Props) => (index: number) => () => {
|
||||
setFoodItem(
|
||||
foodItem.update('images', (images: Array<string>) => {
|
||||
images.splice(index, 1);
|
||||
return images;
|
||||
})
|
||||
);
|
||||
},
|
||||
updatePlace: ({ setPlace, foodItem, setFoodItem }: Props) => ({
|
||||
placeID,
|
||||
latitude,
|
||||
longitude,
|
||||
name,
|
||||
address,
|
||||
phoneNumber,
|
||||
website,
|
||||
}) => {
|
||||
setPlace(
|
||||
new PlaceRecord({
|
||||
id: placeID,
|
||||
name,
|
||||
address,
|
||||
latitude,
|
||||
longitude,
|
||||
phoneNumber,
|
||||
website,
|
||||
})
|
||||
);
|
||||
|
||||
setFoodItem(
|
||||
foodItem.merge({
|
||||
placeId: placeID,
|
||||
latitude,
|
||||
longitude,
|
||||
})
|
||||
);
|
||||
},
|
||||
toggleNameModal: ({ nameModalOpen, setNameModalOpen }) => () => setNameModalOpen(!nameModalOpen),
|
||||
setPropOfFoodItem,
|
||||
addImage,
|
||||
updatePlace,
|
||||
toggleNameModal,
|
||||
}),
|
||||
branch(({ nameModalOpen }) => !!nameModalOpen, enhanceNameModal(NameModal))
|
||||
branch(({ nameModalOpen }) => !!nameModalOpen, NameModalComp),
|
||||
branch(({ imagePreview }) => imagePreview > -1, ImagePreviewComp)
|
||||
)(CreateFoodItem);
|
||||
|
|
|
|||
|
|
@ -68,15 +68,15 @@ export class FoodItemDetail extends Component {
|
|||
return (
|
||||
<View style={{ ...theme.page.container }}>
|
||||
<View style={{ flex: 3 }}>
|
||||
{viewableImages.length === 1 &&
|
||||
<Image style={stretchedStyle} source={{ uri: viewableImages[0] }} />}
|
||||
{viewableImages.length > 1 &&
|
||||
{viewableImages.size === 1 &&
|
||||
<Image style={stretchedStyle} source={{ uri: viewableImages.get(0) }} />}
|
||||
{viewableImages.size > 1 &&
|
||||
<Carousel autoplay={false} onAnimateNextPage={this.changeCurrentImage} style={stretchedStyle}>
|
||||
{viewableImages.map(uri =>
|
||||
<Image key={uri} style={{ flex: 1, resizeMode: 'stretch' }} source={{ uri }} />
|
||||
)}
|
||||
</Carousel>}
|
||||
<CountBadge currentImage={this.state.currentImage + 1} totalCount={viewableImages.length} />
|
||||
<CountBadge currentImage={this.state.currentImage + 1} totalCount={viewableImages.size} />
|
||||
</View>
|
||||
<View style={{ flex: 1, marginBottom: 10, ...contentTileStyle }}>
|
||||
<View style={{ marginTop: 15 }}>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//@flow
|
||||
import { Record } from 'immutable';
|
||||
import { fromJS, List, Record } from 'immutable';
|
||||
|
||||
export const QUANTITY_NONE: 'none' = 'none';
|
||||
export const QUANTITY_FEW: 'few' = 'few';
|
||||
|
|
@ -28,7 +28,7 @@ export type FoodItem = {
|
|||
distance: number,
|
||||
quantity: Quantity,
|
||||
category: Category,
|
||||
images: Array<string>,
|
||||
images: List<string>,
|
||||
thumbImage: ?string,
|
||||
titleImage: ?string,
|
||||
};
|
||||
|
|
@ -42,9 +42,18 @@ const FoodRecordDefaults: FoodItem = {
|
|||
distance: 999,
|
||||
quantity: QUANTITY_MANY,
|
||||
category: CATEGORY_DESSERTS,
|
||||
images: [],
|
||||
images: new List(),
|
||||
thumbImage: '',
|
||||
titleImage: '',
|
||||
};
|
||||
|
||||
export default Record(FoodRecordDefaults, 'FoodItemRecord');
|
||||
const FoodItemRecord = Record(FoodRecordDefaults, 'FoodItemRecord');
|
||||
|
||||
export const createFoodItem = (foodItemRaw: Object) => {
|
||||
return new FoodItemRecord({
|
||||
...foodItemRaw,
|
||||
images: fromJS(foodItemRaw.images),
|
||||
});
|
||||
};
|
||||
|
||||
export default FoodItemRecord;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//@flow
|
||||
import FoodItemRecord from '../records/FoodItemRecord';
|
||||
import { createFoodItem } from '../records/FoodItemRecord';
|
||||
import { Observable } from 'rxjs';
|
||||
import { setById } from '../helpers/ImmutableHelpers';
|
||||
import { Map } from 'immutable';
|
||||
|
|
@ -110,4 +110,4 @@ const DUMMY_DATA = [
|
|||
|
||||
export const foodItemsRaw$ = Observable.from(DUMMY_DATA);
|
||||
|
||||
export default foodItemsRaw$.map(FoodItemRecord).scan(setById, Map());
|
||||
export default foodItemsRaw$.map(createFoodItem).scan(setById, Map());
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue