Change main page and modify flows

This commit is contained in:
Thomas Demirdjian
2025-09-02 11:45:27 +02:00
parent 8b7980308a
commit 98367af0b7
47 changed files with 3695 additions and 1020 deletions
+17 -7
View File
@@ -1,4 +1,5 @@
import { View, Text, FlatList, Image, Pressable } from "react-native";
import { View, Text, FlatList, Pressable, Image as RNImage } from "react-native";
import { Image as ExpoImage } from "expo-image";
import React, { useState } from "react";
import Page from "../../layouts/Page";
import { background, img } from "../../assets";
@@ -56,12 +57,21 @@ const AllMyMusic = () => {
navigate(Routes.MusicDetails, { projectId: item.id })
}
>
<Image
source={
item?.coverUrl ? { uri: item.coverUrl } : img.placeholder2
}
style={{ width: "100%", height: 114, borderRadius: 8 }}
/>
{item?.coverUrl ? (
<ExpoImage
source={{ uri: item.coverUrl }}
cachePolicy="memory-disk"
priority="high"
contentFit="cover"
transition={100}
style={{ width: "100%", height: 114, borderRadius: 8 }}
/>
) : (
<RNImage
source={img.placeholder2}
style={{ width: "100%", height: 114, borderRadius: 8 }}
/>
)}
<Text
style={{
fontSize: 12,
+1
View File
@@ -23,6 +23,7 @@ const Library = () => {
<SearchBar
textInputProps={{
editable: false,
onPress: () => navigate(Routes.Research),
}}
/>
</Pressable>
+32 -30
View File
@@ -1,14 +1,8 @@
import { useRoute } from "@react-navigation/core";
import { Audio } from "expo-av";
import { Audio } from "expo-audio";
import React, { useEffect, useMemo, useState } from "react";
import {
Image,
Pressable,
ScrollView,
StyleSheet,
Text,
View,
} from "react-native";
import { Pressable, ScrollView, StyleSheet, Text, View, Image as RNImage } from "react-native";
import { Image as ExpoImage } from "expo-image";
import { SheetManager } from "react-native-actions-sheet";
import { useGlobal } from "reactn";
import { background, icons, img } from "../../assets";
@@ -78,7 +72,7 @@ const MusicDetails = () => {
const soundRef = React.useRef(null);
// Load/unload audio with expo-av for reliable status updates on iOS/Android
// Load/unload audio with expo-audio for reliable status updates on iOS/Android
useEffect(() => {
let isMounted = true;
const load = async () => {
@@ -95,16 +89,16 @@ const MusicDetails = () => {
if (!songUrl) return;
const { sound } = await Audio.Sound.createAsync(
{ uri: songUrl },
{ shouldPlay: false },
(status) => {
if (!isMounted) return;
if (!status || !status.isLoaded) return;
const pos = status.positionMillis || 0;
const dur = status.durationMillis || 0;
setProgressInfo({ pos, dur });
setIsPlaying(!!status.isPlaying);
}
{ shouldPlay: false }
);
sound.setOnPlaybackStatusUpdate((status) => {
if (!isMounted) return;
if (!status || !status.isLoaded) return;
const pos = status.positionMillis || 0;
const dur = status.durationMillis || 0;
setProgressInfo({ pos, dur });
setIsPlaying(!!status.isPlaying);
});
soundRef.current = sound;
} catch (e) {
console.log("Audio load error", e?.message);
@@ -236,7 +230,7 @@ const MusicDetails = () => {
},
rightComponent: () => (
<Pressable onPress={() => SheetManager.show("DeleteAudio")}>
<Image source={icons.trash} />
<RNImage source={icons.trash} />
</Pressable>
),
})}
@@ -250,10 +244,18 @@ const MusicDetails = () => {
// stickyHeaderIndices={[1]}
>
<View style={{ gap: 28 }}>
<Image
source={coverUrl ? { uri: coverUrl } : img.placeholder4}
style={styles.img}
/>
{coverUrl ? (
<ExpoImage
source={{ uri: coverUrl }}
cachePolicy="memory-disk"
priority="high"
contentFit="cover"
transition={150}
style={styles.img}
/>
) : (
<RNImage source={img.placeholder4} style={styles.img} />
)}
<View style={{ ...Style.containerSpaceBetween }}>
<View>
<Text style={styles.title}>{title}</Text>
@@ -276,7 +278,7 @@ const MusicDetails = () => {
}
}}
>
<Image
<RNImage
source={fav ? icons.heart : icons.heartOutline}
style={{ ...size({ size: 24 }) }}
resizeMode="contain"
@@ -287,7 +289,7 @@ const MusicDetails = () => {
SheetManager.show("Playlist", { payload: { projectId } })
}
>
<Image
<RNImage
source={icons.more}
style={{ ...size({ size: 24 }) }}
resizeMode="contain"
@@ -334,8 +336,8 @@ const MusicDetails = () => {
/>
<View style={{ ...Style.containerRow, gap: 24, alignSelf: "center" }}>
{/* Previous (rewind 10s) */}
<Pressable onPress={() => seekBy(-10)}>
<Image
<Pressable onPress={() => seekBy(-10)}>
<RNImage
source={icons.forward}
style={{
...size({ size: 30 }),
@@ -351,7 +353,7 @@ const MusicDetails = () => {
}}
onPress={togglePlay}
>
<Image
<RNImage
resizeMode={"contain"}
source={isPlaying ? icons.pause : icons.play}
style={size({ size: 34 })}
@@ -359,7 +361,7 @@ const MusicDetails = () => {
</Pressable>
{/* Next (forward 10s) */}
<Pressable onPress={() => seekBy(10)}>
<Image
<RNImage
source={icons.forward}
style={{
...size({ size: 30 }),
+37 -3
View File
@@ -1,7 +1,8 @@
import React, { useState } from "react";
import { View } from "react-native";
import { View, Pressable, Image, Alert } from "react-native";
import { useGlobal } from "reactn";
import Page from "../../layouts/Page";
import { background } from "../../assets";
import { background, icons } from "../../assets";
import { gutters } from "../../styles";
import { useRoute } from "@react-navigation/native";
import { useDataFromRef } from "react-native-minuit/src/hooks";
@@ -9,10 +10,11 @@ import useDataFromArrayId from "react-native-minuit/src/hooks/useDataFromArrayId
import { playlistsRef, projectsRef } from "../../config/firebase";
import MusicCard from "./components/MusicCard";
import MoreMenu from "../../components/MoreMenu";
import { navigate } from "../../navigation/NavigationService";
import { navigate, goBack } from "../../navigation/NavigationService";
import { Routes } from "../../navigation";
const PlaylistDetails = () => {
const [, setTooltip] = useGlobal("_tooltip");
const route = useRoute();
const playlistId = route?.params?.playlistId;
@@ -37,11 +39,43 @@ const PlaylistDetails = () => {
const [showMenu, setShowMenu] = useState(false);
const [selectedProjectId, setSelectedProjectId] = useState(null);
const confirmDelete = () => {
Alert.alert(
"Supprimer la playlist",
"Es-tu sûr de vouloir supprimer cette playlist ?",
[
{ text: "Annuler", style: "cancel" },
{
text: "Supprimer",
style: "destructive",
onPress: async () => {
try {
if (playlistId) {
await playlistsRef.doc(playlistId).delete();
setTooltip({ type: "success", text: "Playlist supprimée" });
}
} catch (e) {
console.log("Delete playlist error", e?.message);
setTooltip({ type: "error", text: e?.message || "Suppression impossible" });
} finally {
goBack();
}
},
},
],
);
};
return (
<Page
headerType="NAVIGATION"
backgroundImg={background.libraryBG}
title={playlist?.name || "Playlist"}
rightComponent={() => (
<Pressable onPress={confirmDelete}>
<Image source={icons.trash} style={{ width: 24, height: 24 }} />
</Pressable>
)}
contentContainerStyle={{ paddingBottom: gutters * 2 }}
>
<View style={{ flex: 1, gap: 10 }}>
+259 -148
View File
@@ -1,5 +1,6 @@
import React, { useEffect, useMemo, useState } from "react";
import { Image, Pressable, ScrollView, Text, View } from "react-native";
import { Image as ExpoImage } from "expo-image";
import { background, img } from "../../assets";
import MoreMenu from "../../components/MoreMenu";
import { usersRef, projectsRef } from "../../config/firebase";
@@ -19,32 +20,53 @@ const Research = () => {
const [selected, setSelected] = useState(null);
const [search, setSearch] = useState("");
const queryText = useMemo(() => search.trim(), [search]);
const queryLower = useMemo(
() => (search || "").toLowerCase().trim(),
[search],
);
const [currentUID] = useGlobal("currentUID");
const [autoLoads, setAutoLoads] = useState(0);
const usersQueryRef = useMemo(() => {
try {
if (queryText) {
const lower = queryLower;
if (lower) {
return usersRef
.orderBy("userName")
.startAt(queryText)
.endAt(queryText + "\uf8ff");
.orderBy("userNameLower")
.startAt(lower)
.endAt(lower + "\uf8ff");
}
return usersRef.orderBy("userName");
return usersRef.orderBy("userNameLower");
} catch (e) {
return null;
}
}, [queryLower]);
const projectsQueryRefLower = useMemo(() => {
try {
const lower = queryText ? queryText.toLowerCase() : "";
if (lower) {
return projectsRef
.orderBy("titleLower")
.startAt(lower)
.endAt(lower + "\uf8ff");
}
return null;
} catch (e) {
return null;
}
}, [queryText]);
const projectsQueryRef = useMemo(() => {
const projectsQueryRefCase = useMemo(() => {
try {
if (queryText) {
const raw = queryText || "";
if (raw) {
return projectsRef
.orderBy("title")
.startAt(queryText)
.endAt(queryText + "\uf8ff");
.startAt(raw)
.endAt(raw + "\uf8ff");
}
return projectsRef.orderBy("updatedAt", "desc");
return null;
} catch (e) {
return null;
}
@@ -59,12 +81,19 @@ const Research = () => {
simpleRef: false,
listener: false,
condition: !!usersQueryRef,
refreshArray: [queryText],
refreshArray: [queryLower],
usePagination: true,
batchSize: 5,
});
const filteredUsers = useMemo(() => {
const arr = Array.isArray(userResults) ? userResults : [];
let arr = Array.isArray(userResults) ? userResults : [];
// Client-side safety filter to guarantee match on pseudo
if (queryLower) {
arr = arr.filter((u) => {
const nameLower = (u?.userNameLower || u?.userName || "").toLowerCase();
return nameLower.includes(queryLower);
});
}
const seen = new Set();
const unique = [];
for (const u of arr) {
@@ -75,24 +104,83 @@ const Research = () => {
unique.push(u);
}
return unique;
}, [JSON.stringify(userResults), currentUID]);
}, [JSON.stringify(userResults), queryLower, currentUID]);
const {
data: projectResults = [],
loading: projectsLoading,
loadMore: loadMoreProjects,
data: projectResultsLower = [],
loading: projectsLoadingLower,
loadMore: loadMoreProjectsLower,
} = useDataFromRef({
ref: projectsQueryRef,
ref: projectsQueryRefLower,
simpleRef: false,
listener: false,
condition: !!projectsQueryRef,
condition: !!projectsQueryRefLower,
refreshArray: [queryText],
usePagination: true,
batchSize: 6,
});
const {
data: projectResultsCase = [],
loading: projectsLoadingCase,
loadMore: loadMoreProjectsCase,
} = useDataFromRef({
ref: projectsQueryRefCase,
simpleRef: false,
listener: false,
condition: !!projectsQueryRefCase,
refreshArray: [queryText],
usePagination: true,
batchSize: 6,
});
const {
data: projectResultsDefault = [],
loading: projectsLoadingDefault,
loadMore: loadMoreProjectsDefault,
} = useDataFromRef({
ref: !queryText ? projectsRef.orderBy("updatedAt", "desc") : null,
simpleRef: false,
listener: false,
condition: !queryText,
refreshArray: [queryText],
usePagination: true,
batchSize: 6,
});
const projectsLoading = queryText
? projectsLoadingLower || projectsLoadingCase
: projectsLoadingDefault;
const loadMoreProjects = () => {
if (queryText) {
loadMoreProjectsLower?.();
loadMoreProjectsCase?.();
} else {
loadMoreProjectsDefault?.();
}
};
const filteredProjects = useMemo(() => {
return Array.isArray(projectResults) ? projectResults : [];
}, [JSON.stringify(projectResults)]);
const arr = queryText
? [
...(Array.isArray(projectResultsLower) ? projectResultsLower : []),
...(Array.isArray(projectResultsCase) ? projectResultsCase : []),
]
: Array.isArray(projectResultsDefault)
? projectResultsDefault
: [];
const seen = new Set();
const unique = [];
for (const p of arr) {
const id = p?.id;
if (!id || seen.has(id)) continue;
seen.add(id);
unique.push(p);
}
return unique;
}, [
queryText,
JSON.stringify(projectResultsLower),
JSON.stringify(projectResultsCase),
JSON.stringify(projectResultsDefault),
]);
useEffect(() => {
setAutoLoads(0);
@@ -105,13 +193,7 @@ const Research = () => {
loadMoreUsers();
}
}
}, [
filteredUsers.length,
usersLoading,
usersQueryRef,
autoLoads,
loadMoreUsers,
]);
}, [filteredUsers.length, usersLoading, usersQueryRef, autoLoads]);
const [menuTop, setMenuTop] = useState(0);
const [showMenu, setShowMenu] = useState(false);
const [selectedProjectId, setSelectedProjectId] = useState(null);
@@ -124,6 +206,21 @@ const Research = () => {
}
};
const EmptyText = ({ text }) => (
<View style={{ flex: 1, alignItems: "center", paddingVertical: 16 }}>
<Text
style={{
fontSize: 14,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
opacity: 0.8,
}}
>
{text}
</Text>
</View>
);
return (
<Page
headerType="NAVIGATION"
@@ -142,7 +239,15 @@ const Research = () => {
/>
<View style={{ flex: 1 }}>
<ScrollView contentContainerStyle={{ paddingTop: 2 }}>
{(!selected || selected === "Musiques") && (
{(!selected &&
!projectsLoading &&
!usersLoading &&
filteredProjects.length === 0 &&
filteredUsers.length === 0) && (
<EmptyText text={"Aucun résultat"} />
)}
{((!selected && (filteredProjects.length > 0 || projectsLoading)) ||
selected === "Musiques") && (
<View style={{ paddingHorizontal: 2 }}>
<CreateLyricsHeader
gradientProps={{
@@ -150,138 +255,144 @@ const Research = () => {
end: { x: 0, y: 1 },
}}
>
<View style={{ gap: 10 }}>
{Array.isArray(filteredProjects) &&
filteredProjects.slice(0, 6).map((p) => (
<MusicCard
key={p.id}
title={p?.title || "Sans titre"}
subtitle={"MusicLand"}
imageUri={p?.coverUrl || null}
projectId={p?.id}
likedBy={p?.likedBy || []}
onPress={() =>
navigate(Routes.MusicDetails, { projectId: p.id })
}
onPressMore={(posTop) => {
setSelectedProjectId(p.id);
setMenuTop(posTop);
setShowMenu((prev) => !prev || posTop !== menuTop);
}}
/>
))}
{(filteredProjects.length >= 6 || projectsLoading) && (
<Pressable
onPress={loadMoreProjects}
style={{ alignSelf: "center", marginTop: 6 }}
>
<Text
style={{
fontSize: 12,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
opacity: projectsLoading ? 0.6 : 1,
}}
>
{projectsLoading ? "Chargement…" : "Charger plus"}
</Text>
</Pressable>
)}
</View>
</CreateLyricsHeader>
</View>
)}
{(!selected || selected === "Clips") && (
<View style={{ paddingHorizontal: 2, paddingTop: 10 }}>
<CreateLyricsHeader
gradientProps={{
start: { x: 0, y: 0 },
end: { x: 0, y: 1 },
}}
>
<View style={{ gap: 6, ...Style.containerRow }}>
{Array.from({ length: 3 }).map((_, index) => (
<View style={{ flex: 1, gap: 6 }} key={index}>
<Image
source={img.placeholder3}
style={{
width: "100%",
height: 147,
borderRadius: 10,
}}
/>
<Text
style={{
fontSize: 12,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
}}
>
Pour Lili
</Text>
</View>
))}
</View>
</CreateLyricsHeader>
</View>
)}
{(!selected || selected === "Profils") && (
<View style={{ paddingHorizontal: 2, paddingTop: 10 }}>
<CreateLyricsHeader
gradientProps={{ start: { x: 0, y: 0 }, end: { x: 0, y: 1 } }}
>
<View style={{ gap: 8 }}>
{Array.isArray(filteredUsers) &&
filteredUsers.slice(0, 5).map((u) => (
<Pressable
style={{ gap: 14, ...Style.containerRow }}
key={u.id}
onPress={() =>
navigate(Routes.SingerProfile, { userId: u.id })
}
>
<Image
source={
u?.pictureUrl || u?.profilePictureURL || u?.photoURL
? {
uri:
u?.pictureUrl ||
u?.profilePictureURL ||
u?.photoURL,
}
: img.profile
{filteredProjects.length > 0 ? (
<View style={{ gap: 10 }}>
{Array.isArray(filteredProjects) &&
filteredProjects.slice(0, 6).map((p) => (
<MusicCard
key={p.id}
title={p?.title || "Sans titre"}
subtitle={"MusicLand"}
imageUri={p?.coverUrl || null}
projectId={p?.id}
likedBy={p?.likedBy || []}
onPress={() =>
navigate(Routes.MusicDetails, { projectId: p.id })
}
style={{ ...size({ size: 60 }), borderRadius: 100 }}
onPressMore={(posTop) => {
setSelectedProjectId(p.id);
setMenuTop(posTop);
setShowMenu(
(prev) => !prev || posTop !== menuTop,
);
}}
/>
))}
{(filteredProjects.length >= 6 || projectsLoading) && (
<Pressable
onPress={loadMoreProjects}
style={{ alignSelf: "center", marginTop: 6 }}
>
<Text
style={{
fontSize: 12,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
opacity: projectsLoading ? 0.6 : 1,
}}
>
{u?.userName || "Utilisateur"}
{projectsLoading ? "Chargement…" : "Charger plus"}
</Text>
</Pressable>
))}
{(filteredUsers.length >= 5 || usersLoading) && (
<Pressable
onPress={loadMoreUsers}
style={{ alignSelf: "center", marginTop: 6 }}
>
<Text
style={{
fontSize: 12,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
opacity: usersLoading ? 0.6 : 1,
}}
)}
</View>
) : (
!projectsLoading && (
<EmptyText text={"Aucune musique trouvée"} />
)
)}
</CreateLyricsHeader>
</View>
)}
{((!selected && (filteredUsers.length > 0 || usersLoading)) ||
selected === "Profils") && (
<View style={{ paddingHorizontal: 2, paddingTop: 10 }}>
<CreateLyricsHeader
gradientProps={{ start: { x: 0, y: 0 }, end: { x: 0, y: 1 } }}
>
{filteredUsers.length > 0 ? (
<View style={{ gap: 8 }}>
{Array.isArray(filteredUsers) &&
filteredUsers.slice(0, 5).map((u) => (
<Pressable
style={{ gap: 14, ...Style.containerRow }}
key={u.id}
onPress={() =>
navigate(Routes.SingerProfile, { userId: u.id })
}
>
<ExpoImage
source={
u?.pictureUrl ||
u?.profilePictureURL ||
u?.photoURL
? {
uri:
u?.pictureUrl ||
u?.profilePictureURL ||
u?.photoURL,
}
: img.profile
}
cachePolicy="memory-disk"
priority="high"
contentFit="cover"
transition={100}
style={{
...size({ size: 60 }),
borderRadius: 100,
}}
/>
<Text
style={{
fontSize: 12,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
}}
>
{u?.userName || "Utilisateur"}
</Text>
</Pressable>
))}
{(filteredUsers.length >= 5 || usersLoading) && (
<Pressable
onPress={loadMoreUsers}
style={{ alignSelf: "center", marginTop: 6 }}
>
{usersLoading ? "Chargement…" : "Charger plus"}
</Text>
</Pressable>
)}
</View>
<Text
style={{
fontSize: 12,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
opacity: usersLoading ? 0.6 : 1,
}}
>
{usersLoading ? "Chargement…" : "Charger plus"}
</Text>
</Pressable>
)}
</View>
) : (
!usersLoading && <EmptyText text={"Aucun profil trouvé"} />
)}
</CreateLyricsHeader>
</View>
)}
{selected === "Playbacks" && (
<View style={{ paddingHorizontal: 2, paddingTop: 10 }}>
<CreateLyricsHeader
gradientProps={{ start: { x: 0, y: 0 }, end: { x: 0, y: 1 } }}
>
<EmptyText text={"Aucun playback trouvé"} />
</CreateLyricsHeader>
</View>
)}
{selected === "Clips" && (
<View style={{ paddingHorizontal: 2, paddingTop: 10 }}>
<CreateLyricsHeader
gradientProps={{ start: { x: 0, y: 0 }, end: { x: 0, y: 1 } }}
>
<EmptyText text={"Aucun clip trouvé"} />
</CreateLyricsHeader>
</View>
)}
+23 -10
View File
@@ -1,5 +1,6 @@
import React from "react";
import { FlatList, Image, Pressable, useWindowDimensions } from "react-native";
import { FlatList, Pressable, useWindowDimensions, Image as RNImage } from "react-native";
import { Image as ExpoImage } from "expo-image";
import { img } from "../../../assets";
import { Routes } from "../../../navigation";
import { navigate } from "../../../navigation/NavigationService";
@@ -36,15 +37,27 @@ const LikedMusic = () => {
navigate(Routes.MusicDetails, { projectId: item.id })
}
>
<Image
source={
item?.coverUrl ? { uri: item.coverUrl } : img.placeholder3
}
style={{
height: itemWidth - containerGap,
borderRadius: 10,
}}
/>
{item?.coverUrl ? (
<ExpoImage
source={{ uri: item.coverUrl }}
cachePolicy="memory-disk"
priority="high"
contentFit="cover"
transition={100}
style={{
height: itemWidth - containerGap,
borderRadius: 10,
}}
/>
) : (
<RNImage
source={img.placeholder3}
style={{
height: itemWidth - containerGap,
borderRadius: 10,
}}
/>
)}
</Pressable>
)}
/>
+35 -15
View File
@@ -1,13 +1,7 @@
import { BlurView } from "expo-blur";
import React, { useEffect, useState } from "react";
import {
Image,
Platform,
Pressable,
StyleSheet,
Text,
View,
} from "react-native";
import React, { useEffect, useRef, useState } from "react";
import { Platform, 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";
@@ -28,6 +22,7 @@ const MusicCard = ({
const [selected, setSelected] = useState(false);
const [layout, setLayout] = useState(null);
const [menuPos, setMenuPos] = useState(0);
const cardRef = useRef(null);
useEffect(() => {
if (layout) {
@@ -57,6 +52,19 @@ const MusicCard = ({
};
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);
};
@@ -67,13 +75,25 @@ const MusicCard = ({
...Style.containerRow,
gap: 6,
}}
ref={cardRef}
onPress={onPress}
onLayout={(e) => setLayout(e.nativeEvent.layout)}
>
<Image
source={imageUri ? { uri: imageUri } : img.placeholder2}
style={{ ...size({ size: 60 }), borderRadius: 12 }}
/>
{imageUri ? (
<ExpoImage
source={{ uri: imageUri }}
cachePolicy="memory-disk"
priority="high"
contentFit="cover"
transition={100}
style={{ ...size({ size: 60 }), borderRadius: 12 }}
/>
) : (
<RNImage
source={img.placeholder2}
style={{ ...size({ size: 60 }), borderRadius: 12 }}
/>
)}
<View style={styles.blurContainer}>
<BlurView
intensity={20}
@@ -97,14 +117,14 @@ const MusicCard = ({
}}
>
<Pressable onPress={toggleLike}>
<Image
<RNImage
source={selected ? icons.heart : icons.heartOutline}
style={size({ size: 24 })}
resizeMode="contain"
/>
</Pressable>
<Pressable onPress={onPressMenu}>
<Image source={icons.more} style={size({ size: 24 })} />
<RNImage source={icons.more} style={size({ size: 24 })} />
</Pressable>
</View>
</BlurView>
@@ -6,13 +6,19 @@ import BorderGradient from "../../../components/BorderGradient/BorderGradient";
import { BlurView } from "expo-blur";
import { FONT_FAMILY } from "../../../styles/Fonts";
const ResearchHeader = ({ onPress, selected, searchValue = "", onChangeSearch = () => {} }) => {
const ResearchHeader = ({
onPress,
selected,
searchValue = "",
onChangeSearch = () => {},
}) => {
return (
<View style={{ gap: 12 }}>
<SearchBar
textInputProps={{
value: searchValue,
onChangeText: onChangeSearch,
autoFocus: true,
}}
/>
<View