mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-05 22:39:11 +00:00
refactor: unify progress bar logic
This commit is contained in:
committed by
Carlos Valente
parent
c3fb3061f6
commit
347f333b3e
@@ -1,12 +1,12 @@
|
|||||||
import { MaybeNumber } from 'ontime-types';
|
import { MaybeNumber } from 'ontime-types';
|
||||||
|
|
||||||
import { clamp } from '../../utils/math';
|
import { getProgress } from '../../utils/getProgress';
|
||||||
|
|
||||||
import './MultiPartProgressBar.scss';
|
import './MultiPartProgressBar.scss';
|
||||||
|
|
||||||
interface MultiPartProgressBar {
|
interface MultiPartProgressBar {
|
||||||
now: MaybeNumber;
|
now: MaybeNumber;
|
||||||
complete: number;
|
complete: MaybeNumber;
|
||||||
normalColor: string;
|
normalColor: string;
|
||||||
warning?: MaybeNumber;
|
warning?: MaybeNumber;
|
||||||
warningColor: string;
|
warningColor: string;
|
||||||
@@ -31,10 +31,9 @@ export default function MultiPartProgressBar(props: MultiPartProgressBar) {
|
|||||||
className = '',
|
className = '',
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const percentRemaining = complete === 0 ? 0 : 100 - clamp(100 - (Math.max(now ?? 0, 0) * 100) / complete, 0, 100);
|
const percentRemaining = 100 - getProgress(now, complete);
|
||||||
|
const dangerWidth = danger ? 100 - getProgress(danger, complete) : 0;
|
||||||
const dangerWidth = danger ? clamp((danger / complete) * 100, 0, 100) : 0;
|
const warningWidth = warning ? 100 - dangerWidth - getProgress(warning, complete) : 0;
|
||||||
const warningWidth = warning ? clamp((warning / complete) * 100 - dangerWidth, 0, 100) : 0;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
import { clamp } from '../../utils/math';
|
import { MaybeNumber } from 'ontime-types';
|
||||||
|
|
||||||
|
import { getProgress } from '../../utils/getProgress';
|
||||||
|
|
||||||
import './ProgressBar.scss';
|
import './ProgressBar.scss';
|
||||||
|
|
||||||
interface ProgressBarProps {
|
interface ProgressBarProps {
|
||||||
now?: number;
|
current: MaybeNumber;
|
||||||
complete?: number;
|
duration: MaybeNumber;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ProgressBar(props: ProgressBarProps) {
|
export default function ProgressBar(props: ProgressBarProps) {
|
||||||
const { now = 0, complete = 100, hidden, className = '' } = props;
|
const { current, duration, hidden, className = '' } = props;
|
||||||
|
const progress = getProgress(current, duration);
|
||||||
const percentComplete = clamp(100 - (Math.max(now, 0) * 100) / complete, 0, 100);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`progress-bar__bg ${hidden ? 'progress-bar__bg--hidden' : ''} ${className}`}>
|
<div className={`progress-bar__bg ${hidden ? 'progress-bar__bg--hidden' : ''} ${className}`}>
|
||||||
<div className='progress-bar__indicator' style={{ width: `${percentComplete}%` }} />
|
<div className='progress-bar__indicator' style={{ width: `${progress}%` }} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,7 +150,6 @@ export const useClock = () => {
|
|||||||
/** Used by the progress bar components */
|
/** Used by the progress bar components */
|
||||||
export const useProgressData = () => {
|
export const useProgressData = () => {
|
||||||
const featureSelector = (state: RuntimeStore) => ({
|
const featureSelector = (state: RuntimeStore) => ({
|
||||||
addedTime: state.timer.addedTime,
|
|
||||||
current: state.timer.current,
|
current: state.timer.current,
|
||||||
duration: state.timer.duration,
|
duration: state.timer.duration,
|
||||||
timeWarning: state.eventNow?.timeWarning ?? null,
|
timeWarning: state.eventNow?.timeWarning ?? null,
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { MaybeNumber } from 'ontime-types';
|
||||||
|
|
||||||
|
import { clamp } from './math';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns completion percentage of a progress bar
|
||||||
|
* This code assumes the current time and duration have addedTime already applied
|
||||||
|
*/
|
||||||
|
export function getProgress(current: MaybeNumber, duration: MaybeNumber) {
|
||||||
|
if (current === null || duration === null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current <= 0) {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current >= duration) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clamp(((duration - current) / duration) * 100, 0, 100);
|
||||||
|
}
|
||||||
@@ -6,18 +6,17 @@ import styles from './CuesheetProgress.module.scss';
|
|||||||
|
|
||||||
export default function CuesheetProgress() {
|
export default function CuesheetProgress() {
|
||||||
const { data } = useViewSettings();
|
const { data } = useViewSettings();
|
||||||
const { addedTime, current, duration, timeWarning, timeDanger } = useProgressData();
|
const { current, duration, timeWarning, timeDanger } = useProgressData();
|
||||||
const totalTime = (duration ?? 0) + (addedTime ?? 0);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MultiPartProgressBar
|
<MultiPartProgressBar
|
||||||
now={current}
|
now={current}
|
||||||
complete={totalTime}
|
complete={duration}
|
||||||
normalColor={data!.normalColor}
|
normalColor={data.normalColor}
|
||||||
warning={timeWarning}
|
warning={timeWarning}
|
||||||
warningColor={data!.warningColor}
|
warningColor={data.warningColor}
|
||||||
danger={timeDanger}
|
danger={timeDanger}
|
||||||
dangerColor={data!.dangerColor}
|
dangerColor={data.dangerColor}
|
||||||
className={styles.progressOverride}
|
className={styles.progressOverride}
|
||||||
ignoreCssOverride
|
ignoreCssOverride
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -11,13 +11,12 @@ interface StatusBarProgressProps {
|
|||||||
|
|
||||||
export default function StatusBarProgress(props: StatusBarProgressProps) {
|
export default function StatusBarProgress(props: StatusBarProgressProps) {
|
||||||
const { viewSettings } = props;
|
const { viewSettings } = props;
|
||||||
const { addedTime, current, duration, timeWarning, timeDanger } = useProgressData();
|
const { current, duration, timeWarning, timeDanger } = useProgressData();
|
||||||
const totalTime = (duration ?? 0) + (addedTime ?? 0);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MultiPartProgressBar
|
<MultiPartProgressBar
|
||||||
now={current}
|
now={current}
|
||||||
complete={totalTime}
|
complete={duration}
|
||||||
normalColor={viewSettings.normalColor}
|
normalColor={viewSettings.normalColor}
|
||||||
warning={timeWarning}
|
warning={timeWarning}
|
||||||
warningColor={viewSettings.warningColor}
|
warningColor={viewSettings.warningColor}
|
||||||
|
|||||||
@@ -1,29 +1,12 @@
|
|||||||
import { MaybeNumber } from 'ontime-types';
|
|
||||||
|
|
||||||
import { useTimer } from '../../../../common/hooks/useSocket';
|
import { useTimer } from '../../../../common/hooks/useSocket';
|
||||||
import { clamp } from '../../../../common/utils/math';
|
import { getProgress } from '../../../../common/utils/getProgress';
|
||||||
|
|
||||||
import style from './EventBlockProgressBar.module.scss';
|
import style from './EventBlockProgressBar.module.scss';
|
||||||
|
|
||||||
export function getPercentComplete(remaining: MaybeNumber, total: MaybeNumber): number {
|
|
||||||
if (remaining === null || total === null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remaining <= 0) {
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remaining === total) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return clamp(100 - (remaining * 100) / total, 0, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function EventBlockProgressBar() {
|
export default function EventBlockProgressBar() {
|
||||||
const timer = useTimer();
|
const timer = useTimer();
|
||||||
|
|
||||||
const progress = `${getPercentComplete(timer.current, timer.duration)}%`;
|
const progress = getProgress(timer.current, timer.duration);
|
||||||
return <div className={style.progressBar} style={{ width: progress }} />;
|
|
||||||
|
return <div className={style.progressBar} style={{ width: `${progress}%` }} />;
|
||||||
}
|
}
|
||||||
|
|||||||
-27
@@ -1,27 +0,0 @@
|
|||||||
import { dayInMs } from 'ontime-utils';
|
|
||||||
|
|
||||||
import { getPercentComplete } from '../EventBlockProgressBar';
|
|
||||||
|
|
||||||
describe('getPercentComplete()', () => {
|
|
||||||
describe('calculates progress in normal cases', () => {
|
|
||||||
const testScenarios = [
|
|
||||||
{ current: 0, duration: 0, expect: 100 },
|
|
||||||
{ current: 0, duration: 100, expect: 100 },
|
|
||||||
{ current: 0, duration: dayInMs, expect: 100 },
|
|
||||||
{ current: 10, duration: 100, expect: 90 },
|
|
||||||
{ current: 50, duration: 100, expect: 50 },
|
|
||||||
{ current: 100, duration: 100, expect: 0 },
|
|
||||||
];
|
|
||||||
|
|
||||||
testScenarios.forEach((testCase) => {
|
|
||||||
it(`handles ${testCase.current} / ${testCase.duration}`, () => {
|
|
||||||
const progress = getPercentComplete(testCase.current, testCase.duration);
|
|
||||||
expect(progress).toBe(testCase.expect);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('is 0 if we dont have a current or duration', () => {
|
|
||||||
const progress = getPercentComplete(null, null);
|
|
||||||
expect(progress).toBe(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -94,7 +94,6 @@ export default function Backstage(props: BackstageProps) {
|
|||||||
let stageTimer = millisToString(time.current, { fallback: timerPlaceholderMin });
|
let stageTimer = millisToString(time.current, { fallback: timerPlaceholderMin });
|
||||||
stageTimer = removeLeadingZero(stageTimer);
|
stageTimer = removeLeadingZero(stageTimer);
|
||||||
|
|
||||||
const totalTime = (time.duration ?? 0) + (time.addedTime ?? 0);
|
|
||||||
const defaultFormat = getDefaultFormat(settings?.timeFormat);
|
const defaultFormat = getDefaultFormat(settings?.timeFormat);
|
||||||
const backstageOptions = getBackstageOptions(defaultFormat, customFields);
|
const backstageOptions = getBackstageOptions(defaultFormat, customFields);
|
||||||
|
|
||||||
@@ -111,8 +110,8 @@ export default function Backstage(props: BackstageProps) {
|
|||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
className='progress-container'
|
className='progress-container'
|
||||||
now={time.current ?? undefined}
|
current={time.current}
|
||||||
complete={totalTime}
|
duration={time.duration}
|
||||||
hidden={!showProgress}
|
hidden={!showProgress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user