Make PhotoPanel bound

This commit is contained in:
John Lyon-Smith
2018-04-26 14:11:12 -07:00
parent 109e9f4d3d
commit 71cec6088a
10 changed files with 327 additions and 190 deletions

View File

@@ -36,10 +36,7 @@ export class BoundInput extends React.Component {
handleChangeText(newText) {
const { binder, name } = this.props
// TODO: Sometimes this is undefined and causes a crash?!
if (binder) {
const state = binder.getFieldState(name)
this.setState(binder.updateFieldValue(name, newText))
}
}

View File

@@ -0,0 +1,169 @@
import React, { Component } from "react"
import PropTypes from "prop-types"
import {
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
Dimensions,
ActivityIndicator,
} from "react-native"
import { Icon } from "."
import ImagePicker from "react-native-image-picker"
import autobind from "autobind-decorator"
import { api } from "../API"
const getScreenPortraitDimensions = () => {
const { width, height } = Dimensions.get("window")
return {
screenWidth: Math.min(width, height),
screenHeight: Math.max(width, height),
}
}
export class BoundPhotoPanel extends Component {
static propTypes = {
onUploadStarted: PropTypes.func,
onUploadEnded: PropTypes.func,
}
constructor(props) {
super(props)
const { name, binder } = this.props
this.state = binder.getFieldState(name)
}
componentWillReceiveProps(nextProps) {
if (nextProps.binder !== this.props.binder) {
this.setState(nextProps.binder.getFieldState(nextProps.name))
}
}
@autobind
handlePhotoPress(index) {
const { onUploadStarted, onUploadEnded } = this.props
ImagePicker.showImagePicker(
{
title: "Select Photo",
storageOptions: {
skipBackup: true,
path: "photos",
},
},
(response) => {
if (!response.didCancel && !response.error) {
if (onUploadStarted) {
onUploadStarted()
}
api
.upload(response.data)
.then((uploadData) => {
if (onUploadEnded) {
onUploadEnded(true, uploadData)
}
const { binder, name } = this.props
if (binder) {
const value = binder.getFieldValue(name)
let newValue = value.slice(0)
newValue[index] = uploadData.assetId
this.setState(binder.updateFieldValue(name, newValue))
}
})
.catch((err) => {
if (onUploadEnded) {
onUploadEnded(false)
}
})
}
}
)
}
render() {
const { screenWidth, screenHeight } = getScreenPortraitDimensions()
const photoWidth = screenHeight / 4
const photoHeight = screenWidth / 4
const rowPadding = 10
const { value: assetIds } = this.state
const renderPhoto = (index) => {
const assetId = assetIds[index]
if (assetId) {
console.log(api.makeImageUrl(assetId))
}
return (
<TouchableOpacity
key={assetId || "blank" + index.toString()}
style={{
width: photoWidth,
height: photoHeight,
borderWidth: 2,
borderColor: "gray",
borderRadius: 4,
justifyContent: "center",
}}
onPress={() => this.handlePhotoPress(index)}>
{!assetId && (
<Icon name="add" size={24} style={{ alignSelf: "center" }} />
)}
{assetId && (
<Image
source={{ uri: api.makeImageUrl(assetId) }}
style={{ width: "100%", height: "100%" }}
resizeMode="contain"
/>
)}
</TouchableOpacity>
)
}
const extraRowStyle = {
height: photoHeight + rowPadding,
paddingTop: rowPadding / 2,
paddingBottom: rowPadding / 2,
}
return (
<View
style={{
flexDirection: "column",
justifyContent: "space-between",
}}>
<Text
style={{
fontSize: 14,
marginBottom: 4,
}}>
Pictures:
</Text>
<View style={[styles.photoRow, extraRowStyle]}>
{renderPhoto(0)}
{renderPhoto(1)}
</View>
<View style={[styles.photoRow, extraRowStyle]}>
{renderPhoto(2)}
{renderPhoto(3)}
</View>
</View>
)
}
}
const styles = StyleSheet.create({
photoRow: {
flexDirection: "row",
justifyContent: "space-between",
width: "100%",
},
})

View File

@@ -1,104 +0,0 @@
import React, { Component } from "react"
import {
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
Dimensions,
} from "react-native"
import { Icon } from "."
import ImagePicker from "react-native-image-picker"
import autobind from "autobind-decorator"
const getScreenPortraitDimensions = () => {
const { width, height } = Dimensions.get("window")
return {
screenWidth: Math.min(width, height),
screenHeight: Math.max(width, height),
}
}
export class PhotoPanel extends Component {
@autobind
handlePhotoPress() {
ImagePicker.showImagePicker(
{
title: "Select Photo",
storageOptions: {
skipBackup: true,
path: "photos",
},
},
(response) => {
console.log("Response = ", response)
if (response.didCancel) {
console.log("User cancelled image picker")
} else if (response.error) {
console.log("ImagePicker Error: ", response.error)
} else if (response.customButton) {
console.log("User tapped custom button: ", response.customButton)
} else {
// You can also display the image using data:
// let source = { uri: 'data:image/jpeg;base64,' + response.data };
console.log(response)
}
}
)
}
render() {
const { screenWidth, screenHeight } = getScreenPortraitDimensions()
const photoWidth = screenHeight / 4
const photoHeight = screenWidth / 4
const numRows = 2
const numCols = 2
const rowPadding = 10
return (
<View
style={{
flexDirection: "column",
justifyContent: "space-between",
}}>
<Text
style={{
fontSize: 14,
marginBottom: 4,
}}>
Pictures:
</Text>
{Array.from(new Array(numRows), (x, i) => (
<View
key={"r" + i.toString()}
style={{
flexDirection: "row",
justifyContent: "space-between",
width: "100%",
height: photoHeight + rowPadding,
paddingTop: rowPadding / 2,
paddingBottom: rowPadding / 2,
}}>
{Array.from(new Array(numCols), (y, j) => (
<TouchableOpacity
key={"r" + i.toString() + "c" + j.toString()}
style={{
width: photoWidth,
height: photoHeight,
borderWidth: 2,
borderColor: "gray",
borderRadius: 4,
justifyContent: "center",
}}
onPress={this.handlePhotoPress}>
<Icon name="add" size={24} style={{ alignSelf: "center" }} />
</TouchableOpacity>
))}
</View>
))}
</View>
)
}
}

View File

@@ -1,9 +1,9 @@
export { Icon } from "./Icon"
export { Header } from "./Header"
export { PhotoPanel } from "./PhotoPanel"
export { OptionStrip } from "./OptionStrip"
export { BoundSwitch } from "./BoundSwitch"
export { BoundInput } from "./BoundInput"
export { BoundButton } from "./BoundButton"
export { BoundOptionStrip } from "./BoundOptionStrip"
export { BoundHeader } from "./BoundHeader"
export { BoundPhotoPanel } from "./BoundPhotoPanel"