@draftbit/core 54.0.4-6c949a.2 → 54.0.4-982952.2
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/lib/commonjs/components/DeckSwiper/DeckSwiper.js +1 -1
- package/lib/commonjs/components/DeckSwiper/DeckSwiperCard.js +1 -1
- package/lib/commonjs/components/Layout/Spacer.js +1 -1
- package/lib/commonjs/components/LottieAnimation.js +1 -1
- package/lib/commonjs/components/MediaPlayer/AudioPlayer/AudioPlayerWithInterface.js +1 -1
- package/lib/commonjs/components/MediaPlayer/AudioPlayer/HeadlessAudioPlayer.js +1 -1
- package/lib/commonjs/components/MediaPlayer/MediaPlaybackWrapper.js +1 -1
- package/lib/commonjs/components/MediaPlayer/MediaPlayerCommon.js +1 -1
- package/lib/commonjs/components/MediaPlayer/VideoPlayer/VideoPlayer.js +1 -1
- package/lib/commonjs/components/Picker/PickerInputContainer.js +1 -1
- package/lib/commonjs/components/Progress/CircularProgress/CircularProgress.js +1 -1
- package/lib/commonjs/components/Progress/LinearProgress/LinearProgress.js +1 -1
- package/lib/commonjs/components/SVG.js +1 -1
- package/lib/commonjs/components/SVG.native.js +1 -1
- package/lib/commonjs/components/SectionList/SectionHeader.js +1 -1
- package/lib/commonjs/components/SwipeableItem/SwipeableItem.js +1 -1
- package/lib/commonjs/components/Swiper/Swiper.js +1 -1
- package/lib/commonjs/components/Swiper/SwiperItem.js +1 -1
- package/lib/commonjs/components/Table/TableCell.js +1 -1
- package/lib/commonjs/components/Table/TableRow.js +1 -1
- package/lib/commonjs/components/YoutubePlayer/YoutubePlayer.js +1 -1
- package/lib/typescript/src/components/DeckSwiper/DeckSwiper.d.ts +1 -0
- package/lib/typescript/src/components/DeckSwiper/DeckSwiper.js +3 -2
- package/lib/typescript/src/components/DeckSwiper/DeckSwiper.js.map +1 -1
- package/lib/typescript/src/components/DeckSwiper/DeckSwiperCard.d.ts +2 -2
- package/lib/typescript/src/components/DeckSwiper/DeckSwiperCard.js +3 -3
- package/lib/typescript/src/components/DeckSwiper/DeckSwiperCard.js.map +1 -1
- package/lib/typescript/src/components/Layout/Spacer.d.ts +2 -2
- package/lib/typescript/src/components/Layout/Spacer.js +2 -2
- package/lib/typescript/src/components/Layout/Spacer.js.map +1 -1
- package/lib/typescript/src/components/LottieAnimation.js +2 -2
- package/lib/typescript/src/components/LottieAnimation.js.map +1 -1
- package/lib/typescript/src/components/MediaPlayer/AudioPlayer/AudioPlayerCommon.d.ts +1 -0
- package/lib/typescript/src/components/MediaPlayer/AudioPlayer/AudioPlayerWithInterface.js +4 -2
- package/lib/typescript/src/components/MediaPlayer/AudioPlayer/AudioPlayerWithInterface.js.map +1 -1
- package/lib/typescript/src/components/MediaPlayer/AudioPlayer/HeadlessAudioPlayer.d.ts +3 -1
- package/lib/typescript/src/components/MediaPlayer/AudioPlayer/HeadlessAudioPlayer.js +69 -54
- package/lib/typescript/src/components/MediaPlayer/AudioPlayer/HeadlessAudioPlayer.js.map +1 -1
- package/lib/typescript/src/components/MediaPlayer/MediaPlaybackWrapper.d.ts +3 -2
- package/lib/typescript/src/components/MediaPlayer/MediaPlaybackWrapper.js +19 -21
- package/lib/typescript/src/components/MediaPlayer/MediaPlaybackWrapper.js.map +1 -1
- package/lib/typescript/src/components/MediaPlayer/MediaPlayerCommon.d.ts +5 -4
- package/lib/typescript/src/components/MediaPlayer/MediaPlayerCommon.js +3 -26
- package/lib/typescript/src/components/MediaPlayer/MediaPlayerCommon.js.map +1 -1
- package/lib/typescript/src/components/MediaPlayer/VideoPlayer/VideoPlayer.d.ts +14 -4
- package/lib/typescript/src/components/MediaPlayer/VideoPlayer/VideoPlayer.js +129 -62
- package/lib/typescript/src/components/MediaPlayer/VideoPlayer/VideoPlayer.js.map +1 -1
- package/lib/typescript/src/components/Picker/PickerCommon.d.ts +1 -0
- package/lib/typescript/src/components/Picker/PickerCommon.js.map +1 -1
- package/lib/typescript/src/components/Picker/PickerInputContainer.js +4 -2
- package/lib/typescript/src/components/Picker/PickerInputContainer.js.map +1 -1
- package/lib/typescript/src/components/Progress/CircularProgress/CircularProgress.js +4 -2
- package/lib/typescript/src/components/Progress/CircularProgress/CircularProgress.js.map +1 -1
- package/lib/typescript/src/components/Progress/LinearProgress/LinearProgress.js +4 -2
- package/lib/typescript/src/components/Progress/LinearProgress/LinearProgress.js.map +1 -1
- package/lib/typescript/src/components/Progress/ProgressCommon.d.ts +1 -0
- package/lib/typescript/src/components/SVG.d.ts +1 -0
- package/lib/typescript/src/components/SVG.js +4 -2
- package/lib/typescript/src/components/SVG.js.map +1 -1
- package/lib/typescript/src/components/SVG.native.d.ts +1 -0
- package/lib/typescript/src/components/SVG.native.js +4 -2
- package/lib/typescript/src/components/SVG.native.js.map +1 -1
- package/lib/typescript/src/components/SectionList/SectionHeader.d.ts +2 -2
- package/lib/typescript/src/components/SectionList/SectionHeader.js +1 -1
- package/lib/typescript/src/components/SectionList/SectionHeader.js.map +1 -1
- package/lib/typescript/src/components/SwipeableItem/SwipeableItem.d.ts +1 -0
- package/lib/typescript/src/components/SwipeableItem/SwipeableItem.js +4 -2
- package/lib/typescript/src/components/SwipeableItem/SwipeableItem.js.map +1 -1
- package/lib/typescript/src/components/Swiper/Swiper.d.ts +2 -2
- package/lib/typescript/src/components/Swiper/Swiper.js +2 -2
- package/lib/typescript/src/components/Swiper/Swiper.js.map +1 -1
- package/lib/typescript/src/components/Swiper/SwiperItem.d.ts +3 -3
- package/lib/typescript/src/components/Swiper/SwiperItem.js +2 -2
- package/lib/typescript/src/components/Swiper/SwiperItem.js.map +1 -1
- package/lib/typescript/src/components/Table/TableCell.d.ts +1 -0
- package/lib/typescript/src/components/Table/TableCell.js +4 -2
- package/lib/typescript/src/components/Table/TableCell.js.map +1 -1
- package/lib/typescript/src/components/Table/TableRow.d.ts +1 -0
- package/lib/typescript/src/components/Table/TableRow.js +4 -2
- package/lib/typescript/src/components/Table/TableRow.js.map +1 -1
- package/lib/typescript/src/components/YoutubePlayer/YoutubePlayer.js +2 -2
- package/lib/typescript/src/components/YoutubePlayer/YoutubePlayer.js.map +1 -1
- package/lib/typescript/src/components/YoutubePlayer/YoutubePlayerProps.d.ts +1 -0
- package/lib/typescript/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -4
- package/src/components/DeckSwiper/DeckSwiper.tsx +5 -1
- package/src/components/DeckSwiper/DeckSwiperCard.tsx +11 -3
- package/src/components/Layout/Spacer.tsx +4 -2
- package/src/components/LottieAnimation.tsx +1 -2
- package/src/components/MediaPlayer/AudioPlayer/AudioPlayerCommon.ts +1 -0
- package/src/components/MediaPlayer/AudioPlayer/AudioPlayerWithInterface.tsx +3 -0
- package/src/components/MediaPlayer/AudioPlayer/HeadlessAudioPlayer.tsx +84 -72
- package/src/components/MediaPlayer/MediaPlaybackWrapper.tsx +21 -24
- package/src/components/MediaPlayer/MediaPlayerCommon.ts +8 -34
- package/src/components/MediaPlayer/VideoPlayer/VideoPlayer.tsx +220 -86
- package/src/components/Picker/PickerCommon.ts +1 -0
- package/src/components/Picker/PickerInputContainer.tsx +7 -1
- package/src/components/Progress/CircularProgress/CircularProgress.tsx +3 -0
- package/src/components/Progress/LinearProgress/LinearProgress.tsx +3 -0
- package/src/components/Progress/ProgressCommon.ts +1 -0
- package/src/components/SVG.native.tsx +7 -1
- package/src/components/SVG.tsx +10 -1
- package/src/components/SectionList/SectionHeader.tsx +8 -3
- package/src/components/SwipeableItem/SwipeableItem.tsx +4 -0
- package/src/components/Swiper/Swiper.tsx +4 -3
- package/src/components/Swiper/SwiperItem.tsx +12 -4
- package/src/components/Table/TableCell.tsx +4 -0
- package/src/components/Table/TableRow.tsx +4 -0
- package/src/components/YoutubePlayer/YoutubePlayer.tsx +5 -1
- package/src/components/YoutubePlayer/YoutubePlayerProps.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@draftbit/core",
|
|
3
|
-
"version": "54.0.4-
|
|
3
|
+
"version": "54.0.4-982952.2+9829524",
|
|
4
4
|
"description": "Core (non-native) Components",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"types": "lib/typescript/src/index.d.ts",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"homepage": "https://github.com/draftbit/react-native-jigsaw#readme",
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@draftbit/react-theme-provider": "^2.1.1",
|
|
45
|
-
"@draftbit/theme": "^54.0.4-
|
|
45
|
+
"@draftbit/theme": "^54.0.4-982952.2+9829524",
|
|
46
46
|
"@emotion/react": "^11.13.5",
|
|
47
47
|
"@emotion/styled": "^11.13.5",
|
|
48
48
|
"@expo/vector-icons": "^15.0.3",
|
|
@@ -57,8 +57,9 @@
|
|
|
57
57
|
"color": "^4.2.3",
|
|
58
58
|
"date-fns": "^4.1.0",
|
|
59
59
|
"dateformat": "^5.0.3",
|
|
60
|
-
"expo-
|
|
60
|
+
"expo-audio": "~1.1.1",
|
|
61
61
|
"expo-image": "~3.0.11",
|
|
62
|
+
"expo-video": "~3.0.16",
|
|
62
63
|
"lodash.isequal": "^4.5.0",
|
|
63
64
|
"lodash.isnumber": "^3.0.3",
|
|
64
65
|
"lodash.omit": "^4.5.0",
|
|
@@ -122,5 +123,5 @@
|
|
|
122
123
|
],
|
|
123
124
|
"testEnvironment": "node"
|
|
124
125
|
},
|
|
125
|
-
"gitHead": "
|
|
126
|
+
"gitHead": "982952444fe6e477d4268d769d270e9674bface6"
|
|
126
127
|
}
|
|
@@ -25,6 +25,7 @@ export interface DeckSwiperProps<T> {
|
|
|
25
25
|
keyExtractor?: (item: T) => string;
|
|
26
26
|
renderItem?: ({ item, index }: { item: T; index: number }) => JSX.Element;
|
|
27
27
|
style?: StyleProp<ViewStyle>;
|
|
28
|
+
className?: string;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
const DeckSwiper = React.forwardRef<DeckSwiperRef, DeckSwiperProps<any>>(
|
|
@@ -48,6 +49,7 @@ const DeckSwiper = React.forwardRef<DeckSwiperRef, DeckSwiperProps<any>>(
|
|
|
48
49
|
keyExtractor,
|
|
49
50
|
renderItem,
|
|
50
51
|
style,
|
|
52
|
+
className,
|
|
51
53
|
children,
|
|
52
54
|
}: React.PropsWithChildren<DeckSwiperProps<T>>,
|
|
53
55
|
ref: React.Ref<DeckSwiperRef>
|
|
@@ -146,7 +148,9 @@ const DeckSwiper = React.forwardRef<DeckSwiperRef, DeckSwiperProps<any>>(
|
|
|
146
148
|
*/
|
|
147
149
|
|
|
148
150
|
return (
|
|
149
|
-
<View
|
|
151
|
+
<View // @ts-ignore
|
|
152
|
+
className={className}
|
|
153
|
+
>
|
|
150
154
|
<View style={styles.containerHeightFiller}>{renderFirstCard()}</View>
|
|
151
155
|
<DeckSwiperComponent
|
|
152
156
|
ref={deckSwiperRef}
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
ViewProps,
|
|
5
|
+
StyleSheet,
|
|
6
|
+
StyleProp,
|
|
7
|
+
ViewStyle,
|
|
8
|
+
} from "react-native";
|
|
3
9
|
import type { ReadTheme } from "@draftbit/theme";
|
|
4
10
|
import { withTheme } from "@draftbit/theme";
|
|
5
11
|
|
|
6
|
-
export interface DeckSwiperCardProps
|
|
12
|
+
export interface DeckSwiperCardProps
|
|
13
|
+
extends Omit<ViewProps, "style" | "children"> {
|
|
7
14
|
style?: StyleProp<ViewStyle>;
|
|
8
15
|
theme: ReadTheme;
|
|
9
16
|
}
|
|
10
17
|
|
|
11
18
|
const DeckSwiperCard: React.FC<
|
|
12
19
|
React.PropsWithChildren<DeckSwiperCardProps>
|
|
13
|
-
> = ({ style, children, theme }) => (
|
|
20
|
+
> = ({ style, children, theme, ...rest }) => (
|
|
14
21
|
<View
|
|
15
22
|
style={[
|
|
16
23
|
styles.card,
|
|
@@ -20,6 +27,7 @@ const DeckSwiperCard: React.FC<
|
|
|
20
27
|
},
|
|
21
28
|
style,
|
|
22
29
|
]}
|
|
30
|
+
{...rest}
|
|
23
31
|
>
|
|
24
32
|
{children}
|
|
25
33
|
</View>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { View, StyleProp, ViewStyle } from "react-native";
|
|
2
|
+
import { View, ViewProps, StyleProp, ViewStyle } from "react-native";
|
|
3
3
|
|
|
4
|
-
interface SpacerProps {
|
|
4
|
+
interface SpacerProps extends Omit<ViewProps, "style"> {
|
|
5
5
|
top?: number;
|
|
6
6
|
right?: number;
|
|
7
7
|
left?: number;
|
|
@@ -15,6 +15,7 @@ const Spacer: React.FC<SpacerProps> = ({
|
|
|
15
15
|
bottom = 8,
|
|
16
16
|
left = 8,
|
|
17
17
|
style,
|
|
18
|
+
...rest
|
|
18
19
|
}) => {
|
|
19
20
|
return (
|
|
20
21
|
<View
|
|
@@ -27,6 +28,7 @@ const Spacer: React.FC<SpacerProps> = ({
|
|
|
27
28
|
paddingBottom: bottom,
|
|
28
29
|
},
|
|
29
30
|
]}
|
|
31
|
+
{...rest}
|
|
30
32
|
/>
|
|
31
33
|
);
|
|
32
34
|
};
|
|
@@ -25,7 +25,7 @@ const LottieAnimation = forwardRef<LottieView, Props>(
|
|
|
25
25
|
ref
|
|
26
26
|
) => {
|
|
27
27
|
return (
|
|
28
|
-
<View style={style}>
|
|
28
|
+
<View style={style} {...rest}>
|
|
29
29
|
<LottieView
|
|
30
30
|
ref={ref}
|
|
31
31
|
source={source}
|
|
@@ -36,7 +36,6 @@ const LottieAnimation = forwardRef<LottieView, Props>(
|
|
|
36
36
|
// A specific size is required on mobile, but not on web.
|
|
37
37
|
// This ensures consistent behavior across platforms during preview.
|
|
38
38
|
style={{ width: "100%", height: "100%" }}
|
|
39
|
-
{...rest}
|
|
40
39
|
/>
|
|
41
40
|
</View>
|
|
42
41
|
);
|
|
@@ -21,6 +21,7 @@ const AudioPlayerWithInterface = React.forwardRef<
|
|
|
21
21
|
(
|
|
22
22
|
{
|
|
23
23
|
style,
|
|
24
|
+
className,
|
|
24
25
|
thumbColor,
|
|
25
26
|
completedTrackColor,
|
|
26
27
|
remainingTrackColor,
|
|
@@ -127,6 +128,8 @@ const AudioPlayerWithInterface = React.forwardRef<
|
|
|
127
128
|
/>
|
|
128
129
|
<View
|
|
129
130
|
testID="audio-player-interface"
|
|
131
|
+
// @ts-ignore
|
|
132
|
+
className={className}
|
|
130
133
|
style={[
|
|
131
134
|
{
|
|
132
135
|
backgroundColor: theme.colors.background.base,
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
3
|
-
Audio,
|
|
4
|
-
AVPlaybackStatus,
|
|
5
|
-
InterruptionModeIOS,
|
|
6
|
-
InterruptionModeAndroid,
|
|
7
|
-
} from "expo-av";
|
|
2
|
+
import { useAudioPlayer, setAudioModeAsync, AudioStatus } from "expo-audio";
|
|
8
3
|
import { HeadlessAudioPlayerProps } from "./AudioPlayerCommon";
|
|
9
4
|
import {
|
|
10
|
-
mapToMediaPlayerStatus,
|
|
11
5
|
normalizeBase64Source,
|
|
6
|
+
useSourceDeepCompareMemoize,
|
|
12
7
|
useSourceDeepCompareEffect,
|
|
13
8
|
} from "../MediaPlayerCommon";
|
|
14
|
-
import type { MediaPlayerRef } from "../MediaPlayerCommon";
|
|
9
|
+
import type { MediaPlayerRef, MediaPlayerStatus } from "../MediaPlayerCommon";
|
|
15
10
|
import MediaPlaybackWrapper from "../MediaPlaybackWrapper";
|
|
16
11
|
|
|
17
12
|
/**
|
|
@@ -36,38 +31,70 @@ const HeadlessAudioPlayer = React.forwardRef<
|
|
|
36
31
|
},
|
|
37
32
|
ref
|
|
38
33
|
) => {
|
|
39
|
-
const
|
|
34
|
+
const stableSource = useSourceDeepCompareMemoize(
|
|
35
|
+
normalizeBase64Source(source, "audio")
|
|
36
|
+
);
|
|
37
|
+
const player = useAudioPlayer(stableSource);
|
|
38
|
+
|
|
40
39
|
const [isPlaying, setIsPlaying] = React.useState(false);
|
|
41
40
|
|
|
42
41
|
React.useEffect(() => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
typeof currentSound?.setIsLoopingAsync === "function"
|
|
46
|
-
) {
|
|
47
|
-
currentSound.setIsLoopingAsync(isLooping);
|
|
48
|
-
}
|
|
49
|
-
}, [currentSound, isLooping]);
|
|
42
|
+
player.loop = isLooping;
|
|
43
|
+
}, [player, isLooping]);
|
|
50
44
|
|
|
51
45
|
React.useEffect(() => {
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
player.volume = volume;
|
|
47
|
+
}, [player, volume]);
|
|
48
|
+
|
|
49
|
+
// Emit loading state immediately
|
|
50
|
+
React.useEffect(() => {
|
|
51
|
+
onPlaybackStatusUpdateProp?.({
|
|
52
|
+
isPlaying: false,
|
|
53
|
+
isLoading: true,
|
|
54
|
+
isBuffering: false,
|
|
55
|
+
currentPositionMillis: 0,
|
|
56
|
+
durationMillis: 0,
|
|
57
|
+
bufferedDurationMillis: 0,
|
|
58
|
+
isError: false,
|
|
59
|
+
});
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
React.useEffect(() => {
|
|
63
|
+
const subscription = player.addListener(
|
|
64
|
+
"playbackStatusUpdate",
|
|
65
|
+
(status) => {
|
|
66
|
+
const mappedStatus = mapToMediaPlayerStatus(status);
|
|
67
|
+
onPlaybackStatusUpdateProp?.(mappedStatus);
|
|
68
|
+
|
|
69
|
+
if (status.isLoaded) {
|
|
70
|
+
if (status.didJustFinish && !isLooping) {
|
|
71
|
+
onPlaybackFinish?.();
|
|
72
|
+
}
|
|
73
|
+
setIsPlaying(status.playing);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
return () => subscription.remove();
|
|
78
|
+
}, []);
|
|
79
|
+
|
|
80
|
+
// Replace source when it changes (deep comparison on URI to avoid unnecessary reloads)
|
|
81
|
+
const isFirstSourceRender = React.useRef(true);
|
|
82
|
+
useSourceDeepCompareEffect(() => {
|
|
83
|
+
if (isFirstSourceRender.current) {
|
|
84
|
+
isFirstSourceRender.current = false;
|
|
85
|
+
return;
|
|
54
86
|
}
|
|
55
|
-
|
|
87
|
+
player.replace(normalizeBase64Source(source, "audio") as any);
|
|
88
|
+
}, [source]);
|
|
56
89
|
|
|
57
90
|
const updateAudioMode = React.useCallback(async () => {
|
|
58
91
|
try {
|
|
59
|
-
await
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
interruptionMode === "lower volume"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
interruptionModeAndroid:
|
|
66
|
-
interruptionMode === "lower volume"
|
|
67
|
-
? InterruptionModeAndroid.DuckOthers
|
|
68
|
-
: InterruptionModeAndroid.DoNotMix,
|
|
69
|
-
playsInSilentModeIOS,
|
|
70
|
-
playThroughEarpieceAndroid,
|
|
92
|
+
await setAudioModeAsync({
|
|
93
|
+
shouldPlayInBackground: playsInBackground,
|
|
94
|
+
interruptionMode:
|
|
95
|
+
interruptionMode === "lower volume" ? "duckOthers" : "doNotMix",
|
|
96
|
+
playsInSilentMode: playsInSilentModeIOS,
|
|
97
|
+
shouldRouteThroughEarpiece: playThroughEarpieceAndroid,
|
|
71
98
|
});
|
|
72
99
|
} catch (e) {
|
|
73
100
|
if ((e as { code?: string })?.code === "E_AUDIO_AUDIOMODE") {
|
|
@@ -88,59 +115,44 @@ const HeadlessAudioPlayer = React.forwardRef<
|
|
|
88
115
|
playThroughEarpieceAndroid,
|
|
89
116
|
]);
|
|
90
117
|
|
|
91
|
-
const onPlaybackStatusUpdate = (status: AVPlaybackStatus) => {
|
|
92
|
-
const mappedStatus = mapToMediaPlayerStatus(status);
|
|
93
|
-
onPlaybackStatusUpdateProp?.(mappedStatus);
|
|
94
|
-
|
|
95
|
-
if (status.isLoaded) {
|
|
96
|
-
if (status.didJustFinish) {
|
|
97
|
-
if (isLooping) {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
onPlaybackFinish?.();
|
|
101
|
-
}
|
|
102
|
-
setIsPlaying(status.isPlaying);
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
118
|
const onTogglePlayback = () => {
|
|
107
|
-
//Has to be called everytime a player is played to reconfigure the global Audio config based on each player's configuration
|
|
119
|
+
// Has to be called everytime a player is played to reconfigure the global Audio config based on each player's configuration
|
|
108
120
|
updateAudioMode();
|
|
109
121
|
};
|
|
110
122
|
|
|
111
|
-
const loadAudio = async () => {
|
|
112
|
-
onPlaybackStatusUpdateProp?.({
|
|
113
|
-
isPlaying: false,
|
|
114
|
-
isLoading: true,
|
|
115
|
-
isBuffering: false,
|
|
116
|
-
currentPositionMillis: 0,
|
|
117
|
-
durationMillis: 0,
|
|
118
|
-
bufferedDurationMillis: 0,
|
|
119
|
-
isError: false,
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
const finalSource = await normalizeBase64Source(source, "audio");
|
|
123
|
-
|
|
124
|
-
const { sound } = await Audio.Sound.createAsync(finalSource);
|
|
125
|
-
setCurrentSound(sound);
|
|
126
|
-
sound.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate);
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
useSourceDeepCompareEffect(() => {
|
|
130
|
-
loadAudio();
|
|
131
|
-
|
|
132
|
-
// Ignore dependency of loadAudio
|
|
133
|
-
}, [source]);
|
|
134
|
-
|
|
135
123
|
return (
|
|
136
124
|
<MediaPlaybackWrapper
|
|
137
125
|
ref={ref}
|
|
138
126
|
isPlaying={isPlaying}
|
|
139
|
-
|
|
127
|
+
player={player}
|
|
140
128
|
onTogglePlayback={onTogglePlayback}
|
|
141
129
|
/>
|
|
142
130
|
);
|
|
143
131
|
}
|
|
144
132
|
);
|
|
145
133
|
|
|
134
|
+
export function mapToMediaPlayerStatus(status: AudioStatus): MediaPlayerStatus {
|
|
135
|
+
if (status.isLoaded) {
|
|
136
|
+
return {
|
|
137
|
+
isPlaying: status.playing,
|
|
138
|
+
isLoading: false,
|
|
139
|
+
isBuffering: status.isBuffering,
|
|
140
|
+
currentPositionMillis: status.currentTime * 1000,
|
|
141
|
+
durationMillis: status.duration * 1000,
|
|
142
|
+
bufferedDurationMillis: status.duration * 1000,
|
|
143
|
+
isError: false,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
isPlaying: false,
|
|
149
|
+
isLoading: true,
|
|
150
|
+
isBuffering: false,
|
|
151
|
+
currentPositionMillis: 0,
|
|
152
|
+
durationMillis: 0,
|
|
153
|
+
bufferedDurationMillis: 0,
|
|
154
|
+
isError: false,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
146
158
|
export default HeadlessAudioPlayer;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import type {
|
|
2
|
+
import type { AudioPlayer } from "expo-audio";
|
|
3
|
+
import type { VideoPlayer } from "expo-video";
|
|
3
4
|
|
|
4
5
|
import type { MediaPlayerRef } from "./MediaPlayerCommon";
|
|
5
6
|
|
|
6
7
|
interface MediaPlaybackWrapperProps {
|
|
7
|
-
|
|
8
|
+
player?: AudioPlayer | VideoPlayer;
|
|
8
9
|
isPlaying?: boolean;
|
|
9
10
|
onTogglePlayback?: () => void;
|
|
10
11
|
}
|
|
@@ -15,42 +16,38 @@ interface MediaPlaybackWrapperProps {
|
|
|
15
16
|
const MediaPlaybackWrapper = React.forwardRef<
|
|
16
17
|
MediaPlayerRef,
|
|
17
18
|
React.PropsWithChildren<MediaPlaybackWrapperProps>
|
|
18
|
-
>(({
|
|
19
|
-
const togglePlayback = React.useCallback(
|
|
19
|
+
>(({ player, isPlaying, onTogglePlayback, children }, ref) => {
|
|
20
|
+
const togglePlayback = React.useCallback(() => {
|
|
20
21
|
onTogglePlayback?.();
|
|
21
22
|
|
|
22
23
|
if (isPlaying) {
|
|
23
|
-
|
|
24
|
+
player?.pause();
|
|
24
25
|
} else {
|
|
25
|
-
|
|
26
|
+
player?.play();
|
|
26
27
|
}
|
|
27
|
-
}, [
|
|
28
|
+
}, [isPlaying, onTogglePlayback]);
|
|
28
29
|
|
|
29
|
-
const pause = React.useCallback(
|
|
30
|
+
const pause = React.useCallback(() => {
|
|
30
31
|
onTogglePlayback?.();
|
|
31
|
-
|
|
32
|
-
}, [
|
|
32
|
+
player?.pause();
|
|
33
|
+
}, [player, onTogglePlayback]);
|
|
33
34
|
|
|
34
|
-
const play = React.useCallback(
|
|
35
|
+
const play = React.useCallback(() => {
|
|
35
36
|
onTogglePlayback?.();
|
|
36
|
-
|
|
37
|
-
}, [
|
|
37
|
+
player?.play();
|
|
38
|
+
}, [player, onTogglePlayback]);
|
|
38
39
|
|
|
39
40
|
const seekToPosition = React.useCallback(
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
(positionMillis: number) => {
|
|
42
|
+
if (typeof (player as any)?.seekTo === "function") {
|
|
43
|
+
(player as AudioPlayer).seekTo(positionMillis / 1000);
|
|
44
|
+
} else if (player) {
|
|
45
|
+
player.currentTime = positionMillis / 1000;
|
|
46
|
+
}
|
|
42
47
|
},
|
|
43
|
-
[
|
|
48
|
+
[player]
|
|
44
49
|
);
|
|
45
50
|
|
|
46
|
-
React.useEffect(() => {
|
|
47
|
-
return media
|
|
48
|
-
? () => {
|
|
49
|
-
media.unloadAsync();
|
|
50
|
-
}
|
|
51
|
-
: undefined;
|
|
52
|
-
}, [media]);
|
|
53
|
-
|
|
54
51
|
React.useImperativeHandle(
|
|
55
52
|
ref,
|
|
56
53
|
() => ({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AudioSource } from "expo-audio";
|
|
2
|
+
import { VideoSource } from "expo-video";
|
|
2
3
|
import { v4 as uuid } from "uuid";
|
|
3
4
|
import { Platform } from "react-native";
|
|
4
5
|
import React from "react";
|
|
@@ -24,34 +25,7 @@ export interface MediaPlayerRef {
|
|
|
24
25
|
export interface MediaPlayerProps {
|
|
25
26
|
onPlaybackStatusUpdate?: (status: MediaPlayerStatus) => void;
|
|
26
27
|
onPlaybackFinish?: () => void;
|
|
27
|
-
source:
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function mapToMediaPlayerStatus(
|
|
31
|
-
status: AVPlaybackStatus
|
|
32
|
-
): MediaPlayerStatus {
|
|
33
|
-
if (status.isLoaded) {
|
|
34
|
-
return {
|
|
35
|
-
isPlaying: status.isPlaying,
|
|
36
|
-
isLoading: false,
|
|
37
|
-
isBuffering: status.isBuffering,
|
|
38
|
-
currentPositionMillis: status.positionMillis || 0,
|
|
39
|
-
durationMillis: status.durationMillis || 0,
|
|
40
|
-
bufferedDurationMillis: status.playableDurationMillis || 0,
|
|
41
|
-
isError: false,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
isPlaying: false,
|
|
47
|
-
isLoading: false,
|
|
48
|
-
isBuffering: false,
|
|
49
|
-
currentPositionMillis: 0,
|
|
50
|
-
durationMillis: 0,
|
|
51
|
-
bufferedDurationMillis: 0,
|
|
52
|
-
isError: true,
|
|
53
|
-
error: status.error,
|
|
54
|
-
};
|
|
28
|
+
source: AudioSource | VideoSource;
|
|
55
29
|
}
|
|
56
30
|
|
|
57
31
|
const URL_REGEX =
|
|
@@ -60,14 +34,14 @@ const URL_REGEX =
|
|
|
60
34
|
/**
|
|
61
35
|
* Base64 strings are not playable on iOS and needs to be saved to a file before playing
|
|
62
36
|
*/
|
|
63
|
-
export
|
|
64
|
-
source:
|
|
37
|
+
export function normalizeBase64Source(
|
|
38
|
+
source: AudioSource | VideoSource,
|
|
65
39
|
type: "audio" | "video"
|
|
66
|
-
):
|
|
40
|
+
): AudioSource | VideoSource {
|
|
67
41
|
const uri: string | undefined = (source as any)?.uri;
|
|
68
42
|
|
|
69
43
|
if (Platform.OS === "ios" && uri && !uri.match(URL_REGEX)) {
|
|
70
|
-
const { File, Paths } =
|
|
44
|
+
const { File, Paths } = require("expo-file-system");
|
|
71
45
|
|
|
72
46
|
const defaultMimeType = type === "audio" ? "wav" : "mp4";
|
|
73
47
|
const mimeType = uri.startsWith(`data:${type}/`)
|
|
@@ -100,7 +74,7 @@ function sourceDeepCompareEquals(a: any, b: any) {
|
|
|
100
74
|
return a === b;
|
|
101
75
|
}
|
|
102
76
|
|
|
103
|
-
function useSourceDeepCompareMemoize(value: any) {
|
|
77
|
+
export function useSourceDeepCompareMemoize(value: any) {
|
|
104
78
|
const ref = React.useRef<any>(undefined);
|
|
105
79
|
if (!sourceDeepCompareEquals(value, ref.current)) {
|
|
106
80
|
ref.current = value;
|