@applicaster/zapp-react-native-ui-components 15.1.5 → 15.1.6-alpha.2015591222
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/ModalComponent/AudioPlayer/Components/Action.tsx +33 -69
- package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +25 -47
- package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +122 -39
- package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +671 -0
- package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +299 -131
- package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +86 -0
- package/Components/ModalComponent/AudioPlayer/Components/index.ts +8 -4
- package/Components/ModalComponent/BottomSheetModalContent.tsx +290 -55
- package/Components/ModalComponent/Button/index.tsx +5 -3
- package/Components/ModalComponent/Header/utils.ts +1 -1
- package/Components/ModalComponent/SortableList.tsx +142 -0
- package/Components/ModalComponent/TextInputContent.tsx +100 -0
- package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +183 -0
- package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +128 -0
- package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
- package/Components/ModalComponent/index.tsx +11 -0
- package/Components/ModalComponent/presets/__tests__/getCell.test.ts +66 -0
- package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +74 -0
- package/Components/ModalComponent/presets/index.ts +27 -0
- package/Components/ModalComponent/presets/selectableCell.tsx +27 -0
- package/Components/ModalComponent/presets/standardCell.tsx +41 -0
- package/Components/ModalComponent/presets/types.ts +35 -0
- package/Components/ModalComponent/showTextInput.ts +43 -0
- package/package.json +6 -5
|
@@ -12,7 +12,18 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import React from "react";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
Image,
|
|
17
|
+
Platform,
|
|
18
|
+
Pressable,
|
|
19
|
+
StyleSheet,
|
|
20
|
+
Text,
|
|
21
|
+
View,
|
|
22
|
+
} from "react-native";
|
|
23
|
+
import {
|
|
24
|
+
MenuItem,
|
|
25
|
+
SelectionBehavior,
|
|
26
|
+
} from "@applicaster/zapp-react-native-utils/modalState/types";
|
|
16
27
|
|
|
17
28
|
const styles = StyleSheet.create({
|
|
18
29
|
row: {
|
|
@@ -97,50 +108,6 @@ export type ItemConfiguration = {
|
|
|
97
108
|
textLabel2: LabelConfiguration;
|
|
98
109
|
};
|
|
99
110
|
|
|
100
|
-
export interface Action {
|
|
101
|
-
type: string;
|
|
102
|
-
payload?: any;
|
|
103
|
-
options?: any;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export interface Header {
|
|
107
|
-
title: string;
|
|
108
|
-
subtitle?: string;
|
|
109
|
-
icon?: string;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export interface Content {
|
|
113
|
-
title: string;
|
|
114
|
-
stickyTitle?: boolean;
|
|
115
|
-
items: MenuItem[];
|
|
116
|
-
itemsUrl?: string;
|
|
117
|
-
action?: Action;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export interface Menu {
|
|
121
|
-
header?: Header;
|
|
122
|
-
content: Content;
|
|
123
|
-
closeButton?: boolean;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export interface PresentSubMenuAction extends Action {
|
|
127
|
-
menu: Menu;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export interface SecondaryAction {
|
|
131
|
-
action: Action | PresentSubMenuAction;
|
|
132
|
-
icon?: string;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export interface MenuItem {
|
|
136
|
-
title: string;
|
|
137
|
-
summary?: string;
|
|
138
|
-
icon?: string;
|
|
139
|
-
isSelected?: boolean;
|
|
140
|
-
action?: Action | PresentSubMenuAction;
|
|
141
|
-
secondaryAction?: SecondaryAction;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
111
|
export const DEFAULT_TEXT_LABEL_1_CONFIGURATION: LabelConfiguration = {
|
|
145
112
|
fontColor: "#FFFFFF",
|
|
146
113
|
focusedFontColor: "#FFFFFF",
|
|
@@ -191,14 +158,19 @@ export type ItemData = {
|
|
|
191
158
|
leadingButton?: ItemButtonAction;
|
|
192
159
|
/** Button 1 (right most) — hardcoded action decides icon. */
|
|
193
160
|
trailingButton?: ItemButtonAction;
|
|
161
|
+
isSelected?: boolean;
|
|
194
162
|
};
|
|
195
163
|
|
|
196
|
-
export type
|
|
164
|
+
export type AudioPlayerTrackItemProps = {
|
|
197
165
|
configuration: ItemConfiguration;
|
|
198
166
|
data: ItemData;
|
|
199
167
|
focused?: boolean;
|
|
200
168
|
focusedLeadingButton?: boolean;
|
|
201
169
|
focusedTrailingButton?: boolean;
|
|
170
|
+
onPress?: () => void;
|
|
171
|
+
onLeadingButtonPress?: () => void;
|
|
172
|
+
onTrailingButtonPress?: () => void;
|
|
173
|
+
renderHandle?: (element: React.ReactElement) => React.ReactElement;
|
|
202
174
|
};
|
|
203
175
|
|
|
204
176
|
// ---------------------------------------------------------------------------
|
|
@@ -234,9 +206,9 @@ const CONTAINER_SPEC_LARGE_IMAGE: ContainerSpec = {
|
|
|
234
206
|
|
|
235
207
|
const CONTAINER_SPEC_DEFAULT: ContainerSpec = {
|
|
236
208
|
paddingTop: 8,
|
|
237
|
-
paddingRight:
|
|
209
|
+
paddingRight: 20,
|
|
238
210
|
paddingBottom: 8,
|
|
239
|
-
paddingLeft:
|
|
211
|
+
paddingLeft: 20,
|
|
240
212
|
horizontalGutter: 12,
|
|
241
213
|
verticalGutter: 2,
|
|
242
214
|
};
|
|
@@ -297,16 +269,6 @@ const DEFAULT_THUMB_ASSET =
|
|
|
297
269
|
const DEFAULT_EQUALIZER_ASSET =
|
|
298
270
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAI0lEQVR42mNgGNTgPxTQzwB0DVQ3gKCBowbQwYAhkBIHBAAA9TvPMeOFaLMAAAAASUVORK5CYII=";
|
|
299
271
|
|
|
300
|
-
const BUTTON_ASSETS: Record<ItemButtonAction, string> = {
|
|
301
|
-
playPause:
|
|
302
|
-
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAAdklEQVR42u3ZwRUAERAEUfkn3TaF5TFTrSuCf3CgjZGg6ast7G8YaAlcB8JAj8F1MRR2G63CUNglNAqsRvmB1TAfsBoXcMABV4MFKEci4IADNrkAed2H80R66SHqvUvglh/ktoZcL5H7MHKBx/5xYH+RsP90t5t2UpF6+22a+AAAAABJRU5ErkJggg==",
|
|
303
|
-
drag: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAIklEQVR42mNgGAWjYGiC/2SCwWPBaByMxsFoHIyCUTDYAAAqhk7AVXdZJwAAAABJRU5ErkJggg==",
|
|
304
|
-
multiSelect:
|
|
305
|
-
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAWklEQVR42t2VUQ4AIAhCvf+lrQsULJJZbH7GM1cS0Uk5dd0Qqcz4GJSCSs0pSCkAHNoWBfkTgIxpgGK+ujyEKABqRGyn9FO1A+yfrf+qsGxTSx5YEs2WyU9oAKBJKg8Kfq4dAAAAAElFTkSuQmCC",
|
|
306
|
-
remove:
|
|
307
|
-
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAUklEQVR42mNgGPbgPx5AVYOJlSPJcGqrJU8DKXooCVui9FIacXj1UyNl4DWDLhYgc8nA+INpeFgwtCOZ5vmALjmZ5mURXUpTutQHdKnRRgEMAACwjWWprU1B+AAAAABJRU5ErkJggg==",
|
|
308
|
-
};
|
|
309
|
-
|
|
310
272
|
function getTextTransformStyle(
|
|
311
273
|
textTransform: TextTransform
|
|
312
274
|
): "none" | "lowercase" | "uppercase" | "capitalize" {
|
|
@@ -324,32 +286,43 @@ function resolveContainerSpec(image: ImageConfiguration): ContainerSpec {
|
|
|
324
286
|
: CONTAINER_SPEC_DEFAULT;
|
|
325
287
|
}
|
|
326
288
|
|
|
327
|
-
function mapMenuItemToNowPlayingData(item: MenuItem): ItemData {
|
|
289
|
+
export function mapMenuItemToNowPlayingData(item: MenuItem): ItemData {
|
|
328
290
|
return {
|
|
329
291
|
imageUri: item.icon,
|
|
330
292
|
textLabel1: item.title,
|
|
331
293
|
textLabel2: item.summary ?? "",
|
|
332
294
|
nowPlayingLabel: "Now Playing",
|
|
333
295
|
trailingButton: "playPause",
|
|
296
|
+
isSelected: item.isSelected,
|
|
334
297
|
};
|
|
335
298
|
}
|
|
336
299
|
|
|
337
|
-
function mapMenuItemToQueuedData(item: MenuItem): ItemData {
|
|
300
|
+
export function mapMenuItemToQueuedData(item: MenuItem): ItemData {
|
|
338
301
|
return {
|
|
339
302
|
imageUri: item.icon,
|
|
340
303
|
textLabel1: item.title,
|
|
341
304
|
textLabel2: item.summary ?? "",
|
|
342
305
|
leadingButton: "remove",
|
|
343
306
|
trailingButton: "drag",
|
|
307
|
+
isSelected: item.isSelected,
|
|
344
308
|
};
|
|
345
309
|
}
|
|
346
310
|
|
|
347
|
-
function mapMenuItemToPlaylistData(
|
|
311
|
+
export function mapMenuItemToPlaylistData(
|
|
312
|
+
item: MenuItem,
|
|
313
|
+
behavior?: SelectionBehavior
|
|
314
|
+
): ItemData {
|
|
315
|
+
const showSelectionWidget =
|
|
316
|
+
behavior?.selectMode !== "none" && item.trailingButton !== "none";
|
|
317
|
+
|
|
348
318
|
return {
|
|
349
319
|
imageUri: item.icon,
|
|
350
320
|
textLabel1: item.title,
|
|
351
321
|
textLabel2: item.summary ?? "",
|
|
352
|
-
trailingButton:
|
|
322
|
+
trailingButton: showSelectionWidget
|
|
323
|
+
? item.trailingButton || ("multiSelect" as ItemButtonAction)
|
|
324
|
+
: undefined,
|
|
325
|
+
isSelected: item.isSelected,
|
|
353
326
|
};
|
|
354
327
|
}
|
|
355
328
|
|
|
@@ -362,6 +335,7 @@ type ItemContainerProps = {
|
|
|
362
335
|
background: BackgroundConfiguration;
|
|
363
336
|
focused: boolean;
|
|
364
337
|
children: React.ReactNode;
|
|
338
|
+
onPress?: () => void;
|
|
365
339
|
};
|
|
366
340
|
|
|
367
341
|
function ItemContainer({
|
|
@@ -369,23 +343,25 @@ function ItemContainer({
|
|
|
369
343
|
background,
|
|
370
344
|
focused,
|
|
371
345
|
children,
|
|
346
|
+
onPress,
|
|
372
347
|
}: ItemContainerProps) {
|
|
373
348
|
const container = resolveContainerSpec(image);
|
|
374
349
|
const bg = focused ? background.focusedColor : background.defaultColor;
|
|
375
350
|
|
|
376
351
|
return (
|
|
377
|
-
<
|
|
378
|
-
|
|
379
|
-
|
|
352
|
+
<Pressable
|
|
353
|
+
onPress={onPress}
|
|
354
|
+
style={({ pressed }) => ({
|
|
355
|
+
backgroundColor: pressed ? background.focusedColor : bg,
|
|
380
356
|
borderRadius: background.cornerRadius,
|
|
381
357
|
paddingTop: container.paddingTop,
|
|
382
358
|
paddingRight: container.paddingRight,
|
|
383
359
|
paddingBottom: container.paddingBottom,
|
|
384
360
|
paddingLeft: container.paddingLeft,
|
|
385
|
-
}}
|
|
361
|
+
})}
|
|
386
362
|
>
|
|
387
363
|
{children}
|
|
388
|
-
</
|
|
364
|
+
</Pressable>
|
|
389
365
|
);
|
|
390
366
|
}
|
|
391
367
|
|
|
@@ -486,27 +462,212 @@ function NowPlayingRow({
|
|
|
486
462
|
type ItemButtonProps = {
|
|
487
463
|
action: ItemButtonAction;
|
|
488
464
|
focused?: boolean;
|
|
465
|
+
onPress?: () => void;
|
|
466
|
+
isSelected?: boolean;
|
|
489
467
|
};
|
|
490
468
|
|
|
491
|
-
function ItemButton({
|
|
469
|
+
function ItemButton({
|
|
470
|
+
action,
|
|
471
|
+
focused = false,
|
|
472
|
+
onPress,
|
|
473
|
+
isSelected = false,
|
|
474
|
+
}: ItemButtonProps) {
|
|
492
475
|
const layout = BUTTON_LAYOUT_SPEC[action];
|
|
493
476
|
|
|
477
|
+
if (!layout) {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const renderIcon = () => {
|
|
482
|
+
switch (action) {
|
|
483
|
+
case "playPause": {
|
|
484
|
+
const iconSize = layout.assetWidth;
|
|
485
|
+
const iconRadius = iconSize / 2;
|
|
486
|
+
|
|
487
|
+
return (
|
|
488
|
+
<View
|
|
489
|
+
style={{
|
|
490
|
+
width: iconSize,
|
|
491
|
+
height: iconSize,
|
|
492
|
+
borderRadius: iconRadius,
|
|
493
|
+
backgroundColor: "#FFFFFF",
|
|
494
|
+
justifyContent: "center",
|
|
495
|
+
alignItems: "center",
|
|
496
|
+
}}
|
|
497
|
+
>
|
|
498
|
+
{isSelected ? (
|
|
499
|
+
<View
|
|
500
|
+
style={{
|
|
501
|
+
flexDirection: "row",
|
|
502
|
+
justifyContent: "space-between",
|
|
503
|
+
width: 10,
|
|
504
|
+
height: 16,
|
|
505
|
+
}}
|
|
506
|
+
>
|
|
507
|
+
<View
|
|
508
|
+
style={{
|
|
509
|
+
width: 3.5,
|
|
510
|
+
height: 16,
|
|
511
|
+
backgroundColor: "#1e1e1e",
|
|
512
|
+
borderRadius: 1,
|
|
513
|
+
}}
|
|
514
|
+
/>
|
|
515
|
+
<View
|
|
516
|
+
style={{
|
|
517
|
+
width: 3.5,
|
|
518
|
+
height: 16,
|
|
519
|
+
backgroundColor: "#1e1e1e",
|
|
520
|
+
borderRadius: 1,
|
|
521
|
+
}}
|
|
522
|
+
/>
|
|
523
|
+
</View>
|
|
524
|
+
) : (
|
|
525
|
+
<View
|
|
526
|
+
style={{
|
|
527
|
+
width: 0,
|
|
528
|
+
height: 0,
|
|
529
|
+
backgroundColor: "transparent",
|
|
530
|
+
borderStyle: "solid",
|
|
531
|
+
borderLeftWidth: 14,
|
|
532
|
+
borderRightWidth: 0,
|
|
533
|
+
borderTopWidth: 8,
|
|
534
|
+
borderBottomWidth: 8,
|
|
535
|
+
borderLeftColor: "#1e1e1e",
|
|
536
|
+
borderRightColor: "transparent",
|
|
537
|
+
borderTopColor: "transparent",
|
|
538
|
+
borderBottomColor: "transparent",
|
|
539
|
+
marginLeft: 3,
|
|
540
|
+
}}
|
|
541
|
+
/>
|
|
542
|
+
)}
|
|
543
|
+
</View>
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
case "drag": {
|
|
548
|
+
return (
|
|
549
|
+
<View
|
|
550
|
+
style={{
|
|
551
|
+
width: 20,
|
|
552
|
+
height: 12,
|
|
553
|
+
justifyContent: "space-between",
|
|
554
|
+
}}
|
|
555
|
+
>
|
|
556
|
+
<View
|
|
557
|
+
style={{
|
|
558
|
+
height: 2,
|
|
559
|
+
backgroundColor: "rgba(255, 255, 255, 0.7)",
|
|
560
|
+
borderRadius: 1,
|
|
561
|
+
}}
|
|
562
|
+
/>
|
|
563
|
+
<View
|
|
564
|
+
style={{
|
|
565
|
+
height: 2,
|
|
566
|
+
backgroundColor: "rgba(255, 255, 255, 0.7)",
|
|
567
|
+
borderRadius: 1,
|
|
568
|
+
}}
|
|
569
|
+
/>
|
|
570
|
+
<View
|
|
571
|
+
style={{
|
|
572
|
+
height: 2,
|
|
573
|
+
backgroundColor: "rgba(255, 255, 255, 0.7)",
|
|
574
|
+
borderRadius: 1,
|
|
575
|
+
}}
|
|
576
|
+
/>
|
|
577
|
+
</View>
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
case "remove": {
|
|
582
|
+
return (
|
|
583
|
+
<View
|
|
584
|
+
style={{
|
|
585
|
+
width: 24,
|
|
586
|
+
height: 24,
|
|
587
|
+
borderRadius: 12,
|
|
588
|
+
borderWidth: 1.5,
|
|
589
|
+
borderColor: "rgba(255, 255, 255, 0.7)",
|
|
590
|
+
justifyContent: "center",
|
|
591
|
+
alignItems: "center",
|
|
592
|
+
}}
|
|
593
|
+
>
|
|
594
|
+
<View
|
|
595
|
+
style={{
|
|
596
|
+
width: 10,
|
|
597
|
+
height: 1.5,
|
|
598
|
+
backgroundColor: "rgba(255, 255, 255, 0.7)",
|
|
599
|
+
borderRadius: 1,
|
|
600
|
+
}}
|
|
601
|
+
/>
|
|
602
|
+
</View>
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
case "multiSelect": {
|
|
607
|
+
if (!isSelected) {
|
|
608
|
+
return (
|
|
609
|
+
<View
|
|
610
|
+
style={{
|
|
611
|
+
width: layout.assetWidth,
|
|
612
|
+
height: layout.assetHeight,
|
|
613
|
+
borderRadius: layout.assetWidth / 2,
|
|
614
|
+
borderWidth: 1.5,
|
|
615
|
+
borderColor: "rgba(255, 255, 255, 0.7)",
|
|
616
|
+
backgroundColor: "transparent",
|
|
617
|
+
}}
|
|
618
|
+
/>
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
return (
|
|
623
|
+
<View
|
|
624
|
+
style={{
|
|
625
|
+
width: 24,
|
|
626
|
+
height: 24,
|
|
627
|
+
borderRadius: 12,
|
|
628
|
+
backgroundColor: "#FFFFFF",
|
|
629
|
+
justifyContent: "center",
|
|
630
|
+
alignItems: "center",
|
|
631
|
+
}}
|
|
632
|
+
>
|
|
633
|
+
<View
|
|
634
|
+
style={{
|
|
635
|
+
width: 6,
|
|
636
|
+
height: 10,
|
|
637
|
+
borderBottomWidth: 2,
|
|
638
|
+
borderRightWidth: 2,
|
|
639
|
+
borderColor: "#1e1e1e",
|
|
640
|
+
transform: [{ rotate: "45deg" }],
|
|
641
|
+
marginTop: -2,
|
|
642
|
+
}}
|
|
643
|
+
/>
|
|
644
|
+
</View>
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
default:
|
|
649
|
+
return null;
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
|
|
494
653
|
return (
|
|
495
|
-
<
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
paddingBottom: layout.paddingBottom,
|
|
500
|
-
paddingLeft: layout.paddingLeft,
|
|
501
|
-
opacity: focused ? 0.7 : 1,
|
|
654
|
+
<Pressable
|
|
655
|
+
onPress={(e: any) => {
|
|
656
|
+
e?.stopPropagation?.();
|
|
657
|
+
onPress?.();
|
|
502
658
|
}}
|
|
659
|
+
style={({ pressed }) => [
|
|
660
|
+
{
|
|
661
|
+
paddingTop: layout.paddingTop,
|
|
662
|
+
paddingRight: layout.paddingRight,
|
|
663
|
+
paddingBottom: layout.paddingBottom,
|
|
664
|
+
paddingLeft: layout.paddingLeft,
|
|
665
|
+
opacity: pressed || focused ? 0.7 : 1,
|
|
666
|
+
},
|
|
667
|
+
]}
|
|
503
668
|
>
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
style={{ width: layout.assetWidth, height: layout.assetHeight }}
|
|
507
|
-
resizeMode="contain"
|
|
508
|
-
/>
|
|
509
|
-
</View>
|
|
669
|
+
{renderIcon()}
|
|
670
|
+
</Pressable>
|
|
510
671
|
);
|
|
511
672
|
}
|
|
512
673
|
|
|
@@ -515,6 +676,10 @@ type ItemButtonsProps = {
|
|
|
515
676
|
trailingButton?: ItemButtonAction;
|
|
516
677
|
focusedLeadingButton?: boolean;
|
|
517
678
|
focusedTrailingButton?: boolean;
|
|
679
|
+
onLeadingButtonPress?: () => void;
|
|
680
|
+
onTrailingButtonPress?: () => void;
|
|
681
|
+
isSelected?: boolean;
|
|
682
|
+
renderHandle?: (element: React.ReactElement) => React.ReactElement;
|
|
518
683
|
};
|
|
519
684
|
|
|
520
685
|
function ItemButtons({
|
|
@@ -522,6 +687,10 @@ function ItemButtons({
|
|
|
522
687
|
trailingButton,
|
|
523
688
|
focusedLeadingButton = false,
|
|
524
689
|
focusedTrailingButton = false,
|
|
690
|
+
onLeadingButtonPress,
|
|
691
|
+
onTrailingButtonPress,
|
|
692
|
+
isSelected = false,
|
|
693
|
+
renderHandle,
|
|
525
694
|
}: ItemButtonsProps) {
|
|
526
695
|
if (!leadingButton && !trailingButton) {
|
|
527
696
|
return null;
|
|
@@ -531,28 +700,62 @@ function ItemButtons({
|
|
|
531
700
|
<View style={styles.buttonsRow}>
|
|
532
701
|
{leadingButton ? (
|
|
533
702
|
<>
|
|
534
|
-
<ItemButton
|
|
703
|
+
<ItemButton
|
|
704
|
+
action={leadingButton}
|
|
705
|
+
focused={focusedLeadingButton}
|
|
706
|
+
onPress={onLeadingButtonPress}
|
|
707
|
+
isSelected={isSelected}
|
|
708
|
+
/>
|
|
535
709
|
<View style={{ width: BUTTONS_CONTAINER_HORIZONTAL_GUTTER }} />
|
|
536
710
|
</>
|
|
537
711
|
) : null}
|
|
538
712
|
{trailingButton ? (
|
|
539
|
-
|
|
713
|
+
trailingButton === "drag" ? (
|
|
714
|
+
renderHandle ? (
|
|
715
|
+
renderHandle(
|
|
716
|
+
<ItemButton
|
|
717
|
+
action={trailingButton}
|
|
718
|
+
focused={focusedTrailingButton}
|
|
719
|
+
onPress={onTrailingButtonPress}
|
|
720
|
+
isSelected={isSelected}
|
|
721
|
+
/>
|
|
722
|
+
)
|
|
723
|
+
) : (
|
|
724
|
+
<ItemButton
|
|
725
|
+
action={trailingButton}
|
|
726
|
+
focused={focusedTrailingButton}
|
|
727
|
+
onPress={onTrailingButtonPress}
|
|
728
|
+
isSelected={isSelected}
|
|
729
|
+
/>
|
|
730
|
+
)
|
|
731
|
+
) : (
|
|
732
|
+
<ItemButton
|
|
733
|
+
action={trailingButton}
|
|
734
|
+
focused={focusedTrailingButton}
|
|
735
|
+
onPress={onTrailingButtonPress}
|
|
736
|
+
isSelected={isSelected}
|
|
737
|
+
/>
|
|
738
|
+
)
|
|
540
739
|
) : null}
|
|
541
740
|
</View>
|
|
542
741
|
);
|
|
543
742
|
}
|
|
544
743
|
|
|
545
744
|
// ---------------------------------------------------------------------------
|
|
546
|
-
//
|
|
745
|
+
// AudioPlayerTrackItem
|
|
547
746
|
// ---------------------------------------------------------------------------
|
|
548
747
|
|
|
549
|
-
export function
|
|
748
|
+
export function AudioPlayerTrackItem({
|
|
550
749
|
configuration,
|
|
551
750
|
data,
|
|
552
751
|
focused = false,
|
|
553
752
|
focusedLeadingButton = false,
|
|
554
753
|
focusedTrailingButton = false,
|
|
555
|
-
|
|
754
|
+
onPress,
|
|
755
|
+
onLeadingButtonPress,
|
|
756
|
+
onTrailingButtonPress,
|
|
757
|
+
renderHandle,
|
|
758
|
+
}: AudioPlayerTrackItemProps) {
|
|
556
759
|
const {
|
|
557
760
|
background,
|
|
558
761
|
image,
|
|
@@ -566,7 +769,12 @@ export function Item({
|
|
|
566
769
|
const showNowPlaying = !!data.nowPlayingLabel;
|
|
567
770
|
|
|
568
771
|
return (
|
|
569
|
-
<ItemContainer
|
|
772
|
+
<ItemContainer
|
|
773
|
+
image={image}
|
|
774
|
+
background={background}
|
|
775
|
+
focused={focused}
|
|
776
|
+
onPress={onPress}
|
|
777
|
+
>
|
|
570
778
|
<View style={styles.row}>
|
|
571
779
|
<ItemThumbnail configuration={image} imageUri={data.imageUri} />
|
|
572
780
|
<View style={{ width: container.horizontalGutter }} />
|
|
@@ -594,6 +802,10 @@ export function Item({
|
|
|
594
802
|
trailingButton={data.trailingButton}
|
|
595
803
|
focusedLeadingButton={focusedLeadingButton}
|
|
596
804
|
focusedTrailingButton={focusedTrailingButton}
|
|
805
|
+
onLeadingButtonPress={onLeadingButtonPress}
|
|
806
|
+
onTrailingButtonPress={onTrailingButtonPress}
|
|
807
|
+
isSelected={data.isSelected}
|
|
808
|
+
renderHandle={renderHandle}
|
|
597
809
|
/>
|
|
598
810
|
</View>
|
|
599
811
|
</ItemContainer>
|
|
@@ -663,47 +875,3 @@ export const VARIANT_PLAYLIST_ITEM: ItemConfiguration = {
|
|
|
663
875
|
textLabel1: DEFAULT_TEXT_LABEL_1_CONFIGURATION,
|
|
664
876
|
textLabel2: DEFAULT_TEXT_LABEL_2_CONFIGURATION,
|
|
665
877
|
};
|
|
666
|
-
|
|
667
|
-
export default function App() {
|
|
668
|
-
// Hardcoded core mock data objects matching user types framework
|
|
669
|
-
const sharedMockItem: MenuItem = {
|
|
670
|
-
title: "Content Title",
|
|
671
|
-
summary: "Artist",
|
|
672
|
-
icon: "https://picsum.photos/200",
|
|
673
|
-
action: { type: "PLAY_AUDIO" },
|
|
674
|
-
secondaryAction: { action: { type: "OPEN_CONTEXT_MENU" } },
|
|
675
|
-
};
|
|
676
|
-
|
|
677
|
-
const playlistMockItem: MenuItem = {
|
|
678
|
-
title: "Playlist Name",
|
|
679
|
-
summary: "12 Songs",
|
|
680
|
-
icon: "https://picsum.photos/201",
|
|
681
|
-
isSelected: true,
|
|
682
|
-
action: { type: "NAVIGATE_PLAYLIST" },
|
|
683
|
-
};
|
|
684
|
-
|
|
685
|
-
return (
|
|
686
|
-
<View style={styles.demoScreen}>
|
|
687
|
-
<Text style={styles.demoHeading}>Modal Item Building Block</Text>
|
|
688
|
-
|
|
689
|
-
<Text style={styles.demoLabel}>Now Playing</Text>
|
|
690
|
-
<Item
|
|
691
|
-
configuration={VARIANT_NOW_PLAYING}
|
|
692
|
-
data={mapMenuItemToNowPlayingData(sharedMockItem)}
|
|
693
|
-
/>
|
|
694
|
-
|
|
695
|
-
<Text style={styles.demoLabel}>Queued Item</Text>
|
|
696
|
-
<Item
|
|
697
|
-
configuration={VARIANT_QUEUED_ITEM}
|
|
698
|
-
data={mapMenuItemToQueuedData(sharedMockItem)}
|
|
699
|
-
focused
|
|
700
|
-
/>
|
|
701
|
-
|
|
702
|
-
<Text style={styles.demoLabel}>Playlist Item</Text>
|
|
703
|
-
<Item
|
|
704
|
-
configuration={VARIANT_PLAYLIST_ITEM}
|
|
705
|
-
data={mapMenuItemToPlaylistData(playlistMockItem)}
|
|
706
|
-
/>
|
|
707
|
-
</View>
|
|
708
|
-
);
|
|
709
|
-
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { StyleSheet, View } from "react-native";
|
|
3
|
+
import {
|
|
4
|
+
AudioPlayerTrackItem,
|
|
5
|
+
VARIANT_NOW_PLAYING,
|
|
6
|
+
mapMenuItemToNowPlayingData,
|
|
7
|
+
} from "./Item";
|
|
8
|
+
import { AudioPlayerHeader, VARIANT_SECTION_HEADER } from "./Header";
|
|
9
|
+
import type { MenuItem } from "@applicaster/zapp-react-native-utils/modalState/types";
|
|
10
|
+
import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
|
|
11
|
+
import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
|
|
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
|
+
type NowPlayingHeaderSectionProps = {
|
|
23
|
+
onClear?: () => void;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export function NowPlayingHeaderSection({
|
|
27
|
+
onClear,
|
|
28
|
+
}: NowPlayingHeaderSectionProps) {
|
|
29
|
+
const player = usePlayer();
|
|
30
|
+
const playerState = usePlayerState("queue-now-playing-section");
|
|
31
|
+
|
|
32
|
+
const renderNowPlayingTrack = () => {
|
|
33
|
+
if (!player?.entry) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const mediaGroup = player.entry.media_group;
|
|
38
|
+
|
|
39
|
+
const imageGroup = Array.isArray(mediaGroup)
|
|
40
|
+
? mediaGroup.find((g: any) => g.type === "image")
|
|
41
|
+
: null;
|
|
42
|
+
|
|
43
|
+
const firstImage = Array.isArray(imageGroup?.media_item)
|
|
44
|
+
? imageGroup.media_item[0]?.src
|
|
45
|
+
: imageGroup?.media_item?.src;
|
|
46
|
+
|
|
47
|
+
const nowPlayingItem: MenuItem = {
|
|
48
|
+
title: (player.entry.title as string) || String(player.entry.id),
|
|
49
|
+
summary: (player.entry.summary as string) ?? "",
|
|
50
|
+
icon: firstImage,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const data = mapMenuItemToNowPlayingData(nowPlayingItem);
|
|
54
|
+
data.isSelected = !playerState?.isPaused;
|
|
55
|
+
|
|
56
|
+
const handlePlayPause = () => {
|
|
57
|
+
if (playerState?.isPaused) {
|
|
58
|
+
player?.play();
|
|
59
|
+
} else {
|
|
60
|
+
player?.pause();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<View>
|
|
66
|
+
<AudioPlayerTrackItem
|
|
67
|
+
configuration={VARIANT_NOW_PLAYING}
|
|
68
|
+
data={data}
|
|
69
|
+
onTrailingButtonPress={handlePlayPause}
|
|
70
|
+
/>
|
|
71
|
+
<View style={styles.divider} />
|
|
72
|
+
</View>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<View>
|
|
78
|
+
{renderNowPlayingTrack()}
|
|
79
|
+
<AudioPlayerHeader
|
|
80
|
+
configuration={VARIANT_SECTION_HEADER}
|
|
81
|
+
data={{ title: "Next Up" }}
|
|
82
|
+
onClear={onClear}
|
|
83
|
+
/>
|
|
84
|
+
</View>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { AudioPlayerAction } from "./Action";
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { AudioPlayerButton, VARIANT_WITH_ICON } from "./Button";
|
|
4
4
|
|
|
5
|
-
export {
|
|
5
|
+
export { AudioPlayerHeader } from "./Header";
|
|
6
6
|
|
|
7
|
-
export {
|
|
7
|
+
export { AudioPlayerTrackItem } from "./Item";
|
|
8
|
+
|
|
9
|
+
export { NowPlayingHeaderSection } from "./NowPlayingHeaderSection";
|
|
10
|
+
|
|
11
|
+
export { AudioPlayerInput } from "./Input";
|