import React from "react" import { StyleSheet, Text, TextInput, SectionList, Image, View, TouchableOpacity, TouchableHighlight, PermissionsAndroid, Platform, } from "react-native" import MapView, { Marker, Callout } from "react-native-maps" import { Icon, Header } from "../ui" import { MessageModal } from "../Modal" import { api } from "../API" import autobind from "autobind-decorator" import { ifIphoneX } from "react-native-iphone-x-helper" import { geoDistance, workItemTypeText, pad, regionContainingPoints, dotify, } from "../util" import { ensurePermissions } from "../App" import { versionInfo } from "../version" import { config } from "../config" import KeyboardSpacer from "react-native-keyboard-spacer" import hardhatPinImage from "./images/hardhat-pin.png" import clipboardPinImage from "./images/clipboard-pin.png" import questionPinImage from "./images/question-pin.png" const neverAskForLocationPermissionKeyName = "NeverAskForLocationPermission" const neverAskForCameraKeyName = "NeverAskForCameraPermission" export class Home extends React.Component { constructor(props) { super(props) this.state = { sections: [], showWorkItems: true, region: config.initialRegion, positionInfo: null, haveCameraPermission: false, workItemDistance: -1, } this.watchId = null ensurePermissions( [ PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, PermissionsAndroid.PERMISSIONS.CAMERA, PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, ], { title: versionInfo.title, message: "This app needs these permissions so that you can " + "find, access and photograph geo located items.", }, (results) => { if ( results[PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION] === PermissionsAndroid.RESULTS.GRANTED ) { this.setState({ haveLocationPermission: true }) navigator.geolocation.getCurrentPosition(this.handlePositionChange) } if ( results[PermissionsAndroid.PERMISSIONS.CAMERA] === PermissionsAndroid.RESULTS.GRANTED ) { this.setState({ haveCameraPermission: true }) } }, () => { this.setState({ messageModal: { icon: "hand", message: "You have denied the app access to phone features it needs to function. " + "Some parts of the app are disabled.", detail: "To enable these features in future " + "please go to Settings.", }, }) } ) api .listWorkItemActivities() .then((list) => { this.setState({ sections: list.items, region: regionContainingPoints( list.items.map((item) => item.coordinate), 0.02 ) || this.state.region, }) }) .catch((err) => { console.error(err) }) } componentWillUnmount() { if (this.watchId) { navigator.geolocation.clearWatch(this.watchId) this.watchId = null } } @autobind handleMessageDismiss() { this.setState({ messageModal: null }) } @autobind handlePositionChange(positionInfo) { this.setState({ positionInfo }) } @autobind handleMarkerPress(e, sectionIndex) { if (this.sectionList) { this.sectionList.scrollToLocation({ sectionIndex, itemIndex: 0, viewOffset: 45, }) } if (this.state.positionInfo) { const coords = this.state.positionInfo.coords const workItem = this.state.sections[sectionIndex] const { latitude, longitude } = workItem.coordinate this.setState({ workItemDistance: geoDistance( coords.latitude, coords.longitude, latitude, longitude, "K" ).toFixed(2), }) } } @autobind handleWorkItemsListPress() { const { positionInfo } = this.state if (positionInfo) { const { coords } = positionInfo this.props.history.push( `/workItemList?latLng=${coords.latitude},${coords.longitude}` ) } else { this.props.history.push("/workItemList") } } @autobind handleItemSelect(activity) { this.props.history.push(`/activity?id=${activity._id}`) } @autobind handleSectionSelect(workItem) { const { latitude, longitude } = workItem.coordinate const region = { latitude, longitude, latitudeDelta: 0.01, longitudeDelta: 0.01, } this.setState({ region }) } @autobind handleLogoutPress() { this.props.history.replace("/logout") } @autobind handleGlassesPress() { const { sections: workItems } = this.state const { latitude: latitude1, longitude: longitude1, } = this.state.positionInfo.coords let closestWorkItem = config.alwaysShowWorkItemInAR ? workItems[0] : null let shortestDistance = config.minDistanceToItem workItems.forEach((workItem) => { const { latitude: latitude2, longitude: longitude2 } = workItem.coordinate const distance = geoDistance(latitude1, longitude1, latitude2, longitude2, "K") * 1000 if (distance <= shortestDistance) { closestWorkItem = workItem shortestDistance = distance } }) this.props.history.push( `/arviewer${ closestWorkItem ? "?workItemId=" + closestWorkItem._id + "&workItemType=" + closestWorkItem.workItemType : "" }` ) } @autobind handleMyLocationPress() { 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, showWorkItems, region, positionInfo, messageModal, haveCameraPermission, haveLocationPermission, workItemDistance, } = this.state if (!this.watchId && haveLocationPermission) { this.watchId = navigator.geolocation.watchPosition( this.handlePositionChange, null, { distanceFilter: 10 } ) } return (
{ this.map = ref }} style={[ { width: "100%", }, showWorkItems && { height: "40%" }, !showWorkItems && { flexGrow: 1 }, ]} showsUserLocation showsBuildings={false} showsTraffic={false} showsIndoors={false} zoomControlEnabled={false} showsMyLocationButton={false} region={region}> {sections.map((workItem, index) => ( this.handleMarkerPress(e, index)}> {pad(workItem.ticketNumber, 4) + ": " + workItemTypeText[workItem.workItemType] + " (" + (workItemDistance > 0 ? workItemDistance.toString() : "?") + " km)"} {dotify(workItem.address)} ))} {/* // TODO: Search feature */} (this.sectionList = ref)} style={{ width: "100%", flexGrow: 1 }} sections={sections} stickySectionHeadersEnabled={true} renderSectionHeader={({ section: workItem }) => ( this.handleSectionSelect(workItem)}> {workItemTypeText[workItem.workItemType].toUpperCase()}{" "} {pad(workItem.ticketNumber, 4)} )} keyExtractor={(item) => item._id} renderItem={({ item: activity, section }) => { return ( this.handleItemSelect(activity)}> {activity.status.toUpperCase()} {activity.resolution} {activity.when} ) }} /> {showWorkItems ? "Hide List" : "Show List"} {Platform.OS === "ios" && } ) } }