@applicaster/zapp-react-native-utils 16.0.0-rc.8 → 16.0.0-rc.81

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 (190) hide show
  1. package/actionsExecutor/ActionExecutor.ts +47 -11
  2. package/actionsExecutor/ActionExecutorContext.tsx +102 -315
  3. package/actionsExecutor/__tests__/feedDecorator.test.ts +61 -0
  4. package/actionsExecutor/actions/__tests__/dismissBottomSheet.test.ts +25 -0
  5. package/actionsExecutor/actions/__tests__/goBack.test.ts +62 -0
  6. package/actionsExecutor/actions/__tests__/goHome.test.ts +19 -0
  7. package/actionsExecutor/actions/__tests__/loadItemsFromSource.test.ts +88 -0
  8. package/actionsExecutor/actions/__tests__/navigateToScreen.test.ts +133 -0
  9. package/actionsExecutor/actions/__tests__/openBottomSheet.customContent.test.ts +76 -0
  10. package/actionsExecutor/actions/__tests__/openBottomSheet.inlineItems.test.ts +212 -0
  11. package/actionsExecutor/actions/__tests__/showToast.test.ts +88 -0
  12. package/actionsExecutor/actions/appRestart.ts +24 -0
  13. package/actionsExecutor/actions/confirmDialog.ts +53 -0
  14. package/actionsExecutor/actions/dismissBottomSheet.ts +23 -0
  15. package/actionsExecutor/actions/goBack.ts +60 -0
  16. package/actionsExecutor/actions/goHome.ts +31 -0
  17. package/actionsExecutor/actions/index.ts +38 -0
  18. package/actionsExecutor/actions/localStorageRemove.ts +27 -0
  19. package/actionsExecutor/actions/localStorageSet.ts +28 -0
  20. package/actionsExecutor/actions/localStorageToggleFlag.ts +28 -0
  21. package/actionsExecutor/actions/navigateToScreen.ts +137 -0
  22. package/actionsExecutor/actions/openBottomSheet.ts +325 -0
  23. package/actionsExecutor/actions/refreshComponent.ts +85 -0
  24. package/actionsExecutor/actions/screenSetVariable.ts +35 -0
  25. package/actionsExecutor/actions/screenToggleFlag.ts +38 -0
  26. package/actionsExecutor/actions/sendCloudEvent.ts +93 -0
  27. package/actionsExecutor/actions/sessionStorageRemove.ts +19 -0
  28. package/actionsExecutor/actions/sessionStorageSet.ts +20 -0
  29. package/actionsExecutor/actions/sessionStorageToggleFlag.ts +15 -0
  30. package/actionsExecutor/actions/showToast.ts +87 -0
  31. package/actionsExecutor/actions/switchLayout.ts +40 -0
  32. package/actionsExecutor/consts.ts +25 -0
  33. package/actionsExecutor/feedDecorator.ts +6 -6
  34. package/actionsExecutor/types.ts +59 -0
  35. package/analyticsUtils/AnalyticsEvents/sendMenuClickEvent.ts +2 -2
  36. package/analyticsUtils/PlayerAnalyticsManager.ts +12 -2
  37. package/analyticsUtils/__tests__/analyticsMapper.test.ts +35 -0
  38. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testACP_events.json +1 -1
  39. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testBlockUnlistedParams_rules.json +1 -1
  40. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEmptyRenameKeepsName_events.json +4 -0
  41. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEmptyRenameKeepsName_rules.json +6 -0
  42. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEventRegex_events.json +3 -9
  43. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testIgnoreOrdering_events.json +18 -0
  44. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testIgnoreOrdering_rules.json +16 -0
  45. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexEventNoFallback_events.json +4 -0
  46. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexEventNoFallback_rules.json +6 -0
  47. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexMultiGroupRename_events.json +4 -0
  48. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexMultiGroupRename_rules.json +6 -0
  49. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexNonNamedFullMatch_events.json +4 -0
  50. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexNonNamedFullMatch_rules.json +6 -0
  51. package/analyticsUtils/__tests__/fixtures/index.js +20 -0
  52. package/analyticsUtils/analyticsMapper.ts +4 -1
  53. package/analyticsUtils/playerAnalyticsTracker.ts +26 -3
  54. package/appUtils/HooksManager/index.ts +12 -8
  55. package/appUtils/contextKeysManager/__tests__/getKey/failure.test.ts +1 -1
  56. package/appUtils/contextKeysManager/__tests__/removeKey/failure.test.ts +1 -1
  57. package/appUtils/contextKeysManager/__tests__/setKey/failure/invalidKey.test.ts +4 -4
  58. package/appUtils/contextKeysManager/index.ts +1 -1
  59. package/appUtils/contextKeysManager/utils/index.ts +38 -25
  60. package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +143 -53
  61. package/appUtils/playerManager/OverlayObserver/__tests__/liveContent.test.ts +205 -0
  62. package/appUtils/playerManager/OverlayObserver/__tests__/utils.test.ts +49 -0
  63. package/appUtils/playerManager/OverlayObserver/getUpcomingQueue.android.tv.ts +4 -0
  64. package/appUtils/playerManager/OverlayObserver/getUpcomingQueue.ios.tv.ts +4 -0
  65. package/appUtils/playerManager/OverlayObserver/getUpcomingQueue.ts +11 -0
  66. package/appUtils/playerManager/OverlayObserver/getUpcomingQueue.web.ts +4 -0
  67. package/appUtils/playerManager/OverlayObserver/utils.ts +54 -20
  68. package/appUtils/playerManager/__tests__/playerContent.test.ts +403 -0
  69. package/appUtils/playerManager/__tests__/playerFactory.test.ts +1 -1
  70. package/appUtils/playerManager/__tests__/playerNative.test.ts +38 -0
  71. package/appUtils/playerManager/__tests__/usePlayerContent.test.tsx +64 -0
  72. package/appUtils/playerManager/{conts.ts → const.ts} +20 -0
  73. package/appUtils/playerManager/index.ts +1 -1
  74. package/appUtils/playerManager/player.ts +115 -3
  75. package/appUtils/playerManager/playerFactory.ts +1 -1
  76. package/appUtils/playerManager/playerNative.ts +6 -4
  77. package/appUtils/playerManager/usePlayerContent.tsx +43 -0
  78. package/appUtils/playerManager/usePlayerControllerSetup.tsx +1 -1
  79. package/appUtils/playerManager/userLanguagePreference.ts +1 -1
  80. package/arrayUtils/__tests__/{anyThruthy.test.ts → anyTruthy.test.ts} +8 -0
  81. package/arrayUtils/__tests__/arrayUtils.test.ts +165 -108
  82. package/arrayUtils/__tests__/isEmptyArray.test.ts +11 -0
  83. package/arrayUtils/__tests__/isFilledArray.test.ts +12 -0
  84. package/arrayUtils/__tests__/isFirst.test.ts +17 -0
  85. package/arrayUtils/__tests__/isIndexInRange.test.ts +14 -0
  86. package/arrayUtils/__tests__/isLast.test.ts +31 -0
  87. package/arrayUtils/__tests__/makeListOf.test.ts +31 -0
  88. package/arrayUtils/__tests__/makeListOfIndexes.test.ts +20 -0
  89. package/arrayUtils/__tests__/reorderByIds.test.ts +50 -0
  90. package/arrayUtils/__tests__/sample.test.ts +61 -0
  91. package/arrayUtils/index.ts +136 -20
  92. package/bottomSheet/__tests__/scrollContext.test.tsx +35 -0
  93. package/bottomSheet/index.ts +17 -0
  94. package/cellUtils/index.ts +33 -8
  95. package/colorUtils/__tests__/isTransparentColor.test.ts +76 -0
  96. package/colorUtils/__tests__/isValidColor.test.ts +70 -0
  97. package/colorUtils/index.ts +50 -0
  98. package/configurationUtils/__tests__/manifestKeyParser.test.ts +21 -0
  99. package/configurationUtils/__tests__/modalBlocksParser.test.ts +260 -0
  100. package/configurationUtils/manifestKeyParser.ts +50 -10
  101. package/configurationUtils/modalBlocksParser.ts +296 -0
  102. package/entryActions/__tests__/buildEntryActions.test.ts +156 -0
  103. package/entryActions/aliasPresentation.ts +124 -0
  104. package/entryActions/buildEntryActions.ts +166 -0
  105. package/entryActions/index.ts +17 -0
  106. package/entryActions/types.ts +39 -0
  107. package/manifestUtils/__tests__/player.audioControls.test.js +158 -0
  108. package/manifestUtils/_internals/index.js +14 -3
  109. package/manifestUtils/defaultManifestConfigurations/generalContent.js +35 -0
  110. package/manifestUtils/defaultManifestConfigurations/player.js +349 -20
  111. package/manifestUtils/fieldUtils/__tests__/fieldUtils.test.js +84 -0
  112. package/manifestUtils/fieldUtils/index.js +125 -0
  113. package/manifestUtils/index.js +3 -0
  114. package/manifestUtils/keys.js +9 -0
  115. package/manifestUtils/mobileAction/button/index.js +16 -0
  116. package/manifestUtils/mobileAction/container/index.js +3 -1
  117. package/manifestUtils/mobileAction/groups/defaults.js +3 -1
  118. package/manifestUtils/modalBlocks.js +304 -0
  119. package/manifestUtils/platformIsTV.js +1 -0
  120. package/modalState/ContentViewModel.ts +113 -0
  121. package/modalState/EditableCollection.ts +17 -0
  122. package/modalState/EditableCollectionRegistry.ts +51 -0
  123. package/modalState/ModalOrchestrator.ts +211 -0
  124. package/modalState/RemoteEditableCollection.ts +227 -0
  125. package/modalState/__tests__/ContentViewModel.editable.test.ts +69 -0
  126. package/modalState/__tests__/ContentViewModel.test.ts +165 -0
  127. package/modalState/__tests__/EditableCollectionRegistry.test.ts +112 -0
  128. package/modalState/__tests__/ModalOrchestrator.phase3.test.ts +47 -0
  129. package/modalState/__tests__/RemoteEditableCollection.test.ts +326 -0
  130. package/modalState/__tests__/index.test.ts +30 -1
  131. package/modalState/__tests__/useBottomSheetContent.test.ts +349 -0
  132. package/modalState/index.ts +35 -83
  133. package/modalState/store.ts +102 -0
  134. package/modalState/types.ts +159 -0
  135. package/modalState/useBottomSheetContent.ts +104 -0
  136. package/numberUtils/__tests__/isMinusZero.test.ts +20 -0
  137. package/numberUtils/__tests__/isZero.test.ts +27 -0
  138. package/numberUtils/__tests__/requireNumber.test.ts +50 -0
  139. package/numberUtils/__tests__/toNumber.test.ts +27 -0
  140. package/numberUtils/__tests__/toNumberWithDefault.test.ts +64 -0
  141. package/numberUtils/__tests__/toNumberWithDefaultZero.test.ts +48 -0
  142. package/numberUtils/index.ts +27 -8
  143. package/package.json +2 -2
  144. package/pipesUtils/__tests__/buildUrlWithQuery.test.ts +33 -0
  145. package/pipesUtils/__tests__/withPipesEndpoint.test.tsx +56 -0
  146. package/pipesUtils/index.ts +1 -0
  147. package/pipesUtils/withPipesEndpoint.tsx +54 -0
  148. package/playerUtils/__tests__/contentDataKeys.test.ts +297 -0
  149. package/playerUtils/__tests__/resolvePlayerActions.test.ts +138 -0
  150. package/playerUtils/__tests__/resolvePlayerTitleSubtitle.test.ts +180 -0
  151. package/playerUtils/contentDataKeys.ts +134 -0
  152. package/playerUtils/index.ts +58 -15
  153. package/playerUtils/isAudioItem.ts +26 -0
  154. package/playerUtils/resolvePlayerActions.ts +71 -0
  155. package/playerUtils/resolvePlayerTitleSubtitle.ts +76 -0
  156. package/reactHooks/actions/index.ts +117 -2
  157. package/reactHooks/cell-click/index.ts +18 -10
  158. package/reactHooks/feed/__mocks__/useMarkPipesDataStale.ts +4 -0
  159. package/reactHooks/feed/__tests__/useInflatedUrl.test.tsx +25 -0
  160. package/reactHooks/feed/index.ts +5 -1
  161. package/reactHooks/feed/useBatchLoading.ts +9 -1
  162. package/reactHooks/feed/{usePipesCacheReset.ts → useMarkPipesDataStale.ts} +12 -4
  163. package/reactHooks/index.ts +2 -0
  164. package/reactHooks/layout/index.ts +1 -1
  165. package/reactHooks/navigation/__mocks__/index.ts +4 -0
  166. package/reactHooks/navigation/__tests__/useIsScreenActive.test.ts +42 -0
  167. package/reactHooks/navigation/index.ts +1 -1
  168. package/reactHooks/navigation/useIsScreenActive.ts +29 -8
  169. package/reactHooks/state/useComponentScreenState.ts +1 -1
  170. package/reactHooks/usePluginConfiguration.ts +4 -1
  171. package/reactHooks/utils/__tests__/index.test.js +22 -2
  172. package/reactHooks/utils/index.ts +13 -2
  173. package/reactHooks/videoModal/hooks/useVideoModalScreenData.tsx +22 -4
  174. package/riverComponetsMeasurementProvider/index.tsx +12 -8
  175. package/stringUtils/__tests__/stringUtils.test.js +42 -0
  176. package/stringUtils/index.ts +2 -2
  177. package/uiActionsRegistrator/__tests__/resolveActionIdentifiers.test.ts +93 -0
  178. package/uiActionsRegistrator/__tests__/subscribe.test.ts +107 -0
  179. package/uiActionsRegistrator/__tests__/usableActionItems.test.ts +52 -0
  180. package/uiActionsRegistrator/index.ts +25 -0
  181. package/uiActionsRegistrator/registry.ts +335 -0
  182. package/uiActionsRegistrator/resolveActionIdentifiers.ts +100 -0
  183. package/uiActionsRegistrator/usableActionItems.ts +66 -0
  184. package/zappFrameworkUtils/__tests__/localStorageHelper.test.ts +146 -0
  185. package/zappFrameworkUtils/localStorageHelper.ts +19 -15
  186. package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +0 -56
  187. package/playerUtils/__tests__/getPlayerActionButtons.test.ts +0 -54
  188. package/playerUtils/getPlayerActionButtons.ts +0 -17
  189. package/reactHooks/feed/__mocks__/usePipesCacheReset.ts +0 -1
  190. /package/reactHooks/actions/__tests__/{index.test.js → index.test.tsx} +0 -0
@@ -204,6 +204,20 @@ function getPlayerConfiguration({ platform, version }) {
204
204
  label_tooltip: "Label for close button accessibility",
205
205
  type: "text_input",
206
206
  },
207
+ {
208
+ key: "accessibility_overflow_label",
209
+ label: "Accessibility overflow label",
210
+ initial_value: "More actions",
211
+ label_tooltip: "Label for the overflow (…) button accessibility",
212
+ type: "text_input",
213
+ },
214
+ {
215
+ key: "accessibility_overflow_hint",
216
+ label: "Accessibility overflow hint",
217
+ initial_value: "Opens the remaining player actions",
218
+ label_tooltip: "Hint for the overflow (…) button accessibility",
219
+ type: "text_input",
220
+ },
207
221
  {
208
222
  key: "accessibility_close_hint",
209
223
  label: "Accessibility close hint",
@@ -383,7 +397,45 @@ function getPlayerConfiguration({ platform, version }) {
383
397
  initial_value: "Start Over",
384
398
  type: "text_input",
385
399
  });
400
+ }
401
+
402
+ if (isMobile(platform)) {
403
+ // Screen reader strings for the audio player's playlist controls. Mobile
404
+ // only, because the audio player layout itself is mobile only.
405
+ localizations.fields.push({
406
+ key: "accessibility_previous_track_label",
407
+ label: "Accessibility previous track label",
408
+ initial_value: "Previous track button",
409
+ label_tooltip: "Label for previous track button accessibility",
410
+ type: "text_input",
411
+ });
386
412
 
413
+ localizations.fields.push({
414
+ key: "accessibility_previous_track_hint",
415
+ label: "Accessibility previous track hint",
416
+ initial_value: "Press to play the previous track",
417
+ label_tooltip: "Hint for previous track button accessibility",
418
+ type: "text_input",
419
+ });
420
+
421
+ localizations.fields.push({
422
+ key: "accessibility_next_track_label",
423
+ label: "Accessibility next track label",
424
+ initial_value: "Next track button",
425
+ label_tooltip: "Label for next track button accessibility",
426
+ type: "text_input",
427
+ });
428
+
429
+ localizations.fields.push({
430
+ key: "accessibility_next_track_hint",
431
+ label: "Accessibility next track hint",
432
+ initial_value: "Press to play the next track",
433
+ label_tooltip: "Hint for next track button accessibility",
434
+ type: "text_input",
435
+ });
436
+ }
437
+
438
+ if (isTV(platform)) {
387
439
  styles.fields.push(
388
440
  fieldsGroup("Always Show Scrub Bar & Timestamp", "", [
389
441
  {
@@ -753,7 +805,7 @@ function getPlayerConfiguration({ platform, version }) {
753
805
  label: "Player action buttons",
754
806
  initial_value: null,
755
807
  label_tooltip:
756
- "type here the identifiers of the action buttons you want to show on the player, separated by commas. Only 2 action buttons may be added at the same time",
808
+ "Comma-separated action identifiers. The entry_actions token expands from the playing entry's extensions.entry_action. When more than 2 actions resolve, the video and fullscreen audio players show Overflow (…) plus one companion - the first action that did not come from the entry, otherwise the first one - and the Overflow sheet lists every resolved action. A repeated identifier is counted once. No extra plugin is required.",
757
809
  type: "text_input",
758
810
  },
759
811
  {
@@ -781,21 +833,6 @@ function getPlayerConfiguration({ platform, version }) {
781
833
  }
782
834
  );
783
835
 
784
- if (
785
- platform.includes("android") ||
786
- platform.includes("amazon") ||
787
- platform.includes("ios") ||
788
- platform.includes("tvos")
789
- ) {
790
- general.fields.push({
791
- key: "user_agent",
792
- label: "User agent",
793
- initial_value: "",
794
- type: "text_input",
795
- label_tooltip: "Override default user agent string",
796
- });
797
- }
798
-
799
836
  if (platform === "android_for_quickbrick") {
800
837
  general.fields.push({
801
838
  key: "stop_playback_on_task_removal",
@@ -1068,6 +1105,13 @@ function getPlayerConfiguration({ platform, version }) {
1068
1105
  type: "uploader",
1069
1106
  label_tooltip: "Override default close badge / icon",
1070
1107
  },
1108
+ {
1109
+ key: "overflow",
1110
+ label: "Overflow badge",
1111
+ type: "uploader",
1112
+ label_tooltip:
1113
+ "Override default overflow (…) badge / icon, shown when more action buttons resolve than fit on the player overlay",
1114
+ },
1071
1115
  {
1072
1116
  key: "lock",
1073
1117
  label: "Lock player badge",
@@ -1236,6 +1280,13 @@ function getPlayerConfiguration({ platform, version }) {
1236
1280
  type: "uploader",
1237
1281
  label_tooltip: "Playback Speed 0.8x",
1238
1282
  initial_value: null,
1283
+ rules: "conditional",
1284
+ conditional_fields: [
1285
+ {
1286
+ key: "styles/player_controls_layout",
1287
+ condition_value: "playback_speed_and_sleep_timer",
1288
+ },
1289
+ ],
1239
1290
  },
1240
1291
  {
1241
1292
  key: "speed_1",
@@ -1243,6 +1294,13 @@ function getPlayerConfiguration({ platform, version }) {
1243
1294
  type: "uploader",
1244
1295
  label_tooltip: "Playback Speed 1x",
1245
1296
  initial_value: null,
1297
+ rules: "conditional",
1298
+ conditional_fields: [
1299
+ {
1300
+ key: "styles/player_controls_layout",
1301
+ condition_value: "playback_speed_and_sleep_timer",
1302
+ },
1303
+ ],
1246
1304
  },
1247
1305
  {
1248
1306
  key: "speed_1_2",
@@ -1250,6 +1308,13 @@ function getPlayerConfiguration({ platform, version }) {
1250
1308
  type: "uploader",
1251
1309
  label_tooltip: "Playback Speed 1.2x",
1252
1310
  initial_value: null,
1311
+ rules: "conditional",
1312
+ conditional_fields: [
1313
+ {
1314
+ key: "styles/player_controls_layout",
1315
+ condition_value: "playback_speed_and_sleep_timer",
1316
+ },
1317
+ ],
1253
1318
  },
1254
1319
  {
1255
1320
  key: "speed_1_5",
@@ -1257,6 +1322,13 @@ function getPlayerConfiguration({ platform, version }) {
1257
1322
  type: "uploader",
1258
1323
  label_tooltip: "Playback Speed 1.5x",
1259
1324
  initial_value: null,
1325
+ rules: "conditional",
1326
+ conditional_fields: [
1327
+ {
1328
+ key: "styles/player_controls_layout",
1329
+ condition_value: "playback_speed_and_sleep_timer",
1330
+ },
1331
+ ],
1260
1332
  },
1261
1333
  {
1262
1334
  key: "speed_2",
@@ -1264,6 +1336,13 @@ function getPlayerConfiguration({ platform, version }) {
1264
1336
  type: "uploader",
1265
1337
  label_tooltip: "Playback Speed 2x",
1266
1338
  initial_value: null,
1339
+ rules: "conditional",
1340
+ conditional_fields: [
1341
+ {
1342
+ key: "styles/player_controls_layout",
1343
+ condition_value: "playback_speed_and_sleep_timer",
1344
+ },
1345
+ ],
1267
1346
  },
1268
1347
  {
1269
1348
  key: "sleep_timer",
@@ -1271,6 +1350,13 @@ function getPlayerConfiguration({ platform, version }) {
1271
1350
  type: "uploader",
1272
1351
  label_tooltip: "Sleep Timer Default",
1273
1352
  initial_value: null,
1353
+ rules: "conditional",
1354
+ conditional_fields: [
1355
+ {
1356
+ key: "styles/player_controls_layout",
1357
+ condition_value: "playback_speed_and_sleep_timer",
1358
+ },
1359
+ ],
1274
1360
  },
1275
1361
  {
1276
1362
  key: "sleep_timer_active",
@@ -1278,6 +1364,43 @@ function getPlayerConfiguration({ platform, version }) {
1278
1364
  type: "uploader",
1279
1365
  label_tooltip: "Sleep Timer Active",
1280
1366
  initial_value: null,
1367
+ rules: "conditional",
1368
+ conditional_fields: [
1369
+ {
1370
+ key: "styles/player_controls_layout",
1371
+ condition_value: "playback_speed_and_sleep_timer",
1372
+ },
1373
+ ],
1374
+ },
1375
+ {
1376
+ key: "previous_track",
1377
+ label: "Previous Track Control Icon",
1378
+ type: "uploader",
1379
+ label_tooltip:
1380
+ "Override the default Previous Track icon. Recommended size 120x120px (@3x).",
1381
+ initial_value: null,
1382
+ rules: "conditional",
1383
+ conditional_fields: [
1384
+ {
1385
+ key: "styles/player_controls_layout",
1386
+ condition_value: "playlist_controls",
1387
+ },
1388
+ ],
1389
+ },
1390
+ {
1391
+ key: "next_track",
1392
+ label: "Next Track Control Icon",
1393
+ type: "uploader",
1394
+ label_tooltip:
1395
+ "Override the default Next Track icon. Recommended size 120x120px (@3x).",
1396
+ initial_value: null,
1397
+ rules: "conditional",
1398
+ conditional_fields: [
1399
+ {
1400
+ key: "styles/player_controls_layout",
1401
+ condition_value: "playlist_controls",
1402
+ },
1403
+ ],
1281
1404
  },
1282
1405
  ]
1283
1406
  ),
@@ -1294,6 +1417,35 @@ function getPlayerConfiguration({ platform, version }) {
1294
1417
  type: "switch",
1295
1418
  label_tooltip: "Select whether you want to display title in player",
1296
1419
  },
1420
+ {
1421
+ section: "title",
1422
+ key: "title_data_key_source",
1423
+ label: "Title data key",
1424
+ initial_value: "title",
1425
+ type: "select",
1426
+ options: [
1427
+ { text: "Title", value: "title" },
1428
+ { text: "Other", value: "other" },
1429
+ ],
1430
+ label_tooltip:
1431
+ "Select which feed data key provides the player content title. Keep 'Title' to use the entry title",
1432
+ },
1433
+ {
1434
+ section: "title",
1435
+ key: "title_custom_data_key",
1436
+ label: "Custom title data key",
1437
+ initial_value: "",
1438
+ type: "text_input",
1439
+ rules: "conditional",
1440
+ conditional_fields: [
1441
+ {
1442
+ key: "styles/title_data_key_source",
1443
+ condition_value: "other",
1444
+ },
1445
+ ],
1446
+ label_tooltip:
1447
+ "Data key on the feed entry, dot notation supported, for example extensions.episode_name. Falls back to the entry title if the key is empty or missing",
1448
+ },
1297
1449
  {
1298
1450
  section: "title",
1299
1451
  key: "title_font_android",
@@ -1701,6 +1853,35 @@ function getPlayerConfiguration({ platform, version }) {
1701
1853
  label_tooltip:
1702
1854
  "Select whether you want to display subtitle in player",
1703
1855
  },
1856
+ {
1857
+ section: "subtitle",
1858
+ key: "subtitle_data_key_source",
1859
+ label: "Subtitle data key",
1860
+ initial_value: "summary",
1861
+ type: "select",
1862
+ options: [
1863
+ { text: "Subtitle", value: "summary" },
1864
+ { text: "Other", value: "other" },
1865
+ ],
1866
+ label_tooltip:
1867
+ "Select which feed data key provides the player content subtitle. Keep 'Subtitle' to use the entry summary",
1868
+ },
1869
+ {
1870
+ section: "subtitle",
1871
+ key: "subtitle_custom_data_key",
1872
+ label: "Custom subtitle data key",
1873
+ initial_value: "",
1874
+ type: "text_input",
1875
+ rules: "conditional",
1876
+ conditional_fields: [
1877
+ {
1878
+ key: "styles/subtitle_data_key_source",
1879
+ condition_value: "other",
1880
+ },
1881
+ ],
1882
+ label_tooltip:
1883
+ "Data key on the feed entry, dot notation supported, for example extensions.episode_subtitle. Falls back to the entry summary if the key is empty or missing",
1884
+ },
1704
1885
  {
1705
1886
  section: "subtitle",
1706
1887
  key: "subtitle_font_android",
@@ -2415,6 +2596,21 @@ function getPlayerConfiguration({ platform, version }) {
2415
2596
  );
2416
2597
  }
2417
2598
 
2599
+ if (
2600
+ platform.includes("android") ||
2601
+ platform.includes("amazon") ||
2602
+ platform.includes("ios") ||
2603
+ platform.includes("tvos")
2604
+ ) {
2605
+ general.fields.push({
2606
+ key: "user_agent",
2607
+ label: "User agent",
2608
+ initial_value: "",
2609
+ type: "text_input",
2610
+ label_tooltip: "Override default user agent string",
2611
+ });
2612
+ }
2613
+
2418
2614
  compact([
2419
2615
  {
2420
2616
  key: "liveCatchUpEnabled",
@@ -2850,6 +3046,33 @@ function getPlayerConfiguration({ platform, version }) {
2850
3046
  "Video Player - Title Text",
2851
3047
  "Video Player Title Text Label Styles",
2852
3048
  [
3049
+ {
3050
+ key: "video_player_title_data_key_source",
3051
+ label: "Video title data key",
3052
+ initial_value: "title",
3053
+ type: "select",
3054
+ options: [
3055
+ { text: "Title", value: "title" },
3056
+ { text: "Other", value: "other" },
3057
+ ],
3058
+ label_tooltip:
3059
+ "Select which feed data key provides the video player title. Keep 'Title' to use the entry title",
3060
+ },
3061
+ {
3062
+ key: "video_player_title_custom_data_key",
3063
+ label: "Custom video title data key",
3064
+ initial_value: "",
3065
+ type: "text_input",
3066
+ rules: "conditional",
3067
+ conditional_fields: [
3068
+ {
3069
+ key: "styles/video_player_title_data_key_source",
3070
+ condition_value: "other",
3071
+ },
3072
+ ],
3073
+ label_tooltip:
3074
+ "Data key on the feed entry, dot notation supported, for example extensions.episode_name. Falls back to the entry title if the key is empty or missing",
3075
+ },
2853
3076
  {
2854
3077
  key: "player_title_color",
2855
3078
  label: "Font color",
@@ -2935,6 +3158,33 @@ function getPlayerConfiguration({ platform, version }) {
2935
3158
  "Video Player - Summary Text",
2936
3159
  "Video Player Summary Text Label Styles",
2937
3160
  [
3161
+ {
3162
+ key: "video_player_summary_data_key_source",
3163
+ label: "Video summary data key",
3164
+ initial_value: "summary",
3165
+ type: "select",
3166
+ options: [
3167
+ { text: "Summary", value: "summary" },
3168
+ { text: "Other", value: "other" },
3169
+ ],
3170
+ label_tooltip:
3171
+ "Select which feed data key provides the video player summary. Keep 'Summary' to use the entry summary",
3172
+ },
3173
+ {
3174
+ key: "video_player_summary_custom_data_key",
3175
+ label: "Custom video summary data key",
3176
+ initial_value: "",
3177
+ type: "text_input",
3178
+ rules: "conditional",
3179
+ conditional_fields: [
3180
+ {
3181
+ key: "styles/video_player_summary_data_key_source",
3182
+ condition_value: "other",
3183
+ },
3184
+ ],
3185
+ label_tooltip:
3186
+ "Data key on the feed entry, dot notation supported, for example extensions.episode_subtitle. Falls back to the entry summary if the key is empty or missing",
3187
+ },
2938
3188
  {
2939
3189
  key: "player_summary_color",
2940
3190
  label: "Font color",
@@ -3020,6 +3270,33 @@ function getPlayerConfiguration({ platform, version }) {
3020
3270
  "Audio Player - Title Text",
3021
3271
  "Audio Player Title Text Label Styles",
3022
3272
  [
3273
+ {
3274
+ key: "audio_player_title_data_key_source",
3275
+ label: "Audio title data key",
3276
+ initial_value: "title",
3277
+ type: "select",
3278
+ options: [
3279
+ { text: "Title", value: "title" },
3280
+ { text: "Other", value: "other" },
3281
+ ],
3282
+ label_tooltip:
3283
+ "Select which feed data key provides the audio player title. Keep 'Title' to use the entry title",
3284
+ },
3285
+ {
3286
+ key: "audio_player_title_custom_data_key",
3287
+ label: "Custom audio title data key",
3288
+ initial_value: "",
3289
+ type: "text_input",
3290
+ rules: "conditional",
3291
+ conditional_fields: [
3292
+ {
3293
+ key: "styles/audio_player_title_data_key_source",
3294
+ condition_value: "other",
3295
+ },
3296
+ ],
3297
+ label_tooltip:
3298
+ "Data key on the feed entry, dot notation supported, for example extensions.episode_name. Falls back to the entry title if the key is empty or missing",
3299
+ },
3023
3300
  {
3024
3301
  key: "audio_player_title_color",
3025
3302
  label: "Audio player title color",
@@ -3105,6 +3382,33 @@ function getPlayerConfiguration({ platform, version }) {
3105
3382
  "Audio Player - Summary Text",
3106
3383
  "Audio Player Summary Text Label Styles",
3107
3384
  [
3385
+ {
3386
+ key: "audio_player_summary_data_key_source",
3387
+ label: "Audio summary data key",
3388
+ initial_value: "summary",
3389
+ type: "select",
3390
+ options: [
3391
+ { text: "Summary", value: "summary" },
3392
+ { text: "Other", value: "other" },
3393
+ ],
3394
+ label_tooltip:
3395
+ "Select which feed data key provides the audio player summary. Keep 'Summary' to use the entry summary",
3396
+ },
3397
+ {
3398
+ key: "audio_player_summary_custom_data_key",
3399
+ label: "Custom audio summary data key",
3400
+ initial_value: "",
3401
+ type: "text_input",
3402
+ rules: "conditional",
3403
+ conditional_fields: [
3404
+ {
3405
+ key: "styles/audio_player_summary_data_key_source",
3406
+ condition_value: "other",
3407
+ },
3408
+ ],
3409
+ label_tooltip:
3410
+ "Data key on the feed entry, dot notation supported, for example extensions.episode_subtitle. Falls back to the entry summary if the key is empty or missing",
3411
+ },
3108
3412
  {
3109
3413
  key: "audio_player_summary_color",
3110
3414
  label: "Audio player summary color",
@@ -3451,6 +3755,31 @@ function getPlayerConfiguration({ platform, version }) {
3451
3755
  },
3452
3756
  ],
3453
3757
  },
3758
+ {
3759
+ key: "player_controls_layout",
3760
+ label: "Player Controls Layout",
3761
+ type: "select",
3762
+ initial_value: "playback_speed_and_sleep_timer",
3763
+ label_tooltip:
3764
+ "Choose which secondary controls appear in the audio player transport row.",
3765
+ rules: "conditional",
3766
+ conditional_fields: [
3767
+ {
3768
+ key: "styles/full_screen_audio_player",
3769
+ condition_value: true,
3770
+ },
3771
+ ],
3772
+ options: [
3773
+ {
3774
+ text: "Playback Speed & Sleep Timer (Default)",
3775
+ value: "playback_speed_and_sleep_timer",
3776
+ },
3777
+ {
3778
+ text: "Playlist Controls (Previous & Next)",
3779
+ value: "playlist_controls",
3780
+ },
3781
+ ],
3782
+ },
3454
3783
  {
3455
3784
  key: "audio_player_artwork_shadow_enabled",
3456
3785
  label: "Image Shadow Enabled",
@@ -3522,13 +3851,13 @@ function getPlayerConfiguration({ platform, version }) {
3522
3851
  label: "Advanced Player Styles",
3523
3852
  type: "text_input",
3524
3853
  multiline: true,
3525
- initial_value: `.vjs-text-track-cue {
3526
- inset: unset !important;
3527
- top: 94% !important;
3854
+ initial_value: `.vjs-text-track-cue {
3855
+ top: auto !important;
3528
3856
  bottom: 0 !important;
3529
3857
  left: 0 !important;
3530
- right: 0 !important;
3858
+ right: auto !important;
3531
3859
  width: 100% !important;
3860
+ height: auto !important;
3532
3861
  }`,
3533
3862
  label_tooltip:
3534
3863
  "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.",
@@ -1,9 +1,93 @@
1
1
  const {
2
+ parseShorthand,
3
+ margin,
4
+ padding,
2
5
  withConditional,
3
6
  getConditionalKey,
4
7
  createConditionalField,
5
8
  } = require("..");
6
9
 
10
+ describe("parseShorthand", () => {
11
+ it("1 value → all four sides equal", () => {
12
+ expect(parseShorthand("8")).toEqual([8, 8, 8, 8]);
13
+ });
14
+
15
+ it("2 values → top/bottom, right/left", () => {
16
+ expect(parseShorthand("0 20")).toEqual([0, 20, 0, 20]);
17
+ });
18
+
19
+ it("3 values → top, right/left, bottom", () => {
20
+ expect(parseShorthand("0 0 20")).toEqual([0, 0, 20, 0]);
21
+ });
22
+
23
+ it("4 values → top right bottom left", () => {
24
+ expect(parseShorthand("1 2 3 4")).toEqual([1, 2, 3, 4]);
25
+ });
26
+
27
+ it("throws on invalid count", () => {
28
+ expect(() => parseShorthand("1 2 3 4 5")).toThrow();
29
+ });
30
+ });
31
+
32
+ describe("margin", () => {
33
+ it("returns 4 field descriptors with correct suffixes", () => {
34
+ const fields = margin("margin", { mobile: "0" });
35
+
36
+ expect(fields.map((f) => f.suffix)).toEqual([
37
+ "margin top",
38
+ "margin right",
39
+ "margin bottom",
40
+ "margin left",
41
+ ]);
42
+ });
43
+
44
+ it("sets type to number_input", () => {
45
+ margin("margin", { mobile: "0" }).forEach((f) => {
46
+ expect(f.type).toBe("number_input");
47
+ });
48
+ });
49
+
50
+ it("expands shorthand per platform", () => {
51
+ const fields = margin("margin", { mobile: "0 0 20", tv: "0 0 90" });
52
+ const byKey = Object.fromEntries(fields.map((f) => [f.suffix, f]));
53
+ expect(byKey["margin top"].initialValue).toEqual({ mobile: 0, tv: 0 });
54
+ expect(byKey["margin bottom"].initialValue).toEqual({ mobile: 20, tv: 90 });
55
+ expect(byKey["margin left"].initialValue).toEqual({ mobile: 0, tv: 0 });
56
+ });
57
+
58
+ it("supports a custom suffix prefix", () => {
59
+ const fields = margin("input margin", { mobile: "4" });
60
+ expect(fields[0].suffix).toBe("input margin top");
61
+ });
62
+ });
63
+
64
+ describe("padding", () => {
65
+ it("returns 4 field descriptors with correct suffixes", () => {
66
+ const fields = padding("padding", { mobile: "0" });
67
+
68
+ expect(fields.map((f) => f.suffix)).toEqual([
69
+ "padding top",
70
+ "padding right",
71
+ "padding bottom",
72
+ "padding left",
73
+ ]);
74
+ });
75
+
76
+ it("expands 2-value shorthand symmetrically", () => {
77
+ const fields = padding("padding", { mobile: "0 20", tv: "0 124" });
78
+ const byKey = Object.fromEntries(fields.map((f) => [f.suffix, f]));
79
+
80
+ expect(byKey["padding right"].initialValue).toEqual({
81
+ mobile: 20,
82
+ tv: 124,
83
+ });
84
+
85
+ expect(byKey["padding left"].initialValue).toEqual({ mobile: 20, tv: 124 });
86
+ expect(byKey["padding top"].initialValue).toEqual({ mobile: 0, tv: 0 });
87
+ expect(byKey["padding bottom"].initialValue).toEqual({ mobile: 0, tv: 0 });
88
+ });
89
+ });
90
+
7
91
  describe("manifestUtils/fieldUtils", () => {
8
92
  it("appends conditions and adds all_conditions when there is more than one condition", () => {
9
93
  const config = {