diff --git a/expo_project/components/MapWithMarkers.js b/expo_project/components/MapWithMarkers.js
index 736b20a..485e87d 100644
--- a/expo_project/components/MapWithMarkers.js
+++ b/expo_project/components/MapWithMarkers.js
@@ -1,44 +1,46 @@
+import { MapView } from "expo";
import PropTypes from "prop-types";
import React from "react";
-import { Platform, StyleSheet } from "react-native";
-import { MapView } from "expo";
-import PersonIcon from "./PersonIcon";
-// import { Location, Permissions } from "expo";
-
+import { Platform, StyleSheet, TouchableOpacity } from "react-native";
+import { AnimatedCircularProgress } from "react-native-circular-progress";
+import { iconColors } from "../constants/Colors";
import MapConfig from "../constants/Map";
+import PersonIcon from "../components/PersonIcon";
+
+// NOTE: A longPress is more like 500ms,
+// however there's a delay between when the longPress is registered
+// and when a new marker is created in firestore and thereafter rendered
+// Currently setting halo animation to 1000 to account for that
+// but that might confuse users who release early (e.g. at 600ms) which still ends up creating a marker
+const CIRCULAR_PROGRESS_ANIMATION_DURATION = 1000;
+const CIRCULAR_PROGRESS_SIZE = 100;
class MapWithMarkers extends React.Component {
constructor(props) {
super(props);
- this.state = { region: MapConfig.defaultRegion };
+ this.state = {
+ region: MapConfig.defaultRegion,
+ circularProgressLocation: null,
+ nextMarkerColor: this.getRandomIconColor()
+ };
}
- // componentDidMount() {
- // this._getLocationAsync();
- // }
+ getRandomIconColor = () => {
+ const iconOptions = Object.values(iconColors);
+ return iconOptions[Math.floor(Math.random() * iconOptions.length)];
+ };
- // _getLocationAsync = async () => {
- // let region = MapConfig.defaultRegion;
- // // react native maps (the belly of expo's MapView ) requests location permissions for us
- // // so here we are only retrieving permission, not asking for it
- // const { status } = await Permissions.askAsync(Permissions.LOCATION);
- // if (status === "granted") {
- // const location = await Location.getCurrentPositionAsync({
- // enableHighAccuracy: true
- // });
- // const { latitude, longitude } = location.coords;
- // region = {
- // latitude,
- // longitude,
- // latitudeDelta: 0.0043,
- // longitudeDelta: 0.0034
- // };
- // }
- // this.setState({ region });
- // };
+ setNextColor = () => {
+ this.setState({ nextMarkerColor: this.getRandomIconColor() });
+ };
render() {
+ /*
+ Note: we're taking advantage of the fact that AnimatedCircularProgress animates on mount
+ by mounting on pressIn and unmounting on pressOut.
+ Unmounting so often might give us a noticeable performance hit, so if that happens, we can instead manage fill in state.
+ */
const {
markers,
activeMarkerId,
@@ -48,50 +50,95 @@ class MapWithMarkers extends React.Component {
onMapLongPress
} = this.props;
return this.state.region ? (
- onMapPress()}
- onLongPress={e => onMapLongPress(e.nativeEvent.coordinate)}
- initialRegion={this.state.region}
- showsUserLocation
- scrollEnabled
- zoomEnabled
- pitchEnabled={false}
+ {
+ const { nativeEvent } = e;
+ this.setState({
+ circularProgressLocation: {
+ top: nativeEvent.locationY - CIRCULAR_PROGRESS_SIZE / 2,
+ left: nativeEvent.locationX - CIRCULAR_PROGRESS_SIZE / 2
+ }
+ });
+ }}
+ onPressOut={e => {
+ this.setState({
+ circularProgressLocation: null,
+ nextMarkerColor: this.getRandomIconColor()
+ });
+ }}
+ style={styles.container}
>
-
- {markers.map(marker => {
- const selected = marker.id === activeMarkerId;
- const key = marker.id + (selected ? "-selected" : ""); //trigger a re render when switching states, so it recenters itself
- return (
- onMarkerPress(marker.id)}
- anchor={{ x: 0, y: 0 }}
- calloutAnchor={{ x: 0, y: 0 }}
- >
-
-
- );
- })}
-
+ onMapPress()}
+ onLongPress={e =>
+ onMapLongPress(e.nativeEvent.coordinate, this.state.nextMarkerColor)
+ }
+ initialRegion={this.state.region}
+ showsUserLocation
+ scrollEnabled
+ zoomEnabled
+ pitchEnabled={false}
+ >
+
+ {markers.map(marker => {
+ const selected = marker.id === activeMarkerId;
+ const key = marker.id + (selected ? "-selected" : ""); //trigger a re render when switching states, so it recenters itself
+ return (
+
+ onMarkerDragEnd(e.nativeEvent.id, e.nativeEvent.coordinate)
+ }
+ onPress={() => onMarkerPress(marker.id)}
+ anchor={{ x: 0.5, y: 0.5 }}
+ >
+
+
+ );
+ })}
+
+ {this.state.circularProgressLocation && (
+ (this.circularProgress = ref)}
+ style={[
+ styles.circularProgress,
+ {
+ top: this.state.circularProgressLocation.top,
+ left: this.state.circularProgressLocation.left
+ }
+ ]}
+ size={CIRCULAR_PROGRESS_SIZE}
+ width={3}
+ tintColor={this.state.nextMarkerColor}
+ backgroundColor="transparent"
+ duration={CIRCULAR_PROGRESS_ANIMATION_DURATION}
+ fill={100}
+ />
+ )}
+
) : null;
}
}
const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ position: "relative"
+ },
mapStyle: {
...Platform.select({
ios: {
@@ -105,6 +152,11 @@ const styles = StyleSheet.create({
right: 0
}
})
+ },
+ circularProgress: {
+ alignSelf: "center",
+ position: "absolute",
+ backgroundColor: "transparent"
}
});
diff --git a/expo_project/package.json b/expo_project/package.json
index b6b03cd..9207b98 100644
--- a/expo_project/package.json
+++ b/expo_project/package.json
@@ -16,6 +16,8 @@
"prop-types": "^15.6.2",
"react": "16.3.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-28.0.0.tar.gz",
+ "react-native-circular-progress": "^1.0.1",
+ "react-native-svg": "^6.5.2",
"react-navigation": "2.3.1"
},
"devDependencies": {
diff --git a/expo_project/screens/HomeScreen.js b/expo_project/screens/HomeScreen.js
index 3f9a452..77e7a2a 100644
--- a/expo_project/screens/HomeScreen.js
+++ b/expo_project/screens/HomeScreen.js
@@ -1,23 +1,21 @@
import React from "react";
import {
+ Animated,
PanResponder,
Platform,
StyleSheet,
+ ScrollView,
View,
- Animated,
TouchableOpacity
} from "react-native";
import { withNavigation } from "react-navigation";
import * as _ from "lodash";
-import { iconColors } from "../constants/Colors";
-import { ScrollView } from "../node_modules/react-native-gesture-handler";
import moment from "moment";
-import Layout from "../constants/Layout";
-
import MapWithMarkers from "../components/MapWithMarkers";
import MarkerCarousel from "../components/MarkerCarousel";
import Survey from "../components/Survey";
import ColoredButton from "../components/ColoredButton";
+import Layout from "../constants/Layout";
// TODO (Ananta): shouold be dynamically set
const INITIAL_DRAWER_TRANSLATE_Y = Layout.drawer.height;
@@ -77,7 +75,6 @@ class HomeScreen extends React.Component {
this.resetDrawer = this.resetDrawer.bind(this);
this.toggleDrawer = this.toggleDrawer.bind(this);
this.selectMarker = this.selectMarker.bind(this);
- this.getRandomIconColor = this.getRandomIconColor.bind(this);
this.createNewMarker = this.createNewMarker.bind(this);
this.setMarkerLocation = this.setMarkerLocation.bind(this);
this.setFormResponse = this.setFormResponse.bind(this);
@@ -235,7 +232,7 @@ class HomeScreen extends React.Component {
}
}
- createNewMarker(coordinate) {
+ createNewMarker(coordinate, color) {
const markersCopy = [...this.state.markers];
const date = moment();
const dateLabel = date.format("HH:mm");
@@ -243,11 +240,13 @@ class HomeScreen extends React.Component {
const marker = {
coordinate: coordinate,
- color: this.getRandomIconColor(),
+ color,
title,
dateLabel
};
+ // TODO (Seabass or Ananta): Figure out a way to get faster UI feedback
+ // Would be nice for UI to optimistically render before firestore returns
this.firestore
.collection("study")
.doc(studyId)
@@ -267,9 +266,8 @@ class HomeScreen extends React.Component {
});
}
- setMarkerLocation(e) {
+ setMarkerLocation(id, coordinate) {
// TODO: add logic for updating in db
- const { id, coordinate } = e.nativeEvent;
const markersCopy = [...this.state.markers];
const marker = _.find(markersCopy, { id });
@@ -290,11 +288,6 @@ class HomeScreen extends React.Component {
}
}
- getRandomIconColor() {
- const iconOptions = Object.values(iconColors);
- return iconOptions[Math.floor(Math.random() * iconOptions.length)];
- }
-
render() {
const { activeMarkerId, markers } = this.state;
const activeMarker = _.find(markers, { id: activeMarkerId });
diff --git a/expo_project/yarn.lock b/expo_project/yarn.lock
index a3bd7cc..3d3aa70 100644
--- a/expo_project/yarn.lock
+++ b/expo_project/yarn.lock
@@ -5512,6 +5512,12 @@ react-native-branch@2.2.5:
version "2.2.5"
resolved "https://registry.yarnpkg.com/react-native-branch/-/react-native-branch-2.2.5.tgz#4074dd63b4973e6397d9ce50e97b57c77a518e9d"
+react-native-circular-progress@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/react-native-circular-progress/-/react-native-circular-progress-1.0.1.tgz#94a0e9b1f2ec28ce0fa56665ef29dfba99d1d2d6"
+ dependencies:
+ prop-types "^15.6.0"
+
react-native-dismiss-keyboard@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/react-native-dismiss-keyboard/-/react-native-dismiss-keyboard-1.0.0.tgz#32886242b3f2317e121f3aeb9b0a585e2b879b49"
@@ -5577,6 +5583,14 @@ react-native-svg@6.2.2:
lodash "^4.16.6"
pegjs "^0.10.0"
+react-native-svg@^6.5.2:
+ version "6.5.2"
+ resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-6.5.2.tgz#1105896b8873b0856821b18daa0c6898cea6c00c"
+ dependencies:
+ color "^2.0.1"
+ lodash "^4.16.6"
+ pegjs "^0.10.0"
+
react-native-tab-view@^0.0.77:
version "0.0.77"
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-0.0.77.tgz#11ceb8e7c23100d07e628dc151b57797524d00d4"