@applicaster/zapp-react-native-ui-components 16.0.0-alpha.1263110541 → 16.0.0-alpha.1334507601
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/Components/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +15 -0
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +19 -4
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +43 -1
- package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/factory.test.ts +32 -0
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +1 -2
- package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +4 -2
- package/Components/ModalComponent/ActionsBottomSheet/__tests__/openActionsBottomSheet.test.ts +38 -0
- package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +5 -2
- package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +4 -1
- package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +70 -73
- package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +1 -36
- package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +1 -26
- package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +180 -47
- package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +13 -20
- package/Components/ModalComponent/AudioPlayer/Components/__tests__/Item.test.tsx +113 -0
- package/Components/ModalComponent/AudioPlayer/Components/index.ts +0 -2
- package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +248 -0
- package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +194 -19
- package/Components/ModalComponent/BottomSheetModalContent.tsx +94 -66
- package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
- package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
- package/Components/ModalComponent/SortableList.tsx +38 -23
- package/Components/ModalComponent/SortableList.web.tsx +1 -1
- package/Components/ModalComponent/TextInputContent.tsx +15 -3
- package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +37 -5
- package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +36 -0
- package/Components/ModalComponent/index.tsx +7 -9
- package/Components/ModalComponent/presets/__tests__/getCell.test.ts +24 -0
- package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +1 -1
- package/Components/ModalComponent/presets/selectableCell.tsx +1 -1
- package/Components/ModalComponent/utils.ts +6 -1
- package/Components/OfflineHandler/hooks.ts +0 -12
- package/Components/River/ComponentsMap/ComponentsMap.tsx +85 -59
- package/Components/River/River.tsx +4 -0
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +138 -75
- package/Components/River/__tests__/componentsMap.test.js +8 -3
- package/Components/River/__tests__/resultCallback.test.tsx +47 -0
- package/Components/Screen/__tests__/Screen.test.tsx +24 -0
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
- package/Components/Screen/index.tsx +5 -0
- package/Components/Screen/navigationHandler.ts +8 -8
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +18 -2
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +36 -0
- package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +56 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +21 -4
- package/Contexts/ModalNavigationContext/__tests__/index.test.tsx +15 -0
- package/Contexts/ModalNavigationContext/index.tsx +2 -2
- package/package.json +5 -5
- package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +0 -314
|
@@ -12,14 +12,8 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import React from "react";
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
Platform,
|
|
18
|
-
Pressable,
|
|
19
|
-
StyleSheet,
|
|
20
|
-
Text,
|
|
21
|
-
View,
|
|
22
|
-
} from "react-native";
|
|
15
|
+
import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
|
|
16
|
+
import { Platform, Pressable, StyleSheet, Text, View } from "react-native";
|
|
23
17
|
import {
|
|
24
18
|
MenuItem,
|
|
25
19
|
SelectionBehavior,
|
|
@@ -56,6 +50,12 @@ export type BackgroundConfiguration = {
|
|
|
56
50
|
defaultColor: string;
|
|
57
51
|
focusedColor: string;
|
|
58
52
|
cornerRadius: number;
|
|
53
|
+
paddingTop?: number;
|
|
54
|
+
paddingRight?: number;
|
|
55
|
+
paddingBottom?: number;
|
|
56
|
+
paddingLeft?: number;
|
|
57
|
+
highlightInsetLeft?: number;
|
|
58
|
+
highlightInsetRight?: number;
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
export type ImageConfiguration = {
|
|
@@ -82,6 +82,20 @@ export type NowPlayingAssetConfiguration = {
|
|
|
82
82
|
asset?: string;
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
+
export type CheckboxAssetsConfiguration = {
|
|
86
|
+
/** Unchecked multiSelect control (item.checkbox_asset). */
|
|
87
|
+
asset?: string;
|
|
88
|
+
/** Checked multiSelect control (item.checked_checkbox_asset). */
|
|
89
|
+
checkedAsset?: string;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type ActionButtonAssetsConfiguration = {
|
|
93
|
+
/** Leading remove control on Edit Order rows. */
|
|
94
|
+
removeAsset?: string;
|
|
95
|
+
/** Trailing drag handle on Edit Order / queue rows. */
|
|
96
|
+
dragAsset?: string;
|
|
97
|
+
};
|
|
98
|
+
|
|
85
99
|
export type ItemConfiguration = {
|
|
86
100
|
background: BackgroundConfiguration;
|
|
87
101
|
image: ImageConfiguration;
|
|
@@ -89,6 +103,8 @@ export type ItemConfiguration = {
|
|
|
89
103
|
nowPlayingLabel: LabelConfiguration;
|
|
90
104
|
textLabel1: LabelConfiguration;
|
|
91
105
|
textLabel2: LabelConfiguration;
|
|
106
|
+
checkboxAssets?: CheckboxAssetsConfiguration;
|
|
107
|
+
actionButtonAssets?: ActionButtonAssetsConfiguration;
|
|
92
108
|
};
|
|
93
109
|
|
|
94
110
|
export const DEFAULT_TEXT_LABEL_1_CONFIGURATION: LabelConfiguration = {
|
|
@@ -189,9 +205,9 @@ const CONTAINER_SPEC_LARGE_IMAGE: ContainerSpec = {
|
|
|
189
205
|
|
|
190
206
|
const CONTAINER_SPEC_DEFAULT: ContainerSpec = {
|
|
191
207
|
paddingTop: 8,
|
|
192
|
-
paddingRight:
|
|
208
|
+
paddingRight: 10,
|
|
193
209
|
paddingBottom: 8,
|
|
194
|
-
paddingLeft:
|
|
210
|
+
paddingLeft: 10,
|
|
195
211
|
horizontalGutter: 12,
|
|
196
212
|
verticalGutter: 2,
|
|
197
213
|
};
|
|
@@ -271,13 +287,14 @@ function resolveContainerSpec(image: ImageConfiguration): ContainerSpec {
|
|
|
271
287
|
|
|
272
288
|
export function mapMenuItemToNowPlayingData(
|
|
273
289
|
item: MenuItem,
|
|
274
|
-
isPaused?: boolean
|
|
290
|
+
isPaused?: boolean,
|
|
291
|
+
nowPlayingLabel = "Now Playing"
|
|
275
292
|
): ItemData {
|
|
276
293
|
return {
|
|
277
294
|
imageUri: item.icon,
|
|
278
295
|
textLabel1: item.title,
|
|
279
296
|
textLabel2: item.summary ?? "",
|
|
280
|
-
nowPlayingLabel
|
|
297
|
+
nowPlayingLabel,
|
|
281
298
|
trailingButton: "playPause",
|
|
282
299
|
isSelected: isPaused !== undefined ? !isPaused : item.isSelected,
|
|
283
300
|
};
|
|
@@ -301,10 +318,13 @@ export function mapMenuItemToPlaylistData(
|
|
|
301
318
|
const showSelectionWidget =
|
|
302
319
|
behavior?.selectMode !== "none" && item.trailingButton !== "none";
|
|
303
320
|
|
|
321
|
+
const summary =
|
|
322
|
+
typeof item.summary === "string" ? item.summary.trim() : item.summary;
|
|
323
|
+
|
|
304
324
|
return {
|
|
305
325
|
imageUri: item.icon,
|
|
306
326
|
textLabel1: item.title,
|
|
307
|
-
textLabel2:
|
|
327
|
+
textLabel2: summary || "",
|
|
308
328
|
trailingButton: showSelectionWidget
|
|
309
329
|
? item.trailingButton || ("multiSelect" as ItemButtonAction)
|
|
310
330
|
: undefined,
|
|
@@ -332,21 +352,30 @@ function ItemContainer({
|
|
|
332
352
|
onPress,
|
|
333
353
|
}: ItemContainerProps) {
|
|
334
354
|
const container = resolveContainerSpec(image);
|
|
335
|
-
const
|
|
355
|
+
const insetLeft = background.highlightInsetLeft ?? 0;
|
|
356
|
+
const insetRight = background.highlightInsetRight ?? 0;
|
|
336
357
|
|
|
337
358
|
return (
|
|
338
|
-
<Pressable
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
359
|
+
<Pressable onPress={onPress}>
|
|
360
|
+
{({ pressed }) => (
|
|
361
|
+
<View
|
|
362
|
+
style={{
|
|
363
|
+
marginLeft: insetLeft,
|
|
364
|
+
marginRight: insetRight,
|
|
365
|
+
backgroundColor:
|
|
366
|
+
pressed || focused
|
|
367
|
+
? background.focusedColor
|
|
368
|
+
: background.defaultColor,
|
|
369
|
+
borderRadius: background.cornerRadius,
|
|
370
|
+
paddingTop: background.paddingTop ?? container.paddingTop,
|
|
371
|
+
paddingRight: background.paddingRight ?? container.paddingRight,
|
|
372
|
+
paddingBottom: background.paddingBottom ?? container.paddingBottom,
|
|
373
|
+
paddingLeft: background.paddingLeft ?? container.paddingLeft,
|
|
374
|
+
}}
|
|
375
|
+
>
|
|
376
|
+
{children}
|
|
377
|
+
</View>
|
|
378
|
+
)}
|
|
350
379
|
</Pressable>
|
|
351
380
|
);
|
|
352
381
|
}
|
|
@@ -379,6 +408,10 @@ type ItemLabelProps = {
|
|
|
379
408
|
};
|
|
380
409
|
|
|
381
410
|
function ItemLabel({ text, configuration, focused = false }: ItemLabelProps) {
|
|
411
|
+
if (!text) {
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
|
|
382
415
|
const color =
|
|
383
416
|
focused && configuration.focusedFontColor
|
|
384
417
|
? configuration.focusedFontColor
|
|
@@ -450,6 +483,8 @@ type ItemButtonProps = {
|
|
|
450
483
|
focused?: boolean;
|
|
451
484
|
onPress?: () => void;
|
|
452
485
|
isSelected?: boolean;
|
|
486
|
+
checkboxAssets?: CheckboxAssetsConfiguration;
|
|
487
|
+
actionButtonAssets?: ActionButtonAssetsConfiguration;
|
|
453
488
|
};
|
|
454
489
|
|
|
455
490
|
function ItemButton({
|
|
@@ -457,6 +492,8 @@ function ItemButton({
|
|
|
457
492
|
focused = false,
|
|
458
493
|
onPress,
|
|
459
494
|
isSelected = false,
|
|
495
|
+
checkboxAssets,
|
|
496
|
+
actionButtonAssets,
|
|
460
497
|
}: ItemButtonProps) {
|
|
461
498
|
const layout = BUTTON_LAYOUT_SPEC[action];
|
|
462
499
|
|
|
@@ -531,6 +568,19 @@ function ItemButton({
|
|
|
531
568
|
}
|
|
532
569
|
|
|
533
570
|
case "drag": {
|
|
571
|
+
if (actionButtonAssets?.dragAsset) {
|
|
572
|
+
return (
|
|
573
|
+
<Image
|
|
574
|
+
source={{ uri: actionButtonAssets.dragAsset }}
|
|
575
|
+
style={{
|
|
576
|
+
width: layout.assetWidth,
|
|
577
|
+
height: layout.assetHeight,
|
|
578
|
+
}}
|
|
579
|
+
resizeMode="contain"
|
|
580
|
+
/>
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
|
|
534
584
|
return (
|
|
535
585
|
<View
|
|
536
586
|
style={{
|
|
@@ -565,6 +615,19 @@ function ItemButton({
|
|
|
565
615
|
}
|
|
566
616
|
|
|
567
617
|
case "remove": {
|
|
618
|
+
if (actionButtonAssets?.removeAsset) {
|
|
619
|
+
return (
|
|
620
|
+
<Image
|
|
621
|
+
source={{ uri: actionButtonAssets.removeAsset }}
|
|
622
|
+
style={{
|
|
623
|
+
width: layout.assetWidth,
|
|
624
|
+
height: layout.assetHeight,
|
|
625
|
+
}}
|
|
626
|
+
resizeMode="contain"
|
|
627
|
+
/>
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
|
|
568
631
|
return (
|
|
569
632
|
<View
|
|
570
633
|
style={{
|
|
@@ -590,6 +653,23 @@ function ItemButton({
|
|
|
590
653
|
}
|
|
591
654
|
|
|
592
655
|
case "multiSelect": {
|
|
656
|
+
const studioAsset = isSelected
|
|
657
|
+
? checkboxAssets?.checkedAsset
|
|
658
|
+
: checkboxAssets?.asset;
|
|
659
|
+
|
|
660
|
+
if (studioAsset) {
|
|
661
|
+
return (
|
|
662
|
+
<Image
|
|
663
|
+
source={{ uri: studioAsset }}
|
|
664
|
+
style={{
|
|
665
|
+
width: layout.assetWidth,
|
|
666
|
+
height: layout.assetHeight,
|
|
667
|
+
}}
|
|
668
|
+
resizeMode="contain"
|
|
669
|
+
/>
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
|
|
593
673
|
if (!isSelected) {
|
|
594
674
|
return (
|
|
595
675
|
<View
|
|
@@ -636,18 +716,31 @@ function ItemButton({
|
|
|
636
716
|
}
|
|
637
717
|
};
|
|
638
718
|
|
|
719
|
+
const buttonPadding = {
|
|
720
|
+
paddingTop: layout.paddingTop,
|
|
721
|
+
paddingRight: layout.paddingRight,
|
|
722
|
+
paddingBottom: layout.paddingBottom,
|
|
723
|
+
paddingLeft: layout.paddingLeft,
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
// A nested Pressable with no handler swallows the parent row press.
|
|
727
|
+
if (!onPress) {
|
|
728
|
+
return (
|
|
729
|
+
<View pointerEvents="none" style={buttonPadding}>
|
|
730
|
+
{renderIcon()}
|
|
731
|
+
</View>
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
|
|
639
735
|
return (
|
|
640
736
|
<Pressable
|
|
641
737
|
onPress={(e: any) => {
|
|
642
738
|
e?.stopPropagation?.();
|
|
643
|
-
onPress
|
|
739
|
+
onPress();
|
|
644
740
|
}}
|
|
645
741
|
style={({ pressed }) => [
|
|
742
|
+
buttonPadding,
|
|
646
743
|
{
|
|
647
|
-
paddingTop: layout.paddingTop,
|
|
648
|
-
paddingRight: layout.paddingRight,
|
|
649
|
-
paddingBottom: layout.paddingBottom,
|
|
650
|
-
paddingLeft: layout.paddingLeft,
|
|
651
744
|
opacity: pressed || focused ? 0.7 : 1,
|
|
652
745
|
},
|
|
653
746
|
]}
|
|
@@ -666,6 +759,8 @@ type ItemButtonsProps = {
|
|
|
666
759
|
onTrailingButtonPress?: () => void;
|
|
667
760
|
isSelected?: boolean;
|
|
668
761
|
renderHandle?: (element: React.ReactElement) => React.ReactElement;
|
|
762
|
+
checkboxAssets?: CheckboxAssetsConfiguration;
|
|
763
|
+
actionButtonAssets?: ActionButtonAssetsConfiguration;
|
|
669
764
|
};
|
|
670
765
|
|
|
671
766
|
function ItemButtons({
|
|
@@ -677,6 +772,8 @@ function ItemButtons({
|
|
|
677
772
|
onTrailingButtonPress,
|
|
678
773
|
isSelected = false,
|
|
679
774
|
renderHandle,
|
|
775
|
+
checkboxAssets,
|
|
776
|
+
actionButtonAssets,
|
|
680
777
|
}: ItemButtonsProps) {
|
|
681
778
|
if (!leadingButton && !trailingButton) {
|
|
682
779
|
return null;
|
|
@@ -691,6 +788,8 @@ function ItemButtons({
|
|
|
691
788
|
focused={focusedLeadingButton}
|
|
692
789
|
onPress={onLeadingButtonPress}
|
|
693
790
|
isSelected={isSelected}
|
|
791
|
+
checkboxAssets={checkboxAssets}
|
|
792
|
+
actionButtonAssets={actionButtonAssets}
|
|
694
793
|
/>
|
|
695
794
|
<View style={{ width: BUTTONS_CONTAINER_HORIZONTAL_GUTTER }} />
|
|
696
795
|
</>
|
|
@@ -704,6 +803,8 @@ function ItemButtons({
|
|
|
704
803
|
focused={focusedTrailingButton}
|
|
705
804
|
onPress={onTrailingButtonPress}
|
|
706
805
|
isSelected={isSelected}
|
|
806
|
+
checkboxAssets={checkboxAssets}
|
|
807
|
+
actionButtonAssets={actionButtonAssets}
|
|
707
808
|
/>
|
|
708
809
|
)
|
|
709
810
|
) : (
|
|
@@ -712,6 +813,8 @@ function ItemButtons({
|
|
|
712
813
|
focused={focusedTrailingButton}
|
|
713
814
|
onPress={onTrailingButtonPress}
|
|
714
815
|
isSelected={isSelected}
|
|
816
|
+
checkboxAssets={checkboxAssets}
|
|
817
|
+
actionButtonAssets={actionButtonAssets}
|
|
715
818
|
/>
|
|
716
819
|
)
|
|
717
820
|
) : (
|
|
@@ -720,6 +823,8 @@ function ItemButtons({
|
|
|
720
823
|
focused={focusedTrailingButton}
|
|
721
824
|
onPress={onTrailingButtonPress}
|
|
722
825
|
isSelected={isSelected}
|
|
826
|
+
checkboxAssets={checkboxAssets}
|
|
827
|
+
actionButtonAssets={actionButtonAssets}
|
|
723
828
|
/>
|
|
724
829
|
)
|
|
725
830
|
) : null}
|
|
@@ -761,10 +866,16 @@ export function AudioPlayerTrackItem({
|
|
|
761
866
|
textLabel2,
|
|
762
867
|
nowPlayingLabel,
|
|
763
868
|
nowPlayingAsset,
|
|
869
|
+
checkboxAssets,
|
|
870
|
+
actionButtonAssets,
|
|
764
871
|
} = effectiveConfig;
|
|
765
872
|
|
|
766
873
|
const container = resolveContainerSpec(image);
|
|
767
874
|
|
|
875
|
+
const handleTrailingButtonPress =
|
|
876
|
+
onTrailingButtonPress ??
|
|
877
|
+
(data.trailingButton === "multiSelect" ? onPress : undefined);
|
|
878
|
+
|
|
768
879
|
return (
|
|
769
880
|
<ItemContainer
|
|
770
881
|
image={image}
|
|
@@ -777,22 +888,28 @@ export function AudioPlayerTrackItem({
|
|
|
777
888
|
<View style={{ width: container.horizontalGutter }} />
|
|
778
889
|
<View style={styles.contentColumn}>
|
|
779
890
|
{showNowPlaying ? (
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
891
|
+
<NowPlayingRow
|
|
892
|
+
assetConfiguration={nowPlayingAsset}
|
|
893
|
+
labelConfiguration={nowPlayingLabel}
|
|
894
|
+
label={data.nowPlayingLabel}
|
|
895
|
+
/>
|
|
896
|
+
) : null}
|
|
897
|
+
{showNowPlaying && (data.textLabel1 || data.textLabel2) ? (
|
|
898
|
+
<View style={{ height: container.verticalGutter }} />
|
|
899
|
+
) : null}
|
|
900
|
+
{data.textLabel1 ? (
|
|
901
|
+
<ItemLabel
|
|
902
|
+
text={data.textLabel1}
|
|
903
|
+
configuration={textLabel1}
|
|
904
|
+
focused={focused}
|
|
905
|
+
/>
|
|
906
|
+
) : null}
|
|
907
|
+
{data.textLabel1 && data.textLabel2 ? (
|
|
908
|
+
<View style={{ height: container.verticalGutter }} />
|
|
909
|
+
) : null}
|
|
910
|
+
{data.textLabel2 ? (
|
|
911
|
+
<ItemLabel text={data.textLabel2} configuration={textLabel2} />
|
|
788
912
|
) : null}
|
|
789
|
-
<ItemLabel
|
|
790
|
-
text={data.textLabel1}
|
|
791
|
-
configuration={textLabel1}
|
|
792
|
-
focused={focused}
|
|
793
|
-
/>
|
|
794
|
-
<View style={{ height: container.verticalGutter }} />
|
|
795
|
-
<ItemLabel text={data.textLabel2} configuration={textLabel2} />
|
|
796
913
|
</View>
|
|
797
914
|
<ItemButtons
|
|
798
915
|
leadingButton={data.leadingButton}
|
|
@@ -800,9 +917,11 @@ export function AudioPlayerTrackItem({
|
|
|
800
917
|
focusedLeadingButton={focusedLeadingButton}
|
|
801
918
|
focusedTrailingButton={focusedTrailingButton}
|
|
802
919
|
onLeadingButtonPress={onLeadingButtonPress}
|
|
803
|
-
onTrailingButtonPress={
|
|
920
|
+
onTrailingButtonPress={handleTrailingButtonPress}
|
|
804
921
|
isSelected={data.isSelected}
|
|
805
922
|
renderHandle={renderHandle}
|
|
923
|
+
checkboxAssets={checkboxAssets}
|
|
924
|
+
actionButtonAssets={actionButtonAssets}
|
|
806
925
|
/>
|
|
807
926
|
</View>
|
|
808
927
|
</ItemContainer>
|
|
@@ -819,6 +938,10 @@ export const VARIANT_NOW_PLAYING: ItemConfiguration = {
|
|
|
819
938
|
defaultColor: "transparent",
|
|
820
939
|
focusedColor: "transparent",
|
|
821
940
|
cornerRadius: 0,
|
|
941
|
+
paddingTop: 8,
|
|
942
|
+
paddingRight: 20,
|
|
943
|
+
paddingBottom: 8,
|
|
944
|
+
paddingLeft: 20,
|
|
822
945
|
},
|
|
823
946
|
image: {
|
|
824
947
|
width: 72,
|
|
@@ -839,6 +962,12 @@ export const VARIANT_QUEUED_ITEM: ItemConfiguration = {
|
|
|
839
962
|
defaultColor: "transparent",
|
|
840
963
|
focusedColor: "rgba(62, 62, 62, 1)",
|
|
841
964
|
cornerRadius: 12,
|
|
965
|
+
paddingTop: 8,
|
|
966
|
+
paddingRight: 10,
|
|
967
|
+
paddingBottom: 8,
|
|
968
|
+
paddingLeft: 10,
|
|
969
|
+
highlightInsetLeft: 10,
|
|
970
|
+
highlightInsetRight: 10,
|
|
842
971
|
},
|
|
843
972
|
image: {
|
|
844
973
|
width: 48,
|
|
@@ -859,6 +988,10 @@ export const VARIANT_PLAYLIST_ITEM: ItemConfiguration = {
|
|
|
859
988
|
defaultColor: "transparent",
|
|
860
989
|
focusedColor: "rgba(62, 62, 62, 1)",
|
|
861
990
|
cornerRadius: 12,
|
|
991
|
+
paddingTop: 8,
|
|
992
|
+
paddingRight: 10,
|
|
993
|
+
paddingBottom: 8,
|
|
994
|
+
paddingLeft: 10,
|
|
862
995
|
},
|
|
863
996
|
image: {
|
|
864
997
|
width: 48,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { View } from "react-native";
|
|
3
3
|
import {
|
|
4
4
|
AudioPlayerTrackItem,
|
|
5
5
|
VARIANT_NOW_PLAYING,
|
|
@@ -10,21 +10,16 @@ import type { MenuItem } from "@applicaster/zapp-react-native-utils/modalState/t
|
|
|
10
10
|
import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
|
|
11
11
|
import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
|
|
12
12
|
|
|
13
|
-
const styles = StyleSheet.create({
|
|
14
|
-
divider: {
|
|
15
|
-
height: StyleSheet.hairlineWidth,
|
|
16
|
-
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
|
17
|
-
marginHorizontal: 20,
|
|
18
|
-
marginVertical: 8,
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
|
|
22
13
|
type NowPlayingHeaderSectionProps = {
|
|
23
14
|
onClear?: () => void;
|
|
15
|
+
nextUpTitle?: string;
|
|
16
|
+
nowPlayingTitle?: string;
|
|
24
17
|
};
|
|
25
18
|
|
|
26
19
|
export function NowPlayingHeaderSection({
|
|
27
20
|
onClear,
|
|
21
|
+
nextUpTitle = "Next Up",
|
|
22
|
+
nowPlayingTitle = "Now Playing",
|
|
28
23
|
}: NowPlayingHeaderSectionProps) {
|
|
29
24
|
const player = usePlayer();
|
|
30
25
|
const playerState = usePlayerState("queue-now-playing-section");
|
|
@@ -53,7 +48,8 @@ export function NowPlayingHeaderSection({
|
|
|
53
48
|
|
|
54
49
|
const data = mapMenuItemToNowPlayingData(
|
|
55
50
|
nowPlayingItem,
|
|
56
|
-
playerState?.isPaused
|
|
51
|
+
playerState?.isPaused,
|
|
52
|
+
nowPlayingTitle
|
|
57
53
|
);
|
|
58
54
|
|
|
59
55
|
const handlePlayPause = () => {
|
|
@@ -65,14 +61,11 @@ export function NowPlayingHeaderSection({
|
|
|
65
61
|
};
|
|
66
62
|
|
|
67
63
|
return (
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
/>
|
|
74
|
-
<View style={styles.divider} />
|
|
75
|
-
</View>
|
|
64
|
+
<AudioPlayerTrackItem
|
|
65
|
+
configuration={VARIANT_NOW_PLAYING}
|
|
66
|
+
data={data}
|
|
67
|
+
onTrailingButtonPress={handlePlayPause}
|
|
68
|
+
/>
|
|
76
69
|
);
|
|
77
70
|
};
|
|
78
71
|
|
|
@@ -81,7 +74,7 @@ export function NowPlayingHeaderSection({
|
|
|
81
74
|
{renderNowPlayingTrack()}
|
|
82
75
|
<AudioPlayerHeader
|
|
83
76
|
configuration={VARIANT_SECTION_HEADER}
|
|
84
|
-
data={{ title:
|
|
77
|
+
data={{ title: nextUpTitle }}
|
|
85
78
|
onClear={onClear}
|
|
86
79
|
/>
|
|
87
80
|
</View>
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Pressable } from "react-native";
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react-native";
|
|
4
|
+
import {
|
|
5
|
+
AudioPlayerTrackItem,
|
|
6
|
+
VARIANT_PLAYLIST_ITEM,
|
|
7
|
+
mapMenuItemToNowPlayingData,
|
|
8
|
+
} from "../Item";
|
|
9
|
+
|
|
10
|
+
const playlistItemData = {
|
|
11
|
+
textLabel1: "Queue",
|
|
12
|
+
textLabel2: "",
|
|
13
|
+
trailingButton: "multiSelect" as const,
|
|
14
|
+
isSelected: false,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
describe("AudioPlayerTrackItem multiSelect checkbox", () => {
|
|
18
|
+
it("invokes onPress when the checkbox is pressed even if onTrailingButtonPress is omitted", () => {
|
|
19
|
+
const onPress = jest.fn();
|
|
20
|
+
|
|
21
|
+
render(
|
|
22
|
+
<AudioPlayerTrackItem
|
|
23
|
+
configuration={VARIANT_PLAYLIST_ITEM}
|
|
24
|
+
data={playlistItemData}
|
|
25
|
+
onPress={onPress}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const pressables = screen.UNSAFE_getAllByType(Pressable);
|
|
30
|
+
fireEvent.press(pressables[pressables.length - 1]);
|
|
31
|
+
|
|
32
|
+
expect(onPress).toHaveBeenCalledTimes(1);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("invokes onTrailingButtonPress instead of onPress when a dedicated trailing handler is provided", () => {
|
|
36
|
+
const onPress = jest.fn();
|
|
37
|
+
const onTrailingButtonPress = jest.fn();
|
|
38
|
+
|
|
39
|
+
render(
|
|
40
|
+
<AudioPlayerTrackItem
|
|
41
|
+
configuration={VARIANT_PLAYLIST_ITEM}
|
|
42
|
+
data={playlistItemData}
|
|
43
|
+
onPress={onPress}
|
|
44
|
+
onTrailingButtonPress={onTrailingButtonPress}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const pressables = screen.UNSAFE_getAllByType(Pressable);
|
|
49
|
+
fireEvent.press(pressables[pressables.length - 1]);
|
|
50
|
+
|
|
51
|
+
expect(onTrailingButtonPress).toHaveBeenCalledTimes(1);
|
|
52
|
+
expect(onPress).not.toHaveBeenCalled();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("invokes onPress when the row is pressed", () => {
|
|
56
|
+
const onPress = jest.fn();
|
|
57
|
+
|
|
58
|
+
render(
|
|
59
|
+
<AudioPlayerTrackItem
|
|
60
|
+
configuration={VARIANT_PLAYLIST_ITEM}
|
|
61
|
+
data={playlistItemData}
|
|
62
|
+
onPress={onPress}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
fireEvent.press(screen.UNSAFE_getAllByType(Pressable)[0]);
|
|
67
|
+
|
|
68
|
+
expect(onPress).toHaveBeenCalledTimes(1);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("renders only textLabel1 Text element when textLabel2 is missing or empty", () => {
|
|
72
|
+
const { UNSAFE_getAllByType, queryByText } = render(
|
|
73
|
+
<AudioPlayerTrackItem
|
|
74
|
+
configuration={VARIANT_PLAYLIST_ITEM}
|
|
75
|
+
data={{
|
|
76
|
+
textLabel1: "Only Title",
|
|
77
|
+
textLabel2: "",
|
|
78
|
+
}}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const { Text } = require("react-native");
|
|
83
|
+
const textNodes = UNSAFE_getAllByType(Text);
|
|
84
|
+
expect(textNodes).toHaveLength(1);
|
|
85
|
+
expect(queryByText("Only Title")).toBeTruthy();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe("mapMenuItemToNowPlayingData", () => {
|
|
90
|
+
const item = {
|
|
91
|
+
id: "item_1",
|
|
92
|
+
title: "Track Title",
|
|
93
|
+
summary: "Artist Name",
|
|
94
|
+
icon: "https://example.com/cover.png",
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
it("uses default 'Now Playing' label when omitted", () => {
|
|
98
|
+
const data = mapMenuItemToNowPlayingData(item as any);
|
|
99
|
+
expect(data.nowPlayingLabel).toBe("Now Playing");
|
|
100
|
+
expect(data.textLabel1).toBe("Track Title");
|
|
101
|
+
expect(data.textLabel2).toBe("Artist Name");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("uses custom nowPlayingLabel when provided", () => {
|
|
105
|
+
const data = mapMenuItemToNowPlayingData(
|
|
106
|
+
item as any,
|
|
107
|
+
false,
|
|
108
|
+
"En cours de lecture"
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
expect(data.nowPlayingLabel).toBe("En cours de lecture");
|
|
112
|
+
});
|
|
113
|
+
});
|