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

Sep 2024 Fixes #1181

Merged
merged 6 commits into from
Sep 27, 2024
Merged
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
4 changes: 1 addition & 3 deletions package.cordovabuild.json
Original file line number Diff line number Diff line change
@@ -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.1",
"enketo-core": "^6.1.7",
2 changes: 1 addition & 1 deletion setup/setup_native.sh
Original file line number Diff line number Diff line change
@@ -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 ];
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { formatForDisplay } from '../js/util';
import { formatForDisplay } from '../js/datetimeUtil';

describe('util.ts', () => {
describe('formatForDisplay', () => {
2 changes: 1 addition & 1 deletion www/index.js
Original file line number Diff line number Diff line change
@@ -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);
2 changes: 1 addition & 1 deletion www/js/TimelineContext.ts
Original file line number Diff line number Diff line change
@@ -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();
7 changes: 4 additions & 3 deletions www/js/components/Chart.tsx
Original file line number Diff line number Diff line change
@@ -4,7 +4,8 @@
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 @@
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]);

Check warning on line 68 in www/js/components/Chart.tsx

Codecov / codecov/patch

www/js/components/Chart.tsx#L68

Added line #L68 was not covered by tests
}
return {
datasets: chartDatasets.map((e, i) => ({
@@ -73,7 +74,7 @@
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,
113 changes: 37 additions & 76 deletions www/js/components/charting.ts
Original file line number Diff line number Diff line change
@@ -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') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: why is this commented out? will it be restored or removed in the future?

// 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;
}
2 changes: 1 addition & 1 deletion www/js/config/useImperialConfig.ts
Original file line number Diff line number Diff line change
@@ -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;
File renamed without changes.
2 changes: 1 addition & 1 deletion www/js/diary/diaryHelper.ts
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion www/js/diary/list/DateSelect.tsx
Original file line number Diff line number Diff line change
@@ -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 = {
2 changes: 1 addition & 1 deletion www/js/diary/list/TimelineScrollList.tsx
Original file line number Diff line number Diff line change
@@ -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 }) {
5 changes: 3 additions & 2 deletions www/js/diary/useDerivedProperties.tsx
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@
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 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);

Check warning on line 22 in www/js/diary/useDerivedProperties.tsx

Codecov / codecov/patch

www/js/diary/useDerivedProperties.tsx#L22

Added line #L22 was not covered by tests

return {
confirmedMode: confirmedModeFor(tlEntry),
2 changes: 1 addition & 1 deletion www/js/metrics/MetricsTab.tsx
Original file line number Diff line number Diff line change
@@ -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 = {
Original file line number Diff line number Diff line change
@@ -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 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])}`;

Check warning on line 24 in www/js/metrics/SummaryCard.tsx

Codecov / codecov/patch

www/js/metrics/SummaryCard.tsx#L24

Added line #L24 was not covered by tests
};

const colorFn = (v: Value) => {
2 changes: 1 addition & 1 deletion www/js/metrics/footprint/FootprintComparisonCard.tsx
Original file line number Diff line number Diff line change
@@ -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,
4 changes: 2 additions & 2 deletions www/js/metrics/footprint/FootprintSection.tsx
Original file line number Diff line number Diff line change
@@ -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';
2 changes: 1 addition & 1 deletion www/js/metrics/footprint/WeeklyFootprintCard.tsx
Original file line number Diff line number Diff line change
@@ -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';
7 changes: 6 additions & 1 deletion www/js/metrics/metricsHelper.ts
Original file line number Diff line number Diff line change
@@ -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';
2 changes: 1 addition & 1 deletion www/js/metrics/movement/WeeklyActiveMinutesCard.tsx
Original file line number Diff line number Diff line change
@@ -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) => {
4 changes: 2 additions & 2 deletions www/js/onboarding/OnboardingStack.tsx
Original file line number Diff line number Diff line change
@@ -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 <WelcomePage />;
}
// All other pages go back to 'default' (black text)
window['StatusBar']?.styleDefault();
// window['StatusBar']?.styleDefault();
if (onboardingState.route == OnboardingRoute.SUMMARY) {
return <SummaryPage />;
} else if (onboardingState.route == OnboardingRoute.PROTOCOL) {
2 changes: 1 addition & 1 deletion www/js/survey/enketo/AddedNotesList.tsx
Original file line number Diff line number Diff line change
@@ -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;