made mute button global
This commit is contained in:
parent
9d7e6f6cd2
commit
7a72117b6a
@ -45,6 +45,7 @@ import { usePageNavigationState } from '../hooks/usePageNavigationState';
|
|||||||
import { useTransitionPlayback } from '../hooks/useTransitionPlayback';
|
import { useTransitionPlayback } from '../hooks/useTransitionPlayback';
|
||||||
import { useNetworkAware } from '../hooks/useNetworkAware';
|
import { useNetworkAware } from '../hooks/useNetworkAware';
|
||||||
import { resolveAssetPlaybackUrl } from '../lib/assetUrl';
|
import { resolveAssetPlaybackUrl } from '../lib/assetUrl';
|
||||||
|
import { presentationHasAudio } from '../lib/presentationAudio';
|
||||||
import { downloadManager } from '../lib/offline/DownloadManager';
|
import { downloadManager } from '../lib/offline/DownloadManager';
|
||||||
import { isSafari } from '../lib/browserUtils';
|
import { isSafari } from '../lib/browserUtils';
|
||||||
import { logger } from '../lib/logger';
|
import { logger } from '../lib/logger';
|
||||||
@ -817,39 +818,9 @@ export default function RuntimePresentation({
|
|||||||
selectedPage?.background_audio_end_time != null
|
selectedPage?.background_audio_end_time != null
|
||||||
? parseFloat(String(selectedPage.background_audio_end_time))
|
? parseFloat(String(selectedPage.background_audio_end_time))
|
||||||
: null;
|
: null;
|
||||||
const hasElementAudio = useMemo(
|
const hasPresentationAudio = useMemo(
|
||||||
() =>
|
() => presentationHasAudio(pages),
|
||||||
pageElements.some((element) => {
|
[pages],
|
||||||
if (element.hoverAudioUrl || element.clickAudioUrl) return true;
|
|
||||||
if (
|
|
||||||
(element.type === 'audio_player' ||
|
|
||||||
element.type === 'video_player') &&
|
|
||||||
element.mediaUrl &&
|
|
||||||
!element.mediaMuted
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
element.galleryCards?.some(
|
|
||||||
(card: GalleryCarouselMediaItem) =>
|
|
||||||
card.mediaType === 'video' || Boolean(card.videoUrl),
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
element.infoPanelSections?.some((section) =>
|
|
||||||
section.images?.some(
|
|
||||||
(item: InfoPanelImage) =>
|
|
||||||
item.itemType === 'video' || Boolean(item.videoUrl),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}),
|
|
||||||
[pageElements],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Global sound control starts muted for browser autoplay compatibility.
|
// Global sound control starts muted for browser autoplay compatibility.
|
||||||
@ -857,7 +828,7 @@ export default function RuntimePresentation({
|
|||||||
pageHasSound: pageVideoMuted === false,
|
pageHasSound: pageVideoMuted === false,
|
||||||
hasBackgroundVideo: Boolean(backgroundVideoUrl),
|
hasBackgroundVideo: Boolean(backgroundVideoUrl),
|
||||||
hasBackgroundAudio: Boolean(backgroundAudioUrl),
|
hasBackgroundAudio: Boolean(backgroundAudioUrl),
|
||||||
hasElementAudio,
|
hasPresentationAudio,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Note: useBackgroundVideoPlayback is handled internally by CanvasBackground component
|
// Note: useBackgroundVideoPlayback is handled internally by CanvasBackground component
|
||||||
|
|||||||
@ -24,6 +24,8 @@ export interface UseVideoSoundControlOptions {
|
|||||||
hasBackgroundAudio?: boolean;
|
hasBackgroundAudio?: boolean;
|
||||||
/** Whether page elements have hover/click audio effects or media player sound */
|
/** Whether page elements have hover/click audio effects or media player sound */
|
||||||
hasElementAudio?: boolean;
|
hasElementAudio?: boolean;
|
||||||
|
/** Whether any page in the presentation can produce sound */
|
||||||
|
hasPresentationAudio?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UseVideoSoundControlResult {
|
export interface UseVideoSoundControlResult {
|
||||||
@ -61,6 +63,7 @@ export function useVideoSoundControl({
|
|||||||
hasBackgroundVideo,
|
hasBackgroundVideo,
|
||||||
hasBackgroundAudio = false,
|
hasBackgroundAudio = false,
|
||||||
hasElementAudio = false,
|
hasElementAudio = false,
|
||||||
|
hasPresentationAudio = false,
|
||||||
}: UseVideoSoundControlOptions): UseVideoSoundControlResult {
|
}: UseVideoSoundControlOptions): UseVideoSoundControlResult {
|
||||||
const { isMuted } = useGlobalAudioMute();
|
const { isMuted } = useGlobalAudioMute();
|
||||||
|
|
||||||
@ -71,6 +74,7 @@ export function useVideoSoundControl({
|
|||||||
return {
|
return {
|
||||||
isMuted,
|
isMuted,
|
||||||
showSoundButton:
|
showSoundButton:
|
||||||
|
hasPresentationAudio ||
|
||||||
(pageHasSound && hasBackgroundVideo) ||
|
(pageHasSound && hasBackgroundVideo) ||
|
||||||
hasBackgroundAudio ||
|
hasBackgroundAudio ||
|
||||||
hasElementAudio,
|
hasElementAudio,
|
||||||
|
|||||||
75
frontend/src/lib/presentationAudio.ts
Normal file
75
frontend/src/lib/presentationAudio.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import type { CanvasElement, ConstructorSchema } from '../types/constructor';
|
||||||
|
import type { TourPage } from '../types/entities';
|
||||||
|
import { parseJsonObject } from './parseJson';
|
||||||
|
|
||||||
|
type PageWithAudioFields = Pick<
|
||||||
|
TourPage,
|
||||||
|
| 'background_audio_url'
|
||||||
|
| 'background_video_url'
|
||||||
|
| 'background_video_muted'
|
||||||
|
| 'ui_schema_json'
|
||||||
|
>;
|
||||||
|
|
||||||
|
const asRecords = (value: unknown): Record<string, unknown>[] =>
|
||||||
|
Array.isArray(value)
|
||||||
|
? value.filter(
|
||||||
|
(item): item is Record<string, unknown> =>
|
||||||
|
Boolean(item) && typeof item === 'object',
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const elementHasAudio = (element: Partial<CanvasElement>): boolean => {
|
||||||
|
if (element.hoverAudioUrl || element.clickAudioUrl) return true;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(element.type === 'audio_player' || element.type === 'video_player') &&
|
||||||
|
element.mediaUrl &&
|
||||||
|
!element.mediaMuted
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const galleryCards = asRecords(element.galleryCards);
|
||||||
|
if (
|
||||||
|
galleryCards.some(
|
||||||
|
(card) => card.mediaType === 'video' || Boolean(card.videoUrl),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const infoPanelSections = asRecords(element.infoPanelSections);
|
||||||
|
if (
|
||||||
|
infoPanelSections.some((section) =>
|
||||||
|
asRecords(section.images).some(
|
||||||
|
(item) => item.itemType === 'video' || Boolean(item.videoUrl),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const elementsHaveAudio = (
|
||||||
|
elements: Array<Partial<CanvasElement>> = [],
|
||||||
|
): boolean => elements.some(elementHasAudio);
|
||||||
|
|
||||||
|
export const pageHasAudio = (page: PageWithAudioFields): boolean => {
|
||||||
|
if (page.background_audio_url) return true;
|
||||||
|
if (page.background_video_url && page.background_video_muted === false) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const schema = parseJsonObject<ConstructorSchema>(
|
||||||
|
page.ui_schema_json,
|
||||||
|
{} as ConstructorSchema,
|
||||||
|
);
|
||||||
|
return Array.isArray(schema.elements) && elementsHaveAudio(schema.elements);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const presentationHasAudio = (
|
||||||
|
pages: PageWithAudioFields[] = [],
|
||||||
|
extraElements: Array<Partial<CanvasElement>> = [],
|
||||||
|
): boolean => pages.some(pageHasAudio) || elementsHaveAudio(extraElements);
|
||||||
@ -48,6 +48,7 @@ import { backgroundAudioController } from '../lib/backgroundAudioController';
|
|||||||
import { isSafari } from '../lib/browserUtils';
|
import { isSafari } from '../lib/browserUtils';
|
||||||
import { resolveAssetPlaybackUrl } from '../lib/assetUrl';
|
import { resolveAssetPlaybackUrl } from '../lib/assetUrl';
|
||||||
import { downloadManager } from '../lib/offline/DownloadManager';
|
import { downloadManager } from '../lib/offline/DownloadManager';
|
||||||
|
import { presentationHasAudio } from '../lib/presentationAudio';
|
||||||
import { parseJsonObject } from '../lib/parseJson';
|
import { parseJsonObject } from '../lib/parseJson';
|
||||||
import {
|
import {
|
||||||
resolveNavigationTarget,
|
resolveNavigationTarget,
|
||||||
@ -366,39 +367,18 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
[elements],
|
[elements],
|
||||||
);
|
);
|
||||||
|
|
||||||
const hasElementAudio = useMemo(
|
const hasPresentationAudio = useMemo(
|
||||||
() =>
|
() =>
|
||||||
elements.some((element) => {
|
presentationHasAudio(pages, elements) ||
|
||||||
if (element.hoverAudioUrl || element.clickAudioUrl) return true;
|
Boolean(backgroundAudioUrl) ||
|
||||||
if (
|
Boolean(backgroundVideoUrl && backgroundVideoMuted === false),
|
||||||
(element.type === 'audio_player' ||
|
[
|
||||||
element.type === 'video_player') &&
|
pages,
|
||||||
element.mediaUrl &&
|
elements,
|
||||||
!element.mediaMuted
|
backgroundAudioUrl,
|
||||||
) {
|
backgroundVideoUrl,
|
||||||
return true;
|
backgroundVideoMuted,
|
||||||
}
|
],
|
||||||
if (
|
|
||||||
element.galleryCards?.some(
|
|
||||||
(card: GalleryCarouselMediaItem) =>
|
|
||||||
card.mediaType === 'video' || Boolean(card.videoUrl),
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
element.infoPanelSections?.some((section) =>
|
|
||||||
section.images?.some(
|
|
||||||
(item: InfoPanelImage) =>
|
|
||||||
item.itemType === 'video' || Boolean(item.videoUrl),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}),
|
|
||||||
[elements],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Global sound control starts muted for browser autoplay compatibility.
|
// Global sound control starts muted for browser autoplay compatibility.
|
||||||
@ -406,7 +386,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
pageHasSound: backgroundVideoMuted === false,
|
pageHasSound: backgroundVideoMuted === false,
|
||||||
hasBackgroundVideo: Boolean(backgroundVideoUrl),
|
hasBackgroundVideo: Boolean(backgroundVideoUrl),
|
||||||
hasBackgroundAudio: Boolean(backgroundAudioUrl),
|
hasBackgroundAudio: Boolean(backgroundAudioUrl),
|
||||||
hasElementAudio,
|
hasPresentationAudio,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Look up current element for gallery carousel (so it receives updates from element editor)
|
// Look up current element for gallery carousel (so it receives updates from element editor)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user