diff --git a/BalancedBite/android/.project b/BalancedBite/android/.project new file mode 100644 index 0000000..b23c840 --- /dev/null +++ b/BalancedBite/android/.project @@ -0,0 +1,17 @@ + + + BalancedBite + Project android created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/BalancedBite/android/.settings/org.eclipse.buildship.core.prefs b/BalancedBite/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..e889521 --- /dev/null +++ b/BalancedBite/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir= +eclipse.preferences.version=1 diff --git a/BalancedBite/android/app/.classpath b/BalancedBite/android/app/.classpath new file mode 100644 index 0000000..eb19361 --- /dev/null +++ b/BalancedBite/android/app/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/BalancedBite/android/app/.project b/BalancedBite/android/app/.project new file mode 100644 index 0000000..ac485d7 --- /dev/null +++ b/BalancedBite/android/app/.project @@ -0,0 +1,23 @@ + + + app + Project app created by Buildship. + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/BalancedBite/android/app/.settings/org.eclipse.buildship.core.prefs b/BalancedBite/android/app/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..b1886ad --- /dev/null +++ b/BalancedBite/android/app/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir=.. +eclipse.preferences.version=1 diff --git a/new-gui/.expo/packager-info.json b/new-gui/.expo/packager-info.json index ba74420..e63e1f9 100755 --- a/new-gui/.expo/packager-info.json +++ b/new-gui/.expo/packager-info.json @@ -1,10 +1,10 @@ { - "expoServerNgrokUrl": "https://rp-cnx.anonymous.new-gui.exp.direct", - "packagerNgrokUrl": "https://packager.rp-cnx.anonymous.new-gui.exp.direct", - "ngrokPid": 19628, - "packagerPort": 19001, - "packagerPid": 8452, + "expoServerNgrokUrl": null, + "packagerNgrokUrl": null, + "ngrokPid": null, + "packagerPort": null, + "packagerPid": null, "devToolsPort": 19002, - "expoServerPort": 19000, + "expoServerPort": null, "webpackServerPort": null } \ No newline at end of file diff --git a/new-gui/.expo/settings.json b/new-gui/.expo/settings.json index ad63e25..de4f26b 100755 --- a/new-gui/.expo/settings.json +++ b/new-gui/.expo/settings.json @@ -3,5 +3,5 @@ "lanType": "ip", "dev": true, "minify": false, - "urlRandomness": "rp-cnx" + "urlRandomness": "c8-ats" } \ No newline at end of file diff --git a/new-gui/src/commons/serverRequest/index.js b/new-gui/src/commons/serverRequest/index.js index 6febc7d..c1e2222 100755 --- a/new-gui/src/commons/serverRequest/index.js +++ b/new-gui/src/commons/serverRequest/index.js @@ -1,2 +1,3 @@ -const HOST = "52.39.77.219"; +//const HOST = "52.39.77.219"; +const HOST = "174.77.40.238"; export const SERVER_URL = "http://" + HOST + ":8080"; \ No newline at end of file diff --git a/new-gui/src/components/UserInformationPanel/index.js b/new-gui/src/components/UserInformationPanel/index.js index 47e2313..52d28a7 100755 --- a/new-gui/src/components/UserInformationPanel/index.js +++ b/new-gui/src/components/UserInformationPanel/index.js @@ -1,11 +1,12 @@ import { mapDispatchToProps, mapStateToProps } from "../../commons/redux"; import React, { Component } from "react"; -import { Platform,StatusBar,View,SafeAreaView, Text, Button, SectionList, StyleSheet, TouchableHighlight,Image,TextInput,Dimensions,ImageBackground } from "react-native"; +import { Platform,StatusBar,View,SafeAreaView, Text,Alert, Button, SectionList, StyleSheet, TouchableHighlight,Image,TextInput,Dimensions,ImageBackground } from "react-native"; import { connect } from "react-redux"; import { withNavigation } from "react-navigation"; import { Ionicons } from '@expo/vector-icons'; import { SERVER_URL } from "../../commons/serverRequest"; - +import Expo from "expo"; +import { Pedometer } from "expo"; import Svg from 'react-native-svg'; import { CheckBox,Input } from "react-native-elements"; @@ -22,33 +23,55 @@ class EditableLabel extends Component{ renderInput() { - if(typeof this.state.myText === "string" || typeof this.state.myText === "number") + if(this.props.type === "number" || this.props.type === "string") { return ( this._input = component} textAlign="right" + keyboardType={this.props.type==="number"?"numeric":"default"} style={styles.infoText} onChangeText={(text) =>{this.setState({myText:text})}} editable = {this.state.editable} multiline = {false} - onEndEditing={()=>{this.setState({editable:false}); this.props.receiver(this.props.fieldName,this.state.myText);}} - value={this.state.myText.toString()} + onEndEditing={()=>{ + this.setState({editable:false}); + if(this.props.checker==null || this.props.checker(this.state.myText)) + this.props.receiver(this.props.fieldName,this.props.type==="number"?parseInt(this.state.myText):this.state.myText); + else{ + this.state.myText=this.props.value; + Alert.alert("Error", this.props.errorMessage, [{ + text: "Okay" + }]); + } + }} + value={this.state.myText} />); } - else if(typeof this.state.myText === "boolean") + else if(this.props.type === "boolean") { return ( this._input = component} right={true} iconRight - onPress={() => this.setState({myText: !this.state.myText,editable:false})} + onPress={()=>{ + const val=!this.state.myText; + this.setState({editable:false,myText:!this.state.myText}); + if(this.props.checker==null || this.props.checker(val)) + this.props.receiver(this.props.fieldName,val); + else{ + this.state.myText=this.props.value; + Alert.alert("Error", this.props.errorMessage, [{ + text: "Okay" + }]); + } + }} checked={this.state.myText} disabled={!this.state.editable} /> ); } - else if(Array.isArray(this.state.myText)) + else if(this.props.type === "list") { return( this._input = component} @@ -57,7 +80,17 @@ class EditableLabel extends Component{ onChangeText={(text) =>{this.setState({myText:text})}} editable = {this.state.editable} multiline = {false} - onEndEditing={()=>{this.setState({editable:false}); console.warn(this.state.myText);this.props.receiver(this.props.fieldName,this.state.myText.split(",").filter(element => element.trim().length > 0));}} + onEndEditing={()=>{ + this.setState({editable:false}); + if(this.props.checker==null || this.props.checker(this.state.myText)) + this.props.receiver(this.props.fieldName,this.state.myText.split(",").filter(element => element.trim().length > 0)); + else{ + this.state.myText=this.props.value; + Alert.alert("Error", this.props.errorMessage, [{ + text: "Okay" + }]); + } + }} value={this.state.myText} />); } @@ -85,26 +118,29 @@ class EditableLabel extends Component{ class UserInformationComponent extends Component { - - updateInformation(fieldName,fieldValue){ - fetch(UPDATE_URL, { - method : "POST", - body: JSON.stringify({token: this.props.currentToken, fieldName: fieldValue}), - headers : { - "Content-Type": "application/json" - } - }) - .then(res => res.json()) - .then(res => { - console.warn(res); - this.setState({userInfo:res},()=>{this.forceUpdate();}); - }) + + fetchStepCountThenGetInformation(){ + const now = new Date(); + const todayMidnight = new Date(); + todayMidnight.setHours(0,0,0,0); + Pedometer.getStepCountAsync(todayMidnight,now).then( + result => { + this.setState({ pastStepCount: result.steps }); + this.getInformation(result.steps); + }, + error => { + this.setState({ pastStepCount: "N/A"}); + this.getInformation(0); + } + ); } - componentDidMount(){ + + + getInformation(stepCount){ fetch(FETCH_URL, { method: "POST", - body: JSON.stringify({token: this.props.currentToken, distanceTraveled: 0.42, stepCount: 1055}), + body: JSON.stringify({token: this.props.currentToken, stepCount: stepCount}), headers : { "Content-Type" : "application/json" } @@ -123,17 +159,45 @@ class UserInformationComponent extends Component { ) } + updateInformation(fieldName,fieldValue){ + fetch(UPDATE_URL, { + method : "POST", + body: JSON.stringify({token: this.props.currentToken,fieldName:fieldName,fieldValue:fieldValue}), + headers : { + "Content-Type": "application/json" + } + }) + .then(res => res.json()) + .then(res => { + if(res.code==0){ + console.warn("Fail to update"); + }else{ + this.fetchStepCountThenGetInformation(); + } + }) + } + + componentWillMount(){ + Pedometer.isAvailableAsync(); + this.fetchStepCountThenGetInformation(); + } + + isNormalInteger(str) { + return /^\+?(0|[1-9]\d*)$/.test(str); + } + + render() { - if(this.state) + if(this.state && this.state.userInfo) return ( @@ -144,27 +208,46 @@ class UserInformationComponent extends Component { stickySectionHeadersEnabled={true} renderItem={({item, index, section}) => { if(section.title==="Health Infomation") - return ({item[0]+": "}{item[1]+" "+item[2]}); + return ( + + {item[0]+": "} + {item[1]+" "+item[2]} + + + ); else - return (this.updateInformation(k,v)}>); + return ( + this.updateInformation(k,v)}> + + + ); }} renderSectionHeader={({section: {title}}) => ( {title} )} sections={[ - {title: 'Health Infomation', data: [["BMI",this.state.userInfo.bmi.toFixed(2),""], - ["Calories Needed",4200,"Cal"], - ["Step Count",999,""], - ["Distance Traveled",1253,"m"]]}, - {title: 'User Infomation', data: [['Age',this.state.userInfo.age,'','age'], - ['Weight',this.state.userInfo.weight,'kg','weight'], - ['Height',this.state.userInfo.height,'cm','height'], - ['HealthProblems',this.state.userInfo.healthProblems.join(),"","healthProblems"], - ['DislikeFoods',this.state.userInfo.dislikeFoods.join(),"","dislikeFoods"], - ['Allergies',this.state.userInfo.allergies.join(),"","alleriges"], - ['Workout',this.state.userInfo.workoutBoolean,"","workoutBoolean"], - ['WorkoutFrequency',this.state.userInfo.workoutFrequency,"","workoutFrequency"], - ['WorkoutType',this.state.userInfo.workoutType,"","workoutType"]]}, + {title: 'Health Infomation', data: [["BMI",this.state.userInfo.bmi?this.state.userInfo.bmi.toFixed(2):0,""], + ["Calories Needed",this.state.userInfo.caloriesNeeded,"Cal(s)"], + ["Calories Taken",this.state.userInfo.caloriesTakenCurrently,"Cal(s)"], + ["Foods Eaten",this.state.userInfo.foodsEatenCurrently.join(),""], + ["Step Count",this.state.pastStepCount,""]]}, + {title: 'User Infomation', data: [['Age',this.state.userInfo.age.toString(),'','age',(x)=>this.isNormalInteger(x) && parseInt(x)<150,"Age is not valid(1-150)!","number"], + ['Weight',this.state.userInfo.weight.toString(),'kg','weight',(x)=>this.isNormalInteger(x) && parseInt(x)<1000,"Weight is not valid(1-1000)!","number"], + ['Height',this.state.userInfo.height.toString(),'cm','height',(x)=>this.isNormalInteger(x) && parseInt(x)<1000,"Height is not valid(1-1000)!","number"], + ['HealthProblems',this.state.userInfo.healthProblems.join(),"","healthProblems",null,null,"list"], + ['DislikeFoods',this.state.userInfo.dislikeFoods.join(),"","dislikeFoods",null,null,"list"], + ['Allergies',this.state.userInfo.allergies.join(),"","alleriges",null,null,"list"], + ['Workout',this.state.userInfo.workoutBoolean,"","workoutBoolean",null,null,"boolean"], + ['WorkoutFrequency',this.state.userInfo.workoutFrequency.toString(),"","workoutFrequency",(x)=>this.isNormalInteger(x) && parseInt(x)<=7,"Workout Frequency should be an integer between 0 and 7!","number"], + ['WorkoutType',this.state.userInfo.workoutType,"","workoutType",null,null,"string"]]}, ]} keyExtractor={(item, index) => item + index} /> diff --git a/new-gui/src/components/UserSignupPanel/index.js b/new-gui/src/components/UserSignupPanel/index.js index 6efd018..b2c6ad0 100755 --- a/new-gui/src/components/UserSignupPanel/index.js +++ b/new-gui/src/components/UserSignupPanel/index.js @@ -126,7 +126,7 @@ class UserSignupPanel extends Component { } ); } else { - Alert.alert("Error", "User was not added successfully", [{ + Alert.alert("Error", "User already exists", [{ text: "Okay" }]) } diff --git a/new-gui/src/images/person.png b/new-gui/src/images/person.png new file mode 100644 index 0000000..1dc1a9d Binary files /dev/null and b/new-gui/src/images/person.png differ diff --git a/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/api/UserInfo.java b/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/api/UserInfo.java index 5150039..e0cb55a 100755 --- a/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/api/UserInfo.java +++ b/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/api/UserInfo.java @@ -16,7 +16,7 @@ public class UserInfo { private Integer height = null; private Integer age = null; private Integer caloriesNeeded = null; - private double BMI; + private double BMI=0.0; private String sexes = "Male"; @@ -26,7 +26,7 @@ public class UserInfo { private List dislikeFoods = new ArrayList<> (); private List healthProblems = new ArrayList<> (); private boolean workoutBoolean = false; - private Integer workoutFrequency = null; + private Integer workoutFrequency = 0; private String workoutType = "None"; @@ -183,43 +183,43 @@ public void setSexes(String sexes) { } @JsonProperty - public void getBodyFat(Integer bodyFat) { + public void setBodyFat(Integer bodyFat) { this.bodyFat = bodyFat; } @JsonProperty - public void getFoodRestriction (String foodRestriction) { + public void setFoodRestriction (String foodRestriction) { this.foodRestriction = foodRestriction; } @JsonProperty - public void getAllergies(List allergies) { + public void setAllergies(List allergies) { this.allergies = allergies; } @JsonProperty - public void getDislikeFoods(List dislikeFoods) { + public void setDislikeFoods(List dislikeFoods) { this.dislikeFoods = dislikeFoods; } @JsonProperty - public void getHealthProblems(List healthProblems) { + public void setHealthProblems(List healthProblems) { this.healthProblems = healthProblems; } @JsonProperty - public void getWorkoutBoolean(boolean workoutBoolean) { + public void setWorkoutBoolean(boolean workoutBoolean) { this.workoutBoolean = workoutBoolean; } @JsonProperty - public void getWorkoutFrequency(Integer workoutFrequency) { + public void setWorkoutFrequency(Integer workoutFrequency) { this.workoutFrequency = workoutFrequency; } @JsonProperty - public void getWorkoutType(String workoutType) { + public void setWorkoutType(String workoutType) { this.workoutType = workoutType; } diff --git a/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/api/UserInformationRequest.java b/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/api/UserInformationRequest.java index 93d6cee..f6661ec 100755 --- a/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/api/UserInformationRequest.java +++ b/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/api/UserInformationRequest.java @@ -5,7 +5,6 @@ public class UserInformationRequest { private String token; private Integer stepCount; - private Integer distanceTraveled; @JsonProperty public String getToken() { @@ -17,11 +16,6 @@ public Integer getStepCount() { return stepCount; } - @JsonProperty - public Integer getDistanceTraveled() { - return distanceTraveled; - } - // deserialize @JsonProperty @@ -34,9 +28,4 @@ public void setStepCount(Integer stepCount) { this.stepCount = stepCount; } - @JsonProperty - public void setDistanceTraveled(Integer distanceTraveled) { - this.distanceTraveled = distanceTraveled; - } - } diff --git a/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/resources/CheckSessionResource.java b/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/resources/CheckSessionResource.java index 06a86c8..343a40e 100755 --- a/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/resources/CheckSessionResource.java +++ b/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/resources/CheckSessionResource.java @@ -97,10 +97,7 @@ public JsonNode checkSessionTokenExist(String tokenInformation) throws JsonParse // update token time to current time tokenCollection.updateOne(Filters.eq("token", currToken), Updates.set("time", dateFormat.format(currentTime))); - response.put("code", 1); - - client.close(); return response; } diff --git a/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/resources/SignUpResource.java b/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/resources/SignUpResource.java index dab9a6c..1dfb5ab 100755 --- a/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/resources/SignUpResource.java +++ b/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/resources/SignUpResource.java @@ -135,7 +135,7 @@ public JsonNode signUpNewUser(String newUserMetaData) throws JsonParseException, MongoCollection collection = MongoDBRequest.getInstance().getUserInfoCollection(database); // check if the user exists in the database - UserInfo currUserInfo = collection.find(and(eq("username", username), eq("password", password))).first(); + UserInfo currUserInfo = collection.find(eq("username", username)).first(); // generate response ObjectNode response = new ObjectMapper().createObjectNode(); @@ -148,7 +148,6 @@ public JsonNode signUpNewUser(String newUserMetaData) throws JsonParseException, UserToken newToken = new UserToken(randomID, username, currentTime); MongoCollection tokenCollection = MongoDBRequest.getInstance().getUserTokenCollection(database); tokenCollection.insertOne(newToken); - response.put("code", 1); response.put("token", randomID); } else { diff --git a/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/resources/UserDataResource.java b/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/resources/UserDataResource.java index 3648a27..20aea65 100755 --- a/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/resources/UserDataResource.java +++ b/web/balancedbite/src/main/java/edu/uci/ics/balancedbite/web/resources/UserDataResource.java @@ -3,7 +3,10 @@ import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Calendar; +import java.util.Map; +import java.lang.reflect.Field; +import javax.lang.model.util.ElementScanner6; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -47,17 +50,17 @@ public UserDataResource(String host, int port) { * https://www.livestrong.com/article/238020-how-to-convert-pedometer-steps-to-calories/ * * @param weight weights in kg - * @param distanceWalked distance in miles * @param stepCount step count currently * @return calories burned currently */ - public static int calculateCaloriesBurned(int weight, int distanceWalked, int stepCount) { - if (distanceWalked == 0 || stepCount == 0) { + public static int calculateCaloriesBurned(int weight, int stepCount) { + if (stepCount == 0) { return 0; } double weightInlbs = weight * 2.20462; double caloriesPerMile = 0.57 * weightInlbs; - double stepsPerMile = (1 / distanceWalked) * stepCount; + // double stepsPerMile = (1 / distanceWalked) * stepCount; : cannot get expo distance travel, bad API + double stepsPerMile = 2300.0; // default double caloriesPerStep = caloriesPerMile / stepsPerMile; return (int)(caloriesPerStep * stepCount); } @@ -76,7 +79,6 @@ public JsonNode fetchUserInformation(String userRequest) throws JsonParseExcepti UserInformationRequest currentRequest = new ObjectMapper().readValue(userRequest, UserInformationRequest.class); String token = currentRequest.getToken(); -// System.out.println("token = " + token); System.out.println(new ObjectMapper().writeValueAsString(currentRequest)); MongoClient client = MongoDBRequest.getInstance().connectToMongoDB(host, port); MongoDatabase database = MongoDBRequest.getInstance().getMongoDatabase(client); @@ -102,9 +104,9 @@ public JsonNode fetchUserInformation(String userRequest) throws JsonParseExcepti client.close(); return response; } - + int caloriesBurnedCurrenlty = calculateCaloriesBurned(currentUserInfo.getWeight(), - currentRequest.getStepCount(), currentRequest.getDistanceTraveled()); + currentRequest.getStepCount()); currentUserInfo.setCaloriesNeeded(currentUserInfo.getCaloriesNeeded() + caloriesBurnedCurrenlty); ObjectNode userObject = new ObjectMapper().valueToTree(currentUserInfo); @@ -118,10 +120,45 @@ public JsonNode fetchUserInformation(String userRequest) throws JsonParseExcepti @POST @Path("/update-user") @Consumes(MediaType.APPLICATION_JSON) - public JsonNode updateUserInformation(String token) throws JsonParseException, JsonMappingException, IOException { - System.out.println("token = " + token); + public JsonNode updateUserInformation(String token) throws JsonParseException, JsonMappingException, IOException, NoSuchFieldException,IllegalAccessException { + //System.out.println("token = " + token); + Map map = new ObjectMapper().readValue(token, Map.class); + MongoClient client = MongoDBRequest.getInstance().connectToMongoDB(host, port); + MongoDatabase database = MongoDBRequest.getInstance().getMongoDatabase(client); + MongoCollection tokenCollection = MongoDBRequest.getInstance().getUserTokenCollection(database); + MongoCollection userCollection = MongoDBRequest.getInstance().getUserInfoCollection(database); + + UserToken userToken = tokenCollection.find(eq("token", map.get("token").toString())).first(); + ObjectNode response = new ObjectMapper().createObjectNode(); + if (userToken == null) { + response.put("code", 0); + client.close(); + return response; + } + String currentUser = userToken.getUsername(); + UserInfo currentUserInfo = userCollection.find(eq("username", currentUser)).first(); + if (currentUserInfo == null) { + response.put("code", 0); + client.close(); + return response; + } + String field=map.get("fieldName").toString(); + Object value=map.get("fieldValue"); + if(field=="age") + currentUserInfo.setAge((Integer)value); + else if(field=="weight") + currentUserInfo.setWeight((Integer)value); + else if(field=="height") + currentUserInfo.setHeight((Integer)value); + else if(field=="workoutFrequency") + currentUserInfo.setWorkoutFrequency((Integer)value); + double userBMI = SignUpResource.calculateBMI(currentUserInfo.getWeight(), currentUserInfo.getHeight()); + int userCaloricIntake = SignUpResource.calculateCalories(currentUserInfo.getSexes(), currentUserInfo.getWeight(), currentUserInfo.getHeight(), + currentUserInfo.getAge(), currentUserInfo.getWorkoutFrequency()); + userCollection.updateOne(Filters.eq("username", currentUser),Updates.combine(Updates.set(field,value),Updates.set("bMI",userBMI),Updates.set("caloriesNeeded",userCaloricIntake))); - return null; + response.put("code", 1); + return response; } }