184 lines
4.7 KiB
JavaScript
184 lines
4.7 KiB
JavaScript
import { BlurView } from "expo-blur";
|
|
import React, { useEffect, useRef, useState } from "react";
|
|
import {
|
|
Pressable,
|
|
StyleSheet,
|
|
Text,
|
|
View,
|
|
Image as RNImage,
|
|
} from "react-native";
|
|
import { Image as ExpoImage } from "expo-image";
|
|
import { useGlobal } from "reactn";
|
|
import { icons, img } from "../../../assets";
|
|
import { arrayRemove, arrayUnion, projectsRef } from "../../../config/firebase";
|
|
import { Palette, Style } from "../../../styles";
|
|
import { FONT_FAMILY } from "../../../styles/Fonts";
|
|
import { size } from "../../../styles/Style";
|
|
import { responsiveWidth } from "react-native-responsive-dimensions";
|
|
|
|
const MusicCard = ({
|
|
onPress,
|
|
onPressMore,
|
|
title = "Sans titre",
|
|
subtitle = "MusicLand",
|
|
imageUri = null,
|
|
projectId = null,
|
|
likedBy = [],
|
|
}) => {
|
|
const [currentUID] = useGlobal("currentUID");
|
|
const [selected, setSelected] = useState(false);
|
|
const [layout, setLayout] = useState(null);
|
|
const [menuPos, setMenuPos] = useState(0);
|
|
const cardRef = useRef(null);
|
|
|
|
useEffect(() => {
|
|
if (layout) {
|
|
const top = layout?.y + 45;
|
|
setMenuPos(top);
|
|
}
|
|
}, [layout]);
|
|
|
|
useEffect(() => {
|
|
if (Array.isArray(likedBy) && currentUID) {
|
|
setSelected(likedBy.includes(currentUID));
|
|
}
|
|
}, [JSON.stringify(likedBy), currentUID]);
|
|
|
|
const toggleLike = async () => {
|
|
if (!projectId || !currentUID) return;
|
|
const next = !selected;
|
|
setSelected(next);
|
|
try {
|
|
await projectsRef.doc(projectId).update({
|
|
likedBy: next ? arrayUnion(currentUID) : arrayRemove(currentUID),
|
|
});
|
|
} catch (e) {
|
|
// rollback on failure
|
|
setSelected(!next);
|
|
}
|
|
};
|
|
|
|
const onPressMenu = () => {
|
|
// Prefer absolute screen position when available (Portal rendering)
|
|
if (cardRef?.current?.measureInWindow) {
|
|
try {
|
|
cardRef.current.measureInWindow((x, y, width, height) => {
|
|
const top = (y || 0) + 45;
|
|
setMenuPos(top);
|
|
onPressMore?.(top);
|
|
});
|
|
return;
|
|
} catch (e) {
|
|
// fallback to relative layout position
|
|
}
|
|
}
|
|
onPressMore?.(menuPos);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Pressable
|
|
style={{
|
|
...Style.containerRow,
|
|
gap: 6,
|
|
}}
|
|
ref={cardRef}
|
|
onPress={onPress}
|
|
onLayout={(e) => setLayout(e.nativeEvent.layout)}
|
|
>
|
|
{imageUri ? (
|
|
<ExpoImage
|
|
source={{ uri: imageUri }}
|
|
cachePolicy="memory-disk"
|
|
priority="high"
|
|
contentFit="cover"
|
|
transition={100}
|
|
style={{ ...size({ size: 60 }), borderRadius: 12 }}
|
|
/>
|
|
) : (
|
|
<RNImage
|
|
source={img.placeholder}
|
|
style={{ ...size({ size: 60 }), borderRadius: 12 }}
|
|
/>
|
|
)}
|
|
<View style={styles.blurContainer}>
|
|
<BlurView
|
|
intensity={20}
|
|
style={{
|
|
flex: 1,
|
|
...Style.containerSpaceBetween,
|
|
paddingHorizontal: 8,
|
|
}}
|
|
// experimentalBlurMethod={
|
|
// Platform.OS !== "ios" ? "dimezisBlurView" : "none"
|
|
// }
|
|
>
|
|
<View>
|
|
<Text numberOfLines={2} style={styles.title}>
|
|
{title || "Sans titre"}
|
|
</Text>
|
|
<Text style={styles.subTitle}>{subtitle || "MusicLand"}</Text>
|
|
</View>
|
|
<View
|
|
style={{
|
|
...Style.containerRow,
|
|
gap: 12,
|
|
}}
|
|
>
|
|
<Pressable onPress={toggleLike}>
|
|
<RNImage
|
|
source={selected ? icons.heart : icons.heartOutline}
|
|
style={size({ size: 24 })}
|
|
resizeMode="contain"
|
|
/>
|
|
</Pressable>
|
|
<Pressable onPress={onPressMenu}>
|
|
<RNImage source={icons.more} style={size({ size: 24 })} />
|
|
</Pressable>
|
|
</View>
|
|
</BlurView>
|
|
</View>
|
|
</Pressable>
|
|
{/* {open && (
|
|
<View
|
|
style={{
|
|
width: 100,
|
|
height: 50,
|
|
backgroundColor: "red",
|
|
position: "absolute",
|
|
right: 0,
|
|
top: menuPos,
|
|
zIndex: 2,
|
|
}}
|
|
/>
|
|
)} */}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default MusicCard;
|
|
|
|
const styles = StyleSheet.create({
|
|
blurContainer: {
|
|
borderRadius: 12,
|
|
overflow: "hidden",
|
|
flex: 1,
|
|
height: "100%",
|
|
},
|
|
title: {
|
|
fontSize: 16,
|
|
color: Palette.white,
|
|
fontFamily: FONT_FAMILY.OwnersRegular,
|
|
lineHeight: 18,
|
|
width: responsiveWidth(45),
|
|
},
|
|
subTitle: {
|
|
fontSize: 12,
|
|
color: Palette.white,
|
|
fontFamily: FONT_FAMILY.InterRegular,
|
|
},
|
|
filterContainer: {
|
|
backgroundColor: Palette.tran,
|
|
},
|
|
});
|