UNPKG

@applicaster/zapp-react-native-utils

Version:

Applicaster Zapp React Native utilities package

278 lines (225 loc) • 7.52 kB
import { BehaviorSubject } from "rxjs"; import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage"; import { isLgPlatform, isSamsungPlatform, } from "@applicaster/zapp-react-dom-app/App/Loader/utils/platform"; import { PLATFORM_KEYS, PLATFORMS, ZappPlatform } from "./const"; import { createLogger, utilsLogger } from "../../logger"; import { getPlatform } from "../../reactUtils"; import { appStore } from "@applicaster/zapp-react-native-redux/AppStore"; import { calculateReadingTime } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/utils"; const { log_debug } = createLogger({ category: "General", subsystem: "PlatformUtils", parent: utilsLogger, }); export const getZappPlatform = (): ZappPlatform => { const platform = appStore.get("appData")?.platform; switch (platform) { case "amazon_fire_tv": return ZappPlatform.AmazonFireTV; case ZappPlatform.Vizio: return ZappPlatform.Vizio; default: // TODO: Use only ZappPlatform enum return getPlatform() as ZappPlatform; } }; export const getUserAgent = () => window?.navigator?.userAgent; /** VIZIO UTILS */ /** * Checks if we are on the Vizio platform by using the userAgent string * * Use this method when you need to identify the platform on runtime * before the VIZIO Companion Library has loaded */ export const isVizioPlatform = () => { const userAgent = getUserAgent(); if (!userAgent) return false; const isVizioAgent = userAgent.includes(PLATFORMS.vizio) || userAgent.includes(PLATFORMS.smartcast) || userAgent.includes(PLATFORMS.conjure); return isVizioAgent; }; /** * Checks if we are on the Vizio platform by checking for the global VIZIO object * and the VIZIO Companion Library. This method does not use the userAgent string, * because it mainly checks whether we have access to apis, which may not be available yet */ export const hasVizioAPIs = () => { const hasAPIs = typeof window.VIZIO !== "undefined" && window?.applicaster?.vizioLibraryDidLoad; return hasAPIs; }; /** * Manages device based closed captioning state * Returns an observable that emits the current state and updates whenever it changes */ export class ClosedCaptioningManager { private ccState$ = new BehaviorSubject<boolean>(false); private static ccManagerInstance: ClosedCaptioningManager; private constructor() { this.initialize(); window["vizioDebug"] = { setCCEnabled: (isCCEnabled: boolean) => { this.ccState$.next(isCCEnabled); }, }; } static getInstance(): ClosedCaptioningManager { if (!ClosedCaptioningManager.ccManagerInstance) { log_debug("ClosedCaptioningManager: Creating new instance"); ClosedCaptioningManager.ccManagerInstance = new ClosedCaptioningManager(); } log_debug("ClosedCaptioningManager: Returning existing instance"); return ClosedCaptioningManager.ccManagerInstance; } async initialize() { const existingState = await sessionStorage.getItem( PLATFORM_KEYS.deviceClosedCaptioningEnabled ); if (existingState !== null) { log_debug( `ClosedCaptioningManager: Setting initial state to ${existingState}` ); this.ccState$.next(existingState === "true" || existingState === true); } else { log_debug("ClosedCaptioningManager: No existing state found"); } if (hasVizioAPIs()) { log_debug("ClosedCaptioningManager: Setting closed captioning handler"); window.VIZIO!.setClosedCaptionHandler((isCCEnabled) => { log_debug( "ClosedCaptioningManager: There was a change in the CC state", { isCCEnabled } ); sessionStorage.setItem( PLATFORM_KEYS.deviceClosedCaptioningEnabled, isCCEnabled ); log_debug( "ClosedCaptioningManager: Saved CC state to session storage", { isCCEnabled } ); this.ccState$.next(isCCEnabled); }); } else { log_debug( "ClosedCaptioningManager: Vizio APIs are not available, skipping setup" ); } } getCurrentState(): boolean { return this.ccState$.getValue(); } getStateAsObservable() { return this.ccState$.asObservable(); } } /** * Subscribe to closed captioning state changes * @returns Observable<boolean> * @example * const subscription = getClosedCaptionState().subscribe( * isEnabled => setClosedCaptionState(isEnabled) * ); * subscription.unsubscribe(), []); */ export const getClosedCaptionState = () => { const ccManager = ClosedCaptioningManager.getInstance(); return ccManager.getStateAsObservable(); }; /** * Manages device based closed captioning state * Returns an observable that emits the current state and updates whenever it changes */ export class TTSManager { private ttsState$ = new BehaviorSubject<boolean>(false); private static ttsManagerInstance: TTSManager; private constructor() { this.initialize(); } static getInstance(): TTSManager { if (!TTSManager.ttsManagerInstance) { TTSManager.ttsManagerInstance = new TTSManager(); } return TTSManager.ttsManagerInstance; } async initialize() { if (!isVizioPlatform()) return; document.addEventListener( "VIZIO_TTS_ENABLED", () => { this.ttsState$.next(true); }, false ); document.addEventListener( "VIZIO_TTS_DISABLED", () => { this.ttsState$.next(false); }, false ); } getCurrentState(): boolean { return this.ttsState$.getValue(); } getStateAsObservable() { return this.ttsState$.asObservable(); } readText(text: string) { this.ttsState$.next(true); if (isSamsungPlatform() && window.speechSynthesis) { const utterance = new SpeechSynthesisUtterance(text); window.speechSynthesis.cancel(); // Cancel previous speech before speaking new text window.speechSynthesis.speak(utterance); // Estimate reading time and set inactive when done this.scheduleTTSComplete(text); } if (isLgPlatform() && window.webOS?.service) { try { window.webOS.service.request("luna://com.webos.service.tts", { method: "speak", onFailure(error: any) { log_debug("There was a failure setting up webOS TTS service", { error, }); this.ttsState$.next(false); }, onSuccess(response: any) { log_debug("webOS TTS service is configured successfully", { response, }); // Estimate reading time and set inactive when done this.scheduleTTSComplete(text); }, parameters: { text, clear: true, // Clear any previous speech before speaking new text }, }); } catch (error) { log_debug("webOS TTS service error", { error }); this.ttsState$.next(false); } } if (!window.VIZIO?.Chromevox) { // For platforms without TTS, estimate reading time this.scheduleTTSComplete(text); return; } window.VIZIO.Chromevox.play(text); // Estimate reading time and set inactive when done this.scheduleTTSComplete(text); } private scheduleTTSComplete(text: string) { const readingTime = calculateReadingTime(text); setTimeout(() => { this.ttsState$.next(false); }, readingTime); } }