Added RNFS and refactor image upload to use it
This commit is contained in:
@@ -3,6 +3,7 @@ import io from "socket.io-client"
|
||||
import { AsyncStorage } from "react-native"
|
||||
import autobind from "autobind-decorator"
|
||||
import { config } from "./config"
|
||||
import RNFS from "react-native-fs"
|
||||
|
||||
const authTokenKeyName = "AuthToken"
|
||||
const backendKeyName = "Backend"
|
||||
@@ -209,17 +210,15 @@ class API extends EventEmitter {
|
||||
headers.set("Authorization", "Bearer " + this.token)
|
||||
}
|
||||
if (method === "POST" || method === "PUT") {
|
||||
if (requestOptions.raw) {
|
||||
const isBase64 = requestOptions.raw.base64
|
||||
if (requestOptions.binary) {
|
||||
const { isBase64, offset } = requestOptions.binary
|
||||
|
||||
headers.set(
|
||||
"Content-Type",
|
||||
isBase64 ? "application/base64" : "application/octet-stream"
|
||||
)
|
||||
headers.set("Content-Length", requestOptions.raw.length)
|
||||
headers.set(
|
||||
"Content-Range",
|
||||
(isBase64 ? "base64" : "byte") + " " + requestOptions.raw.offset
|
||||
)
|
||||
headers.set("Content-Length", requestBody.length)
|
||||
headers.set("Content-Range", `byte ${offset}`)
|
||||
fetchOptions.body = requestBody
|
||||
} else {
|
||||
headers.set("Content-Type", "application/json")
|
||||
@@ -236,7 +235,7 @@ class API extends EventEmitter {
|
||||
.then((res) => {
|
||||
return Promise.all([
|
||||
Promise.resolve(res),
|
||||
requestOptions.raw && method === "GET" ? res.blob() : res.json(),
|
||||
requestOptions.binary && method === "GET" ? res.blob() : res.json(),
|
||||
])
|
||||
})
|
||||
.then((arr) => {
|
||||
@@ -429,21 +428,27 @@ class API extends EventEmitter {
|
||||
return promise
|
||||
}
|
||||
|
||||
upload(data, progressCallback) {
|
||||
upload(path, progressCallback) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunkSize = 32 * 1024
|
||||
const uploadSize = data.length
|
||||
const numberOfChunks = Math.ceil(uploadSize / chunkSize)
|
||||
let uploadSize = 0
|
||||
let numberOfChunks = 0
|
||||
let chunk = 0
|
||||
let uploadId = null
|
||||
|
||||
const uploadNextChunk = () => {
|
||||
const start = chunk * chunkSize
|
||||
const end = Math.min(uploadSize, start + chunkSize)
|
||||
const offset = chunk * chunkSize
|
||||
const length = Math.min(chunkSize, uploadSize - offset)
|
||||
|
||||
this.post("/assets/upload/" + uploadId, data.slice(start, end), {
|
||||
raw: { base64: true, length: chunkSize, offset: start },
|
||||
})
|
||||
RNFS.read(path, length, offset, "base64")
|
||||
.then((data) => {
|
||||
return this.post("/assets/upload/" + uploadId, data, {
|
||||
binary: {
|
||||
isBase64: true,
|
||||
offset,
|
||||
},
|
||||
})
|
||||
})
|
||||
.then((uploadData) => {
|
||||
chunk++
|
||||
if (progressCallback && !progressCallback(uploadData)) {
|
||||
@@ -459,12 +464,18 @@ class API extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
this.post("/assets/upload", {
|
||||
uploadSize,
|
||||
contentType: "image/jpeg",
|
||||
chunkContentType: "application/base64",
|
||||
numberOfChunks,
|
||||
})
|
||||
RNFS.stat(path)
|
||||
.then((stat) => {
|
||||
uploadSize = stat.size
|
||||
numberOfChunks = Math.ceil(uploadSize / chunkSize)
|
||||
|
||||
return this.post("/assets/upload", {
|
||||
uploadSize,
|
||||
contentType: "image/jpeg",
|
||||
chunkContentType: "application/base64",
|
||||
numberOfChunks,
|
||||
})
|
||||
})
|
||||
.then((uploadData) => {
|
||||
uploadId = uploadData.uploadId
|
||||
uploadNextChunk()
|
||||
|
||||
@@ -62,6 +62,10 @@ class WorkItemSceneAR extends React.Component {
|
||||
return this.arScene
|
||||
.performARHitTestWithRay(orientation.forward)
|
||||
.then((results) => {
|
||||
if (!results) {
|
||||
return
|
||||
}
|
||||
|
||||
const forward = orientation.forward
|
||||
const position = orientation.position
|
||||
// Default position is just one meter in front of the user.
|
||||
@@ -69,9 +73,6 @@ class WorkItemSceneAR extends React.Component {
|
||||
[forward[0] * 1.0, forward[1] * 1.0, forward[2]] * 1.0
|
||||
let hitResultPosition = null
|
||||
|
||||
console.log(orientation)
|
||||
console.log(results)
|
||||
|
||||
// Filter the hit test results based on the position.
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
let result = results[i]
|
||||
@@ -109,9 +110,7 @@ class WorkItemSceneAR extends React.Component {
|
||||
this.updateInitialRotation()
|
||||
}, 200)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
.catch((err) => {})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ export class Activity extends React.Component {
|
||||
isValid: (r, v) => v !== "",
|
||||
},
|
||||
photos: {
|
||||
initValue: [],
|
||||
isValid: (r, v) => v && v.length > 0,
|
||||
},
|
||||
status: {
|
||||
|
||||
@@ -47,8 +47,6 @@ export class Home extends React.Component {
|
||||
workItemDistance: -1,
|
||||
}
|
||||
|
||||
this.watchId = null
|
||||
|
||||
if (Platform.OS !== "ios") {
|
||||
ensurePermissions(
|
||||
[
|
||||
@@ -130,13 +128,6 @@ export class Home extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.watchId) {
|
||||
navigator.geolocation.clearWatch(this.watchId)
|
||||
this.watchId = null
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleMessageDismiss() {
|
||||
this.setState({ messageModal: null })
|
||||
@@ -255,6 +246,17 @@ export class Home extends React.Component {
|
||||
this.setState({ showWorkItems: !this.state.showWorkItems })
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleCalloutPress(workItem) {
|
||||
if (api.loggedInUser.administrator) {
|
||||
this.props.history.push(
|
||||
`/arviewer?workItemId=${workItem._id}&workItemType=${
|
||||
workItem.workItemType
|
||||
}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
sections,
|
||||
@@ -310,7 +312,7 @@ export class Home extends React.Component {
|
||||
: hardhatPinImage
|
||||
}
|
||||
onPress={(e) => this.handleMarkerPress(e, index)}>
|
||||
<Callout>
|
||||
<Callout onPress={() => this.handleCalloutPress(workItem)}>
|
||||
<View>
|
||||
<Text>
|
||||
{pad(workItem.ticketNumber, 4) +
|
||||
|
||||
@@ -29,6 +29,7 @@ import { api } from "../API"
|
||||
import "url-search-params-polyfill"
|
||||
import { config } from "../config"
|
||||
import { workItemTypeEnum, formatLatLng, parseLatLng } from "../util"
|
||||
import PropTypes from "prop-types"
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
@@ -50,6 +51,10 @@ const styles = StyleSheet.create({
|
||||
})
|
||||
|
||||
export class WorkItem extends React.Component {
|
||||
static propTypes = {
|
||||
history: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||
}
|
||||
|
||||
static bindings = {
|
||||
header: {
|
||||
noValue: true,
|
||||
@@ -65,6 +70,7 @@ export class WorkItem extends React.Component {
|
||||
isReadOnly: true,
|
||||
},
|
||||
photos: {
|
||||
initValue: [],
|
||||
isValid: (r, v) => v && v.length > 0,
|
||||
},
|
||||
details: {
|
||||
@@ -270,6 +276,13 @@ export class WorkItem extends React.Component {
|
||||
this.setState({ progressModal: null })
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleAddActivity() {
|
||||
if (this.history) {
|
||||
this.history.push(`/activity?workItemId=${this.binder._id}`)
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
binder,
|
||||
@@ -360,6 +373,26 @@ export class WorkItem extends React.Component {
|
||||
onUploadProgress={this.handleUploadProgress}
|
||||
/>
|
||||
</View>
|
||||
{api.loggedInUser.administrator &&
|
||||
binder._id && (
|
||||
<View style={styles.panel}>
|
||||
<TouchableOpacity
|
||||
onPress={this.handleAddActivity}
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
backgroundColor: "blue",
|
||||
justifyContent: "center",
|
||||
paddingHorizontal: 10,
|
||||
height: 40,
|
||||
width: "100%",
|
||||
backgroundColor: "#3BB0FD",
|
||||
}}>
|
||||
<Text style={{ alignSelf: "center", color: "black" }}>
|
||||
Add Activity
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
{isIphoneX ? <View style={{ height: 30, width: "100%" }} /> : null}
|
||||
</ScrollView>
|
||||
<ProgressModal
|
||||
|
||||
@@ -53,9 +53,10 @@ export class BoundPhotoPanel extends Component {
|
||||
ImagePicker.showImagePicker(
|
||||
{
|
||||
title: "Select Photo",
|
||||
noData: true,
|
||||
storageOptions: {
|
||||
skipBackup: true,
|
||||
path: "photos",
|
||||
path: "deighton",
|
||||
},
|
||||
},
|
||||
(response) => {
|
||||
@@ -64,7 +65,7 @@ export class BoundPhotoPanel extends Component {
|
||||
onUploadStarted()
|
||||
}
|
||||
api
|
||||
.upload(response.data, this.props.onUploadProgress)
|
||||
.upload(response.path, this.props.onUploadProgress)
|
||||
.then((uploadData) => {
|
||||
if (onUploadEnded) {
|
||||
onUploadEnded(true, uploadData)
|
||||
@@ -74,7 +75,7 @@ export class BoundPhotoPanel extends Component {
|
||||
|
||||
if (binder) {
|
||||
const value = binder.getFieldValue(name)
|
||||
let newValue = value.slice(0)
|
||||
let newValue = typeof value === "array" ? value.slice(0) : []
|
||||
|
||||
newValue[index] = uploadData.assetId
|
||||
|
||||
|
||||
Reference in New Issue
Block a user