@applicaster/zapp-react-native-utils 12.0.0-rc.5 → 12.0.0-rc.50
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/__tests__/analyticsManager.test.js +75 -73
- package/analyticsUtils/helpers/hooks.ts +1 -1
- package/appUtils/HooksManager/index.js +3 -1
- package/appUtils/focusManager/treeDataStructure/Utils/index.js +12 -3
- package/appUtils/keyCodes/__tests__/__snapshots__/keyCodes.test.js.snap +1 -1
- package/appUtils/keyCodes/__tests__/keyCodes.test.js +80 -85
- package/appUtils/keyCodes/keys.web.js +1 -0
- package/appUtils/orientationHelper.ts +1 -1
- package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +53 -0
- package/appUtils/playerManager/conts.ts +5 -0
- package/appUtils/playerManager/player.ts +46 -4
- package/appUtils/playerManager/playerFactory.ts +15 -1
- package/appUtils/playerManager/playerNative.ts +30 -0
- package/appUtils/playerManager/usePlayerState.tsx +13 -1
- package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +50 -0
- package/cellUtils/__tests__/cellUtils.test.ts +59 -0
- package/cellUtils/__tests__/fixtures.ts +13 -0
- package/cellUtils/index.ts +46 -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/localizationUtils/__tests__/localizationUtils.test.ts +17 -13
- package/localizationUtils/index.ts +6 -3
- 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 +57 -0
- package/navigationUtils/index.ts +56 -7
- package/package.json +3 -2
- package/playerUtils/configurationGenerator.ts +11 -1
- package/pluginUtils/index.ts +11 -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 +6 -2
- package/reactHooks/cell-click/index.ts +2 -2
- 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/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 +2 -0
- package/reactHooks/navigation/__mocks__/useNavigation.ts +4 -0
- package/reactHooks/navigation/__tests__/index.test.tsx +234 -78
- package/reactHooks/navigation/index.ts +251 -85
- package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +3 -1
- package/reactHooks/screen/__mocks__/useScreenContext.ts +3 -1
- package/reactHooks/screen/index.ts +2 -0
- package/reactHooks/screen/useScreenContext.ts +1 -1
- 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 +1 -4
- package/reactHooks/videoModal/hooks/useVideoModalScreenData.tsx +10 -9
- package/riverComponetsMeasurementProvider/index.tsx +2 -2
- package/screenState/index.ts +8 -0
- package/testUtils/index.tsx +15 -2
- package/reactHooks/device/useIsTablet.android.tsx +0 -14
- package/reactHooks/device/useIsTablet.ios.tsx +0 -7
- package/reactHooks/device/useIsTablet.web.tsx +0 -3
|
@@ -11,11 +11,9 @@ import * as QuickBrickManager from "@applicaster/zapp-react-native-bridge/QuickB
|
|
|
11
11
|
import { showConfirmationDialog } from "../alertUtils";
|
|
12
12
|
import { createCloudEvent, sendCloudEvent } from "../cloudEventsUtils";
|
|
13
13
|
import { createLogger } from "../logger";
|
|
14
|
-
import {
|
|
15
|
-
StorageMultiSelectProvider
|
|
16
|
-
} from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
|
|
14
|
+
import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
|
|
17
15
|
|
|
18
|
-
const { log_error,
|
|
16
|
+
const { log_error, log_info } = createLogger({
|
|
19
17
|
subsystem: "ActionExecutorContext",
|
|
20
18
|
category: "General",
|
|
21
19
|
});
|
|
@@ -110,11 +108,17 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
110
108
|
const tag = entry?.extensions?.tag;
|
|
111
109
|
|
|
112
110
|
if (keyNamespace && tag) {
|
|
113
|
-
const multiSelectProvider =
|
|
111
|
+
const multiSelectProvider =
|
|
112
|
+
StorageMultiSelectProvider.getProvider(keyNamespace);
|
|
114
113
|
|
|
115
114
|
const selectedItems = await multiSelectProvider.getSelectedAsync();
|
|
116
115
|
const isTagInSelectedItems = selectedItems.includes(tag);
|
|
117
|
-
|
|
116
|
+
|
|
117
|
+
log_info(
|
|
118
|
+
`handleAction: localStorageToggleFlag event will ${
|
|
119
|
+
isTagInSelectedItems ? "remove" : "add"
|
|
120
|
+
} tag: ${tag} for keyNamespace: ${keyNamespace}, current selectedItems: ${selectedItems}`
|
|
121
|
+
);
|
|
118
122
|
|
|
119
123
|
if (selectedItems.includes(tag)) {
|
|
120
124
|
await multiSelectProvider.removeItem(tag);
|
|
@@ -122,13 +126,17 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
122
126
|
await multiSelectProvider.addItem(tag);
|
|
123
127
|
}
|
|
124
128
|
} else {
|
|
125
|
-
log_error(
|
|
129
|
+
log_error(
|
|
130
|
+
"handleAction: localStorageToggleFlag event missing keyNamespace or tag",
|
|
131
|
+
{ keyNamespace, tag }
|
|
132
|
+
);
|
|
126
133
|
|
|
127
134
|
return ActionResult.Error;
|
|
128
135
|
}
|
|
129
136
|
|
|
130
137
|
return ActionResult.Success;
|
|
131
|
-
}
|
|
138
|
+
}
|
|
139
|
+
);
|
|
132
140
|
};
|
|
133
141
|
|
|
134
142
|
export const ActionExecutorContext =
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
+
import * as ReactNative from "react-native";
|
|
2
|
+
|
|
1
3
|
const mock_postEvent = jest.fn();
|
|
2
4
|
const mock_setPlugins = jest.fn();
|
|
3
5
|
const mock_postTimedEvent = jest.fn();
|
|
4
6
|
const mock_endTimedEvent = jest.fn();
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
},
|
|
15
|
-
}));
|
|
8
|
+
const AnalyticsBridge = {
|
|
9
|
+
postEvent: mock_postEvent,
|
|
10
|
+
setPlugins: mock_setPlugins,
|
|
11
|
+
postTimedEvent: mock_postTimedEvent,
|
|
12
|
+
endTimedEvent: mock_endTimedEvent,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
ReactNative.NativeModules.AnalyticsBridge = AnalyticsBridge;
|
|
16
16
|
|
|
17
17
|
const eventName = "event";
|
|
18
18
|
const payload = {};
|
|
@@ -26,90 +26,92 @@ function clearAllMocks() {
|
|
|
26
26
|
mock_endTimedEvent.mockClear();
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
describe("
|
|
30
|
-
|
|
29
|
+
describe("AnalyticsManager", () => {
|
|
30
|
+
describe("isValidAnalyticsData", () => {
|
|
31
|
+
beforeEach(clearAllMocks);
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
it("returns false if eventName is not a string", () => {
|
|
34
|
+
expect(analyticsManager.isValidAnalyticsData(42)).toBe(false);
|
|
35
|
+
expect(analyticsManager.isValidAnalyticsData({})).toBe(false);
|
|
36
|
+
expect(analyticsManager.isValidAnalyticsData([])).toBe(false);
|
|
37
|
+
expect(analyticsManager.isValidAnalyticsData(() => ({}))).toBe(false);
|
|
38
|
+
});
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
it("returns false if payload is not an object", () => {
|
|
41
|
+
expect(analyticsManager.isValidAnalyticsData(eventName, "string")).toBe(
|
|
42
|
+
false
|
|
43
|
+
);
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
expect(analyticsManager.isValidAnalyticsData(eventName, 42)).toBe(false);
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
expect(analyticsManager.isValidAnalyticsData(eventName, () => ({}))).toBe(
|
|
48
|
+
false
|
|
49
|
+
);
|
|
50
|
+
});
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
it("returns true if eventName is a string and payload is null or an object", () => {
|
|
53
|
+
expect(analyticsManager.isValidAnalyticsData(eventName)).toBe(true);
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
expect(analyticsManager.isValidAnalyticsData(eventName, payload)).toBe(
|
|
56
|
+
true
|
|
57
|
+
);
|
|
58
|
+
});
|
|
57
59
|
});
|
|
58
|
-
});
|
|
59
60
|
|
|
60
|
-
describe("postAnalyticEvent", () => {
|
|
61
|
-
|
|
61
|
+
describe("postAnalyticEvent", () => {
|
|
62
|
+
beforeEach(clearAllMocks);
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
it("calls the postEvent method of the analytic bridge", () => {
|
|
65
|
+
analyticsManager.postAnalyticEvent(eventName, payload);
|
|
66
|
+
expect(mock_postEvent).toHaveBeenCalledWith(eventName, payload);
|
|
67
|
+
});
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
it("skips the event if it is not valid", () => {
|
|
70
|
+
analyticsManager.postAnalyticEvent(42);
|
|
71
|
+
expect(mock_postTimedEvent).not.toHaveBeenCalled();
|
|
72
|
+
});
|
|
71
73
|
});
|
|
72
|
-
});
|
|
73
74
|
|
|
74
|
-
describe("providePlugins", () => {
|
|
75
|
-
|
|
75
|
+
describe("providePlugins", () => {
|
|
76
|
+
beforeEach(clearAllMocks);
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
it("calls the setPlugins method of the analytic bridge", () => {
|
|
79
|
+
const plugins = [];
|
|
80
|
+
const plugin_configurations = {};
|
|
81
|
+
const callback = jest.fn();
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
analyticsManager.providePlugins(plugins, plugin_configurations, callback);
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
expect(mock_setPlugins).toHaveBeenCalledWith(
|
|
86
|
+
plugins,
|
|
87
|
+
plugin_configurations,
|
|
88
|
+
callback
|
|
89
|
+
);
|
|
90
|
+
});
|
|
89
91
|
});
|
|
90
|
-
});
|
|
91
92
|
|
|
92
|
-
describe("startAnalyticsTimedEvent", () => {
|
|
93
|
-
|
|
93
|
+
describe("startAnalyticsTimedEvent", () => {
|
|
94
|
+
beforeEach(clearAllMocks);
|
|
94
95
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
it("skips the event if it is not valid", () => {
|
|
97
|
+
analyticsManager.startAnalyticsTimedEvent(42);
|
|
98
|
+
expect(mock_postTimedEvent).not.toHaveBeenCalled();
|
|
99
|
+
});
|
|
98
100
|
});
|
|
99
|
-
});
|
|
100
101
|
|
|
101
|
-
describe("endAnalyticsTimedEvent", () => {
|
|
102
|
-
|
|
102
|
+
describe("endAnalyticsTimedEvent", () => {
|
|
103
|
+
beforeEach(clearAllMocks);
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
it("emits a time_on_screen event and adds duration to payload", () => {
|
|
106
|
+
analyticsManager.endAnalyticsTimedEvent(eventName, payload);
|
|
107
|
+
const newEventName = "time_on_screen";
|
|
108
|
+
payload.duration = "N/A";
|
|
109
|
+
expect(mock_postEvent).toHaveBeenCalledWith(newEventName, payload);
|
|
110
|
+
});
|
|
110
111
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
it("skips the event if it is not valid", () => {
|
|
113
|
+
analyticsManager.endAnalyticsTimedEvent(42);
|
|
114
|
+
expect(mock_postEvent).not.toHaveBeenCalled();
|
|
115
|
+
});
|
|
114
116
|
});
|
|
115
117
|
});
|
|
@@ -26,7 +26,7 @@ export const useHookAnalytics = (props): void => {
|
|
|
26
26
|
if (screenData?.hookPlugin?.module?.runInBackground) {
|
|
27
27
|
sendScreenEvent({ analyticsScreenData });
|
|
28
28
|
}
|
|
29
|
-
}, [hookPlugin.screen_id]);
|
|
29
|
+
}, [sendScreenEvent, screenData, hookPlugin.screen_id]);
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
export const useScreenAnalytics = (props) => {
|
|
@@ -270,7 +270,9 @@ export function HooksManager({
|
|
|
270
270
|
});
|
|
271
271
|
|
|
272
272
|
const isHookInHomescreen = payload?.home;
|
|
273
|
-
|
|
273
|
+
|
|
274
|
+
const isHookFlowBlocker =
|
|
275
|
+
hookPlugin?.module?.isFlowBlocker?.() ?? false;
|
|
274
276
|
|
|
275
277
|
// TODO: We technically need to also support the case where there is more than one hook in the stack,
|
|
276
278
|
// if needed we could add differentiation explicit user cancellation (when we should go to background) and other types of cancellation
|
|
@@ -187,11 +187,20 @@ export function getTargetInDirection(
|
|
|
187
187
|
return null;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
const orientationDistance = measureDistance(
|
|
191
|
+
direction,
|
|
192
|
+
comparisonRect,
|
|
193
|
+
componentRect
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const euclidDistance = measureEuclidianDistanceToCenter(
|
|
197
|
+
comparisonRect,
|
|
198
|
+
componentRect
|
|
199
|
+
);
|
|
200
|
+
|
|
190
201
|
return {
|
|
191
202
|
distance:
|
|
192
|
-
|
|
193
|
-
measureEuclidianDistanceToCenter(comparisonRect, componentRect) /
|
|
194
|
-
10000,
|
|
203
|
+
orientationDistance > 0 ? euclidDistance : orientationDistance,
|
|
195
204
|
target,
|
|
196
205
|
};
|
|
197
206
|
})
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
const { Platform } = require("react-native");
|
|
2
|
+
|
|
3
|
+
Platform.OS = "web";
|
|
4
|
+
|
|
1
5
|
import { directionHelper } from "../../directionHelper";
|
|
2
6
|
|
|
3
7
|
const globalTizen = {
|
|
@@ -6,105 +10,96 @@ const globalTizen = {
|
|
|
6
10
|
},
|
|
7
11
|
};
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
describe("keyCode", () => {
|
|
14
|
-
const { keyCode } = require("../index");
|
|
15
|
-
const { KEYS } = require("../keys.web");
|
|
16
|
-
|
|
17
|
-
it("returns an object for a given key event", () => {
|
|
18
|
-
expect(keyCode(KEYS.Enter)).toMatchSnapshot();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("has a matcher method for a single key", () => {
|
|
22
|
-
expect(keyCode(KEYS.Enter).matches("Enter")).toBeTruthy();
|
|
23
|
-
expect(keyCode(KEYS.Enter).matches(KEYS.Enter)).toBeTruthy();
|
|
24
|
-
expect(keyCode(KEYS.Back).matches("Enter")).toBeFalsy();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it("has matcher for multiple keys", () => {
|
|
28
|
-
expect(
|
|
29
|
-
keyCode(KEYS.Enter).matchesAny("Enter", "Back", "ArrowUp")
|
|
30
|
-
).toBeTruthy();
|
|
13
|
+
describe("keyCodes", () => {
|
|
14
|
+
describe("keyCode", () => {
|
|
15
|
+
const { keyCode } = require("..");
|
|
16
|
+
const { KEYS } = require("../keys.web");
|
|
31
17
|
|
|
32
|
-
|
|
33
|
-
keyCode(KEYS.Enter).
|
|
34
|
-
)
|
|
35
|
-
});
|
|
18
|
+
it("returns an object for a given key event", () => {
|
|
19
|
+
expect(keyCode(KEYS.Enter)).toMatchSnapshot();
|
|
20
|
+
});
|
|
36
21
|
|
|
37
|
-
|
|
38
|
-
|
|
22
|
+
it("has a matcher method for a single key", () => {
|
|
23
|
+
expect(keyCode(KEYS.Enter).matches("Enter")).toBeTruthy();
|
|
24
|
+
expect(keyCode(KEYS.Enter).matches(KEYS.Enter)).toBeTruthy();
|
|
25
|
+
expect(keyCode(KEYS.Back).matches("Enter")).toBeFalsy();
|
|
26
|
+
});
|
|
39
27
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
28
|
+
it("has matcher for multiple keys", () => {
|
|
29
|
+
expect(
|
|
30
|
+
keyCode(KEYS.Enter).matchesAny("Enter", "Back", "ArrowUp")
|
|
31
|
+
).toBeTruthy();
|
|
44
32
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
expect(
|
|
34
|
+
keyCode(KEYS.Enter).matchesAny("Back", "ArrowUp", "ArrowDown")
|
|
35
|
+
).toBeFalsy();
|
|
48
36
|
});
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
37
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return { Platform: { OS: "samsung_tv" } };
|
|
55
|
-
});
|
|
38
|
+
it("returns the direction if it matches an arrow key", () => {
|
|
39
|
+
expect(keyCode(KEYS.Enter).direction()).toBe(null);
|
|
56
40
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
41
|
+
expect(keyCode(KEYS.ArrowDown).direction()).toEqual(
|
|
42
|
+
directionHelper(KEYS.ArrowDown)
|
|
43
|
+
);
|
|
44
|
+
});
|
|
61
45
|
|
|
62
|
-
|
|
63
|
-
|
|
46
|
+
describe("in web env", () => {
|
|
47
|
+
it("uses the proper keyCode for the environment", () => {
|
|
48
|
+
expect(keyCode({ keyCode: 13 }).matches(KEYS.Enter)).toBeTruthy();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
64
51
|
});
|
|
65
52
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
53
|
+
describe("in Tizen Env", () => {
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
jest.resetModules();
|
|
56
|
+
global.tizen = globalTizen;
|
|
57
|
+
});
|
|
69
58
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"MediaPlayPause",
|
|
74
|
-
"MediaPause",
|
|
75
|
-
"MediaFastForward",
|
|
76
|
-
"MediaRewind",
|
|
77
|
-
"MediaStop",
|
|
78
|
-
"Exit",
|
|
79
|
-
"0",
|
|
80
|
-
"1",
|
|
81
|
-
"2",
|
|
82
|
-
"3",
|
|
83
|
-
"4",
|
|
84
|
-
"5",
|
|
85
|
-
"6",
|
|
86
|
-
"7",
|
|
87
|
-
"8",
|
|
88
|
-
"9",
|
|
89
|
-
]);
|
|
90
|
-
|
|
91
|
-
expect(keyCode({ keyCode: 10009 }).matches(KEYS.Back)).toBeTruthy();
|
|
92
|
-
});
|
|
93
|
-
});
|
|
59
|
+
afterEach(() => {
|
|
60
|
+
global.tizen = undefined;
|
|
61
|
+
});
|
|
94
62
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
63
|
+
it("uses the proper keyCode for the environment", () => {
|
|
64
|
+
Platform.OS = "samsung_tv";
|
|
65
|
+
const { keyCode } = require("../");
|
|
66
|
+
const { KEYS } = require("../keys.web");
|
|
67
|
+
|
|
68
|
+
expect(globalTizen.tvinputdevice.registerKeyBatch).toHaveBeenCalledWith([
|
|
69
|
+
"MediaPlay",
|
|
70
|
+
"MediaPlayPause",
|
|
71
|
+
"MediaPause",
|
|
72
|
+
"MediaFastForward",
|
|
73
|
+
"MediaRewind",
|
|
74
|
+
"MediaStop",
|
|
75
|
+
"Exit",
|
|
76
|
+
"0",
|
|
77
|
+
"1",
|
|
78
|
+
"2",
|
|
79
|
+
"3",
|
|
80
|
+
"4",
|
|
81
|
+
"5",
|
|
82
|
+
"6",
|
|
83
|
+
"7",
|
|
84
|
+
"8",
|
|
85
|
+
"9",
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
expect(keyCode({ keyCode: 10009 }).matches(KEYS.Back)).toBeTruthy();
|
|
89
|
+
});
|
|
98
90
|
});
|
|
99
91
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
92
|
+
describe("in WebOS Env", () => {
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
jest.resetModules();
|
|
95
|
+
});
|
|
103
96
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
97
|
+
it("uses the proper keyCode for the environment", () => {
|
|
98
|
+
Platform.OS = "lg_tv";
|
|
99
|
+
const { keyCode } = require("..");
|
|
100
|
+
const { KEYS } = require("../keys.web");
|
|
101
|
+
// Back is reserved on LG
|
|
102
|
+
expect(keyCode({ keyCode: 417 }).matches(KEYS.Forward)).toBeTruthy();
|
|
103
|
+
});
|
|
109
104
|
});
|
|
110
105
|
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import * as ReactNative from "react-native";
|
|
3
3
|
import { isTV, platformSelect } from "../reactUtils";
|
|
4
4
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
5
|
+
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
5
6
|
|
|
6
7
|
import {
|
|
7
8
|
QUICK_BRICK_EVENTS,
|
|
@@ -9,7 +10,6 @@ import {
|
|
|
9
10
|
sendQuickBrickEvent,
|
|
10
11
|
} from "@applicaster/zapp-react-native-bridge/QuickBrick";
|
|
11
12
|
import { utilsLogger } from "../logger";
|
|
12
|
-
import { useIsTablet } from "../reactHooks/device/useIsTablet";
|
|
13
13
|
|
|
14
14
|
const { DeviceEventEmitter, NativeModules, NativeEventEmitter } = ReactNative;
|
|
15
15
|
|
|
@@ -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
|
|
|
@@ -20,6 +20,11 @@ export enum SharedPlayerCallBacksKeys {
|
|
|
20
20
|
OnPlayerMute = "onPlayerMute",
|
|
21
21
|
OnPlayerUnmute = "onPlayerUnmute",
|
|
22
22
|
|
|
23
|
+
onVideoFullscreenPlayerDidDismiss = "onVideoFullscreenPlayerDidDismiss",
|
|
24
|
+
onVideoFullscreenPlayerDidPresent = "onVideoFullscreenPlayerDidPresent",
|
|
25
|
+
onVideoFullscreenPlayerWillDismiss = "onVideoFullscreenPlayerWillDismiss",
|
|
26
|
+
onVideoFullscreenPlayerWillPresent = "onVideoFullscreenPlayerWillPresent",
|
|
27
|
+
|
|
23
28
|
OnAdBegin = "onAdBegin",
|
|
24
29
|
OnAdBreakBegin = "onAdBreakBegin",
|
|
25
30
|
OnAdBreakEnd = "onAdBreakEnd",
|