@applicaster/zapp-react-native-utils 15.0.0-rc.11 → 15.0.0-rc.111

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.
Files changed (158) hide show
  1. package/README.md +0 -6
  2. package/actionsExecutor/ActionExecutorContext.tsx +3 -6
  3. package/actionsExecutor/feedDecorator.ts +6 -6
  4. package/adsUtils/__tests__/createVMAP.test.ts +419 -0
  5. package/adsUtils/index.ts +2 -2
  6. package/analyticsUtils/README.md +1 -1
  7. package/analyticsUtils/analyticsMapper.ts +10 -2
  8. package/appDataUtils/__tests__/urlScheme.test.ts +678 -0
  9. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +0 -188
  10. package/appUtils/HooksManager/__tests__/hooksManager.test.js +16 -2
  11. package/appUtils/HooksManager/index.ts +10 -10
  12. package/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
  13. package/appUtils/accessibilityManager/__tests__/utils.test.ts +360 -0
  14. package/appUtils/accessibilityManager/const.ts +4 -0
  15. package/appUtils/accessibilityManager/hooks.ts +20 -13
  16. package/appUtils/accessibilityManager/index.ts +28 -1
  17. package/appUtils/accessibilityManager/utils.ts +59 -8
  18. package/appUtils/contextKeysManager/__tests__/getKeys/failure.test.ts +7 -2
  19. package/appUtils/contextKeysManager/__tests__/getKeys/success.test.ts +48 -0
  20. package/appUtils/contextKeysManager/contextResolver.ts +51 -22
  21. package/appUtils/contextKeysManager/index.ts +65 -10
  22. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +4 -0
  23. package/appUtils/focusManager/index.ios.ts +59 -3
  24. package/appUtils/focusManager/treeDataStructure/Tree/__tests__/Tree.test.js +46 -0
  25. package/appUtils/focusManager/treeDataStructure/Tree/index.js +18 -18
  26. package/appUtils/focusManagerAux/utils/index.ios.ts +122 -0
  27. package/appUtils/focusManagerAux/utils/index.ts +21 -5
  28. package/appUtils/focusManagerAux/utils/utils.ios.ts +234 -0
  29. package/appUtils/keyCodes/keys/keys.web.ts +1 -4
  30. package/appUtils/orientationHelper.ts +2 -4
  31. package/appUtils/platform/platformUtils.ts +117 -18
  32. package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +94 -4
  33. package/appUtils/playerManager/OverlayObserver/utils.ts +32 -20
  34. package/appUtils/playerManager/player.ts +4 -0
  35. package/appUtils/playerManager/playerNative.ts +31 -17
  36. package/appUtils/playerManager/usePlayerState.tsx +14 -2
  37. package/arrayUtils/__tests__/allTruthy.test.ts +24 -0
  38. package/arrayUtils/__tests__/anyThruthy.test.ts +24 -0
  39. package/arrayUtils/index.ts +5 -0
  40. package/cellUtils/index.ts +32 -0
  41. package/cloudEventsUtils/__tests__/index.test.ts +529 -0
  42. package/cloudEventsUtils/index.ts +65 -1
  43. package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +38 -0
  44. package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
  45. package/configurationUtils/index.ts +17 -11
  46. package/dateUtils/__tests__/dayjs.test.ts +330 -0
  47. package/enumUtils/__tests__/getEnumKeyByEnumValue.test.ts +207 -0
  48. package/errorUtils/__tests__/GeneralError.test.ts +97 -0
  49. package/errorUtils/__tests__/HttpStatusCode.test.ts +344 -0
  50. package/errorUtils/__tests__/MissingPluginError.test.ts +113 -0
  51. package/errorUtils/__tests__/NetworkError.test.ts +202 -0
  52. package/errorUtils/__tests__/getParsedResponse.test.ts +188 -0
  53. package/errorUtils/__tests__/invariant.test.ts +112 -0
  54. package/focusManager/aux/index.ts +1 -1
  55. package/headersUtils/__tests__/headersUtils.test.js +11 -1
  56. package/headersUtils/index.ts +2 -1
  57. package/manifestUtils/defaultManifestConfigurations/player.js +109 -11
  58. package/manifestUtils/keys.js +21 -0
  59. package/manifestUtils/platformIsTV.js +13 -0
  60. package/manifestUtils/sharedConfiguration/screenPicker/utils.js +1 -0
  61. package/manifestUtils/tvAction/container/index.js +1 -1
  62. package/navigationUtils/index.ts +15 -5
  63. package/numberUtils/__tests__/toNumber.test.ts +12 -0
  64. package/numberUtils/__tests__/toPositiveNumber.test.ts +165 -0
  65. package/numberUtils/index.ts +19 -1
  66. package/package.json +4 -4
  67. package/playerUtils/usePlayerTTS.ts +8 -3
  68. package/pluginUtils/index.ts +4 -0
  69. package/reactHooks/advertising/index.ts +2 -2
  70. package/reactHooks/analytics/__tests__/useSendAnalyticsOnPress.test.ts +537 -0
  71. package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
  72. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  73. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -2
  74. package/reactHooks/cell-click/__tests__/index.test.js +1 -3
  75. package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
  76. package/reactHooks/connection/__tests__/index.test.js +1 -1
  77. package/reactHooks/debugging/__tests__/index.test.js +4 -4
  78. package/reactHooks/dev/__tests__/useReRenderLog.test.ts +188 -0
  79. package/reactHooks/device/useIsTablet.tsx +14 -19
  80. package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
  81. package/reactHooks/events/index.ts +20 -0
  82. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +32 -23
  83. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
  84. package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +4 -1
  85. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
  86. package/reactHooks/feed/__tests__/{useInflatedUrl.test.ts → useInflatedUrl.test.tsx} +62 -7
  87. package/reactHooks/feed/index.ts +0 -2
  88. package/reactHooks/feed/useBatchLoading.ts +7 -1
  89. package/reactHooks/feed/useEntryScreenId.ts +2 -2
  90. package/reactHooks/feed/useInflatedUrl.ts +43 -17
  91. package/reactHooks/feed/usePipesCacheReset.ts +3 -1
  92. package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
  93. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +12 -8
  94. package/reactHooks/index.ts +2 -0
  95. package/reactHooks/layout/__tests__/index.test.tsx +1 -1
  96. package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
  97. package/reactHooks/layout/index.ts +1 -1
  98. package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
  99. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
  100. package/reactHooks/navigation/__tests__/index.test.tsx +40 -9
  101. package/reactHooks/navigation/index.ts +27 -11
  102. package/reactHooks/navigation/useRoute.ts +11 -7
  103. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
  104. package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
  105. package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
  106. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
  107. package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
  108. package/reactHooks/resolvers/useCellResolver.ts +6 -2
  109. package/reactHooks/resolvers/useComponentResolver.ts +8 -2
  110. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +2 -2
  111. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
  112. package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
  113. package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +12 -4
  114. package/reactHooks/screen/useTargetScreenData.ts +4 -2
  115. package/reactHooks/state/__tests__/useComponentScreenState.test.ts +246 -0
  116. package/reactHooks/state/index.ts +2 -0
  117. package/reactHooks/state/useComponentScreenState.ts +45 -0
  118. package/reactHooks/state/useRefWithInitialValue.ts +10 -0
  119. package/reactHooks/state/useRivers.ts +1 -1
  120. package/reactHooks/ui/__tests__/useFadeOutWhenBlurred.test.ts +580 -0
  121. package/reactHooks/usePluginConfiguration.ts +2 -2
  122. package/reactHooks/utils/__tests__/index.test.js +1 -1
  123. package/rectUtils/__tests__/index.test.ts +549 -0
  124. package/rectUtils/index.ts +2 -2
  125. package/refreshUtils/RefreshCoordinator/__tests__/refreshCoordinator.test.ts +161 -0
  126. package/refreshUtils/RefreshCoordinator/index.ts +216 -0
  127. package/refreshUtils/RefreshCoordinator/utils/__tests__/getDataRefreshConfig.test.ts +104 -0
  128. package/refreshUtils/RefreshCoordinator/utils/index.ts +29 -0
  129. package/screenPickerUtils/__tests__/index.test.ts +333 -0
  130. package/screenPickerUtils/index.ts +5 -0
  131. package/screenState/__tests__/index.test.ts +1 -1
  132. package/screenUtils/index.ts +3 -0
  133. package/searchUtils/const.ts +7 -0
  134. package/searchUtils/index.ts +3 -0
  135. package/services/storageServiceSync.web.ts +1 -1
  136. package/stringUtils/index.ts +1 -1
  137. package/testUtils/index.tsx +30 -21
  138. package/time/__tests__/BackgroundTimer.test.ts +156 -0
  139. package/time/__tests__/Timer.test.ts +236 -0
  140. package/typeGuards/__tests__/isString.test.ts +21 -0
  141. package/typeGuards/index.ts +4 -0
  142. package/utils/__tests__/clone.test.ts +158 -0
  143. package/utils/__tests__/mapAccum.test.ts +73 -0
  144. package/utils/__tests__/mergeRight.test.ts +48 -0
  145. package/utils/__tests__/path.test.ts +7 -0
  146. package/utils/__tests__/selectors.test.ts +124 -0
  147. package/utils/clone.ts +7 -0
  148. package/utils/index.ts +22 -1
  149. package/utils/mapAccum.ts +23 -0
  150. package/utils/mergeRight.ts +5 -0
  151. package/utils/path.ts +6 -3
  152. package/utils/pathOr.ts +5 -1
  153. package/utils/selectors.ts +46 -0
  154. package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +49 -12
  155. package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
  156. package/reactHooks/componentsMap/index.ts +0 -55
  157. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +0 -75
  158. package/reactHooks/feed/useFeedRefresh.tsx +0 -65
@@ -331,10 +331,53 @@ function getPlayerConfiguration({ platform, version }) {
331
331
  label_tooltip: "Hint for skip intro button accessibility",
332
332
  type: "text_input",
333
333
  },
334
+ {
335
+ type: "text_input",
336
+ label: "Text Tracks Label",
337
+ key: "text_tracks_label",
338
+ initial_value: "Subtitles",
339
+ label_tooltip: "Label for the text tracks list",
340
+ },
341
+ {
342
+ type: "text_input",
343
+ label: "Audio Tracks Label",
344
+ key: "audio_tracks_label",
345
+ initial_value: "Audio",
346
+ label_tooltip: "Label for the audio tracks list",
347
+ },
348
+ {
349
+ type: "text_input",
350
+ label: "Off Track Label",
351
+ key: "off_track_label",
352
+ initial_value: "Off",
353
+ label_tooltip: "Label for the 'Off' option in text tracks list",
354
+ },
355
+ {
356
+ type: "text_input",
357
+ label: "Default Track Label",
358
+ key: "default_track_label",
359
+ initial_value: "Default",
360
+ label_tooltip:
361
+ "Label for the 'Default' audio track in audio tracks list",
362
+ },
334
363
  ],
335
364
  };
336
365
 
337
366
  if (isTV(platform)) {
367
+ localizations.fields.push({
368
+ key: "back_to_live_label",
369
+ label: "Back to live label",
370
+ initial_value: "Back To Live",
371
+ type: "text_input",
372
+ });
373
+
374
+ localizations.fields.push({
375
+ key: "start_over_label",
376
+ label: "Start over label",
377
+ initial_value: "Start Over",
378
+ type: "text_input",
379
+ });
380
+
338
381
  styles.fields.push(
339
382
  fieldsGroup("Always Show Scrub Bar & Timestamp", "", [
340
383
  {
@@ -447,7 +490,7 @@ function getPlayerConfiguration({ platform, version }) {
447
490
  ),
448
491
  fieldsGroup(
449
492
  "Skip Button",
450
- "This section allows you to configure the skip button styles for tv",
493
+ "This section allows you to configure the skip button behaviour",
451
494
  [
452
495
  {
453
496
  type: "switch",
@@ -464,6 +507,12 @@ function getPlayerConfiguration({ platform, version }) {
464
507
  label: "Persistent Button Toggle",
465
508
  initial_value: true,
466
509
  },
510
+ ]
511
+ ),
512
+ fieldsGroup(
513
+ "Labeled Button Style",
514
+ "This section allows you to configure the labeled button styles",
515
+ [
467
516
  {
468
517
  type: "color_picker_rgba",
469
518
  label_tooltip: "",
@@ -619,6 +668,44 @@ function getPlayerConfiguration({ platform, version }) {
619
668
  );
620
669
  }
621
670
 
671
+ if (isTV(platform)) {
672
+ general.fields.push(
673
+ {
674
+ key: "liveSeekingEnabled",
675
+ label: "Live Seeking Enabled",
676
+ initial_value: false,
677
+ type: "switch",
678
+ label_tooltip: "Enable Live Seek",
679
+ },
680
+ {
681
+ key: "minimumAllowedSeekableDurationInSeconds",
682
+ label: "Minimum allowed seekable duration in seconds",
683
+ initial_value: 300,
684
+ type: "number_input",
685
+ label_tooltip:
686
+ "If duration less than this value, player will disable 'liveSeekingEnabled' value",
687
+ },
688
+ {
689
+ key: "live_image",
690
+ label: "Live badge",
691
+ type: "uploader",
692
+ label_tooltip: "Override default live badge / icon",
693
+ },
694
+ {
695
+ key: "live_width",
696
+ label: "Live badge width",
697
+ type: "number_input",
698
+ initial_value: 85,
699
+ },
700
+ {
701
+ key: "live_height",
702
+ label: "Live badge height",
703
+ type: "number_input",
704
+ initial_value: 50,
705
+ }
706
+ );
707
+ }
708
+
622
709
  if (isMobile(platform)) {
623
710
  general.fields.push(
624
711
  {
@@ -1142,40 +1229,35 @@ function getPlayerConfiguration({ platform, version }) {
1142
1229
  label: "Playback Speed 0.8x",
1143
1230
  type: "uploader",
1144
1231
  label_tooltip: "Playback Speed 0.8x",
1145
- initial_value:
1146
- "data:image/png;base64,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",
1232
+ initial_value: null,
1147
1233
  },
1148
1234
  {
1149
1235
  key: "speed_1",
1150
1236
  label: "Playback Speed 1x",
1151
1237
  type: "uploader",
1152
1238
  label_tooltip: "Playback Speed 1x",
1153
- initial_value:
1154
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAI4SURBVHgB7dzhcRJBGIDhT8cCkg6SDmIHsQNLiBUYKwAqUCtIC5ZACVqBdIAdxN3JMSLecXcE8Tt5npkdJlxyf97ZcLcLRAAAAAAAAAAAAAAAAAAAAAAAAADAMb2IiViv17fl4aGMq45fub68vFwFv3kVyZWwF+VhVsZ9MFrqwANmLT1SBm5mbQ37NniWl5FMifu+PHwPcY8izQwuYa/iadbeBkeTaQbfxf64P8r4GoyS7l90h89lXJfxLRgl+23Sqox35f52WX8o/8aDcTLP4EUZrzdxOUzGGbws40MJ6/X2CDIFrhdRNeyn4GjSBBb275jKVTQHEvg/d/aB69Lo+sljGR/jADvnmEUiZx242a2qr/0XzVP35bmHkeeY7Zxj3pw3hXOfwTctz90NjdzEnbccuo0kzj1w1712b+Q9cfed9+TOOnCzSrboONwZuSfuopz3SyRx9hdZJcY8RkQeELfr2D/hNimGR55a3Cr9m+5OpcZpdqvabnNq5HpBdtPx5ynjVmbwlp6ZPLm4lcA7eiLvSh23ErjFwMjp41YCd3t85vEUBG7Rc7W8Mc+27txG4B0D426kjyzwlp64y47nU0cWuDFgEeNNdF94pY0scAxfoeq5uk4Z2Yb/yOXHqUW24X/A2vKAyGk+OGfDv13vIsaBy5onZ8P/T4NXqPZEtuGfwdaG/yp+vfF+HiNsRV5tnSPNhv9kvoSlaj75f9F2zBewAAAAAAAAAAAAAAAAAAAAAAAAwHT8BNhH51wNSx95AAAAAElFTkSuQmCC",
1239
+ initial_value: null,
1155
1240
  },
1156
1241
  {
1157
1242
  key: "speed_1_2",
1158
1243
  label: "Playback Speed 1.2x",
1159
1244
  type: "uploader",
1160
1245
  label_tooltip: "Playback Speed 1.2x",
1161
- initial_value:
1162
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAUjSURBVHgB7d3bUeNIFAbgA7Xv2EUCmgiWjWBNBAwRYCKYdQQrIliIYEUEw0awymDIYDQBUFC8g+eccWsulPomteTu1v9VdZlSGyP0W1KrWxciAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgPgc0Mw8Pj4u+KUt4mm5XDaUqVED5oX5gV/ea6o3vGDvaQI8Hyt+ueAir4XmbTIvNZebnAIfJWBeoCf88g/tFqjOKS/ImkbE8/FezUdBfu5o9wVsKHGHFJBs/rjIAv1E5nBHpebjX/7xI/mHK+SL8Zk/429K3G8UiNoMykItaI/UPvZ/Lic0XMmfR7wmX1GiBq/BP621slAL2j9Z60KE25KQ/6JEDdoHD9jHieD7YJ6fNe22IjpPXG5p16Bq1DT5MpyReZciv/eO5/eJEtN7E63C/Wh5myyQBU1Hu888ODi42263lx0h1Vyu1ZdDvqxd8yvTZC0uKTFDNtGm4GQhbrjc0ERUy73QVNeLxeLctAZyXcUv56R3QQkK2or+9oGHhxXtNmfXNK2Voe6SHKhdxq2muuAvUUGJCRlww+X06Ojock/7qj810+89j2fvDHUFJSZUwLIp/mPsjgsL3S7jC/mZpHdtKkOPg2VhbPYcbEuOVbs2rw35mbJROLohAdeqYRKFgF+ywlCX3GFS7010xiMwZ5rpzVSDIyEFb0WnTLWS1111fHRQU4IQ8K+0vWCvr69J9kcjYEWNHK001c5jxNIvz2XLpfdolIyEtZ/x/Pw8qIMFAdP3ExNKTXVDjl2UqruzHZgoaDdQ4RWyGuZct5/x8vJSqRGyXmYfMC88WUNMvW6nHh03q45pziG/Cdf2uU5mHbAKtzK8xfesjloz3RqyIVzRu/U+24Adwr3y7U+XfgFujOn6srUhW8K9GnJIOsuAHcMtqYfj4+O1T8gO4ZY0wOwCdgj3duhCdQ157HDFrAJ2DHdNATiELCcmrjX1QcIVswl4ynBblpB1540FC1fMImB1nFsZ3hI83JYl5LeChiuyD1jt70yt4dHCbTmGHDxckXXAKtzS8JbRw23xYMXW8hZbfb+/S5mKKVxLa7nl3a3pItiVDaGpoTs5NVf6YeW8qjuP300t3FbwKymiDLgrIJ4m3XXWfuGEwpX/p6slHTTk6AJWIzJlR5UsDDnR/tTwu7ZwGy6Vuo6qF9dTg1w6MR4eHireN3cNBwYLOcY1+MxQt5Khs661WF0/VJJZQbtrqPpquLyzvcm1h0pa1xwyjRlyjI0s29jnief0Sfl2P/r2XfuKMWDbeczRnvimdi9rTbX2ONch5N5f3hgDrgx1N8u4r/BbaaZbOzEsIRfUU3QBq0aMXEvUvKmS1m/s1+nWHdOce6gMIffeao3dyJJj10ZTp5v+beCcN0s17farsk9uHFqvFenPqAjFuPVQ813wjx/UJO+TBiRk/gz5Oxfq7w0a8AcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANif7B8Q/dOlJHI7iEJNvlcl+8tCsg5Y3R/Ldm1QuUz46aI2ud9lx+XCr1HubhOLLNdgh6eQdjn3uZNPKnIN+DP5XzQtl6ha77+Rmuw20eoOOgX5K4bcfSdWOe6Dh9yMJYobuYSUY8BDnj2Y1XMLRY4BD7lJS3LPJrTJMeAht1lK7tmENmhF/4BWdEI25C/L3qwsA1YdFj6BXcX0LOSQcu+LLvnF1g258b2XVUrmMppUcvmdfhznNlz+43Kd+2jSV0z9PFgMpokeAAAAAElFTkSuQmCC",
1246
+ initial_value: null,
1163
1247
  },
1164
1248
  {
1165
1249
  key: "speed_1_5",
1166
1250
  label: "Playback Speed 1.5x",
1167
1251
  type: "uploader",
1168
1252
  label_tooltip: "Playback Speed 1.5x",
1169
- initial_value:
1170
- "data:image/png;base64,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",
1253
+ initial_value: null,
1171
1254
  },
1172
1255
  {
1173
1256
  key: "speed_2",
1174
1257
  label: "Playback Speed 2x",
1175
1258
  type: "uploader",
1176
1259
  label_tooltip: "Playback Speed 2x",
1177
- initial_value:
1178
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAQnSURBVHgB7d2PUdRAFMfxh2MBUIGxArECjwqECjwqUCowV4FYgdABVCAdSAekg7ME35pFgnOb3ZDAvmy+n5lMGJLL3dzvkuyfZCMCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2LMnM7Hdbvd11p2ag4ODRtDLdMAa6kpnH3U61qkKrHbrp0sN/EbwiMmAfbBfdVrJMI1OZxr0leAvcwFruC7YWsY515DPBLYC1nC/6eyLTONCQz6VhXslRvg9d6pwnbX/wSyaiT1Yg6h0dhdZzZ1Xr6U9zzqHOn2QtgDW52jJhS8rAf/Q2Tqw2JWQT0JVIv/j+CnhUvaNvvZIFip7wL5+uw0sbqTdA5vINiqd/ZK2fryLbuLgtyyQhXPwYc+yTUpjhl/ne88qK1koCwGvQgs0uAtJ17duJQtlIeDQYfVWBojs6fuyUK8lP1c63hXmlOfMRZ5/newBT1WF0YJW37m8kYUy09Axgb6ABx3uSzKb7sI+vqrlqknVjsXJ9WC/HRlTpZpiG1MqZQ92zZxVYNmlJPBNpdv2z6c1cfrXjdrG1Ga/B+sX+Vln54HFV7onnUh8GytpW8O6BnVWBFrjTnJ3Xc56D/YFq1C47hCZ2mW46/y99qGlfI5QU+uhZDbbgDtt0CFJrWBeqBAWDTnSjn4jmc0y4E64oQYMF+65JPJVtU1gcTDkSLgbC71YszsHJ/QeuWuz1vK0bdfSFth2eXROTgi3FgNmFXBCuLf6xb6Xce9RSyTkuYTrzOmyWVdg6Tssu/Po0RT1z0jIjYR/YKbCdWYR8EuG23nPWsIh72IuXMd8wDnC7bx3LWkhmwzXsX7he7ZwO5+hlv6QzYbrmK0mWQjXezNyeVZW72wwEW6ktNxl9hpsc3uwfqmfZF7hOsnNmi/NVMA+3AsJh9tI24CfM9ybwP9Nhmzpzob7cEMaSbiEdoLPEWvEcH3Lg5s1c7Fy4Xss3PueoUaeKKVdeEgL1ZBmzZwsXPi+kv5eoUnoF74X+Rx9N77trArNIWQLh+hKMtOgjmVguI7/f9/h+lgyK+miuzGqwP+jjRiRkOnwN2JXh39yC1VPyFeSGQHLvwKYu3bLBd1IOwxELQP49U//28atZGahkFXJC9wcNvA+JwAAAAAAAAAAAAAAAAAAAAAAAIxWxIjvffytMW5M6e4ziO+fOTxkRNpZKjrgyGDh92oNeSOFKvbuQj9Ef8qQwrVft0hF7sEa2FpnQwdDyT78/nMoNeA7GT40RKMBv5XCFHeI9oO6VDJc5V9blBLPwWPGxcg+psbUSgx4X55uzGtNKjHgMcMcPvfItS+uxIDHDHySfdCUqVGKfkApekZSn3jWVWRrVpEB+waLIYFtSh1mqfS26FriD9U4G/KUtLlZSm9SrdM7eajnNjpd63Reem/SH2FDq35f8ateAAAAAElFTkSuQmCC",
1260
+ initial_value: null,
1179
1261
  },
1180
1262
  {
1181
1263
  key: "sleep_timer",
@@ -3429,6 +3511,22 @@ function getPlayerConfiguration({ platform, version }) {
3429
3511
  label_tooltip:
3430
3512
  "This field allows you to override the player configuration / initialization options. i.e. html5: { vhs: { limitRenditionByPlayerDimensions: false } } Please ensure your configuration matches the player you are targeting, and that it is a valid json. See config options here: https://videojs.com/guides/options/",
3431
3513
  },
3514
+ {
3515
+ key: "advanced_player_styles",
3516
+ label: "Advanced Player Styles",
3517
+ type: "text_input",
3518
+ multiline: true,
3519
+ initial_value: `.vjs-text-track-cue {
3520
+ inset: unset !important;
3521
+ top: 94% !important;
3522
+ bottom: 0 !important;
3523
+ left: 0 !important;
3524
+ right: 0 !important;
3525
+ width: 100% !important;
3526
+ }`,
3527
+ label_tooltip:
3528
+ "This field allows you to inject custom CSS styles to override default player styles. The styles will be injected into the document head and can be used to customize the appearance of the player. Leave empty to use only default styles.",
3529
+ },
3432
3530
  {
3433
3531
  key: "use_dashjs_player",
3434
3532
  label: "Use Enhanced Player for DASH streams",
@@ -959,6 +959,27 @@ const TV_CELL_LABEL_FIELDS = [
959
959
  rules: "conditional",
960
960
  conditions: [{ key: "switch", section: "styles", value: true }],
961
961
  },
962
+ {
963
+ type: ZAPPIFEST_FIELDS.font_selector.roku,
964
+ suffix: "roku font family",
965
+ tooltip: "",
966
+ rules: "conditional",
967
+ conditions: [{ key: "switch", section: "styles", value: true }],
968
+ },
969
+ {
970
+ type: ZAPPIFEST_FIELDS.number_input,
971
+ suffix: "roku font size",
972
+ tooltip: "",
973
+ rules: "conditional",
974
+ conditions: [{ key: "switch", section: "styles", value: true }],
975
+ },
976
+ {
977
+ type: ZAPPIFEST_FIELDS.number_input,
978
+ suffix: "roku line height",
979
+ tooltip: "",
980
+ rules: "conditional",
981
+ conditions: [{ key: "switch", section: "styles", value: true }],
982
+ },
962
983
  {
963
984
  type: ZAPPIFEST_FIELDS.select,
964
985
  suffix: "text alignment",
@@ -0,0 +1,13 @@
1
+ function platformIsTV(platform) {
2
+ return [
3
+ "tvos_for_quickbrick",
4
+ "android_tv_for_quickbrick",
5
+ "amazon_fire_tv_for_quickbrick",
6
+ "lg_tv",
7
+ "samsung_tv",
8
+ "web",
9
+ "vizio",
10
+ ].includes(platform);
11
+ }
12
+
13
+ module.exports = { platformIsTV };
@@ -3,6 +3,7 @@ const defaultPlatforms = {
3
3
  android_tv: "Android TV",
4
4
  lg_tv: "LG TV",
5
5
  samsung_tv: "Samsung TV",
6
+ roku: "Roku TV",
6
7
  };
7
8
 
8
9
  const global_defaults = {
@@ -38,7 +38,7 @@ function tvActionButtonsContainer({ label, description, defaults }) {
38
38
  generateFieldsFromDefaultsWithoutPrefixedLabel(
39
39
  label,
40
40
  defaults,
41
- tvActionButtonContainerFields(defaults["position"])
41
+ tvActionButtonContainerFields(defaults.position)
42
42
  )
43
43
  );
44
44
 
@@ -5,7 +5,8 @@ import { layoutV2TypeMatcher } from "./layoutV2TypeMatcher";
5
5
  import { HOOKS_EVENTS } from "../appUtils/HooksManager/constants";
6
6
  import { HooksManager } from "../appUtils/HooksManager";
7
7
  import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
8
- import { HookModalContextT } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
8
+
9
+ import { zappHookModalStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
9
10
  import { logger } from "@applicaster/zapp-react-native-utils/logger";
10
11
  import {
11
12
  isGeneralPlugin,
@@ -15,6 +16,8 @@ import {
15
16
  } from "./itemTypeMatchers";
16
17
  import { RootState } from "@applicaster/zapp-react-native-redux/store";
17
18
 
19
+ import { pick } from "@applicaster/zapp-react-native-utils/utils";
20
+
18
21
  type PathAttribute = {
19
22
  screenType: string;
20
23
  screenId: string;
@@ -403,15 +406,22 @@ export const mapContentTypesToRivers = (
403
406
  };
404
407
 
405
408
  export const runZappHooksForEntry = async (
406
- entry: HookPluginProps["payload"],
407
- {
409
+ entry: HookPluginProps["payload"]
410
+ ): Promise<{ success: boolean; payload: ZappEntry }> => {
411
+ const {
408
412
  setState,
409
413
  resetState,
410
414
  setIsHooksExecutionInProgress,
411
415
  setIsPresentingFullScreen,
412
416
  setIsRunningInBackground,
413
- }: Partial<HookModalContextT>
414
- ): Promise<{ success: boolean; payload: ZappEntry }> => {
417
+ } = pick(zappHookModalStore.getState(), [
418
+ "setState",
419
+ "resetState",
420
+ "setIsHooksExecutionInProgress",
421
+ "setIsPresentingFullScreen",
422
+ "setIsRunningInBackground",
423
+ ]);
424
+
415
425
  resetState?.();
416
426
 
417
427
  let success;
@@ -11,6 +11,16 @@ describe("toNumber", () => {
11
11
  });
12
12
  });
13
13
 
14
+ it("return number if input is BigInt", () => {
15
+ const inputs = [5n, -5n];
16
+ expect.assertions(inputs.length);
17
+
18
+ inputs.forEach((input) => {
19
+ const output = toNumber(input);
20
+ expect(output).toBe(Number(input));
21
+ });
22
+ });
23
+
14
24
  it("return number if input is string as number", () => {
15
25
  const inputs = ["-1", "0", "1", "100", "0.2"];
16
26
  expect.assertions(inputs.length);
@@ -32,6 +42,8 @@ describe("toNumber", () => {
32
42
  { test: 1 },
33
43
  [],
34
44
  [1],
45
+ "5n",
46
+ "-5n",
35
47
  ];
36
48
 
37
49
  expect.assertions(inputs.length);
@@ -0,0 +1,165 @@
1
+ import { toPositiveNumber } from "..";
2
+
3
+ describe("toPositiveNumber", () => {
4
+ describe("valid positive numbers", () => {
5
+ it("returns the number for positive integers", () => {
6
+ expect(toPositiveNumber(5)).toBe(5);
7
+ expect(toPositiveNumber(1000)).toBe(1000);
8
+ });
9
+
10
+ it("returns the number for positive floats", () => {
11
+ expect(toPositiveNumber(0.1)).toBe(0.1);
12
+ expect(toPositiveNumber(3.14159)).toBe(3.14159);
13
+ });
14
+
15
+ it("returns the number for very small positive numbers", () => {
16
+ expect(toPositiveNumber(1e-300)).toBe(1e-300);
17
+ });
18
+
19
+ it("returns the number for very large positive numbers", () => {
20
+ expect(toPositiveNumber(1e300)).toBe(1e300);
21
+ });
22
+
23
+ it("returns Infinity for positive infinity", () => {
24
+ expect(toPositiveNumber(Infinity)).toBe(Infinity);
25
+ });
26
+
27
+ it("converts valid positive strings to numbers", () => {
28
+ expect(toPositiveNumber("5")).toBe(5);
29
+ expect(toPositiveNumber("3.14")).toBe(3.14);
30
+ expect(toPositiveNumber(" 100 ")).toBe(100);
31
+ });
32
+
33
+ it("converts boolean true to undefined", () => {
34
+ expect(toPositiveNumber(true)).toBeUndefined();
35
+ });
36
+
37
+ it("converts single-element arrays to undefined", () => {
38
+ expect(toPositiveNumber([5])).toBeUndefined();
39
+ expect(toPositiveNumber(["10"])).toBeUndefined();
40
+ });
41
+ });
42
+
43
+ describe("invalid cases (return undefined)", () => {
44
+ describe("zero values", () => {
45
+ it("returns undefined for zero", () => {
46
+ expect(toPositiveNumber(0)).toBeUndefined();
47
+ expect(toPositiveNumber(-0)).toBeUndefined();
48
+ });
49
+
50
+ it("returns undefined for string zero", () => {
51
+ expect(toPositiveNumber("0")).toBeUndefined();
52
+ expect(toPositiveNumber(" 0 ")).toBeUndefined();
53
+ });
54
+
55
+ it("returns undefined for boolean false", () => {
56
+ expect(toPositiveNumber(false)).toBeUndefined();
57
+ });
58
+
59
+ it("returns undefined for empty arrays", () => {
60
+ expect(toPositiveNumber([])).toBeUndefined();
61
+ });
62
+
63
+ it("returns undefined for empty strings", () => {
64
+ expect(toPositiveNumber("")).toBeUndefined();
65
+ expect(toPositiveNumber(" ")).toBeUndefined();
66
+ });
67
+ });
68
+
69
+ describe("negative values", () => {
70
+ it("returns undefined for negative numbers", () => {
71
+ expect(toPositiveNumber(-5)).toBeUndefined();
72
+ expect(toPositiveNumber(-0.1)).toBeUndefined();
73
+ });
74
+
75
+ it("returns undefined for negative strings", () => {
76
+ expect(toPositiveNumber("-5")).toBeUndefined();
77
+ expect(toPositiveNumber(" -10 ")).toBeUndefined();
78
+ });
79
+
80
+ it("returns undefined for negative infinity", () => {
81
+ expect(toPositiveNumber(-Infinity)).toBeUndefined();
82
+ });
83
+ });
84
+
85
+ describe("non-convertible values", () => {
86
+ it("returns undefined for null", () => {
87
+ expect(toPositiveNumber(null)).toBeUndefined();
88
+ });
89
+
90
+ it("returns undefined for undefined", () => {
91
+ expect(toPositiveNumber(undefined)).toBeUndefined();
92
+ });
93
+
94
+ it("returns undefined for objects", () => {
95
+ expect(toPositiveNumber({})).toBeUndefined();
96
+ expect(toPositiveNumber({ a: 1 })).toBeUndefined();
97
+ });
98
+
99
+ it("returns undefined for multi-element arrays", () => {
100
+ expect(toPositiveNumber([1, 2])).toBeUndefined();
101
+ expect(toPositiveNumber(["a", "b"])).toBeUndefined();
102
+ });
103
+
104
+ it("returns undefined for non-numeric strings", () => {
105
+ expect(toPositiveNumber("abc")).toBeUndefined();
106
+ expect(toPositiveNumber("5px")).toBeUndefined();
107
+ expect(toPositiveNumber("123.45.67")).toBeUndefined();
108
+ });
109
+
110
+ it("returns undefined for NaN", () => {
111
+ expect(toPositiveNumber(NaN)).toBeUndefined();
112
+ expect(toPositiveNumber(Number("abc"))).toBeUndefined();
113
+ });
114
+ });
115
+ });
116
+
117
+ describe("special cases", () => {
118
+ it("handles exponential notation correctly", () => {
119
+ expect(toPositiveNumber("1e5")).toBe(100000);
120
+ expect(toPositiveNumber("1e-5")).toBe(0.00001);
121
+ expect(toPositiveNumber("-1e5")).toBeUndefined();
122
+ });
123
+
124
+ it("preserves precision for decimal numbers", () => {
125
+ expect(toPositiveNumber(0.1 + 0.2)).toBeCloseTo(0.3);
126
+ expect(toPositiveNumber("0.1")).toBe(0.1);
127
+ });
128
+
129
+ it("handles numeric strings with leading zeros", () => {
130
+ expect(toPositiveNumber("005")).toBe(5);
131
+ expect(toPositiveNumber("0.5")).toBe(0.5);
132
+ });
133
+
134
+ it("returns undefined for numeric strings with trailing non-numeric characters", () => {
135
+ expect(toPositiveNumber("5px")).toBeUndefined();
136
+ expect(toPositiveNumber("10%")).toBeUndefined();
137
+ });
138
+
139
+ it("handles scientific notation correctly", () => {
140
+ expect(toPositiveNumber("1.5e2")).toBe(150);
141
+ expect(toPositiveNumber("-2.5e3")).toBeUndefined();
142
+ });
143
+ });
144
+
145
+ describe("type conversion behavior", () => {
146
+ it("converts Date objects correctly", () => {
147
+ const date = new Date(2026, 1, 17);
148
+ expect(toPositiveNumber(date)).toBeUndefined();
149
+ });
150
+
151
+ it("converts functions to NaN (returns undefined)", () => {
152
+ expect(toPositiveNumber(() => {})).toBeUndefined();
153
+ expect(toPositiveNumber(Math.sqrt)).toBeUndefined();
154
+ });
155
+
156
+ it("handles Symbol values", () => {
157
+ expect(toPositiveNumber(Symbol("test"))).toBeUndefined();
158
+ });
159
+
160
+ it("converts BigInt values", () => {
161
+ expect(toPositiveNumber(5n)).toBe(5);
162
+ expect(toPositiveNumber(-5n)).toBeUndefined();
163
+ });
164
+ });
165
+ });
@@ -8,7 +8,7 @@ export const toNumber = (value: unknown): number | undefined => {
8
8
  return undefined;
9
9
  }
10
10
 
11
- if (R.is(Number, value) || R.is(String, value)) {
11
+ if (R.is(Number, value) || R.is(BigInt, value) || R.is(String, value)) {
12
12
  const numberOrNan = Number(value);
13
13
 
14
14
  return Number.isNaN(numberOrNan) ? undefined : numberOrNan;
@@ -69,6 +69,24 @@ export const isMinusZero = (value: number) => {
69
69
  return 1 / value === -Infinity;
70
70
  };
71
71
 
72
+ export const toPositiveNumber = (value: unknown): number | undefined => {
73
+ const possibleNumber = toNumber(value);
74
+
75
+ if (R.isNil(possibleNumber)) {
76
+ return undefined;
77
+ }
78
+
79
+ if (possibleNumber < 0) {
80
+ return undefined;
81
+ }
82
+
83
+ if (isZero(possibleNumber)) {
84
+ return undefined;
85
+ }
86
+
87
+ return possibleNumber;
88
+ };
89
+
72
90
  export const toPositiveNumberWithDefault = (
73
91
  defaultValue: number,
74
92
  value: unknown
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "15.0.0-rc.11",
3
+ "version": "15.0.0-rc.111",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,13 +27,13 @@
27
27
  },
28
28
  "homepage": "https://github.com/applicaster/quickbrick#readme",
29
29
  "dependencies": {
30
- "@applicaster/applicaster-types": "15.0.0-rc.11",
30
+ "@applicaster/applicaster-types": "15.0.0-rc.111",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
34
+ "handlebars": "4.7.8",
34
35
  "memoizee": "0.4.15",
35
- "prop-types": "^15.0.0",
36
- "react-native-handlebars": "^5.0.0-alpha.1"
36
+ "prop-types": "^15.0.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@applicaster/zapp-pipes-v2-client": "*",
@@ -1,14 +1,19 @@
1
1
  import * as React from "react";
2
2
  import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
3
- import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
3
+ import {
4
+ useAccessibilityManager,
5
+ useAccessibilityState,
6
+ } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
4
7
  import { PlayerTTS } from "@applicaster/zapp-react-native-utils/playerUtils/PlayerTTS";
5
8
 
6
9
  export const usePlayerTTS = () => {
7
10
  const player = usePlayer();
8
11
  const accessibilityManager = useAccessibilityManager({});
12
+ const accessibilityState = useAccessibilityState();
13
+ const isScreenReaderEnabled = accessibilityState.screenReaderEnabled;
9
14
 
10
15
  React.useEffect(() => {
11
- if (player && accessibilityManager) {
16
+ if (player && accessibilityManager && isScreenReaderEnabled) {
12
17
  const playerTTS = new PlayerTTS(player, accessibilityManager);
13
18
  const unsubscribe = playerTTS.init();
14
19
 
@@ -17,5 +22,5 @@ export const usePlayerTTS = () => {
17
22
  playerTTS.destroy();
18
23
  };
19
24
  }
20
- }, [player, accessibilityManager]);
25
+ }, [player, accessibilityManager, isScreenReaderEnabled]);
21
26
  };
@@ -6,6 +6,7 @@ import { deprecationMessage } from "../appUtils";
6
6
 
7
7
  import { pluginUtilsLogger } from "./logger";
8
8
  import { platformSelect } from "../reactUtils";
9
+ import { get } from "../utils";
9
10
 
10
11
  type PluginModule = any;
11
12
  type Plugin = {
@@ -254,3 +255,6 @@ const getPluginType = R.pathOr("unknown_plugin_type", [
254
255
 
255
256
  export const isPlayerPlugin = (routeState): boolean =>
256
257
  getPluginType(routeState) === "player";
258
+
259
+ export const getPluginModuleUrlScheme = (plugin) =>
260
+ get(plugin, ["module", "urlScheme"]);
@@ -3,7 +3,7 @@ import { View } from "react-native";
3
3
  import * as R from "ramda";
4
4
 
5
5
  import { useNavigation } from "../navigation";
6
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
6
+ import { usePlugins } from "@applicaster/zapp-react-native-redux/hooks";
7
7
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
8
8
  import { dismissModal, openModal } from "../../modalState";
9
9
 
@@ -16,7 +16,7 @@ const ModalContainer = platformSelect({
16
16
 
17
17
  export function useAdvertisingInterstitial() {
18
18
  const { screenData, currentRoute } = useNavigation();
19
- const { plugins } = usePickFromState();
19
+ const plugins = usePlugins();
20
20
 
21
21
  return useEffect(() => {
22
22
  // TODD: typing problem: fix any type