fix player web

This commit is contained in:
2025-10-07 12:15:17 +02:00
parent 0c9e9f5f56
commit 6734dea010
5 changed files with 145 additions and 101 deletions
@@ -22,7 +22,7 @@ const AnimatedPaginationDot = ({
}) => {
const animatedValue = useMemo(
() => scrollValue || new Animated.Value(0),
[scrollValue],
[scrollValue]
);
const { width, height } = useWindowDimensions();
@@ -36,7 +36,10 @@ const AnimatedPaginationDot = ({
return Math.max(width, 1);
}, [height, itemDimension, orientation, width]);
const resolvedDotStyle = useMemo(() => StyleSheet.flatten(dotStyle) || {}, [dotStyle]);
const resolvedDotStyle = useMemo(
() => StyleSheet.flatten(dotStyle) || {},
[dotStyle]
);
const defaultSize = Math.max(baseDotSize, 1);
const baseWidth =
typeof resolvedDotStyle?.width === "number"
+119 -8
View File
@@ -1,11 +1,14 @@
import { BlurView } from "expo-blur";
import React, { useMemo } from "react";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { Image, Pressable, StyleSheet, Text, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { icons, img } from "../../assets";
import { arrayRemove, arrayUnion, projectsRef } from "../../config/firebase";
import { isWeb } from "../../hooks/useLayoutType";
import useDataFromRef from "../../hooks/useDataFromRef";
import usePlayer from "../../hooks/usePlayer";
import { useUser } from "../../providers/UserDataProvider";
import { gutters, Palette } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts";
@@ -21,16 +24,90 @@ const formatDuration = (ms) => {
const GlobalAudioPlayer = () => {
const { currentTrack, isPlaying, positionMs, durationMs, pause, resume } =
usePlayer();
const { currentUID } = useUser() || {};
const [pendingLike, setPendingLike] = useState(null);
const projectId = useMemo(() => {
const metadataProjectId =
typeof currentTrack?.metadata?.projectId === "string"
? currentTrack.metadata.projectId
: null;
const metadataPlaybackId =
typeof currentTrack?.metadata?.playbackId === "string"
? currentTrack.metadata.playbackId
: null;
const contextProjectId =
typeof currentTrack?.context?.projectId === "string"
? currentTrack.context.projectId
: null;
return metadataProjectId || metadataPlaybackId || contextProjectId || null;
}, [
currentTrack?.context?.projectId,
currentTrack?.metadata?.playbackId,
currentTrack?.metadata?.projectId,
]);
const { data: projectData } = useDataFromRef({
ref: projectId ? projectsRef.doc(projectId) : null,
simpleRef: true,
listener: true,
condition: !!projectId,
refreshArray: [projectId],
});
const likedByList = Array.isArray(projectData?.likedBy)
? projectData.likedBy
: [];
const likedFromDoc = useMemo(() => {
if (!projectId || !currentUID) return false;
return likedByList.includes(currentUID);
}, [likedByList, projectId, currentUID]);
const effectiveIsLiked =
pendingLike !== null ? pendingLike : likedFromDoc;
const isLikeProcessing =
pendingLike !== null && pendingLike !== likedFromDoc;
useEffect(() => {
setPendingLike(null);
}, [projectId, currentUID]);
useEffect(() => {
if (pendingLike === null) return;
if (pendingLike === likedFromDoc) {
setPendingLike(null);
}
}, [pendingLike, likedFromDoc]);
const handleToggleLike = useCallback(async () => {
if (!projectId || !currentUID || isLikeProcessing) return;
const next = !effectiveIsLiked;
setPendingLike(next);
try {
await projectsRef.doc(projectId).set(
{
likedBy: next ? arrayUnion(currentUID) : arrayRemove(currentUID),
},
{ merge: true }
);
} catch (_error) {
setPendingLike(null);
}
}, [
currentUID,
effectiveIsLiked,
isLikeProcessing,
projectId,
]);
const insets = useSafeAreaInsets();
const hasTrack = !!currentTrack?.source;
if (!hasTrack) return null;
const title = currentTrack?.title || "Lecture en cours";
const artist = currentTrack?.artist || "";
const progress =
durationMs > 0 ? Math.min(1, Math.max(0, positionMs / durationMs)) : 0;
const artworkSource = useMemo(() => {
if (typeof currentTrack?.artwork === "number") return currentTrack.artwork;
@@ -55,6 +132,8 @@ const GlobalAudioPlayer = () => {
const GAP_WITH_TAB = 8;
const bottomOffset = (isWeb ? gutters : 3) + TAB_BAR_HEIGHT + GAP_WITH_TAB;
if (!hasTrack) return null;
return (
<View
pointerEvents="box-none"
@@ -83,10 +162,26 @@ const GlobalAudioPlayer = () => {
)}
</View>
<View style={styles.actions}>
<Pressable
onPress={handleToggleLike}
hitSlop={12}
disabled={!projectId || !currentUID || isLikeProcessing}
style={[
styles.actionButton,
styles.likeButton,
(!projectId || !currentUID || isLikeProcessing) &&
styles.disabledAction,
]}
>
<Image
source={effectiveIsLiked ? icons.heart : icons.heartOutline}
style={styles.likeIcon}
/>
</Pressable>
<Pressable
onPress={handleToggle}
hitSlop={12}
style={styles.toggleButton}
style={[styles.actionButton, styles.toggleButton]}
>
<Image
source={isPlaying ? icons.pause : icons.play}
@@ -164,13 +259,29 @@ const styles = StyleSheet.create({
actions: {
flexDirection: "row",
alignItems: "center",
gap: 8,
},
actionButton: {
alignItems: "center",
justifyContent: "center",
},
disabledAction: {
opacity: 0.6,
},
likeButton: {
width: 40,
height: 40,
borderRadius: 20,
},
likeIcon: {
width: 22,
height: 22,
resizeMode: "contain",
},
toggleButton: {
width: 44,
height: 44,
borderRadius: 22,
alignItems: "center",
justifyContent: "center",
// backgroundColor: "rgba(255, 255, 255, 0.1)",
},
toggleIcon: {