diff --git a/frontend/src/Components/LikesTab.js b/frontend/src/Components/LikesTab.js
index 0728e45a..f3c1ee98 100644
--- a/frontend/src/Components/LikesTab.js
+++ b/frontend/src/Components/LikesTab.js
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react";
-import { View, Text, StyleSheet, ScrollView } from "react-native";
+import { View, Text, StyleSheet, ScrollView, RefreshControl } from "react-native";
import { useTheme } from "../styles/ThemeContext";
import { getUserLikedPosts, getLikesOfPost, getLikesOfReview } from "../Services/LikesApiService";
import { getCountCommentsOfPost, getCountCommentsOfReview, removePost, removeReview } from "../Services/PostsApiServices";
@@ -8,7 +8,7 @@ import Post from "./Post";
import Review from "./Review";
-export default function LikesTab({ userInfo, userProfile, handleCommentPress, refreshing }) {
+export default function LikesTab({ userInfo, userProfile, handleCommentPress, refreshing, onRefresh }) {
const [likedPosts, setLikedPosts] = useState([]);
const [loading, setLoading] = useState(false);
const { theme } = useTheme();
@@ -88,10 +88,11 @@ export default function LikesTab({ userInfo, userProfile, handleCommentPress, re
useEffect(() => {
fetchLikedPosts();
- }, []);
+ }, [refreshing]);
const handleRefresh = () => {
if (refreshing) {
+ console.log("refreshing");
fetchLikedPosts();
}
};
diff --git a/frontend/src/Components/PostsTab.js b/frontend/src/Components/PostsTab.js
index 5bda0efa..33f7f27a 100644
--- a/frontend/src/Components/PostsTab.js
+++ b/frontend/src/Components/PostsTab.js
@@ -102,7 +102,9 @@ export default function PostsTab({ userInfo, userProfile, handleCommentPress, re
useEffect(() => {
fetchPostsAndReviews();
- }, []);
+ }, [refreshing]);
+
+
if (refreshing) {
console.log("refreshing");
diff --git a/frontend/src/Components/Review.js b/frontend/src/Components/Review.js
index c4310f1e..f6ff86d2 100644
--- a/frontend/src/Components/Review.js
+++ b/frontend/src/Components/Review.js
@@ -220,7 +220,7 @@ export default function Review({
Review
-
+
@@ -232,7 +232,7 @@ export default function Review({
- {rating}
+ {rating}
@@ -244,7 +244,7 @@ export default function Review({
{likeCount}
@@ -254,7 +254,7 @@ export default function Review({
onPress={() => {
handleCommentPress(reviewId, true);
}}>
-
+
{comments}
diff --git a/frontend/src/Components/Watchlist.js b/frontend/src/Components/Watchlist.js
index 75f71ac5..2a671cb1 100644
--- a/frontend/src/Components/Watchlist.js
+++ b/frontend/src/Components/Watchlist.js
@@ -1,12 +1,12 @@
import React, { useState, useEffect } from "react";
-import { View, Text, ScrollView, TouchableOpacity, StyleSheet, Modal, Image, Alert } from "react-native";
+import { View, Text, ScrollView, TouchableOpacity, StyleSheet, Modal, Image, Alert, RefreshControl } from "react-native";
import { MaterialIcons } from "@expo/vector-icons";
import { useNavigation } from '@react-navigation/native';
import { getUserWatchlists } from "../Services/UsersApiService";
import { deleteWatchlist } from "../Services/ListApiService"; // Import the deleteWatchlist function
import { useTheme } from "../styles/ThemeContext";
-const WatchlistTab = ({ userInfo }) => {
+const WatchlistTab = ({ userInfo , refreshing, onRefresh}) => {
const [modalVisible, setModalVisible] = useState(false);
const [selectedWatchlist, setSelectedWatchlist] = useState(null);
@@ -14,7 +14,7 @@ const WatchlistTab = ({ userInfo }) => {
const navigation = useNavigation();
const {theme} = useTheme();
// Fetch user watchlists
- useEffect(() => {
+
const fetchUserWatchlists = async () => {
try {
const userId = userInfo.userId;
@@ -32,8 +32,18 @@ const WatchlistTab = ({ userInfo }) => {
}
};
+
+ useEffect(() => {
+ fetchUserWatchlists();
+ }, [refreshing]);
+
+
+
+ if (refreshing) {
+ console.log("refreshing");
fetchUserWatchlists();
- }, []);
+ }
+
const openOptionsMenu = (watchlist) => {
setSelectedWatchlist(watchlist);
diff --git a/frontend/src/Screens/ExplorePage.js b/frontend/src/Screens/ExplorePage.js
index 9433a6d3..b95bac77 100644
--- a/frontend/src/Screens/ExplorePage.js
+++ b/frontend/src/Screens/ExplorePage.js
@@ -1,5 +1,5 @@
import React, { useState, useEffect, useRef, useCallback } from 'react';
-import { StyleSheet, Text, View, ScrollView, FlatList, TextInput } from 'react-native';
+import { StyleSheet, Text, View, ScrollView, FlatList, TextInput , RefreshControl} from 'react-native';
import { useNavigation, useFocusEffect } from "@react-navigation/native";
import { Ionicons } from '@expo/vector-icons';
import { TouchableOpacity } from "react-native";
@@ -22,6 +22,7 @@ import Post from "../Components/Post"; // To render posts
import Review from "../Components/Review"; // To render reviews
import moment from "moment";
import { useTheme } from '../styles/ThemeContext';
+import { colors, themeStyles } from "../styles/theme";
import SearchBar from '../Components/SearchBar';
@@ -41,10 +42,10 @@ export default function ExplorePage({ route }) {
const [recentRooms, setRecentRooms] = useState([]);
const [searchResults, setSearchResults] = useState([]);
const [sortedContent, setSortedContent] = useState([]);
+ const [refreshing, setRefreshing] = useState(false);
const keywords = ["art", "city", "neon", "space", "movie", "night", "stars", "sky", "sunset", "sunrise"];
- useEffect(() => {
const fetchContent = async () => {
try {
const friendsContent = await getFriendsOfFriendsContent(userInfo);
@@ -86,9 +87,10 @@ export default function ExplorePage({ route }) {
console.error('Error fetching content:', error);
}
};
-
- fetchContent();
- }, [userInfo]);
+
+ useEffect(() => {
+ fetchContent();
+ }, [userInfo]);
useFocusEffect(
useCallback(() => {
@@ -133,14 +135,19 @@ export default function ExplorePage({ route }) {
console.error("Failed to fetch friends content:", error);
}
}, [userInfo]);
+
+ useEffect(() => {
+ if (userInfo) {
+ fetchFriendsContent();
+ }
+ }, [userInfo, fetchFriendsContent]);
+
+ const onRefresh = useCallback(async () => {
+ setRefreshing(true);
+ await Promise.all([fetchContent(), fetchFriendsContent()]);
+ setRefreshing(false);
+ }, []);
- useFocusEffect(
- useCallback(() => {
- if (userInfo) {
- fetchFriendsContent();
- }
- }, [userInfo, fetchFriendsContent])
- );
const handleOpenHub = () => {
navigation.navigate("HubScreen", { userInfo });
@@ -305,7 +312,10 @@ export default function ExplorePage({ route }) {
});
return (
-
+
+ }>
{searchResults.length > 0 ? (
diff --git a/frontend/src/Screens/Home.js b/frontend/src/Screens/Home.js
index 0e7e827b..8258b496 100644
--- a/frontend/src/Screens/Home.js
+++ b/frontend/src/Screens/Home.js
@@ -1,8 +1,9 @@
import React, { useState, useEffect, useRef, useCallback } from "react";
-import { StyleSheet, Text, View, StatusBar, Animated, Platform, Image, Dimensions, FlatList, Pressable, LogBox, SafeAreaView,ScrollView , TouchableOpacity,} from "react-native";
+import { StyleSheet, Text, View, StatusBar, Animated, Platform, Image, Dimensions, FlatList, Pressable, LogBox, SafeAreaView,ScrollView , TouchableOpacity, ActivityIndicator} from "react-native";
import { LinearGradient } from "expo-linear-gradient";
import { useTheme } from "../styles/ThemeContext";
import { colors, themeStyles } from "../styles/theme";
+import FastImage from 'react-native-fast-image';
import Svg from "react-native-svg";
import MovieCard from "../Components/MovieCard"
import TrendingMovie from "../Components/TrendingMovies"
@@ -15,9 +16,13 @@ import {getFollowedUsersWatchlists} from "../Services/ListApiService"
import BottomHeader from "../Components/BottomHeader";
import Genres from "../Components/Genres";
import Rating from "../Components/Rating";
+import Post from "../Components/Post";
+import Review from "../Components/Review";
import HomeHeader from "../Components/HomeHeader";
+import CommentsModal from "../Components/CommentsModal";
import moment from "moment";
-import { getPopularMovies, getMoviesByGenre, getMovieDetails, getNewMovies, getTopPicksForToday, fetchClassicMovies } from '../Services/TMDBApiService';
+import NonFollowerPost from "../Components/NonFollowerPost";
+import { getPopularMovies, getMoviesByGenre, getMovieDetails, getNewMovies, getTopPicksForToday, fetchClassicMovies, fetchCurrentlyPlayingMovies } from '../Services/TMDBApiService';
import { getUserProfile, getFollowingCount, getFollowersCount } from "../Services/UsersApiService";
import { getUserWatchlists } from "../Services/UsersApiService";
@@ -128,6 +133,7 @@ const Home = ({ route }) => {
const [isPost, setIsPost] = useState(false);
const [comments, setComments] = useState([]);
const [loadingComments, setLoadingComments] = useState(false);
+ const [loading, setLoading] = useState(true);
const [selectedPostId, setSelectedPostId] = useState(null); // Add this line
// const [friendsContent, setFriendsContent] = useState([]);
const [sortedContent, setSortedContent] = useState([]);
@@ -142,55 +148,36 @@ const Home = ({ route }) => {
const [watchlists, setWatchlists] = useState([]);
+
useEffect(() => {
- const fetchMoviesByGenres = async () => {
- try {
- const genreMoviesPromises = Object.entries(genres).map(async ([genreName, genreId]) => {
- const movies = await getNewMovies(genreId); // Using the imported function here
- return { genre: genreName, movies };
- });
-
- const fetchedMovies = await Promise.all(genreMoviesPromises);
-
- const moviesByGenreData = fetchedMovies.reduce((acc, curr) => {
- acc[curr.genre] = curr.movies;
- return acc;
- }, {});
-
- setMoviesByGenre(moviesByGenreData);
- } catch (error) {
- console.error('Error fetching movies by genres:', error);
- }
- };
-
- fetchMoviesByGenres();
- }, []);
-
- useEffect(() => {
const fetchOTHERMovies = async () => {
try {
- const fetchedMovies = await getPopularMovies();
+ // Create an array of promises for parallel fetching
+ const moviePromises = [
+ getPopularMovies(),
+ getMoviesByGenre(53), // Thriller
+ getMoviesByGenre(35), // Comedy
+ getMoviesByGenre(28), // Romance
+ ];
+
+ // Await all promises to resolve in parallel
+ const [fetchedMovies, fetchedThrillerMovies, fetchedComedyMovies, fetchedRomanceMovies] = await Promise.all(moviePromises);
+
+ // Update the respective states after fetching
setMovies1(fetchedMovies);
-
- const fetchedThrillerMovies = await getMoviesByGenre(53);
setThrillerMovies(fetchedThrillerMovies);
-
- const fetchedComedyMovies = await getMoviesByGenre(35);
setComedyMovies(fetchedComedyMovies);
-
- const fetchedRomanceMovies = await getMoviesByGenre(28);
setRomanceMovies(fetchedRomanceMovies);
-
+
} catch (error) {
console.error('Error fetching movies:', error);
- } finally {
-
}
};
-
- fetchOTHERMovies();
+
+ fetchOTHERMovies();
}, []);
+
const shuffleArray = (array) => {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
@@ -204,29 +191,25 @@ const Home = ({ route }) => {
try {
let moviesData = await getMovies();
moviesData = shuffleArray(moviesData); // Shuffle the movies array
- setMovies([{ key: "empty-left" }, ...moviesData, { key: "empty-right" }]);
+ setMovies([{ key: "empty-left" }, ...moviesData.slice(0, 9), { key: "empty-right" }]);
} catch (error) {
console.error("Failed to fetch movies:", error);
}
};
-
+
fetchMovies();
}, []);
+
+
useEffect(() => {
+
const fetchUserWatchlists = async () => {
try {
const userId = userInfo.userId;
- let userWatchlists = await getUserWatchlists(userId);
-
- //let userWatchlists = await getFollowedUsersWatchlists(userId);
-
-
- // Remove duplicates based on watchlist IDs
- // userWatchlists = userWatchlists.filter((watchlist, index, self) =>
- // index === self.findIndex((w) => w.id === watchlist.id)
- // );
-
+ let userWatchlists = await getFollowedUsersWatchlists(userId);
+
+
setWatchlists(userWatchlists);
} catch (error) {
console.error('Error fetching user watchlists:', error);
@@ -237,10 +220,48 @@ const Home = ({ route }) => {
fetchUserWatchlists();
}, []);
+ useEffect(() => {
+ const fetchMoviesByGenres = async () => {
+ try {
+ const genreMoviesPromises = Object.entries(genres).map(([genreName, genreId]) =>
+ getNewMovies(genreId)
+ );
+
+ const fetchedMovies = await Promise.all(genreMoviesPromises);
+
+ const moviesByGenreData = Object.keys(genres).reduce((acc, genreName, index) => {
+ acc[genreName] = fetchedMovies[index];
+ return acc;
+ }, {});
+
+ setMoviesByGenre(moviesByGenreData);
+ } catch (error) {
+ console.error('Error fetching movies by genres:', error);
+ }
+ };
+
+ fetchMoviesByGenres();
+ }, []);
+
+
+
+ useEffect(() => {
+ const fetchMovies = async () => {
+ try {
+ const moviesData = await getMovies();
+ setMovies([{ key: "empty-left" }, ...moviesData, { key: "empty-right" }]);
+ } catch (error) {
+ console.error("Failed to fetch movies:", error);
+ }
+ };
+
+ fetchMovies();
+ }, []);
+
// useEffect(() => {
// let interval;
-
+
// if (isAutoScrolling) {
// interval = setInterval(() => {
// if (activeIndex === 9) {
@@ -262,7 +283,7 @@ const Home = ({ route }) => {
// }
// }, 2000); // Adjust the interval as needed
// }
-
+
// return () => clearInterval(interval);
// }, [isAutoScrolling, activeIndex, movies1]);
// const getItemLayout = (data, index) => ({
@@ -305,7 +326,7 @@ const Home = ({ route }) => {
return ;
}
-
+
const homeStyles = StyleSheet.create({
container: {
@@ -333,6 +354,13 @@ const Home = ({ route }) => {
overview={item.overview}
rating={item.vote_average.toFixed(1)}
date={new Date(item.release_date).getFullYear()}
+ imageComponent={
+
+ }
/>
);
@@ -381,7 +409,7 @@ const Home = ({ route }) => {
return (
- navigation.navigate("MovieDescriptionPage", { userInfo: userInfo, ...movieDetails })}>
+ navigation.navigate("MovieDescriptionPage", { ...movieDetails, userInfo })}>
{
{item.description}
- navigation.navigate("MovieDescriptionPage", { userInfo: userInfo, ...movieDetails })}>
+ navigation.navigate("MovieDescriptionPage", { ...movieDetails })}>
Read more
@@ -428,7 +456,7 @@ const Home = ({ route }) => {
- {comedyMovies.slice(5, 24).map((movie, index) => (
+ {comedyMovies.slice(5, 16).map((movie, index) => (
{
- {watchlists.map((watchlist) => (
- goToWatchlistDetails(watchlist)}>
-
+ {watchlists.map((watchlist, index) => (
+ goToWatchlistDetails(watchlist)}>
+ {loading && (
+
+ )}
+ setLoading(false)}/>
(
-// goToWatchlistDetails(watchlist)}>
-//
-//
-// {watchlist.name}
+ }} numberOfLines={1} // Limits the text to 1 line
+ ellipsizeMode="tail"
+ >{watchlist.name}
-
+
))}
@@ -501,7 +528,7 @@ const Home = ({ route }) => {
- {romanceMovies.slice(0, 20).map((movie, index) => (
+ {romanceMovies.slice(0, 10).map((movie, index) => (
{
- {moviesByGenre[genreName]?.slice(0, 20).map((movie, index) => (
+ {moviesByGenre[genreName]?.slice(0, 10).map((movie, index) => (
{
setRefreshing(true);
+ renderTabContent();
fetchData().finally(() => setRefreshing(false));
};
@@ -176,11 +177,11 @@ export default function ProfilePage({ route }) {
const renderTabContent = () => {
switch (activeTab) {
case 'posts':
- return ;
+ return ;
case 'likes':
- return ;
+ return ;
case 'watchlist':
- return ;
+ return ;
default:
return null;
}
@@ -196,7 +197,7 @@ export default function ProfilePage({ route }) {
return (
- } scrollbarThumbColor="rgba(0, 0, 0, 0)" showsVerticalScrollIndicator={false} >
+ } scrollbarThumbColor="rgba(0, 0, 0, 0)" showsVerticalScrollIndicator={false} >
{
useEffect(() => {
const fetchPosters = async () => {
const posters = {};
- const usedPosters = new Set(); // set of posters that have been used
+ const usedPosters = new Set();
+ const cachedPosters = await AsyncStorage.getItem('cachedPosters');
+ const parsedCachedPosters = cachedPosters ? JSON.parse(cachedPosters) : {};
+
for (const [genreId, genreName] of sortedGenres) {
+ if (parsedCachedPosters[genreName]) {
+ posters[genreName] = parsedCachedPosters[genreName];
+ continue;
+ }
+
const movies = await getMoviesByGenre(genreId);
if (movies.length > 0) {
let posterPath = `https://image.tmdb.org/t/p/w500${movies[0].poster_path}`;
let index = 0;
- // Ensure the poster is unique
while (usedPosters.has(posterPath) && index < movies.length) {
index++;
- posterPath = `https://image.tmdb.org/t/p/w500${movies[index].poster_path}`;
+ if (index < movies.length) {
+ posterPath = `https://image.tmdb.org/t/p/w500${movies[index].poster_path}`;
+ } else {
+ break;
+ }
}
usedPosters.add(posterPath);
posters[genreName] = posterPath;
+
+ parsedCachedPosters[genreName] = posterPath;
}
}
+
+ await AsyncStorage.setItem('cachedPosters', JSON.stringify(parsedCachedPosters));
setGenrePosters(posters);
};
+
fetchPosters();
}, []);
@@ -237,6 +254,7 @@ const SearchPage = ({ route }) => {
backgroundColor: "#00000080",
flex: 1,
textAlignVertical: "center",
+ justifyContent: "center",
},
grid: {