@applicaster/zapp-react-native-utils 12.0.0-alpha.5035843303 → 12.0.0-alpha.5050333009
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actionsExecutor/ActionExecutorContext.tsx +16 -8
- package/analyticsUtils/AnalyticsEvents/index.ts +13 -0
- package/analyticsUtils/AnalyticsEvents/searchEvents.ts +21 -0
- package/analyticsUtils/AnalyticsEvents/sendShareEvent.ts +21 -0
- package/analyticsUtils/__tests__/analyticsManager.test.js +75 -73
- package/analyticsUtils/analyticsPlugins.ts +25 -0
- package/analyticsUtils/events.ts +12 -0
- package/analyticsUtils/helpers/hooks.ts +1 -1
- package/analyticsUtils/index.tsx +12 -0
- package/appUtils/HooksManager/{Hook.js → Hook.ts} +35 -23
- package/appUtils/HooksManager/{constants.js → constants.ts} +1 -1
- package/appUtils/HooksManager/{index.js → index.ts} +121 -112
- package/appUtils/HooksManager/types.ts +116 -0
- package/appUtils/RiverFocusManager/index.js +17 -12
- package/appUtils/accessibilityManager/const.ts +50 -0
- package/appUtils/accessibilityManager/hooks.ts +31 -0
- package/appUtils/accessibilityManager/index.ts +150 -0
- package/appUtils/accessibilityManager/logger.ts +5 -0
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -3
- package/appUtils/focusManager/__tests__/focusManager.test.js +4 -24
- package/appUtils/focusManager/__tests__/index.test.ts +2 -3
- package/appUtils/focusManager/index.ts +76 -57
- package/appUtils/focusManager/treeDataStructure/Tree/index.js +2 -3
- package/appUtils/focusManager/treeDataStructure/Utils/index.js +76 -38
- package/appUtils/focusManager/utils/index.ts +100 -0
- package/appUtils/focusManagerAux/index.ts +76 -0
- package/appUtils/focusManagerAux/utils/index.ts +100 -0
- package/appUtils/{index.js → index.ts} +2 -0
- package/appUtils/keyCodes/__tests__/__snapshots__/keyCodes.test.js.snap +1 -1
- package/appUtils/keyCodes/__tests__/keyCodes.test.js +80 -85
- package/appUtils/keyCodes/{index.js → index.ts} +2 -0
- package/appUtils/keyCodes/keys/index.ts +3 -0
- package/appUtils/keyCodes/{keys.android.js → keys/keyEventMapper.ts} +0 -19
- package/appUtils/keyCodes/keys/keys.android.ts +18 -0
- package/appUtils/keyCodes/keys/keys.ios.ts +25 -0
- package/appUtils/keyCodes/keys/keys.ts +15 -0
- package/appUtils/keyCodes/{keys.web.js → keys/keys.web.ts} +9 -0
- package/appUtils/keyCodes/{keysByPlatform.js → keys/keysByPlatform.ts} +11 -1
- package/appUtils/orientationHelper.ts +1 -1
- package/appUtils/platform/const.ts +25 -0
- package/appUtils/platform/index.ts +3 -0
- package/appUtils/platform/platformUtils.ts +171 -0
- package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +53 -0
- package/appUtils/playerManager/conts.ts +5 -0
- package/appUtils/playerManager/index.ts +11 -5
- package/appUtils/playerManager/nativePlayerManager.ts +12 -0
- package/appUtils/playerManager/player.ts +48 -7
- package/appUtils/playerManager/playerFactory.ts +15 -1
- package/appUtils/playerManager/playerNative.ts +40 -14
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +7 -1
- package/appUtils/playerManager/usePlayerState.tsx +13 -1
- package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +50 -0
- package/arrayUtils/__tests__/isFilledArray.test.ts +63 -0
- package/arrayUtils/index.ts +5 -0
- package/booleanUtils/index.ts +4 -4
- package/cellUtils/__tests__/cellUtils.test.ts +48 -0
- package/cellUtils/__tests__/fixtures.ts +13 -0
- package/cellUtils/index.ts +40 -2
- package/dateUtils/index.ts +11 -0
- package/domUtils/{cookieManager.js → cookieManager.ts} +1 -2
- package/focusManager/index.ts +1 -1
- package/functionUtils/__tests__/__snapshots__/functionUtils.test.js.snap +2 -2
- package/functionUtils/__tests__/functionUtils.test.js +244 -248
- package/functionUtils/index.ts +15 -11
- package/headersUtils/index.ts +1 -0
- package/inflatedUrlUtils/index.ts +4 -4
- package/keyboardState/index.ts +0 -0
- package/localizationUtils/__tests__/localizationUtils.test.ts +78 -55
- package/localizationUtils/index.ts +13 -19
- package/logger/index.ts +1 -1
- package/manifestUtils/defaultManifestConfigurations/generalContent.js +6 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +10 -1
- package/manifestUtils/index.js +5 -1
- package/manifestUtils/secondaryImage/index.js +18 -15
- package/modalState/index.ts +53 -0
- package/navigationUtils/index.ts +118 -12
- package/numberUtils/__tests__/isLikeNumber.test.ts +18 -0
- package/numberUtils/index.ts +9 -18
- package/package.json +3 -2
- package/playerUtils/configurationGenerator.ts +11 -1
- package/pluginUtils/index.ts +20 -7
- package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +2 -0
- package/reactHooks/autoscrolling/__tests__/{useTrackedView.test.ts → useTrackedView.test.tsx} +18 -1
- package/reactHooks/cell-click/__tests__/index.test.js +16 -3
- package/reactHooks/cell-click/index.ts +14 -14
- package/reactHooks/device/index.ts +0 -1
- package/reactHooks/device/useIsTablet.tsx +28 -3
- package/reactHooks/device/useMemoizedIsTablet.ts +1 -1
- package/reactHooks/device/useOrientation.tsx +3 -1
- package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +30 -70
- package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +6 -2
- package/reactHooks/feed/__tests__/useInflatedUrl.test.ts +18 -3
- package/reactHooks/feed/useBuildPipesUrl.ts +7 -10
- package/reactHooks/feed/useFeedRefresh.tsx +9 -7
- package/reactHooks/feed/useInflatedUrl.ts +44 -15
- package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +16 -9
- package/reactHooks/index.ts +2 -0
- package/reactHooks/layout/__tests__/{index.test.js → index.test.tsx} +66 -59
- package/reactHooks/layout/getDeviceInfo/index.ts +4 -2
- package/reactHooks/layout/index.ts +2 -1
- package/reactHooks/layout/types/index.ts +2 -0
- package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.native.test.js +11 -16
- package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +12 -14
- package/reactHooks/layout/useDimensions/useDimensions.ts +13 -7
- package/reactHooks/navigation/__mocks__/index.ts +15 -0
- package/reactHooks/navigation/__mocks__/useNavigation.ts +7 -0
- package/reactHooks/navigation/__tests__/index.test.tsx +240 -81
- package/reactHooks/navigation/index.ts +246 -84
- package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +3 -1
- package/reactHooks/screen/__mocks__/useScreenContext.ts +3 -1
- package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +21 -23
- package/reactHooks/screen/index.ts +4 -0
- package/reactHooks/screen/useScreenBackgroundColor.ts +23 -0
- package/reactHooks/screen/useScreenContext.ts +4 -4
- package/reactHooks/screen/useScreenData.ts +1 -1
- package/reactHooks/screen/useTargetScreenData.ts +7 -0
- package/reactHooks/state/useRivers.ts +3 -1
- package/reactHooks/useListenEventBusEvent.ts +6 -15
- package/reactHooks/videoModal/hooks/useVideoModalScreenData.tsx +10 -9
- package/reactUtils/index.ts +91 -0
- package/riverComponetsMeasurementProvider/index.tsx +2 -2
- package/stringUtils/index.ts +5 -0
- package/testUtils/getByTestId.ts +14 -0
- package/testUtils/index.tsx +38 -23
- package/types.ts +4 -0
- package/zappFrameworkUtils/loginPluginUtils.ts +12 -2
- package/appUtils/focusManager/FocusableEvents.ts +0 -8
- package/appUtils/focusManager/treeDataStructure/Utils/__tests__/Utils_android.test.js +0 -1094
- package/appUtils/focusManager/treeDataStructure/Utils/index.android.js +0 -261
- package/appUtils/keyCodes/keys.ios.js +0 -46
- package/reactHooks/device/useIsTablet.android.tsx +0 -14
- package/reactHooks/device/useIsTablet.ios.tsx +0 -7
- package/reactHooks/device/useIsTablet.web.tsx +0 -3
- /package/appUtils/HooksManager/{logger.js → logger.ts} +0 -0
- /package/appUtils/{directionHelper.js → directionHelper.ts} +0 -0
- /package/appUtils/keyCodes/{androidTVKeys.js → androidTVKeys.ts} +0 -0
- /package/appUtils/{localizationsHelper.js → localizationsHelper.ts} +0 -0
- /package/domUtils/{logger.js → logger.ts} +0 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { BehaviorSubject } from "rxjs";
|
|
2
|
+
|
|
3
|
+
import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
|
|
4
|
+
|
|
5
|
+
import { PLATFORM_KEYS, PLATFORMS } from "./const";
|
|
6
|
+
import { createLogger, utilsLogger } from "../../logger";
|
|
7
|
+
|
|
8
|
+
const { log_debug } = createLogger({
|
|
9
|
+
category: "General",
|
|
10
|
+
subsystem: "PlatformUtils",
|
|
11
|
+
parent: utilsLogger,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const getUserAgent = () =>
|
|
15
|
+
window?.navigator?.userAgent || global?.navigator?.userAgent;
|
|
16
|
+
|
|
17
|
+
/** VIZIO UTILS */
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Checks if we are on the Vizio platform by using the userAgent string
|
|
21
|
+
*
|
|
22
|
+
* Use this method when you need to identify the platform on runtime
|
|
23
|
+
* before the VIZIO Companion Library has loaded
|
|
24
|
+
*/
|
|
25
|
+
export const isVizioPlatform = () => {
|
|
26
|
+
const userAgent = getUserAgent();
|
|
27
|
+
|
|
28
|
+
const isVizioAgent =
|
|
29
|
+
userAgent.includes(PLATFORMS.vizio) ||
|
|
30
|
+
userAgent.includes(PLATFORMS.smartcast) ||
|
|
31
|
+
userAgent.includes(PLATFORMS.conjure);
|
|
32
|
+
|
|
33
|
+
return isVizioAgent;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Checks if we are on the Vizio platform by checking for the global VIZIO object
|
|
38
|
+
* and the VIZIO Companion Library. This method does not use the userAgent string,
|
|
39
|
+
* because it mainly checks whether we have access to apis, which may not be available yet
|
|
40
|
+
*/
|
|
41
|
+
export const hasVizioAPIs = () => {
|
|
42
|
+
const hasAPIs =
|
|
43
|
+
typeof window.VIZIO !== "undefined" &&
|
|
44
|
+
window?.applicaster?.vizioLibraryDidLoad;
|
|
45
|
+
|
|
46
|
+
return hasAPIs;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Manages device based closed captioning state
|
|
51
|
+
* Returns an observable that emits the current state and updates whenever it changes
|
|
52
|
+
*/
|
|
53
|
+
export class ClosedCaptioningManager {
|
|
54
|
+
private ccState$ = new BehaviorSubject<boolean>(false);
|
|
55
|
+
private static ccManagerInstance: ClosedCaptioningManager;
|
|
56
|
+
|
|
57
|
+
private constructor() {
|
|
58
|
+
this.initialize();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static getInstance(): ClosedCaptioningManager {
|
|
62
|
+
if (!ClosedCaptioningManager.ccManagerInstance) {
|
|
63
|
+
ClosedCaptioningManager.ccManagerInstance = new ClosedCaptioningManager();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return ClosedCaptioningManager.ccManagerInstance;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async initialize() {
|
|
70
|
+
const existingState = await sessionStorage.getItem(
|
|
71
|
+
PLATFORM_KEYS.deviceClosedCaptioningEnabled
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
log_debug("Initializing closed captioning manager", { existingState });
|
|
75
|
+
|
|
76
|
+
if (existingState !== null) {
|
|
77
|
+
this.ccState$.next(existingState === "true" || existingState === true);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (hasVizioAPIs()) {
|
|
81
|
+
window.VIZIO!.setClosedCaptionHandler((isCCEnabled) => {
|
|
82
|
+
log_debug("CC state changed", { isCCEnabled });
|
|
83
|
+
|
|
84
|
+
sessionStorage.setItem(
|
|
85
|
+
PLATFORM_KEYS.deviceClosedCaptioningEnabled,
|
|
86
|
+
isCCEnabled
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
this.ccState$.next(isCCEnabled);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
getCurrentState(): boolean {
|
|
95
|
+
return this.ccState$.getValue();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
getStateAsObservable() {
|
|
99
|
+
return this.ccState$.asObservable();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Subscribe to closed captioning state changes
|
|
105
|
+
* @returns Observable<boolean>
|
|
106
|
+
* @example
|
|
107
|
+
* const subscription = getClosedCaptionState().subscribe(
|
|
108
|
+
* isEnabled => setClosedCaptionState(isEnabled)
|
|
109
|
+
* );
|
|
110
|
+
* subscription.unsubscribe(), []);
|
|
111
|
+
*/
|
|
112
|
+
export const getClosedCaptionState = () => {
|
|
113
|
+
const ccManager = ClosedCaptioningManager.getInstance();
|
|
114
|
+
|
|
115
|
+
return ccManager.getStateAsObservable();
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Manages device based closed captioning state
|
|
120
|
+
* Returns an observable that emits the current state and updates whenever it changes
|
|
121
|
+
*/
|
|
122
|
+
export class TTSManager {
|
|
123
|
+
private ttsState$ = new BehaviorSubject<boolean>(false);
|
|
124
|
+
private static ttsManagerInstance: TTSManager;
|
|
125
|
+
|
|
126
|
+
private constructor() {
|
|
127
|
+
this.initialize();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static getInstance(): TTSManager {
|
|
131
|
+
if (!TTSManager.ttsManagerInstance) {
|
|
132
|
+
TTSManager.ttsManagerInstance = new TTSManager();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return TTSManager.ttsManagerInstance;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async initialize() {
|
|
139
|
+
if (!isVizioPlatform()) return;
|
|
140
|
+
|
|
141
|
+
document.addEventListener(
|
|
142
|
+
"VIZIO_TTS_ENABLED",
|
|
143
|
+
() => {
|
|
144
|
+
this.ttsState$.next(true);
|
|
145
|
+
},
|
|
146
|
+
false
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
document.addEventListener(
|
|
150
|
+
"VIZIO_TTS_DISABLED",
|
|
151
|
+
() => {
|
|
152
|
+
this.ttsState$.next(false);
|
|
153
|
+
},
|
|
154
|
+
false
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
getCurrentState(): boolean {
|
|
159
|
+
return this.ttsState$.getValue();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
getStateAsObservable() {
|
|
163
|
+
return this.ttsState$.asObservable();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
readText(text: string) {
|
|
167
|
+
if (!window.VIZIO?.Chromevox) return;
|
|
168
|
+
|
|
169
|
+
window.VIZIO.Chromevox.play(text);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -41,6 +41,11 @@ export type ChapterMarkerEvent = {
|
|
|
41
41
|
actions: ActionChapter[];
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
+
export type TitleSummaryEvent = {
|
|
45
|
+
title: string | number;
|
|
46
|
+
summary: string | number;
|
|
47
|
+
};
|
|
48
|
+
|
|
44
49
|
type ChapterMarkersObserverProps = {
|
|
45
50
|
player: Player;
|
|
46
51
|
};
|
|
@@ -60,6 +65,11 @@ export type PlayNextState = PlayNextConfig & {
|
|
|
60
65
|
export class OverlaysObserver {
|
|
61
66
|
readonly chapterSubject: BehaviorSubject<ChapterMarkerEvent>;
|
|
62
67
|
private playNextSubject: BehaviorSubject<PlayNextState>;
|
|
68
|
+
private titleSummarySubject: BehaviorSubject<TitleSummaryEvent>;
|
|
69
|
+
private feedUrl: string;
|
|
70
|
+
private reloadData: () => void;
|
|
71
|
+
private updateTitleAndDescription: (data: any) => void;
|
|
72
|
+
private feedDataInterval: any;
|
|
63
73
|
private releasePlayerObserver?: () => void;
|
|
64
74
|
readonly entry: ZappEntry;
|
|
65
75
|
private chapterMarkerEvents: ChapterMarkerEvent[];
|
|
@@ -70,14 +80,55 @@ export class OverlaysObserver {
|
|
|
70
80
|
constructor({ player }: ChapterMarkersObserverProps) {
|
|
71
81
|
this.chapterSubject = new BehaviorSubject(null);
|
|
72
82
|
this.playNextSubject = new BehaviorSubject(null);
|
|
83
|
+
|
|
84
|
+
this.titleSummarySubject = new BehaviorSubject<TitleSummaryEvent>({
|
|
85
|
+
title: player.getEntry()?.title || "",
|
|
86
|
+
summary: player.getEntry()?.summary || "",
|
|
87
|
+
});
|
|
88
|
+
|
|
73
89
|
this.entry = player.getEntry();
|
|
74
90
|
this.player = player;
|
|
75
91
|
|
|
76
92
|
this.chapterMarkerEvents = this.prepareChapterMarkers();
|
|
77
93
|
this.releasePlayerObserver = this.subscribeToPlayerEvents();
|
|
94
|
+
this.feedUrl = "";
|
|
95
|
+
this.reloadData = () => {};
|
|
96
|
+
this.updateTitleAndDescription = () => {};
|
|
97
|
+
this.feedDataInterval = null;
|
|
78
98
|
void this.preparePlayNext();
|
|
79
99
|
}
|
|
80
100
|
|
|
101
|
+
private setupFeedDataInterval(interval: number) {
|
|
102
|
+
if (this.feedUrl && this.reloadData && this.updateTitleAndDescription) {
|
|
103
|
+
this.feedDataInterval = setInterval(() => {
|
|
104
|
+
this.reloadData();
|
|
105
|
+
}, interval * 1000);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public clearFeedDataInterval() {
|
|
110
|
+
if (this.feedDataInterval) {
|
|
111
|
+
clearInterval(this.feedDataInterval);
|
|
112
|
+
this.feedDataInterval = null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public setFeedDataHandlers(
|
|
117
|
+
feedUrl: string,
|
|
118
|
+
reloadData: () => void,
|
|
119
|
+
interval: number,
|
|
120
|
+
updateTitleAndDescription: (data: any) => void
|
|
121
|
+
) {
|
|
122
|
+
this.feedUrl = feedUrl;
|
|
123
|
+
this.reloadData = reloadData;
|
|
124
|
+
this.updateTitleAndDescription = updateTitleAndDescription;
|
|
125
|
+
this.setupFeedDataInterval(interval);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public getTitleSummaryObservable(): Observable<TitleSummaryEvent> {
|
|
129
|
+
return this.titleSummarySubject.asObservable().pipe(distinctUntilChanged());
|
|
130
|
+
}
|
|
131
|
+
|
|
81
132
|
handleUserCancelPlayNext = () => {
|
|
82
133
|
this.isCanceledByUser = true;
|
|
83
134
|
this.playNextSubject.next(null);
|
|
@@ -281,7 +332,9 @@ export class OverlaysObserver {
|
|
|
281
332
|
onPlayerClose = () => {
|
|
282
333
|
this.chapterSubject.complete();
|
|
283
334
|
this.playNextSubject.complete();
|
|
335
|
+
this.titleSummarySubject.complete();
|
|
284
336
|
this.releasePlayerObserver?.();
|
|
337
|
+
this.clearFeedDataInterval();
|
|
285
338
|
this.releasePlayerObserver = null;
|
|
286
339
|
};
|
|
287
340
|
|
|
@@ -21,6 +21,11 @@ export enum SharedPlayerCallBacksKeys {
|
|
|
21
21
|
OnPlayerMute = "onPlayerMute",
|
|
22
22
|
OnPlayerUnmute = "onPlayerUnmute",
|
|
23
23
|
|
|
24
|
+
onVideoFullscreenPlayerDidDismiss = "onVideoFullscreenPlayerDidDismiss",
|
|
25
|
+
onVideoFullscreenPlayerDidPresent = "onVideoFullscreenPlayerDidPresent",
|
|
26
|
+
onVideoFullscreenPlayerWillDismiss = "onVideoFullscreenPlayerWillDismiss",
|
|
27
|
+
onVideoFullscreenPlayerWillPresent = "onVideoFullscreenPlayerWillPresent",
|
|
28
|
+
|
|
24
29
|
OnAdBegin = "onAdBegin",
|
|
25
30
|
OnAdBreakBegin = "onAdBreakBegin",
|
|
26
31
|
OnAdBreakEnd = "onAdBreakEnd",
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "@applicaster/quick-brick-core/App/NetworkStatusProvider/utils";
|
|
12
12
|
import { setUserLanguagePreference } from "./userLanguagePreference";
|
|
13
13
|
import { PlayerRole } from "./conts";
|
|
14
|
+
import { RNPlayerManager } from "./nativePlayerManager";
|
|
14
15
|
|
|
15
16
|
const { log_error, log_debug, log_warning } = createLogger({
|
|
16
17
|
category: "General",
|
|
@@ -164,6 +165,10 @@ export class PlayerManager {
|
|
|
164
165
|
this.addPlayer(id, playerController);
|
|
165
166
|
|
|
166
167
|
if (playerController.playerRole === PlayerRole.Primary) {
|
|
168
|
+
if (playerController.playerPluginId !== "QuickBrickPlayerPlugin") {
|
|
169
|
+
RNPlayerManager?.["QuickBrickPlayerPlugin"]?.stopBackgroundPlayback?.();
|
|
170
|
+
}
|
|
171
|
+
|
|
167
172
|
playerController.addListener({
|
|
168
173
|
id: this.getPlayerListenerId(id),
|
|
169
174
|
listener: {
|
|
@@ -361,9 +366,9 @@ export class PlayerManager {
|
|
|
361
366
|
// TODO: Remove
|
|
362
367
|
if (this.castingReceiver) {
|
|
363
368
|
this.castingReceiver.rewind(deltaTime);
|
|
369
|
+
} else {
|
|
370
|
+
this.getActivePlayer()?.rewind(deltaTime);
|
|
364
371
|
}
|
|
365
|
-
|
|
366
|
-
this.getActivePlayer()?.rewind(deltaTime);
|
|
367
372
|
}
|
|
368
373
|
|
|
369
374
|
public forward(deltaTime = null) {
|
|
@@ -371,9 +376,9 @@ export class PlayerManager {
|
|
|
371
376
|
|
|
372
377
|
if (this.castingReceiver) {
|
|
373
378
|
this.castingReceiver.forward(deltaTime);
|
|
379
|
+
} else {
|
|
380
|
+
this.getActivePlayer()?.forward(deltaTime);
|
|
374
381
|
}
|
|
375
|
-
|
|
376
|
-
this.getActivePlayer()?.forward(deltaTime);
|
|
377
382
|
}
|
|
378
383
|
|
|
379
384
|
public seeking(time) {
|
|
@@ -436,7 +441,7 @@ export class PlayerManager {
|
|
|
436
441
|
}
|
|
437
442
|
|
|
438
443
|
// Call method on player just in case
|
|
439
|
-
return this.getActivePlayer()?.
|
|
444
|
+
return this.getActivePlayer()?.selectTrack(track);
|
|
440
445
|
}
|
|
441
446
|
|
|
442
447
|
public isRegistered() {
|
|
@@ -461,6 +466,7 @@ export class PlayerManager {
|
|
|
461
466
|
if (this.castingReceiver) {
|
|
462
467
|
this.castingReceiver.closeNativePlayer();
|
|
463
468
|
} else {
|
|
469
|
+
this.getActivePlayer().closeNativePlayer();
|
|
464
470
|
this.invokeHandler("close");
|
|
465
471
|
}
|
|
466
472
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { NativeModules } from "react-native";
|
|
2
|
+
import { isApplePlatform } from "../../reactUtils";
|
|
3
|
+
|
|
4
|
+
export const RNPlayerManager = {
|
|
5
|
+
QuickBrickPlayerPlugin: isApplePlatform()
|
|
6
|
+
? NativeModules.PlayerModule
|
|
7
|
+
: NativeModules.QuickBrickDefaultPlayerModule,
|
|
8
|
+
KalturaPlayerPlugin: isApplePlatform()
|
|
9
|
+
? NativeModules.KalturaPlayerModule
|
|
10
|
+
: NativeModules.QBKalturaPlayerModule,
|
|
11
|
+
"quick-brick-player-brightcove": NativeModules.BrightcovePlayerModule,
|
|
12
|
+
};
|
|
@@ -42,7 +42,7 @@ export class Player {
|
|
|
42
42
|
|
|
43
43
|
protected startPosition?: number | null;
|
|
44
44
|
readonly playerRole: PlayerRole = PlayerRole.Unspecified;
|
|
45
|
-
private
|
|
45
|
+
private overlaysObserver?: OverlaysObserver | null;
|
|
46
46
|
private entryObservable?: BehaviorSubject<ZappEntry> | null;
|
|
47
47
|
|
|
48
48
|
protected listeners: {
|
|
@@ -95,11 +95,11 @@ export class Player {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
getOverlayObservable = () => {
|
|
98
|
-
if (!this.
|
|
99
|
-
this.
|
|
98
|
+
if (!this.overlaysObserver) {
|
|
99
|
+
this.overlaysObserver = new OverlaysObserver({ player: this });
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
return this.
|
|
102
|
+
return this.overlaysObserver;
|
|
103
103
|
};
|
|
104
104
|
|
|
105
105
|
getEntryObservable = (): BehaviorSubject<ZappEntry | null> => {
|
|
@@ -278,6 +278,10 @@ export class Player {
|
|
|
278
278
|
return this.playerState.isBuffering;
|
|
279
279
|
};
|
|
280
280
|
|
|
281
|
+
isReadyToPlay = (): boolean => {
|
|
282
|
+
return this.playerState.isReadyToPlay;
|
|
283
|
+
};
|
|
284
|
+
|
|
281
285
|
// Methods to call actions on the player
|
|
282
286
|
seekTo = (_position: number) => {};
|
|
283
287
|
|
|
@@ -417,6 +421,32 @@ export class Player {
|
|
|
417
421
|
});
|
|
418
422
|
};
|
|
419
423
|
|
|
424
|
+
onVideoFullscreenPlayerWillDismiss = () => {
|
|
425
|
+
this.invokeListenersUpdate({
|
|
426
|
+
callbackName:
|
|
427
|
+
SharedPlayerCallBacksKeys.onVideoFullscreenPlayerWillDismiss,
|
|
428
|
+
});
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
onVideoFullscreenPlayerDidDismiss = () => {
|
|
432
|
+
this.invokeListenersUpdate({
|
|
433
|
+
callbackName: SharedPlayerCallBacksKeys.onVideoFullscreenPlayerDidDismiss,
|
|
434
|
+
});
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
onVideoFullscreenPlayerWillPresent = () => {
|
|
438
|
+
this.invokeListenersUpdate({
|
|
439
|
+
callbackName:
|
|
440
|
+
SharedPlayerCallBacksKeys.onVideoFullscreenPlayerWillPresent,
|
|
441
|
+
});
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
onVideoFullscreenPlayerDidPresent = () => {
|
|
445
|
+
this.invokeListenersUpdate({
|
|
446
|
+
callbackName: SharedPlayerCallBacksKeys.onVideoFullscreenPlayerDidPresent,
|
|
447
|
+
});
|
|
448
|
+
};
|
|
449
|
+
|
|
420
450
|
public invokeListenersUpdate = ({
|
|
421
451
|
callbackName,
|
|
422
452
|
event = {},
|
|
@@ -638,6 +668,12 @@ export class Player {
|
|
|
638
668
|
onBufferStart: this.onBufferStart,
|
|
639
669
|
onBufferComplete: this.onBufferComplete,
|
|
640
670
|
|
|
671
|
+
onPlayerClose: this.onPlayerClose,
|
|
672
|
+
onVideoFullscreenPlayerWillPresent: this.onVideoFullscreenPlayerWillPresent,
|
|
673
|
+
onVideoFullscreenPlayerDidPresent: this.onVideoFullscreenPlayerDidPresent,
|
|
674
|
+
onVideoFullscreenPlayerWillDismiss: this.onVideoFullscreenPlayerWillDismiss,
|
|
675
|
+
onVideoFullscreenPlayerDidDismiss: this.onVideoFullscreenPlayerDidDismiss,
|
|
676
|
+
|
|
641
677
|
// Ads Callbacks:
|
|
642
678
|
onAdBegin: this.onAdBegin,
|
|
643
679
|
onAdBreakBegin: this.onAdBreakBegin,
|
|
@@ -656,9 +692,10 @@ export class Player {
|
|
|
656
692
|
play = () => {};
|
|
657
693
|
pause = () => {};
|
|
658
694
|
disableBufferAnimation = (): boolean => true;
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
) => {};
|
|
695
|
+
|
|
696
|
+
setPlaybackRate = (_rate) => {};
|
|
697
|
+
startSleepTimer = (_timestamp) => {};
|
|
698
|
+
cancelSleepTimer = () => {};
|
|
662
699
|
|
|
663
700
|
getPluginConfiguration = () => null;
|
|
664
701
|
appStateChange = (_appState, _previousAppState) => {};
|
|
@@ -693,4 +730,8 @@ export class Player {
|
|
|
693
730
|
isFullScreenSupported(): boolean {
|
|
694
731
|
return true;
|
|
695
732
|
}
|
|
733
|
+
|
|
734
|
+
public supportsNativeControls = (): boolean => false;
|
|
735
|
+
public supportNativeCast = (): boolean => false;
|
|
736
|
+
public destroy = () => {};
|
|
696
737
|
}
|
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
2
2
|
import { findPluginByIdentifier } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
3
3
|
import { Player } from "./player";
|
|
4
|
+
import { PlayerRole } from "./conts";
|
|
4
5
|
|
|
5
6
|
type PlayerFactoryItem = {
|
|
6
7
|
Component: any;
|
|
7
8
|
controller: Player;
|
|
8
9
|
};
|
|
9
10
|
|
|
11
|
+
type PlayerFactoryProps = {
|
|
12
|
+
player: any;
|
|
13
|
+
playerId: string;
|
|
14
|
+
autoplay: boolean;
|
|
15
|
+
entry: ZappEntry;
|
|
16
|
+
muted: boolean;
|
|
17
|
+
playerPluginId: string;
|
|
18
|
+
screenConfig: Record<string, any>;
|
|
19
|
+
playerRole: PlayerRole;
|
|
20
|
+
};
|
|
21
|
+
|
|
10
22
|
interface PlayerConstructor {
|
|
11
23
|
new (params: any): Player;
|
|
12
24
|
}
|
|
13
25
|
|
|
14
|
-
export const playerFactory = (
|
|
26
|
+
export const playerFactory = (
|
|
27
|
+
config: PlayerFactoryProps
|
|
28
|
+
): PlayerFactoryItem | null => {
|
|
15
29
|
const IDENTIFIER = config?.playerPluginId;
|
|
16
30
|
|
|
17
31
|
if (!IDENTIFIER) {
|
|
@@ -2,18 +2,10 @@ import * as R from "ramda";
|
|
|
2
2
|
import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
3
3
|
import { createLogger, utilsLogger } from "../../logger";
|
|
4
4
|
import { Player } from "./player";
|
|
5
|
-
import { findNodeHandle
|
|
6
|
-
import { isApplePlatform } from "../../reactUtils";
|
|
5
|
+
import { findNodeHandle } from "react-native";
|
|
7
6
|
import { PlayerRole } from "./conts";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
QuickBrickPlayerPlugin: isApplePlatform()
|
|
11
|
-
? NativeModules.PlayerModule
|
|
12
|
-
: NativeModules.QuickBrickDefaultPlayerModule,
|
|
13
|
-
KalturaPlayerPlugin: isApplePlatform()
|
|
14
|
-
? NativeModules.KalturaPlayerModule
|
|
15
|
-
: NativeModules.QBKalturaPlayerModule,
|
|
16
|
-
};
|
|
7
|
+
import { toBooleanWithDefaultFalse } from "../../booleanUtils";
|
|
8
|
+
import { RNPlayerManager } from "./nativePlayerManager";
|
|
17
9
|
|
|
18
10
|
const logger = createLogger({
|
|
19
11
|
category: "PlayerNativeController",
|
|
@@ -41,6 +33,9 @@ const PlayerModuleFuncNames = {
|
|
|
41
33
|
rewind: "rewind",
|
|
42
34
|
play: "play",
|
|
43
35
|
pause: "pause",
|
|
36
|
+
startSleepTimer: "startSleepTimer",
|
|
37
|
+
cancelSleepTimer: "cancelSleepTimer",
|
|
38
|
+
getSleepTimerEnd: "getSleepTimerEnd",
|
|
44
39
|
};
|
|
45
40
|
|
|
46
41
|
export class PlayerNative extends Player {
|
|
@@ -107,7 +102,7 @@ export class PlayerNative extends Player {
|
|
|
107
102
|
return;
|
|
108
103
|
}
|
|
109
104
|
|
|
110
|
-
const newPosition = R.clamp(0,
|
|
105
|
+
const newPosition = R.clamp(0, this.playerState.seekableDuration, position);
|
|
111
106
|
|
|
112
107
|
if (
|
|
113
108
|
!this.invokeNativeFunction(
|
|
@@ -172,12 +167,35 @@ export class PlayerNative extends Player {
|
|
|
172
167
|
}
|
|
173
168
|
};
|
|
174
169
|
|
|
170
|
+
startSleepTimer = (sleepTimestamp: number) => {
|
|
171
|
+
if (
|
|
172
|
+
!this.invokeNativeFunction(
|
|
173
|
+
PlayerModuleFuncNames.startSleepTimer,
|
|
174
|
+
sleepTimestamp
|
|
175
|
+
)
|
|
176
|
+
) {
|
|
177
|
+
this.currentPlayerComponent()?.["startSleepTimer"](sleepTimestamp);
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
cancelSleepTimer = () => {
|
|
182
|
+
if (!this.invokeNativeFunction(PlayerModuleFuncNames.cancelSleepTimer)) {
|
|
183
|
+
this.currentPlayerComponent()?.[
|
|
184
|
+
PlayerModuleFuncNames.cancelSleepTimer
|
|
185
|
+
]?.();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
175
189
|
disableBufferAnimation = (): boolean => false;
|
|
176
190
|
|
|
177
|
-
|
|
191
|
+
selectTrack = (
|
|
178
192
|
selected: QuickBrickPlayer.TextTrack | QuickBrickPlayer.AudioTrack
|
|
179
193
|
) => {
|
|
180
|
-
this.currentPlayerComponent()?.["
|
|
194
|
+
this.currentPlayerComponent()?.["selectTrack"]?.(selected);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
setPlaybackRate = (rate: number) => {
|
|
198
|
+
this.currentPlayerComponent()?.["setPlaybackRate"]?.(rate);
|
|
181
199
|
};
|
|
182
200
|
|
|
183
201
|
getPluginConfiguration = () => {
|
|
@@ -265,4 +283,12 @@ export class PlayerNative extends Player {
|
|
|
265
283
|
|
|
266
284
|
return !(isFullScreenAudioPlayer && this.isAudioItem());
|
|
267
285
|
};
|
|
286
|
+
|
|
287
|
+
supportsNativeControls = (): boolean =>
|
|
288
|
+
toBooleanWithDefaultFalse(this.getConfig()?.["supports_native_controls"]);
|
|
289
|
+
|
|
290
|
+
supportNativeCast = (): boolean =>
|
|
291
|
+
toBooleanWithDefaultFalse(
|
|
292
|
+
this.playerPluginId === "quick-brick-player-brightcove"
|
|
293
|
+
);
|
|
268
294
|
}
|
|
@@ -4,6 +4,7 @@ import { useEffect } from "react";
|
|
|
4
4
|
import { playerManager } from "./index";
|
|
5
5
|
import { useValidatePlayerConfig } from "../../playerUtils/useValidatePlayerConfig";
|
|
6
6
|
import { PlayerRole } from "./conts";
|
|
7
|
+
import { isAppleTV } from "@applicaster/zapp-react-native-ui-components/Helpers/Platform";
|
|
7
8
|
|
|
8
9
|
// TODO: Rename to ControllerType
|
|
9
10
|
export const usePlayerControllerSetup = ({
|
|
@@ -34,10 +35,14 @@ export const usePlayerControllerSetup = ({
|
|
|
34
35
|
useValidatePlayerConfig(config);
|
|
35
36
|
|
|
36
37
|
useEffect(() => {
|
|
38
|
+
const newConfig = isAppleTV()
|
|
39
|
+
? { supports_native_controls: true, ...config }
|
|
40
|
+
: config;
|
|
41
|
+
|
|
37
42
|
const newPlayerController = new ControllerType({
|
|
38
43
|
player: ref,
|
|
39
44
|
listener: props as any,
|
|
40
|
-
config,
|
|
45
|
+
config: newConfig,
|
|
41
46
|
playerId,
|
|
42
47
|
entry,
|
|
43
48
|
playerPluginId: pluginId,
|
|
@@ -67,6 +72,7 @@ export const usePlayerControllerSetup = ({
|
|
|
67
72
|
|
|
68
73
|
return () => {
|
|
69
74
|
playerManager.unregisterPlayer(playerId);
|
|
75
|
+
playerController.destroy?.();
|
|
70
76
|
};
|
|
71
77
|
}, [playerId, playerController]);
|
|
72
78
|
|
|
@@ -9,6 +9,7 @@ type PlayerState = {
|
|
|
9
9
|
isLive: boolean;
|
|
10
10
|
isPaused: boolean;
|
|
11
11
|
isBuffering: boolean;
|
|
12
|
+
isReadyToPlay: boolean;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
export const usePlayerState = (
|
|
@@ -20,12 +21,14 @@ export const usePlayerState = (
|
|
|
20
21
|
const [seekableDuration, setSeekableDuration] = React.useState<number>(null);
|
|
21
22
|
const [isLive, setIsLive] = React.useState<boolean>(null);
|
|
22
23
|
const [isBuffering, setIsBuffering] = React.useState<boolean>(false);
|
|
24
|
+
const [isReadyToPlay, setIsReadyToPlay] = React.useState<boolean>(false);
|
|
23
25
|
const [isPaused, setIsPaused] = React.useState<boolean>(false);
|
|
24
26
|
|
|
25
27
|
const player: Player = usePlayer(playerId);
|
|
26
28
|
|
|
27
29
|
const onPlayerChangeState = React.useCallback(() => {
|
|
28
30
|
setIsBuffering(player.isBuffering());
|
|
31
|
+
setIsReadyToPlay(player.isReadyToPlay);
|
|
29
32
|
setCurrentTime(player.getContentPosition());
|
|
30
33
|
setDuration(player.getDuration());
|
|
31
34
|
setSeekableDuration(player.getSeekableDuration());
|
|
@@ -60,7 +63,16 @@ export const usePlayerState = (
|
|
|
60
63
|
isLive,
|
|
61
64
|
isPaused,
|
|
62
65
|
isBuffering,
|
|
66
|
+
isReadyToPlay,
|
|
63
67
|
}),
|
|
64
|
-
[
|
|
68
|
+
[
|
|
69
|
+
currentTime,
|
|
70
|
+
duration,
|
|
71
|
+
seekableDuration,
|
|
72
|
+
isLive,
|
|
73
|
+
isPaused,
|
|
74
|
+
isBuffering,
|
|
75
|
+
isReadyToPlay,
|
|
76
|
+
]
|
|
65
77
|
);
|
|
66
78
|
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { OverlaysObserver } from "./OverlayObserver/OverlaysObserver";
|
|
3
|
+
import { useFeedLoader } from "../../reactHooks";
|
|
4
|
+
import { usePlayer } from "./usePlayer";
|
|
5
|
+
|
|
6
|
+
export const useTitleSummaryOverlay = (
|
|
7
|
+
feedUrl,
|
|
8
|
+
entry,
|
|
9
|
+
isLive = false,
|
|
10
|
+
interval: number
|
|
11
|
+
) => {
|
|
12
|
+
const player = usePlayer();
|
|
13
|
+
const [title, setTitle] = useState<string | number>(entry?.title || "");
|
|
14
|
+
const [summary, setSummary] = useState<string | number>(entry?.summary || "");
|
|
15
|
+
|
|
16
|
+
// Hook to load feed data
|
|
17
|
+
const { data: feedData, reloadData } = useFeedLoader({ feedUrl });
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (player && feedUrl && isLive) {
|
|
21
|
+
const observer = new OverlaysObserver({ player });
|
|
22
|
+
|
|
23
|
+
observer.setFeedDataHandlers(feedUrl, reloadData, interval, (entry) => {
|
|
24
|
+
setTitle(entry?.title || "");
|
|
25
|
+
setSummary(entry?.summary || "");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const subscription = observer
|
|
29
|
+
.getTitleSummaryObservable()
|
|
30
|
+
.subscribe(({ title, summary }) => {
|
|
31
|
+
setTitle(title);
|
|
32
|
+
setSummary(summary);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return () => {
|
|
36
|
+
subscription.unsubscribe();
|
|
37
|
+
observer.clearFeedDataInterval();
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}, [player, feedUrl, reloadData, isLive]);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (isLive && feedData?.entry?.[0]) {
|
|
44
|
+
setTitle(feedData.entry[0].title || "");
|
|
45
|
+
setSummary(feedData.entry[0].summary || "");
|
|
46
|
+
}
|
|
47
|
+
}, [feedData]);
|
|
48
|
+
|
|
49
|
+
return { title, summary };
|
|
50
|
+
};
|