diff --git a/package.cordovabuild.json b/package.cordovabuild.json
index b3b85fb6a..5018b3b05 100644
--- a/package.cordovabuild.json
+++ b/package.cordovabuild.json
@@ -98,8 +98,7 @@
},
"cordova-plugin-bluetooth-classic-serial-port": {},
"cordova-custom-config": {},
- "com.unarin.cordova.beacon": {},
- "cordova-plugin-statusbar": {}
+ "com.unarin.cordova.beacon": {}
}
},
"dependencies": {
@@ -137,7 +136,6 @@
"cordova-plugin-bluetooth-classic-serial-port": "git+https://github.com/e-mission/cordova-plugin-bluetooth-classic-serial-port.git",
"cordova-custom-config": "^5.1.1",
"com.unarin.cordova.beacon": "github:e-mission/cordova-plugin-ibeacon",
- "cordova-plugin-statusbar": "^4.0.0",
"core-js": "^2.5.7",
"e-mission-common": "github:JGreenlee/e-mission-common#semver:0.6.2",
"enketo-core": "^6.1.7",
diff --git a/setup/setup_native.sh b/setup/setup_native.sh
index a7c396ab2..05624a693 100644
--- a/setup/setup_native.sh
+++ b/setup/setup_native.sh
@@ -121,7 +121,7 @@ sed -i -e "s|/usr/bin/env node|/usr/bin/env node --unhandled-rejections=strict|"
npx cordova prepare$PLATFORMS
-EXPECTED_COUNT=26
+EXPECTED_COUNT=25
INSTALLED_COUNT=`npx cordova plugin list | wc -l`
echo "Found $INSTALLED_COUNT plugins, expected $EXPECTED_COUNT"
if [ $INSTALLED_COUNT -lt $EXPECTED_COUNT ];
diff --git a/www/__tests__/util.ts b/www/__tests__/datetimeUtil.test.ts
similarity index 94%
rename from www/__tests__/util.ts
rename to www/__tests__/datetimeUtil.test.ts
index 0a8678a34..6d3fab6f2 100644
--- a/www/__tests__/util.ts
+++ b/www/__tests__/datetimeUtil.test.ts
@@ -1,4 +1,4 @@
-import { formatForDisplay } from '../js/util';
+import { formatForDisplay } from '../js/datetimeUtil';
describe('util.ts', () => {
describe('formatForDisplay', () => {
diff --git a/www/index.js b/www/index.js
index 4ea9e93ac..3b7c86a0b 100644
--- a/www/index.js
+++ b/www/index.js
@@ -24,7 +24,7 @@ window.skipLocalNotificationReady = true;
deviceReady.then(() => {
logDebug('deviceReady');
// On init, use 'default' status bar (black text)
- window['StatusBar']?.styleDefault();
+ // window['StatusBar']?.styleDefault();
cordova.plugin.http.setDataSerializer('json');
const rootEl = document.getElementById('appRoot');
const reactRoot = createRoot(rootEl);
diff --git a/www/js/TimelineContext.ts b/www/js/TimelineContext.ts
index 2a94d2b0b..9b53d2a27 100644
--- a/www/js/TimelineContext.ts
+++ b/www/js/TimelineContext.ts
@@ -22,7 +22,7 @@ import { getNotDeletedCandidates, mapInputsToTimelineEntries } from './survey/in
import { EnketoUserInputEntry } from './survey/enketo/enketoHelper';
import { primarySectionForTrip } from './diary/diaryHelper';
import useAppStateChange from './useAppStateChange';
-import { isoDateRangeToTsRange, isoDateWithOffset } from './util';
+import { isoDateRangeToTsRange, isoDateWithOffset } from './datetimeUtil';
import { base_modes } from 'e-mission-common';
const TODAY_DATE = DateTime.now().toISODate();
diff --git a/www/js/components/Chart.tsx b/www/js/components/Chart.tsx
index 8d7406b6c..97844f946 100644
--- a/www/js/components/Chart.tsx
+++ b/www/js/components/Chart.tsx
@@ -4,7 +4,8 @@ import { useTheme } from 'react-native-paper';
import { ChartData, Chart as ChartJS, ScriptableContext, registerables } from 'chart.js';
import { Chart as ChartJSChart } from 'react-chartjs-2';
import Annotation, { AnnotationOptions, LabelPosition } from 'chartjs-plugin-annotation';
-import { dedupColors, getChartHeight, darkenOrLighten } from './charting';
+import { getChartHeight } from './charting';
+import { base_modes } from 'e-mission-common';
import { logDebug } from '../plugin/logger';
ChartJS.register(...registerables, Annotation);
@@ -64,7 +65,7 @@ const Chart = ({
let labelColorMap; // object mapping labels to colors
if (getColorForLabel) {
const colorEntries = chartDatasets.map((d) => [d.label, getColorForLabel(d.label)]);
- labelColorMap = dedupColors(colorEntries);
+ labelColorMap = base_modes.dedupe_colors(colorEntries, [0.4, 1.6]);
}
return {
datasets: chartDatasets.map((e, i) => ({
@@ -73,7 +74,7 @@ const Chart = ({
labelColorMap?.[e.label] ||
getColorForChartEl?.(chartRef.current, e, barCtx, 'background'),
borderColor: (barCtx) =>
- darkenOrLighten(labelColorMap?.[e.label], -0.5) ||
+ base_modes.scale_lightness(labelColorMap?.[e.label], 0.5) ||
getColorForChartEl?.(chartRef.current, e, barCtx, 'border'),
borderWidth: borderWidth || 2,
borderRadius: 3,
diff --git a/www/js/components/charting.ts b/www/js/components/charting.ts
index 657a3b8ab..91379f23b 100644
--- a/www/js/components/charting.ts
+++ b/www/js/components/charting.ts
@@ -59,44 +59,44 @@ function getBarHeight(stacks) {
return totalHeight;
}
-//fill pattern creation
-//https://stackoverflow.com/questions/28569667/fill-chart-js-bar-chart-with-diagonal-stripes-or-other-patterns
-function createDiagonalPattern(color = 'black') {
- let shape = document.createElement('canvas');
- shape.width = 10;
- shape.height = 10;
- let c = shape.getContext('2d') as CanvasRenderingContext2D;
- c.strokeStyle = color;
- c.lineWidth = 2;
- c.beginPath();
- c.moveTo(2, 0);
- c.lineTo(10, 8);
- c.stroke();
- c.beginPath();
- c.moveTo(0, 8);
- c.lineTo(2, 10);
- c.stroke();
- return c.createPattern(shape, 'repeat');
-}
+// //fill pattern creation
+// //https://stackoverflow.com/questions/28569667/fill-chart-js-bar-chart-with-diagonal-stripes-or-other-patterns
+// function createDiagonalPattern(color = 'black') {
+// let shape = document.createElement('canvas');
+// shape.width = 10;
+// shape.height = 10;
+// let c = shape.getContext('2d') as CanvasRenderingContext2D;
+// c.strokeStyle = color;
+// c.lineWidth = 2;
+// c.beginPath();
+// c.moveTo(2, 0);
+// c.lineTo(10, 8);
+// c.stroke();
+// c.beginPath();
+// c.moveTo(0, 8);
+// c.lineTo(2, 10);
+// c.stroke();
+// return c.createPattern(shape, 'repeat');
+// }
-export function getMeteredBackgroundColor(meter, currDataset, barCtx, colors, darken = 0) {
- if (!barCtx || !currDataset) return;
- let bar_height = getBarHeight(barCtx.parsed._stacks);
- logDebug(`bar height for ${barCtx.raw.y} is ${bar_height} which in chart is ${currDataset}`);
- let meteredColor;
- if (bar_height > meter.high) meteredColor = colors.danger;
- else if (bar_height > meter.middle) meteredColor = colors.warn;
- else meteredColor = colors.success;
- if (darken) {
- return color(meteredColor).darken(darken).hex();
- }
- //if "unlabeled", etc -> stripes
- if (currDataset.label == meter.uncertainty_prefix) {
- return createDiagonalPattern(meteredColor);
- }
- //if :labeled", etc -> solid
- return meteredColor;
-}
+// export function getMeteredBackgroundColor(meter, currDataset, barCtx, colors, darken = 0) {
+// if (!barCtx || !currDataset) return;
+// let bar_height = getBarHeight(barCtx.parsed._stacks);
+// logDebug(`bar height for ${barCtx.raw.y} is ${bar_height} which in chart is ${currDataset}`);
+// let meteredColor;
+// if (bar_height > meter.high) meteredColor = colors.danger;
+// else if (bar_height > meter.middle) meteredColor = colors.warn;
+// else meteredColor = colors.success;
+// if (darken) {
+// return color(meteredColor).darken(darken).hex();
+// }
+// //if "unlabeled", etc -> stripes
+// if (currDataset.label == meter.uncertainty_prefix) {
+// return createDiagonalPattern(meteredColor);
+// }
+// //if :labeled", etc -> solid
+// return meteredColor;
+// }
const meterColors = {
below: '#00cc95', // green oklch(75% 0.3 165)
@@ -142,42 +142,3 @@ export function getGradient(
}
return gradient;
}
-
-/**
- * @param baseColor a color string
- * @param change a number between -1 and 1, indicating the amount to darken or lighten the color
- * @returns an adjusted color, either darkened or lightened, depending on the sign of change
- */
-export function darkenOrLighten(baseColor: string, change: number) {
- if (!baseColor) return baseColor;
- let colorObj = color(baseColor);
- if (change < 0) {
- // darkening appears more drastic than lightening, so we will be less aggressive (scale change by .5)
- return colorObj.darken(Math.abs(change * 0.5)).hex();
- } else {
- return colorObj.lighten(Math.abs(change)).hex();
- }
-}
-
-/**
- * @param colors an array of colors, each of which is an array of [key, color string]
- * @returns an object mapping keys to colors, with duplicates darkened/lightened to be distinguishable
- */
-export function dedupColors(colors: string[][]) {
- const dedupedColors = {};
- const maxAdjustment = 0.7; // more than this is too drastic and the colors approach black/white
- for (const [key, clr] of colors) {
- if (!clr) continue; // skip empty colors
- const duplicates = colors.filter(([k, c]) => c == clr);
- if (duplicates.length > 1) {
- // there are duplicates; calculate an evenly-spaced adjustment for each one
- duplicates.forEach(([k, c], i) => {
- const change = -maxAdjustment + ((maxAdjustment * 2) / (duplicates.length - 1)) * i;
- dedupedColors[k] = darkenOrLighten(clr, change);
- });
- } else if (!dedupedColors[key]) {
- dedupedColors[key] = clr; // not a dupe, & not already deduped, so use the color as-is
- }
- }
- return dedupedColors;
-}
diff --git a/www/js/config/useImperialConfig.ts b/www/js/config/useImperialConfig.ts
index 900c9854e..ba32ccec2 100644
--- a/www/js/config/useImperialConfig.ts
+++ b/www/js/config/useImperialConfig.ts
@@ -1,6 +1,6 @@
import React, { useMemo } from 'react';
import useAppConfig from '../useAppConfig';
-import { formatForDisplay } from '../util';
+import { formatForDisplay } from '../datetimeUtil';
export type ImperialConfig = {
distanceSuffix: string;
diff --git a/www/js/util.ts b/www/js/datetimeUtil.ts
similarity index 100%
rename from www/js/util.ts
rename to www/js/datetimeUtil.ts
diff --git a/www/js/diary/diaryHelper.ts b/www/js/diary/diaryHelper.ts
index e182835c4..b6510f288 100644
--- a/www/js/diary/diaryHelper.ts
+++ b/www/js/diary/diaryHelper.ts
@@ -4,7 +4,7 @@ import { LabelOptions } from '../types/labelTypes';
import { LocalDt } from '../types/serverData';
import { ImperialConfig } from '../config/useImperialConfig';
import { base_modes } from 'e-mission-common';
-import { humanizeIsoRange } from '../util';
+import { humanizeIsoRange } from '../datetimeUtil';
export type BaseModeKey = string; // TODO figure out how to get keyof typeof base_modes.BASE_MODES
diff --git a/www/js/diary/list/DateSelect.tsx b/www/js/diary/list/DateSelect.tsx
index 2f629b3d1..52cebe63e 100644
--- a/www/js/diary/list/DateSelect.tsx
+++ b/www/js/diary/list/DateSelect.tsx
@@ -19,7 +19,7 @@ import { Text, useTheme } from 'react-native-paper';
import i18next from 'i18next';
import { useTranslation } from 'react-i18next';
import { NavBarButton } from '../../components/NavBar';
-import { formatIsoNoYear, isoDateRangeToTsRange } from '../../util';
+import { formatIsoNoYear, isoDateRangeToTsRange } from '../../datetimeUtil';
// formats as e.g. 'Aug 1'
const MONTH_DAY_SHORT: Intl.DateTimeFormatOptions = {
diff --git a/www/js/diary/list/TimelineScrollList.tsx b/www/js/diary/list/TimelineScrollList.tsx
index 98f12d139..e640b2b11 100644
--- a/www/js/diary/list/TimelineScrollList.tsx
+++ b/www/js/diary/list/TimelineScrollList.tsx
@@ -7,7 +7,7 @@ import { ActivityIndicator, Banner, Button, Icon, Text } from 'react-native-pape
import LoadMoreButton from './LoadMoreButton';
import { useTranslation } from 'react-i18next';
import TimelineContext from '../../TimelineContext';
-import { isoDateRangeToTsRange, isoDateWithOffset } from '../../util';
+import { isoDateRangeToTsRange, isoDateWithOffset } from '../../datetimeUtil';
import { DateTime } from 'luxon';
function renderCard({ item: listEntry, index }) {
diff --git a/www/js/diary/useDerivedProperties.tsx b/www/js/diary/useDerivedProperties.tsx
index 4071000f7..3a46f7cca 100644
--- a/www/js/diary/useDerivedProperties.tsx
+++ b/www/js/diary/useDerivedProperties.tsx
@@ -7,7 +7,7 @@ import {
primarySectionForTrip,
} from './diaryHelper';
import TimelineContext from '../TimelineContext';
-import { formatIsoNoYear, formatIsoWeekday, humanizeIsoRange, isoDatesDifference } from '../util';
+import { formatIsoNoYear, formatIsoWeekday, humanizeIsoRange } from '../datetimeUtil';
const useDerivedProperties = (tlEntry) => {
const imperialConfig = useImperialConfig();
@@ -18,7 +18,8 @@ const useDerivedProperties = (tlEntry) => {
const endFmt = tlEntry.end_fmt_time || tlEntry.exit_fmt_time;
const beginDt = tlEntry.start_local_dt || tlEntry.enter_local_dt;
const endDt = tlEntry.end_local_dt || tlEntry.exit_local_dt;
- const tlEntryIsMultiDay = isoDatesDifference(beginFmt, endFmt);
+ // given YYYY-MM-DDTHH:MM:SSZ strings: if YYYY-MM-DD differs, is multi-day
+ const tlEntryIsMultiDay = beginFmt.substring(0, 10) != endFmt.substring(0, 10);
return {
confirmedMode: confirmedModeFor(tlEntry),
diff --git a/www/js/metrics/MetricsTab.tsx b/www/js/metrics/MetricsTab.tsx
index d4fdddc35..65a0bb847 100644
--- a/www/js/metrics/MetricsTab.tsx
+++ b/www/js/metrics/MetricsTab.tsx
@@ -14,7 +14,7 @@ import { metrics_summaries } from 'e-mission-common';
import MetricsScreen from './MetricsScreen';
import { LabelOptions } from '../types/labelTypes';
import { useAppTheme } from '../appTheme';
-import { isoDatesDifference } from '../util';
+import { isoDatesDifference } from '../datetimeUtil';
const N_DAYS_TO_LOAD = 14; // 2 weeks
export const DEFAULT_METRIC_LIST: MetricList = {
diff --git a/www/js/metrics/SumaryCard.tsx b/www/js/metrics/SummaryCard.tsx
similarity index 89%
rename from www/js/metrics/SumaryCard.tsx
rename to www/js/metrics/SummaryCard.tsx
index 7f3170c5d..577f2ee97 100644
--- a/www/js/metrics/SumaryCard.tsx
+++ b/www/js/metrics/SummaryCard.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { Card, Text } from 'react-native-paper';
-import { formatForDisplay } from '../util';
+import { formatForDisplay } from '../datetimeUtil';
import { colors } from '../appTheme';
import { t } from 'i18next';
import { FootprintGoal } from '../types/appConfigTypes';
@@ -20,9 +20,8 @@ const SummaryCard = ({ title, unit, value, nDays, goals }: Props) => {
const perDayValue = value.map((v) => v / nDays) as Value;
const formatVal = (v: Value) => {
- const opts = { maximumFractionDigits: 1 };
- if (valueIsRange) return `${formatForDisplay(v[0], opts)} - ${formatForDisplay(v[1], opts)}`;
- return `${formatForDisplay(v[0], opts)}`;
+ if (valueIsRange) return `${formatForDisplay(v[0])} - ${formatForDisplay(v[1])}`;
+ return `${formatForDisplay(v[0])}`;
};
const colorFn = (v: Value) => {
diff --git a/www/js/metrics/footprint/FootprintComparisonCard.tsx b/www/js/metrics/footprint/FootprintComparisonCard.tsx
index 344a94164..0dfd4bc42 100644
--- a/www/js/metrics/footprint/FootprintComparisonCard.tsx
+++ b/www/js/metrics/footprint/FootprintComparisonCard.tsx
@@ -5,7 +5,7 @@ import BarChart from '../../components/BarChart';
import { useTranslation } from 'react-i18next';
import { ChartRecord } from '../../components/Chart';
import TimelineContext from '../../TimelineContext';
-import { formatIsoNoYear } from '../../util';
+import { formatIsoNoYear } from '../../datetimeUtil';
const FootprintComparisonCard = ({
type,
diff --git a/www/js/metrics/footprint/FootprintSection.tsx b/www/js/metrics/footprint/FootprintSection.tsx
index c871f9b07..ce97c99e5 100644
--- a/www/js/metrics/footprint/FootprintSection.tsx
+++ b/www/js/metrics/footprint/FootprintSection.tsx
@@ -2,11 +2,11 @@ import React, { useContext, useMemo, useState } from 'react';
import { View } from 'react-native';
import { Text } from 'react-native-paper';
import color from 'color';
-import SummaryCard from '../SumaryCard';
+import SummaryCard from '../SummaryCard';
import { useTranslation } from 'react-i18next';
import { sumMetricEntries } from '../metricsHelper';
import TimelineContext from '../../TimelineContext';
-import { formatIso, isoDatesDifference } from '../../util';
+import { formatIso, isoDatesDifference } from '../../datetimeUtil';
import WeeklyFootprintCard from './WeeklyFootprintCard';
import useAppConfig from '../../useAppConfig';
import { getFootprintGoals } from './footprintHelper';
diff --git a/www/js/metrics/footprint/WeeklyFootprintCard.tsx b/www/js/metrics/footprint/WeeklyFootprintCard.tsx
index 5f4968f1a..d3005362d 100644
--- a/www/js/metrics/footprint/WeeklyFootprintCard.tsx
+++ b/www/js/metrics/footprint/WeeklyFootprintCard.tsx
@@ -10,7 +10,7 @@ import {
sumMetricEntries,
trimGroupingPrefix,
} from '../metricsHelper';
-import { formatIsoNoYear, isoDateWithOffset } from '../../util';
+import { formatIsoNoYear, isoDateWithOffset } from '../../datetimeUtil';
import { useTranslation } from 'react-i18next';
import BarChart from '../../components/BarChart';
import { ChartRecord } from '../../components/Chart';
diff --git a/www/js/metrics/metricsHelper.ts b/www/js/metrics/metricsHelper.ts
index f0cc458c5..fc759f320 100644
--- a/www/js/metrics/metricsHelper.ts
+++ b/www/js/metrics/metricsHelper.ts
@@ -6,7 +6,12 @@ import { MetricName, groupingFields } from '../types/appConfigTypes';
import { ImperialConfig } from '../config/useImperialConfig';
import i18next from 'i18next';
import { base_modes, metrics_summaries } from 'e-mission-common';
-import { formatForDisplay, formatIsoNoYear, isoDatesDifference, isoDateWithOffset } from '../util';
+import {
+ formatForDisplay,
+ formatIsoNoYear,
+ isoDatesDifference,
+ isoDateWithOffset,
+} from '../datetimeUtil';
import { LabelOptions, RichMode } from '../types/labelTypes';
import { labelOptions, textToLabelKey } from '../survey/multilabel/confirmHelper';
import { UNCERTAIN_OPACITY } from '../components/charting';
diff --git a/www/js/metrics/movement/WeeklyActiveMinutesCard.tsx b/www/js/metrics/movement/WeeklyActiveMinutesCard.tsx
index 3fcdade74..bce6db844 100644
--- a/www/js/metrics/movement/WeeklyActiveMinutesCard.tsx
+++ b/www/js/metrics/movement/WeeklyActiveMinutesCard.tsx
@@ -13,7 +13,7 @@ import { useTranslation } from 'react-i18next';
import BarChart from '../../components/BarChart';
import { labelKeyToText } from '../../survey/multilabel/confirmHelper';
import TimelineContext from '../../TimelineContext';
-import { formatIsoNoYear, isoDateWithOffset } from '../../util';
+import { formatIsoNoYear, isoDateWithOffset } from '../../datetimeUtil';
type Props = { userMetrics?: MetricsData; activeModes: string[] };
const WeeklyActiveMinutesCard = ({ userMetrics, activeModes }: Props) => {
diff --git a/www/js/onboarding/OnboardingStack.tsx b/www/js/onboarding/OnboardingStack.tsx
index 38def9cc3..c84f484ac 100644
--- a/www/js/onboarding/OnboardingStack.tsx
+++ b/www/js/onboarding/OnboardingStack.tsx
@@ -14,11 +14,11 @@ const OnboardingStack = () => {
if (onboardingState.route == OnboardingRoute.WELCOME) {
// This page needs 'light content' status bar (white text) due to blue header at the top
- window['StatusBar']?.styleLightContent();
+ // window['StatusBar']?.styleLightContent();
return ;
}
// All other pages go back to 'default' (black text)
- window['StatusBar']?.styleDefault();
+ // window['StatusBar']?.styleDefault();
if (onboardingState.route == OnboardingRoute.SUMMARY) {
return ;
} else if (onboardingState.route == OnboardingRoute.PROTOCOL) {
diff --git a/www/js/survey/enketo/AddedNotesList.tsx b/www/js/survey/enketo/AddedNotesList.tsx
index caf53e89c..49e883cf5 100644
--- a/www/js/survey/enketo/AddedNotesList.tsx
+++ b/www/js/survey/enketo/AddedNotesList.tsx
@@ -11,7 +11,7 @@ import EnketoModal from './EnketoModal';
import { useTranslation } from 'react-i18next';
import { EnketoUserInputEntry } from './enketoHelper';
import { displayErrorMsg, logDebug } from '../../plugin/logger';
-import { formatIsoNoYear, isoDatesDifference } from '../../util';
+import { formatIsoNoYear, isoDatesDifference } from '../../datetimeUtil';
type Props = {
timelineEntry: any;