music details web
This commit is contained in:
@@ -58,7 +58,9 @@ const useHtmlAudioPlayer = (source) => {
|
|||||||
audioRef.current = audio;
|
audioRef.current = audio;
|
||||||
|
|
||||||
const syncDuration = () => {
|
const syncDuration = () => {
|
||||||
const duration = Number.isFinite(audio.duration) ? audio.duration * 1000 : 0;
|
const duration = Number.isFinite(audio.duration)
|
||||||
|
? audio.duration * 1000
|
||||||
|
: 0;
|
||||||
setState((prev) => ({ ...prev, durationMs: duration }));
|
setState((prev) => ({ ...prev, durationMs: duration }));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,7 +73,8 @@ const useHtmlAudioPlayer = (source) => {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
const handlePlay = () => setState((prev) => ({ ...prev, isPlaying: true }));
|
const handlePlay = () => setState((prev) => ({ ...prev, isPlaying: true }));
|
||||||
const handlePause = () => setState((prev) => ({ ...prev, isPlaying: false }));
|
const handlePause = () =>
|
||||||
|
setState((prev) => ({ ...prev, isPlaying: false }));
|
||||||
const handleEnded = () =>
|
const handleEnded = () =>
|
||||||
setState((prev) => ({
|
setState((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
@@ -462,7 +465,7 @@ const MusicDetails = ({ route }) => {
|
|||||||
>
|
>
|
||||||
<View>
|
<View>
|
||||||
<View style={{ gap: 28 }}>
|
<View style={{ gap: 28 }}>
|
||||||
{coverUrl && (
|
{coverUrl ? (
|
||||||
<ExpoImage
|
<ExpoImage
|
||||||
source={{ uri: coverUrl }}
|
source={{ uri: coverUrl }}
|
||||||
cachePolicy="memory-disk"
|
cachePolicy="memory-disk"
|
||||||
@@ -471,9 +474,17 @@ const MusicDetails = ({ route }) => {
|
|||||||
transition={150}
|
transition={150}
|
||||||
style={styles.img}
|
style={styles.img}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
// empty container
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
...styles.img,
|
||||||
|
backgroundColor: Palette.transparentWhite,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<View style={{ ...Style.containerSpaceBetween }}>
|
<View style={{ ...Style.containerSpaceBetween }}>
|
||||||
<View>
|
<View style={{ flex: 1, minWidth: 0 }}>
|
||||||
<Text style={styles.title}>{title}</Text>
|
<Text style={styles.title}>{title}</Text>
|
||||||
<Text style={styles.name}>{artist}</Text>
|
<Text style={styles.name}>{artist}</Text>
|
||||||
</View>
|
</View>
|
||||||
@@ -517,33 +528,6 @@ const MusicDetails = ({ route }) => {
|
|||||||
|
|
||||||
{songUrl && (
|
{songUrl && (
|
||||||
<View style={{ paddingTop: 22 }}>
|
<View style={{ paddingTop: 22 }}>
|
||||||
<Slider
|
|
||||||
value={fmt(positionMs)}
|
|
||||||
maxValue={fmt(durationMs)}
|
|
||||||
progress={durationMs ? (positionMs || 0) / durationMs : 0}
|
|
||||||
seekEnabled={!!songUrl}
|
|
||||||
onSeekStart={async () => {
|
|
||||||
try {
|
|
||||||
wasPlayingBeforeSeek.current = !!isPlaying;
|
|
||||||
if (isPlaying) {
|
|
||||||
await pauseAudio();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Pause on seek start error", e?.message);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onSeek={onSeek}
|
|
||||||
onSeekEnd={async () => {
|
|
||||||
try {
|
|
||||||
if (wasPlayingBeforeSeek.current) {
|
|
||||||
await playAudio();
|
|
||||||
}
|
|
||||||
wasPlayingBeforeSeek.current = false;
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Resume after seek error", e?.message);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
...Style.containerRow,
|
...Style.containerRow,
|
||||||
@@ -586,6 +570,33 @@ const MusicDetails = ({ route }) => {
|
|||||||
/>
|
/>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
</View>
|
</View>
|
||||||
|
<Slider
|
||||||
|
value={fmt(positionMs)}
|
||||||
|
maxValue={fmt(durationMs)}
|
||||||
|
progress={durationMs ? (positionMs || 0) / durationMs : 0}
|
||||||
|
seekEnabled={!!songUrl}
|
||||||
|
onSeekStart={async () => {
|
||||||
|
try {
|
||||||
|
wasPlayingBeforeSeek.current = !!isPlaying;
|
||||||
|
if (isPlaying) {
|
||||||
|
await pauseAudio();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Pause on seek start error", e?.message);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onSeek={onSeek}
|
||||||
|
onSeekEnd={async () => {
|
||||||
|
try {
|
||||||
|
if (wasPlayingBeforeSeek.current) {
|
||||||
|
await playAudio();
|
||||||
|
}
|
||||||
|
wasPlayingBeforeSeek.current = false;
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Resume after seek error", e?.message);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
@@ -667,8 +678,8 @@ export default MusicDetails;
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
img: {
|
img: {
|
||||||
width: 160,
|
width: 200,
|
||||||
height: 160,
|
height: 200,
|
||||||
borderRadius: 24,
|
borderRadius: 24,
|
||||||
alignSelf: "center",
|
alignSelf: "center",
|
||||||
},
|
},
|
||||||
@@ -676,7 +687,8 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: Palette.white,
|
color: Palette.white,
|
||||||
fontFamily: FONT_FAMILY.HelveticaNeueMedium,
|
fontFamily: FONT_FAMILY.HelveticaNeueMedium,
|
||||||
width: responsiveWidth(70),
|
maxWidth: responsiveWidth(70),
|
||||||
|
flexShrink: 1,
|
||||||
marginBottom: responsiveHeight(1),
|
marginBottom: responsiveHeight(1),
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
|
|||||||
Reference in New Issue
Block a user