Add GPS related disable for buttons

This commit is contained in:
John Lyon-Smith
2018-04-14 14:05:21 -07:00
parent 7e366062b1
commit 84e43b0573
5 changed files with 206 additions and 122 deletions

View File

@@ -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({
latitude: info.coords.latitude, this.map.animateToCoordinate({
longitude: info.coords.longitude, latitude: coords.latitude,
}) 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%", {
height: "50%", width: "100%",
}} },
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}
@@ -145,103 +168,131 @@ export class Home extends React.Component {
</MapView> </MapView>
<View <View
style={{ style={{
flexDirection: "row", display: showWorkItems ? "flex" : "none",
alignItems: "center", flexDirection: "column",
flexGrow: 1,
flexBasis: 0,
width: "100%", width: "100%",
height: 40,
backgroundColor: "white",
}}> }}>
<Icon <View
name="search" style={{
size={16} flexDirection: "row",
style={{ marginLeft: 10, marginRight: 5, tintColor: "gray" }} alignItems: "center",
/> width: "100%",
<TextInput height: 40,
style={{ flexGrow: 1, flexBasis: 0, height: "100%" }} backgroundColor: "white",
underlineColorAndroid="white" }}>
placeholder="Search" <Icon
/> name="search"
<Icon size={16}
name="cancel" style={{ marginLeft: 10, marginRight: 5, tintColor: "gray" }}
size={16} />
style={{ marginLeft: 5, marginRight: 10, 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> </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 <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"

View File

@@ -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)}

View File

@@ -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 = ""

View File

@@ -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"),

View File

@@ -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,
}
}