@applicaster/zapp-react-native-utils
Version:
Applicaster Zapp React Native utilities package
256 lines (211 loc) • 6.67 kB
text/typescript
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";
declare global {
interface Window {
VIZIO?: {
exitApplication: () => void;
Chromevox: {
play: (text: string) => void;
};
setClosedCaptionHandler: (
callback: (isCCEnabled: boolean) => void
) => void;
};
}
}
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();
}
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) {
if (isSamsungPlatform() && window.speechSynthesis) {
const utterance = new SpeechSynthesisUtterance(text);
window.speechSynthesis.speak(utterance);
}
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,
});
},
onSuccess(response: any) {
log_debug("webOS TTS service is configured successfully", {
response,
});
},
parameters: {
text,
},
});
} catch (error) {
log_debug("webOS TTS service error", { error });
}
}
if (!window.VIZIO?.Chromevox) return;
window.VIZIO.Chromevox.play(text);
}
}