@draftbit/core 46.13.1-2d051e.2 → 46.13.1-618d50.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/src/components/SwipeableItem/SwipeableItem.js +2 -2
- package/lib/src/components/SwipeableItem/SwipeableItem.js.map +1 -1
- package/lib/src/index.d.ts +0 -1
- package/lib/src/index.js +0 -1
- package/lib/src/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -5
- package/src/components/SwipeableItem/SwipeableItem.js +2 -2
- package/src/components/SwipeableItem/SwipeableItem.js.map +1 -1
- package/src/components/SwipeableItem/SwipeableItem.tsx +4 -0
- package/src/index.js +0 -1
- package/src/index.js.map +1 -1
- package/src/index.tsx +0 -5
- package/lib/src/components/AudioPlayer/AudioPlayerCommon.d.ts +0 -39
- package/lib/src/components/AudioPlayer/AudioPlayerCommon.js +0 -2
- package/lib/src/components/AudioPlayer/AudioPlayerCommon.js.map +0 -1
- package/lib/src/components/AudioPlayer/AudioPlayerWithInterface.d.ts +0 -6
- package/lib/src/components/AudioPlayer/AudioPlayerWithInterface.js +0 -126
- package/lib/src/components/AudioPlayer/AudioPlayerWithInterface.js.map +0 -1
- package/lib/src/components/AudioPlayer/HeadlessAudioPlayer.d.ts +0 -8
- package/lib/src/components/AudioPlayer/HeadlessAudioPlayer.js +0 -132
- package/lib/src/components/AudioPlayer/HeadlessAudioPlayer.js.map +0 -1
- package/lib/src/components/AudioPlayer/index.d.ts +0 -10
- package/lib/src/components/AudioPlayer/index.js +0 -15
- package/lib/src/components/AudioPlayer/index.js.map +0 -1
- package/src/components/AudioPlayer/AudioPlayerCommon.js +0 -2
- package/src/components/AudioPlayer/AudioPlayerCommon.js.map +0 -1
- package/src/components/AudioPlayer/AudioPlayerCommon.ts +0 -44
- package/src/components/AudioPlayer/AudioPlayerWithInterface.js +0 -126
- package/src/components/AudioPlayer/AudioPlayerWithInterface.js.map +0 -1
- package/src/components/AudioPlayer/AudioPlayerWithInterface.tsx +0 -217
- package/src/components/AudioPlayer/HeadlessAudioPlayer.js +0 -132
- package/src/components/AudioPlayer/HeadlessAudioPlayer.js.map +0 -1
- package/src/components/AudioPlayer/HeadlessAudioPlayer.tsx +0 -187
- package/src/components/AudioPlayer/index.js +0 -15
- package/src/components/AudioPlayer/index.js.map +0 -1
- package/src/components/AudioPlayer/index.tsx +0 -30
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { Text, View, StyleSheet } from "react-native";
|
|
3
|
-
import { AntDesign } from "@expo/vector-icons";
|
|
4
|
-
import { withTheme } from "../../theming";
|
|
5
|
-
import Slider from "@react-native-community/slider";
|
|
6
|
-
import HeadlessAudioPlayer from "./HeadlessAudioPlayer";
|
|
7
|
-
import Pressable from "../Pressable";
|
|
8
|
-
/**
|
|
9
|
-
* Built on top of HeadlessAudioPlayer to provide a simple interface for playing audio
|
|
10
|
-
*/
|
|
11
|
-
const AudioPlayerWithInterface = React.forwardRef(({ style, theme, thumbColor = theme.colors.primary, completedTrackColor = theme.colors.primary, remainingTrackColor = theme.colors.divider, togglePlaybackIconSize = 24, togglePlaybackIconColor = theme.colors.primary, onPlaybackStatusUpdate: onPlaybackStatusUpdateProp, onPlaybackFinish: onPlaybackFinishProp, hidePlaybackIcon = false, hideDuration = false, hideSlider = false, ...rest }, ref) => {
|
|
12
|
-
const [isPlaying, setIsPlaying] = React.useState(false);
|
|
13
|
-
const [isLoading, setIsLoading] = React.useState(false);
|
|
14
|
-
const [durationMillis, setDurationMillis] = React.useState(1);
|
|
15
|
-
const [isDraggingSlider, setIsDraggingSlider] = React.useState(false);
|
|
16
|
-
const [sliderPositionMillis, setSliderPositionMillis] = React.useState(0);
|
|
17
|
-
const newHeadlessAudioPlayerRef = React.useRef(null);
|
|
18
|
-
// Use the provided ref or default to new ref when not provided
|
|
19
|
-
const headlessAudioPlayerRef = ref
|
|
20
|
-
? ref
|
|
21
|
-
: newHeadlessAudioPlayerRef;
|
|
22
|
-
const { color, fontFamily, fontWeight, fontSize, lineHeight, letterSpacing, textTransform, textAlign, textDecorationLine, textDecorationColor, textDecorationStyle, ...viewStyles } = StyleSheet.flatten(style || {});
|
|
23
|
-
const textStyles = {
|
|
24
|
-
color,
|
|
25
|
-
fontFamily,
|
|
26
|
-
fontWeight,
|
|
27
|
-
fontSize,
|
|
28
|
-
lineHeight,
|
|
29
|
-
letterSpacing,
|
|
30
|
-
textTransform,
|
|
31
|
-
textAlign,
|
|
32
|
-
textDecorationLine,
|
|
33
|
-
textDecorationColor,
|
|
34
|
-
textDecorationStyle,
|
|
35
|
-
};
|
|
36
|
-
const onPlaybackStatusUpdate = (status) => {
|
|
37
|
-
setIsLoading(status.isLoading);
|
|
38
|
-
setDurationMillis(status.durationMillis);
|
|
39
|
-
setSliderPositionMillis(status.currentPositionMillis);
|
|
40
|
-
setIsPlaying(status.isPlaying);
|
|
41
|
-
onPlaybackStatusUpdateProp === null || onPlaybackStatusUpdateProp === void 0 ? void 0 : onPlaybackStatusUpdateProp(status);
|
|
42
|
-
};
|
|
43
|
-
const onPlaybackFinish = () => {
|
|
44
|
-
var _a, _b;
|
|
45
|
-
setIsPlaying(false);
|
|
46
|
-
setSliderPositionMillis(0);
|
|
47
|
-
(_a = headlessAudioPlayerRef.current) === null || _a === void 0 ? void 0 : _a.togglePlayback();
|
|
48
|
-
(_b = headlessAudioPlayerRef.current) === null || _b === void 0 ? void 0 : _b.seekToPosition(0);
|
|
49
|
-
onPlaybackFinishProp === null || onPlaybackFinishProp === void 0 ? void 0 : onPlaybackFinishProp();
|
|
50
|
-
};
|
|
51
|
-
const onSlidingComplete = (sliderValue) => {
|
|
52
|
-
var _a;
|
|
53
|
-
if (isDraggingSlider) {
|
|
54
|
-
setIsDraggingSlider(false);
|
|
55
|
-
}
|
|
56
|
-
(_a = headlessAudioPlayerRef.current) === null || _a === void 0 ? void 0 : _a.seekToPosition(sliderValue);
|
|
57
|
-
};
|
|
58
|
-
const onSliderChange = () => {
|
|
59
|
-
if (!isDraggingSlider) {
|
|
60
|
-
setIsDraggingSlider(true);
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
let iconName;
|
|
64
|
-
if (isLoading) {
|
|
65
|
-
iconName = "loading1";
|
|
66
|
-
}
|
|
67
|
-
else if (isPlaying) {
|
|
68
|
-
iconName = "pause";
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
iconName = "play";
|
|
72
|
-
}
|
|
73
|
-
return (React.createElement(React.Fragment, null,
|
|
74
|
-
React.createElement(HeadlessAudioPlayer, { ...rest, ref: headlessAudioPlayerRef, onPlaybackStatusUpdate: onPlaybackStatusUpdate, onPlaybackFinish: onPlaybackFinish }),
|
|
75
|
-
React.createElement(View, { style: [
|
|
76
|
-
{
|
|
77
|
-
backgroundColor: theme.colors.background,
|
|
78
|
-
borderColor: theme.colors.divider,
|
|
79
|
-
},
|
|
80
|
-
styles.container,
|
|
81
|
-
viewStyles,
|
|
82
|
-
] },
|
|
83
|
-
!hidePlaybackIcon && (React.createElement(Pressable, { onPress: () => { var _a; return (_a = headlessAudioPlayerRef.current) === null || _a === void 0 ? void 0 : _a.togglePlayback(); }, style: styles.spacingEnd },
|
|
84
|
-
React.createElement(AntDesign, { name: iconName, size: togglePlaybackIconSize, color: togglePlaybackIconColor }))),
|
|
85
|
-
!hideDuration && (React.createElement(Text, { style: [
|
|
86
|
-
{ color: theme.colors.strong },
|
|
87
|
-
styles.spacingEnd,
|
|
88
|
-
{ ...textStyles },
|
|
89
|
-
] },
|
|
90
|
-
formatDuration(sliderPositionMillis !== null && sliderPositionMillis !== void 0 ? sliderPositionMillis : 0),
|
|
91
|
-
" /",
|
|
92
|
-
" ",
|
|
93
|
-
formatDuration(durationMillis || 0))),
|
|
94
|
-
!hideSlider && (React.createElement(Slider, { style: styles.slider, minimumTrackTintColor: completedTrackColor, maximumTrackTintColor: remainingTrackColor, thumbTintColor: thumbColor, minimumValue: 0, value: sliderPositionMillis, maximumValue: durationMillis, onValueChange: onSliderChange, onSlidingComplete: onSlidingComplete })))));
|
|
95
|
-
});
|
|
96
|
-
const styles = StyleSheet.create({
|
|
97
|
-
container: {
|
|
98
|
-
padding: 8,
|
|
99
|
-
flexDirection: "row",
|
|
100
|
-
alignItems: "center",
|
|
101
|
-
borderRadius: 8,
|
|
102
|
-
borderWidth: 1,
|
|
103
|
-
},
|
|
104
|
-
spacingEnd: {
|
|
105
|
-
marginEnd: 8,
|
|
106
|
-
},
|
|
107
|
-
slider: {
|
|
108
|
-
flex: 1,
|
|
109
|
-
},
|
|
110
|
-
});
|
|
111
|
-
function formatDuration(duration) {
|
|
112
|
-
if (duration === 0)
|
|
113
|
-
return "00:00";
|
|
114
|
-
const seconds = Math.floor((duration / 1000) % 60);
|
|
115
|
-
const minutes = Math.floor((duration / (1000 * 60)) % 60);
|
|
116
|
-
const hours = Math.floor((duration / (1000 * 60 * 60)) % 24);
|
|
117
|
-
const renderedHours = hours < 10 ? "0" + hours : hours;
|
|
118
|
-
const renderedMinutes = minutes < 10 ? "0" + minutes : minutes;
|
|
119
|
-
const renderedSeconds = seconds < 10 ? "0" + seconds : seconds;
|
|
120
|
-
if (hours > 0) {
|
|
121
|
-
return renderedHours + ":" + renderedMinutes + ":" + renderedSeconds;
|
|
122
|
-
}
|
|
123
|
-
return renderedMinutes + ":" + renderedSeconds;
|
|
124
|
-
}
|
|
125
|
-
export default withTheme(AudioPlayerWithInterface);
|
|
126
|
-
//# sourceMappingURL=AudioPlayerWithInterface.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AudioPlayerWithInterface.js","sourceRoot":"","sources":["AudioPlayerWithInterface.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { Text, View, StyleSheet } from "react-native";
|
|
3
|
-
import { AntDesign } from "@expo/vector-icons";
|
|
4
|
-
import { withTheme } from "../../theming";
|
|
5
|
-
import Slider from "@react-native-community/slider";
|
|
6
|
-
import HeadlessAudioPlayer from "./HeadlessAudioPlayer";
|
|
7
|
-
import {
|
|
8
|
-
AudioPlayerInterfaceProps,
|
|
9
|
-
AudioPlayerStatus,
|
|
10
|
-
HeadlessAudioPlayerProps,
|
|
11
|
-
HeadlessAudioPlayerRef,
|
|
12
|
-
} from "./AudioPlayerCommon";
|
|
13
|
-
import Pressable from "../Pressable";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Built on top of HeadlessAudioPlayer to provide a simple interface for playing audio
|
|
17
|
-
*/
|
|
18
|
-
const AudioPlayerWithInterface = React.forwardRef<
|
|
19
|
-
HeadlessAudioPlayerRef,
|
|
20
|
-
AudioPlayerInterfaceProps & HeadlessAudioPlayerProps
|
|
21
|
-
>(
|
|
22
|
-
(
|
|
23
|
-
{
|
|
24
|
-
style,
|
|
25
|
-
theme,
|
|
26
|
-
thumbColor = theme.colors.primary,
|
|
27
|
-
completedTrackColor = theme.colors.primary,
|
|
28
|
-
remainingTrackColor = theme.colors.divider,
|
|
29
|
-
togglePlaybackIconSize = 24,
|
|
30
|
-
togglePlaybackIconColor = theme.colors.primary,
|
|
31
|
-
onPlaybackStatusUpdate: onPlaybackStatusUpdateProp,
|
|
32
|
-
onPlaybackFinish: onPlaybackFinishProp,
|
|
33
|
-
hidePlaybackIcon = false,
|
|
34
|
-
hideDuration = false,
|
|
35
|
-
hideSlider = false,
|
|
36
|
-
...rest
|
|
37
|
-
},
|
|
38
|
-
ref
|
|
39
|
-
) => {
|
|
40
|
-
const [isPlaying, setIsPlaying] = React.useState(false);
|
|
41
|
-
const [isLoading, setIsLoading] = React.useState(false);
|
|
42
|
-
const [durationMillis, setDurationMillis] = React.useState<
|
|
43
|
-
number | undefined
|
|
44
|
-
>(1);
|
|
45
|
-
const [isDraggingSlider, setIsDraggingSlider] = React.useState(false);
|
|
46
|
-
const [sliderPositionMillis, setSliderPositionMillis] = React.useState(0);
|
|
47
|
-
const newHeadlessAudioPlayerRef =
|
|
48
|
-
React.useRef<HeadlessAudioPlayerRef>(null);
|
|
49
|
-
|
|
50
|
-
// Use the provided ref or default to new ref when not provided
|
|
51
|
-
const headlessAudioPlayerRef = ref
|
|
52
|
-
? (ref as React.RefObject<HeadlessAudioPlayerRef>)
|
|
53
|
-
: newHeadlessAudioPlayerRef;
|
|
54
|
-
|
|
55
|
-
const {
|
|
56
|
-
color,
|
|
57
|
-
fontFamily,
|
|
58
|
-
fontWeight,
|
|
59
|
-
fontSize,
|
|
60
|
-
lineHeight,
|
|
61
|
-
letterSpacing,
|
|
62
|
-
textTransform,
|
|
63
|
-
textAlign,
|
|
64
|
-
textDecorationLine,
|
|
65
|
-
textDecorationColor,
|
|
66
|
-
textDecorationStyle,
|
|
67
|
-
...viewStyles
|
|
68
|
-
} = StyleSheet.flatten(style || {});
|
|
69
|
-
|
|
70
|
-
const textStyles = {
|
|
71
|
-
color,
|
|
72
|
-
fontFamily,
|
|
73
|
-
fontWeight,
|
|
74
|
-
fontSize,
|
|
75
|
-
lineHeight,
|
|
76
|
-
letterSpacing,
|
|
77
|
-
textTransform,
|
|
78
|
-
textAlign,
|
|
79
|
-
textDecorationLine,
|
|
80
|
-
textDecorationColor,
|
|
81
|
-
textDecorationStyle,
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const onPlaybackStatusUpdate = (status: AudioPlayerStatus) => {
|
|
85
|
-
setIsLoading(status.isLoading);
|
|
86
|
-
setDurationMillis(status.durationMillis);
|
|
87
|
-
setSliderPositionMillis(status.currentPositionMillis);
|
|
88
|
-
setIsPlaying(status.isPlaying);
|
|
89
|
-
onPlaybackStatusUpdateProp?.(status);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const onPlaybackFinish = () => {
|
|
93
|
-
setIsPlaying(false);
|
|
94
|
-
setSliderPositionMillis(0);
|
|
95
|
-
headlessAudioPlayerRef.current?.togglePlayback();
|
|
96
|
-
headlessAudioPlayerRef.current?.seekToPosition(0);
|
|
97
|
-
onPlaybackFinishProp?.();
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const onSlidingComplete = (sliderValue: number) => {
|
|
101
|
-
if (isDraggingSlider) {
|
|
102
|
-
setIsDraggingSlider(false);
|
|
103
|
-
}
|
|
104
|
-
headlessAudioPlayerRef.current?.seekToPosition(sliderValue);
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const onSliderChange = () => {
|
|
108
|
-
if (!isDraggingSlider) {
|
|
109
|
-
setIsDraggingSlider(true);
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
let iconName;
|
|
114
|
-
if (isLoading) {
|
|
115
|
-
iconName = "loading1";
|
|
116
|
-
} else if (isPlaying) {
|
|
117
|
-
iconName = "pause";
|
|
118
|
-
} else {
|
|
119
|
-
iconName = "play";
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return (
|
|
123
|
-
<>
|
|
124
|
-
<HeadlessAudioPlayer
|
|
125
|
-
{...rest}
|
|
126
|
-
ref={headlessAudioPlayerRef}
|
|
127
|
-
onPlaybackStatusUpdate={onPlaybackStatusUpdate}
|
|
128
|
-
onPlaybackFinish={onPlaybackFinish}
|
|
129
|
-
/>
|
|
130
|
-
<View
|
|
131
|
-
style={[
|
|
132
|
-
{
|
|
133
|
-
backgroundColor: theme.colors.background,
|
|
134
|
-
borderColor: theme.colors.divider,
|
|
135
|
-
},
|
|
136
|
-
styles.container,
|
|
137
|
-
viewStyles,
|
|
138
|
-
]}
|
|
139
|
-
>
|
|
140
|
-
{!hidePlaybackIcon && (
|
|
141
|
-
<Pressable
|
|
142
|
-
onPress={() => headlessAudioPlayerRef.current?.togglePlayback()}
|
|
143
|
-
style={styles.spacingEnd}
|
|
144
|
-
>
|
|
145
|
-
<AntDesign
|
|
146
|
-
name={iconName as any}
|
|
147
|
-
size={togglePlaybackIconSize}
|
|
148
|
-
color={togglePlaybackIconColor}
|
|
149
|
-
/>
|
|
150
|
-
</Pressable>
|
|
151
|
-
)}
|
|
152
|
-
{!hideDuration && (
|
|
153
|
-
<Text
|
|
154
|
-
style={[
|
|
155
|
-
{ color: theme.colors.strong },
|
|
156
|
-
styles.spacingEnd,
|
|
157
|
-
{ ...textStyles },
|
|
158
|
-
]}
|
|
159
|
-
>
|
|
160
|
-
{formatDuration(sliderPositionMillis ?? 0)} /{" "}
|
|
161
|
-
{formatDuration(durationMillis || 0)}
|
|
162
|
-
</Text>
|
|
163
|
-
)}
|
|
164
|
-
{!hideSlider && (
|
|
165
|
-
<Slider
|
|
166
|
-
style={styles.slider}
|
|
167
|
-
minimumTrackTintColor={completedTrackColor}
|
|
168
|
-
maximumTrackTintColor={remainingTrackColor}
|
|
169
|
-
thumbTintColor={thumbColor}
|
|
170
|
-
minimumValue={0}
|
|
171
|
-
value={sliderPositionMillis}
|
|
172
|
-
maximumValue={durationMillis}
|
|
173
|
-
onValueChange={onSliderChange}
|
|
174
|
-
onSlidingComplete={onSlidingComplete}
|
|
175
|
-
/>
|
|
176
|
-
)}
|
|
177
|
-
</View>
|
|
178
|
-
</>
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
const styles = StyleSheet.create({
|
|
184
|
-
container: {
|
|
185
|
-
padding: 8,
|
|
186
|
-
flexDirection: "row",
|
|
187
|
-
alignItems: "center",
|
|
188
|
-
borderRadius: 8,
|
|
189
|
-
borderWidth: 1,
|
|
190
|
-
},
|
|
191
|
-
spacingEnd: {
|
|
192
|
-
marginEnd: 8,
|
|
193
|
-
},
|
|
194
|
-
slider: {
|
|
195
|
-
flex: 1,
|
|
196
|
-
},
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
function formatDuration(duration: number) {
|
|
200
|
-
if (duration === 0) return "00:00";
|
|
201
|
-
|
|
202
|
-
const seconds = Math.floor((duration / 1000) % 60);
|
|
203
|
-
const minutes = Math.floor((duration / (1000 * 60)) % 60);
|
|
204
|
-
const hours = Math.floor((duration / (1000 * 60 * 60)) % 24);
|
|
205
|
-
|
|
206
|
-
const renderedHours = hours < 10 ? "0" + hours : hours;
|
|
207
|
-
const renderedMinutes = minutes < 10 ? "0" + minutes : minutes;
|
|
208
|
-
const renderedSeconds = seconds < 10 ? "0" + seconds : seconds;
|
|
209
|
-
|
|
210
|
-
if (hours > 0) {
|
|
211
|
-
return renderedHours + ":" + renderedMinutes + ":" + renderedSeconds;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return renderedMinutes + ":" + renderedSeconds;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
export default withTheme(AudioPlayerWithInterface);
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { Audio, InterruptionModeIOS, InterruptionModeAndroid, } from "expo-av";
|
|
3
|
-
/**
|
|
4
|
-
* Audio Player component without an interface (UI).
|
|
5
|
-
* Only handles playing of the audio and provides callbacks and ref functions
|
|
6
|
-
*/
|
|
7
|
-
const HeadlessAudioPlayer = React.forwardRef(({ source, interruptionMode = "lower volume", playsInBackground = false, playsInSilentModeIOS = false, playThroughEarpieceAndroid = false, onPlaybackStatusUpdate: onPlaybackStatusUpdateProp, onPlaybackFinish, }, ref) => {
|
|
8
|
-
const [currentSound, setCurrentSound] = React.useState();
|
|
9
|
-
const [isPlaying, setIsPlaying] = React.useState(false);
|
|
10
|
-
const updateAudioMode = React.useCallback(async () => {
|
|
11
|
-
try {
|
|
12
|
-
await Audio.setAudioModeAsync({
|
|
13
|
-
staysActiveInBackground: playsInBackground,
|
|
14
|
-
interruptionModeIOS: interruptionMode === "lower volume"
|
|
15
|
-
? InterruptionModeIOS.DuckOthers
|
|
16
|
-
: InterruptionModeIOS.DoNotMix,
|
|
17
|
-
interruptionModeAndroid: interruptionMode === "lower volume"
|
|
18
|
-
? InterruptionModeAndroid.DuckOthers
|
|
19
|
-
: InterruptionModeAndroid.DoNotMix,
|
|
20
|
-
playsInSilentModeIOS,
|
|
21
|
-
playThroughEarpieceAndroid,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
catch (e) {
|
|
25
|
-
console.error("Failed to set audio mode. interruptionMode, playsInBackground, playsInSilentModeIOS, playThroughEarpieceAndroid might not be set. Failed with", e);
|
|
26
|
-
}
|
|
27
|
-
}, [
|
|
28
|
-
interruptionMode,
|
|
29
|
-
playsInBackground,
|
|
30
|
-
playsInSilentModeIOS,
|
|
31
|
-
playThroughEarpieceAndroid,
|
|
32
|
-
]);
|
|
33
|
-
const onPlaybackStatusUpdate = (status) => {
|
|
34
|
-
if (status.isLoaded) {
|
|
35
|
-
onPlaybackStatusUpdateProp === null || onPlaybackStatusUpdateProp === void 0 ? void 0 : onPlaybackStatusUpdateProp({
|
|
36
|
-
isPlaying: status.isPlaying,
|
|
37
|
-
isLoading: false,
|
|
38
|
-
isBuffering: status.isBuffering,
|
|
39
|
-
currentPositionMillis: status.positionMillis || 0,
|
|
40
|
-
durationMillis: status.durationMillis || 0,
|
|
41
|
-
bufferedDurationMillis: status.playableDurationMillis || 0,
|
|
42
|
-
isError: false,
|
|
43
|
-
});
|
|
44
|
-
if (status.didJustFinish) {
|
|
45
|
-
onPlaybackFinish === null || onPlaybackFinish === void 0 ? void 0 : onPlaybackFinish();
|
|
46
|
-
}
|
|
47
|
-
setIsPlaying(status.isPlaying);
|
|
48
|
-
}
|
|
49
|
-
else if (status.error) {
|
|
50
|
-
onPlaybackStatusUpdateProp === null || onPlaybackStatusUpdateProp === void 0 ? void 0 : onPlaybackStatusUpdateProp({
|
|
51
|
-
isPlaying: false,
|
|
52
|
-
isLoading: false,
|
|
53
|
-
isBuffering: false,
|
|
54
|
-
currentPositionMillis: 0,
|
|
55
|
-
durationMillis: 0,
|
|
56
|
-
bufferedDurationMillis: 0,
|
|
57
|
-
isError: true,
|
|
58
|
-
error: status.error,
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
const loadAudio = async () => {
|
|
63
|
-
onPlaybackStatusUpdateProp === null || onPlaybackStatusUpdateProp === void 0 ? void 0 : onPlaybackStatusUpdateProp({
|
|
64
|
-
isPlaying: false,
|
|
65
|
-
isLoading: true,
|
|
66
|
-
isBuffering: false,
|
|
67
|
-
currentPositionMillis: 0,
|
|
68
|
-
durationMillis: 0,
|
|
69
|
-
bufferedDurationMillis: 0,
|
|
70
|
-
isError: false,
|
|
71
|
-
});
|
|
72
|
-
const { sound } = await Audio.Sound.createAsync(source);
|
|
73
|
-
setCurrentSound(sound);
|
|
74
|
-
sound.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate);
|
|
75
|
-
};
|
|
76
|
-
const togglePlayback = React.useCallback(async () => {
|
|
77
|
-
//Has to be called everytime a player is played to reconfigure the global Audio config based on each player's configuration
|
|
78
|
-
await updateAudioMode();
|
|
79
|
-
if (isPlaying) {
|
|
80
|
-
await (currentSound === null || currentSound === void 0 ? void 0 : currentSound.pauseAsync());
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
await (currentSound === null || currentSound === void 0 ? void 0 : currentSound.playAsync());
|
|
84
|
-
}
|
|
85
|
-
}, [currentSound, updateAudioMode, isPlaying]);
|
|
86
|
-
const seekToPosition = React.useCallback(async (positionMillis) => {
|
|
87
|
-
await (currentSound === null || currentSound === void 0 ? void 0 : currentSound.setPositionAsync(positionMillis));
|
|
88
|
-
}, [currentSound]);
|
|
89
|
-
useSourceDeepCompareEffect(() => {
|
|
90
|
-
loadAudio();
|
|
91
|
-
// Ignore dependency of loadAudio
|
|
92
|
-
}, [source]);
|
|
93
|
-
React.useEffect(() => {
|
|
94
|
-
return currentSound
|
|
95
|
-
? () => {
|
|
96
|
-
currentSound.unloadAsync();
|
|
97
|
-
}
|
|
98
|
-
: undefined;
|
|
99
|
-
}, [currentSound]);
|
|
100
|
-
React.useImperativeHandle(ref, () => {
|
|
101
|
-
return {
|
|
102
|
-
seekToPosition,
|
|
103
|
-
togglePlayback,
|
|
104
|
-
};
|
|
105
|
-
}, [seekToPosition, togglePlayback]);
|
|
106
|
-
return null;
|
|
107
|
-
});
|
|
108
|
-
// The source provided into the AudioPlayer can be of type {uri: "some uri"}
|
|
109
|
-
// In the case that this object is created inline, each rerender provides a new source object because a new object is initialized everytime
|
|
110
|
-
// This creates an issue with being a useEffect dependency
|
|
111
|
-
//
|
|
112
|
-
// This creates variants of useEffect that checks deep equality of 'uri' to determine if dependency changed or not
|
|
113
|
-
// Follows: https://stackoverflow.com/a/54096391
|
|
114
|
-
function sourceDeepCompareEquals(a, b) {
|
|
115
|
-
if ((a === null || a === void 0 ? void 0 : a.uri) && (b === null || b === void 0 ? void 0 : b.uri)) {
|
|
116
|
-
return a.uri === b.uri;
|
|
117
|
-
}
|
|
118
|
-
return a === b;
|
|
119
|
-
}
|
|
120
|
-
function useSourceDeepCompareMemoize(value) {
|
|
121
|
-
const ref = React.useRef();
|
|
122
|
-
if (!sourceDeepCompareEquals(value, ref.current)) {
|
|
123
|
-
ref.current = value;
|
|
124
|
-
}
|
|
125
|
-
return ref.current;
|
|
126
|
-
}
|
|
127
|
-
function useSourceDeepCompareEffect(callback, dependencies) {
|
|
128
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
129
|
-
React.useEffect(callback, dependencies.map(useSourceDeepCompareMemoize));
|
|
130
|
-
}
|
|
131
|
-
export default HeadlessAudioPlayer;
|
|
132
|
-
//# sourceMappingURL=HeadlessAudioPlayer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"HeadlessAudioPlayer.js","sourceRoot":"","sources":["HeadlessAudioPlayer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {
|
|
3
|
-
Audio,
|
|
4
|
-
AVPlaybackStatus,
|
|
5
|
-
InterruptionModeIOS,
|
|
6
|
-
InterruptionModeAndroid,
|
|
7
|
-
} from "expo-av";
|
|
8
|
-
import {
|
|
9
|
-
HeadlessAudioPlayerProps,
|
|
10
|
-
HeadlessAudioPlayerRef,
|
|
11
|
-
} from "./AudioPlayerCommon";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Audio Player component without an interface (UI).
|
|
15
|
-
* Only handles playing of the audio and provides callbacks and ref functions
|
|
16
|
-
*/
|
|
17
|
-
const HeadlessAudioPlayer = React.forwardRef<
|
|
18
|
-
HeadlessAudioPlayerRef,
|
|
19
|
-
HeadlessAudioPlayerProps
|
|
20
|
-
>(
|
|
21
|
-
(
|
|
22
|
-
{
|
|
23
|
-
source,
|
|
24
|
-
interruptionMode = "lower volume",
|
|
25
|
-
playsInBackground = false,
|
|
26
|
-
playsInSilentModeIOS = false,
|
|
27
|
-
playThroughEarpieceAndroid = false,
|
|
28
|
-
onPlaybackStatusUpdate: onPlaybackStatusUpdateProp,
|
|
29
|
-
onPlaybackFinish,
|
|
30
|
-
},
|
|
31
|
-
ref
|
|
32
|
-
) => {
|
|
33
|
-
const [currentSound, setCurrentSound] = React.useState<Audio.Sound>();
|
|
34
|
-
const [isPlaying, setIsPlaying] = React.useState(false);
|
|
35
|
-
|
|
36
|
-
const updateAudioMode = React.useCallback(async () => {
|
|
37
|
-
try {
|
|
38
|
-
await Audio.setAudioModeAsync({
|
|
39
|
-
staysActiveInBackground: playsInBackground,
|
|
40
|
-
interruptionModeIOS:
|
|
41
|
-
interruptionMode === "lower volume"
|
|
42
|
-
? InterruptionModeIOS.DuckOthers
|
|
43
|
-
: InterruptionModeIOS.DoNotMix,
|
|
44
|
-
interruptionModeAndroid:
|
|
45
|
-
interruptionMode === "lower volume"
|
|
46
|
-
? InterruptionModeAndroid.DuckOthers
|
|
47
|
-
: InterruptionModeAndroid.DoNotMix,
|
|
48
|
-
playsInSilentModeIOS,
|
|
49
|
-
playThroughEarpieceAndroid,
|
|
50
|
-
});
|
|
51
|
-
} catch (e) {
|
|
52
|
-
console.error(
|
|
53
|
-
"Failed to set audio mode. interruptionMode, playsInBackground, playsInSilentModeIOS, playThroughEarpieceAndroid might not be set. Failed with",
|
|
54
|
-
e
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
}, [
|
|
58
|
-
interruptionMode,
|
|
59
|
-
playsInBackground,
|
|
60
|
-
playsInSilentModeIOS,
|
|
61
|
-
playThroughEarpieceAndroid,
|
|
62
|
-
]);
|
|
63
|
-
|
|
64
|
-
const onPlaybackStatusUpdate = (status: AVPlaybackStatus) => {
|
|
65
|
-
if (status.isLoaded) {
|
|
66
|
-
onPlaybackStatusUpdateProp?.({
|
|
67
|
-
isPlaying: status.isPlaying,
|
|
68
|
-
isLoading: false,
|
|
69
|
-
isBuffering: status.isBuffering,
|
|
70
|
-
currentPositionMillis: status.positionMillis || 0,
|
|
71
|
-
durationMillis: status.durationMillis || 0,
|
|
72
|
-
bufferedDurationMillis: status.playableDurationMillis || 0,
|
|
73
|
-
isError: false,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
if (status.didJustFinish) {
|
|
77
|
-
onPlaybackFinish?.();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
setIsPlaying(status.isPlaying);
|
|
81
|
-
} else if (status.error) {
|
|
82
|
-
onPlaybackStatusUpdateProp?.({
|
|
83
|
-
isPlaying: false,
|
|
84
|
-
isLoading: false,
|
|
85
|
-
isBuffering: false,
|
|
86
|
-
currentPositionMillis: 0,
|
|
87
|
-
durationMillis: 0,
|
|
88
|
-
bufferedDurationMillis: 0,
|
|
89
|
-
isError: true,
|
|
90
|
-
error: status.error,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const loadAudio = async () => {
|
|
96
|
-
onPlaybackStatusUpdateProp?.({
|
|
97
|
-
isPlaying: false,
|
|
98
|
-
isLoading: true,
|
|
99
|
-
isBuffering: false,
|
|
100
|
-
currentPositionMillis: 0,
|
|
101
|
-
durationMillis: 0,
|
|
102
|
-
bufferedDurationMillis: 0,
|
|
103
|
-
isError: false,
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
const { sound } = await Audio.Sound.createAsync(source);
|
|
107
|
-
setCurrentSound(sound);
|
|
108
|
-
sound.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate);
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const togglePlayback = React.useCallback(async () => {
|
|
112
|
-
//Has to be called everytime a player is played to reconfigure the global Audio config based on each player's configuration
|
|
113
|
-
await updateAudioMode();
|
|
114
|
-
|
|
115
|
-
if (isPlaying) {
|
|
116
|
-
await currentSound?.pauseAsync();
|
|
117
|
-
} else {
|
|
118
|
-
await currentSound?.playAsync();
|
|
119
|
-
}
|
|
120
|
-
}, [currentSound, updateAudioMode, isPlaying]);
|
|
121
|
-
|
|
122
|
-
const seekToPosition = React.useCallback(
|
|
123
|
-
async (positionMillis: number) => {
|
|
124
|
-
await currentSound?.setPositionAsync(positionMillis);
|
|
125
|
-
},
|
|
126
|
-
[currentSound]
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
useSourceDeepCompareEffect(() => {
|
|
130
|
-
loadAudio();
|
|
131
|
-
|
|
132
|
-
// Ignore dependency of loadAudio
|
|
133
|
-
}, [source]);
|
|
134
|
-
|
|
135
|
-
React.useEffect(() => {
|
|
136
|
-
return currentSound
|
|
137
|
-
? () => {
|
|
138
|
-
currentSound.unloadAsync();
|
|
139
|
-
}
|
|
140
|
-
: undefined;
|
|
141
|
-
}, [currentSound]);
|
|
142
|
-
|
|
143
|
-
React.useImperativeHandle(
|
|
144
|
-
ref,
|
|
145
|
-
() => {
|
|
146
|
-
return {
|
|
147
|
-
seekToPosition,
|
|
148
|
-
togglePlayback,
|
|
149
|
-
};
|
|
150
|
-
},
|
|
151
|
-
[seekToPosition, togglePlayback]
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
return null;
|
|
155
|
-
}
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
// The source provided into the AudioPlayer can be of type {uri: "some uri"}
|
|
159
|
-
// In the case that this object is created inline, each rerender provides a new source object because a new object is initialized everytime
|
|
160
|
-
// This creates an issue with being a useEffect dependency
|
|
161
|
-
//
|
|
162
|
-
// This creates variants of useEffect that checks deep equality of 'uri' to determine if dependency changed or not
|
|
163
|
-
// Follows: https://stackoverflow.com/a/54096391
|
|
164
|
-
function sourceDeepCompareEquals(a: any, b: any) {
|
|
165
|
-
if (a?.uri && b?.uri) {
|
|
166
|
-
return a.uri === b.uri;
|
|
167
|
-
}
|
|
168
|
-
return a === b;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function useSourceDeepCompareMemoize(value: any) {
|
|
172
|
-
const ref = React.useRef();
|
|
173
|
-
if (!sourceDeepCompareEquals(value, ref.current)) {
|
|
174
|
-
ref.current = value;
|
|
175
|
-
}
|
|
176
|
-
return ref.current;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function useSourceDeepCompareEffect(
|
|
180
|
-
callback: React.EffectCallback,
|
|
181
|
-
dependencies: React.DependencyList
|
|
182
|
-
) {
|
|
183
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
184
|
-
React.useEffect(callback, dependencies.map(useSourceDeepCompareMemoize));
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export default HeadlessAudioPlayer;
|