-
-
Notifications
You must be signed in to change notification settings - Fork 56
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
pop-out-clock proof of concept #1247
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,91 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { hideTimerSeconds } from '../../../common/components/view-params-editor/constants'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { ViewOption } from '../../../common/components/view-params-editor/types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export const MINIMAL_TIMER_OPTIONS: ViewOption[] = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ section: 'Timer Options' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
hideTimerSeconds, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ section: 'Element visibility' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: 'hideovertime', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title: 'Hide Overtime', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: 'Whether to suppress overtime styles (red borders and red text)', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: 'boolean', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defaultValue: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: 'hideendmessage', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title: 'Hide End Message', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: 'Whether to hide end message and continue showing the clock if timer is in overtime', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: 'boolean', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defaultValue: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ section: 'View style override' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: 'key', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title: 'Key Colour', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: 'Background colour in hexadecimal', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
prefix: '#', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: 'string', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
placeholder: '00000000 (default)', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: 'text', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title: 'Text Colour', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: 'Text colour in hexadecimal', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
prefix: '#', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: 'string', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
placeholder: 'fffff (default)', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: 'textbg', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title: 'Text Background', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: 'Colour of text background in hexadecimal', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
prefix: '#', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: 'string', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
placeholder: '00000000 (default)', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: 'font', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title: 'Font', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: 'Font family, will use the fonts available in the system', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: 'string', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
placeholder: 'Arial Black (default)', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+22
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix inconsistency in text color placeholder. The "View style override" section is well-structured, providing comprehensive customization options. However, there's an inconsistency in the text color placeholder. Apply this change to fix the inconsistency: - placeholder: 'fffff (default)',
+ placeholder: 'ffffff (default)', This change ensures that the placeholder represents a valid 6-digit hexadecimal color code, consistent with the other color options. 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: 'size', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title: 'Text Size', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: 'Scales the current style (0.5 = 50% 1 = 100% 2 = 200%)', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: 'number', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
placeholder: '1 (default)', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: 'alignx', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title: 'Align Horizontal', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: 'Moves the horizontally in page to start = left | center | end = right', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: 'option', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
values: { start: 'Start', center: 'Center', end: 'End' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defaultValue: 'center', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: 'offsetx', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title: 'Offset Horizontal', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: 'Offsets the timer horizontal position by a given amount in pixels', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: 'number', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
placeholder: '0 (default)', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: 'aligny', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title: 'Align Vertical', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: 'Moves the vertically in page to start = left | center | end = right', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: 'option', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
values: { start: 'Start', center: 'Center', end: 'End' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defaultValue: 'center', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: 'offsety', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title: 'Offset Vertical', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: 'Offsets the timer vertical position by a given amount in pixels', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: 'number', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
placeholder: '0 (default)', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
@use '../../../theme/viewerDefs' as *; | ||
|
||
.minimal-timer { | ||
margin: 0; | ||
box-sizing: border-box; /* reset */ | ||
overflow: hidden; | ||
width: 100%; /* restrict the page width to viewport */ | ||
height: 100vh; | ||
transition: opacity 0.5s ease-in-out; | ||
|
||
background: var(--background-color-override, $viewer-background-color); | ||
color: var(--color-override, $viewer-color); | ||
display: grid; | ||
place-content: center; | ||
|
||
&--finished { | ||
outline: clamp(4px, 1vw, 16px) solid $timer-finished-color; | ||
outline-offset: calc(clamp(4px, 1vw, 16px) * -1); | ||
transition: $viewer-transition-time; | ||
} | ||
|
||
.timer { | ||
opacity: 1; | ||
font-family: var(--font-family-bold-override, $timer-bold-font-family) ; | ||
font-size: 20vw; | ||
position: relative; | ||
color: var(--timer-color-override, var(--phase-color)); | ||
transition: $viewer-transition-time; | ||
transition-property: opacity; | ||
background-color: transparent; | ||
letter-spacing: 0.05em; | ||
|
||
&--paused { | ||
opacity: $viewer-opacity-disabled; | ||
transition: $viewer-transition-time; | ||
} | ||
|
||
&--finished { | ||
color: $timer-finished-color; | ||
} | ||
} | ||
|
||
/* =================== OVERLAY ===================*/ | ||
|
||
.end-message { | ||
text-align: center; | ||
font-size: 12vw; | ||
line-height: 0.9em; | ||
font-weight: 600; | ||
color: $timer-finished-color; | ||
padding: 0; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,160 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { useEffect, useRef, useState } from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { getFormattedTimer, getTimerByType, isStringBoolean } from '../common/viewUtils'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { Playback, TimerPhase, TimerType, ViewSettings } from 'ontime-types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
Check failure on line 3 in apps/client/src/features/viewers/pop-out-clock/PopOutTimer.tsx GitHub Actions / unit-test
Check failure on line 3 in apps/client/src/features/viewers/pop-out-clock/PopOutTimer.tsx GitHub Actions / unit-test
|
||||||||||||||||||||||||||||||||||||||||||||||||||
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { useTranslation } from '../../../translation/TranslationProvider'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
import './PopOutTimer.scss'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
interface MinimalTimerProps { | ||||||||||||||||||||||||||||||||||||||||||||||||||
isMirrored: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||
time: ViewExtendedTimer; | ||||||||||||||||||||||||||||||||||||||||||||||||||
viewSettings: ViewSettings; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
export default function PopOutClock(props: MinimalTimerProps) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
const { isMirrored, time, viewSettings } = props; | ||||||||||||||||||||||||||||||||||||||||||||||||||
Check failure on line 18 in apps/client/src/features/viewers/pop-out-clock/PopOutTimer.tsx GitHub Actions / unit-test
|
||||||||||||||||||||||||||||||||||||||||||||||||||
const [ready, setReady] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||
const [videoSource, setVideoSource] = useState<string | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||
const canvasRef = useRef<HTMLCanvasElement | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||
const videoRef = useRef<HTMLVideoElement | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
const { getLocalizedString } = useTranslation(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
const stageTimer = getTimerByType(false, time); | ||||||||||||||||||||||||||||||||||||||||||||||||||
const display = getFormattedTimer(stageTimer, time.timerType, getLocalizedString('common.minutes'), { | ||||||||||||||||||||||||||||||||||||||||||||||||||
removeSeconds: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||
removeLeadingZero: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
let color = "#000000"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
let title = ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||
let clicked = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+34
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using The variables To maintain their values across renders, consider using Apply this diff to fix the issue: - let color = "#000000";
- let title = "";
- let clicked = false;
+ const colorRef = useRef("#000000");
+ const titleRef = useRef("");
+ const clickedRef = useRef(false); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
const canvas = canvasRef.current; | ||||||||||||||||||||||||||||||||||||||||||||||||||
const videoElement = videoRef.current; | ||||||||||||||||||||||||||||||||||||||||||||||||||
if (canvas && videoElement) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
const context = canvas.getContext('2d'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
if (context) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
changeVideo(color, title, context, canvas, videoElement); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
setReady(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
}, []); | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+38
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Variables In the If |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
const openPip = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
if (!videoRef.current) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||
clicked = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||
await videoRef.current.play(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
if (videoRef.current !== document.pictureInPictureElement) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||
await videoRef.current.requestPictureInPicture(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
console.error("Error: Unable to enter Picture-in-Picture mode:", error); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||
await document.exitPictureInPicture(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
console.error("Error: Unable to exit Picture-in-Picture mode:", error); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
const drawFrame = (color: string, text: string, context: CanvasRenderingContext2D, canvas: HTMLCanvasElement) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
context.fillStyle = color; | ||||||||||||||||||||||||||||||||||||||||||||||||||
context.fillRect(0, 0, canvas.width, canvas.height); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
context.font = "60px Arial"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
context.fillStyle = "white"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
const textWidth = context.measureText(text).width; | ||||||||||||||||||||||||||||||||||||||||||||||||||
const x = (canvas.width - textWidth) / 2; | ||||||||||||||||||||||||||||||||||||||||||||||||||
const y = canvas.height / 2 + 15; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
context.fillText(text, x, y); | ||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
const createVideoBlob = (canvas: HTMLCanvasElement, context: CanvasRenderingContext2D, callback: (url: string) => void) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
const stream = canvas.captureStream(30); | ||||||||||||||||||||||||||||||||||||||||||||||||||
const mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm' }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
const chunks: BlobPart[] = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
mediaRecorder.ondataavailable = (event) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
if (event.data.size > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
chunks.push(event.data); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
mediaRecorder.onstop = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
const blob = new Blob(chunks, { type: 'video/webm' }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
callback(URL.createObjectURL(blob)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
mediaRecorder.start(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
setTimeout(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
mediaRecorder.stop(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
}, 100); | ||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+83
to
+103
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Optimize video generation by using a continuous stream instead of creating blobs repeatedly Currently, Consider using the canvas stream directly as the source for the video element without creating new blobs. This can be achieved by assigning the canvas stream to the video element's Apply this diff to refactor the video handling: - createVideoBlob(canvas, context, (newVideoSource) => {
- if (videoSource) {
- URL.revokeObjectURL(videoSource);
- }
- setVideoSource(newVideoSource);
- videoElement.src = newVideoSource;
- videoElement.play().catch((error) => {
- console.error("Error playing video:", error);
- });
- });
+ const stream = canvas.captureStream(30);
+ videoElement.srcObject = stream;
+ videoElement.play().catch((error) => {
+ console.error("Error playing video:", error);
+ });
💡 Codebase verification Proper Cleanup of Media Resources is Not Fully Implemented
🔗 Analysis chainEnsure proper cleanup of media resources to prevent memory leaks When creating media streams and blobs, it's crucial to properly clean up resources to avoid memory leaks. Ensure that any streams, blobs, or object URLs are correctly released when no longer needed. Run the following script to check for proper cleanup of media resources: 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Search for any unreleased media resources in the codebase.
# Expectation: All created media streams and object URLs should be properly revoked or released.
rg --type js 'URL\.createObjectURL|captureStream' -A 5
Length of output: 56 Script: #!/bin/bash
# Description: Search for any unreleased media resources in JavaScript and TypeScript files.
# Expectation: All created media streams and object URLs should be properly revoked or released.
rg --type js --type ts --type jsx --type tsx 'URL\.createObjectURL|captureStream' -A 5
Length of output: 116 Script: #!/bin/bash
# Description: Search for any unreleased media resources in JavaScript and TypeScript files, including JSX and TSX.
# Define custom types for jsx and tsx
rg --type-add 'jsx:*.jsx' --type-add 'tsx:*.tsx' 'URL\.createObjectURL|captureStream' -t js -t ts -t jsx -t tsx -A 5
Length of output: 1906 |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
const changeVideo = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
color: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||
text: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||
context: CanvasRenderingContext2D, | ||||||||||||||||||||||||||||||||||||||||||||||||||
canvas: HTMLCanvasElement, | ||||||||||||||||||||||||||||||||||||||||||||||||||
videoElement: HTMLVideoElement | ||||||||||||||||||||||||||||||||||||||||||||||||||
) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
drawFrame(color, text, context, canvas); | ||||||||||||||||||||||||||||||||||||||||||||||||||
createVideoBlob(canvas, context, (newVideoSource) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
if (videoSource) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
URL.revokeObjectURL(videoSource); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
setVideoSource(newVideoSource); | ||||||||||||||||||||||||||||||||||||||||||||||||||
videoElement.src = newVideoSource; | ||||||||||||||||||||||||||||||||||||||||||||||||||
videoElement.play().catch((error) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
console.error("Error playing video:", error); | ||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
if (ready && canvasRef.current && videoRef.current) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
const canvas = canvasRef.current; | ||||||||||||||||||||||||||||||||||||||||||||||||||
const context = canvas.getContext('2d'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
let i = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||
const interval = setInterval(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
changeVideo("green", display, context!, canvas, videoRef.current!); | ||||||||||||||||||||||||||||||||||||||||||||||||||
i++; | ||||||||||||||||||||||||||||||||||||||||||||||||||
}, 1000); | ||||||||||||||||||||||||||||||||||||||||||||||||||
return () => clearInterval(interval); // Clean up the interval on component unmount | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
}, [ready]); | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+125
to
+136
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider updating the The Update the dependency array and adjust the effect: - }, [ready, display]);
+ }, [ready, time]);
Include dependencies in the The Consider adding Apply this diff to fix the dependency array: - }, [ready]);
+ }, [ready, display]); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
<div> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<div>{display}</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<canvas | ||||||||||||||||||||||||||||||||||||||||||||||||||
ref={canvasRef} | ||||||||||||||||||||||||||||||||||||||||||||||||||
id="canvas" | ||||||||||||||||||||||||||||||||||||||||||||||||||
width="640" | ||||||||||||||||||||||||||||||||||||||||||||||||||
height="360" | ||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<video | ||||||||||||||||||||||||||||||||||||||||||||||||||
ref={videoRef} | ||||||||||||||||||||||||||||||||||||||||||||||||||
id="pip-video" | ||||||||||||||||||||||||||||||||||||||||||||||||||
loop | ||||||||||||||||||||||||||||||||||||||||||||||||||
controls | ||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||
{videoSource && <source src={videoSource} type="video/webm" />} | ||||||||||||||||||||||||||||||||||||||||||||||||||
</video> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<button onClick={openPip}> | ||||||||||||||||||||||||||||||||||||||||||||||||||
Picture-in-Picture | ||||||||||||||||||||||||||||||||||||||||||||||||||
</button> | ||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider refactoring hardcoded values in PopOutTimer props.
While the placement of the
PopOutTimer
component is correct, there are a few points to consider:time
prop contains many hardcoded values. This could lead to maintenance issues and might not reflect the actual state of the application.viewSettings
prop has empty strings for colors and messages.Given that this is a proof of concept, these issues are understandable. However, for the next iteration, consider:
time
prop to your application's state management system (e.g., Redux, Context API) to reflect real-time values.viewSettings
to make them easily customizable.Would you like assistance in setting up a more dynamic prop structure for the
PopOutTimer
component?