follow from playback

This commit is contained in:
2025-09-02 16:09:51 +02:00
parent 6383b84ad9
commit 9d1f7c7cda
+111 -35
View File
@@ -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 }) => {
>
<View style={{ gap: 6, alignItems: "center" }}>
<Pressable>
<Image
source={img.profile}
style={{
...size({ size: 45 }),
borderRadius: 100,
}}
/>
</Pressable>
<Pressable>
<BlurView
tint="dark"
intensity={20}
style={{
paddingVertical: 6,
paddingHorizontal: 12,
borderRadius: 12,
borderWidth: 1,
borderColor: Palette.white,
overflow: "hidden",
}}
experimentalBlurMethod={
Platform.OS !== "ios" ? "dimezisBlurView" : "none"
}
>
<Text
{owner?.profilePictureURL ? (
<Image
source={{ uri: owner.profilePictureURL }}
style={{
fontSize: 13,
color: Palette.white,
fontFamily: FONT_FAMILY.InterMedium,
...size({ size: 45 }),
borderRadius: 100,
}}
>
Suivre
</Text>
</BlurView>
/>
) : (
<Image
source={img.profile}
style={{
...size({ size: 45 }),
borderRadius: 100,
}}
/>
)}
</Pressable>
{owner?.id && currentUID && owner.id !== currentUID && (
<Pressable
onPress={async () => {
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);
}
}}
>
<BlurView
tint="dark"
intensity={20}
style={{
paddingVertical: 6,
paddingHorizontal: 12,
borderRadius: 12,
borderWidth: 1,
borderColor: Palette.white,
overflow: "hidden",
backgroundColor: isFollowing ? "#FFFFFF1A" : undefined,
}}
experimentalBlurMethod={
Platform.OS !== "ios" ? "dimezisBlurView" : "none"
}
>
<Text
style={{
fontSize: 13,
color: Palette.white,
fontFamily: FONT_FAMILY.InterMedium,
}}
>
{isFollowing ? "Suivi" : "Suivre"}
</Text>
</BlurView>
</Pressable>
)}
</View>
<Pressable
onPress={async () => {
@@ -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 = () => {
<PlaybackItem
key={item?.id || index}
item={item}
userCache={userCache}
getUserByUid={getUserByUid}
isActive={index === activeIndex}
/>
)}