diff --git a/ts/components/lightbox/Lightbox.tsx b/ts/components/lightbox/Lightbox.tsx index 20f55228a8..39a529ce9f 100644 --- a/ts/components/lightbox/Lightbox.tsx +++ b/ts/components/lightbox/Lightbox.tsx @@ -23,6 +23,7 @@ import { AriaLabels } from '../../util/hardcodedAriaLabels'; import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; import { SessionLucideIconButton } from '../icon/SessionIconButton'; import { SessionFocusTrap } from '../SessionFocusTrap'; +import { LightboxVideo } from './LightboxVideo'; type Props = { contentType: MIME.MIMEType | undefined; @@ -443,9 +444,12 @@ const LightboxObject = ({ } return ( - + ); } diff --git a/ts/components/lightbox/LightboxVideo.tsx b/ts/components/lightbox/LightboxVideo.tsx new file mode 100644 index 0000000000..d5fd49effc --- /dev/null +++ b/ts/components/lightbox/LightboxVideo.tsx @@ -0,0 +1,39 @@ +import type { CSSProperties, Ref, SyntheticEvent } from 'react'; + +import { SettingsKey } from '../../data/settings-key'; + +type Props = { + renderedRef: Ref; + style: CSSProperties; + urlToLoad: string | undefined; +}; + +const isValidVolume = (volume: unknown): volume is number => + typeof volume === 'number' && Number.isFinite(volume) && volume >= 0 && volume <= 1; + +export const LightboxVideo = ({ renderedRef, style, urlToLoad }: Props) => { + const handleLoadedMetadata = (event: SyntheticEvent) => { + const savedVolume = window.getSettingValue(SettingsKey.lightboxVideoVolume); + if (isValidVolume(savedVolume)) { + const video = event.currentTarget; + video.volume = savedVolume; + } + }; + + const handleVolumeChange = (event: SyntheticEvent) => { + void window.setSettingValue(SettingsKey.lightboxVideoVolume, event.currentTarget.volume); + }; + + return ( + + ); +}; diff --git a/ts/data/settings-key.ts b/ts/data/settings-key.ts index df01d4e9b7..21aba9238f 100644 --- a/ts/data/settings-key.ts +++ b/ts/data/settings-key.ts @@ -63,6 +63,7 @@ export const SettingsKey = { proLongerMessagesSent, proBadgesSent, audioAutoplay: 'audioAutoplay', + lightboxVideoVolume: 'lightboxVideoVolume', showRecoveryPhrasePrompt: 'showRecoveryPhrasePrompt', dismissedRecoveryPhrasePrompt: 'dismissedRecoveryPhrasePrompt', hideMessageRequests: 'hideMessageRequests', diff --git a/ts/test/components/LightboxVideo_test.tsx b/ts/test/components/LightboxVideo_test.tsx new file mode 100644 index 0000000000..2b163a6c67 --- /dev/null +++ b/ts/test/components/LightboxVideo_test.tsx @@ -0,0 +1,66 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { fireEvent } from '@testing-library/react'; +import { expect } from 'chai'; +import { createRef } from 'react'; +import Sinon from 'sinon'; + +import { LightboxVideo } from '../../components/lightbox/LightboxVideo'; +import { SettingsKey } from '../../data/settings-key'; +import { findAllByTagName, renderComponent } from './renderComponent'; + +describe('LightboxVideo', () => { + const getSettingValue = Sinon.stub(); + const setSettingValue = Sinon.stub().resolves(); + const originalGetSettingValue = window.getSettingValue; + const originalSetSettingValue = window.setSettingValue; + + beforeEach(() => { + getSettingValue.reset(); + setSettingValue.resetHistory(); + window.getSettingValue = getSettingValue; + window.setSettingValue = setSettingValue; + }); + + afterEach(() => { + window.getSettingValue = originalGetSettingValue; + window.setSettingValue = originalSetSettingValue; + }); + + const renderVideo = () => { + const result = renderComponent( + + ); + const [video] = findAllByTagName(result, 'video'); + return { result, video }; + }; + + it('restores the saved volume when the video metadata loads', () => { + getSettingValue.withArgs(SettingsKey.lightboxVideoVolume).returns(0.35); + const { result, video } = renderVideo(); + + fireEvent.loadedMetadata(video); + + expect(video.volume).to.equal(0.35); + result.unmount(); + }); + + it('ignores an invalid saved volume', () => { + getSettingValue.withArgs(SettingsKey.lightboxVideoVolume).returns(2); + const { result, video } = renderVideo(); + + fireEvent.loadedMetadata(video); + + expect(video.volume).to.equal(1); + result.unmount(); + }); + + it('saves volume changes', () => { + const { result, video } = renderVideo(); + video.volume = 0.42; + + fireEvent.volumeChange(video); + + expect(setSettingValue.calledWithExactly(SettingsKey.lightboxVideoVolume, 0.42)).to.equal(true); + result.unmount(); + }); +});