diff --git a/src/screens/Playbacks.js b/src/screens/Playbacks.js
index 7bb90a5..7c6629c 100644
--- a/src/screens/Playbacks.js
+++ b/src/screens/Playbacks.js
@@ -1,7 +1,7 @@
import { useAudioPlayer } from "expo-audio";
import { BlurView } from "expo-blur";
import { VideoView, useVideoPlayer } from "expo-video";
-import React, { useCallback, useEffect, useMemo, useState } from "react";
+import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Image, Platform, Pressable, Text, View } from "react-native";
import Carousel from "react-native-reanimated-carousel";
import { responsiveHeight } from "react-native-responsive-dimensions";
@@ -13,8 +13,8 @@ import { Palette } from "../styles";
import { FONT_FAMILY } from "../styles/Fonts";
import { size } from "../styles/Style";
-const PlaybackItem = ({ item, isActive }) => {
- const { currentUID } = useUser() || {};
+const PlaybackItem = ({ item, isActive, userCache, getUserByUid }) => {
+ const { currentUID, followUser, unfollowUser } = useUser() || {};
const videoUrl = item?.playbackUrl || null;
const audioSource = useMemo(() => {
const fromSong = item?.songUrl ? { uri: item.songUrl } : null;
@@ -29,6 +29,43 @@ const PlaybackItem = ({ item, isActive }) => {
);
const [likesCount, setLikesCount] = useState(initialLikedBy.length);
+ // Fetch owner profile (cached)
+ const [owner, setOwner] = useState(
+ item?.userId && userCache?.current?.get(item.userId)
+ ? userCache.current.get(item.userId)
+ : null,
+ );
+ useEffect(() => {
+ let cancelled = false;
+ const run = async () => {
+ try {
+ const uid = item?.userId;
+ if (!uid || !userCache) return;
+ const cached = userCache.current.get(uid);
+ if (cached) {
+ if (!cancelled) setOwner(cached);
+ return;
+ }
+ const user = await getUserByUid?.(uid);
+ if (!cancelled && user) {
+ userCache.current.set(uid, user);
+ setOwner(user);
+ }
+ } catch (e) {}
+ };
+ run();
+ return () => {
+ cancelled = true;
+ };
+ }, [item?.userId, userCache, getUserByUid]);
+
+ // Follow state derived from owner.followedBy
+ const [isFollowing, setIsFollowing] = useState(false);
+ useEffect(() => {
+ const list = Array.isArray(owner?.followedBy) ? owner.followedBy : [];
+ setIsFollowing(currentUID ? list.includes(currentUID) : false);
+ }, [owner?.followedBy, currentUID]);
+
useEffect(() => {
const lb = Array.isArray(item?.likedBy) ? item.likedBy : [];
setLikesCount(lb.length);
@@ -135,41 +172,76 @@ const PlaybackItem = ({ item, isActive }) => {
>
-
-
-
-
-
- Suivre
-
-
+ />
+ ) : (
+
+ )}
+ {owner?.id && currentUID && owner.id !== currentUID && (
+ {
+ try {
+ const next = !isFollowing;
+ setIsFollowing(next);
+ // Optimistic update of local owner.followedBy
+ setOwner((prev) => {
+ const fb = Array.isArray(prev?.followedBy)
+ ? prev.followedBy
+ : [];
+ const newFb = next
+ ? Array.from(new Set([...fb, currentUID]))
+ : fb.filter((x) => x !== currentUID);
+ return prev ? { ...prev, followedBy: newFb } : prev;
+ });
+ if (next) await followUser?.(owner.id);
+ else await unfollowUser?.(owner.id);
+ } catch (e) {
+ // rollback on failure
+ setIsFollowing((v) => !v);
+ }
+ }}
+ >
+
+
+ {isFollowing ? "Suivi" : "Suivre"}
+
+
+
+ )}
{
@@ -253,6 +325,8 @@ const PlaybackItem = ({ item, isActive }) => {
const Playbacks = () => {
const [activeIndex, setActiveIndex] = useState(0);
+ const userCache = useRef(new Map());
+ const { getUserByUid } = useUser() || {};
const { data: playbacks = [], loadMore } = useDataFromRef({
ref: projectsRef.where("playbackUrl", "!=", null),
simpleRef: false,
@@ -285,6 +359,8 @@ const Playbacks = () => {
)}