diff --git a/src/components/bottomsheets/CommentsBottomSheet.js b/src/components/bottomsheets/CommentsBottomSheet.js index 0abd697..382c38f 100644 --- a/src/components/bottomsheets/CommentsBottomSheet.js +++ b/src/components/bottomsheets/CommentsBottomSheet.js @@ -87,12 +87,19 @@ const CommentsBottomSheet = () => { } }, [projectId]); - const { data: comments = [] } = useDataFromRef({ + const { + data: comments = [], + setData: setComments, + loadMore, + loading: loadingComments, + } = useDataFromRef({ ref: commentsRef, simpleRef: false, - listener: true, + listener: false, condition: !!commentsRef, refreshArray: [projectId], + usePagination: true, + batchSize: 20, }); const onSend = async () => { @@ -100,7 +107,7 @@ const CommentsBottomSheet = () => { if (!value || !projectId || !currentUID) return; try { setText(""); - await projectsRef + const docRef = await projectsRef .doc(projectId) .collection("comments") .add({ @@ -110,6 +117,19 @@ const CommentsBottomSheet = () => { text: value, createdAt: serverTimestamp(), }); + // Optimistic: ajouter immédiatement le commentaire en tête de liste + const optimistic = { + id: docRef?.id || Math.random().toString(36).slice(2), + userId: currentUID, + userName: currentUserData?.userName || "", + profilePicture: currentUserData?.profilePictureURL || "", + text: value, + createdAt: new Date(), + }; + setComments((prev = []) => [ + optimistic, + ...prev.filter((x) => x?.id !== optimistic.id), + ]); } catch { // ignore } @@ -127,6 +147,23 @@ const CommentsBottomSheet = () => { [typing] ); + const handleScroll = useCallback( + ({ nativeEvent }) => { + try { + const { layoutMeasurement, contentOffset, contentSize } = + nativeEvent || {}; + const paddingToBottom = 80; + if ( + layoutMeasurement?.height + contentOffset?.y >= + (contentSize?.height || 0) - paddingToBottom + ) { + loadMore?.(); + } + } catch {} + }, + [loadMore] + ); + return ( { > { { + const { + title = "Partager", + message = "Choisis une application pour partager", + text = "Découvre ce playback sur MusicLand", + url = "", + } = payload || {}; + + const onClose = () => { + SheetManager.hide("Share"); + }; + + const shareText = useMemo(() => { + return [text, url].filter(Boolean).join(" "); + }, [text, url]); + + const openScheme = async () => { + try { + const supported = await Linking.canOpenURL(url); + if (supported) { + await Linking.openURL(url); + } else { + // fallback vers partage natif + shareLink({ url, title: "Partager", message: shareText }); + } + } catch (e) { + shareLink({ url, title: "Partager", message: shareText }); + } finally { + onClose(); + } + }; + + return ( + + + + + {title} + + + {message} + + + + + { + openScheme(); + }} + style={{ alignItems: "center", gap: 8, flex: 1 }} + > + + + partager + + + + partager + + + + + + ); +}; + +export default ShareModal; diff --git a/src/helpers/index.js b/src/helpers/index.js index c14bcea..cf1197f 100644 --- a/src/helpers/index.js +++ b/src/helpers/index.js @@ -1,12 +1,9 @@ -import numbro from "numbro"; -import { Clipboard } from "react-native-web"; import moment from "moment"; +import numbro from "numbro"; -import alert from "../components/Alert.js"; - +import { Linking } from "react-native"; import { isTauri, isWeb } from "../hooks/useLayoutType"; import Palette from "../styles/Palette.js"; -import { Linking, Share } from "react-native"; export const capitalize = (string) => { return string.charAt(0).toUpperCase() + string.slice(1); @@ -196,26 +193,3 @@ export const openLinkInBrowser = ({ url }) => { console.error(error); } }; - -export const shareLink = ({ url, title = "", message = "" }) => { - try { - if (isWeb) { - if (!Clipboard.isAvailable) { - throw new Error("Clipboard not available"); - } - - Clipboard.setString(url); - - alert("Lien copié", "Le lien a été copié dans votre presse-papiers."); - } else { - Share.share({ - message, - url, - title, - }); - } - } catch (error) { - console.log(error); - alert("Partage non disponible", "Il y a eu une erreur lors du partage."); - } -}; diff --git a/src/screens/Playbacks.js b/src/screens/Playbacks.js index 73578f5..bbc1f97 100644 --- a/src/screens/Playbacks.js +++ b/src/screens/Playbacks.js @@ -9,7 +9,7 @@ import React, { useRef, useState, } from "react"; -import { Image, Platform, Pressable, Text, View } from "react-native"; +import { Image, Platform, Pressable, Share, Text, View } from "react-native"; import Carousel from "react-native-reanimated-carousel"; import { responsiveHeight } from "react-native-responsive-dimensions"; import { icons, img } from "../assets"; @@ -105,7 +105,6 @@ const PlaybackItem = ({ item, isActive, userCache, getUserByUid }) => { setLikesCount(lb.length); setIsLiked(currentUID ? lb.includes(currentUID) : false); }, [item?.likedBy, currentUID]); - console.log("has external audio : ", hasExternalAudio); const audioPlayer = useAudioPlayer(audioSource || undefined); const videoPlayer = useVideoPlayer(videoUrl || null, (p) => { @@ -193,6 +192,7 @@ const PlaybackItem = ({ item, isActive, userCache, getUserByUid }) => { return () => clearInterval(id); }, [isActive, hasExternalAudio, audioPlayer, videoPlayer]); + // partage: géré via l'API native Share directement dans l'UI return ( { > - + { + try { + const url = item?.playbackUrl || ""; + const title = item?.title || "Partager"; + const base = item?.title + ? `Découvre « ${item.title} » sur MusicLand` + : `Découvre ce playback sur MusicLand`; + const message = url ? `${base}\n${url}` : base; + + await Share.share( + Platform.select({ + ios: url ? { url, message, title } : { message, title }, + default: { message, title }, + }) + ); + } catch (e) {} + }} + >