From e7c3d0f7d52889b232093a0fa2a0e59f39e45f04 Mon Sep 17 00:00:00 2001 From: louisg1337 Date: Thu, 11 Jul 2024 10:20:43 -0400 Subject: [PATCH 1/7] Integrated e-mission-common base mode colors and helper function into e-mission-phone --- www/__tests__/diaryHelper.test.ts | 9 ++- www/js/components/charting.ts | 1 - www/js/diary/cards/ModesIndicator.tsx | 5 +- .../details/TripSectionsDescriptives.tsx | 7 +- www/js/diary/diaryHelper.ts | 73 +++---------------- www/js/diary/timelineHelper.ts | 8 +- www/js/metrics/MetricsCard.tsx | 5 +- 7 files changed, 29 insertions(+), 79 deletions(-) diff --git a/www/__tests__/diaryHelper.test.ts b/www/__tests__/diaryHelper.test.ts index 0eb4a8628..a0a2d00d5 100644 --- a/www/__tests__/diaryHelper.test.ts +++ b/www/__tests__/diaryHelper.test.ts @@ -4,10 +4,11 @@ import { getFormattedDateAbbr, getFormattedTimeRange, getDetectedModes, - getBaseModeByKey, modeColors, } from '../js/diary/diaryHelper'; +import { base_mode_colors } from 'e-mission-common'; + import initializedI18next from '../js/i18nextInit'; window['i18next'] = initializedI18next; @@ -38,17 +39,17 @@ it('returns a human readable time range', () => { }); it('returns a Base Mode for a given key', () => { - expect(getBaseModeByKey('WALKING')).toEqual({ + expect(base_mode_colors.get_base_mode_by_key('WALKING')).toEqual({ name: 'WALKING', icon: 'walk', color: modeColors.blue, }); - expect(getBaseModeByKey('MotionTypes.WALKING')).toEqual({ + expect(base_mode_colors.get_base_mode_by_key('MotionTypes.WALKING')).toEqual({ name: 'WALKING', icon: 'walk', color: modeColors.blue, }); - expect(getBaseModeByKey('I made this type up')).toEqual({ + expect(base_mode_colors.get_base_mode_by_key('I made this type up')).toEqual({ name: 'UNKNOWN', icon: 'help', color: modeColors.grey, diff --git a/www/js/components/charting.ts b/www/js/components/charting.ts index f536fc04f..11ae43be7 100644 --- a/www/js/components/charting.ts +++ b/www/js/components/charting.ts @@ -1,5 +1,4 @@ import color from 'color'; -import { getBaseModeByKey } from '../diary/diaryHelper'; import { readableLabelToKey } from '../survey/multilabel/confirmHelper'; import { logDebug } from '../plugin/logger'; diff --git a/www/js/diary/cards/ModesIndicator.tsx b/www/js/diary/cards/ModesIndicator.tsx index 2ec5d9dc2..df6ec0833 100644 --- a/www/js/diary/cards/ModesIndicator.tsx +++ b/www/js/diary/cards/ModesIndicator.tsx @@ -3,9 +3,10 @@ import { View, StyleSheet } from 'react-native'; import color from 'color'; import TimelineContext from '../../TimelineContext'; import { logDebug } from '../../plugin/logger'; -import { getBaseModeByKey, getBaseModeByValue } from '../diaryHelper'; +import { getBaseModeByValue } from '../diaryHelper'; import { Text, Icon, useTheme } from 'react-native-paper'; import { useTranslation } from 'react-i18next'; +import { base_mode_colors } from 'e-mission-common'; const ModesIndicator = ({ trip, detectedModes }) => { const { t } = useTranslation(); @@ -18,7 +19,7 @@ const ModesIndicator = ({ trip, detectedModes }) => { let modeViews; const confirmedModeForTrip = confirmedModeFor(trip); if (labelOptions && confirmedModeForTrip?.value) { - const baseMode = getBaseModeByKey(confirmedModeForTrip.baseMode); + const baseMode = base_mode_colors.get_base_mode_by_key(confirmedModeForTrip.baseMode); indicatorBorderColor = baseMode.color; logDebug(`TripCard: got baseMode = ${JSON.stringify(baseMode)}`); modeViews = ( diff --git a/www/js/diary/details/TripSectionsDescriptives.tsx b/www/js/diary/details/TripSectionsDescriptives.tsx index 13c15019d..686f2b082 100644 --- a/www/js/diary/details/TripSectionsDescriptives.tsx +++ b/www/js/diary/details/TripSectionsDescriptives.tsx @@ -2,8 +2,9 @@ import React, { useContext } from 'react'; import { View, StyleSheet } from 'react-native'; import { Icon, Text, useTheme } from 'react-native-paper'; import useDerivedProperties from '../useDerivedProperties'; -import { getBaseModeByKey, getBaseModeByValue } from '../diaryHelper'; +import { getBaseModeByValue } from '../diaryHelper'; import TimelineContext from '../../TimelineContext'; +import { base_mode_colors } from 'e-mission-common'; const TripSectionsDescriptives = ({ trip, showConfirmedMode = false }) => { const { labelOptions, labelFor, confirmedModeFor } = useContext(TimelineContext); @@ -24,9 +25,9 @@ const TripSectionsDescriptives = ({ trip, showConfirmedMode = false }) => { if ((showConfirmedMode && confirmedModeForTrip) || !trip.sections?.length) { let baseMode; if (showConfirmedMode && labelOptions && confirmedModeForTrip) { - baseMode = getBaseModeByKey(confirmedModeForTrip.baseMode); + baseMode = base_mode_colors.get_base_mode_by_key(confirmedModeForTrip.baseMode); } else { - baseMode = getBaseModeByKey('UNPROCESSED'); + baseMode = base_mode_colors.get_base_mode_by_key('UNPROCESSED'); } sections = [ { diff --git a/www/js/diary/diaryHelper.ts b/www/js/diary/diaryHelper.ts index 12495742d..e68fd5b70 100644 --- a/www/js/diary/diaryHelper.ts +++ b/www/js/diary/diaryHelper.ts @@ -9,24 +9,9 @@ import { LocalDt } from '../types/serverData'; import humanizeDuration from 'humanize-duration'; import { AppConfig } from '../types/appConfigTypes'; import { ImperialConfig } from '../config/useImperialConfig'; +import { base_mode_colors } from 'e-mission-common'; -export const modeColors = { - pink: '#c32e85', // oklch(56% 0.2 350) // e-car - red: '#c21725', // oklch(52% 0.2 25) // car - orange: '#bf5900', // oklch(58% 0.16 50) // air, hsr - green: '#008148', // oklch(53% 0.14 155) // bike, e-bike, moped - blue: '#0074b7', // oklch(54% 0.14 245) // walk - periwinkle: '#6356bf', // oklch(52% 0.16 285) // light rail, train, tram, subway - magenta: '#9240a4', // oklch(52% 0.17 320) // bus - grey: '#555555', // oklch(45% 0 0) // unprocessed / unknown - taupe: '#7d585a', // oklch(50% 0.05 15) // ferry, trolleybus, user-defined modes -}; - -type BaseMode = { - name: string; - icon: string; - color: string; -}; +export const modeColors = base_mode_colors.mode_colors; // parallels the server-side MotionTypes enum: https://github.com/e-mission/e-mission-server/blob/94e7478e627fa8c171323662f951c611c0993031/emission/core/wrapper/motionactivity.py#L12 export type MotionTypeKey = @@ -42,54 +27,16 @@ export type MotionTypeKey = | 'STOPPED_WHILE_IN_VEHICLE' | 'AIR_OR_HSR'; -const BaseModes: { [k: string]: BaseMode } = { - // BEGIN MotionTypes - IN_VEHICLE: { name: 'IN_VEHICLE', icon: 'speedometer', color: modeColors.red }, - BICYCLING: { name: 'BICYCLING', icon: 'bike', color: modeColors.green }, - ON_FOOT: { name: 'ON_FOOT', icon: 'walk', color: modeColors.blue }, - UNKNOWN: { name: 'UNKNOWN', icon: 'help', color: modeColors.grey }, - WALKING: { name: 'WALKING', icon: 'walk', color: modeColors.blue }, - AIR_OR_HSR: { name: 'AIR_OR_HSR', icon: 'airplane', color: modeColors.orange }, - // END MotionTypes - CAR: { name: 'CAR', icon: 'car', color: modeColors.red }, - E_CAR: { name: 'E_CAR', icon: 'car-electric', color: modeColors.pink }, - E_BIKE: { name: 'E_BIKE', icon: 'bicycle-electric', color: modeColors.green }, - E_SCOOTER: { name: 'E_SCOOTER', icon: 'scooter-electric', color: modeColors.periwinkle }, - MOPED: { name: 'MOPED', icon: 'moped', color: modeColors.green }, - TAXI: { name: 'TAXI', icon: 'taxi', color: modeColors.red }, - BUS: { name: 'BUS', icon: 'bus-side', color: modeColors.magenta }, - AIR: { name: 'AIR', icon: 'airplane', color: modeColors.orange }, - LIGHT_RAIL: { name: 'LIGHT_RAIL', icon: 'train-car-passenger', color: modeColors.periwinkle }, - TRAIN: { name: 'TRAIN', icon: 'train-car-passenger', color: modeColors.periwinkle }, - TRAM: { name: 'TRAM', icon: 'fas fa-tram', color: modeColors.periwinkle }, - SUBWAY: { name: 'SUBWAY', icon: 'subway-variant', color: modeColors.periwinkle }, - FERRY: { name: 'FERRY', icon: 'ferry', color: modeColors.taupe }, - TROLLEYBUS: { name: 'TROLLEYBUS', icon: 'bus-side', color: modeColors.taupe }, - UNPROCESSED: { name: 'UNPROCESSED', icon: 'help', color: modeColors.grey }, - OTHER: { name: 'OTHER', icon: 'pencil-circle', color: modeColors.taupe }, -}; - -export type BaseModeKey = keyof typeof BaseModes; -/** - * @param motionName A string like "WALKING" or "MotionTypes.WALKING" - * @returns A BaseMode object containing the name, icon, and color of the motion type - */ -export function getBaseModeByKey( - motionName: BaseModeKey | MotionTypeKey | `MotionTypes.${MotionTypeKey}`, -) { - const key = ('' + motionName).toUpperCase(); - const pop = key.split('.').pop(); // if "MotionTypes.WALKING", then just take "WALKING" - return (pop && BaseModes[pop]) || BaseModes.UNKNOWN; -} +const BaseModes = base_mode_colors.BASE_MODES; export function getBaseModeByValue(value: string, labelOptions: LabelOptions) { const modeOption = labelOptions?.MODE?.find((opt) => opt.value == value); - return getBaseModeByKey(modeOption?.baseMode || 'OTHER'); + return base_mode_colors.get_base_mode_by_key(modeOption?.baseMode || 'OTHER'); } export function getBaseModeByText(text: string, labelOptions: LabelOptions) { const modeOption = labelOptions?.MODE?.find((opt) => opt.text == text); - return getBaseModeByKey(modeOption?.baseMode || 'OTHER'); + return base_mode_colors.get_base_mode_by_key(modeOption?.baseMode || 'OTHER'); } /** @@ -172,11 +119,11 @@ export function getDetectedModes(trip: CompositeTrip) { if (!sectionSummary?.distance) return []; return Object.entries(sectionSummary.distance) - .sort(([modeA, distA], [modeB, distB]) => distB - distA) // sort by distance (highest first) + .sort(([modeA, distA]: [string, number], [modeB, distB]: [string, number]) => distB - distA) // sort by distance (highest first) .map(([mode, dist]: [MotionTypeKey, number]) => ({ mode, - icon: getBaseModeByKey(mode)?.icon, - color: getBaseModeByKey(mode)?.color || 'black', + icon: base_mode_colors.get_base_mode_by_key(mode)?.icon, + color: base_mode_colors.get_base_mode_by_key(mode)?.color || 'black', pct: Math.round((dist / trip.distance) * 100) || '<1', // if rounds to 0%, show <1% })); } @@ -187,8 +134,8 @@ export function getFormattedSectionProperties(trip: CompositeTrip, imperialConfi duration: getFormattedTimeRange(s.start_fmt_time, s.end_fmt_time), distance: imperialConfig.getFormattedDistance(s.distance), distanceSuffix: imperialConfig.distanceSuffix, - icon: getBaseModeByKey(s.sensed_mode_str)?.icon, - color: getBaseModeByKey(s.sensed_mode_str)?.color || '#333', + icon: base_mode_colors.get_base_mode_by_key(s.sensed_mode_str)?.icon, + color: base_mode_colors.get_base_mode_by_key(s.sensed_mode_str)?.color || '#333', })); } diff --git a/www/js/diary/timelineHelper.ts b/www/js/diary/timelineHelper.ts index d5c1e507b..ea165ec8a 100644 --- a/www/js/diary/timelineHelper.ts +++ b/www/js/diary/timelineHelper.ts @@ -1,5 +1,5 @@ import { displayError, displayErrorMsg, logDebug } from '../plugin/logger'; -import { getBaseModeByKey, getBaseModeByValue } from './diaryHelper'; +import { getBaseModeByValue } from './diaryHelper'; import { getUnifiedDataForInterval } from '../services/unifiedDataLoader'; import { getRawEntries } from '../services/commHelper'; import { ServerResponse, BEMData } from '../types/serverData'; @@ -28,7 +28,7 @@ import { } from '../survey/enketo/enketoHelper'; import { AppConfig } from '../types/appConfigTypes'; import { Point, Feature } from 'geojson'; -import { ble_matching } from 'e-mission-common'; +import { ble_matching, base_mode_colors } from 'e-mission-common'; const cachedGeojsons: Map = new Map(); @@ -42,7 +42,7 @@ export function useGeojsonForTrip(trip: CompositeTrip, baseMode?: string) { return cachedGeojsons.get(gjKey); } - const trajectoryColor = (baseMode && getBaseModeByKey(baseMode)?.color) || undefined; + const trajectoryColor = (baseMode && base_mode_colors.get_base_mode_by_key(baseMode)?.color) || undefined; logDebug("Reading trip's " + trip.locations.length + ' location points at ' + new Date()); const features = [ @@ -266,7 +266,7 @@ function locations2GeojsonTrajectory( style: { /* If a color was passed as arg, use it for the whole trajectory. Otherwise, use the color for the sensed mode of this section, and fall back to dark grey */ - color: trajectoryColor || getBaseModeByKey(section?.sensed_mode_str)?.color || '#333', + color: trajectoryColor || base_mode_colors.get_base_mode_by_key(section?.sensed_mode_str)?.color || '#333', }, properties: { feature_type: 'section_trajectory', diff --git a/www/js/metrics/MetricsCard.tsx b/www/js/metrics/MetricsCard.tsx index 287193711..9b5acddcd 100644 --- a/www/js/metrics/MetricsCard.tsx +++ b/www/js/metrics/MetricsCard.tsx @@ -15,10 +15,11 @@ import { import ToggleSwitch from '../components/ToggleSwitch'; import { cardStyles } from './MetricsTab'; import { labelKeyToRichMode, labelOptions } from '../survey/multilabel/confirmHelper'; -import { getBaseModeByKey, getBaseModeByText, modeColors } from '../diary/diaryHelper'; +import { getBaseModeByText, modeColors } from '../diary/diaryHelper'; import { useTranslation } from 'react-i18next'; import { GroupingField, MetricName } from '../types/appConfigTypes'; import { useImperialConfig } from '../config/useImperialConfig'; +import { base_mode_colors } from 'e-mission-common'; type Props = { metricName: MetricName; @@ -115,7 +116,7 @@ const MetricsCard = ({ // All other modes are colored according to their base mode const getColorForLabel = (label: string) => { if (label == 'Unlabeled') { - const unknownModeColor = getBaseModeByKey('UNKNOWN').color; + const unknownModeColor = base_mode_colors.get_base_mode_by_key('UNKNOWN').color; return colorLib(unknownModeColor).alpha(0.15).rgb().string(); } return getBaseModeByText(label, labelOptions).color; From efcdf3ceebb8efd68d3cfa390f92c1e4f885d3b8 Mon Sep 17 00:00:00 2001 From: louisg1337 Date: Thu, 11 Jul 2024 12:28:17 -0400 Subject: [PATCH 2/7] Ran prettier to fix error --- www/js/diary/timelineHelper.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/www/js/diary/timelineHelper.ts b/www/js/diary/timelineHelper.ts index ea165ec8a..2cd80df55 100644 --- a/www/js/diary/timelineHelper.ts +++ b/www/js/diary/timelineHelper.ts @@ -42,7 +42,8 @@ export function useGeojsonForTrip(trip: CompositeTrip, baseMode?: string) { return cachedGeojsons.get(gjKey); } - const trajectoryColor = (baseMode && base_mode_colors.get_base_mode_by_key(baseMode)?.color) || undefined; + const trajectoryColor = + (baseMode && base_mode_colors.get_base_mode_by_key(baseMode)?.color) || undefined; logDebug("Reading trip's " + trip.locations.length + ' location points at ' + new Date()); const features = [ @@ -266,7 +267,10 @@ function locations2GeojsonTrajectory( style: { /* If a color was passed as arg, use it for the whole trajectory. Otherwise, use the color for the sensed mode of this section, and fall back to dark grey */ - color: trajectoryColor || base_mode_colors.get_base_mode_by_key(section?.sensed_mode_str)?.color || '#333', + color: + trajectoryColor || + base_mode_colors.get_base_mode_by_key(section?.sensed_mode_str)?.color || + '#333', }, properties: { feature_type: 'section_trajectory', From 9d57af93ede02a235d97ef5357a1738569db8faf Mon Sep 17 00:00:00 2001 From: louisg1337 Date: Mon, 22 Jul 2024 11:10:34 -0400 Subject: [PATCH 3/7] Bumped e-mission-common to 0.5.4 and changed all instances of base_mode_colors to base_modes --- package.cordovabuild.json | 2 +- package.serve.json | 2 +- www/__tests__/diaryHelper.test.ts | 8 ++++---- www/js/diary/cards/ModesIndicator.tsx | 4 ++-- .../diary/details/TripSectionsDescriptives.tsx | 6 +++--- www/js/diary/diaryHelper.ts | 18 +++++++++--------- www/js/diary/timelineHelper.ts | 6 +++--- www/js/metrics/MetricsCard.tsx | 4 ++-- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/package.cordovabuild.json b/package.cordovabuild.json index a4a729beb..a2c36e855 100644 --- a/package.cordovabuild.json +++ b/package.cordovabuild.json @@ -137,7 +137,7 @@ "cordova-custom-config": "^5.1.1", "cordova-plugin-ibeacon": "git+https://github.com/louisg1337/cordova-plugin-ibeacon.git", "core-js": "^2.5.7", - "e-mission-common": "github:JGreenlee/e-mission-common#semver:0.5.1", + "e-mission-common": "github:JGreenlee/e-mission-common#semver:0.5.4", "enketo-core": "^6.1.7", "enketo-transformer": "^4.0.0", "fast-xml-parser": "^4.2.2", diff --git a/package.serve.json b/package.serve.json index ff9bf5879..a96c29657 100644 --- a/package.serve.json +++ b/package.serve.json @@ -65,7 +65,7 @@ "chartjs-adapter-luxon": "^1.3.1", "chartjs-plugin-annotation": "^3.0.1", "core-js": "^2.5.7", - "e-mission-common": "github:JGreenlee/e-mission-common#semver:0.5.1", + "e-mission-common": "github:JGreenlee/e-mission-common#semver:0.5.4", "enketo-core": "^6.1.7", "enketo-transformer": "^4.0.0", "fast-xml-parser": "^4.2.2", diff --git a/www/__tests__/diaryHelper.test.ts b/www/__tests__/diaryHelper.test.ts index a0a2d00d5..c52e3f6dc 100644 --- a/www/__tests__/diaryHelper.test.ts +++ b/www/__tests__/diaryHelper.test.ts @@ -7,7 +7,7 @@ import { modeColors, } from '../js/diary/diaryHelper'; -import { base_mode_colors } from 'e-mission-common'; +import { base_modes } from 'e-mission-common'; import initializedI18next from '../js/i18nextInit'; window['i18next'] = initializedI18next; @@ -39,17 +39,17 @@ it('returns a human readable time range', () => { }); it('returns a Base Mode for a given key', () => { - expect(base_mode_colors.get_base_mode_by_key('WALKING')).toEqual({ + expect(base_modes.get_base_mode_by_key('WALKING')).toEqual({ name: 'WALKING', icon: 'walk', color: modeColors.blue, }); - expect(base_mode_colors.get_base_mode_by_key('MotionTypes.WALKING')).toEqual({ + expect(base_modes.get_base_mode_by_key('MotionTypes.WALKING')).toEqual({ name: 'WALKING', icon: 'walk', color: modeColors.blue, }); - expect(base_mode_colors.get_base_mode_by_key('I made this type up')).toEqual({ + expect(base_modes.get_base_mode_by_key('I made this type up')).toEqual({ name: 'UNKNOWN', icon: 'help', color: modeColors.grey, diff --git a/www/js/diary/cards/ModesIndicator.tsx b/www/js/diary/cards/ModesIndicator.tsx index df6ec0833..31f649897 100644 --- a/www/js/diary/cards/ModesIndicator.tsx +++ b/www/js/diary/cards/ModesIndicator.tsx @@ -6,7 +6,7 @@ import { logDebug } from '../../plugin/logger'; import { getBaseModeByValue } from '../diaryHelper'; import { Text, Icon, useTheme } from 'react-native-paper'; import { useTranslation } from 'react-i18next'; -import { base_mode_colors } from 'e-mission-common'; +import { base_modes } from 'e-mission-common'; const ModesIndicator = ({ trip, detectedModes }) => { const { t } = useTranslation(); @@ -19,7 +19,7 @@ const ModesIndicator = ({ trip, detectedModes }) => { let modeViews; const confirmedModeForTrip = confirmedModeFor(trip); if (labelOptions && confirmedModeForTrip?.value) { - const baseMode = base_mode_colors.get_base_mode_by_key(confirmedModeForTrip.baseMode); + const baseMode = base_modes.get_base_mode_by_key(confirmedModeForTrip.baseMode); indicatorBorderColor = baseMode.color; logDebug(`TripCard: got baseMode = ${JSON.stringify(baseMode)}`); modeViews = ( diff --git a/www/js/diary/details/TripSectionsDescriptives.tsx b/www/js/diary/details/TripSectionsDescriptives.tsx index 686f2b082..b9ecd6dba 100644 --- a/www/js/diary/details/TripSectionsDescriptives.tsx +++ b/www/js/diary/details/TripSectionsDescriptives.tsx @@ -4,7 +4,7 @@ import { Icon, Text, useTheme } from 'react-native-paper'; import useDerivedProperties from '../useDerivedProperties'; import { getBaseModeByValue } from '../diaryHelper'; import TimelineContext from '../../TimelineContext'; -import { base_mode_colors } from 'e-mission-common'; +import { base_modes } from 'e-mission-common'; const TripSectionsDescriptives = ({ trip, showConfirmedMode = false }) => { const { labelOptions, labelFor, confirmedModeFor } = useContext(TimelineContext); @@ -25,9 +25,9 @@ const TripSectionsDescriptives = ({ trip, showConfirmedMode = false }) => { if ((showConfirmedMode && confirmedModeForTrip) || !trip.sections?.length) { let baseMode; if (showConfirmedMode && labelOptions && confirmedModeForTrip) { - baseMode = base_mode_colors.get_base_mode_by_key(confirmedModeForTrip.baseMode); + baseMode = base_modes.get_base_mode_by_key(confirmedModeForTrip.baseMode); } else { - baseMode = base_mode_colors.get_base_mode_by_key('UNPROCESSED'); + baseMode = base_modes.get_base_mode_by_key('UNPROCESSED'); } sections = [ { diff --git a/www/js/diary/diaryHelper.ts b/www/js/diary/diaryHelper.ts index e68fd5b70..793a61062 100644 --- a/www/js/diary/diaryHelper.ts +++ b/www/js/diary/diaryHelper.ts @@ -9,9 +9,9 @@ import { LocalDt } from '../types/serverData'; import humanizeDuration from 'humanize-duration'; import { AppConfig } from '../types/appConfigTypes'; import { ImperialConfig } from '../config/useImperialConfig'; -import { base_mode_colors } from 'e-mission-common'; +import { base_modes } from 'e-mission-common'; -export const modeColors = base_mode_colors.mode_colors; +export const modeColors = base_modes.mode_colors; // parallels the server-side MotionTypes enum: https://github.com/e-mission/e-mission-server/blob/94e7478e627fa8c171323662f951c611c0993031/emission/core/wrapper/motionactivity.py#L12 export type MotionTypeKey = @@ -27,16 +27,16 @@ export type MotionTypeKey = | 'STOPPED_WHILE_IN_VEHICLE' | 'AIR_OR_HSR'; -const BaseModes = base_mode_colors.BASE_MODES; +const BaseModes = base_modes.BASE_MODES; export function getBaseModeByValue(value: string, labelOptions: LabelOptions) { const modeOption = labelOptions?.MODE?.find((opt) => opt.value == value); - return base_mode_colors.get_base_mode_by_key(modeOption?.baseMode || 'OTHER'); + return base_modes.get_base_mode_by_key(modeOption?.baseMode || 'OTHER'); } export function getBaseModeByText(text: string, labelOptions: LabelOptions) { const modeOption = labelOptions?.MODE?.find((opt) => opt.text == text); - return base_mode_colors.get_base_mode_by_key(modeOption?.baseMode || 'OTHER'); + return base_modes.get_base_mode_by_key(modeOption?.baseMode || 'OTHER'); } /** @@ -122,8 +122,8 @@ export function getDetectedModes(trip: CompositeTrip) { .sort(([modeA, distA]: [string, number], [modeB, distB]: [string, number]) => distB - distA) // sort by distance (highest first) .map(([mode, dist]: [MotionTypeKey, number]) => ({ mode, - icon: base_mode_colors.get_base_mode_by_key(mode)?.icon, - color: base_mode_colors.get_base_mode_by_key(mode)?.color || 'black', + icon: base_modes.get_base_mode_by_key(mode)?.icon, + color: base_modes.get_base_mode_by_key(mode)?.color || 'black', pct: Math.round((dist / trip.distance) * 100) || '<1', // if rounds to 0%, show <1% })); } @@ -134,8 +134,8 @@ export function getFormattedSectionProperties(trip: CompositeTrip, imperialConfi duration: getFormattedTimeRange(s.start_fmt_time, s.end_fmt_time), distance: imperialConfig.getFormattedDistance(s.distance), distanceSuffix: imperialConfig.distanceSuffix, - icon: base_mode_colors.get_base_mode_by_key(s.sensed_mode_str)?.icon, - color: base_mode_colors.get_base_mode_by_key(s.sensed_mode_str)?.color || '#333', + icon: base_modes.get_base_mode_by_key(s.sensed_mode_str)?.icon, + color: base_modes.get_base_mode_by_key(s.sensed_mode_str)?.color || '#333', })); } diff --git a/www/js/diary/timelineHelper.ts b/www/js/diary/timelineHelper.ts index 2cd80df55..7b20f56cf 100644 --- a/www/js/diary/timelineHelper.ts +++ b/www/js/diary/timelineHelper.ts @@ -28,7 +28,7 @@ import { } from '../survey/enketo/enketoHelper'; import { AppConfig } from '../types/appConfigTypes'; import { Point, Feature } from 'geojson'; -import { ble_matching, base_mode_colors } from 'e-mission-common'; +import { ble_matching, base_modes } from 'e-mission-common'; const cachedGeojsons: Map = new Map(); @@ -43,7 +43,7 @@ export function useGeojsonForTrip(trip: CompositeTrip, baseMode?: string) { } const trajectoryColor = - (baseMode && base_mode_colors.get_base_mode_by_key(baseMode)?.color) || undefined; + (baseMode && base_modes.get_base_mode_by_key(baseMode)?.color) || undefined; logDebug("Reading trip's " + trip.locations.length + ' location points at ' + new Date()); const features = [ @@ -269,7 +269,7 @@ function locations2GeojsonTrajectory( color for the sensed mode of this section, and fall back to dark grey */ color: trajectoryColor || - base_mode_colors.get_base_mode_by_key(section?.sensed_mode_str)?.color || + base_modes.get_base_mode_by_key(section?.sensed_mode_str)?.color || '#333', }, properties: { diff --git a/www/js/metrics/MetricsCard.tsx b/www/js/metrics/MetricsCard.tsx index 9b5acddcd..c1de9d320 100644 --- a/www/js/metrics/MetricsCard.tsx +++ b/www/js/metrics/MetricsCard.tsx @@ -19,7 +19,7 @@ import { getBaseModeByText, modeColors } from '../diary/diaryHelper'; import { useTranslation } from 'react-i18next'; import { GroupingField, MetricName } from '../types/appConfigTypes'; import { useImperialConfig } from '../config/useImperialConfig'; -import { base_mode_colors } from 'e-mission-common'; +import { base_modes } from 'e-mission-common'; type Props = { metricName: MetricName; @@ -116,7 +116,7 @@ const MetricsCard = ({ // All other modes are colored according to their base mode const getColorForLabel = (label: string) => { if (label == 'Unlabeled') { - const unknownModeColor = base_mode_colors.get_base_mode_by_key('UNKNOWN').color; + const unknownModeColor = base_modes.get_base_mode_by_key('UNKNOWN').color; return colorLib(unknownModeColor).alpha(0.15).rgb().string(); } return getBaseModeByText(label, labelOptions).color; From b1cd24a9b42fc4a9e53667917c2a81532b3fe72f Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Fri, 16 Aug 2024 13:59:59 -0400 Subject: [PATCH 4/7] base modes cleanup -remove unused imports -fix missing type "BaseModeKey" --this was previously `keyof typeof BASE_MODES`. Now that BASE_MODES is in e-mission-common and is defined as a `dict`, Typescript has a harder time picking up on the types. Keeping as `string` for now. --- www/js/diary/cards/ModesIndicator.tsx | 1 - www/js/diary/details/TripSectionsDescriptives.tsx | 1 - www/js/diary/diaryHelper.ts | 4 +--- www/js/diary/timelineHelper.ts | 1 - www/js/metrics/MetricsCard.tsx | 2 +- 5 files changed, 2 insertions(+), 7 deletions(-) diff --git a/www/js/diary/cards/ModesIndicator.tsx b/www/js/diary/cards/ModesIndicator.tsx index 31f649897..8a4cf1689 100644 --- a/www/js/diary/cards/ModesIndicator.tsx +++ b/www/js/diary/cards/ModesIndicator.tsx @@ -3,7 +3,6 @@ import { View, StyleSheet } from 'react-native'; import color from 'color'; import TimelineContext from '../../TimelineContext'; import { logDebug } from '../../plugin/logger'; -import { getBaseModeByValue } from '../diaryHelper'; import { Text, Icon, useTheme } from 'react-native-paper'; import { useTranslation } from 'react-i18next'; import { base_modes } from 'e-mission-common'; diff --git a/www/js/diary/details/TripSectionsDescriptives.tsx b/www/js/diary/details/TripSectionsDescriptives.tsx index b9ecd6dba..4592c838f 100644 --- a/www/js/diary/details/TripSectionsDescriptives.tsx +++ b/www/js/diary/details/TripSectionsDescriptives.tsx @@ -2,7 +2,6 @@ import React, { useContext } from 'react'; import { View, StyleSheet } from 'react-native'; import { Icon, Text, useTheme } from 'react-native-paper'; import useDerivedProperties from '../useDerivedProperties'; -import { getBaseModeByValue } from '../diaryHelper'; import TimelineContext from '../../TimelineContext'; import { base_modes } from 'e-mission-common'; diff --git a/www/js/diary/diaryHelper.ts b/www/js/diary/diaryHelper.ts index 793a61062..505a4b0d1 100644 --- a/www/js/diary/diaryHelper.ts +++ b/www/js/diary/diaryHelper.ts @@ -11,7 +11,7 @@ import { AppConfig } from '../types/appConfigTypes'; import { ImperialConfig } from '../config/useImperialConfig'; import { base_modes } from 'e-mission-common'; -export const modeColors = base_modes.mode_colors; +export type BaseModeKey = string; // TODO figure out how to get keyof typeof base_modes.BASE_MODES // parallels the server-side MotionTypes enum: https://github.com/e-mission/e-mission-server/blob/94e7478e627fa8c171323662f951c611c0993031/emission/core/wrapper/motionactivity.py#L12 export type MotionTypeKey = @@ -27,8 +27,6 @@ export type MotionTypeKey = | 'STOPPED_WHILE_IN_VEHICLE' | 'AIR_OR_HSR'; -const BaseModes = base_modes.BASE_MODES; - export function getBaseModeByValue(value: string, labelOptions: LabelOptions) { const modeOption = labelOptions?.MODE?.find((opt) => opt.value == value); return base_modes.get_base_mode_by_key(modeOption?.baseMode || 'OTHER'); diff --git a/www/js/diary/timelineHelper.ts b/www/js/diary/timelineHelper.ts index 7b20f56cf..d4dded91b 100644 --- a/www/js/diary/timelineHelper.ts +++ b/www/js/diary/timelineHelper.ts @@ -1,5 +1,4 @@ import { displayError, displayErrorMsg, logDebug } from '../plugin/logger'; -import { getBaseModeByValue } from './diaryHelper'; import { getUnifiedDataForInterval } from '../services/unifiedDataLoader'; import { getRawEntries } from '../services/commHelper'; import { ServerResponse, BEMData } from '../types/serverData'; diff --git a/www/js/metrics/MetricsCard.tsx b/www/js/metrics/MetricsCard.tsx index c1de9d320..241ab8208 100644 --- a/www/js/metrics/MetricsCard.tsx +++ b/www/js/metrics/MetricsCard.tsx @@ -15,7 +15,7 @@ import { import ToggleSwitch from '../components/ToggleSwitch'; import { cardStyles } from './MetricsTab'; import { labelKeyToRichMode, labelOptions } from '../survey/multilabel/confirmHelper'; -import { getBaseModeByText, modeColors } from '../diary/diaryHelper'; +import { getBaseModeByText } from '../diary/diaryHelper'; import { useTranslation } from 'react-i18next'; import { GroupingField, MetricName } from '../types/appConfigTypes'; import { useImperialConfig } from '../config/useImperialConfig'; From 04830af2774dbbea1cc70d5bb0ac2658915326d4 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Fri, 16 Aug 2024 14:01:13 -0400 Subject: [PATCH 5/7] fix diaryHelper.test.ts modeColors is not in diaryHelper anymore; must be accessed from e-mission-common's `base_modes` --- www/__tests__/diaryHelper.test.ts | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/www/__tests__/diaryHelper.test.ts b/www/__tests__/diaryHelper.test.ts index c52e3f6dc..58cd20246 100644 --- a/www/__tests__/diaryHelper.test.ts +++ b/www/__tests__/diaryHelper.test.ts @@ -4,7 +4,6 @@ import { getFormattedDateAbbr, getFormattedTimeRange, getDetectedModes, - modeColors, } from '../js/diary/diaryHelper'; import { base_modes } from 'e-mission-common'; @@ -39,20 +38,17 @@ it('returns a human readable time range', () => { }); it('returns a Base Mode for a given key', () => { - expect(base_modes.get_base_mode_by_key('WALKING')).toEqual({ - name: 'WALKING', + expect(base_modes.get_base_mode_by_key('WALKING')).toMatchObject({ icon: 'walk', - color: modeColors.blue, + color: base_modes.mode_colors['blue'], }); - expect(base_modes.get_base_mode_by_key('MotionTypes.WALKING')).toEqual({ - name: 'WALKING', + expect(base_modes.get_base_mode_by_key('MotionTypes.WALKING')).toMatchObject({ icon: 'walk', - color: modeColors.blue, + color: base_modes.mode_colors['blue'], }); - expect(base_modes.get_base_mode_by_key('I made this type up')).toEqual({ - name: 'UNKNOWN', + expect(base_modes.get_base_mode_by_key('I made this type up')).toMatchObject({ icon: 'help', - color: modeColors.grey, + color: base_modes.mode_colors['grey'], }); }); @@ -88,11 +84,13 @@ let myFakeTrip2 = { }; let myFakeDetectedModes = [ - { mode: 'BICYCLING', icon: 'bike', color: modeColors.green, pct: 89 }, - { mode: 'WALKING', icon: 'walk', color: modeColors.blue, pct: 11 }, + { mode: 'BICYCLING', icon: 'bike', color: base_modes.mode_colors['green'], pct: 89 }, + { mode: 'WALKING', icon: 'walk', color: base_modes.mode_colors['blue'], pct: 11 }, ]; -let myFakeDetectedModes2 = [{ mode: 'BICYCLING', icon: 'bike', color: modeColors.green, pct: 100 }]; +let myFakeDetectedModes2 = [ + { mode: 'BICYCLING', icon: 'bike', color: base_modes.mode_colors['green'], pct: 100 }, +]; it('returns the detected modes, with percentages, for a trip', () => { expect(getDetectedModes(myFakeTrip)).toEqual(myFakeDetectedModes); From a58e8263734b60df3aad6e1adacd79173bc41b9b Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Mon, 19 Aug 2024 00:31:38 -0400 Subject: [PATCH 6/7] remove unused getBaseModeByValue There are no usages of this --- www/js/diary/diaryHelper.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/www/js/diary/diaryHelper.ts b/www/js/diary/diaryHelper.ts index 505a4b0d1..4af19c2cf 100644 --- a/www/js/diary/diaryHelper.ts +++ b/www/js/diary/diaryHelper.ts @@ -27,11 +27,6 @@ export type MotionTypeKey = | 'STOPPED_WHILE_IN_VEHICLE' | 'AIR_OR_HSR'; -export function getBaseModeByValue(value: string, labelOptions: LabelOptions) { - const modeOption = labelOptions?.MODE?.find((opt) => opt.value == value); - return base_modes.get_base_mode_by_key(modeOption?.baseMode || 'OTHER'); -} - export function getBaseModeByText(text: string, labelOptions: LabelOptions) { const modeOption = labelOptions?.MODE?.find((opt) => opt.text == text); return base_modes.get_base_mode_by_key(modeOption?.baseMode || 'OTHER'); From e6aea4e7068ba828a40fb07e608557ba7ea3f0c3 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Mon, 19 Aug 2024 12:45:10 -0400 Subject: [PATCH 7/7] fix agg metrics, don't use "for .. in .." on JS arrays Agg metrics were broken because we iterated over an array using "for .. in ..", which has unexpected consequences. "for .. in .." iterates over all the keys in an object. Arrays are a type of object, where the elements of the array are keyed by index. But they can have other properties too (like their methods) so when you use "for .. in .." you get everything. In general arrays should be iterated with "for .. of .." or ".forEach", but in this specific case I noticed we are basically just copying an array with some values substituted, so I opted for ".map". Note: There is repeated code across these two files that should obviously be refactored later, but for now I just want to get this bug fixed. --- www/js/metrics/CarbonFootprintCard.tsx | 13 ++++++------- www/js/metrics/CarbonTextCard.tsx | 13 ++++++------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/www/js/metrics/CarbonFootprintCard.tsx b/www/js/metrics/CarbonFootprintCard.tsx index 9624e10df..c40254256 100644 --- a/www/js/metrics/CarbonFootprintCard.tsx +++ b/www/js/metrics/CarbonFootprintCard.tsx @@ -131,15 +131,14 @@ const CarbonFootprintCard = ({ userMetrics, aggMetrics }: Props) => { // Issue 422: // https://github.com/e-mission/e-mission-docs/issues/422 - let aggCarbonData: MetricsSummary[] = []; - for (let i in aggThisWeekSummary) { - aggCarbonData.push(aggThisWeekSummary[i]); - if (isNaN(aggCarbonData[i].values)) { + let aggCarbonData: MetricsSummary[] = aggThisWeekSummary.map((summaryEntry) => { + if (isNaN(summaryEntry.values)) { logWarn(`WARNING in calculating groupCarbonRecords: value is NaN for mode - ${aggCarbonData[i].key}, changing to 0`); - aggCarbonData[i].values = 0; + ${summaryEntry.key}, changing to 0`); + summaryEntry.values = 0; } - } + return summaryEntry; + }); let groupRecords: { label: string; x: number | string; y: number | string }[] = []; diff --git a/www/js/metrics/CarbonTextCard.tsx b/www/js/metrics/CarbonTextCard.tsx index ca9f50fdc..225942af1 100644 --- a/www/js/metrics/CarbonTextCard.tsx +++ b/www/js/metrics/CarbonTextCard.tsx @@ -107,15 +107,14 @@ const CarbonTextCard = ({ userMetrics, aggMetrics }: Props) => { // Issue 422: // https://github.com/e-mission/e-mission-docs/issues/422 - let aggCarbonData: MetricsSummary[] = []; - for (let i in aggThisWeekSummary) { - aggCarbonData.push(aggThisWeekSummary[i]); - if (isNaN(aggCarbonData[i].values)) { + let aggCarbonData: MetricsSummary[] = aggThisWeekSummary.map((summaryEntry) => { + if (isNaN(summaryEntry.values)) { logWarn(`WARNING in calculating groupCarbonRecords: value is NaN for mode - ${aggCarbonData[i].key}, changing to 0`); - aggCarbonData[i].values = 0; + ${summaryEntry.key}, changing to 0`); + summaryEntry.values = 0; } - } + return summaryEntry; + }); let groupText: { label: string; value: string }[] = [];