diff --git a/eas.json b/eas.json index c035dfa..f075478 100644 --- a/eas.json +++ b/eas.json @@ -5,25 +5,24 @@ "promptToConfigurePushNotifications": true }, "build": { + "preview": { + "distribution": "internal", + "android": { + "buildType": "apk" + }, + "ios": { + "simulator": true + } + }, "production": { + "android": { + "buildType": "app-bundle", + "autoIncrement": "versionCode", + "resourceClass": "large" + }, "ios": { "buildConfiguration": "Release", "autoIncrement": "buildNumber" - }, - "android": { - "buildType": "apk", - "autoIncrement": "versionCode" - } - }, - "preview": { - "distribution": "internal", - "ios": { - "simulator": true - }, - "android": { - "buildType": "apk", - "gradleCommand": ":app:assembleDebug", - "applicationArchivePath": "android/app/build/outputs/apk/debug/app-debug.apk" } } }, diff --git a/src/components/AnimatedPaginationDot/AnimatedPaginationDot.js b/src/components/AnimatedPaginationDot/AnimatedPaginationDot.js index cca6259..fcf1a7e 100644 --- a/src/components/AnimatedPaginationDot/AnimatedPaginationDot.js +++ b/src/components/AnimatedPaginationDot/AnimatedPaginationDot.js @@ -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" diff --git a/src/components/player/GlobalAudioPlayer.js b/src/components/player/GlobalAudioPlayer.js index 99e9648..d47ce77 100644 --- a/src/components/player/GlobalAudioPlayer.js +++ b/src/components/player/GlobalAudioPlayer.js @@ -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 ( { )} + + + { const creatorName = item?.userName; const audioPlayer = useSharedAudioPlayer(audioSource || undefined, { - id: item?.id ? `playback-${item.id}` : audioSource?.uri ? `playback-${audioSource.uri}` : undefined, + id: item?.id + ? `playback-${item.id}` + : audioSource?.uri + ? `playback-${audioSource.uri}` + : undefined, title: typeof item?.title === "string" ? item.title : "", artist: typeof item?.userName === "string" ? item.userName : "", artwork: item?.coverUrl || null, @@ -217,57 +221,6 @@ const PlaybackItem = ({ item, isActive, userCache, getUserByUid }) => { backgroundColor: "black", }} > - {(projectTitle || creatorName) && ( - - - {projectTitle ? ( - - {projectTitle} - - ) : null} - {creatorName ? ( - - {creatorName} - - ) : null} - - - )} {!!videoUrl ? ( { return ( - {(activeTitle || activeCreatorName) && ( - - - {activeTitle ? ( - - {activeTitle} - - ) : null} - {activeCreatorName ? ( - - {activeCreatorName} - - ) : null} - - - )} {activeVideoUrl ? (