Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Safe paths branch into develop #328

Merged
merged 7 commits into from
Apr 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions __mocks__/react-native-i18n.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
export function getLanguages() {
return new Promise((resolve, reject) => {
process.nextTick(() =>
resolve(['en-US'])
);
})
};
process.nextTick(() => resolve(['en-US']));
});
}
8 changes: 7 additions & 1 deletion app/Entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import NewsScreen from './views/News';
import ExportScreen from './views/Export';
import ImportScreen from './views/Import';
import OverlapScreen from './views/Overlap';
import SettingsScreen from './views/Settings';
import LicencesScreen from './views/Licenses';
import NotificationScreen from './views/Notification';
import Slider from './views/welcomeScreens/Slider';
import { GetStoreData } from './helpers/General';
import { GetStoreData, SetStoreData } from './helpers/General';

const Stack = createStackNavigator();

Expand Down Expand Up @@ -83,6 +84,11 @@ class Entry extends Component {
component={ImportScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name='SettingsScreen'
component={SettingsScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name='LicensesScreen'
component={LicencesScreen}
Expand Down
Binary file added app/assets/images/closeIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/assets/images/kebabIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/images/saveIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
149 changes: 149 additions & 0 deletions app/helpers/Intersect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/**
* Intersect a set of points against the user's locally stored points.
*
* v1 - Unencrypted, simpleminded (minimal optimization).
*/

import { GetStoreData, SetStoreData } from '../helpers/General';

export async function IntersectSet(concernLocationArray) {
GetStoreData('LOCATION_DATA').then(locationArrayString => {
var locationArray;
if (locationArrayString !== null) {
locationArray = JSON.parse(locationArrayString);
} else {
locationArray = [];
}

let dayBin = [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
]; // Bins for 28 days

// Sort the concernLocationArray
let localArray = normalizeData(locationArray);
let concernArray = normalizeData(concernLocationArray);

let concernTimeWindow = 1000 * 60 * 60 * 2; // +/- 2 hours window
let concernDistWindow = 60; // distance of concern, in feet

// At 38 degrees North latitude:
let ftPerLat = 364000; // 1 deg lat equals 364,000 ft
let ftPerLon = 288200; // 1 deg of longitude equals 288,200 ft

var nowUTC = new Date().toISOString();
var timeNow = Date.parse(nowUTC);

// Save a little CPU, no need to do sqrt()
let concernDistWindowSq = concernDistWindow * concernDistWindow;

// Both locationArray and concernLocationArray should be in the
// format [ { "time": 123, "latitude": 12.34, "longitude": 34.56 }]

for (let loc of localArray) {
let timeMin = loc.time - concernTimeWindow;
let timeMax = loc.time + concernTimeWindow;

let i = binarySearchForTime(concernArray, timeMin);
if (i < 0) i = -(i + 1);

while (i < concernArray.length && concernArray[i].time <= timeMax) {
// Perform a simple Euclidian distance test
let deltaLat = (concernArray[i].latitude - loc.latitude) * ftPerLat;
let deltaLon = (concernArray[i].longitude - loc.longitude) * ftPerLon;
// TODO: Scale ftPer factors based on lat to reduce projection error

let distSq = deltaLat * deltaLat + deltaLon * deltaLon;
if (distSq < concernDistWindowSq) {
// Crossed path. Bin the count of encounters by days from today.
let longAgo = timeNow - loc.time;
let daysAgo = Math.round(longAgo / (1000 * 60 * 60 * 24));

dayBin[daysAgo] += 1;
}

i++;
}
}

// TODO: Show in the UI!
console.log('Crossing results: ', dayBin);
SetStoreData('CROSSED_PATHS', dayBin); // TODO: Store per authority?
});
}

function normalizeData(arr) {
// This fixes several issues that I found in different input data:
// * Values stored as strings instead of numbers
// * Extra info in the input
// * Improperly sorted data (can happen after an Import)
var result = [];

for (var i = 0; i < arr.length; i++) {
elem = arr[i];
if ('time' in elem && 'latitude' in elem && 'longitude' in elem) {
result.push({
time: Number(elem.time),
latitude: Number(elem.latitude),
longitude: Number(elem.longitude),
});
}
}

result.sort();
return result;
}

function binarySearchForTime(array, targetTime) {
// Binary search:
// array = sorted array
// target = search target
// Returns:
// value >= 0, index of found item
// value < 0, i where -(i+1) is the insertion point
var i = 0;
var n = array.length - 1;

while (i <= n) {
var k = (n + i) >> 1;
var cmp = targetTime - array[k].time;

if (cmp > 0) {
i = k + 1;
} else if (cmp < 0) {
n = k - 1;
} else {
// Found exact match!
// NOTE: Could be one of several if array has duplicates
return k;
}
}
return -i - 1;
}
2 changes: 2 additions & 0 deletions app/locales/en/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import exportFile from './exportscreen.json';
import licensesFile from './licensesscreen.json';
import overlapFile from './overlap.json';
import notificationFile from './notification.json';
import settingsFile from './settingsScreen.json';

export default {
...intro,
Expand All @@ -14,4 +15,5 @@ export default {
...overlapFile,
...licensesFile,
...notificationFile,
...settingsFile,
};
6 changes: 3 additions & 3 deletions app/locales/en/overlap.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"overlap_title": "Check Overlap",
"overlap_para_1": "The green trail represents your location history\n\nThe light purple circles represent the public dataset",
"show_overlap": "Click to view the public dataset",
"loading_public_data": "loading data...",
"overlap_para_1": "Green circles are clusters of your locations, click to zoom. Red markers are your recorded locations.\n\nPress the button to download public information of confirmed cases, shown as faint purple circles.",
"show_overlap": "Check Public Data",
"loading_public_data": "Loading Data...",
"overlap_no_results_button_label": "Public Data Loaded",
"overlap_found_button_label": "Public Data Loaded",
"nCoV2019_url_info": "For more information on the dataset for this map",
Expand Down
16 changes: 16 additions & 0 deletions app/locales/en/settingsScreen.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"settings_title": "Settings",
"authorities_title": "Trusted Sources",
"authorities_desc": "You can get data from one or more healthcare authorities that you trust. Either select a name from the global registry, or enter the web address of an authority you trust that's implemented Safe Paths.",
"authorities_removal_alert_title": "Remove authority",
"authorities_removal_alert_desc": "Are you sure you want to remove this authority data source?",
"authorities_removal_alert_cancel": "Cancel",
"authorities_removal_alert_proceed": "Procceed",
"authorities_no_sources": "No data sources yet! Tap below to add one.",
"authorities_add_button_label": "Add Trusted Source",
"authorities_coming_soon_title": "Coming soon",
"authorities_coming_soon_desc": "You'll be able to add custom data sources in an imminent update.",
"authorities_done": "Done",
"authorities_add_url": "Add authority via URL",
"authorities_input_placeholder": "Paste your URL here"
}
2 changes: 1 addition & 1 deletion app/locales/fr/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ export default {
...overlapFile,
...licensesFile,
...notificationFile,
};
};
12 changes: 6 additions & 6 deletions app/locales/ht/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import licensesFile from './licensesscreen.json';
import overlapFile from './overlap.json';

export default {
...intro,
...locationTracking,
...importFile,
...exportFile,
...overlapFile,
...licensesFile,
...intro,
...locationTracking,
...importFile,
...exportFile,
...overlapFile,
...licensesFile,
};
12 changes: 6 additions & 6 deletions app/locales/it/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import licensesFile from './licensesscreen.json';
import overlapFile from './overlap.json';

export default {
...intro,
...locationTracking,
...importFile,
...exportFile,
...overlapFile,
...licensesFile,
...intro,
...locationTracking,
...importFile,
...exportFile,
...overlapFile,
...licensesFile,
};
2 changes: 1 addition & 1 deletion app/locales/languages.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ i18next.init({
gj: {
translation: {
label: gjlabels,
}
},
},
cs: {
translation: {
Expand Down
12 changes: 6 additions & 6 deletions app/locales/pt_BR/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import licensesFile from './licensesscreen.json';
import overlapFile from './overlap.json';

export default {
...intro,
...locationTracking,
...importFile,
...exportFile,
...overlapFile,
...licensesFile,
...intro,
...locationTracking,
...importFile,
...exportFile,
...overlapFile,
...licensesFile,
};
Loading