Add GPS related disable for buttons
This commit is contained in:
@@ -7,54 +7,66 @@ import {
|
||||
Image,
|
||||
View,
|
||||
TouchableOpacity,
|
||||
TouchableHighlight,
|
||||
} from "react-native"
|
||||
import MapView, { Marker } from "react-native-maps"
|
||||
import { Icon, Header } from "../ui"
|
||||
import { api } from "../API"
|
||||
import autobind from "autobind-decorator"
|
||||
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"
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#FFFFFF",
|
||||
alignItems: "flex-start",
|
||||
justifyContent: "flex-start",
|
||||
},
|
||||
})
|
||||
const minGPSAccuracy = 20
|
||||
|
||||
export class Home extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
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
|
||||
.listWorkItemActivities()
|
||||
.then((list) => {
|
||||
this.setState({ sections: list.items })
|
||||
this.setState({
|
||||
sections: list.items,
|
||||
region: regionContainingPoints(
|
||||
list.items.map((item) => item.coordinate),
|
||||
0.02
|
||||
),
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
@autobind
|
||||
_handleNavigatorEvent(event) {
|
||||
switch (event.id) {
|
||||
case "logout":
|
||||
api.logout().then(() => {
|
||||
this.props.history.replace("/login")
|
||||
})
|
||||
break
|
||||
case "viewer":
|
||||
this.props.push("/viewer")
|
||||
break
|
||||
componentWillUnmount() {
|
||||
if (this.watchId) {
|
||||
navigator.geolocation.clearWatch(this.watchId)
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
handlePositionChange(positionInfo) {
|
||||
this.setState({ positionInfo })
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleMarkerPress(e, sectionIndex) {
|
||||
if (this.sectionList) {
|
||||
@@ -88,45 +100,56 @@ export class Home extends React.Component {
|
||||
|
||||
@autobind
|
||||
handleMyLocationPress() {
|
||||
navigator.geolocation.getCurrentPosition((info) => {
|
||||
if (this.map) {
|
||||
this.map.animateToCoordinate({
|
||||
latitude: info.coords.latitude,
|
||||
longitude: info.coords.longitude,
|
||||
})
|
||||
}
|
||||
})
|
||||
if (this.state.positionInfo) {
|
||||
const coords = this.state.positionInfo.coords
|
||||
|
||||
this.map.animateToCoordinate({
|
||||
latitude: coords.latitude,
|
||||
longitude: coords.longitude,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleToggleWorkItemsList() {
|
||||
this.setState({ showWorkItems: !this.state.showWorkItems })
|
||||
}
|
||||
|
||||
render() {
|
||||
const { sections } = this.state
|
||||
const { sections, showWorkItems, region, positionInfo } = this.state
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
backgroundColor: "#FFFFFF",
|
||||
}}>
|
||||
<Header
|
||||
title="Work Item Map"
|
||||
leftButton={{ icon: "logout", onPress: this.handleLogoutPress }}
|
||||
rightButton={{ icon: "glasses", onPress: this.handleGlassesPress }}
|
||||
disabled={
|
||||
!(positionInfo && positionInfo.coords.accuracy <= minGPSAccuracy)
|
||||
}
|
||||
/>
|
||||
<MapView
|
||||
ref={(ref) => {
|
||||
this.map = ref
|
||||
}}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "50%",
|
||||
}}
|
||||
style={[
|
||||
{
|
||||
width: "100%",
|
||||
},
|
||||
showWorkItems && { height: "40%" },
|
||||
!showWorkItems && { flexGrow: 1 },
|
||||
]}
|
||||
showsUserLocation
|
||||
showsBuildings={false}
|
||||
showsTraffic={false}
|
||||
showsIndoors={false}
|
||||
zoomControlEnabled
|
||||
initialRegion={{
|
||||
latitude: 43.653908,
|
||||
longitude: -79.384293,
|
||||
latitudeDelta: 0.0922,
|
||||
longitudeDelta: 0.0922,
|
||||
}}>
|
||||
region={region}>
|
||||
{sections.map((workItem, index) => (
|
||||
<Marker
|
||||
key={index}
|
||||
@@ -145,103 +168,131 @@ export class Home extends React.Component {
|
||||
</MapView>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
display: showWorkItems ? "flex" : "none",
|
||||
flexDirection: "column",
|
||||
flexGrow: 1,
|
||||
flexBasis: 0,
|
||||
width: "100%",
|
||||
height: 40,
|
||||
backgroundColor: "white",
|
||||
}}>
|
||||
<Icon
|
||||
name="search"
|
||||
size={16}
|
||||
style={{ marginLeft: 10, marginRight: 5, tintColor: "gray" }}
|
||||
/>
|
||||
<TextInput
|
||||
style={{ flexGrow: 1, flexBasis: 0, height: "100%" }}
|
||||
underlineColorAndroid="white"
|
||||
placeholder="Search"
|
||||
/>
|
||||
<Icon
|
||||
name="cancel"
|
||||
size={16}
|
||||
style={{ marginLeft: 5, marginRight: 10, tintColor: "gray" }}
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
height: 40,
|
||||
backgroundColor: "white",
|
||||
}}>
|
||||
<Icon
|
||||
name="search"
|
||||
size={16}
|
||||
style={{ marginLeft: 10, marginRight: 5, tintColor: "gray" }}
|
||||
/>
|
||||
<TextInput
|
||||
style={{ flexGrow: 1, flexBasis: 0, height: "100%" }}
|
||||
underlineColorAndroid="white"
|
||||
placeholder="Search"
|
||||
/>
|
||||
<Icon
|
||||
style={{ marginLeft: 5, marginRight: 10 }}
|
||||
name="cancel"
|
||||
size={16}
|
||||
/>
|
||||
</View>
|
||||
<SectionList
|
||||
ref={(ref) => (this.sectionList = ref)}
|
||||
style={{ width: "100%", flexGrow: 1 }}
|
||||
sections={sections}
|
||||
stickySectionHeadersEnabled={true}
|
||||
renderSectionHeader={({ section: workItem }) => (
|
||||
<View
|
||||
key={workItem._id}
|
||||
style={{
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "#F4F4F4",
|
||||
paddingLeft: 8,
|
||||
height: 45,
|
||||
}}>
|
||||
<Text style={{ fontSize: 16 }}>
|
||||
{workItemTypeText[workItem.workItemType].toUpperCase()}{" "}
|
||||
{pad(workItem.ticketNumber, 4)}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
keyExtractor={(item) => item._id}
|
||||
renderItem={({ item: activity, section }) => {
|
||||
return (
|
||||
<TouchableHighlight
|
||||
style={{
|
||||
height: 50,
|
||||
paddingLeft: 20,
|
||||
paddingRight: 20,
|
||||
backgroundColor: "white",
|
||||
}}
|
||||
underlayColor="#EEEEEE"
|
||||
onPress={() => this.handleItemSelect(activity, index)}>
|
||||
<View
|
||||
style={{
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
flexDirection: "row",
|
||||
}}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 8,
|
||||
width: 45,
|
||||
alignSelf: "center",
|
||||
}}>
|
||||
{activity.status.toUpperCase()}
|
||||
</Text>
|
||||
<View
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
flexBasis: 0,
|
||||
flexDirection: "column",
|
||||
}}>
|
||||
<Text style={{ fontSize: 20, fontWeight: "bold" }}>
|
||||
{activity.resolution}
|
||||
</Text>
|
||||
<Text style={{ fontSize: 14, color: "gray" }}>
|
||||
{activity.address || "..."}
|
||||
</Text>
|
||||
</View>
|
||||
<Icon
|
||||
name="rightArrow"
|
||||
size={16}
|
||||
style={{ alignSelf: "center" }}
|
||||
/>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<SectionList
|
||||
ref={(ref) => (this.sectionList = ref)}
|
||||
style={{ width: "100%", flexGrow: 1 }}
|
||||
sections={sections}
|
||||
stickySectionHeadersEnabled={true}
|
||||
renderSectionHeader={({ section: workItem }) => (
|
||||
<View
|
||||
key={workItem._id}
|
||||
style={{
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "#F4F4F4",
|
||||
paddingLeft: 8,
|
||||
height: 45,
|
||||
}}>
|
||||
<Text style={{ fontSize: 16 }}>
|
||||
{workItemTypeText[workItem.workItemType].toUpperCase()}{" "}
|
||||
{pad(workItem.ticketNumber, 4)}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
keyExtractor={(item) => item._id}
|
||||
renderItem={({ item: activity, section }) => {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
height: 50,
|
||||
marginTop: 3,
|
||||
marginBottom: 3,
|
||||
}}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 8,
|
||||
width: 45,
|
||||
marginLeft: 5,
|
||||
alignSelf: "center",
|
||||
}}>
|
||||
{activity.status.toUpperCase()}
|
||||
</Text>
|
||||
<View style={{ width: "75%", flexDirection: "column" }}>
|
||||
<Text style={{ fontSize: 20, fontWeight: "bold" }}>
|
||||
{activity.resolution}
|
||||
</Text>
|
||||
<Text style={{ fontSize: 14, color: "gray" }}>
|
||||
{activity.address || "..."}
|
||||
</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={{ alignSelf: "center" }}
|
||||
onPress={() => this.handleItemSelect(activity, index)}>
|
||||
<Icon name="rightArrow" size={16} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
height: 45,
|
||||
height: 55,
|
||||
backgroundColor: "#F4F4F4",
|
||||
...ifIphoneX({ marginBottom: 22 }, {}),
|
||||
}}>
|
||||
<TouchableOpacity onPress={this.handleMyLocationPress}>
|
||||
<TouchableOpacity
|
||||
disabled={!positionInfo}
|
||||
onPress={this.handleMyLocationPress}>
|
||||
<Icon
|
||||
name="center"
|
||||
size={24}
|
||||
style={{ marginLeft: 15, tintColor: "gray" }}
|
||||
/>
|
||||
</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}>
|
||||
<Icon
|
||||
name="settings"
|
||||
|
||||
@@ -145,7 +145,6 @@ export class WorkItemList extends React.Component {
|
||||
style={{
|
||||
fontSize: 10,
|
||||
width: 45,
|
||||
marginLeft: 5,
|
||||
alignSelf: "center",
|
||||
}}>
|
||||
{pad(item.ticketNumber, 4)}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export const localIPAddr = "192.168.1.175"
|
||||
// export const defaultUser = "john@lyon-smith.org"
|
||||
export const defaultUser = ""
|
||||
export const defaultUser = "john@lyon-smith.org"
|
||||
// export const defaultUser = ""
|
||||
|
||||
@@ -8,6 +8,7 @@ const images = {
|
||||
back: require("./images/back.png"),
|
||||
hand: require("./images/hand.png"),
|
||||
center: require("./images/center.png"),
|
||||
cancel: require("./images/cancel.png"),
|
||||
rightArrow: require("./images/right-arrow.png"),
|
||||
search: require("./images/search.png"),
|
||||
settings: require("./images/settings.png"),
|
||||
|
||||
@@ -55,3 +55,36 @@ export const pad = (num, size) => {
|
||||
while (s.length < size) s = "0" + 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