Add GPS related disable for buttons
This commit is contained in:
@@ -7,54 +7,66 @@ import {
|
|||||||
Image,
|
Image,
|
||||||
View,
|
View,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
|
TouchableHighlight,
|
||||||
} from "react-native"
|
} from "react-native"
|
||||||
import MapView, { Marker } from "react-native-maps"
|
import MapView, { Marker } from "react-native-maps"
|
||||||
import { Icon, Header } from "../ui"
|
import { Icon, Header } from "../ui"
|
||||||
import { api } from "../API"
|
import { api } from "../API"
|
||||||
import autobind from "autobind-decorator"
|
import autobind from "autobind-decorator"
|
||||||
import { ifIphoneX } from "react-native-iphone-x-helper"
|
import { ifIphoneX } from "react-native-iphone-x-helper"
|
||||||
import { workItemTypeText, pad } from "../util"
|
import { workItemTypeText, pad, regionContainingPoints } from "../util"
|
||||||
import pinImage from "./images/pin.png"
|
import pinImage from "./images/pin.png"
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const minGPSAccuracy = 20
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: "#FFFFFF",
|
|
||||||
alignItems: "flex-start",
|
|
||||||
justifyContent: "flex-start",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export class Home extends React.Component {
|
export class Home extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
sections: [],
|
sections: [],
|
||||||
|
showWorkItems: true,
|
||||||
|
region: {
|
||||||
|
latitude: 43.653908,
|
||||||
|
longitude: -79.384293,
|
||||||
|
latitudeDelta: 0.0922,
|
||||||
|
longitudeDelta: 0.0922,
|
||||||
|
},
|
||||||
|
positionInfo: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.watchId = navigator.geolocation.watchPosition(
|
||||||
|
this.handlePositionChange,
|
||||||
|
null,
|
||||||
|
{ distanceFilter: 10 }
|
||||||
|
)
|
||||||
|
|
||||||
api
|
api
|
||||||
.listWorkItemActivities()
|
.listWorkItemActivities()
|
||||||
.then((list) => {
|
.then((list) => {
|
||||||
this.setState({ sections: list.items })
|
this.setState({
|
||||||
|
sections: list.items,
|
||||||
|
region: regionContainingPoints(
|
||||||
|
list.items.map((item) => item.coordinate),
|
||||||
|
0.02
|
||||||
|
),
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
componentWillUnmount() {
|
||||||
_handleNavigatorEvent(event) {
|
if (this.watchId) {
|
||||||
switch (event.id) {
|
navigator.geolocation.clearWatch(this.watchId)
|
||||||
case "logout":
|
|
||||||
api.logout().then(() => {
|
|
||||||
this.props.history.replace("/login")
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case "viewer":
|
|
||||||
this.props.push("/viewer")
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
handlePositionChange(positionInfo) {
|
||||||
|
this.setState({ positionInfo })
|
||||||
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
handleMarkerPress(e, sectionIndex) {
|
handleMarkerPress(e, sectionIndex) {
|
||||||
if (this.sectionList) {
|
if (this.sectionList) {
|
||||||
@@ -88,45 +100,56 @@ export class Home extends React.Component {
|
|||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
handleMyLocationPress() {
|
handleMyLocationPress() {
|
||||||
navigator.geolocation.getCurrentPosition((info) => {
|
if (this.state.positionInfo) {
|
||||||
if (this.map) {
|
const coords = this.state.positionInfo.coords
|
||||||
|
|
||||||
this.map.animateToCoordinate({
|
this.map.animateToCoordinate({
|
||||||
latitude: info.coords.latitude,
|
latitude: coords.latitude,
|
||||||
longitude: info.coords.longitude,
|
longitude: coords.longitude,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
handleToggleWorkItemsList() {
|
||||||
|
this.setState({ showWorkItems: !this.state.showWorkItems })
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { sections } = this.state
|
const { sections, showWorkItems, region, positionInfo } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: "column",
|
||||||
|
height: "100%",
|
||||||
|
backgroundColor: "#FFFFFF",
|
||||||
|
}}>
|
||||||
<Header
|
<Header
|
||||||
title="Work Item Map"
|
title="Work Item Map"
|
||||||
leftButton={{ icon: "logout", onPress: this.handleLogoutPress }}
|
leftButton={{ icon: "logout", onPress: this.handleLogoutPress }}
|
||||||
rightButton={{ icon: "glasses", onPress: this.handleGlassesPress }}
|
rightButton={{ icon: "glasses", onPress: this.handleGlassesPress }}
|
||||||
|
disabled={
|
||||||
|
!(positionInfo && positionInfo.coords.accuracy <= minGPSAccuracy)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<MapView
|
<MapView
|
||||||
ref={(ref) => {
|
ref={(ref) => {
|
||||||
this.map = ref
|
this.map = ref
|
||||||
}}
|
}}
|
||||||
style={{
|
style={[
|
||||||
|
{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "50%",
|
},
|
||||||
}}
|
showWorkItems && { height: "40%" },
|
||||||
|
!showWorkItems && { flexGrow: 1 },
|
||||||
|
]}
|
||||||
showsUserLocation
|
showsUserLocation
|
||||||
showsBuildings={false}
|
showsBuildings={false}
|
||||||
showsTraffic={false}
|
showsTraffic={false}
|
||||||
showsIndoors={false}
|
showsIndoors={false}
|
||||||
zoomControlEnabled
|
zoomControlEnabled
|
||||||
initialRegion={{
|
region={region}>
|
||||||
latitude: 43.653908,
|
|
||||||
longitude: -79.384293,
|
|
||||||
latitudeDelta: 0.0922,
|
|
||||||
longitudeDelta: 0.0922,
|
|
||||||
}}>
|
|
||||||
{sections.map((workItem, index) => (
|
{sections.map((workItem, index) => (
|
||||||
<Marker
|
<Marker
|
||||||
key={index}
|
key={index}
|
||||||
@@ -143,6 +166,14 @@ export class Home extends React.Component {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</MapView>
|
</MapView>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
display: showWorkItems ? "flex" : "none",
|
||||||
|
flexDirection: "column",
|
||||||
|
flexGrow: 1,
|
||||||
|
flexBasis: 0,
|
||||||
|
width: "100%",
|
||||||
|
}}>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
@@ -162,9 +193,9 @@ export class Home extends React.Component {
|
|||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
/>
|
/>
|
||||||
<Icon
|
<Icon
|
||||||
|
style={{ marginLeft: 5, marginRight: 10 }}
|
||||||
name="cancel"
|
name="cancel"
|
||||||
size={16}
|
size={16}
|
||||||
style={{ marginLeft: 5, marginRight: 10, tintColor: "gray" }}
|
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<SectionList
|
<SectionList
|
||||||
@@ -191,23 +222,35 @@ export class Home extends React.Component {
|
|||||||
keyExtractor={(item) => item._id}
|
keyExtractor={(item) => item._id}
|
||||||
renderItem={({ item: activity, section }) => {
|
renderItem={({ item: activity, section }) => {
|
||||||
return (
|
return (
|
||||||
|
<TouchableHighlight
|
||||||
|
style={{
|
||||||
|
height: 50,
|
||||||
|
paddingLeft: 20,
|
||||||
|
paddingRight: 20,
|
||||||
|
backgroundColor: "white",
|
||||||
|
}}
|
||||||
|
underlayColor="#EEEEEE"
|
||||||
|
onPress={() => this.handleItemSelect(activity, index)}>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
|
height: "100%",
|
||||||
|
width: "100%",
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
height: 50,
|
|
||||||
marginTop: 3,
|
|
||||||
marginBottom: 3,
|
|
||||||
}}>
|
}}>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: 8,
|
fontSize: 8,
|
||||||
width: 45,
|
width: 45,
|
||||||
marginLeft: 5,
|
|
||||||
alignSelf: "center",
|
alignSelf: "center",
|
||||||
}}>
|
}}>
|
||||||
{activity.status.toUpperCase()}
|
{activity.status.toUpperCase()}
|
||||||
</Text>
|
</Text>
|
||||||
<View style={{ width: "75%", flexDirection: "column" }}>
|
<View
|
||||||
|
style={{
|
||||||
|
flexGrow: 1,
|
||||||
|
flexBasis: 0,
|
||||||
|
flexDirection: "column",
|
||||||
|
}}>
|
||||||
<Text style={{ fontSize: 20, fontWeight: "bold" }}>
|
<Text style={{ fontSize: 20, fontWeight: "bold" }}>
|
||||||
{activity.resolution}
|
{activity.resolution}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -215,33 +258,41 @@ export class Home extends React.Component {
|
|||||||
{activity.address || "..."}
|
{activity.address || "..."}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<TouchableOpacity
|
<Icon
|
||||||
|
name="rightArrow"
|
||||||
|
size={16}
|
||||||
style={{ alignSelf: "center" }}
|
style={{ alignSelf: "center" }}
|
||||||
onPress={() => this.handleItemSelect(activity, index)}>
|
/>
|
||||||
<Icon name="rightArrow" size={16} />
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</View>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: 45,
|
height: 55,
|
||||||
backgroundColor: "#F4F4F4",
|
backgroundColor: "#F4F4F4",
|
||||||
...ifIphoneX({ marginBottom: 22 }, {}),
|
...ifIphoneX({ marginBottom: 22 }, {}),
|
||||||
}}>
|
}}>
|
||||||
<TouchableOpacity onPress={this.handleMyLocationPress}>
|
<TouchableOpacity
|
||||||
|
disabled={!positionInfo}
|
||||||
|
onPress={this.handleMyLocationPress}>
|
||||||
<Icon
|
<Icon
|
||||||
name="center"
|
name="center"
|
||||||
size={24}
|
size={24}
|
||||||
style={{ marginLeft: 15, tintColor: "gray" }}
|
style={{ marginLeft: 15, tintColor: "gray" }}
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<Text style={{ color: "gray", fontSize: 20 }}>Hide List</Text>
|
<TouchableOpacity onPress={this.handleToggleWorkItemsList}>
|
||||||
|
<Text style={{ color: "gray", fontSize: 20 }}>
|
||||||
|
{showWorkItems ? "Hide List" : "Show List"}
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
<TouchableOpacity onPress={this.handleWorkItemsListPress}>
|
<TouchableOpacity onPress={this.handleWorkItemsListPress}>
|
||||||
<Icon
|
<Icon
|
||||||
name="settings"
|
name="settings"
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ export class WorkItemList extends React.Component {
|
|||||||
style={{
|
style={{
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
width: 45,
|
width: 45,
|
||||||
marginLeft: 5,
|
|
||||||
alignSelf: "center",
|
alignSelf: "center",
|
||||||
}}>
|
}}>
|
||||||
{pad(item.ticketNumber, 4)}
|
{pad(item.ticketNumber, 4)}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export const localIPAddr = "192.168.1.175"
|
export const localIPAddr = "192.168.1.175"
|
||||||
// export const defaultUser = "john@lyon-smith.org"
|
export const defaultUser = "john@lyon-smith.org"
|
||||||
export const defaultUser = ""
|
// export const defaultUser = ""
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const images = {
|
|||||||
back: require("./images/back.png"),
|
back: require("./images/back.png"),
|
||||||
hand: require("./images/hand.png"),
|
hand: require("./images/hand.png"),
|
||||||
center: require("./images/center.png"),
|
center: require("./images/center.png"),
|
||||||
|
cancel: require("./images/cancel.png"),
|
||||||
rightArrow: require("./images/right-arrow.png"),
|
rightArrow: require("./images/right-arrow.png"),
|
||||||
search: require("./images/search.png"),
|
search: require("./images/search.png"),
|
||||||
settings: require("./images/settings.png"),
|
settings: require("./images/settings.png"),
|
||||||
|
|||||||
@@ -55,3 +55,36 @@ export const pad = (num, size) => {
|
|||||||
while (s.length < size) s = "0" + s
|
while (s.length < size) s = "0" + s
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const regionContainingPoints = (points, inset) => {
|
||||||
|
let minX, maxX, minY, maxY
|
||||||
|
|
||||||
|
// init first point
|
||||||
|
;((point) => {
|
||||||
|
minX = point.latitude
|
||||||
|
maxX = point.latitude
|
||||||
|
minY = point.longitude
|
||||||
|
maxY = point.longitude
|
||||||
|
})(points[0])
|
||||||
|
|
||||||
|
// calculate rect
|
||||||
|
points.map((point) => {
|
||||||
|
minX = Math.min(minX, point.latitude)
|
||||||
|
maxX = Math.max(maxX, point.latitude)
|
||||||
|
minY = Math.min(minY, point.longitude)
|
||||||
|
maxY = Math.max(maxY, point.longitude)
|
||||||
|
})
|
||||||
|
|
||||||
|
const midX = (minX + maxX) / 2
|
||||||
|
const midY = (minY + maxY) / 2
|
||||||
|
const midPoint = [midX, midY]
|
||||||
|
const deltaX = maxX - minX + inset
|
||||||
|
const deltaY = maxY - minY + inset
|
||||||
|
|
||||||
|
return {
|
||||||
|
latitude: midX,
|
||||||
|
longitude: midY,
|
||||||
|
latitudeDelta: deltaX,
|
||||||
|
longitudeDelta: deltaY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user