diff --git a/src/components/TimeDisplay/index.jsx b/src/components/TimeDisplay/index.jsx index 1a340b1a4..5ae789e78 100644 --- a/src/components/TimeDisplay/index.jsx +++ b/src/components/TimeDisplay/index.jsx @@ -2,7 +2,6 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import Obstruction from 'obstruction'; import raf from 'raf'; -import dayjs from 'dayjs'; import { withStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; @@ -14,7 +13,7 @@ import { Tooltip } from '@material-ui/core'; import { DownArrow, Forward10, Pause, PlayArrow, Replay10, UpArrow } from '../../icons'; import { currentOffset } from '../../timeline'; import { seek, play, pause } from '../../timeline/playback'; -import { getSegmentNumber } from '../../utils'; +import { formatVideoTime, getSegmentNumber } from '../../utils'; import { isIos } from '../../utils/browser.js'; const timerSteps = [ @@ -35,7 +34,7 @@ const styles = (theme) => ({ height: '64px', borderRadius: '32px', padding: theme.spacing.unit, - width: 400, + width: 500, maxWidth: '100%', margin: '0 auto', opacity: 0, @@ -141,11 +140,11 @@ class TimeDisplay extends Component { getDisplayTime() { const offset = currentOffset(); const { currentRoute } = this.props; - const now = new Date(offset + currentRoute.start_time_utc_millis); - if (Number.isNaN(now.getTime())) { - return '...'; + let dateString = formatVideoTime(offset); + if (currentRoute && currentRoute.start_time_utc_millis && currentRoute.end_time_utc_millis) { + const routeDuration = currentRoute.end_time_utc_millis - currentRoute.start_time_utc_millis; + dateString = `${dateString} / ${formatVideoTime(routeDuration)}`; } - let dateString = dayjs(now).format('HH:mm:ss'); const seg = getSegmentNumber(currentRoute); if (seg !== null) { dateString = `${dateString} \u2013 ${seg}`; diff --git a/src/utils/index.js b/src/utils/index.js index ac8b67171..c5ad15a2b 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -47,6 +47,18 @@ export function formatDriveDuration(duration) { return `${hours > 0 ? `${hours} hr ` : ''}${minutes} min`; } +export function formatVideoTime(offset) { + const totalSeconds = Math.floor(offset / 1000); + const hours = Math.floor(totalSeconds / 3600); + const minutes = Math.floor((totalSeconds % 3600) / 60); + const seconds = totalSeconds % 60; + const pad = (n) => n.toString().padStart(2, '0'); + if (hours === 0) { + return `${pad(minutes)}:${pad(seconds)}`; + } + return `${hours}:${pad(minutes)}:${pad(seconds)}`; +} + export function timeFromNow(ts) { const dt = (Date.now() - ts) / 1000; if (dt > 3600 * 24 * 30) { diff --git a/src/utils/utils.test.js b/src/utils/utils.test.js index 188886652..d24d74534 100644 --- a/src/utils/utils.test.js +++ b/src/utils/utils.test.js @@ -1,5 +1,5 @@ /* eslint-env jest */ -import { deviceVersionAtLeast, formatDriveDuration } from '.'; +import { deviceVersionAtLeast, formatDriveDuration, formatOffset } from '.'; test('formats durations correctly', () => { // 1 hour, 59 minutes, 59 seconds @@ -23,6 +23,20 @@ test('formats durations correctly', () => { expect(fourFormatted).toEqual('0 min'); }); +test('formats offsets correctly', () => { + // 1 hour, 23 minutes, 45 seconds + expect(formatOffset(1 * 60 * 60 * 1000 + 23 * 60 * 1000 + 45 * 1000)).toEqual('1:23:45'); + + // 5 minutes, 9 seconds (hours omitted when zero) + expect(formatOffset(5 * 60 * 1000 + 9 * 1000)).toEqual('05:09'); + + // 3 seconds (drops sub-second milliseconds) + expect(formatOffset(3 * 1000 + 500)).toEqual('00:03'); + + // zero + expect(formatOffset(0)).toEqual('00:00'); +}); + test('compares versions correctly', () => { const device = (version) => ({ openpilot_version: version }); expect(deviceVersionAtLeast(device('0.8.0'), '0.0.1')).toEqual(true);