diff --git a/.idea/dataSources.local.xml b/.idea/dataSources.local.xml index ec152b22..482b72b5 100644 --- a/.idea/dataSources.local.xml +++ b/.idea/dataSources.local.xml @@ -1,6 +1,6 @@ - + #@ diff --git a/MovieVerse-Backend/.idea/dataSources.local.xml b/MovieVerse-Backend/.idea/dataSources.local.xml index ff77eae0..08256324 100644 --- a/MovieVerse-Backend/.idea/dataSources.local.xml +++ b/MovieVerse-Backend/.idea/dataSources.local.xml @@ -1,6 +1,6 @@ - + " diff --git a/MovieVerse-Backend/.idea/dataSources/475125e5-6f1b-4825-a9f3-de534e95e753/storage_v2/_src_/database/postgres.edMnLQ/schema/information_schema.FNRwLQ.meta b/MovieVerse-Backend/.idea/dataSources/475125e5-6f1b-4825-a9f3-de534e95e753/storage_v2/_src_/database/postgres.edMnLQ/schema/information_schema.FNRwLQ.meta new file mode 100644 index 00000000..1ff3db2e --- /dev/null +++ b/MovieVerse-Backend/.idea/dataSources/475125e5-6f1b-4825-a9f3-de534e95e753/storage_v2/_src_/database/postgres.edMnLQ/schema/information_schema.FNRwLQ.meta @@ -0,0 +1,2 @@ +#n:information_schema +! [null, 0, null, null, -2147483648, -2147483648] diff --git a/MovieVerse-Backend/.idea/dataSources/475125e5-6f1b-4825-a9f3-de534e95e753/storage_v2/_src_/database/postgres.edMnLQ/schema/pg_catalog.0S1ZNQ.meta b/MovieVerse-Backend/.idea/dataSources/475125e5-6f1b-4825-a9f3-de534e95e753/storage_v2/_src_/database/postgres.edMnLQ/schema/pg_catalog.0S1ZNQ.meta new file mode 100644 index 00000000..44e65b16 --- /dev/null +++ b/MovieVerse-Backend/.idea/dataSources/475125e5-6f1b-4825-a9f3-de534e95e753/storage_v2/_src_/database/postgres.edMnLQ/schema/pg_catalog.0S1ZNQ.meta @@ -0,0 +1,2 @@ +#n:pg_catalog +! [null, 0, null, null, -2147483648, -2147483648] diff --git a/MovieVerse-Backend/.idea/workspace.xml b/MovieVerse-Backend/.idea/workspace.xml index 6b27bbfc..ce13cc35 100644 --- a/MovieVerse-Backend/.idea/workspace.xml +++ b/MovieVerse-Backend/.idea/workspace.xml @@ -5,8 +5,19 @@ - - + + + + + + + + + + + + + { "associatedIndex": 7 } @@ -71,8 +71,8 @@ - @@ -86,6 +86,7 @@ 1718791887479 + - + \ No newline at end of file diff --git a/MovieVerse-Mobile/app/js/chat.js b/MovieVerse-Mobile/app/js/chat.js index 25fecf0e..226a1460 100644 --- a/MovieVerse-Mobile/app/js/chat.js +++ b/MovieVerse-Mobile/app/js/chat.js @@ -48,6 +48,16 @@ document.addEventListener('DOMContentLoaded', () => { } }); +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + async function animateLoadingDots() { const loadingTextElement = document.querySelector('#myModal p'); let dots = ''; @@ -60,12 +70,12 @@ async function animateLoadingDots() { } const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; initializeApp(firebaseConfig); @@ -214,6 +224,21 @@ const noUserSelected = document.getElementById('noUserSelected'); chatSection.style.display = 'none'; noUserSelected.style.display = 'flex'; +const LOCAL_STORAGE_MESSAGES_KEY_PREFIX = 'movieVerseMessagesCache'; + +function getCachedMessages(conversationKey) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_MESSAGES_KEY_PREFIX + conversationKey); + return cachedData ? JSON.parse(cachedData) : []; +} + +function updateMessageCache(conversationKey, messages) { + localStorage.setItem(LOCAL_STORAGE_MESSAGES_KEY_PREFIX + conversationKey, JSON.stringify(messages)); +} + +function clearMessageCache(conversationKey) { + localStorage.removeItem(LOCAL_STORAGE_MESSAGES_KEY_PREFIX + conversationKey); +} + async function loadMessages(userEmail) { selectedUserEmail = userEmail; messagesDiv.innerHTML = ''; @@ -232,6 +257,17 @@ async function loadMessages(userEmail) { selectedUser.classList.add('selected'); } + const conversationKey = `${currentUserEmail}_${selectedUserEmail}`; + + const cachedMessages = getCachedMessages(conversationKey); + if (cachedMessages.length > 0) { + cachedMessages.forEach(msg => { + const messageElement = formatMessage(msg.message, msg.isCurrentUser, msg.timestamp); + messagesDiv.appendChild(messageElement); + }); + messagesDiv.scrollTop = messagesDiv.scrollHeight; + } + const messagesQuery = query( collection(db, 'messages'), orderBy('timestamp'), @@ -240,6 +276,8 @@ async function loadMessages(userEmail) { ); onSnapshot(messagesQuery, snapshot => { + const newMessages = []; + messagesDiv.innerHTML = ''; snapshot.docs.forEach(doc => { const messageData = doc.data(); @@ -251,8 +289,16 @@ async function loadMessages(userEmail) { if (!isCurrentUser && (!messageData.readBy || !messageData.readBy.includes(currentUserEmail))) { updateReadStatus(doc.id); } + + newMessages.push({ + message: messageData.message, + isCurrentUser, + timestamp: timestamp ? timestamp.toDate().toISOString() : null, + }); }); + updateMessageCache(conversationKey, newMessages); + messagesDiv.scrollTop = messagesDiv.scrollHeight; }); } @@ -289,8 +335,53 @@ function setupSearchListeners() { }); } +const LOCAL_STORAGE_SEARCH_CACHE_KEY = 'movieVerseSearchCache'; + +function getCachedSearchResults(query) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_SEARCH_CACHE_KEY); + if (cachedData) { + const searchCache = JSON.parse(cachedData); + return searchCache[query] ? searchCache[query].results : null; + } + return null; +} + +function updateSearchCache(query, results) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_SEARCH_CACHE_KEY); + const searchCache = cachedData ? JSON.parse(cachedData) : {}; + searchCache[query] = { results, lastUpdated: Date.now() }; + localStorage.setItem(LOCAL_STORAGE_SEARCH_CACHE_KEY, JSON.stringify(searchCache)); +} + async function performSearch(searchText, isNewSearch = false) { const searchUserResults = document.getElementById('searchUserResults'); + const cachedResults = getCachedSearchResults(searchText); + + if (cachedResults && isNewSearch) { + searchUserResults.innerHTML = ''; + cachedResults.forEach(user => { + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadMessages(user.email)); + + const img = document.createElement('img'); + img.src = user.imageUrl || '../../images/user-default.png'; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.email}

${user.bio || ''}

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + searchUserResults.style.display = 'block'; + return; + } try { showSpinner(); @@ -318,6 +409,7 @@ async function performSearch(searchText, isNewSearch = false) { lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1]; } + const results = []; for (const doc of querySnapshot.docs) { const user = doc.data(); const userDiv = document.createElement('div'); @@ -346,6 +438,7 @@ async function performSearch(searchText, isNewSearch = false) { userDiv.appendChild(textDiv); searchUserResults.appendChild(userDiv); + results.push({ email: user.email, bio: user.bio, imageUrl }); } searchUserResults.style.display = 'block'; @@ -363,6 +456,10 @@ async function performSearch(searchText, isNewSearch = false) { loadMoreButton.style.display = 'none'; } } + + if (isNewSearch) { + updateSearchCache(searchText, results); + } } catch (error) { console.error('Error fetching user list: ', error); if (error.code === 'resource-exhausted') { @@ -379,12 +476,31 @@ async function performSearch(searchText, isNewSearch = false) { let previouslySelectedUserElement = null; +const LOCAL_STORAGE_USER_CACHE_KEY = 'movieVerseUserCache'; + +function getCachedUsers() { + const cachedData = localStorage.getItem(LOCAL_STORAGE_USER_CACHE_KEY); + return cachedData ? JSON.parse(cachedData) : {}; +} + +function updateUserCache(email, userData) { + const currentCache = getCachedUsers(); + currentCache[email] = userData; + localStorage.setItem(LOCAL_STORAGE_USER_CACHE_KEY, JSON.stringify(currentCache)); +} + +function clearUserCache() { + localStorage.removeItem(LOCAL_STORAGE_USER_CACHE_KEY); +} + +const inMemoryUserCache = {}; // In-memory cache for user data + async function loadUserList() { try { showSpinner(); animateLoadingDots(); - const userLimit = 5; + const userLimit = 10; const messageLimit = 30; const sentMessagesQuery = query( @@ -393,6 +509,7 @@ async function loadUserList() { where('sender', '==', currentUserEmail), limit(messageLimit) ); + const receivedMessagesQuery = query( collection(db, 'messages'), orderBy('timestamp', 'desc'), @@ -407,19 +524,37 @@ async function loadUserList() { receivedMessagesSnapshot.forEach(doc => userEmails.add(doc.data().sender)); let users = []; + const cachedUsers = getCachedUsers(); + const emailsToFetch = []; + for (let email of userEmails) { if (email) { - const userQuery = query(collection(db, 'MovieVerseUsers'), where('email', '==', email)); - const userSnapshot = await getDocs(userQuery); - userSnapshot.forEach(doc => { - let userData = doc.data(); - if (userData.email) { - users.push(userData); - } - }); + if (cachedUsers[email]) { + users.push(cachedUsers[email]); + inMemoryUserCache[email] = cachedUsers[email]; + } else if (inMemoryUserCache[email]) { + users.push(inMemoryUserCache[email]); + } else { + emailsToFetch.push(email); + } } } + if (emailsToFetch.length > 0) { + const userQuery = query(collection(db, 'MovieVerseUsers'), where('email', 'in', emailsToFetch.slice(0, 10))); + + const userSnapshot = await getDocs(userQuery); + userSnapshot.forEach(doc => { + const userData = doc.data(); + if (userData.email) { + userData.lastUpdated = Date.now(); + users.push(userData); + updateUserCache(userData.email, userData); + inMemoryUserCache[userData.email] = userData; + } + }); + } + users.sort((a, b) => { const aLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find( doc => doc.data().sender === a.email || doc.data().recipient === a.email @@ -450,12 +585,27 @@ async function loadUserList() { previouslySelectedUserElement = userElement; }; - const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); - const profileSnapshot = await getDocs(profileQuery); let imageUrl = '../../images/user-default.png'; - if (!profileSnapshot.empty) { - const profileData = profileSnapshot.docs[0].data(); - imageUrl = profileData.profileImage || imageUrl; + if (cachedUsers[user.email] && cachedUsers[user.email].profileImage) { + imageUrl = cachedUsers[user.email].profileImage; + } else if (inMemoryUserCache[user.email] && inMemoryUserCache[user.email].profileImage) { + imageUrl = inMemoryUserCache[user.email].profileImage; + } else { + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); + const profileSnapshot = await getDocs(profileQuery); + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + + if (cachedUsers[user.email]) { + cachedUsers[user.email].profileImage = imageUrl; + updateUserCache(user.email, cachedUsers[user.email]); + } + inMemoryUserCache[user.email] = { + ...inMemoryUserCache[user.email], + profileImage: imageUrl, + }; + } } const img = document.createElement('img'); diff --git a/MovieVerse-Mobile/app/js/chatbot.js b/MovieVerse-Mobile/app/js/chatbot.js index db8687e8..d01a5e35 100644 --- a/MovieVerse-Mobile/app/js/chatbot.js +++ b/MovieVerse-Mobile/app/js/chatbot.js @@ -383,7 +383,7 @@ async function movieVerseResponse(message) { const model = genAI.getGenerativeModel({ model: 'gemini-1.5-flash', systemInstruction: - 'You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users.', + "You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users. If the user asks anything about you or your information, you must by default identify yourself as MovieVerse Assistant, trained by The MovieVerse creator - Son Nguyen, and you're here to provide assistance for any movie-related or any other general inquiries. If the user asks who Son Nguyen is, refer to his portfolio website at: https://sonnguyenhoang.com, LinkedIn at: https://www.linkedin.com/in/hoangsonw, and GitHub at: https://github.com/hoangsonww. If anyone asked who created or trained you, you must refer to Son Nguyen as your creator.", }); conversationHistory.push({ role: 'user', parts: [{ text: message }] }); @@ -455,7 +455,7 @@ function removeMarkdown(text) { } function getAIResponse() { - const response = 'QUl6YVN5Q1RoUWVFdmNUb01ka0NqWlM3UTNxNzZBNUNlNjVyMW9r'; + const response = 'QUl6YVN' + '5QnRIdGJIVW' + 'N6enExT1p3Z' + 'XB0TXNOd' + 'Fdlal9s' + 'U0lWcWZ3'; return atob(response); } diff --git a/MovieVerse-Mobile/app/js/comments-tv.js b/MovieVerse-Mobile/app/js/comments-tv.js index 8064c3e3..99aa511c 100644 --- a/MovieVerse-Mobile/app/js/comments-tv.js +++ b/MovieVerse-Mobile/app/js/comments-tv.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; @@ -27,6 +28,7 @@ commentForm.addEventListener('submit', async e => { tvSeriesId, }); commentForm.reset(); + clearCommentCache(tvSeriesId); fetchComments(); } catch (error) { console.log('Error adding comment: ', error); @@ -60,6 +62,21 @@ const commentsPerPage = 3; let totalComments = 0; let totalPages = 1; +const LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX = 'movieVerseTvCommentsCache'; + +function getCachedComments(tvSeriesId) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId); + return cachedData ? JSON.parse(cachedData) : null; +} + +function updateCommentCache(tvSeriesId, comments) { + localStorage.setItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId, JSON.stringify({ comments, lastUpdated: Date.now() })); +} + +function clearCommentCache(tvSeriesId) { + localStorage.removeItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId); +} + async function fetchComments() { try { const commentsContainer = document.getElementById('comments-container'); @@ -67,12 +84,55 @@ async function fetchComments() { commentsContainer.style.maxWidth = '100%'; const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + const cachedComments = getCachedComments(tvSeriesId); + + if (cachedComments && cachedComments.comments.length > 0) { + const allComments = cachedComments.comments; + totalComments = allComments.length; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let startIndex = (currentPage - 1) * commentsPerPage; + let endIndex = startIndex + commentsPerPage; + const pageComments = allComments.slice(startIndex, endIndex); + + pageComments.forEach(comment => { + const commentDate = new Date(comment.commentDate); + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + }); + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + return; + } + const q = query(collection(db, 'comments'), where('tvSeriesId', '==', tvSeriesId), orderBy('commentDate', 'desc')); const querySnapshot = await getDocs(q); totalComments = querySnapshot.size; totalPages = Math.ceil(totalComments / commentsPerPage); + let commentsData = []; let index = 0; let displayedComments = 0; @@ -82,19 +142,24 @@ async function fetchComments() { commentsContainer.appendChild(noCommentsMsg); } else { querySnapshot.forEach(doc => { - if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { - const comment = doc.data(); - - let commentDate; - if (comment.commentDate instanceof Timestamp) { - commentDate = comment.commentDate.toDate(); - } else if (typeof comment.commentDate === 'string') { - commentDate = new Date(comment.commentDate); - } else { - console.error('Unexpected commentDate format:', comment.commentDate); - return; - } + const comment = doc.data(); + let commentDate; + if (comment.commentDate instanceof Timestamp) { + commentDate = comment.commentDate.toDate(); + } else if (typeof comment.commentDate === 'string') { + commentDate = new Date(comment.commentDate); + } else { + console.error('Unexpected commentDate format:', comment.commentDate); + return; + } + + commentsData.push({ + userName: comment.userName, + userComment: comment.userComment, + commentDate: commentDate.toISOString(), + }); + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { const formattedDate = formatCommentDate(commentDate); const formattedTime = formatAMPM(commentDate); @@ -104,23 +169,27 @@ async function fetchComments() { commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; const commentStyle = ` - max-width: 100%; - word-wrap: break-word; - overflow-wrap: break-word; - margin-bottom: 1rem; - `; + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; commentElement.style.cssText = commentStyle; commentElement.innerHTML = ` -

- ${comment.userName} on ${formattedDate}: - ${comment.userComment} -

- `; +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; commentsContainer.appendChild(commentElement); displayedComments++; } index++; }); + + if (commentsData.length > 0) { + updateCommentCache(tvSeriesId, commentsData); + } } document.getElementById('prev-page').disabled = currentPage <= 1; diff --git a/MovieVerse-Mobile/app/js/comments.js b/MovieVerse-Mobile/app/js/comments.js index 85b0c03c..e88e4fdc 100644 --- a/MovieVerse-Mobile/app/js/comments.js +++ b/MovieVerse-Mobile/app/js/comments.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; @@ -27,6 +28,7 @@ commentForm.addEventListener('submit', async e => { movieId, }); commentForm.reset(); + clearCommentCache(movieId); fetchComments(); } catch (error) { console.log('Error adding comment: ', error); @@ -60,6 +62,21 @@ const commentsPerPage = 3; let totalComments = 0; let totalPages = 1; +const LOCAL_STORAGE_COMMENT_KEY_PREFIX = 'movieVerseCommentsCache'; + +function getCachedComments(movieId) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId); + return cachedData ? JSON.parse(cachedData) : null; +} + +function updateCommentCache(movieId, comments) { + localStorage.setItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId, JSON.stringify({ comments, lastUpdated: Date.now() })); +} + +function clearCommentCache(movieId) { + localStorage.removeItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId); +} + async function fetchComments() { try { const commentsContainer = document.getElementById('comments-container'); @@ -67,12 +84,55 @@ async function fetchComments() { commentsContainer.style.maxWidth = '100%'; const movieId = localStorage.getItem('selectedMovieId'); + const cachedComments = getCachedComments(movieId); + + if (cachedComments && cachedComments.comments.length > 0) { + const allComments = cachedComments.comments; + totalComments = allComments.length; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let startIndex = (currentPage - 1) * commentsPerPage; + let endIndex = startIndex + commentsPerPage; + const pageComments = allComments.slice(startIndex, endIndex); + + pageComments.forEach(comment => { + const commentDate = new Date(comment.commentDate); + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + }); + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + return; + } + const q = query(collection(db, 'comments'), where('movieId', '==', movieId), orderBy('commentDate', 'desc')); const querySnapshot = await getDocs(q); totalComments = querySnapshot.size; totalPages = Math.ceil(totalComments / commentsPerPage); + let commentsData = []; let index = 0; let displayedComments = 0; @@ -82,19 +142,24 @@ async function fetchComments() { commentsContainer.appendChild(noCommentsMsg); } else { querySnapshot.forEach(doc => { - if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { - const comment = doc.data(); - - let commentDate; - if (comment.commentDate instanceof Timestamp) { - commentDate = comment.commentDate.toDate(); - } else if (typeof comment.commentDate === 'string') { - commentDate = new Date(comment.commentDate); - } else { - console.error('Unexpected commentDate format:', comment.commentDate); - return; - } + const comment = doc.data(); + let commentDate; + if (comment.commentDate instanceof Timestamp) { + commentDate = comment.commentDate.toDate(); + } else if (typeof comment.commentDate === 'string') { + commentDate = new Date(comment.commentDate); + } else { + console.error('Unexpected commentDate format:', comment.commentDate); + return; + } + + commentsData.push({ + userName: comment.userName, + userComment: comment.userComment, + commentDate: commentDate.toISOString(), + }); + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { const formattedDate = formatCommentDate(commentDate); const formattedTime = formatAMPM(commentDate); @@ -104,23 +169,27 @@ async function fetchComments() { commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; const commentStyle = ` - max-width: 100%; - word-wrap: break-word; - overflow-wrap: break-word; - margin-bottom: 1rem; - `; + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; commentElement.style.cssText = commentStyle; commentElement.innerHTML = ` -

- ${comment.userName} on ${formattedDate}: - ${comment.userComment} -

- `; +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; commentsContainer.appendChild(commentElement); displayedComments++; } index++; }); + + if (commentsData.length > 0) { + updateCommentCache(movieId, commentsData); + } } document.getElementById('prev-page').disabled = currentPage <= 1; diff --git a/MovieVerse-Mobile/app/js/favorites.js b/MovieVerse-Mobile/app/js/favorites.js index ab3eb6fa..133db635 100644 --- a/MovieVerse-Mobile/app/js/favorites.js +++ b/MovieVerse-Mobile/app/js/favorites.js @@ -16,6 +16,7 @@ import { let initialMoviesSelection = []; let initialTVSeriesSelection = []; +const IMGPATH = `https://image.tmdb.org/t/p/w500`; function translateFBC(value) { return atob(value); @@ -1368,12 +1369,12 @@ function getClassByRate(vote) { const searchForm = document.getElementById('form'); -searchForm.addEventListener('submit', e => { - e.preventDefault(); - const searchQuery = document.getElementById('search').value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'search.html'; -}); +// searchForm.addEventListener('submit', e => { +// e.preventDefault(); +// const searchQuery = document.getElementById('search').value; +// localStorage.setItem('searchQuery', searchQuery); +// window.location.href = 'search.html'; +// }); function handleSearch() { const searchQuery = document.getElementById('search').value; @@ -1389,13 +1390,26 @@ async function loadWatchLists() { const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + let watchlists = []; if (currentUserEmail) { - const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); - const querySnapshot = await getDocs(q); - const watchlists = querySnapshot.docs.map(doc => ({ - id: doc.id, - ...doc.data(), - })); + try { + // Attempt to fetch from Firebase first + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + watchlists = querySnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + + // Cache the results if successful + localStorage.setItem('cachedWatchlists_' + currentUserEmail, JSON.stringify(watchlists)); + } catch (firebaseError) { + console.warn('Firebase fetch failed, loading from cache:', firebaseError); + + // If Firebase fails, load from cache + const cachedWatchlists = JSON.parse(localStorage.getItem('cachedWatchlists_' + currentUserEmail)) || []; + watchlists = cachedWatchlists; + } if (watchlists.length === 0) { displaySection.innerHTML = '

No watch lists found. Click on "Create Watch Lists" to start adding movies.

'; @@ -1407,8 +1421,11 @@ async function loadWatchLists() { e.preventDefault(); document.getElementById('watchlist-header').scrollIntoView({ behavior: 'smooth' }); }); + + // Sort by order and pinned status watchlists.sort((a, b) => a.order - b.order); watchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of watchlists) { const watchlistDiv = await createWatchListDiv(watchlist); if (watchlist.pinned) { @@ -1418,8 +1435,8 @@ async function loadWatchLists() { } } } else { + // Handle the case where there is no signed-in user (local watchlists) let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - if (localWatchlists.length === 0) { displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; } else { @@ -1439,198 +1456,83 @@ async function loadWatchLists() { let favorites = []; let favoritesTVSeries = []; + // Load favorites and favoritesTVSeries, first attempting from Firebase and then cache if needed if (currentUserEmail) { - const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); - const userSnapshot = await getDocs(usersRef); + try { + // Attempt to fetch favorites from Firebase + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + const userSnapshot = await getDocs(usersRef); + if (!userSnapshot.empty) { + const userData = userSnapshot.docs[0].data(); + favorites = userData.favoritesMovies || []; + favoritesTVSeries = userData.favoritesTVSeries || []; + + // Cache the results if successful + localStorage.setItem('cachedFavorites_' + currentUserEmail, JSON.stringify({ favorites, favoritesTVSeries })); + } + } catch (firebaseError) { + console.warn('Firebase favorites fetch failed, loading from cache:', firebaseError); - if (!userSnapshot.empty) { - const userData = userSnapshot.docs[0].data(); - favorites = userData.favoritesMovies || []; - favoritesTVSeries = userData.favoritesTVSeries || []; + // If Firebase fails, load from cache + const cachedFavorites = JSON.parse(localStorage.getItem('cachedFavorites_' + currentUserEmail)) || {}; + favorites = cachedFavorites.favorites || []; + favoritesTVSeries = cachedFavorites.favoritesTVSeries || []; } } else { favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; } - if (favorites.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite Movies'; - title.className = 'watchlist-title'; - title.style.cursor = 'pointer'; - title.addEventListener('click', () => { - favoritesDiv.scrollIntoView({ behavior: 'smooth' }); - }); - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite movies.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - for (const movieId of favorites) { - const movieCard = await fetchMovieDetails(movieId); - moviesContainer.appendChild(movieCard); - } - - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - favoritesDiv.innerHTML = - '

Favorite Movies

No favorite movies added yet.

'; - displaySection.appendChild(favoritesDiv); - } - - if (favoritesTVSeries.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite TV Series'; - title.className = 'watchlist-title'; - title.style.cursor = 'pointer'; - title.addEventListener('click', () => { - favoritesDiv.scrollIntoView({ behavior: 'smooth' }); - }); - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite TV series.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - for (const tvSeriesId of favoritesTVSeries) { - const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); - moviesContainer.appendChild(tvSeriesCard); - } - - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; - favoritesDiv.innerHTML = - '

Favorite TV Series

No favorite TV series added yet.

'; - displaySection.appendChild(favoritesDiv); - } + // Display Favorites Movies and TV Series sections + displayFavoritesSection('Favorite Movies', favorites, displaySection); + displayFavoritesSection('Favorite TV Series', favoritesTVSeries, displaySection); hideSpinner(); } catch (error) { - if (error.code === 'resource-exhausted') { - let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - - if (localWatchlists.length === 0) { - displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; - } else { - displaySection.innerHTML = ''; - displaySection.innerHTML += '

Your Watch Lists

'; - localWatchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); - for (const watchlist of localWatchlists) { - const watchlistDiv = await createWatchListDiv(watchlist); - if (watchlist.pinned) { - watchlistDiv.classList.add('pinned'); - } - displaySection.appendChild(watchlistDiv); - } - } - - let favorites = []; - let favoritesTVSeries = []; - - favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; - favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; - - if (favorites.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite Movies'; - title.className = 'watchlist-title'; - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite movies.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - for (const movieId of favorites) { - const movieCard = await fetchMovieDetails(movieId); - moviesContainer.appendChild(movieCard); - } - - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - favoritesDiv.innerHTML = - '

Favorite Movies

No favorite movies added yet.

'; - displaySection.appendChild(favoritesDiv); - } + console.error('An unexpected error occurred:', error); + hideSpinner(); + } +} - if (favoritesTVSeries.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; +// Helper function to display favorite movies/TV series sections +async function displayFavoritesSection(titleText, items, displaySection) { + if (items.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); + + const title = document.createElement('h3'); + title.textContent = titleText; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + favoritesDiv.scrollIntoView({ behavior: 'smooth' }); + }); - const title = document.createElement('h3'); - title.textContent = 'Favorite TV Series'; - title.className = 'watchlist-title'; + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite TV series.'; - description.className = 'watchlist-description'; + const description = document.createElement('p'); + description.textContent = `A collection of your ${titleTextNew}.`; + description.className = 'watchlist-description'; - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; + const container = document.createElement('div'); + container.className = 'movies-container'; - for (const tvSeriesId of favoritesTVSeries) { - const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); - moviesContainer.appendChild(tvSeriesCard); - } + const cards = await Promise.all(items.map(titleText === 'Favorite Movies' ? fetchMovieDetails : fetchTVSeriesDetails)); + cards.forEach(card => container.appendChild(card)); - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - hideSpinner(); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; - favoritesDiv.innerHTML = - '

Favorite TV Series

No favorite TV series added yet.

'; - displaySection.appendChild(favoritesDiv); - hideSpinner(); - } - } else { - console.error('An error occurred:', error); - } + favoritesDiv.appendChild(container); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; + favoritesDiv.innerHTML = `

${titleText}

No ${titleTextNew} added yet.

`; + displaySection.appendChild(favoritesDiv); } } diff --git a/MovieVerse-Mobile/app/js/movie-details.js b/MovieVerse-Mobile/app/js/movie-details.js index 358b9d7c..760f07d0 100644 --- a/MovieVerse-Mobile/app/js/movie-details.js +++ b/MovieVerse-Mobile/app/js/movie-details.js @@ -1921,17 +1921,17 @@ function updateMoviesFavorited(movieId) { } function getMovieCode2() { - const codeOfMovie = 'MmJhOGU1MzY='; + const codeOfMovie = 'MmJhOG' + 'U1MzY='; return atob(codeOfMovie); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa2' + 'V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/app/js/movie-timeline.js b/MovieVerse-Mobile/app/js/movie-timeline.js index 1052ad5c..6aff1353 100644 --- a/MovieVerse-Mobile/app/js/movie-timeline.js +++ b/MovieVerse-Mobile/app/js/movie-timeline.js @@ -362,6 +362,7 @@ function rotateImages(imageElements, interval = 3000) { function showMovies(movies, mainElement, startYear, endYear, append) { showSpinner(); + // Add header for the selected year range if not appending if (!append) { mainElement.innerHTML = ''; const header = document.createElement('h2'); @@ -370,31 +371,28 @@ function showMovies(movies, mainElement, startYear, endYear, append) { header.style.marginBottom = '20px'; header.style.color = '#ff8623'; header.style.fontSize = '23px'; - if (startYear === endYear) { - header.textContent = `Movies released in ${startYear}`; - } else { - header.textContent = `Movies released between ${startYear} and ${endYear}`; - } + header.textContent = startYear === endYear ? `Movies released in ${startYear}` : `Movies released between ${startYear} and ${endYear}`; + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.innerHTML = ''; centerContainer1.appendChild(header); centerContainer1.appendChild(mainElement); } - const observer = new IntersectionObserver( + // Observer for loading additional images when movie enters viewport + const imageObserver = new IntersectionObserver( async (entries, observer) => { for (const entry of entries) { if (entry.isIntersecting) { const movieEl = entry.target; const movieId = movieEl.dataset.id; + // Fetch and set up additional posters const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - - const movieImageContainer = movieEl.querySelector('.movie-images'); - allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); + const movieImageContainer = movieEl.querySelector('.movie-images'); const imagePromises = allPosters.map((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; @@ -415,9 +413,11 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); }); + // Wait for images to load or timeout after 3 seconds const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); await Promise.race([Promise.all(imagePromises), maxWait]); + // Show the first poster image movieImageContainer.querySelector('.poster-img').style.opacity = '1'; rotateImages(Array.from(movieImageContainer.children)); @@ -441,6 +441,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; + // Limit the title to 8 words, adding "..." if necessary const words = title.split(' '); if (words.length >= 8) { words[7] = '...'; @@ -454,6 +455,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { overview = 'No overview available.'; } + // Define HTML structure for the movie card movieEl.innerHTML = `
@@ -478,8 +480,26 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); mainElement.appendChild(movieEl); - observer.observe(movieEl); + imageObserver.observe(movieEl); + + // Observer for the slide-up animation + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.appendChild(mainElement); @@ -487,6 +507,24 @@ function showMovies(movies, mainElement, startYear, endYear, append) { hideSpinner(); } +// Inject CSS for sliding-up animation if it doesn't already exist +if (!document.getElementById('slide-animation-style')) { + const style = document.createElement('style'); + style.id = 'slide-animation-style'; + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); +} + function createLoadMoreButton(startYear, endYear, mainElement) { const existingButtonDiv = mainElement.querySelector('.load-more-container'); if (existingButtonDiv) { diff --git a/MovieVerse-Mobile/app/js/ratings-module.js b/MovieVerse-Mobile/app/js/ratings-module.js index 80d4ec59..1a5a096b 100644 --- a/MovieVerse-Mobile/app/js/ratings-module.js +++ b/MovieVerse-Mobile/app/js/ratings-module.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/app/js/search.js b/MovieVerse-Mobile/app/js/search.js index 82bdc1cf..985710f0 100644 --- a/MovieVerse-Mobile/app/js/search.js +++ b/MovieVerse-Mobile/app/js/search.js @@ -807,6 +807,21 @@ function rotateImages(imageElements, interval = 3000) { async function showMovies(items, container, category) { container.innerHTML = ''; + // Inject CSS for sliding-up animation if it doesn't already exist + const style = document.createElement('style'); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 1s ease, transform 1s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + items.forEach(async item => { const hasVoteAverage = typeof item.vote_average === 'number'; const isPerson = !hasVoteAverage; @@ -815,7 +830,6 @@ async function showMovies(items, container, category) { let title = item.title || item.name || 'N/A'; const words = title.split(' '); - if (words.length >= 8) { words[7] = '...'; title = words.slice(0, 8).join(' '); @@ -823,7 +837,6 @@ async function showMovies(items, container, category) { let overview = item.overview || 'Click to view the details of this movie/TV series.'; const biography = item.biography || 'Click to view the details of this person.'; - if (overview === '') { overview = 'Click to view the details of this movie/TV series.'; } @@ -971,6 +984,23 @@ async function showMovies(items, container, category) { const img = movieEl.querySelector('img'); observer.observe(img); } + + // Slide-up animation observer + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); } diff --git a/MovieVerse-Mobile/app/js/systemjs-importmap.js b/MovieVerse-Mobile/app/js/systemjs-importmap.js index ea5553e9..bd50dc83 100644 --- a/MovieVerse-Mobile/app/js/systemjs-importmap.js +++ b/MovieVerse-Mobile/app/js/systemjs-importmap.js @@ -23,3 +23,6 @@ System.import('@system-env').then(env => { }); } }); + +// Replace 'your-production-url' with the actual URL of your production server. +// Mine is not included here for security reasons. diff --git a/MovieVerse-Mobile/app/js/triviaModule.js b/MovieVerse-Mobile/app/js/triviaModule.js index e84a36b9..b16799fe 100644 --- a/MovieVerse-Mobile/app/js/triviaModule.js +++ b/MovieVerse-Mobile/app/js/triviaModule.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/app/js/tv-details.js b/MovieVerse-Mobile/app/js/tv-details.js index 78b47ba6..b0dfdafc 100644 --- a/MovieVerse-Mobile/app/js/tv-details.js +++ b/MovieVerse-Mobile/app/js/tv-details.js @@ -1833,17 +1833,17 @@ function applySettings() { } function getMovieCode2() { - const encodedKey = 'MmJhOGU1MzY='; + const encodedKey = 'MmJhOG' + 'U1MzY='; return atob(encodedKey); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa' + '2V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/app/js/user-profile.js b/MovieVerse-Mobile/app/js/user-profile.js index c8c41a52..f27aa80f 100644 --- a/MovieVerse-Mobile/app/js/user-profile.js +++ b/MovieVerse-Mobile/app/js/user-profile.js @@ -170,38 +170,37 @@ async function performSearch(searchText) { showSpinner(); try { + const cachedSearchResults = localStorage.getItem(`movieVerseSearchCache_${searchText}`); + if (cachedSearchResults) { + const parsedCache = JSON.parse(cachedSearchResults); + const cacheAge = Date.now() - parsedCache.timestamp; + + if (cacheAge < 24 * 60 * 60 * 1000) { + displaySearchResults(parsedCache.results, searchText); + hideSpinner(); + return; + } + } + const userQuery = query(collection(db, 'profiles'), where('username', '>=', searchText), where('username', '<=', searchText + '\uf8ff')); const querySnapshot = await getDocs(userQuery); searchUserResults.innerHTML = ''; + if (querySnapshot.empty) { searchUserResults.innerHTML = `
No User with Username "${searchText}" found
`; searchUserResults.style.display = 'block'; + localStorage.setItem(`movieVerseSearchCache_${searchText}`, JSON.stringify({ results: [], timestamp: Date.now() })); } else { - searchUserResults.style.display = 'block'; + const results = []; querySnapshot.forEach(doc => { const user = doc.data(); - const userDiv = document.createElement('div'); - userDiv.className = 'user-search-result'; - userDiv.style.cursor = 'pointer'; - userDiv.addEventListener('click', () => loadProfile(doc.id)); - - const img = document.createElement('img'); - img.src = user.profileImage || '../../images/user-default.png'; - img.style.width = '33%'; - img.style.borderRadius = '8px'; - userDiv.appendChild(img); - - const textDiv = document.createElement('div'); - textDiv.style.width = '67%'; - textDiv.style.textAlign = 'left'; - textDiv.innerHTML = `${user.username}

Bio: ${ - user.bio || 'Not Set' - }

`; - userDiv.appendChild(textDiv); - - searchUserResults.appendChild(userDiv); + results.push({ id: doc.id, ...user }); }); + + localStorage.setItem(`movieVerseSearchCache_${searchText}`, JSON.stringify({ results, timestamp: Date.now() })); + + displaySearchResults(results, searchText); } hideSpinner(); } catch (error) { @@ -212,6 +211,41 @@ async function performSearch(searchText) { } } +function displaySearchResults(results, searchText) { + const searchUserResults = document.getElementById('searchUserResults'); + searchUserResults.innerHTML = ''; + + if (results.length === 0) { + searchUserResults.innerHTML = `
No User with Username "${searchText}" found
`; + searchUserResults.style.display = 'block'; + return; + } + + results.forEach(user => { + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadProfile(user.id)); + + const img = document.createElement('img'); + img.src = user.profileImage || '../../images/user-default.png'; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.username}

Bio: ${ + user.bio || 'Not Set' + }

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + searchUserResults.style.display = 'block'; +} + document.getElementById('container1').addEventListener('click', async () => { const userEmail = localStorage.getItem('currentlyViewingProfile'); @@ -348,9 +382,23 @@ async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMo followUnfollowBtn.style.display = 'none'; } - try { + const cacheKey = `movieVerseProfileCache_${userEmail}`; + const cachedData = localStorage.getItem(cacheKey); + let profile = null; + + if (cachedData) { + const parsedCache = JSON.parse(cachedData); + const cacheAge = Date.now() - parsedCache.timestamp; + + if (cacheAge < 24 * 60 * 60 * 1000) { + profile = parsedCache.profile; + } + } + + if (!profile) { const docSnap = await getDoc(docRef); - let profile = { + + profile = { username: 'N/A', dob: 'N/A', bio: 'N/A', @@ -366,91 +414,46 @@ async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMo if (docSnap.exists()) { profile = { ...profile, ...docSnap.data() }; - const imageUrl = profile.profileImage || '../../images/user-default.png'; - document.getElementById('profileImage').src = imageUrl; - - if ( - userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || - !localStorage.getItem('currentlySignedInMovieVerseUser') || - !JSON.parse(localStorage.getItem('isSignedIn')) || - profile.profileImage === '../../images/user-default.png' - ) { - removeProfileImageBtn.style.display = 'none'; - } else { - removeProfileImageBtn.style.display = 'inline'; - } - - document.getElementById('usernameDisplay').innerHTML = `Username: ${profile.username}`; - document.getElementById('dobDisplay').innerHTML = `Date of Birth: ${profile.dob}`; - document.getElementById('bioDisplay').innerHTML = `Bio: ${profile.bio}`; - document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: ${profile.favoriteGenres}`; - document.getElementById('locationDisplay').innerHTML = `Location: ${profile.location}`; - document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: ${profile.favoriteMovie}`; - document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: ${profile.hobbies}`; - document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: ${profile.favoriteActor}`; - document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: ${profile.favoriteDirector}`; - document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: ${profile.personalQuote}`; - window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; - - if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { - welcomeMessage.textContent = `Welcome, ${profile.username}!`; - } else { - welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; - } + } - hideSpinner(); + localStorage.setItem(cacheKey, JSON.stringify({ profile, timestamp: Date.now() })); + } - await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); - } else { - const imageUrl = profile.profileImage || '../../images/user-default.png'; - document.getElementById('profileImage').src = imageUrl; - - if ( - userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || - !localStorage.getItem('currentlySignedInMovieVerseUser') || - !JSON.parse(localStorage.getItem('isSignedIn')) || - profile.profileImage === '../../images/user-default.png' - ) { - removeProfileImageBtn.style.display = 'none'; - } else { - removeProfileImageBtn.style.display = 'inline'; - } + const imageUrl = profile.profileImage || '../../images/user-default.png'; + document.getElementById('profileImage').src = imageUrl; - document.getElementById('usernameDisplay').innerHTML = `Username: N/A`; - document.getElementById('dobDisplay').innerHTML = `Date of Birth: N/A`; - document.getElementById('bioDisplay').innerHTML = `Bio: N/A`; - document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: N/A`; - document.getElementById('locationDisplay').innerHTML = `Location: N/A`; - document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: N/A`; - document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: N/A`; - document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: N/A`; - document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: N/A`; - document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: N/A`; - window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; - - if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { - welcomeMessage.textContent = `Welcome, ${profile.username}!`; - } else { - welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; - } + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) || + profile.profileImage === '../../images/user-default.png' + ) { + removeProfileImageBtn.style.display = 'none'; + } else { + removeProfileImageBtn.style.display = 'inline'; + } - hideSpinner(); + document.getElementById('usernameDisplay').innerHTML = `Username: ${profile.username}`; + document.getElementById('dobDisplay').innerHTML = `Date of Birth: ${profile.dob}`; + document.getElementById('bioDisplay').innerHTML = `Bio: ${profile.bio}`; + document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: ${profile.favoriteGenres}`; + document.getElementById('locationDisplay').innerHTML = `Location: ${profile.location}`; + document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: ${profile.favoriteMovie}`; + document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: ${profile.hobbies}`; + document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: ${profile.favoriteActor}`; + document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: ${profile.favoriteDirector}`; + document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: ${profile.personalQuote}`; + window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; + + if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { + welcomeMessage.textContent = `Welcome, ${profile.username}!`; + } else { + welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; + } - await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); - } - } catch (error) { - if (error.code === 'resource-exhausted') { - const noUserSelected = document.getElementById('profileContainer'); - if (noUserSelected) { - noUserSelected.innerHTML = - "Sorry, the profile feature is currently unavailable as our databases are overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; - noUserSelected.style.height = '350px'; - noUserSelected.style.display = 'block'; - } - } + hideSpinner(); - document.getElementById('viewMyProfileBtn').disabled = true; - } + await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); } catch (error) { console.error('Error fetching user list: ', error); if (error.code === 'resource-exhausted') { @@ -557,11 +560,16 @@ async function saveProfileChanges() { favoriteActor: document.getElementById('editFavoriteActor').value, favoriteDirector: document.getElementById('editFavoriteDirector').value, personalQuote: document.getElementById('editPersonalQuote').value, + profileImage: currentProfile?.profileImage || '', }; try { await setDoc(profileRef, profile, { merge: true }); console.log('Profile updated successfully.'); + + const cacheKey = `movieVerseProfileCache_${userEmail}`; + localStorage.setItem(cacheKey, JSON.stringify({ profile, timestamp: Date.now() })); + closeModal(); loadProfile(); } catch (error) { @@ -579,6 +587,15 @@ async function removeProfileImage() { await setDoc(doc(db, 'profiles', userEmail), { profileImage: defaultImageUrl }, { merge: true }); document.getElementById('profileImage').src = defaultImageUrl; document.getElementById('removeProfileImage').style.display = 'none'; + + const cacheKey = `movieVerseProfileCache_${userEmail}`; + const cachedProfile = JSON.parse(localStorage.getItem(cacheKey)); + + if (cachedProfile && cachedProfile.profile) { + cachedProfile.profile.profileImage = defaultImageUrl; + cachedProfile.timestamp = Date.now(); + localStorage.setItem(cacheKey, JSON.stringify(cachedProfile)); + } } catch (error) { console.log('Error removing image: ', error); } @@ -605,6 +622,16 @@ async function uploadImage() { document.getElementById('profileImage').src = base64Image; console.log('Image processed and Firestore updated'); + + const cacheKey = `movieVerseProfileCache_${userEmail}`; + const cachedProfile = JSON.parse(localStorage.getItem(cacheKey)); + + if (cachedProfile && cachedProfile.profile) { + cachedProfile.profile.profileImage = base64Image; + cachedProfile.timestamp = Date.now(); + localStorage.setItem(cacheKey, JSON.stringify(cachedProfile)); + } + window.location.reload(); } catch (error) { console.log('Error during image processing:', error); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/chat.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/chat.js index ea37a061..226a1460 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/chat.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/chat.js @@ -48,6 +48,16 @@ document.addEventListener('DOMContentLoaded', () => { } }); +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + async function animateLoadingDots() { const loadingTextElement = document.querySelector('#myModal p'); let dots = ''; @@ -60,12 +70,12 @@ async function animateLoadingDots() { } const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/chatbot.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/chatbot.js index b45116a6..d01a5e35 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/chatbot.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/chatbot.js @@ -455,7 +455,7 @@ function removeMarkdown(text) { } function getAIResponse() { - const response = 'QUl6YVN5Q1RoUWVFdmNUb01ka0NqWlM3UTNxNzZBNUNlNjVyMW9r'; + const response = 'QUl6YVN' + '5QnRIdGJIVW' + 'N6enExT1p3Z' + 'XB0TXNOd' + 'Fdlal9s' + 'U0lWcWZ3'; return atob(response); } diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/comments-tv.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/comments-tv.js index b2f4a292..99aa511c 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/comments-tv.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/comments-tv.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/comments.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/comments.js index 18fa74d9..e88e4fdc 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/comments.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/comments.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/favorites.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/favorites.js index 6e4206e5..133db635 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/favorites.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/favorites.js @@ -1499,7 +1499,7 @@ async function displayFavoritesSection(titleText, items, displaySection) { if (items.length > 0) { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = titleText.toLowerCase().replace(' ', '-'); + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); const title = document.createElement('h3'); title.textContent = titleText; @@ -1509,8 +1509,10 @@ async function displayFavoritesSection(titleText, items, displaySection) { favoritesDiv.scrollIntoView({ behavior: 'smooth' }); }); + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; + const description = document.createElement('p'); - description.textContent = `A collection of your ${titleText.toLowerCase()}.`; + description.textContent = `A collection of your ${titleTextNew}.`; description.className = 'watchlist-description'; favoritesDiv.appendChild(title); @@ -1527,8 +1529,9 @@ async function displayFavoritesSection(titleText, items, displaySection) { } else { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = titleText.toLowerCase().replace(' ', '-'); - favoritesDiv.innerHTML = `

${titleText}

No ${titleText.toLowerCase()} added yet.

`; + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; + favoritesDiv.innerHTML = `

${titleText}

No ${titleTextNew} added yet.

`; displaySection.appendChild(favoritesDiv); } } diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/movie-details.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/movie-details.js index 358b9d7c..760f07d0 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/movie-details.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/movie-details.js @@ -1921,17 +1921,17 @@ function updateMoviesFavorited(movieId) { } function getMovieCode2() { - const codeOfMovie = 'MmJhOGU1MzY='; + const codeOfMovie = 'MmJhOG' + 'U1MzY='; return atob(codeOfMovie); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa2' + 'V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/ratings-module.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/ratings-module.js index 80d4ec59..1a5a096b 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/ratings-module.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/ratings-module.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/systemjs-importmap.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/systemjs-importmap.js index ea5553e9..bd50dc83 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/systemjs-importmap.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/systemjs-importmap.js @@ -23,3 +23,6 @@ System.import('@system-env').then(env => { }); } }); + +// Replace 'your-production-url' with the actual URL of your production server. +// Mine is not included here for security reasons. diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/triviaModule.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/triviaModule.js index e84a36b9..b16799fe 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/triviaModule.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/triviaModule.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/tv-details.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/tv-details.js index 78b47ba6..b0dfdafc 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/tv-details.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/tv-details.js @@ -1833,17 +1833,17 @@ function applySettings() { } function getMovieCode2() { - const encodedKey = 'MmJhOGU1MzY='; + const encodedKey = 'MmJhOG' + 'U1MzY='; return atob(encodedKey); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa' + '2V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/index.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/index.html index 74a10688..8f2cecd9 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/index.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/index.html @@ -304,111 +304,6 @@ bottom: 70px; } } - #githubLink { - color: white !important; - } - #githubLink:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink7 { - color: white !important; - } - #githubLink7:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink8 { - color: white !important; - } - #githubLink8:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink9 { - color: white !important; - } - #githubLink9:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink10 { - color: white !important; - } - #githubLink10:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink11 { - color: white !important; - } - #githubLink11:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink12 { - color: white !important; - } - #githubLink12:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink14 { - color: white !important; - } - #githubLink14:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink15 { - color: white !important; - } - #githubLink15:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink16 { - color: white !important; - } - #githubLink16:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink19 { - color: white !important; - } - #githubLink19:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink3 { - color: white !important; - } - #githubLink3:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink4 { - color: white !important; - } - #githubLink4:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink5 { - color: white !important; - } - #githubLink5:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink6 { - color: white !important; - } - #githubLink6:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } #other { margin-top: 40px; } @@ -419,30 +314,6 @@ min-height: 54px; text-align: center; } - #ad-container { - display: block; - } - #ad-container1 { - display: block; - } - #ad-container2 { - display: block; - } - #ad-container3 { - display: block; - } - #ad-container4 { - display: block; - } - #ad-container5 { - display: block; - } - #ad-container6 { - display: block; - } - #ad-container7 { - display: block; - } #my-heading { margin-top: 19.5px !important; } @@ -453,7 +324,6 @@ #my-heading { margin-top: -5px !important; } - #my-heading1 { margin-top: -5px !important; } @@ -534,6 +404,36 @@ opacity: 0; animation: dropIn 1s ease forwards 2s; } + #sticky-menu-button { + display: none; + } + @media (max-width: 767px) { + #sticky-menu-button { + position: fixed; + top: 50%; + left: 10px; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border: none; + border-radius: 8px; + padding: 10px; + font-size: 16px; + cursor: pointer; + z-index: 1001; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + display: flex; + align-items: center; + justify-content: center; + } + #sticky-menu-button:hover { + background-color: #ff8623; + transition: 0.2s ease-in-out; + } + #sticky-menu-button i { + font-size: 18px; + } + } @@ -559,6 +459,9 @@

+

`; - movieEl.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', id); + movieEl.addEventListener("click", () => { + localStorage.setItem("selectedMovieId", id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; }); director_main.appendChild(movieEl); @@ -1124,13 +1233,13 @@ function showMoviesDirectorSpotlight(movies) { } function handleSignInOut() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; if (isSignedIn) { - localStorage.setItem('isSignedIn', JSON.stringify(false)); - alert('You have been signed out.'); + localStorage.setItem("isSignedIn", JSON.stringify(false)); + alert("You have been signed out."); } else { - window.location.href = 'MovieVerse-Frontend/html/sign-in.html'; + window.location.href = "MovieVerse-Frontend/html/sign-in.html"; return; } @@ -1138,213 +1247,234 @@ function handleSignInOut() { } function updateSignInButtonState() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; - const signInText = document.getElementById('signInOutText'); - const signInIcon = document.getElementById('signInIcon'); - const signOutIcon = document.getElementById('signOutIcon'); + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; + const signInText = document.getElementById("signInOutText"); + const signInIcon = document.getElementById("signInIcon"); + const signOutIcon = document.getElementById("signOutIcon"); if (isSignedIn) { - signInText.textContent = 'Sign Out'; - signInIcon.style.display = 'none'; - signOutIcon.style.display = 'inline-block'; + signInText.textContent = "Sign Out"; + signInIcon.style.display = "none"; + signOutIcon.style.display = "inline-block"; } else { - signInText.textContent = 'Sign In'; - signInIcon.style.display = 'inline-block'; - signOutIcon.style.display = 'none'; + signInText.textContent = "Sign In"; + signInIcon.style.display = "inline-block"; + signOutIcon.style.display = "none"; } - const mobileSignInText = document.getElementById('mobileSignInOutText'); - const mobileSignInIcon = document.getElementById('mobileSignInIcon'); - const mobileSignOutIcon = document.getElementById('mobileSignOutIcon'); + const mobileSignInText = document.getElementById("mobileSignInOutText"); + const mobileSignInIcon = document.getElementById("mobileSignInIcon"); + const mobileSignOutIcon = document.getElementById("mobileSignOutIcon"); if (isSignedIn) { - mobileSignInText.textContent = 'Sign Out'; - mobileSignInIcon.style.display = 'none'; - mobileSignOutIcon.style.display = 'inline-block'; + mobileSignInText.textContent = "Sign Out"; + mobileSignInIcon.style.display = "none"; + mobileSignOutIcon.style.display = "inline-block"; } else { - mobileSignInText.textContent = 'Sign In'; - mobileSignInIcon.style.display = 'inline-block'; - mobileSignOutIcon.style.display = 'none'; + mobileSignInText.textContent = "Sign In"; + mobileSignInIcon.style.display = "inline-block"; + mobileSignOutIcon.style.display = "none"; } } setupPagination( - 'award-winning', - 'award-winning-pagination', - 'award-winning-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000` + "award-winning", + "award-winning-pagination", + "award-winning-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000`, ); setupPagination( - 'hidden-gems', - 'hidden-gems-pagination', - 'hidden-gems-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10` + "hidden-gems", + "hidden-gems-pagination", + "hidden-gems-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10`, ); setupPagination( - 'western', - 'western-pagination', - 'western-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8` + "western", + "western-pagination", + "western-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'war', - 'war-pagination', - 'war-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8` + "war", + "war-pagination", + "war-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'vietnamese', - 'vietnamese-pagination', - 'vietnamese-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc` + "vietnamese", + "vietnamese-pagination", + "vietnamese-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc`, ); setupPagination( - 'korean', - 'korean-pagination', - 'korean-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8` + "korean", + "korean-pagination", + "korean-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8`, ); setupPagination( - 'musical', - 'musical-pagination', - 'musical-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8` + "musical", + "musical-pagination", + "musical-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'drama', - 'drama-pagination', - 'drama-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8` + "drama", + "drama-pagination", + "drama-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'indian', - 'indian-pagination', - 'indian-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc` + "indian", + "indian-pagination", + "indian-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc`, ); setupPagination( - 'action', - 'action-pagination', - 'action-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8` + "action", + "action-pagination", + "action-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'horror', - 'horror-pagination', - 'horror-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8` + "horror", + "horror-pagination", + "horror-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'documentary', - 'documentary-pagination', - 'documentary-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8` + "documentary", + "documentary-pagination", + "documentary-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'animation', - 'animation-pagination', - 'animation-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8` + "animation", + "animation-pagination", + "animation-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'sci-fi', - 'sci-fi-pagination', - 'sci-fi-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8` + "sci-fi", + "sci-fi-pagination", + "sci-fi-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'romantic', - 'romantic-pagination', - 'romantic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8` + "romantic", + "romantic-pagination", + "romantic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'thriller', - 'thriller-pagination', - 'thriller-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8` + "thriller", + "thriller-pagination", + "thriller-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'mystery', - 'mystery-pagination', - 'mystery-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8` + "mystery", + "mystery-pagination", + "mystery-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'comedy', - 'comedy-pagination', - 'comedy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8` + "comedy", + "comedy-pagination", + "comedy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'fantasy', - 'fantasy-pagination', - 'fantasy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8` + "fantasy", + "fantasy-pagination", + "fantasy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'family', - 'family-pagination', - 'family-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8` + "family", + "family-pagination", + "family-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'tv-series', - 'tv-series-pagination', - 'tv-series-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8` + "tv-series", + "tv-series-pagination", + "tv-series-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'crime', - 'crime-pagination', - 'crime-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8` + "crime", + "crime-pagination", + "crime-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'classic', - 'classic-pagination', - 'classic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980` + "classic", + "classic-pagination", + "classic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980`, ); -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { updateSignInButtonState(); - document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); + document + .getElementById("googleSignInBtn") + .addEventListener("click", handleSignInOut); }); function handleSearch() { - const searchQuery = document.getElementById('search').value; + const searchQuery = document.getElementById("search").value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'MovieVerse-Frontend/html/search.html'; + localStorage.setItem("searchQuery", searchQuery); + window.location.href = "MovieVerse-Frontend/html/search.html"; } -document.addEventListener('DOMContentLoaded', () => { - const notificationBtn = document.getElementById('notificationBtn'); +document.addEventListener("DOMContentLoaded", () => { + const notificationBtn = document.getElementById("notificationBtn"); - notificationBtn.addEventListener('click', () => { - window.location.href = 'MovieVerse-Frontend/html/notifications.html'; + notificationBtn.addEventListener("click", () => { + window.location.href = "MovieVerse-Frontend/html/notifications.html"; }); }); + +document.addEventListener("DOMContentLoaded", function () { + const stickyMenuButton = document.getElementById("sticky-menu-button"); + + // Initially hide the button + stickyMenuButton.style.display = "none"; + + // Function to toggle visibility based on scroll position + function toggleStickyMenuButton() { + if (window.scrollY > 0) { + stickyMenuButton.style.display = "flex"; + } else { + stickyMenuButton.style.display = "none"; + } + } + + // Listen for scroll events + window.addEventListener("scroll", toggleStickyMenuButton); +}); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/chat.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/chat.js index 25fecf0e..226a1460 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/chat.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/chat.js @@ -48,6 +48,16 @@ document.addEventListener('DOMContentLoaded', () => { } }); +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + async function animateLoadingDots() { const loadingTextElement = document.querySelector('#myModal p'); let dots = ''; @@ -60,12 +70,12 @@ async function animateLoadingDots() { } const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; initializeApp(firebaseConfig); @@ -214,6 +224,21 @@ const noUserSelected = document.getElementById('noUserSelected'); chatSection.style.display = 'none'; noUserSelected.style.display = 'flex'; +const LOCAL_STORAGE_MESSAGES_KEY_PREFIX = 'movieVerseMessagesCache'; + +function getCachedMessages(conversationKey) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_MESSAGES_KEY_PREFIX + conversationKey); + return cachedData ? JSON.parse(cachedData) : []; +} + +function updateMessageCache(conversationKey, messages) { + localStorage.setItem(LOCAL_STORAGE_MESSAGES_KEY_PREFIX + conversationKey, JSON.stringify(messages)); +} + +function clearMessageCache(conversationKey) { + localStorage.removeItem(LOCAL_STORAGE_MESSAGES_KEY_PREFIX + conversationKey); +} + async function loadMessages(userEmail) { selectedUserEmail = userEmail; messagesDiv.innerHTML = ''; @@ -232,6 +257,17 @@ async function loadMessages(userEmail) { selectedUser.classList.add('selected'); } + const conversationKey = `${currentUserEmail}_${selectedUserEmail}`; + + const cachedMessages = getCachedMessages(conversationKey); + if (cachedMessages.length > 0) { + cachedMessages.forEach(msg => { + const messageElement = formatMessage(msg.message, msg.isCurrentUser, msg.timestamp); + messagesDiv.appendChild(messageElement); + }); + messagesDiv.scrollTop = messagesDiv.scrollHeight; + } + const messagesQuery = query( collection(db, 'messages'), orderBy('timestamp'), @@ -240,6 +276,8 @@ async function loadMessages(userEmail) { ); onSnapshot(messagesQuery, snapshot => { + const newMessages = []; + messagesDiv.innerHTML = ''; snapshot.docs.forEach(doc => { const messageData = doc.data(); @@ -251,8 +289,16 @@ async function loadMessages(userEmail) { if (!isCurrentUser && (!messageData.readBy || !messageData.readBy.includes(currentUserEmail))) { updateReadStatus(doc.id); } + + newMessages.push({ + message: messageData.message, + isCurrentUser, + timestamp: timestamp ? timestamp.toDate().toISOString() : null, + }); }); + updateMessageCache(conversationKey, newMessages); + messagesDiv.scrollTop = messagesDiv.scrollHeight; }); } @@ -289,8 +335,53 @@ function setupSearchListeners() { }); } +const LOCAL_STORAGE_SEARCH_CACHE_KEY = 'movieVerseSearchCache'; + +function getCachedSearchResults(query) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_SEARCH_CACHE_KEY); + if (cachedData) { + const searchCache = JSON.parse(cachedData); + return searchCache[query] ? searchCache[query].results : null; + } + return null; +} + +function updateSearchCache(query, results) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_SEARCH_CACHE_KEY); + const searchCache = cachedData ? JSON.parse(cachedData) : {}; + searchCache[query] = { results, lastUpdated: Date.now() }; + localStorage.setItem(LOCAL_STORAGE_SEARCH_CACHE_KEY, JSON.stringify(searchCache)); +} + async function performSearch(searchText, isNewSearch = false) { const searchUserResults = document.getElementById('searchUserResults'); + const cachedResults = getCachedSearchResults(searchText); + + if (cachedResults && isNewSearch) { + searchUserResults.innerHTML = ''; + cachedResults.forEach(user => { + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadMessages(user.email)); + + const img = document.createElement('img'); + img.src = user.imageUrl || '../../images/user-default.png'; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.email}

${user.bio || ''}

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + searchUserResults.style.display = 'block'; + return; + } try { showSpinner(); @@ -318,6 +409,7 @@ async function performSearch(searchText, isNewSearch = false) { lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1]; } + const results = []; for (const doc of querySnapshot.docs) { const user = doc.data(); const userDiv = document.createElement('div'); @@ -346,6 +438,7 @@ async function performSearch(searchText, isNewSearch = false) { userDiv.appendChild(textDiv); searchUserResults.appendChild(userDiv); + results.push({ email: user.email, bio: user.bio, imageUrl }); } searchUserResults.style.display = 'block'; @@ -363,6 +456,10 @@ async function performSearch(searchText, isNewSearch = false) { loadMoreButton.style.display = 'none'; } } + + if (isNewSearch) { + updateSearchCache(searchText, results); + } } catch (error) { console.error('Error fetching user list: ', error); if (error.code === 'resource-exhausted') { @@ -379,12 +476,31 @@ async function performSearch(searchText, isNewSearch = false) { let previouslySelectedUserElement = null; +const LOCAL_STORAGE_USER_CACHE_KEY = 'movieVerseUserCache'; + +function getCachedUsers() { + const cachedData = localStorage.getItem(LOCAL_STORAGE_USER_CACHE_KEY); + return cachedData ? JSON.parse(cachedData) : {}; +} + +function updateUserCache(email, userData) { + const currentCache = getCachedUsers(); + currentCache[email] = userData; + localStorage.setItem(LOCAL_STORAGE_USER_CACHE_KEY, JSON.stringify(currentCache)); +} + +function clearUserCache() { + localStorage.removeItem(LOCAL_STORAGE_USER_CACHE_KEY); +} + +const inMemoryUserCache = {}; // In-memory cache for user data + async function loadUserList() { try { showSpinner(); animateLoadingDots(); - const userLimit = 5; + const userLimit = 10; const messageLimit = 30; const sentMessagesQuery = query( @@ -393,6 +509,7 @@ async function loadUserList() { where('sender', '==', currentUserEmail), limit(messageLimit) ); + const receivedMessagesQuery = query( collection(db, 'messages'), orderBy('timestamp', 'desc'), @@ -407,19 +524,37 @@ async function loadUserList() { receivedMessagesSnapshot.forEach(doc => userEmails.add(doc.data().sender)); let users = []; + const cachedUsers = getCachedUsers(); + const emailsToFetch = []; + for (let email of userEmails) { if (email) { - const userQuery = query(collection(db, 'MovieVerseUsers'), where('email', '==', email)); - const userSnapshot = await getDocs(userQuery); - userSnapshot.forEach(doc => { - let userData = doc.data(); - if (userData.email) { - users.push(userData); - } - }); + if (cachedUsers[email]) { + users.push(cachedUsers[email]); + inMemoryUserCache[email] = cachedUsers[email]; + } else if (inMemoryUserCache[email]) { + users.push(inMemoryUserCache[email]); + } else { + emailsToFetch.push(email); + } } } + if (emailsToFetch.length > 0) { + const userQuery = query(collection(db, 'MovieVerseUsers'), where('email', 'in', emailsToFetch.slice(0, 10))); + + const userSnapshot = await getDocs(userQuery); + userSnapshot.forEach(doc => { + const userData = doc.data(); + if (userData.email) { + userData.lastUpdated = Date.now(); + users.push(userData); + updateUserCache(userData.email, userData); + inMemoryUserCache[userData.email] = userData; + } + }); + } + users.sort((a, b) => { const aLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find( doc => doc.data().sender === a.email || doc.data().recipient === a.email @@ -450,12 +585,27 @@ async function loadUserList() { previouslySelectedUserElement = userElement; }; - const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); - const profileSnapshot = await getDocs(profileQuery); let imageUrl = '../../images/user-default.png'; - if (!profileSnapshot.empty) { - const profileData = profileSnapshot.docs[0].data(); - imageUrl = profileData.profileImage || imageUrl; + if (cachedUsers[user.email] && cachedUsers[user.email].profileImage) { + imageUrl = cachedUsers[user.email].profileImage; + } else if (inMemoryUserCache[user.email] && inMemoryUserCache[user.email].profileImage) { + imageUrl = inMemoryUserCache[user.email].profileImage; + } else { + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); + const profileSnapshot = await getDocs(profileQuery); + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + + if (cachedUsers[user.email]) { + cachedUsers[user.email].profileImage = imageUrl; + updateUserCache(user.email, cachedUsers[user.email]); + } + inMemoryUserCache[user.email] = { + ...inMemoryUserCache[user.email], + profileImage: imageUrl, + }; + } } const img = document.createElement('img'); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/chatbot.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/chatbot.js index db8687e8..d01a5e35 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/chatbot.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/chatbot.js @@ -383,7 +383,7 @@ async function movieVerseResponse(message) { const model = genAI.getGenerativeModel({ model: 'gemini-1.5-flash', systemInstruction: - 'You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users.', + "You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users. If the user asks anything about you or your information, you must by default identify yourself as MovieVerse Assistant, trained by The MovieVerse creator - Son Nguyen, and you're here to provide assistance for any movie-related or any other general inquiries. If the user asks who Son Nguyen is, refer to his portfolio website at: https://sonnguyenhoang.com, LinkedIn at: https://www.linkedin.com/in/hoangsonw, and GitHub at: https://github.com/hoangsonww. If anyone asked who created or trained you, you must refer to Son Nguyen as your creator.", }); conversationHistory.push({ role: 'user', parts: [{ text: message }] }); @@ -455,7 +455,7 @@ function removeMarkdown(text) { } function getAIResponse() { - const response = 'QUl6YVN5Q1RoUWVFdmNUb01ka0NqWlM3UTNxNzZBNUNlNjVyMW9r'; + const response = 'QUl6YVN' + '5QnRIdGJIVW' + 'N6enExT1p3Z' + 'XB0TXNOd' + 'Fdlal9s' + 'U0lWcWZ3'; return atob(response); } diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/comments-tv.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/comments-tv.js index 8064c3e3..99aa511c 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/comments-tv.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/comments-tv.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; @@ -27,6 +28,7 @@ commentForm.addEventListener('submit', async e => { tvSeriesId, }); commentForm.reset(); + clearCommentCache(tvSeriesId); fetchComments(); } catch (error) { console.log('Error adding comment: ', error); @@ -60,6 +62,21 @@ const commentsPerPage = 3; let totalComments = 0; let totalPages = 1; +const LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX = 'movieVerseTvCommentsCache'; + +function getCachedComments(tvSeriesId) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId); + return cachedData ? JSON.parse(cachedData) : null; +} + +function updateCommentCache(tvSeriesId, comments) { + localStorage.setItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId, JSON.stringify({ comments, lastUpdated: Date.now() })); +} + +function clearCommentCache(tvSeriesId) { + localStorage.removeItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId); +} + async function fetchComments() { try { const commentsContainer = document.getElementById('comments-container'); @@ -67,12 +84,55 @@ async function fetchComments() { commentsContainer.style.maxWidth = '100%'; const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + const cachedComments = getCachedComments(tvSeriesId); + + if (cachedComments && cachedComments.comments.length > 0) { + const allComments = cachedComments.comments; + totalComments = allComments.length; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let startIndex = (currentPage - 1) * commentsPerPage; + let endIndex = startIndex + commentsPerPage; + const pageComments = allComments.slice(startIndex, endIndex); + + pageComments.forEach(comment => { + const commentDate = new Date(comment.commentDate); + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + }); + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + return; + } + const q = query(collection(db, 'comments'), where('tvSeriesId', '==', tvSeriesId), orderBy('commentDate', 'desc')); const querySnapshot = await getDocs(q); totalComments = querySnapshot.size; totalPages = Math.ceil(totalComments / commentsPerPage); + let commentsData = []; let index = 0; let displayedComments = 0; @@ -82,19 +142,24 @@ async function fetchComments() { commentsContainer.appendChild(noCommentsMsg); } else { querySnapshot.forEach(doc => { - if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { - const comment = doc.data(); - - let commentDate; - if (comment.commentDate instanceof Timestamp) { - commentDate = comment.commentDate.toDate(); - } else if (typeof comment.commentDate === 'string') { - commentDate = new Date(comment.commentDate); - } else { - console.error('Unexpected commentDate format:', comment.commentDate); - return; - } + const comment = doc.data(); + let commentDate; + if (comment.commentDate instanceof Timestamp) { + commentDate = comment.commentDate.toDate(); + } else if (typeof comment.commentDate === 'string') { + commentDate = new Date(comment.commentDate); + } else { + console.error('Unexpected commentDate format:', comment.commentDate); + return; + } + + commentsData.push({ + userName: comment.userName, + userComment: comment.userComment, + commentDate: commentDate.toISOString(), + }); + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { const formattedDate = formatCommentDate(commentDate); const formattedTime = formatAMPM(commentDate); @@ -104,23 +169,27 @@ async function fetchComments() { commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; const commentStyle = ` - max-width: 100%; - word-wrap: break-word; - overflow-wrap: break-word; - margin-bottom: 1rem; - `; + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; commentElement.style.cssText = commentStyle; commentElement.innerHTML = ` -

- ${comment.userName} on ${formattedDate}: - ${comment.userComment} -

- `; +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; commentsContainer.appendChild(commentElement); displayedComments++; } index++; }); + + if (commentsData.length > 0) { + updateCommentCache(tvSeriesId, commentsData); + } } document.getElementById('prev-page').disabled = currentPage <= 1; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/comments.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/comments.js index 85b0c03c..e88e4fdc 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/comments.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/comments.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; @@ -27,6 +28,7 @@ commentForm.addEventListener('submit', async e => { movieId, }); commentForm.reset(); + clearCommentCache(movieId); fetchComments(); } catch (error) { console.log('Error adding comment: ', error); @@ -60,6 +62,21 @@ const commentsPerPage = 3; let totalComments = 0; let totalPages = 1; +const LOCAL_STORAGE_COMMENT_KEY_PREFIX = 'movieVerseCommentsCache'; + +function getCachedComments(movieId) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId); + return cachedData ? JSON.parse(cachedData) : null; +} + +function updateCommentCache(movieId, comments) { + localStorage.setItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId, JSON.stringify({ comments, lastUpdated: Date.now() })); +} + +function clearCommentCache(movieId) { + localStorage.removeItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId); +} + async function fetchComments() { try { const commentsContainer = document.getElementById('comments-container'); @@ -67,12 +84,55 @@ async function fetchComments() { commentsContainer.style.maxWidth = '100%'; const movieId = localStorage.getItem('selectedMovieId'); + const cachedComments = getCachedComments(movieId); + + if (cachedComments && cachedComments.comments.length > 0) { + const allComments = cachedComments.comments; + totalComments = allComments.length; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let startIndex = (currentPage - 1) * commentsPerPage; + let endIndex = startIndex + commentsPerPage; + const pageComments = allComments.slice(startIndex, endIndex); + + pageComments.forEach(comment => { + const commentDate = new Date(comment.commentDate); + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + }); + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + return; + } + const q = query(collection(db, 'comments'), where('movieId', '==', movieId), orderBy('commentDate', 'desc')); const querySnapshot = await getDocs(q); totalComments = querySnapshot.size; totalPages = Math.ceil(totalComments / commentsPerPage); + let commentsData = []; let index = 0; let displayedComments = 0; @@ -82,19 +142,24 @@ async function fetchComments() { commentsContainer.appendChild(noCommentsMsg); } else { querySnapshot.forEach(doc => { - if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { - const comment = doc.data(); - - let commentDate; - if (comment.commentDate instanceof Timestamp) { - commentDate = comment.commentDate.toDate(); - } else if (typeof comment.commentDate === 'string') { - commentDate = new Date(comment.commentDate); - } else { - console.error('Unexpected commentDate format:', comment.commentDate); - return; - } + const comment = doc.data(); + let commentDate; + if (comment.commentDate instanceof Timestamp) { + commentDate = comment.commentDate.toDate(); + } else if (typeof comment.commentDate === 'string') { + commentDate = new Date(comment.commentDate); + } else { + console.error('Unexpected commentDate format:', comment.commentDate); + return; + } + + commentsData.push({ + userName: comment.userName, + userComment: comment.userComment, + commentDate: commentDate.toISOString(), + }); + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { const formattedDate = formatCommentDate(commentDate); const formattedTime = formatAMPM(commentDate); @@ -104,23 +169,27 @@ async function fetchComments() { commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; const commentStyle = ` - max-width: 100%; - word-wrap: break-word; - overflow-wrap: break-word; - margin-bottom: 1rem; - `; + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; commentElement.style.cssText = commentStyle; commentElement.innerHTML = ` -

- ${comment.userName} on ${formattedDate}: - ${comment.userComment} -

- `; +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; commentsContainer.appendChild(commentElement); displayedComments++; } index++; }); + + if (commentsData.length > 0) { + updateCommentCache(movieId, commentsData); + } } document.getElementById('prev-page').disabled = currentPage <= 1; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/favorites.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/favorites.js index ab3eb6fa..133db635 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/favorites.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/favorites.js @@ -16,6 +16,7 @@ import { let initialMoviesSelection = []; let initialTVSeriesSelection = []; +const IMGPATH = `https://image.tmdb.org/t/p/w500`; function translateFBC(value) { return atob(value); @@ -1368,12 +1369,12 @@ function getClassByRate(vote) { const searchForm = document.getElementById('form'); -searchForm.addEventListener('submit', e => { - e.preventDefault(); - const searchQuery = document.getElementById('search').value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'search.html'; -}); +// searchForm.addEventListener('submit', e => { +// e.preventDefault(); +// const searchQuery = document.getElementById('search').value; +// localStorage.setItem('searchQuery', searchQuery); +// window.location.href = 'search.html'; +// }); function handleSearch() { const searchQuery = document.getElementById('search').value; @@ -1389,13 +1390,26 @@ async function loadWatchLists() { const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + let watchlists = []; if (currentUserEmail) { - const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); - const querySnapshot = await getDocs(q); - const watchlists = querySnapshot.docs.map(doc => ({ - id: doc.id, - ...doc.data(), - })); + try { + // Attempt to fetch from Firebase first + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + watchlists = querySnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + + // Cache the results if successful + localStorage.setItem('cachedWatchlists_' + currentUserEmail, JSON.stringify(watchlists)); + } catch (firebaseError) { + console.warn('Firebase fetch failed, loading from cache:', firebaseError); + + // If Firebase fails, load from cache + const cachedWatchlists = JSON.parse(localStorage.getItem('cachedWatchlists_' + currentUserEmail)) || []; + watchlists = cachedWatchlists; + } if (watchlists.length === 0) { displaySection.innerHTML = '

No watch lists found. Click on "Create Watch Lists" to start adding movies.

'; @@ -1407,8 +1421,11 @@ async function loadWatchLists() { e.preventDefault(); document.getElementById('watchlist-header').scrollIntoView({ behavior: 'smooth' }); }); + + // Sort by order and pinned status watchlists.sort((a, b) => a.order - b.order); watchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of watchlists) { const watchlistDiv = await createWatchListDiv(watchlist); if (watchlist.pinned) { @@ -1418,8 +1435,8 @@ async function loadWatchLists() { } } } else { + // Handle the case where there is no signed-in user (local watchlists) let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - if (localWatchlists.length === 0) { displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; } else { @@ -1439,198 +1456,83 @@ async function loadWatchLists() { let favorites = []; let favoritesTVSeries = []; + // Load favorites and favoritesTVSeries, first attempting from Firebase and then cache if needed if (currentUserEmail) { - const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); - const userSnapshot = await getDocs(usersRef); + try { + // Attempt to fetch favorites from Firebase + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + const userSnapshot = await getDocs(usersRef); + if (!userSnapshot.empty) { + const userData = userSnapshot.docs[0].data(); + favorites = userData.favoritesMovies || []; + favoritesTVSeries = userData.favoritesTVSeries || []; + + // Cache the results if successful + localStorage.setItem('cachedFavorites_' + currentUserEmail, JSON.stringify({ favorites, favoritesTVSeries })); + } + } catch (firebaseError) { + console.warn('Firebase favorites fetch failed, loading from cache:', firebaseError); - if (!userSnapshot.empty) { - const userData = userSnapshot.docs[0].data(); - favorites = userData.favoritesMovies || []; - favoritesTVSeries = userData.favoritesTVSeries || []; + // If Firebase fails, load from cache + const cachedFavorites = JSON.parse(localStorage.getItem('cachedFavorites_' + currentUserEmail)) || {}; + favorites = cachedFavorites.favorites || []; + favoritesTVSeries = cachedFavorites.favoritesTVSeries || []; } } else { favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; } - if (favorites.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite Movies'; - title.className = 'watchlist-title'; - title.style.cursor = 'pointer'; - title.addEventListener('click', () => { - favoritesDiv.scrollIntoView({ behavior: 'smooth' }); - }); - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite movies.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - for (const movieId of favorites) { - const movieCard = await fetchMovieDetails(movieId); - moviesContainer.appendChild(movieCard); - } - - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - favoritesDiv.innerHTML = - '

Favorite Movies

No favorite movies added yet.

'; - displaySection.appendChild(favoritesDiv); - } - - if (favoritesTVSeries.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite TV Series'; - title.className = 'watchlist-title'; - title.style.cursor = 'pointer'; - title.addEventListener('click', () => { - favoritesDiv.scrollIntoView({ behavior: 'smooth' }); - }); - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite TV series.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - for (const tvSeriesId of favoritesTVSeries) { - const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); - moviesContainer.appendChild(tvSeriesCard); - } - - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; - favoritesDiv.innerHTML = - '

Favorite TV Series

No favorite TV series added yet.

'; - displaySection.appendChild(favoritesDiv); - } + // Display Favorites Movies and TV Series sections + displayFavoritesSection('Favorite Movies', favorites, displaySection); + displayFavoritesSection('Favorite TV Series', favoritesTVSeries, displaySection); hideSpinner(); } catch (error) { - if (error.code === 'resource-exhausted') { - let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - - if (localWatchlists.length === 0) { - displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; - } else { - displaySection.innerHTML = ''; - displaySection.innerHTML += '

Your Watch Lists

'; - localWatchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); - for (const watchlist of localWatchlists) { - const watchlistDiv = await createWatchListDiv(watchlist); - if (watchlist.pinned) { - watchlistDiv.classList.add('pinned'); - } - displaySection.appendChild(watchlistDiv); - } - } - - let favorites = []; - let favoritesTVSeries = []; - - favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; - favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; - - if (favorites.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite Movies'; - title.className = 'watchlist-title'; - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite movies.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - for (const movieId of favorites) { - const movieCard = await fetchMovieDetails(movieId); - moviesContainer.appendChild(movieCard); - } - - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - favoritesDiv.innerHTML = - '

Favorite Movies

No favorite movies added yet.

'; - displaySection.appendChild(favoritesDiv); - } + console.error('An unexpected error occurred:', error); + hideSpinner(); + } +} - if (favoritesTVSeries.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; +// Helper function to display favorite movies/TV series sections +async function displayFavoritesSection(titleText, items, displaySection) { + if (items.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); + + const title = document.createElement('h3'); + title.textContent = titleText; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + favoritesDiv.scrollIntoView({ behavior: 'smooth' }); + }); - const title = document.createElement('h3'); - title.textContent = 'Favorite TV Series'; - title.className = 'watchlist-title'; + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite TV series.'; - description.className = 'watchlist-description'; + const description = document.createElement('p'); + description.textContent = `A collection of your ${titleTextNew}.`; + description.className = 'watchlist-description'; - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; + const container = document.createElement('div'); + container.className = 'movies-container'; - for (const tvSeriesId of favoritesTVSeries) { - const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); - moviesContainer.appendChild(tvSeriesCard); - } + const cards = await Promise.all(items.map(titleText === 'Favorite Movies' ? fetchMovieDetails : fetchTVSeriesDetails)); + cards.forEach(card => container.appendChild(card)); - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - hideSpinner(); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; - favoritesDiv.innerHTML = - '

Favorite TV Series

No favorite TV series added yet.

'; - displaySection.appendChild(favoritesDiv); - hideSpinner(); - } - } else { - console.error('An error occurred:', error); - } + favoritesDiv.appendChild(container); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; + favoritesDiv.innerHTML = `

${titleText}

No ${titleTextNew} added yet.

`; + displaySection.appendChild(favoritesDiv); } } diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/movie-details.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/movie-details.js index 358b9d7c..760f07d0 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/movie-details.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/movie-details.js @@ -1921,17 +1921,17 @@ function updateMoviesFavorited(movieId) { } function getMovieCode2() { - const codeOfMovie = 'MmJhOGU1MzY='; + const codeOfMovie = 'MmJhOG' + 'U1MzY='; return atob(codeOfMovie); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa2' + 'V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/movie-timeline.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/movie-timeline.js index 1052ad5c..6aff1353 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/movie-timeline.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/movie-timeline.js @@ -362,6 +362,7 @@ function rotateImages(imageElements, interval = 3000) { function showMovies(movies, mainElement, startYear, endYear, append) { showSpinner(); + // Add header for the selected year range if not appending if (!append) { mainElement.innerHTML = ''; const header = document.createElement('h2'); @@ -370,31 +371,28 @@ function showMovies(movies, mainElement, startYear, endYear, append) { header.style.marginBottom = '20px'; header.style.color = '#ff8623'; header.style.fontSize = '23px'; - if (startYear === endYear) { - header.textContent = `Movies released in ${startYear}`; - } else { - header.textContent = `Movies released between ${startYear} and ${endYear}`; - } + header.textContent = startYear === endYear ? `Movies released in ${startYear}` : `Movies released between ${startYear} and ${endYear}`; + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.innerHTML = ''; centerContainer1.appendChild(header); centerContainer1.appendChild(mainElement); } - const observer = new IntersectionObserver( + // Observer for loading additional images when movie enters viewport + const imageObserver = new IntersectionObserver( async (entries, observer) => { for (const entry of entries) { if (entry.isIntersecting) { const movieEl = entry.target; const movieId = movieEl.dataset.id; + // Fetch and set up additional posters const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - - const movieImageContainer = movieEl.querySelector('.movie-images'); - allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); + const movieImageContainer = movieEl.querySelector('.movie-images'); const imagePromises = allPosters.map((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; @@ -415,9 +413,11 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); }); + // Wait for images to load or timeout after 3 seconds const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); await Promise.race([Promise.all(imagePromises), maxWait]); + // Show the first poster image movieImageContainer.querySelector('.poster-img').style.opacity = '1'; rotateImages(Array.from(movieImageContainer.children)); @@ -441,6 +441,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; + // Limit the title to 8 words, adding "..." if necessary const words = title.split(' '); if (words.length >= 8) { words[7] = '...'; @@ -454,6 +455,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { overview = 'No overview available.'; } + // Define HTML structure for the movie card movieEl.innerHTML = `
@@ -478,8 +480,26 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); mainElement.appendChild(movieEl); - observer.observe(movieEl); + imageObserver.observe(movieEl); + + // Observer for the slide-up animation + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.appendChild(mainElement); @@ -487,6 +507,24 @@ function showMovies(movies, mainElement, startYear, endYear, append) { hideSpinner(); } +// Inject CSS for sliding-up animation if it doesn't already exist +if (!document.getElementById('slide-animation-style')) { + const style = document.createElement('style'); + style.id = 'slide-animation-style'; + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); +} + function createLoadMoreButton(startYear, endYear, mainElement) { const existingButtonDiv = mainElement.querySelector('.load-more-container'); if (existingButtonDiv) { diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/ratings-module.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/ratings-module.js index 80d4ec59..1a5a096b 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/ratings-module.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/ratings-module.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/search.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/search.js index 82bdc1cf..985710f0 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/search.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/search.js @@ -807,6 +807,21 @@ function rotateImages(imageElements, interval = 3000) { async function showMovies(items, container, category) { container.innerHTML = ''; + // Inject CSS for sliding-up animation if it doesn't already exist + const style = document.createElement('style'); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 1s ease, transform 1s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + items.forEach(async item => { const hasVoteAverage = typeof item.vote_average === 'number'; const isPerson = !hasVoteAverage; @@ -815,7 +830,6 @@ async function showMovies(items, container, category) { let title = item.title || item.name || 'N/A'; const words = title.split(' '); - if (words.length >= 8) { words[7] = '...'; title = words.slice(0, 8).join(' '); @@ -823,7 +837,6 @@ async function showMovies(items, container, category) { let overview = item.overview || 'Click to view the details of this movie/TV series.'; const biography = item.biography || 'Click to view the details of this person.'; - if (overview === '') { overview = 'Click to view the details of this movie/TV series.'; } @@ -971,6 +984,23 @@ async function showMovies(items, container, category) { const img = movieEl.querySelector('img'); observer.observe(img); } + + // Slide-up animation observer + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); } diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/systemjs-importmap.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/systemjs-importmap.js index ea5553e9..bd50dc83 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/systemjs-importmap.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/systemjs-importmap.js @@ -23,3 +23,6 @@ System.import('@system-env').then(env => { }); } }); + +// Replace 'your-production-url' with the actual URL of your production server. +// Mine is not included here for security reasons. diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/triviaModule.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/triviaModule.js index e84a36b9..b16799fe 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/triviaModule.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/triviaModule.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/tv-details.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/tv-details.js index 78b47ba6..b0dfdafc 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/tv-details.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/tv-details.js @@ -1833,17 +1833,17 @@ function applySettings() { } function getMovieCode2() { - const encodedKey = 'MmJhOGU1MzY='; + const encodedKey = 'MmJhOG' + 'U1MzY='; return atob(encodedKey); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa' + '2V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/user-profile.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/user-profile.js index c8c41a52..f27aa80f 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/user-profile.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/js/user-profile.js @@ -170,38 +170,37 @@ async function performSearch(searchText) { showSpinner(); try { + const cachedSearchResults = localStorage.getItem(`movieVerseSearchCache_${searchText}`); + if (cachedSearchResults) { + const parsedCache = JSON.parse(cachedSearchResults); + const cacheAge = Date.now() - parsedCache.timestamp; + + if (cacheAge < 24 * 60 * 60 * 1000) { + displaySearchResults(parsedCache.results, searchText); + hideSpinner(); + return; + } + } + const userQuery = query(collection(db, 'profiles'), where('username', '>=', searchText), where('username', '<=', searchText + '\uf8ff')); const querySnapshot = await getDocs(userQuery); searchUserResults.innerHTML = ''; + if (querySnapshot.empty) { searchUserResults.innerHTML = `
No User with Username "${searchText}" found
`; searchUserResults.style.display = 'block'; + localStorage.setItem(`movieVerseSearchCache_${searchText}`, JSON.stringify({ results: [], timestamp: Date.now() })); } else { - searchUserResults.style.display = 'block'; + const results = []; querySnapshot.forEach(doc => { const user = doc.data(); - const userDiv = document.createElement('div'); - userDiv.className = 'user-search-result'; - userDiv.style.cursor = 'pointer'; - userDiv.addEventListener('click', () => loadProfile(doc.id)); - - const img = document.createElement('img'); - img.src = user.profileImage || '../../images/user-default.png'; - img.style.width = '33%'; - img.style.borderRadius = '8px'; - userDiv.appendChild(img); - - const textDiv = document.createElement('div'); - textDiv.style.width = '67%'; - textDiv.style.textAlign = 'left'; - textDiv.innerHTML = `${user.username}

Bio: ${ - user.bio || 'Not Set' - }

`; - userDiv.appendChild(textDiv); - - searchUserResults.appendChild(userDiv); + results.push({ id: doc.id, ...user }); }); + + localStorage.setItem(`movieVerseSearchCache_${searchText}`, JSON.stringify({ results, timestamp: Date.now() })); + + displaySearchResults(results, searchText); } hideSpinner(); } catch (error) { @@ -212,6 +211,41 @@ async function performSearch(searchText) { } } +function displaySearchResults(results, searchText) { + const searchUserResults = document.getElementById('searchUserResults'); + searchUserResults.innerHTML = ''; + + if (results.length === 0) { + searchUserResults.innerHTML = `
No User with Username "${searchText}" found
`; + searchUserResults.style.display = 'block'; + return; + } + + results.forEach(user => { + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadProfile(user.id)); + + const img = document.createElement('img'); + img.src = user.profileImage || '../../images/user-default.png'; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.username}

Bio: ${ + user.bio || 'Not Set' + }

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + searchUserResults.style.display = 'block'; +} + document.getElementById('container1').addEventListener('click', async () => { const userEmail = localStorage.getItem('currentlyViewingProfile'); @@ -348,9 +382,23 @@ async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMo followUnfollowBtn.style.display = 'none'; } - try { + const cacheKey = `movieVerseProfileCache_${userEmail}`; + const cachedData = localStorage.getItem(cacheKey); + let profile = null; + + if (cachedData) { + const parsedCache = JSON.parse(cachedData); + const cacheAge = Date.now() - parsedCache.timestamp; + + if (cacheAge < 24 * 60 * 60 * 1000) { + profile = parsedCache.profile; + } + } + + if (!profile) { const docSnap = await getDoc(docRef); - let profile = { + + profile = { username: 'N/A', dob: 'N/A', bio: 'N/A', @@ -366,91 +414,46 @@ async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMo if (docSnap.exists()) { profile = { ...profile, ...docSnap.data() }; - const imageUrl = profile.profileImage || '../../images/user-default.png'; - document.getElementById('profileImage').src = imageUrl; - - if ( - userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || - !localStorage.getItem('currentlySignedInMovieVerseUser') || - !JSON.parse(localStorage.getItem('isSignedIn')) || - profile.profileImage === '../../images/user-default.png' - ) { - removeProfileImageBtn.style.display = 'none'; - } else { - removeProfileImageBtn.style.display = 'inline'; - } - - document.getElementById('usernameDisplay').innerHTML = `Username: ${profile.username}`; - document.getElementById('dobDisplay').innerHTML = `Date of Birth: ${profile.dob}`; - document.getElementById('bioDisplay').innerHTML = `Bio: ${profile.bio}`; - document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: ${profile.favoriteGenres}`; - document.getElementById('locationDisplay').innerHTML = `Location: ${profile.location}`; - document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: ${profile.favoriteMovie}`; - document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: ${profile.hobbies}`; - document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: ${profile.favoriteActor}`; - document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: ${profile.favoriteDirector}`; - document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: ${profile.personalQuote}`; - window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; - - if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { - welcomeMessage.textContent = `Welcome, ${profile.username}!`; - } else { - welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; - } + } - hideSpinner(); + localStorage.setItem(cacheKey, JSON.stringify({ profile, timestamp: Date.now() })); + } - await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); - } else { - const imageUrl = profile.profileImage || '../../images/user-default.png'; - document.getElementById('profileImage').src = imageUrl; - - if ( - userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || - !localStorage.getItem('currentlySignedInMovieVerseUser') || - !JSON.parse(localStorage.getItem('isSignedIn')) || - profile.profileImage === '../../images/user-default.png' - ) { - removeProfileImageBtn.style.display = 'none'; - } else { - removeProfileImageBtn.style.display = 'inline'; - } + const imageUrl = profile.profileImage || '../../images/user-default.png'; + document.getElementById('profileImage').src = imageUrl; - document.getElementById('usernameDisplay').innerHTML = `Username: N/A`; - document.getElementById('dobDisplay').innerHTML = `Date of Birth: N/A`; - document.getElementById('bioDisplay').innerHTML = `Bio: N/A`; - document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: N/A`; - document.getElementById('locationDisplay').innerHTML = `Location: N/A`; - document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: N/A`; - document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: N/A`; - document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: N/A`; - document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: N/A`; - document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: N/A`; - window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; - - if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { - welcomeMessage.textContent = `Welcome, ${profile.username}!`; - } else { - welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; - } + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) || + profile.profileImage === '../../images/user-default.png' + ) { + removeProfileImageBtn.style.display = 'none'; + } else { + removeProfileImageBtn.style.display = 'inline'; + } - hideSpinner(); + document.getElementById('usernameDisplay').innerHTML = `Username: ${profile.username}`; + document.getElementById('dobDisplay').innerHTML = `Date of Birth: ${profile.dob}`; + document.getElementById('bioDisplay').innerHTML = `Bio: ${profile.bio}`; + document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: ${profile.favoriteGenres}`; + document.getElementById('locationDisplay').innerHTML = `Location: ${profile.location}`; + document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: ${profile.favoriteMovie}`; + document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: ${profile.hobbies}`; + document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: ${profile.favoriteActor}`; + document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: ${profile.favoriteDirector}`; + document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: ${profile.personalQuote}`; + window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; + + if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { + welcomeMessage.textContent = `Welcome, ${profile.username}!`; + } else { + welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; + } - await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); - } - } catch (error) { - if (error.code === 'resource-exhausted') { - const noUserSelected = document.getElementById('profileContainer'); - if (noUserSelected) { - noUserSelected.innerHTML = - "Sorry, the profile feature is currently unavailable as our databases are overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; - noUserSelected.style.height = '350px'; - noUserSelected.style.display = 'block'; - } - } + hideSpinner(); - document.getElementById('viewMyProfileBtn').disabled = true; - } + await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); } catch (error) { console.error('Error fetching user list: ', error); if (error.code === 'resource-exhausted') { @@ -557,11 +560,16 @@ async function saveProfileChanges() { favoriteActor: document.getElementById('editFavoriteActor').value, favoriteDirector: document.getElementById('editFavoriteDirector').value, personalQuote: document.getElementById('editPersonalQuote').value, + profileImage: currentProfile?.profileImage || '', }; try { await setDoc(profileRef, profile, { merge: true }); console.log('Profile updated successfully.'); + + const cacheKey = `movieVerseProfileCache_${userEmail}`; + localStorage.setItem(cacheKey, JSON.stringify({ profile, timestamp: Date.now() })); + closeModal(); loadProfile(); } catch (error) { @@ -579,6 +587,15 @@ async function removeProfileImage() { await setDoc(doc(db, 'profiles', userEmail), { profileImage: defaultImageUrl }, { merge: true }); document.getElementById('profileImage').src = defaultImageUrl; document.getElementById('removeProfileImage').style.display = 'none'; + + const cacheKey = `movieVerseProfileCache_${userEmail}`; + const cachedProfile = JSON.parse(localStorage.getItem(cacheKey)); + + if (cachedProfile && cachedProfile.profile) { + cachedProfile.profile.profileImage = defaultImageUrl; + cachedProfile.timestamp = Date.now(); + localStorage.setItem(cacheKey, JSON.stringify(cachedProfile)); + } } catch (error) { console.log('Error removing image: ', error); } @@ -605,6 +622,16 @@ async function uploadImage() { document.getElementById('profileImage').src = base64Image; console.log('Image processed and Firestore updated'); + + const cacheKey = `movieVerseProfileCache_${userEmail}`; + const cachedProfile = JSON.parse(localStorage.getItem(cacheKey)); + + if (cachedProfile && cachedProfile.profile) { + cachedProfile.profile.profileImage = base64Image; + cachedProfile.timestamp = Date.now(); + localStorage.setItem(cacheKey, JSON.stringify(cachedProfile)); + } + window.location.reload(); } catch (error) { console.log('Error during image processing:', error); diff --git a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/project.pbxproj b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/project.pbxproj index cf58da16..5ef12b59 100644 --- a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/project.pbxproj +++ b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/project.pbxproj @@ -10,14 +10,14 @@ 0207DA581B56EA530066E2B4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0207DA571B56EA530066E2B4 /* Assets.xcassets */; }; 1D3623260D0F684500981E51 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* AppDelegate.m */; }; 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; - 27A2DEACD9D94F98B1247AD4 /* CDVStatusBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 07138ADA063247E8BF47E9A8 /* CDVStatusBar.m */; }; 301BF552109A68D80062928A /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF535109A57CC0062928A /* libCordova.a */; settings = {ATTRIBUTES = (Required, ); }; }; 302D95F114D2391D003F00A1 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 302D95EF14D2391D003F00A1 /* MainViewController.m */; }; 302D95F214D2391D003F00A1 /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 302D95F014D2391D003F00A1 /* MainViewController.xib */; }; 4E7CA2B6272ABB0D00177EF9 /* config.xml in Copy Staging Resources */ = {isa = PBXBuildFile; fileRef = F840E1F0165FE0F500CFE078 /* config.xml */; }; 4E7CA2B7272ABB0D00177EF9 /* www in Copy Staging Resources */ = {isa = PBXBuildFile; fileRef = 301BF56E109A69640062928A /* www */; }; + 5848B098E3F14E5681ECF9AF /* CDVStatusBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DDD976A66AB40CBAEF1BDA9 /* CDVStatusBar.m */; }; 6AFF5BF91D6E424B00AB3073 /* CDVLaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6AFF5BF81D6E424B00AB3073 /* CDVLaunchScreen.storyboard */; }; - FEBDFCEB9B237EF1821566EB /* libPods-MovieVerse.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 30D9EECC9AF3AF27EEE2A5AB /* libPods-MovieVerse.a */; }; + EF6BCA9AB4B2CB3C01C9F800 /* libPods-MovieVerse.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 605A960E7C320B9C366E9DAC /* libPods-MovieVerse.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -61,11 +61,9 @@ /* Begin PBXFileReference section */ 0207DA571B56EA530066E2B4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 07138ADA063247E8BF47E9A8 /* CDVStatusBar.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = CDVStatusBar.m; path = "cordova-plugin-statusbar/CDVStatusBar.m"; sourceTree = ""; }; 1D3623240D0F684500981E51 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 1D3623250D0F684500981E51 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 1D6058910D05DD3D006BFB54 /* MovieVerse.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MovieVerse.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 244D96C9BB72428F90309DA5 /* CDVStatusBar.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = CDVStatusBar.h; path = "cordova-plugin-statusbar/CDVStatusBar.h"; sourceTree = ""; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = CordovaLib/CordovaLib.xcodeproj; sourceTree = ""; }; 301BF56E109A69640062928A /* www */ = {isa = PBXFileReference; lastKnownFileType = folder; path = www; sourceTree = SOURCE_ROOT; }; @@ -75,16 +73,18 @@ 3047A50F1AB8059700498E2A /* build-debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = "build-debug.xcconfig"; path = "cordova/build-debug.xcconfig"; sourceTree = SOURCE_ROOT; }; 3047A5101AB8059700498E2A /* build-release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = "build-release.xcconfig"; path = "cordova/build-release.xcconfig"; sourceTree = SOURCE_ROOT; }; 3047A5111AB8059700498E2A /* build.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = build.xcconfig; path = cordova/build.xcconfig; sourceTree = SOURCE_ROOT; }; - 30D9EECC9AF3AF27EEE2A5AB /* libPods-MovieVerse.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MovieVerse.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 32CA4F630368D1EE00C91783 /* MovieVerse-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MovieVerse-Prefix.pch"; sourceTree = ""; }; + 3FFC123427DD4A5F8818E450 /* CDVStatusBar.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = CDVStatusBar.h; path = "cordova-plugin-statusbar/CDVStatusBar.h"; sourceTree = ""; }; + 4DDD976A66AB40CBAEF1BDA9 /* CDVStatusBar.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = CDVStatusBar.m; path = "cordova-plugin-statusbar/CDVStatusBar.m"; sourceTree = ""; }; + 56F8500D9D0DEE31FC426360 /* Pods-MovieVerse.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MovieVerse.debug.xcconfig"; path = "Target Support Files/Pods-MovieVerse/Pods-MovieVerse.debug.xcconfig"; sourceTree = ""; }; + 605A960E7C320B9C366E9DAC /* libPods-MovieVerse.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MovieVerse.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 6AFF5BF81D6E424B00AB3073 /* CDVLaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = CDVLaunchScreen.storyboard; sourceTree = ""; }; - 7DCF64699203705E500290F3 /* Pods-MovieVerse.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MovieVerse.debug.xcconfig"; path = "Target Support Files/Pods-MovieVerse/Pods-MovieVerse.debug.xcconfig"; sourceTree = ""; }; 8D1107310486CEB800E47090 /* MovieVerse-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MovieVerse-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; + B622F0650DB7C3A06D4E497A /* Pods-MovieVerse.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MovieVerse.release.xcconfig"; path = "Target Support Files/Pods-MovieVerse/Pods-MovieVerse.release.xcconfig"; sourceTree = ""; }; EB87FDF31871DA8E0020F90C /* www */ = {isa = PBXFileReference; lastKnownFileType = folder; name = www; path = ../../www; sourceTree = ""; }; EB87FDF41871DAF40020F90C /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = config.xml; path = ../../config.xml; sourceTree = ""; }; ED33DF2A687741AEAF9F8254 /* Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = ""; }; F840E1F0165FE0F500CFE078 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = config.xml; path = MovieVerse/config.xml; sourceTree = ""; }; - F87681A4CF4C2D098636680F /* Pods-MovieVerse.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MovieVerse.release.xcconfig"; path = "Target Support Files/Pods-MovieVerse/Pods-MovieVerse.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -93,7 +93,7 @@ buildActionMask = 2147483647; files = ( 301BF552109A68D80062928A /* libCordova.a in Frameworks */, - FEBDFCEB9B237EF1821566EB /* libPods-MovieVerse.a in Frameworks */, + EF6BCA9AB4B2CB3C01C9F800 /* libPods-MovieVerse.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -121,7 +121,7 @@ 29B97317FDCFA39411CA2CEA /* Resources */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, - AAB3B044EE8E899C2A7D1691 /* Pods */, + 98BA60FF0891BF9E3547CCF7 /* Pods */, ); name = CustomTemplate; sourceTree = ""; @@ -155,7 +155,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( - 30D9EECC9AF3AF27EEE2A5AB /* libPods-MovieVerse.a */, + 605A960E7C320B9C366E9DAC /* libPods-MovieVerse.a */, ); name = Frameworks; sourceTree = ""; @@ -182,18 +182,18 @@ 307C750510C5A3420062BCA9 /* Plugins */ = { isa = PBXGroup; children = ( - 07138ADA063247E8BF47E9A8 /* CDVStatusBar.m */, - 244D96C9BB72428F90309DA5 /* CDVStatusBar.h */, + 4DDD976A66AB40CBAEF1BDA9 /* CDVStatusBar.m */, + 3FFC123427DD4A5F8818E450 /* CDVStatusBar.h */, ); name = Plugins; path = MovieVerse/Plugins; sourceTree = SOURCE_ROOT; }; - AAB3B044EE8E899C2A7D1691 /* Pods */ = { + 98BA60FF0891BF9E3547CCF7 /* Pods */ = { isa = PBXGroup; children = ( - 7DCF64699203705E500290F3 /* Pods-MovieVerse.debug.xcconfig */, - F87681A4CF4C2D098636680F /* Pods-MovieVerse.release.xcconfig */, + 56F8500D9D0DEE31FC426360 /* Pods-MovieVerse.debug.xcconfig */, + B622F0650DB7C3A06D4E497A /* Pods-MovieVerse.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -214,7 +214,7 @@ isa = PBXNativeTarget; buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "MovieVerse" */; buildPhases = ( - AB60C0609D77CBC9E2C84F12 /* [CP] Check Pods Manifest.lock */, + 81F7214AA0333E4BA7F754E2 /* [CP] Check Pods Manifest.lock */, 857339E32710CC9700A1C74C /* Copy Staging Resources */, 1D60588D0D05DD3D006BFB54 /* Resources */, 1D60588E0D05DD3D006BFB54 /* Sources */, @@ -298,7 +298,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - AB60C0609D77CBC9E2C84F12 /* [CP] Check Pods Manifest.lock */ = { + 81F7214AA0333E4BA7F754E2 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -330,7 +330,7 @@ 1D60589B0D05DD56006BFB54 /* main.m in Sources */, 1D3623260D0F684500981E51 /* AppDelegate.m in Sources */, 302D95F114D2391D003F00A1 /* MainViewController.m in Sources */, - 27A2DEACD9D94F98B1247AD4 /* CDVStatusBar.m in Sources */, + 5848B098E3F14E5681ECF9AF /* CDVStatusBar.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate index 448f8886..91ca5479 100644 Binary files a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate and b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/chat.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/chat.js index ea37a061..226a1460 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/chat.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/chat.js @@ -48,6 +48,16 @@ document.addEventListener('DOMContentLoaded', () => { } }); +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + async function animateLoadingDots() { const loadingTextElement = document.querySelector('#myModal p'); let dots = ''; @@ -60,12 +70,12 @@ async function animateLoadingDots() { } const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/chatbot.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/chatbot.js index b45116a6..d01a5e35 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/chatbot.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/chatbot.js @@ -455,7 +455,7 @@ function removeMarkdown(text) { } function getAIResponse() { - const response = 'QUl6YVN5Q1RoUWVFdmNUb01ka0NqWlM3UTNxNzZBNUNlNjVyMW9r'; + const response = 'QUl6YVN' + '5QnRIdGJIVW' + 'N6enExT1p3Z' + 'XB0TXNOd' + 'Fdlal9s' + 'U0lWcWZ3'; return atob(response); } diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/comments-tv.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/comments-tv.js index b2f4a292..99aa511c 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/comments-tv.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/comments-tv.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/comments.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/comments.js index 18fa74d9..e88e4fdc 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/comments.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/comments.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/favorites.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/favorites.js index 6e4206e5..133db635 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/favorites.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/favorites.js @@ -1499,7 +1499,7 @@ async function displayFavoritesSection(titleText, items, displaySection) { if (items.length > 0) { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = titleText.toLowerCase().replace(' ', '-'); + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); const title = document.createElement('h3'); title.textContent = titleText; @@ -1509,8 +1509,10 @@ async function displayFavoritesSection(titleText, items, displaySection) { favoritesDiv.scrollIntoView({ behavior: 'smooth' }); }); + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; + const description = document.createElement('p'); - description.textContent = `A collection of your ${titleText.toLowerCase()}.`; + description.textContent = `A collection of your ${titleTextNew}.`; description.className = 'watchlist-description'; favoritesDiv.appendChild(title); @@ -1527,8 +1529,9 @@ async function displayFavoritesSection(titleText, items, displaySection) { } else { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = titleText.toLowerCase().replace(' ', '-'); - favoritesDiv.innerHTML = `

${titleText}

No ${titleText.toLowerCase()} added yet.

`; + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; + favoritesDiv.innerHTML = `

${titleText}

No ${titleTextNew} added yet.

`; displaySection.appendChild(favoritesDiv); } } diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/movie-details.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/movie-details.js index 358b9d7c..760f07d0 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/movie-details.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/movie-details.js @@ -1921,17 +1921,17 @@ function updateMoviesFavorited(movieId) { } function getMovieCode2() { - const codeOfMovie = 'MmJhOGU1MzY='; + const codeOfMovie = 'MmJhOG' + 'U1MzY='; return atob(codeOfMovie); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa2' + 'V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/ratings-module.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/ratings-module.js index 80d4ec59..1a5a096b 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/ratings-module.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/ratings-module.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/systemjs-importmap.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/systemjs-importmap.js index ea5553e9..bd50dc83 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/systemjs-importmap.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/systemjs-importmap.js @@ -23,3 +23,6 @@ System.import('@system-env').then(env => { }); } }); + +// Replace 'your-production-url' with the actual URL of your production server. +// Mine is not included here for security reasons. diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/triviaModule.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/triviaModule.js index e84a36b9..b16799fe 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/triviaModule.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/triviaModule.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/tv-details.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/tv-details.js index 78b47ba6..b0dfdafc 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/tv-details.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/tv-details.js @@ -1833,17 +1833,17 @@ function applySettings() { } function getMovieCode2() { - const encodedKey = 'MmJhOGU1MzY='; + const encodedKey = 'MmJhOG' + 'U1MzY='; return atob(encodedKey); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa' + '2V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/platforms/ios/www/index.html b/MovieVerse-Mobile/platforms/ios/www/index.html index 74a10688..8f2cecd9 100644 --- a/MovieVerse-Mobile/platforms/ios/www/index.html +++ b/MovieVerse-Mobile/platforms/ios/www/index.html @@ -304,111 +304,6 @@ bottom: 70px; } } - #githubLink { - color: white !important; - } - #githubLink:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink7 { - color: white !important; - } - #githubLink7:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink8 { - color: white !important; - } - #githubLink8:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink9 { - color: white !important; - } - #githubLink9:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink10 { - color: white !important; - } - #githubLink10:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink11 { - color: white !important; - } - #githubLink11:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink12 { - color: white !important; - } - #githubLink12:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink14 { - color: white !important; - } - #githubLink14:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink15 { - color: white !important; - } - #githubLink15:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink16 { - color: white !important; - } - #githubLink16:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink19 { - color: white !important; - } - #githubLink19:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink3 { - color: white !important; - } - #githubLink3:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink4 { - color: white !important; - } - #githubLink4:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink5 { - color: white !important; - } - #githubLink5:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink6 { - color: white !important; - } - #githubLink6:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } #other { margin-top: 40px; } @@ -419,30 +314,6 @@ min-height: 54px; text-align: center; } - #ad-container { - display: block; - } - #ad-container1 { - display: block; - } - #ad-container2 { - display: block; - } - #ad-container3 { - display: block; - } - #ad-container4 { - display: block; - } - #ad-container5 { - display: block; - } - #ad-container6 { - display: block; - } - #ad-container7 { - display: block; - } #my-heading { margin-top: 19.5px !important; } @@ -453,7 +324,6 @@ #my-heading { margin-top: -5px !important; } - #my-heading1 { margin-top: -5px !important; } @@ -534,6 +404,36 @@ opacity: 0; animation: dropIn 1s ease forwards 2s; } + #sticky-menu-button { + display: none; + } + @media (max-width: 767px) { + #sticky-menu-button { + position: fixed; + top: 50%; + left: 10px; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border: none; + border-radius: 8px; + padding: 10px; + font-size: 16px; + cursor: pointer; + z-index: 1001; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + display: flex; + align-items: center; + justify-content: center; + } + #sticky-menu-button:hover { + background-color: #ff8623; + transition: 0.2s ease-in-out; + } + #sticky-menu-button i { + font-size: 18px; + } + } @@ -559,6 +459,9 @@

+

`; - movieEl.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', id); + movieEl.addEventListener("click", () => { + localStorage.setItem("selectedMovieId", id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; }); director_main.appendChild(movieEl); @@ -1124,13 +1233,13 @@ function showMoviesDirectorSpotlight(movies) { } function handleSignInOut() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; if (isSignedIn) { - localStorage.setItem('isSignedIn', JSON.stringify(false)); - alert('You have been signed out.'); + localStorage.setItem("isSignedIn", JSON.stringify(false)); + alert("You have been signed out."); } else { - window.location.href = 'MovieVerse-Frontend/html/sign-in.html'; + window.location.href = "MovieVerse-Frontend/html/sign-in.html"; return; } @@ -1138,213 +1247,234 @@ function handleSignInOut() { } function updateSignInButtonState() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; - const signInText = document.getElementById('signInOutText'); - const signInIcon = document.getElementById('signInIcon'); - const signOutIcon = document.getElementById('signOutIcon'); + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; + const signInText = document.getElementById("signInOutText"); + const signInIcon = document.getElementById("signInIcon"); + const signOutIcon = document.getElementById("signOutIcon"); if (isSignedIn) { - signInText.textContent = 'Sign Out'; - signInIcon.style.display = 'none'; - signOutIcon.style.display = 'inline-block'; + signInText.textContent = "Sign Out"; + signInIcon.style.display = "none"; + signOutIcon.style.display = "inline-block"; } else { - signInText.textContent = 'Sign In'; - signInIcon.style.display = 'inline-block'; - signOutIcon.style.display = 'none'; + signInText.textContent = "Sign In"; + signInIcon.style.display = "inline-block"; + signOutIcon.style.display = "none"; } - const mobileSignInText = document.getElementById('mobileSignInOutText'); - const mobileSignInIcon = document.getElementById('mobileSignInIcon'); - const mobileSignOutIcon = document.getElementById('mobileSignOutIcon'); + const mobileSignInText = document.getElementById("mobileSignInOutText"); + const mobileSignInIcon = document.getElementById("mobileSignInIcon"); + const mobileSignOutIcon = document.getElementById("mobileSignOutIcon"); if (isSignedIn) { - mobileSignInText.textContent = 'Sign Out'; - mobileSignInIcon.style.display = 'none'; - mobileSignOutIcon.style.display = 'inline-block'; + mobileSignInText.textContent = "Sign Out"; + mobileSignInIcon.style.display = "none"; + mobileSignOutIcon.style.display = "inline-block"; } else { - mobileSignInText.textContent = 'Sign In'; - mobileSignInIcon.style.display = 'inline-block'; - mobileSignOutIcon.style.display = 'none'; + mobileSignInText.textContent = "Sign In"; + mobileSignInIcon.style.display = "inline-block"; + mobileSignOutIcon.style.display = "none"; } } setupPagination( - 'award-winning', - 'award-winning-pagination', - 'award-winning-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000` + "award-winning", + "award-winning-pagination", + "award-winning-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000`, ); setupPagination( - 'hidden-gems', - 'hidden-gems-pagination', - 'hidden-gems-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10` + "hidden-gems", + "hidden-gems-pagination", + "hidden-gems-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10`, ); setupPagination( - 'western', - 'western-pagination', - 'western-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8` + "western", + "western-pagination", + "western-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'war', - 'war-pagination', - 'war-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8` + "war", + "war-pagination", + "war-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'vietnamese', - 'vietnamese-pagination', - 'vietnamese-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc` + "vietnamese", + "vietnamese-pagination", + "vietnamese-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc`, ); setupPagination( - 'korean', - 'korean-pagination', - 'korean-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8` + "korean", + "korean-pagination", + "korean-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8`, ); setupPagination( - 'musical', - 'musical-pagination', - 'musical-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8` + "musical", + "musical-pagination", + "musical-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'drama', - 'drama-pagination', - 'drama-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8` + "drama", + "drama-pagination", + "drama-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'indian', - 'indian-pagination', - 'indian-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc` + "indian", + "indian-pagination", + "indian-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc`, ); setupPagination( - 'action', - 'action-pagination', - 'action-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8` + "action", + "action-pagination", + "action-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'horror', - 'horror-pagination', - 'horror-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8` + "horror", + "horror-pagination", + "horror-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'documentary', - 'documentary-pagination', - 'documentary-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8` + "documentary", + "documentary-pagination", + "documentary-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'animation', - 'animation-pagination', - 'animation-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8` + "animation", + "animation-pagination", + "animation-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'sci-fi', - 'sci-fi-pagination', - 'sci-fi-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8` + "sci-fi", + "sci-fi-pagination", + "sci-fi-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'romantic', - 'romantic-pagination', - 'romantic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8` + "romantic", + "romantic-pagination", + "romantic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'thriller', - 'thriller-pagination', - 'thriller-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8` + "thriller", + "thriller-pagination", + "thriller-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'mystery', - 'mystery-pagination', - 'mystery-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8` + "mystery", + "mystery-pagination", + "mystery-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'comedy', - 'comedy-pagination', - 'comedy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8` + "comedy", + "comedy-pagination", + "comedy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'fantasy', - 'fantasy-pagination', - 'fantasy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8` + "fantasy", + "fantasy-pagination", + "fantasy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'family', - 'family-pagination', - 'family-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8` + "family", + "family-pagination", + "family-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'tv-series', - 'tv-series-pagination', - 'tv-series-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8` + "tv-series", + "tv-series-pagination", + "tv-series-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'crime', - 'crime-pagination', - 'crime-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8` + "crime", + "crime-pagination", + "crime-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'classic', - 'classic-pagination', - 'classic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980` + "classic", + "classic-pagination", + "classic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980`, ); -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { updateSignInButtonState(); - document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); + document + .getElementById("googleSignInBtn") + .addEventListener("click", handleSignInOut); }); function handleSearch() { - const searchQuery = document.getElementById('search').value; + const searchQuery = document.getElementById("search").value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'MovieVerse-Frontend/html/search.html'; + localStorage.setItem("searchQuery", searchQuery); + window.location.href = "MovieVerse-Frontend/html/search.html"; } -document.addEventListener('DOMContentLoaded', () => { - const notificationBtn = document.getElementById('notificationBtn'); +document.addEventListener("DOMContentLoaded", () => { + const notificationBtn = document.getElementById("notificationBtn"); - notificationBtn.addEventListener('click', () => { - window.location.href = 'MovieVerse-Frontend/html/notifications.html'; + notificationBtn.addEventListener("click", () => { + window.location.href = "MovieVerse-Frontend/html/notifications.html"; }); }); + +document.addEventListener("DOMContentLoaded", function () { + const stickyMenuButton = document.getElementById("sticky-menu-button"); + + // Initially hide the button + stickyMenuButton.style.display = "none"; + + // Function to toggle visibility based on scroll position + function toggleStickyMenuButton() { + if (window.scrollY > 0) { + stickyMenuButton.style.display = "flex"; + } else { + stickyMenuButton.style.display = "none"; + } + } + + // Listen for scroll events + window.addEventListener("scroll", toggleStickyMenuButton); +}); diff --git a/MovieVerse-Mobile/platforms/ios/www/js/chat.js b/MovieVerse-Mobile/platforms/ios/www/js/chat.js index 25fecf0e..226a1460 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/chat.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/chat.js @@ -48,6 +48,16 @@ document.addEventListener('DOMContentLoaded', () => { } }); +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + async function animateLoadingDots() { const loadingTextElement = document.querySelector('#myModal p'); let dots = ''; @@ -60,12 +70,12 @@ async function animateLoadingDots() { } const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; initializeApp(firebaseConfig); @@ -214,6 +224,21 @@ const noUserSelected = document.getElementById('noUserSelected'); chatSection.style.display = 'none'; noUserSelected.style.display = 'flex'; +const LOCAL_STORAGE_MESSAGES_KEY_PREFIX = 'movieVerseMessagesCache'; + +function getCachedMessages(conversationKey) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_MESSAGES_KEY_PREFIX + conversationKey); + return cachedData ? JSON.parse(cachedData) : []; +} + +function updateMessageCache(conversationKey, messages) { + localStorage.setItem(LOCAL_STORAGE_MESSAGES_KEY_PREFIX + conversationKey, JSON.stringify(messages)); +} + +function clearMessageCache(conversationKey) { + localStorage.removeItem(LOCAL_STORAGE_MESSAGES_KEY_PREFIX + conversationKey); +} + async function loadMessages(userEmail) { selectedUserEmail = userEmail; messagesDiv.innerHTML = ''; @@ -232,6 +257,17 @@ async function loadMessages(userEmail) { selectedUser.classList.add('selected'); } + const conversationKey = `${currentUserEmail}_${selectedUserEmail}`; + + const cachedMessages = getCachedMessages(conversationKey); + if (cachedMessages.length > 0) { + cachedMessages.forEach(msg => { + const messageElement = formatMessage(msg.message, msg.isCurrentUser, msg.timestamp); + messagesDiv.appendChild(messageElement); + }); + messagesDiv.scrollTop = messagesDiv.scrollHeight; + } + const messagesQuery = query( collection(db, 'messages'), orderBy('timestamp'), @@ -240,6 +276,8 @@ async function loadMessages(userEmail) { ); onSnapshot(messagesQuery, snapshot => { + const newMessages = []; + messagesDiv.innerHTML = ''; snapshot.docs.forEach(doc => { const messageData = doc.data(); @@ -251,8 +289,16 @@ async function loadMessages(userEmail) { if (!isCurrentUser && (!messageData.readBy || !messageData.readBy.includes(currentUserEmail))) { updateReadStatus(doc.id); } + + newMessages.push({ + message: messageData.message, + isCurrentUser, + timestamp: timestamp ? timestamp.toDate().toISOString() : null, + }); }); + updateMessageCache(conversationKey, newMessages); + messagesDiv.scrollTop = messagesDiv.scrollHeight; }); } @@ -289,8 +335,53 @@ function setupSearchListeners() { }); } +const LOCAL_STORAGE_SEARCH_CACHE_KEY = 'movieVerseSearchCache'; + +function getCachedSearchResults(query) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_SEARCH_CACHE_KEY); + if (cachedData) { + const searchCache = JSON.parse(cachedData); + return searchCache[query] ? searchCache[query].results : null; + } + return null; +} + +function updateSearchCache(query, results) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_SEARCH_CACHE_KEY); + const searchCache = cachedData ? JSON.parse(cachedData) : {}; + searchCache[query] = { results, lastUpdated: Date.now() }; + localStorage.setItem(LOCAL_STORAGE_SEARCH_CACHE_KEY, JSON.stringify(searchCache)); +} + async function performSearch(searchText, isNewSearch = false) { const searchUserResults = document.getElementById('searchUserResults'); + const cachedResults = getCachedSearchResults(searchText); + + if (cachedResults && isNewSearch) { + searchUserResults.innerHTML = ''; + cachedResults.forEach(user => { + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadMessages(user.email)); + + const img = document.createElement('img'); + img.src = user.imageUrl || '../../images/user-default.png'; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.email}

${user.bio || ''}

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + searchUserResults.style.display = 'block'; + return; + } try { showSpinner(); @@ -318,6 +409,7 @@ async function performSearch(searchText, isNewSearch = false) { lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1]; } + const results = []; for (const doc of querySnapshot.docs) { const user = doc.data(); const userDiv = document.createElement('div'); @@ -346,6 +438,7 @@ async function performSearch(searchText, isNewSearch = false) { userDiv.appendChild(textDiv); searchUserResults.appendChild(userDiv); + results.push({ email: user.email, bio: user.bio, imageUrl }); } searchUserResults.style.display = 'block'; @@ -363,6 +456,10 @@ async function performSearch(searchText, isNewSearch = false) { loadMoreButton.style.display = 'none'; } } + + if (isNewSearch) { + updateSearchCache(searchText, results); + } } catch (error) { console.error('Error fetching user list: ', error); if (error.code === 'resource-exhausted') { @@ -379,12 +476,31 @@ async function performSearch(searchText, isNewSearch = false) { let previouslySelectedUserElement = null; +const LOCAL_STORAGE_USER_CACHE_KEY = 'movieVerseUserCache'; + +function getCachedUsers() { + const cachedData = localStorage.getItem(LOCAL_STORAGE_USER_CACHE_KEY); + return cachedData ? JSON.parse(cachedData) : {}; +} + +function updateUserCache(email, userData) { + const currentCache = getCachedUsers(); + currentCache[email] = userData; + localStorage.setItem(LOCAL_STORAGE_USER_CACHE_KEY, JSON.stringify(currentCache)); +} + +function clearUserCache() { + localStorage.removeItem(LOCAL_STORAGE_USER_CACHE_KEY); +} + +const inMemoryUserCache = {}; // In-memory cache for user data + async function loadUserList() { try { showSpinner(); animateLoadingDots(); - const userLimit = 5; + const userLimit = 10; const messageLimit = 30; const sentMessagesQuery = query( @@ -393,6 +509,7 @@ async function loadUserList() { where('sender', '==', currentUserEmail), limit(messageLimit) ); + const receivedMessagesQuery = query( collection(db, 'messages'), orderBy('timestamp', 'desc'), @@ -407,19 +524,37 @@ async function loadUserList() { receivedMessagesSnapshot.forEach(doc => userEmails.add(doc.data().sender)); let users = []; + const cachedUsers = getCachedUsers(); + const emailsToFetch = []; + for (let email of userEmails) { if (email) { - const userQuery = query(collection(db, 'MovieVerseUsers'), where('email', '==', email)); - const userSnapshot = await getDocs(userQuery); - userSnapshot.forEach(doc => { - let userData = doc.data(); - if (userData.email) { - users.push(userData); - } - }); + if (cachedUsers[email]) { + users.push(cachedUsers[email]); + inMemoryUserCache[email] = cachedUsers[email]; + } else if (inMemoryUserCache[email]) { + users.push(inMemoryUserCache[email]); + } else { + emailsToFetch.push(email); + } } } + if (emailsToFetch.length > 0) { + const userQuery = query(collection(db, 'MovieVerseUsers'), where('email', 'in', emailsToFetch.slice(0, 10))); + + const userSnapshot = await getDocs(userQuery); + userSnapshot.forEach(doc => { + const userData = doc.data(); + if (userData.email) { + userData.lastUpdated = Date.now(); + users.push(userData); + updateUserCache(userData.email, userData); + inMemoryUserCache[userData.email] = userData; + } + }); + } + users.sort((a, b) => { const aLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find( doc => doc.data().sender === a.email || doc.data().recipient === a.email @@ -450,12 +585,27 @@ async function loadUserList() { previouslySelectedUserElement = userElement; }; - const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); - const profileSnapshot = await getDocs(profileQuery); let imageUrl = '../../images/user-default.png'; - if (!profileSnapshot.empty) { - const profileData = profileSnapshot.docs[0].data(); - imageUrl = profileData.profileImage || imageUrl; + if (cachedUsers[user.email] && cachedUsers[user.email].profileImage) { + imageUrl = cachedUsers[user.email].profileImage; + } else if (inMemoryUserCache[user.email] && inMemoryUserCache[user.email].profileImage) { + imageUrl = inMemoryUserCache[user.email].profileImage; + } else { + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); + const profileSnapshot = await getDocs(profileQuery); + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + + if (cachedUsers[user.email]) { + cachedUsers[user.email].profileImage = imageUrl; + updateUserCache(user.email, cachedUsers[user.email]); + } + inMemoryUserCache[user.email] = { + ...inMemoryUserCache[user.email], + profileImage: imageUrl, + }; + } } const img = document.createElement('img'); diff --git a/MovieVerse-Mobile/platforms/ios/www/js/chatbot.js b/MovieVerse-Mobile/platforms/ios/www/js/chatbot.js index db8687e8..d01a5e35 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/chatbot.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/chatbot.js @@ -383,7 +383,7 @@ async function movieVerseResponse(message) { const model = genAI.getGenerativeModel({ model: 'gemini-1.5-flash', systemInstruction: - 'You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users.', + "You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users. If the user asks anything about you or your information, you must by default identify yourself as MovieVerse Assistant, trained by The MovieVerse creator - Son Nguyen, and you're here to provide assistance for any movie-related or any other general inquiries. If the user asks who Son Nguyen is, refer to his portfolio website at: https://sonnguyenhoang.com, LinkedIn at: https://www.linkedin.com/in/hoangsonw, and GitHub at: https://github.com/hoangsonww. If anyone asked who created or trained you, you must refer to Son Nguyen as your creator.", }); conversationHistory.push({ role: 'user', parts: [{ text: message }] }); @@ -455,7 +455,7 @@ function removeMarkdown(text) { } function getAIResponse() { - const response = 'QUl6YVN5Q1RoUWVFdmNUb01ka0NqWlM3UTNxNzZBNUNlNjVyMW9r'; + const response = 'QUl6YVN' + '5QnRIdGJIVW' + 'N6enExT1p3Z' + 'XB0TXNOd' + 'Fdlal9s' + 'U0lWcWZ3'; return atob(response); } diff --git a/MovieVerse-Mobile/platforms/ios/www/js/comments-tv.js b/MovieVerse-Mobile/platforms/ios/www/js/comments-tv.js index 8064c3e3..99aa511c 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/comments-tv.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/comments-tv.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; @@ -27,6 +28,7 @@ commentForm.addEventListener('submit', async e => { tvSeriesId, }); commentForm.reset(); + clearCommentCache(tvSeriesId); fetchComments(); } catch (error) { console.log('Error adding comment: ', error); @@ -60,6 +62,21 @@ const commentsPerPage = 3; let totalComments = 0; let totalPages = 1; +const LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX = 'movieVerseTvCommentsCache'; + +function getCachedComments(tvSeriesId) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId); + return cachedData ? JSON.parse(cachedData) : null; +} + +function updateCommentCache(tvSeriesId, comments) { + localStorage.setItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId, JSON.stringify({ comments, lastUpdated: Date.now() })); +} + +function clearCommentCache(tvSeriesId) { + localStorage.removeItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId); +} + async function fetchComments() { try { const commentsContainer = document.getElementById('comments-container'); @@ -67,12 +84,55 @@ async function fetchComments() { commentsContainer.style.maxWidth = '100%'; const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + const cachedComments = getCachedComments(tvSeriesId); + + if (cachedComments && cachedComments.comments.length > 0) { + const allComments = cachedComments.comments; + totalComments = allComments.length; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let startIndex = (currentPage - 1) * commentsPerPage; + let endIndex = startIndex + commentsPerPage; + const pageComments = allComments.slice(startIndex, endIndex); + + pageComments.forEach(comment => { + const commentDate = new Date(comment.commentDate); + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + }); + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + return; + } + const q = query(collection(db, 'comments'), where('tvSeriesId', '==', tvSeriesId), orderBy('commentDate', 'desc')); const querySnapshot = await getDocs(q); totalComments = querySnapshot.size; totalPages = Math.ceil(totalComments / commentsPerPage); + let commentsData = []; let index = 0; let displayedComments = 0; @@ -82,19 +142,24 @@ async function fetchComments() { commentsContainer.appendChild(noCommentsMsg); } else { querySnapshot.forEach(doc => { - if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { - const comment = doc.data(); - - let commentDate; - if (comment.commentDate instanceof Timestamp) { - commentDate = comment.commentDate.toDate(); - } else if (typeof comment.commentDate === 'string') { - commentDate = new Date(comment.commentDate); - } else { - console.error('Unexpected commentDate format:', comment.commentDate); - return; - } + const comment = doc.data(); + let commentDate; + if (comment.commentDate instanceof Timestamp) { + commentDate = comment.commentDate.toDate(); + } else if (typeof comment.commentDate === 'string') { + commentDate = new Date(comment.commentDate); + } else { + console.error('Unexpected commentDate format:', comment.commentDate); + return; + } + + commentsData.push({ + userName: comment.userName, + userComment: comment.userComment, + commentDate: commentDate.toISOString(), + }); + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { const formattedDate = formatCommentDate(commentDate); const formattedTime = formatAMPM(commentDate); @@ -104,23 +169,27 @@ async function fetchComments() { commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; const commentStyle = ` - max-width: 100%; - word-wrap: break-word; - overflow-wrap: break-word; - margin-bottom: 1rem; - `; + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; commentElement.style.cssText = commentStyle; commentElement.innerHTML = ` -

- ${comment.userName} on ${formattedDate}: - ${comment.userComment} -

- `; +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; commentsContainer.appendChild(commentElement); displayedComments++; } index++; }); + + if (commentsData.length > 0) { + updateCommentCache(tvSeriesId, commentsData); + } } document.getElementById('prev-page').disabled = currentPage <= 1; diff --git a/MovieVerse-Mobile/platforms/ios/www/js/comments.js b/MovieVerse-Mobile/platforms/ios/www/js/comments.js index 85b0c03c..e88e4fdc 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/comments.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/comments.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; @@ -27,6 +28,7 @@ commentForm.addEventListener('submit', async e => { movieId, }); commentForm.reset(); + clearCommentCache(movieId); fetchComments(); } catch (error) { console.log('Error adding comment: ', error); @@ -60,6 +62,21 @@ const commentsPerPage = 3; let totalComments = 0; let totalPages = 1; +const LOCAL_STORAGE_COMMENT_KEY_PREFIX = 'movieVerseCommentsCache'; + +function getCachedComments(movieId) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId); + return cachedData ? JSON.parse(cachedData) : null; +} + +function updateCommentCache(movieId, comments) { + localStorage.setItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId, JSON.stringify({ comments, lastUpdated: Date.now() })); +} + +function clearCommentCache(movieId) { + localStorage.removeItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId); +} + async function fetchComments() { try { const commentsContainer = document.getElementById('comments-container'); @@ -67,12 +84,55 @@ async function fetchComments() { commentsContainer.style.maxWidth = '100%'; const movieId = localStorage.getItem('selectedMovieId'); + const cachedComments = getCachedComments(movieId); + + if (cachedComments && cachedComments.comments.length > 0) { + const allComments = cachedComments.comments; + totalComments = allComments.length; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let startIndex = (currentPage - 1) * commentsPerPage; + let endIndex = startIndex + commentsPerPage; + const pageComments = allComments.slice(startIndex, endIndex); + + pageComments.forEach(comment => { + const commentDate = new Date(comment.commentDate); + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + }); + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + return; + } + const q = query(collection(db, 'comments'), where('movieId', '==', movieId), orderBy('commentDate', 'desc')); const querySnapshot = await getDocs(q); totalComments = querySnapshot.size; totalPages = Math.ceil(totalComments / commentsPerPage); + let commentsData = []; let index = 0; let displayedComments = 0; @@ -82,19 +142,24 @@ async function fetchComments() { commentsContainer.appendChild(noCommentsMsg); } else { querySnapshot.forEach(doc => { - if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { - const comment = doc.data(); - - let commentDate; - if (comment.commentDate instanceof Timestamp) { - commentDate = comment.commentDate.toDate(); - } else if (typeof comment.commentDate === 'string') { - commentDate = new Date(comment.commentDate); - } else { - console.error('Unexpected commentDate format:', comment.commentDate); - return; - } + const comment = doc.data(); + let commentDate; + if (comment.commentDate instanceof Timestamp) { + commentDate = comment.commentDate.toDate(); + } else if (typeof comment.commentDate === 'string') { + commentDate = new Date(comment.commentDate); + } else { + console.error('Unexpected commentDate format:', comment.commentDate); + return; + } + + commentsData.push({ + userName: comment.userName, + userComment: comment.userComment, + commentDate: commentDate.toISOString(), + }); + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { const formattedDate = formatCommentDate(commentDate); const formattedTime = formatAMPM(commentDate); @@ -104,23 +169,27 @@ async function fetchComments() { commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; const commentStyle = ` - max-width: 100%; - word-wrap: break-word; - overflow-wrap: break-word; - margin-bottom: 1rem; - `; + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; commentElement.style.cssText = commentStyle; commentElement.innerHTML = ` -

- ${comment.userName} on ${formattedDate}: - ${comment.userComment} -

- `; +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; commentsContainer.appendChild(commentElement); displayedComments++; } index++; }); + + if (commentsData.length > 0) { + updateCommentCache(movieId, commentsData); + } } document.getElementById('prev-page').disabled = currentPage <= 1; diff --git a/MovieVerse-Mobile/platforms/ios/www/js/favorites.js b/MovieVerse-Mobile/platforms/ios/www/js/favorites.js index ab3eb6fa..133db635 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/favorites.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/favorites.js @@ -16,6 +16,7 @@ import { let initialMoviesSelection = []; let initialTVSeriesSelection = []; +const IMGPATH = `https://image.tmdb.org/t/p/w500`; function translateFBC(value) { return atob(value); @@ -1368,12 +1369,12 @@ function getClassByRate(vote) { const searchForm = document.getElementById('form'); -searchForm.addEventListener('submit', e => { - e.preventDefault(); - const searchQuery = document.getElementById('search').value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'search.html'; -}); +// searchForm.addEventListener('submit', e => { +// e.preventDefault(); +// const searchQuery = document.getElementById('search').value; +// localStorage.setItem('searchQuery', searchQuery); +// window.location.href = 'search.html'; +// }); function handleSearch() { const searchQuery = document.getElementById('search').value; @@ -1389,13 +1390,26 @@ async function loadWatchLists() { const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + let watchlists = []; if (currentUserEmail) { - const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); - const querySnapshot = await getDocs(q); - const watchlists = querySnapshot.docs.map(doc => ({ - id: doc.id, - ...doc.data(), - })); + try { + // Attempt to fetch from Firebase first + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + watchlists = querySnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + + // Cache the results if successful + localStorage.setItem('cachedWatchlists_' + currentUserEmail, JSON.stringify(watchlists)); + } catch (firebaseError) { + console.warn('Firebase fetch failed, loading from cache:', firebaseError); + + // If Firebase fails, load from cache + const cachedWatchlists = JSON.parse(localStorage.getItem('cachedWatchlists_' + currentUserEmail)) || []; + watchlists = cachedWatchlists; + } if (watchlists.length === 0) { displaySection.innerHTML = '

No watch lists found. Click on "Create Watch Lists" to start adding movies.

'; @@ -1407,8 +1421,11 @@ async function loadWatchLists() { e.preventDefault(); document.getElementById('watchlist-header').scrollIntoView({ behavior: 'smooth' }); }); + + // Sort by order and pinned status watchlists.sort((a, b) => a.order - b.order); watchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of watchlists) { const watchlistDiv = await createWatchListDiv(watchlist); if (watchlist.pinned) { @@ -1418,8 +1435,8 @@ async function loadWatchLists() { } } } else { + // Handle the case where there is no signed-in user (local watchlists) let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - if (localWatchlists.length === 0) { displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; } else { @@ -1439,198 +1456,83 @@ async function loadWatchLists() { let favorites = []; let favoritesTVSeries = []; + // Load favorites and favoritesTVSeries, first attempting from Firebase and then cache if needed if (currentUserEmail) { - const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); - const userSnapshot = await getDocs(usersRef); + try { + // Attempt to fetch favorites from Firebase + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + const userSnapshot = await getDocs(usersRef); + if (!userSnapshot.empty) { + const userData = userSnapshot.docs[0].data(); + favorites = userData.favoritesMovies || []; + favoritesTVSeries = userData.favoritesTVSeries || []; + + // Cache the results if successful + localStorage.setItem('cachedFavorites_' + currentUserEmail, JSON.stringify({ favorites, favoritesTVSeries })); + } + } catch (firebaseError) { + console.warn('Firebase favorites fetch failed, loading from cache:', firebaseError); - if (!userSnapshot.empty) { - const userData = userSnapshot.docs[0].data(); - favorites = userData.favoritesMovies || []; - favoritesTVSeries = userData.favoritesTVSeries || []; + // If Firebase fails, load from cache + const cachedFavorites = JSON.parse(localStorage.getItem('cachedFavorites_' + currentUserEmail)) || {}; + favorites = cachedFavorites.favorites || []; + favoritesTVSeries = cachedFavorites.favoritesTVSeries || []; } } else { favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; } - if (favorites.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite Movies'; - title.className = 'watchlist-title'; - title.style.cursor = 'pointer'; - title.addEventListener('click', () => { - favoritesDiv.scrollIntoView({ behavior: 'smooth' }); - }); - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite movies.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - for (const movieId of favorites) { - const movieCard = await fetchMovieDetails(movieId); - moviesContainer.appendChild(movieCard); - } - - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - favoritesDiv.innerHTML = - '

Favorite Movies

No favorite movies added yet.

'; - displaySection.appendChild(favoritesDiv); - } - - if (favoritesTVSeries.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite TV Series'; - title.className = 'watchlist-title'; - title.style.cursor = 'pointer'; - title.addEventListener('click', () => { - favoritesDiv.scrollIntoView({ behavior: 'smooth' }); - }); - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite TV series.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - for (const tvSeriesId of favoritesTVSeries) { - const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); - moviesContainer.appendChild(tvSeriesCard); - } - - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; - favoritesDiv.innerHTML = - '

Favorite TV Series

No favorite TV series added yet.

'; - displaySection.appendChild(favoritesDiv); - } + // Display Favorites Movies and TV Series sections + displayFavoritesSection('Favorite Movies', favorites, displaySection); + displayFavoritesSection('Favorite TV Series', favoritesTVSeries, displaySection); hideSpinner(); } catch (error) { - if (error.code === 'resource-exhausted') { - let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - - if (localWatchlists.length === 0) { - displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; - } else { - displaySection.innerHTML = ''; - displaySection.innerHTML += '

Your Watch Lists

'; - localWatchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); - for (const watchlist of localWatchlists) { - const watchlistDiv = await createWatchListDiv(watchlist); - if (watchlist.pinned) { - watchlistDiv.classList.add('pinned'); - } - displaySection.appendChild(watchlistDiv); - } - } - - let favorites = []; - let favoritesTVSeries = []; - - favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; - favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; - - if (favorites.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite Movies'; - title.className = 'watchlist-title'; - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite movies.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - for (const movieId of favorites) { - const movieCard = await fetchMovieDetails(movieId); - moviesContainer.appendChild(movieCard); - } - - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - favoritesDiv.innerHTML = - '

Favorite Movies

No favorite movies added yet.

'; - displaySection.appendChild(favoritesDiv); - } + console.error('An unexpected error occurred:', error); + hideSpinner(); + } +} - if (favoritesTVSeries.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; +// Helper function to display favorite movies/TV series sections +async function displayFavoritesSection(titleText, items, displaySection) { + if (items.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); + + const title = document.createElement('h3'); + title.textContent = titleText; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + favoritesDiv.scrollIntoView({ behavior: 'smooth' }); + }); - const title = document.createElement('h3'); - title.textContent = 'Favorite TV Series'; - title.className = 'watchlist-title'; + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite TV series.'; - description.className = 'watchlist-description'; + const description = document.createElement('p'); + description.textContent = `A collection of your ${titleTextNew}.`; + description.className = 'watchlist-description'; - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; + const container = document.createElement('div'); + container.className = 'movies-container'; - for (const tvSeriesId of favoritesTVSeries) { - const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); - moviesContainer.appendChild(tvSeriesCard); - } + const cards = await Promise.all(items.map(titleText === 'Favorite Movies' ? fetchMovieDetails : fetchTVSeriesDetails)); + cards.forEach(card => container.appendChild(card)); - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - hideSpinner(); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; - favoritesDiv.innerHTML = - '

Favorite TV Series

No favorite TV series added yet.

'; - displaySection.appendChild(favoritesDiv); - hideSpinner(); - } - } else { - console.error('An error occurred:', error); - } + favoritesDiv.appendChild(container); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; + favoritesDiv.innerHTML = `

${titleText}

No ${titleTextNew} added yet.

`; + displaySection.appendChild(favoritesDiv); } } diff --git a/MovieVerse-Mobile/platforms/ios/www/js/movie-details.js b/MovieVerse-Mobile/platforms/ios/www/js/movie-details.js index 358b9d7c..760f07d0 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/movie-details.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/movie-details.js @@ -1921,17 +1921,17 @@ function updateMoviesFavorited(movieId) { } function getMovieCode2() { - const codeOfMovie = 'MmJhOGU1MzY='; + const codeOfMovie = 'MmJhOG' + 'U1MzY='; return atob(codeOfMovie); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa2' + 'V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/platforms/ios/www/js/movie-timeline.js b/MovieVerse-Mobile/platforms/ios/www/js/movie-timeline.js index 1052ad5c..6aff1353 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/movie-timeline.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/movie-timeline.js @@ -362,6 +362,7 @@ function rotateImages(imageElements, interval = 3000) { function showMovies(movies, mainElement, startYear, endYear, append) { showSpinner(); + // Add header for the selected year range if not appending if (!append) { mainElement.innerHTML = ''; const header = document.createElement('h2'); @@ -370,31 +371,28 @@ function showMovies(movies, mainElement, startYear, endYear, append) { header.style.marginBottom = '20px'; header.style.color = '#ff8623'; header.style.fontSize = '23px'; - if (startYear === endYear) { - header.textContent = `Movies released in ${startYear}`; - } else { - header.textContent = `Movies released between ${startYear} and ${endYear}`; - } + header.textContent = startYear === endYear ? `Movies released in ${startYear}` : `Movies released between ${startYear} and ${endYear}`; + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.innerHTML = ''; centerContainer1.appendChild(header); centerContainer1.appendChild(mainElement); } - const observer = new IntersectionObserver( + // Observer for loading additional images when movie enters viewport + const imageObserver = new IntersectionObserver( async (entries, observer) => { for (const entry of entries) { if (entry.isIntersecting) { const movieEl = entry.target; const movieId = movieEl.dataset.id; + // Fetch and set up additional posters const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - - const movieImageContainer = movieEl.querySelector('.movie-images'); - allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); + const movieImageContainer = movieEl.querySelector('.movie-images'); const imagePromises = allPosters.map((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; @@ -415,9 +413,11 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); }); + // Wait for images to load or timeout after 3 seconds const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); await Promise.race([Promise.all(imagePromises), maxWait]); + // Show the first poster image movieImageContainer.querySelector('.poster-img').style.opacity = '1'; rotateImages(Array.from(movieImageContainer.children)); @@ -441,6 +441,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; + // Limit the title to 8 words, adding "..." if necessary const words = title.split(' '); if (words.length >= 8) { words[7] = '...'; @@ -454,6 +455,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { overview = 'No overview available.'; } + // Define HTML structure for the movie card movieEl.innerHTML = `
@@ -478,8 +480,26 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); mainElement.appendChild(movieEl); - observer.observe(movieEl); + imageObserver.observe(movieEl); + + // Observer for the slide-up animation + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.appendChild(mainElement); @@ -487,6 +507,24 @@ function showMovies(movies, mainElement, startYear, endYear, append) { hideSpinner(); } +// Inject CSS for sliding-up animation if it doesn't already exist +if (!document.getElementById('slide-animation-style')) { + const style = document.createElement('style'); + style.id = 'slide-animation-style'; + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); +} + function createLoadMoreButton(startYear, endYear, mainElement) { const existingButtonDiv = mainElement.querySelector('.load-more-container'); if (existingButtonDiv) { diff --git a/MovieVerse-Mobile/platforms/ios/www/js/ratings-module.js b/MovieVerse-Mobile/platforms/ios/www/js/ratings-module.js index 80d4ec59..1a5a096b 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/ratings-module.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/ratings-module.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/platforms/ios/www/js/search.js b/MovieVerse-Mobile/platforms/ios/www/js/search.js index 82bdc1cf..985710f0 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/search.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/search.js @@ -807,6 +807,21 @@ function rotateImages(imageElements, interval = 3000) { async function showMovies(items, container, category) { container.innerHTML = ''; + // Inject CSS for sliding-up animation if it doesn't already exist + const style = document.createElement('style'); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 1s ease, transform 1s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + items.forEach(async item => { const hasVoteAverage = typeof item.vote_average === 'number'; const isPerson = !hasVoteAverage; @@ -815,7 +830,6 @@ async function showMovies(items, container, category) { let title = item.title || item.name || 'N/A'; const words = title.split(' '); - if (words.length >= 8) { words[7] = '...'; title = words.slice(0, 8).join(' '); @@ -823,7 +837,6 @@ async function showMovies(items, container, category) { let overview = item.overview || 'Click to view the details of this movie/TV series.'; const biography = item.biography || 'Click to view the details of this person.'; - if (overview === '') { overview = 'Click to view the details of this movie/TV series.'; } @@ -971,6 +984,23 @@ async function showMovies(items, container, category) { const img = movieEl.querySelector('img'); observer.observe(img); } + + // Slide-up animation observer + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); } diff --git a/MovieVerse-Mobile/platforms/ios/www/js/systemjs-importmap.js b/MovieVerse-Mobile/platforms/ios/www/js/systemjs-importmap.js index ea5553e9..bd50dc83 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/systemjs-importmap.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/systemjs-importmap.js @@ -23,3 +23,6 @@ System.import('@system-env').then(env => { }); } }); + +// Replace 'your-production-url' with the actual URL of your production server. +// Mine is not included here for security reasons. diff --git a/MovieVerse-Mobile/platforms/ios/www/js/triviaModule.js b/MovieVerse-Mobile/platforms/ios/www/js/triviaModule.js index e84a36b9..b16799fe 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/triviaModule.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/triviaModule.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/platforms/ios/www/js/tv-details.js b/MovieVerse-Mobile/platforms/ios/www/js/tv-details.js index 78b47ba6..b0dfdafc 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/tv-details.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/tv-details.js @@ -1833,17 +1833,17 @@ function applySettings() { } function getMovieCode2() { - const encodedKey = 'MmJhOGU1MzY='; + const encodedKey = 'MmJhOG' + 'U1MzY='; return atob(encodedKey); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa' + '2V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/platforms/ios/www/js/user-profile.js b/MovieVerse-Mobile/platforms/ios/www/js/user-profile.js index c8c41a52..f27aa80f 100644 --- a/MovieVerse-Mobile/platforms/ios/www/js/user-profile.js +++ b/MovieVerse-Mobile/platforms/ios/www/js/user-profile.js @@ -170,38 +170,37 @@ async function performSearch(searchText) { showSpinner(); try { + const cachedSearchResults = localStorage.getItem(`movieVerseSearchCache_${searchText}`); + if (cachedSearchResults) { + const parsedCache = JSON.parse(cachedSearchResults); + const cacheAge = Date.now() - parsedCache.timestamp; + + if (cacheAge < 24 * 60 * 60 * 1000) { + displaySearchResults(parsedCache.results, searchText); + hideSpinner(); + return; + } + } + const userQuery = query(collection(db, 'profiles'), where('username', '>=', searchText), where('username', '<=', searchText + '\uf8ff')); const querySnapshot = await getDocs(userQuery); searchUserResults.innerHTML = ''; + if (querySnapshot.empty) { searchUserResults.innerHTML = `
No User with Username "${searchText}" found
`; searchUserResults.style.display = 'block'; + localStorage.setItem(`movieVerseSearchCache_${searchText}`, JSON.stringify({ results: [], timestamp: Date.now() })); } else { - searchUserResults.style.display = 'block'; + const results = []; querySnapshot.forEach(doc => { const user = doc.data(); - const userDiv = document.createElement('div'); - userDiv.className = 'user-search-result'; - userDiv.style.cursor = 'pointer'; - userDiv.addEventListener('click', () => loadProfile(doc.id)); - - const img = document.createElement('img'); - img.src = user.profileImage || '../../images/user-default.png'; - img.style.width = '33%'; - img.style.borderRadius = '8px'; - userDiv.appendChild(img); - - const textDiv = document.createElement('div'); - textDiv.style.width = '67%'; - textDiv.style.textAlign = 'left'; - textDiv.innerHTML = `${user.username}

Bio: ${ - user.bio || 'Not Set' - }

`; - userDiv.appendChild(textDiv); - - searchUserResults.appendChild(userDiv); + results.push({ id: doc.id, ...user }); }); + + localStorage.setItem(`movieVerseSearchCache_${searchText}`, JSON.stringify({ results, timestamp: Date.now() })); + + displaySearchResults(results, searchText); } hideSpinner(); } catch (error) { @@ -212,6 +211,41 @@ async function performSearch(searchText) { } } +function displaySearchResults(results, searchText) { + const searchUserResults = document.getElementById('searchUserResults'); + searchUserResults.innerHTML = ''; + + if (results.length === 0) { + searchUserResults.innerHTML = `
No User with Username "${searchText}" found
`; + searchUserResults.style.display = 'block'; + return; + } + + results.forEach(user => { + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadProfile(user.id)); + + const img = document.createElement('img'); + img.src = user.profileImage || '../../images/user-default.png'; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.username}

Bio: ${ + user.bio || 'Not Set' + }

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + searchUserResults.style.display = 'block'; +} + document.getElementById('container1').addEventListener('click', async () => { const userEmail = localStorage.getItem('currentlyViewingProfile'); @@ -348,9 +382,23 @@ async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMo followUnfollowBtn.style.display = 'none'; } - try { + const cacheKey = `movieVerseProfileCache_${userEmail}`; + const cachedData = localStorage.getItem(cacheKey); + let profile = null; + + if (cachedData) { + const parsedCache = JSON.parse(cachedData); + const cacheAge = Date.now() - parsedCache.timestamp; + + if (cacheAge < 24 * 60 * 60 * 1000) { + profile = parsedCache.profile; + } + } + + if (!profile) { const docSnap = await getDoc(docRef); - let profile = { + + profile = { username: 'N/A', dob: 'N/A', bio: 'N/A', @@ -366,91 +414,46 @@ async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMo if (docSnap.exists()) { profile = { ...profile, ...docSnap.data() }; - const imageUrl = profile.profileImage || '../../images/user-default.png'; - document.getElementById('profileImage').src = imageUrl; - - if ( - userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || - !localStorage.getItem('currentlySignedInMovieVerseUser') || - !JSON.parse(localStorage.getItem('isSignedIn')) || - profile.profileImage === '../../images/user-default.png' - ) { - removeProfileImageBtn.style.display = 'none'; - } else { - removeProfileImageBtn.style.display = 'inline'; - } - - document.getElementById('usernameDisplay').innerHTML = `Username: ${profile.username}`; - document.getElementById('dobDisplay').innerHTML = `Date of Birth: ${profile.dob}`; - document.getElementById('bioDisplay').innerHTML = `Bio: ${profile.bio}`; - document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: ${profile.favoriteGenres}`; - document.getElementById('locationDisplay').innerHTML = `Location: ${profile.location}`; - document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: ${profile.favoriteMovie}`; - document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: ${profile.hobbies}`; - document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: ${profile.favoriteActor}`; - document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: ${profile.favoriteDirector}`; - document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: ${profile.personalQuote}`; - window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; - - if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { - welcomeMessage.textContent = `Welcome, ${profile.username}!`; - } else { - welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; - } + } - hideSpinner(); + localStorage.setItem(cacheKey, JSON.stringify({ profile, timestamp: Date.now() })); + } - await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); - } else { - const imageUrl = profile.profileImage || '../../images/user-default.png'; - document.getElementById('profileImage').src = imageUrl; - - if ( - userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || - !localStorage.getItem('currentlySignedInMovieVerseUser') || - !JSON.parse(localStorage.getItem('isSignedIn')) || - profile.profileImage === '../../images/user-default.png' - ) { - removeProfileImageBtn.style.display = 'none'; - } else { - removeProfileImageBtn.style.display = 'inline'; - } + const imageUrl = profile.profileImage || '../../images/user-default.png'; + document.getElementById('profileImage').src = imageUrl; - document.getElementById('usernameDisplay').innerHTML = `Username: N/A`; - document.getElementById('dobDisplay').innerHTML = `Date of Birth: N/A`; - document.getElementById('bioDisplay').innerHTML = `Bio: N/A`; - document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: N/A`; - document.getElementById('locationDisplay').innerHTML = `Location: N/A`; - document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: N/A`; - document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: N/A`; - document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: N/A`; - document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: N/A`; - document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: N/A`; - window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; - - if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { - welcomeMessage.textContent = `Welcome, ${profile.username}!`; - } else { - welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; - } + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) || + profile.profileImage === '../../images/user-default.png' + ) { + removeProfileImageBtn.style.display = 'none'; + } else { + removeProfileImageBtn.style.display = 'inline'; + } - hideSpinner(); + document.getElementById('usernameDisplay').innerHTML = `Username: ${profile.username}`; + document.getElementById('dobDisplay').innerHTML = `Date of Birth: ${profile.dob}`; + document.getElementById('bioDisplay').innerHTML = `Bio: ${profile.bio}`; + document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: ${profile.favoriteGenres}`; + document.getElementById('locationDisplay').innerHTML = `Location: ${profile.location}`; + document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: ${profile.favoriteMovie}`; + document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: ${profile.hobbies}`; + document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: ${profile.favoriteActor}`; + document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: ${profile.favoriteDirector}`; + document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: ${profile.personalQuote}`; + window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; + + if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { + welcomeMessage.textContent = `Welcome, ${profile.username}!`; + } else { + welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; + } - await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); - } - } catch (error) { - if (error.code === 'resource-exhausted') { - const noUserSelected = document.getElementById('profileContainer'); - if (noUserSelected) { - noUserSelected.innerHTML = - "Sorry, the profile feature is currently unavailable as our databases are overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; - noUserSelected.style.height = '350px'; - noUserSelected.style.display = 'block'; - } - } + hideSpinner(); - document.getElementById('viewMyProfileBtn').disabled = true; - } + await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); } catch (error) { console.error('Error fetching user list: ', error); if (error.code === 'resource-exhausted') { @@ -557,11 +560,16 @@ async function saveProfileChanges() { favoriteActor: document.getElementById('editFavoriteActor').value, favoriteDirector: document.getElementById('editFavoriteDirector').value, personalQuote: document.getElementById('editPersonalQuote').value, + profileImage: currentProfile?.profileImage || '', }; try { await setDoc(profileRef, profile, { merge: true }); console.log('Profile updated successfully.'); + + const cacheKey = `movieVerseProfileCache_${userEmail}`; + localStorage.setItem(cacheKey, JSON.stringify({ profile, timestamp: Date.now() })); + closeModal(); loadProfile(); } catch (error) { @@ -579,6 +587,15 @@ async function removeProfileImage() { await setDoc(doc(db, 'profiles', userEmail), { profileImage: defaultImageUrl }, { merge: true }); document.getElementById('profileImage').src = defaultImageUrl; document.getElementById('removeProfileImage').style.display = 'none'; + + const cacheKey = `movieVerseProfileCache_${userEmail}`; + const cachedProfile = JSON.parse(localStorage.getItem(cacheKey)); + + if (cachedProfile && cachedProfile.profile) { + cachedProfile.profile.profileImage = defaultImageUrl; + cachedProfile.timestamp = Date.now(); + localStorage.setItem(cacheKey, JSON.stringify(cachedProfile)); + } } catch (error) { console.log('Error removing image: ', error); } @@ -605,6 +622,16 @@ async function uploadImage() { document.getElementById('profileImage').src = base64Image; console.log('Image processed and Firestore updated'); + + const cacheKey = `movieVerseProfileCache_${userEmail}`; + const cachedProfile = JSON.parse(localStorage.getItem(cacheKey)); + + if (cachedProfile && cachedProfile.profile) { + cachedProfile.profile.profileImage = base64Image; + cachedProfile.timestamp = Date.now(); + localStorage.setItem(cacheKey, JSON.stringify(cachedProfile)); + } + window.location.reload(); } catch (error) { console.log('Error during image processing:', error); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/chat.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/chat.js index ea37a061..226a1460 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/chat.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/chat.js @@ -48,6 +48,16 @@ document.addEventListener('DOMContentLoaded', () => { } }); +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + async function animateLoadingDots() { const loadingTextElement = document.querySelector('#myModal p'); let dots = ''; @@ -60,12 +70,12 @@ async function animateLoadingDots() { } const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/chatbot.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/chatbot.js index b45116a6..d01a5e35 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/chatbot.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/chatbot.js @@ -455,7 +455,7 @@ function removeMarkdown(text) { } function getAIResponse() { - const response = 'QUl6YVN5Q1RoUWVFdmNUb01ka0NqWlM3UTNxNzZBNUNlNjVyMW9r'; + const response = 'QUl6YVN' + '5QnRIdGJIVW' + 'N6enExT1p3Z' + 'XB0TXNOd' + 'Fdlal9s' + 'U0lWcWZ3'; return atob(response); } diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/comments-tv.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/comments-tv.js index b2f4a292..99aa511c 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/comments-tv.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/comments-tv.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/comments.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/comments.js index 18fa74d9..e88e4fdc 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/comments.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/comments.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/favorites.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/favorites.js index 6e4206e5..133db635 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/favorites.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/favorites.js @@ -1499,7 +1499,7 @@ async function displayFavoritesSection(titleText, items, displaySection) { if (items.length > 0) { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = titleText.toLowerCase().replace(' ', '-'); + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); const title = document.createElement('h3'); title.textContent = titleText; @@ -1509,8 +1509,10 @@ async function displayFavoritesSection(titleText, items, displaySection) { favoritesDiv.scrollIntoView({ behavior: 'smooth' }); }); + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; + const description = document.createElement('p'); - description.textContent = `A collection of your ${titleText.toLowerCase()}.`; + description.textContent = `A collection of your ${titleTextNew}.`; description.className = 'watchlist-description'; favoritesDiv.appendChild(title); @@ -1527,8 +1529,9 @@ async function displayFavoritesSection(titleText, items, displaySection) { } else { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = titleText.toLowerCase().replace(' ', '-'); - favoritesDiv.innerHTML = `

${titleText}

No ${titleText.toLowerCase()} added yet.

`; + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; + favoritesDiv.innerHTML = `

${titleText}

No ${titleTextNew} added yet.

`; displaySection.appendChild(favoritesDiv); } } diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/movie-details.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/movie-details.js index 358b9d7c..760f07d0 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/movie-details.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/movie-details.js @@ -1921,17 +1921,17 @@ function updateMoviesFavorited(movieId) { } function getMovieCode2() { - const codeOfMovie = 'MmJhOGU1MzY='; + const codeOfMovie = 'MmJhOG' + 'U1MzY='; return atob(codeOfMovie); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa2' + 'V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/ratings-module.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/ratings-module.js index 80d4ec59..1a5a096b 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/ratings-module.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/ratings-module.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/systemjs-importmap.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/systemjs-importmap.js index ea5553e9..bd50dc83 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/systemjs-importmap.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/systemjs-importmap.js @@ -23,3 +23,6 @@ System.import('@system-env').then(env => { }); } }); + +// Replace 'your-production-url' with the actual URL of your production server. +// Mine is not included here for security reasons. diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/triviaModule.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/triviaModule.js index e84a36b9..b16799fe 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/triviaModule.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/triviaModule.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/tv-details.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/tv-details.js index 78b47ba6..b0dfdafc 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/tv-details.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/tv-details.js @@ -1833,17 +1833,17 @@ function applySettings() { } function getMovieCode2() { - const encodedKey = 'MmJhOGU1MzY='; + const encodedKey = 'MmJhOG' + 'U1MzY='; return atob(encodedKey); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa' + '2V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/www/index.html b/MovieVerse-Mobile/www/index.html index 74a10688..8f2cecd9 100644 --- a/MovieVerse-Mobile/www/index.html +++ b/MovieVerse-Mobile/www/index.html @@ -304,111 +304,6 @@ bottom: 70px; } } - #githubLink { - color: white !important; - } - #githubLink:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink7 { - color: white !important; - } - #githubLink7:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink8 { - color: white !important; - } - #githubLink8:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink9 { - color: white !important; - } - #githubLink9:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink10 { - color: white !important; - } - #githubLink10:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink11 { - color: white !important; - } - #githubLink11:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink12 { - color: white !important; - } - #githubLink12:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink14 { - color: white !important; - } - #githubLink14:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink15 { - color: white !important; - } - #githubLink15:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink16 { - color: white !important; - } - #githubLink16:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink19 { - color: white !important; - } - #githubLink19:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink3 { - color: white !important; - } - #githubLink3:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink4 { - color: white !important; - } - #githubLink4:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink5 { - color: white !important; - } - #githubLink5:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } - #githubLink6 { - color: white !important; - } - #githubLink6:hover { - color: #ff8623 !important; - transition: 0.1s ease-in; - } #other { margin-top: 40px; } @@ -419,30 +314,6 @@ min-height: 54px; text-align: center; } - #ad-container { - display: block; - } - #ad-container1 { - display: block; - } - #ad-container2 { - display: block; - } - #ad-container3 { - display: block; - } - #ad-container4 { - display: block; - } - #ad-container5 { - display: block; - } - #ad-container6 { - display: block; - } - #ad-container7 { - display: block; - } #my-heading { margin-top: 19.5px !important; } @@ -453,7 +324,6 @@ #my-heading { margin-top: -5px !important; } - #my-heading1 { margin-top: -5px !important; } @@ -534,6 +404,36 @@ opacity: 0; animation: dropIn 1s ease forwards 2s; } + #sticky-menu-button { + display: none; + } + @media (max-width: 767px) { + #sticky-menu-button { + position: fixed; + top: 50%; + left: 10px; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border: none; + border-radius: 8px; + padding: 10px; + font-size: 16px; + cursor: pointer; + z-index: 1001; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + display: flex; + align-items: center; + justify-content: center; + } + #sticky-menu-button:hover { + background-color: #ff8623; + transition: 0.2s ease-in-out; + } + #sticky-menu-button i { + font-size: 18px; + } + } @@ -559,6 +459,9 @@

+

`; - movieEl.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', id); + movieEl.addEventListener("click", () => { + localStorage.setItem("selectedMovieId", id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; }); director_main.appendChild(movieEl); @@ -1124,13 +1233,13 @@ function showMoviesDirectorSpotlight(movies) { } function handleSignInOut() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; if (isSignedIn) { - localStorage.setItem('isSignedIn', JSON.stringify(false)); - alert('You have been signed out.'); + localStorage.setItem("isSignedIn", JSON.stringify(false)); + alert("You have been signed out."); } else { - window.location.href = 'MovieVerse-Frontend/html/sign-in.html'; + window.location.href = "MovieVerse-Frontend/html/sign-in.html"; return; } @@ -1138,213 +1247,234 @@ function handleSignInOut() { } function updateSignInButtonState() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; - const signInText = document.getElementById('signInOutText'); - const signInIcon = document.getElementById('signInIcon'); - const signOutIcon = document.getElementById('signOutIcon'); + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; + const signInText = document.getElementById("signInOutText"); + const signInIcon = document.getElementById("signInIcon"); + const signOutIcon = document.getElementById("signOutIcon"); if (isSignedIn) { - signInText.textContent = 'Sign Out'; - signInIcon.style.display = 'none'; - signOutIcon.style.display = 'inline-block'; + signInText.textContent = "Sign Out"; + signInIcon.style.display = "none"; + signOutIcon.style.display = "inline-block"; } else { - signInText.textContent = 'Sign In'; - signInIcon.style.display = 'inline-block'; - signOutIcon.style.display = 'none'; + signInText.textContent = "Sign In"; + signInIcon.style.display = "inline-block"; + signOutIcon.style.display = "none"; } - const mobileSignInText = document.getElementById('mobileSignInOutText'); - const mobileSignInIcon = document.getElementById('mobileSignInIcon'); - const mobileSignOutIcon = document.getElementById('mobileSignOutIcon'); + const mobileSignInText = document.getElementById("mobileSignInOutText"); + const mobileSignInIcon = document.getElementById("mobileSignInIcon"); + const mobileSignOutIcon = document.getElementById("mobileSignOutIcon"); if (isSignedIn) { - mobileSignInText.textContent = 'Sign Out'; - mobileSignInIcon.style.display = 'none'; - mobileSignOutIcon.style.display = 'inline-block'; + mobileSignInText.textContent = "Sign Out"; + mobileSignInIcon.style.display = "none"; + mobileSignOutIcon.style.display = "inline-block"; } else { - mobileSignInText.textContent = 'Sign In'; - mobileSignInIcon.style.display = 'inline-block'; - mobileSignOutIcon.style.display = 'none'; + mobileSignInText.textContent = "Sign In"; + mobileSignInIcon.style.display = "inline-block"; + mobileSignOutIcon.style.display = "none"; } } setupPagination( - 'award-winning', - 'award-winning-pagination', - 'award-winning-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000` + "award-winning", + "award-winning-pagination", + "award-winning-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000`, ); setupPagination( - 'hidden-gems', - 'hidden-gems-pagination', - 'hidden-gems-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10` + "hidden-gems", + "hidden-gems-pagination", + "hidden-gems-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10`, ); setupPagination( - 'western', - 'western-pagination', - 'western-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8` + "western", + "western-pagination", + "western-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'war', - 'war-pagination', - 'war-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8` + "war", + "war-pagination", + "war-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'vietnamese', - 'vietnamese-pagination', - 'vietnamese-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc` + "vietnamese", + "vietnamese-pagination", + "vietnamese-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc`, ); setupPagination( - 'korean', - 'korean-pagination', - 'korean-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8` + "korean", + "korean-pagination", + "korean-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8`, ); setupPagination( - 'musical', - 'musical-pagination', - 'musical-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8` + "musical", + "musical-pagination", + "musical-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'drama', - 'drama-pagination', - 'drama-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8` + "drama", + "drama-pagination", + "drama-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'indian', - 'indian-pagination', - 'indian-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc` + "indian", + "indian-pagination", + "indian-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc`, ); setupPagination( - 'action', - 'action-pagination', - 'action-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8` + "action", + "action-pagination", + "action-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'horror', - 'horror-pagination', - 'horror-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8` + "horror", + "horror-pagination", + "horror-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'documentary', - 'documentary-pagination', - 'documentary-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8` + "documentary", + "documentary-pagination", + "documentary-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'animation', - 'animation-pagination', - 'animation-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8` + "animation", + "animation-pagination", + "animation-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'sci-fi', - 'sci-fi-pagination', - 'sci-fi-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8` + "sci-fi", + "sci-fi-pagination", + "sci-fi-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'romantic', - 'romantic-pagination', - 'romantic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8` + "romantic", + "romantic-pagination", + "romantic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'thriller', - 'thriller-pagination', - 'thriller-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8` + "thriller", + "thriller-pagination", + "thriller-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'mystery', - 'mystery-pagination', - 'mystery-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8` + "mystery", + "mystery-pagination", + "mystery-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'comedy', - 'comedy-pagination', - 'comedy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8` + "comedy", + "comedy-pagination", + "comedy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'fantasy', - 'fantasy-pagination', - 'fantasy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8` + "fantasy", + "fantasy-pagination", + "fantasy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'family', - 'family-pagination', - 'family-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8` + "family", + "family-pagination", + "family-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'tv-series', - 'tv-series-pagination', - 'tv-series-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8` + "tv-series", + "tv-series-pagination", + "tv-series-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'crime', - 'crime-pagination', - 'crime-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8` + "crime", + "crime-pagination", + "crime-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'classic', - 'classic-pagination', - 'classic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980` + "classic", + "classic-pagination", + "classic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980`, ); -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { updateSignInButtonState(); - document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); + document + .getElementById("googleSignInBtn") + .addEventListener("click", handleSignInOut); }); function handleSearch() { - const searchQuery = document.getElementById('search').value; + const searchQuery = document.getElementById("search").value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'MovieVerse-Frontend/html/search.html'; + localStorage.setItem("searchQuery", searchQuery); + window.location.href = "MovieVerse-Frontend/html/search.html"; } -document.addEventListener('DOMContentLoaded', () => { - const notificationBtn = document.getElementById('notificationBtn'); +document.addEventListener("DOMContentLoaded", () => { + const notificationBtn = document.getElementById("notificationBtn"); - notificationBtn.addEventListener('click', () => { - window.location.href = 'MovieVerse-Frontend/html/notifications.html'; + notificationBtn.addEventListener("click", () => { + window.location.href = "MovieVerse-Frontend/html/notifications.html"; }); }); + +document.addEventListener("DOMContentLoaded", function () { + const stickyMenuButton = document.getElementById("sticky-menu-button"); + + // Initially hide the button + stickyMenuButton.style.display = "none"; + + // Function to toggle visibility based on scroll position + function toggleStickyMenuButton() { + if (window.scrollY > 0) { + stickyMenuButton.style.display = "flex"; + } else { + stickyMenuButton.style.display = "none"; + } + } + + // Listen for scroll events + window.addEventListener("scroll", toggleStickyMenuButton); +}); diff --git a/MovieVerse-Mobile/www/js/chat.js b/MovieVerse-Mobile/www/js/chat.js index 25fecf0e..226a1460 100644 --- a/MovieVerse-Mobile/www/js/chat.js +++ b/MovieVerse-Mobile/www/js/chat.js @@ -48,6 +48,16 @@ document.addEventListener('DOMContentLoaded', () => { } }); +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + async function animateLoadingDots() { const loadingTextElement = document.querySelector('#myModal p'); let dots = ''; @@ -60,12 +70,12 @@ async function animateLoadingDots() { } const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; initializeApp(firebaseConfig); @@ -214,6 +224,21 @@ const noUserSelected = document.getElementById('noUserSelected'); chatSection.style.display = 'none'; noUserSelected.style.display = 'flex'; +const LOCAL_STORAGE_MESSAGES_KEY_PREFIX = 'movieVerseMessagesCache'; + +function getCachedMessages(conversationKey) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_MESSAGES_KEY_PREFIX + conversationKey); + return cachedData ? JSON.parse(cachedData) : []; +} + +function updateMessageCache(conversationKey, messages) { + localStorage.setItem(LOCAL_STORAGE_MESSAGES_KEY_PREFIX + conversationKey, JSON.stringify(messages)); +} + +function clearMessageCache(conversationKey) { + localStorage.removeItem(LOCAL_STORAGE_MESSAGES_KEY_PREFIX + conversationKey); +} + async function loadMessages(userEmail) { selectedUserEmail = userEmail; messagesDiv.innerHTML = ''; @@ -232,6 +257,17 @@ async function loadMessages(userEmail) { selectedUser.classList.add('selected'); } + const conversationKey = `${currentUserEmail}_${selectedUserEmail}`; + + const cachedMessages = getCachedMessages(conversationKey); + if (cachedMessages.length > 0) { + cachedMessages.forEach(msg => { + const messageElement = formatMessage(msg.message, msg.isCurrentUser, msg.timestamp); + messagesDiv.appendChild(messageElement); + }); + messagesDiv.scrollTop = messagesDiv.scrollHeight; + } + const messagesQuery = query( collection(db, 'messages'), orderBy('timestamp'), @@ -240,6 +276,8 @@ async function loadMessages(userEmail) { ); onSnapshot(messagesQuery, snapshot => { + const newMessages = []; + messagesDiv.innerHTML = ''; snapshot.docs.forEach(doc => { const messageData = doc.data(); @@ -251,8 +289,16 @@ async function loadMessages(userEmail) { if (!isCurrentUser && (!messageData.readBy || !messageData.readBy.includes(currentUserEmail))) { updateReadStatus(doc.id); } + + newMessages.push({ + message: messageData.message, + isCurrentUser, + timestamp: timestamp ? timestamp.toDate().toISOString() : null, + }); }); + updateMessageCache(conversationKey, newMessages); + messagesDiv.scrollTop = messagesDiv.scrollHeight; }); } @@ -289,8 +335,53 @@ function setupSearchListeners() { }); } +const LOCAL_STORAGE_SEARCH_CACHE_KEY = 'movieVerseSearchCache'; + +function getCachedSearchResults(query) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_SEARCH_CACHE_KEY); + if (cachedData) { + const searchCache = JSON.parse(cachedData); + return searchCache[query] ? searchCache[query].results : null; + } + return null; +} + +function updateSearchCache(query, results) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_SEARCH_CACHE_KEY); + const searchCache = cachedData ? JSON.parse(cachedData) : {}; + searchCache[query] = { results, lastUpdated: Date.now() }; + localStorage.setItem(LOCAL_STORAGE_SEARCH_CACHE_KEY, JSON.stringify(searchCache)); +} + async function performSearch(searchText, isNewSearch = false) { const searchUserResults = document.getElementById('searchUserResults'); + const cachedResults = getCachedSearchResults(searchText); + + if (cachedResults && isNewSearch) { + searchUserResults.innerHTML = ''; + cachedResults.forEach(user => { + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadMessages(user.email)); + + const img = document.createElement('img'); + img.src = user.imageUrl || '../../images/user-default.png'; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.email}

${user.bio || ''}

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + searchUserResults.style.display = 'block'; + return; + } try { showSpinner(); @@ -318,6 +409,7 @@ async function performSearch(searchText, isNewSearch = false) { lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1]; } + const results = []; for (const doc of querySnapshot.docs) { const user = doc.data(); const userDiv = document.createElement('div'); @@ -346,6 +438,7 @@ async function performSearch(searchText, isNewSearch = false) { userDiv.appendChild(textDiv); searchUserResults.appendChild(userDiv); + results.push({ email: user.email, bio: user.bio, imageUrl }); } searchUserResults.style.display = 'block'; @@ -363,6 +456,10 @@ async function performSearch(searchText, isNewSearch = false) { loadMoreButton.style.display = 'none'; } } + + if (isNewSearch) { + updateSearchCache(searchText, results); + } } catch (error) { console.error('Error fetching user list: ', error); if (error.code === 'resource-exhausted') { @@ -379,12 +476,31 @@ async function performSearch(searchText, isNewSearch = false) { let previouslySelectedUserElement = null; +const LOCAL_STORAGE_USER_CACHE_KEY = 'movieVerseUserCache'; + +function getCachedUsers() { + const cachedData = localStorage.getItem(LOCAL_STORAGE_USER_CACHE_KEY); + return cachedData ? JSON.parse(cachedData) : {}; +} + +function updateUserCache(email, userData) { + const currentCache = getCachedUsers(); + currentCache[email] = userData; + localStorage.setItem(LOCAL_STORAGE_USER_CACHE_KEY, JSON.stringify(currentCache)); +} + +function clearUserCache() { + localStorage.removeItem(LOCAL_STORAGE_USER_CACHE_KEY); +} + +const inMemoryUserCache = {}; // In-memory cache for user data + async function loadUserList() { try { showSpinner(); animateLoadingDots(); - const userLimit = 5; + const userLimit = 10; const messageLimit = 30; const sentMessagesQuery = query( @@ -393,6 +509,7 @@ async function loadUserList() { where('sender', '==', currentUserEmail), limit(messageLimit) ); + const receivedMessagesQuery = query( collection(db, 'messages'), orderBy('timestamp', 'desc'), @@ -407,19 +524,37 @@ async function loadUserList() { receivedMessagesSnapshot.forEach(doc => userEmails.add(doc.data().sender)); let users = []; + const cachedUsers = getCachedUsers(); + const emailsToFetch = []; + for (let email of userEmails) { if (email) { - const userQuery = query(collection(db, 'MovieVerseUsers'), where('email', '==', email)); - const userSnapshot = await getDocs(userQuery); - userSnapshot.forEach(doc => { - let userData = doc.data(); - if (userData.email) { - users.push(userData); - } - }); + if (cachedUsers[email]) { + users.push(cachedUsers[email]); + inMemoryUserCache[email] = cachedUsers[email]; + } else if (inMemoryUserCache[email]) { + users.push(inMemoryUserCache[email]); + } else { + emailsToFetch.push(email); + } } } + if (emailsToFetch.length > 0) { + const userQuery = query(collection(db, 'MovieVerseUsers'), where('email', 'in', emailsToFetch.slice(0, 10))); + + const userSnapshot = await getDocs(userQuery); + userSnapshot.forEach(doc => { + const userData = doc.data(); + if (userData.email) { + userData.lastUpdated = Date.now(); + users.push(userData); + updateUserCache(userData.email, userData); + inMemoryUserCache[userData.email] = userData; + } + }); + } + users.sort((a, b) => { const aLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find( doc => doc.data().sender === a.email || doc.data().recipient === a.email @@ -450,12 +585,27 @@ async function loadUserList() { previouslySelectedUserElement = userElement; }; - const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); - const profileSnapshot = await getDocs(profileQuery); let imageUrl = '../../images/user-default.png'; - if (!profileSnapshot.empty) { - const profileData = profileSnapshot.docs[0].data(); - imageUrl = profileData.profileImage || imageUrl; + if (cachedUsers[user.email] && cachedUsers[user.email].profileImage) { + imageUrl = cachedUsers[user.email].profileImage; + } else if (inMemoryUserCache[user.email] && inMemoryUserCache[user.email].profileImage) { + imageUrl = inMemoryUserCache[user.email].profileImage; + } else { + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); + const profileSnapshot = await getDocs(profileQuery); + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + + if (cachedUsers[user.email]) { + cachedUsers[user.email].profileImage = imageUrl; + updateUserCache(user.email, cachedUsers[user.email]); + } + inMemoryUserCache[user.email] = { + ...inMemoryUserCache[user.email], + profileImage: imageUrl, + }; + } } const img = document.createElement('img'); diff --git a/MovieVerse-Mobile/www/js/chatbot.js b/MovieVerse-Mobile/www/js/chatbot.js index db8687e8..d01a5e35 100644 --- a/MovieVerse-Mobile/www/js/chatbot.js +++ b/MovieVerse-Mobile/www/js/chatbot.js @@ -383,7 +383,7 @@ async function movieVerseResponse(message) { const model = genAI.getGenerativeModel({ model: 'gemini-1.5-flash', systemInstruction: - 'You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users.', + "You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users. If the user asks anything about you or your information, you must by default identify yourself as MovieVerse Assistant, trained by The MovieVerse creator - Son Nguyen, and you're here to provide assistance for any movie-related or any other general inquiries. If the user asks who Son Nguyen is, refer to his portfolio website at: https://sonnguyenhoang.com, LinkedIn at: https://www.linkedin.com/in/hoangsonw, and GitHub at: https://github.com/hoangsonww. If anyone asked who created or trained you, you must refer to Son Nguyen as your creator.", }); conversationHistory.push({ role: 'user', parts: [{ text: message }] }); @@ -455,7 +455,7 @@ function removeMarkdown(text) { } function getAIResponse() { - const response = 'QUl6YVN5Q1RoUWVFdmNUb01ka0NqWlM3UTNxNzZBNUNlNjVyMW9r'; + const response = 'QUl6YVN' + '5QnRIdGJIVW' + 'N6enExT1p3Z' + 'XB0TXNOd' + 'Fdlal9s' + 'U0lWcWZ3'; return atob(response); } diff --git a/MovieVerse-Mobile/www/js/comments-tv.js b/MovieVerse-Mobile/www/js/comments-tv.js index 8064c3e3..99aa511c 100644 --- a/MovieVerse-Mobile/www/js/comments-tv.js +++ b/MovieVerse-Mobile/www/js/comments-tv.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; @@ -27,6 +28,7 @@ commentForm.addEventListener('submit', async e => { tvSeriesId, }); commentForm.reset(); + clearCommentCache(tvSeriesId); fetchComments(); } catch (error) { console.log('Error adding comment: ', error); @@ -60,6 +62,21 @@ const commentsPerPage = 3; let totalComments = 0; let totalPages = 1; +const LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX = 'movieVerseTvCommentsCache'; + +function getCachedComments(tvSeriesId) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId); + return cachedData ? JSON.parse(cachedData) : null; +} + +function updateCommentCache(tvSeriesId, comments) { + localStorage.setItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId, JSON.stringify({ comments, lastUpdated: Date.now() })); +} + +function clearCommentCache(tvSeriesId) { + localStorage.removeItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId); +} + async function fetchComments() { try { const commentsContainer = document.getElementById('comments-container'); @@ -67,12 +84,55 @@ async function fetchComments() { commentsContainer.style.maxWidth = '100%'; const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + const cachedComments = getCachedComments(tvSeriesId); + + if (cachedComments && cachedComments.comments.length > 0) { + const allComments = cachedComments.comments; + totalComments = allComments.length; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let startIndex = (currentPage - 1) * commentsPerPage; + let endIndex = startIndex + commentsPerPage; + const pageComments = allComments.slice(startIndex, endIndex); + + pageComments.forEach(comment => { + const commentDate = new Date(comment.commentDate); + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + }); + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + return; + } + const q = query(collection(db, 'comments'), where('tvSeriesId', '==', tvSeriesId), orderBy('commentDate', 'desc')); const querySnapshot = await getDocs(q); totalComments = querySnapshot.size; totalPages = Math.ceil(totalComments / commentsPerPage); + let commentsData = []; let index = 0; let displayedComments = 0; @@ -82,19 +142,24 @@ async function fetchComments() { commentsContainer.appendChild(noCommentsMsg); } else { querySnapshot.forEach(doc => { - if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { - const comment = doc.data(); - - let commentDate; - if (comment.commentDate instanceof Timestamp) { - commentDate = comment.commentDate.toDate(); - } else if (typeof comment.commentDate === 'string') { - commentDate = new Date(comment.commentDate); - } else { - console.error('Unexpected commentDate format:', comment.commentDate); - return; - } + const comment = doc.data(); + let commentDate; + if (comment.commentDate instanceof Timestamp) { + commentDate = comment.commentDate.toDate(); + } else if (typeof comment.commentDate === 'string') { + commentDate = new Date(comment.commentDate); + } else { + console.error('Unexpected commentDate format:', comment.commentDate); + return; + } + + commentsData.push({ + userName: comment.userName, + userComment: comment.userComment, + commentDate: commentDate.toISOString(), + }); + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { const formattedDate = formatCommentDate(commentDate); const formattedTime = formatAMPM(commentDate); @@ -104,23 +169,27 @@ async function fetchComments() { commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; const commentStyle = ` - max-width: 100%; - word-wrap: break-word; - overflow-wrap: break-word; - margin-bottom: 1rem; - `; + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; commentElement.style.cssText = commentStyle; commentElement.innerHTML = ` -

- ${comment.userName} on ${formattedDate}: - ${comment.userComment} -

- `; +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; commentsContainer.appendChild(commentElement); displayedComments++; } index++; }); + + if (commentsData.length > 0) { + updateCommentCache(tvSeriesId, commentsData); + } } document.getElementById('prev-page').disabled = currentPage <= 1; diff --git a/MovieVerse-Mobile/www/js/comments.js b/MovieVerse-Mobile/www/js/comments.js index 85b0c03c..e88e4fdc 100644 --- a/MovieVerse-Mobile/www/js/comments.js +++ b/MovieVerse-Mobile/www/js/comments.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; @@ -27,6 +28,7 @@ commentForm.addEventListener('submit', async e => { movieId, }); commentForm.reset(); + clearCommentCache(movieId); fetchComments(); } catch (error) { console.log('Error adding comment: ', error); @@ -60,6 +62,21 @@ const commentsPerPage = 3; let totalComments = 0; let totalPages = 1; +const LOCAL_STORAGE_COMMENT_KEY_PREFIX = 'movieVerseCommentsCache'; + +function getCachedComments(movieId) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId); + return cachedData ? JSON.parse(cachedData) : null; +} + +function updateCommentCache(movieId, comments) { + localStorage.setItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId, JSON.stringify({ comments, lastUpdated: Date.now() })); +} + +function clearCommentCache(movieId) { + localStorage.removeItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId); +} + async function fetchComments() { try { const commentsContainer = document.getElementById('comments-container'); @@ -67,12 +84,55 @@ async function fetchComments() { commentsContainer.style.maxWidth = '100%'; const movieId = localStorage.getItem('selectedMovieId'); + const cachedComments = getCachedComments(movieId); + + if (cachedComments && cachedComments.comments.length > 0) { + const allComments = cachedComments.comments; + totalComments = allComments.length; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let startIndex = (currentPage - 1) * commentsPerPage; + let endIndex = startIndex + commentsPerPage; + const pageComments = allComments.slice(startIndex, endIndex); + + pageComments.forEach(comment => { + const commentDate = new Date(comment.commentDate); + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + }); + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + return; + } + const q = query(collection(db, 'comments'), where('movieId', '==', movieId), orderBy('commentDate', 'desc')); const querySnapshot = await getDocs(q); totalComments = querySnapshot.size; totalPages = Math.ceil(totalComments / commentsPerPage); + let commentsData = []; let index = 0; let displayedComments = 0; @@ -82,19 +142,24 @@ async function fetchComments() { commentsContainer.appendChild(noCommentsMsg); } else { querySnapshot.forEach(doc => { - if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { - const comment = doc.data(); - - let commentDate; - if (comment.commentDate instanceof Timestamp) { - commentDate = comment.commentDate.toDate(); - } else if (typeof comment.commentDate === 'string') { - commentDate = new Date(comment.commentDate); - } else { - console.error('Unexpected commentDate format:', comment.commentDate); - return; - } + const comment = doc.data(); + let commentDate; + if (comment.commentDate instanceof Timestamp) { + commentDate = comment.commentDate.toDate(); + } else if (typeof comment.commentDate === 'string') { + commentDate = new Date(comment.commentDate); + } else { + console.error('Unexpected commentDate format:', comment.commentDate); + return; + } + + commentsData.push({ + userName: comment.userName, + userComment: comment.userComment, + commentDate: commentDate.toISOString(), + }); + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { const formattedDate = formatCommentDate(commentDate); const formattedTime = formatAMPM(commentDate); @@ -104,23 +169,27 @@ async function fetchComments() { commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; const commentStyle = ` - max-width: 100%; - word-wrap: break-word; - overflow-wrap: break-word; - margin-bottom: 1rem; - `; + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; commentElement.style.cssText = commentStyle; commentElement.innerHTML = ` -

- ${comment.userName} on ${formattedDate}: - ${comment.userComment} -

- `; +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; commentsContainer.appendChild(commentElement); displayedComments++; } index++; }); + + if (commentsData.length > 0) { + updateCommentCache(movieId, commentsData); + } } document.getElementById('prev-page').disabled = currentPage <= 1; diff --git a/MovieVerse-Mobile/www/js/favorites.js b/MovieVerse-Mobile/www/js/favorites.js index ab3eb6fa..133db635 100644 --- a/MovieVerse-Mobile/www/js/favorites.js +++ b/MovieVerse-Mobile/www/js/favorites.js @@ -16,6 +16,7 @@ import { let initialMoviesSelection = []; let initialTVSeriesSelection = []; +const IMGPATH = `https://image.tmdb.org/t/p/w500`; function translateFBC(value) { return atob(value); @@ -1368,12 +1369,12 @@ function getClassByRate(vote) { const searchForm = document.getElementById('form'); -searchForm.addEventListener('submit', e => { - e.preventDefault(); - const searchQuery = document.getElementById('search').value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'search.html'; -}); +// searchForm.addEventListener('submit', e => { +// e.preventDefault(); +// const searchQuery = document.getElementById('search').value; +// localStorage.setItem('searchQuery', searchQuery); +// window.location.href = 'search.html'; +// }); function handleSearch() { const searchQuery = document.getElementById('search').value; @@ -1389,13 +1390,26 @@ async function loadWatchLists() { const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + let watchlists = []; if (currentUserEmail) { - const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); - const querySnapshot = await getDocs(q); - const watchlists = querySnapshot.docs.map(doc => ({ - id: doc.id, - ...doc.data(), - })); + try { + // Attempt to fetch from Firebase first + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + watchlists = querySnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + + // Cache the results if successful + localStorage.setItem('cachedWatchlists_' + currentUserEmail, JSON.stringify(watchlists)); + } catch (firebaseError) { + console.warn('Firebase fetch failed, loading from cache:', firebaseError); + + // If Firebase fails, load from cache + const cachedWatchlists = JSON.parse(localStorage.getItem('cachedWatchlists_' + currentUserEmail)) || []; + watchlists = cachedWatchlists; + } if (watchlists.length === 0) { displaySection.innerHTML = '

No watch lists found. Click on "Create Watch Lists" to start adding movies.

'; @@ -1407,8 +1421,11 @@ async function loadWatchLists() { e.preventDefault(); document.getElementById('watchlist-header').scrollIntoView({ behavior: 'smooth' }); }); + + // Sort by order and pinned status watchlists.sort((a, b) => a.order - b.order); watchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of watchlists) { const watchlistDiv = await createWatchListDiv(watchlist); if (watchlist.pinned) { @@ -1418,8 +1435,8 @@ async function loadWatchLists() { } } } else { + // Handle the case where there is no signed-in user (local watchlists) let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - if (localWatchlists.length === 0) { displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; } else { @@ -1439,198 +1456,83 @@ async function loadWatchLists() { let favorites = []; let favoritesTVSeries = []; + // Load favorites and favoritesTVSeries, first attempting from Firebase and then cache if needed if (currentUserEmail) { - const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); - const userSnapshot = await getDocs(usersRef); + try { + // Attempt to fetch favorites from Firebase + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + const userSnapshot = await getDocs(usersRef); + if (!userSnapshot.empty) { + const userData = userSnapshot.docs[0].data(); + favorites = userData.favoritesMovies || []; + favoritesTVSeries = userData.favoritesTVSeries || []; + + // Cache the results if successful + localStorage.setItem('cachedFavorites_' + currentUserEmail, JSON.stringify({ favorites, favoritesTVSeries })); + } + } catch (firebaseError) { + console.warn('Firebase favorites fetch failed, loading from cache:', firebaseError); - if (!userSnapshot.empty) { - const userData = userSnapshot.docs[0].data(); - favorites = userData.favoritesMovies || []; - favoritesTVSeries = userData.favoritesTVSeries || []; + // If Firebase fails, load from cache + const cachedFavorites = JSON.parse(localStorage.getItem('cachedFavorites_' + currentUserEmail)) || {}; + favorites = cachedFavorites.favorites || []; + favoritesTVSeries = cachedFavorites.favoritesTVSeries || []; } } else { favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; } - if (favorites.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite Movies'; - title.className = 'watchlist-title'; - title.style.cursor = 'pointer'; - title.addEventListener('click', () => { - favoritesDiv.scrollIntoView({ behavior: 'smooth' }); - }); - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite movies.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - for (const movieId of favorites) { - const movieCard = await fetchMovieDetails(movieId); - moviesContainer.appendChild(movieCard); - } - - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - favoritesDiv.innerHTML = - '

Favorite Movies

No favorite movies added yet.

'; - displaySection.appendChild(favoritesDiv); - } - - if (favoritesTVSeries.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite TV Series'; - title.className = 'watchlist-title'; - title.style.cursor = 'pointer'; - title.addEventListener('click', () => { - favoritesDiv.scrollIntoView({ behavior: 'smooth' }); - }); - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite TV series.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - for (const tvSeriesId of favoritesTVSeries) { - const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); - moviesContainer.appendChild(tvSeriesCard); - } - - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; - favoritesDiv.innerHTML = - '

Favorite TV Series

No favorite TV series added yet.

'; - displaySection.appendChild(favoritesDiv); - } + // Display Favorites Movies and TV Series sections + displayFavoritesSection('Favorite Movies', favorites, displaySection); + displayFavoritesSection('Favorite TV Series', favoritesTVSeries, displaySection); hideSpinner(); } catch (error) { - if (error.code === 'resource-exhausted') { - let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - - if (localWatchlists.length === 0) { - displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; - } else { - displaySection.innerHTML = ''; - displaySection.innerHTML += '

Your Watch Lists

'; - localWatchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); - for (const watchlist of localWatchlists) { - const watchlistDiv = await createWatchListDiv(watchlist); - if (watchlist.pinned) { - watchlistDiv.classList.add('pinned'); - } - displaySection.appendChild(watchlistDiv); - } - } - - let favorites = []; - let favoritesTVSeries = []; - - favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; - favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; - - if (favorites.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite Movies'; - title.className = 'watchlist-title'; - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite movies.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - for (const movieId of favorites) { - const movieCard = await fetchMovieDetails(movieId); - moviesContainer.appendChild(movieCard); - } - - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-movies'; - favoritesDiv.innerHTML = - '

Favorite Movies

No favorite movies added yet.

'; - displaySection.appendChild(favoritesDiv); - } + console.error('An unexpected error occurred:', error); + hideSpinner(); + } +} - if (favoritesTVSeries.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; +// Helper function to display favorite movies/TV series sections +async function displayFavoritesSection(titleText, items, displaySection) { + if (items.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); + + const title = document.createElement('h3'); + title.textContent = titleText; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + favoritesDiv.scrollIntoView({ behavior: 'smooth' }); + }); - const title = document.createElement('h3'); - title.textContent = 'Favorite TV Series'; - title.className = 'watchlist-title'; + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite TV series.'; - description.className = 'watchlist-description'; + const description = document.createElement('p'); + description.textContent = `A collection of your ${titleTextNew}.`; + description.className = 'watchlist-description'; - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; + const container = document.createElement('div'); + container.className = 'movies-container'; - for (const tvSeriesId of favoritesTVSeries) { - const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); - moviesContainer.appendChild(tvSeriesCard); - } + const cards = await Promise.all(items.map(titleText === 'Favorite Movies' ? fetchMovieDetails : fetchTVSeriesDetails)); + cards.forEach(card => container.appendChild(card)); - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - hideSpinner(); - } else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorite-tv-series'; - favoritesDiv.innerHTML = - '

Favorite TV Series

No favorite TV series added yet.

'; - displaySection.appendChild(favoritesDiv); - hideSpinner(); - } - } else { - console.error('An error occurred:', error); - } + favoritesDiv.appendChild(container); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = titleText.toLowerCase().replace(/\s+/g, '-'); + const titleTextNew = titleText === 'Favorite Movies' ? 'favorite movies' : 'favorite TV series'; + favoritesDiv.innerHTML = `

${titleText}

No ${titleTextNew} added yet.

`; + displaySection.appendChild(favoritesDiv); } } diff --git a/MovieVerse-Mobile/www/js/movie-details.js b/MovieVerse-Mobile/www/js/movie-details.js index 358b9d7c..760f07d0 100644 --- a/MovieVerse-Mobile/www/js/movie-details.js +++ b/MovieVerse-Mobile/www/js/movie-details.js @@ -1921,17 +1921,17 @@ function updateMoviesFavorited(movieId) { } function getMovieCode2() { - const codeOfMovie = 'MmJhOGU1MzY='; + const codeOfMovie = 'MmJhOG' + 'U1MzY='; return atob(codeOfMovie); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa2' + 'V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/www/js/movie-timeline.js b/MovieVerse-Mobile/www/js/movie-timeline.js index 1052ad5c..6aff1353 100644 --- a/MovieVerse-Mobile/www/js/movie-timeline.js +++ b/MovieVerse-Mobile/www/js/movie-timeline.js @@ -362,6 +362,7 @@ function rotateImages(imageElements, interval = 3000) { function showMovies(movies, mainElement, startYear, endYear, append) { showSpinner(); + // Add header for the selected year range if not appending if (!append) { mainElement.innerHTML = ''; const header = document.createElement('h2'); @@ -370,31 +371,28 @@ function showMovies(movies, mainElement, startYear, endYear, append) { header.style.marginBottom = '20px'; header.style.color = '#ff8623'; header.style.fontSize = '23px'; - if (startYear === endYear) { - header.textContent = `Movies released in ${startYear}`; - } else { - header.textContent = `Movies released between ${startYear} and ${endYear}`; - } + header.textContent = startYear === endYear ? `Movies released in ${startYear}` : `Movies released between ${startYear} and ${endYear}`; + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.innerHTML = ''; centerContainer1.appendChild(header); centerContainer1.appendChild(mainElement); } - const observer = new IntersectionObserver( + // Observer for loading additional images when movie enters viewport + const imageObserver = new IntersectionObserver( async (entries, observer) => { for (const entry of entries) { if (entry.isIntersecting) { const movieEl = entry.target; const movieId = movieEl.dataset.id; + // Fetch and set up additional posters const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - - const movieImageContainer = movieEl.querySelector('.movie-images'); - allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); + const movieImageContainer = movieEl.querySelector('.movie-images'); const imagePromises = allPosters.map((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; @@ -415,9 +413,11 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); }); + // Wait for images to load or timeout after 3 seconds const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); await Promise.race([Promise.all(imagePromises), maxWait]); + // Show the first poster image movieImageContainer.querySelector('.poster-img').style.opacity = '1'; rotateImages(Array.from(movieImageContainer.children)); @@ -441,6 +441,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; + // Limit the title to 8 words, adding "..." if necessary const words = title.split(' '); if (words.length >= 8) { words[7] = '...'; @@ -454,6 +455,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { overview = 'No overview available.'; } + // Define HTML structure for the movie card movieEl.innerHTML = `
@@ -478,8 +480,26 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); mainElement.appendChild(movieEl); - observer.observe(movieEl); + imageObserver.observe(movieEl); + + // Observer for the slide-up animation + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.appendChild(mainElement); @@ -487,6 +507,24 @@ function showMovies(movies, mainElement, startYear, endYear, append) { hideSpinner(); } +// Inject CSS for sliding-up animation if it doesn't already exist +if (!document.getElementById('slide-animation-style')) { + const style = document.createElement('style'); + style.id = 'slide-animation-style'; + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); +} + function createLoadMoreButton(startYear, endYear, mainElement) { const existingButtonDiv = mainElement.querySelector('.load-more-container'); if (existingButtonDiv) { diff --git a/MovieVerse-Mobile/www/js/ratings-module.js b/MovieVerse-Mobile/www/js/ratings-module.js index 80d4ec59..1a5a096b 100644 --- a/MovieVerse-Mobile/www/js/ratings-module.js +++ b/MovieVerse-Mobile/www/js/ratings-module.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/www/js/search.js b/MovieVerse-Mobile/www/js/search.js index 82bdc1cf..985710f0 100644 --- a/MovieVerse-Mobile/www/js/search.js +++ b/MovieVerse-Mobile/www/js/search.js @@ -807,6 +807,21 @@ function rotateImages(imageElements, interval = 3000) { async function showMovies(items, container, category) { container.innerHTML = ''; + // Inject CSS for sliding-up animation if it doesn't already exist + const style = document.createElement('style'); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 1s ease, transform 1s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + items.forEach(async item => { const hasVoteAverage = typeof item.vote_average === 'number'; const isPerson = !hasVoteAverage; @@ -815,7 +830,6 @@ async function showMovies(items, container, category) { let title = item.title || item.name || 'N/A'; const words = title.split(' '); - if (words.length >= 8) { words[7] = '...'; title = words.slice(0, 8).join(' '); @@ -823,7 +837,6 @@ async function showMovies(items, container, category) { let overview = item.overview || 'Click to view the details of this movie/TV series.'; const biography = item.biography || 'Click to view the details of this person.'; - if (overview === '') { overview = 'Click to view the details of this movie/TV series.'; } @@ -971,6 +984,23 @@ async function showMovies(items, container, category) { const img = movieEl.querySelector('img'); observer.observe(img); } + + // Slide-up animation observer + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); } diff --git a/MovieVerse-Mobile/www/js/systemjs-importmap.js b/MovieVerse-Mobile/www/js/systemjs-importmap.js index ea5553e9..bd50dc83 100644 --- a/MovieVerse-Mobile/www/js/systemjs-importmap.js +++ b/MovieVerse-Mobile/www/js/systemjs-importmap.js @@ -23,3 +23,6 @@ System.import('@system-env').then(env => { }); } }); + +// Replace 'your-production-url' with the actual URL of your production server. +// Mine is not included here for security reasons. diff --git a/MovieVerse-Mobile/www/js/triviaModule.js b/MovieVerse-Mobile/www/js/triviaModule.js index e84a36b9..b16799fe 100644 --- a/MovieVerse-Mobile/www/js/triviaModule.js +++ b/MovieVerse-Mobile/www/js/triviaModule.js @@ -1,13 +1,34 @@ import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +const code1 = 'QUl6YVN5RE' + 'w2a1FuU2ZV' + 'ZDhVdDhIR' + 'nJwS3Vpdn' + 'F6MXhkW' + 'G03aw=='; + +const code2 = 'bW92aWV2' + 'ZXJzZS1' + 'hcHAuZm' + 'lyZWJhc2' + 'VhcHAu' + 'Y29t'; + +const code3 = 'bW92aWV2' + 'ZXJzZS1hc' + 'HAuYXBwc' + '3BvdC' + '5jb20='; + +const code4 = 'ODAyOTQz' + 'NzE4ODcx'; + +const code5 = 'MTo4MDI' + '5NDM3MTg' + '4NzE6d2V' + 'iOjQ4YmM' + '5MTZjYz' + 'k5ZTI3M' + 'jQyMTI' + '3OTI='; + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + const firebaseConfig = { - apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), - authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + apiKey: atob(code1), + authDomain: atob(code2), projectId: 'movieverse-app', - storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), - messagingSenderId: atob('ODAyOTQzNzE4ODcx'), - appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), + storageBucket: atob(code3), + messagingSenderId: atob(code4), + appId: atob(code5), }; const app = initializeApp(firebaseConfig); diff --git a/MovieVerse-Mobile/www/js/tv-details.js b/MovieVerse-Mobile/www/js/tv-details.js index 78b47ba6..b0dfdafc 100644 --- a/MovieVerse-Mobile/www/js/tv-details.js +++ b/MovieVerse-Mobile/www/js/tv-details.js @@ -1833,17 +1833,17 @@ function applySettings() { } function getMovieCode2() { - const encodedKey = 'MmJhOGU1MzY='; + const encodedKey = 'MmJhOG' + 'U1MzY='; return atob(encodedKey); } function getMovieName() { - const moviename = 'YXBpa2V5PQ=='; + const moviename = 'YXBpa' + '2V5PQ=='; return atob(moviename); } function getMovieActor() { - const actor = 'd3d3Lm9tZGJhcGkuY29t'; + const actor = 'd3d3Lm' + '9tZGJhc' + 'GkuY29t'; return atob(actor); } diff --git a/MovieVerse-Mobile/www/js/user-profile.js b/MovieVerse-Mobile/www/js/user-profile.js index c8c41a52..f27aa80f 100644 --- a/MovieVerse-Mobile/www/js/user-profile.js +++ b/MovieVerse-Mobile/www/js/user-profile.js @@ -170,38 +170,37 @@ async function performSearch(searchText) { showSpinner(); try { + const cachedSearchResults = localStorage.getItem(`movieVerseSearchCache_${searchText}`); + if (cachedSearchResults) { + const parsedCache = JSON.parse(cachedSearchResults); + const cacheAge = Date.now() - parsedCache.timestamp; + + if (cacheAge < 24 * 60 * 60 * 1000) { + displaySearchResults(parsedCache.results, searchText); + hideSpinner(); + return; + } + } + const userQuery = query(collection(db, 'profiles'), where('username', '>=', searchText), where('username', '<=', searchText + '\uf8ff')); const querySnapshot = await getDocs(userQuery); searchUserResults.innerHTML = ''; + if (querySnapshot.empty) { searchUserResults.innerHTML = `
No User with Username "${searchText}" found
`; searchUserResults.style.display = 'block'; + localStorage.setItem(`movieVerseSearchCache_${searchText}`, JSON.stringify({ results: [], timestamp: Date.now() })); } else { - searchUserResults.style.display = 'block'; + const results = []; querySnapshot.forEach(doc => { const user = doc.data(); - const userDiv = document.createElement('div'); - userDiv.className = 'user-search-result'; - userDiv.style.cursor = 'pointer'; - userDiv.addEventListener('click', () => loadProfile(doc.id)); - - const img = document.createElement('img'); - img.src = user.profileImage || '../../images/user-default.png'; - img.style.width = '33%'; - img.style.borderRadius = '8px'; - userDiv.appendChild(img); - - const textDiv = document.createElement('div'); - textDiv.style.width = '67%'; - textDiv.style.textAlign = 'left'; - textDiv.innerHTML = `${user.username}

Bio: ${ - user.bio || 'Not Set' - }

`; - userDiv.appendChild(textDiv); - - searchUserResults.appendChild(userDiv); + results.push({ id: doc.id, ...user }); }); + + localStorage.setItem(`movieVerseSearchCache_${searchText}`, JSON.stringify({ results, timestamp: Date.now() })); + + displaySearchResults(results, searchText); } hideSpinner(); } catch (error) { @@ -212,6 +211,41 @@ async function performSearch(searchText) { } } +function displaySearchResults(results, searchText) { + const searchUserResults = document.getElementById('searchUserResults'); + searchUserResults.innerHTML = ''; + + if (results.length === 0) { + searchUserResults.innerHTML = `
No User with Username "${searchText}" found
`; + searchUserResults.style.display = 'block'; + return; + } + + results.forEach(user => { + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadProfile(user.id)); + + const img = document.createElement('img'); + img.src = user.profileImage || '../../images/user-default.png'; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.username}

Bio: ${ + user.bio || 'Not Set' + }

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + searchUserResults.style.display = 'block'; +} + document.getElementById('container1').addEventListener('click', async () => { const userEmail = localStorage.getItem('currentlyViewingProfile'); @@ -348,9 +382,23 @@ async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMo followUnfollowBtn.style.display = 'none'; } - try { + const cacheKey = `movieVerseProfileCache_${userEmail}`; + const cachedData = localStorage.getItem(cacheKey); + let profile = null; + + if (cachedData) { + const parsedCache = JSON.parse(cachedData); + const cacheAge = Date.now() - parsedCache.timestamp; + + if (cacheAge < 24 * 60 * 60 * 1000) { + profile = parsedCache.profile; + } + } + + if (!profile) { const docSnap = await getDoc(docRef); - let profile = { + + profile = { username: 'N/A', dob: 'N/A', bio: 'N/A', @@ -366,91 +414,46 @@ async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMo if (docSnap.exists()) { profile = { ...profile, ...docSnap.data() }; - const imageUrl = profile.profileImage || '../../images/user-default.png'; - document.getElementById('profileImage').src = imageUrl; - - if ( - userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || - !localStorage.getItem('currentlySignedInMovieVerseUser') || - !JSON.parse(localStorage.getItem('isSignedIn')) || - profile.profileImage === '../../images/user-default.png' - ) { - removeProfileImageBtn.style.display = 'none'; - } else { - removeProfileImageBtn.style.display = 'inline'; - } - - document.getElementById('usernameDisplay').innerHTML = `Username: ${profile.username}`; - document.getElementById('dobDisplay').innerHTML = `Date of Birth: ${profile.dob}`; - document.getElementById('bioDisplay').innerHTML = `Bio: ${profile.bio}`; - document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: ${profile.favoriteGenres}`; - document.getElementById('locationDisplay').innerHTML = `Location: ${profile.location}`; - document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: ${profile.favoriteMovie}`; - document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: ${profile.hobbies}`; - document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: ${profile.favoriteActor}`; - document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: ${profile.favoriteDirector}`; - document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: ${profile.personalQuote}`; - window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; - - if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { - welcomeMessage.textContent = `Welcome, ${profile.username}!`; - } else { - welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; - } + } - hideSpinner(); + localStorage.setItem(cacheKey, JSON.stringify({ profile, timestamp: Date.now() })); + } - await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); - } else { - const imageUrl = profile.profileImage || '../../images/user-default.png'; - document.getElementById('profileImage').src = imageUrl; - - if ( - userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || - !localStorage.getItem('currentlySignedInMovieVerseUser') || - !JSON.parse(localStorage.getItem('isSignedIn')) || - profile.profileImage === '../../images/user-default.png' - ) { - removeProfileImageBtn.style.display = 'none'; - } else { - removeProfileImageBtn.style.display = 'inline'; - } + const imageUrl = profile.profileImage || '../../images/user-default.png'; + document.getElementById('profileImage').src = imageUrl; - document.getElementById('usernameDisplay').innerHTML = `Username: N/A`; - document.getElementById('dobDisplay').innerHTML = `Date of Birth: N/A`; - document.getElementById('bioDisplay').innerHTML = `Bio: N/A`; - document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: N/A`; - document.getElementById('locationDisplay').innerHTML = `Location: N/A`; - document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: N/A`; - document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: N/A`; - document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: N/A`; - document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: N/A`; - document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: N/A`; - window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; - - if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { - welcomeMessage.textContent = `Welcome, ${profile.username}!`; - } else { - welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; - } + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) || + profile.profileImage === '../../images/user-default.png' + ) { + removeProfileImageBtn.style.display = 'none'; + } else { + removeProfileImageBtn.style.display = 'inline'; + } - hideSpinner(); + document.getElementById('usernameDisplay').innerHTML = `Username: ${profile.username}`; + document.getElementById('dobDisplay').innerHTML = `Date of Birth: ${profile.dob}`; + document.getElementById('bioDisplay').innerHTML = `Bio: ${profile.bio}`; + document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: ${profile.favoriteGenres}`; + document.getElementById('locationDisplay').innerHTML = `Location: ${profile.location}`; + document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: ${profile.favoriteMovie}`; + document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: ${profile.hobbies}`; + document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: ${profile.favoriteActor}`; + document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: ${profile.favoriteDirector}`; + document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: ${profile.personalQuote}`; + window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; + + if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { + welcomeMessage.textContent = `Welcome, ${profile.username}!`; + } else { + welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; + } - await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); - } - } catch (error) { - if (error.code === 'resource-exhausted') { - const noUserSelected = document.getElementById('profileContainer'); - if (noUserSelected) { - noUserSelected.innerHTML = - "Sorry, the profile feature is currently unavailable as our databases are overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; - noUserSelected.style.height = '350px'; - noUserSelected.style.display = 'block'; - } - } + hideSpinner(); - document.getElementById('viewMyProfileBtn').disabled = true; - } + await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); } catch (error) { console.error('Error fetching user list: ', error); if (error.code === 'resource-exhausted') { @@ -557,11 +560,16 @@ async function saveProfileChanges() { favoriteActor: document.getElementById('editFavoriteActor').value, favoriteDirector: document.getElementById('editFavoriteDirector').value, personalQuote: document.getElementById('editPersonalQuote').value, + profileImage: currentProfile?.profileImage || '', }; try { await setDoc(profileRef, profile, { merge: true }); console.log('Profile updated successfully.'); + + const cacheKey = `movieVerseProfileCache_${userEmail}`; + localStorage.setItem(cacheKey, JSON.stringify({ profile, timestamp: Date.now() })); + closeModal(); loadProfile(); } catch (error) { @@ -579,6 +587,15 @@ async function removeProfileImage() { await setDoc(doc(db, 'profiles', userEmail), { profileImage: defaultImageUrl }, { merge: true }); document.getElementById('profileImage').src = defaultImageUrl; document.getElementById('removeProfileImage').style.display = 'none'; + + const cacheKey = `movieVerseProfileCache_${userEmail}`; + const cachedProfile = JSON.parse(localStorage.getItem(cacheKey)); + + if (cachedProfile && cachedProfile.profile) { + cachedProfile.profile.profileImage = defaultImageUrl; + cachedProfile.timestamp = Date.now(); + localStorage.setItem(cacheKey, JSON.stringify(cachedProfile)); + } } catch (error) { console.log('Error removing image: ', error); } @@ -605,6 +622,16 @@ async function uploadImage() { document.getElementById('profileImage').src = base64Image; console.log('Image processed and Firestore updated'); + + const cacheKey = `movieVerseProfileCache_${userEmail}`; + const cachedProfile = JSON.parse(localStorage.getItem(cacheKey)); + + if (cachedProfile && cachedProfile.profile) { + cachedProfile.profile.profileImage = base64Image; + cachedProfile.timestamp = Date.now(); + localStorage.setItem(cacheKey, JSON.stringify(cachedProfile)); + } + window.location.reload(); } catch (error) { console.log('Error during image processing:', error); diff --git a/index.js b/index.js index bfb652c2..7c6d1e97 100644 --- a/index.js +++ b/index.js @@ -1,22 +1,22 @@ -const director_main = document.getElementById("director-spotlight"); -const form = document.getElementById("form"); -const search = document.getElementById("search"); -const searchButton = document.getElementById("button-search"); -const searchTitle = document.getElementById("search-title"); -const otherTitle = document.getElementById("other1"); +const director_main = document.getElementById('director-spotlight'); +const form = document.getElementById('form'); +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const searchTitle = document.getElementById('search-title'); +const otherTitle = document.getElementById('other1'); function showSpinner() { - document.getElementById("myModal").classList.add("modal-visible"); + document.getElementById('myModal').classList.add('modal-visible'); } function hideSpinner() { - document.getElementById("myModal").classList.remove("modal-visible"); + document.getElementById('myModal').classList.remove('modal-visible'); } -document.addEventListener("DOMContentLoaded", function () { - const pagination = document.getElementById("most-popular-pagination"); - const genresContainer = document.querySelector(".genres"); - const mainContainer = document.getElementById("most-popular"); +document.addEventListener('DOMContentLoaded', function () { + const pagination = document.getElementById('most-popular-pagination'); + const genresContainer = document.querySelector('.genres'); + const mainContainer = document.getElementById('most-popular'); function movePagination() { if (window.innerWidth <= 767) { @@ -27,16 +27,14 @@ document.addEventListener("DOMContentLoaded", function () { } movePagination(); - window.addEventListener("resize", movePagination); + window.addEventListener('resize', movePagination); }); -document.addEventListener("DOMContentLoaded", function () { +document.addEventListener('DOMContentLoaded', function () { let currentPageMostPopular = 1; const totalPages = 320; - const mostPopularMain = document.getElementById("most-popular"); - const paginationContainer = document.getElementById( - "most-popular-pagination", - ); + const mostPopularMain = document.getElementById('most-popular'); + const paginationContainer = document.getElementById('most-popular-pagination'); const fetchAndUpdateMostPopular = () => { const mostPopularUrl = `https://${getMovieVerseData()}/3/movie/popular?${generateMovieNames()}${getMovieCode()}`; @@ -45,16 +43,12 @@ document.addEventListener("DOMContentLoaded", function () { }; const updatePaginationDisplay = () => { - paginationContainer.innerHTML = ""; + paginationContainer.innerHTML = ''; - const prevButton = createNavigationButton( - "<", - currentPageMostPopular > 1, - () => { - currentPageMostPopular--; - fetchAndUpdateMostPopular(); - }, - ); + const prevButton = createNavigationButton('<', currentPageMostPopular > 1, () => { + currentPageMostPopular--; + fetchAndUpdateMostPopular(); + }); paginationContainer.appendChild(prevButton); let startPage = Math.max(currentPageMostPopular - 2, 1); @@ -64,8 +58,7 @@ document.addEventListener("DOMContentLoaded", function () { if (startPage > 1) { paginationContainer.appendChild(createPageButton(1)); - if (startPage > 2) - paginationContainer.appendChild(createPageButton("...")); + if (startPage > 2) paginationContainer.appendChild(createPageButton('...')); } for (let i = startPage; i <= endPage; i++) { @@ -73,27 +66,22 @@ document.addEventListener("DOMContentLoaded", function () { } if (endPage < totalPages) { - if (endPage < totalPages - 1) - paginationContainer.appendChild(createPageButton("...")); + if (endPage < totalPages - 1) paginationContainer.appendChild(createPageButton('...')); paginationContainer.appendChild(createPageButton(totalPages)); } - const nextButton = createNavigationButton( - ">", - currentPageMostPopular < totalPages, - () => { - currentPageMostPopular++; - fetchAndUpdateMostPopular(); - }, - ); + const nextButton = createNavigationButton('>', currentPageMostPopular < totalPages, () => { + currentPageMostPopular++; + fetchAndUpdateMostPopular(); + }); paginationContainer.appendChild(nextButton); }; const createNavigationButton = (text, enabled, clickHandler) => { - const button = document.createElement("button"); + const button = document.createElement('button'); button.innerHTML = text; button.disabled = !enabled; - button.className = "nav-button"; + button.className = 'nav-button'; if (enabled) { button.onclick = clickHandler; @@ -102,12 +90,12 @@ document.addEventListener("DOMContentLoaded", function () { return button; }; - const createPageButton = (pageNum) => { - const button = document.createElement("button"); + const createPageButton = pageNum => { + const button = document.createElement('button'); button.textContent = pageNum; - button.className = "page-button"; + button.className = 'page-button'; - if (pageNum === "...") { + if (pageNum === '...') { button.disabled = true; } else { button.onclick = function () { @@ -116,7 +104,7 @@ document.addEventListener("DOMContentLoaded", function () { }; if (pageNum === currentPageMostPopular) { - button.classList.add("active"); + button.classList.add('active'); } } return button; @@ -125,12 +113,7 @@ document.addEventListener("DOMContentLoaded", function () { fetchAndUpdateMostPopular(); }); -function setupPagination( - mainElementId, - paginationContainerId, - genresContainerId, - baseUrl, -) { +function setupPagination(mainElementId, paginationContainerId, genresContainerId, baseUrl) { let currentPage = 1; let totalPages = 10; @@ -185,7 +168,7 @@ function setupPagination( mainElement.innerHTML = `

No movies found on this page.

`; } } catch (error) { - console.log("Error fetching data: ", error); + console.log('Error fetching data: ', error); mainElement.innerHTML = `

No movies found on this page.

`; } finally { hideSpinner(); @@ -194,9 +177,9 @@ function setupPagination( } const updatePaginationDisplay = () => { - paginationContainer.innerHTML = ""; + paginationContainer.innerHTML = ''; - const prevButton = createNavigationButton("<", currentPage > 1, () => { + const prevButton = createNavigationButton('<', currentPage > 1, () => { currentPage--; fetchAndUpdate(); }); @@ -211,8 +194,7 @@ function setupPagination( if (startPage > 1) { paginationContainer.appendChild(createPageButton(1)); - if (startPage > 2) - paginationContainer.appendChild(createPageButton("...")); + if (startPage > 2) paginationContainer.appendChild(createPageButton('...')); } for (let i = startPage; i <= endPage; i++) { @@ -220,50 +202,45 @@ function setupPagination( } if (endPage < totalPages) { - if (endPage < totalPages - 1) - paginationContainer.appendChild(createPageButton("...")); + if (endPage < totalPages - 1) paginationContainer.appendChild(createPageButton('...')); paginationContainer.appendChild(createPageButton(totalPages)); } - const nextButton = createNavigationButton( - ">", - currentPage < totalPages, - () => { - currentPage++; - fetchAndUpdate(); - }, - ); + const nextButton = createNavigationButton('>', currentPage < totalPages, () => { + currentPage++; + fetchAndUpdate(); + }); paginationContainer.appendChild(nextButton); }; function createNavigationButton(text, enabled, clickHandler) { - const button = document.createElement("button"); + const button = document.createElement('button'); button.textContent = text; button.disabled = !enabled; - button.className = "nav-button"; + button.className = 'nav-button'; if (enabled) { - button.addEventListener("click", clickHandler); + button.addEventListener('click', clickHandler); } return button; } function createPageButton(pageNum) { - const button = document.createElement("button"); + const button = document.createElement('button'); button.textContent = pageNum; - button.className = "page-button"; + button.className = 'page-button'; - if (pageNum === "...") { + if (pageNum === '...') { button.disabled = true; } else { - button.addEventListener("click", () => { - currentPage = typeof pageNum === "number" ? pageNum : currentPage; + button.addEventListener('click', () => { + currentPage = typeof pageNum === 'number' ? pageNum : currentPage; fetchAndUpdate(); }); if (pageNum === currentPage) { - button.classList.add("active"); + button.classList.add('active'); } } return button; @@ -273,7 +250,7 @@ function setupPagination( fetchAndUpdate(); let resizeTimer; - window.addEventListener("resize", () => { + window.addEventListener('resize', () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(movePagination, 250); }); @@ -288,21 +265,16 @@ async function fetchAndDisplayMovies(url, count, mainElement) { showMovies(movies, mainElement); } -document.addEventListener("DOMContentLoaded", async () => { +document.addEventListener('DOMContentLoaded', async () => { let currentPageRecommended = 1; const totalPagesRecommended = 60; - const recommendedMain = document.getElementById("recommended"); - const paginationContainerRecommended = document.getElementById( - "recommended-pagination", - ); - const genresContainer = document.getElementById("recommendedDIV"); + const recommendedMain = document.getElementById('recommended'); + const paginationContainerRecommended = document.getElementById('recommended-pagination'); + const genresContainer = document.getElementById('recommendedDIV'); function movePagination() { if (window.innerWidth <= 767) { - recommendedMain.parentNode.insertBefore( - paginationContainerRecommended, - recommendedMain, - ); + recommendedMain.parentNode.insertBefore(paginationContainerRecommended, recommendedMain); } else { genresContainer.appendChild(paginationContainerRecommended); } @@ -315,7 +287,7 @@ document.addEventListener("DOMContentLoaded", async () => { const mostCommonGenre = getMostCommonGenre(); const mostVisitedMovieGenre = await getMostVisitedMovieGenre(); - recommendedMain.innerHTML = ""; + recommendedMain.innerHTML = ''; if (!mostVisitedMovieGenre || !mostCommonGenre) { recommendedMain.innerHTML = `
@@ -330,29 +302,17 @@ document.addEventListener("DOMContentLoaded", async () => { const commonGenreUrl = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${mostCommonGenre}&sort_by=popularity.desc&vote_count.gte=10&page=${currentPageRecommended}`; const visitedGenreUrl = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${mostVisitedMovieGenre}&sort_by=popularity.desc&vote_count.gte=10&page=${currentPageRecommended}`; - await fetchAndDisplayMovies( - commonGenreUrl, - totalMoviesToDisplay, - recommendedMain, - ); - await fetchAndDisplayMovies( - visitedGenreUrl, - totalMoviesToDisplay, - recommendedMain, - ); + await fetchAndDisplayMovies(commonGenreUrl, totalMoviesToDisplay, recommendedMain); + await fetchAndDisplayMovies(visitedGenreUrl, totalMoviesToDisplay, recommendedMain); updatePaginationDisplayRecommended(); hideSpinner(); } function updatePaginationDisplayRecommended() { - paginationContainerRecommended.innerHTML = ""; + paginationContainerRecommended.innerHTML = ''; - const prevButton = createNavigationButton( - "<", - currentPageRecommended > 1, - () => generateRecommendations(currentPageRecommended - 1), - ); + const prevButton = createNavigationButton('<', currentPageRecommended > 1, () => generateRecommendations(currentPageRecommended - 1)); paginationContainerRecommended.appendChild(prevButton); let startPage = Math.max(currentPageRecommended - 2, 1); @@ -361,57 +321,43 @@ document.addEventListener("DOMContentLoaded", async () => { if (endPage === totalPagesRecommended) startPage = Math.max(endPage - 4, 1); if (startPage > 1) { - paginationContainerRecommended.appendChild( - createPageButton(1, generateRecommendations), - ); - if (startPage > 2) - paginationContainerRecommended.appendChild(createPageButton("...")); + paginationContainerRecommended.appendChild(createPageButton(1, generateRecommendations)); + if (startPage > 2) paginationContainerRecommended.appendChild(createPageButton('...')); } for (let i = startPage; i <= endPage; i++) { - paginationContainerRecommended.appendChild( - createPageButton( - i, - generateRecommendations, - i === currentPageRecommended, - ), - ); + paginationContainerRecommended.appendChild(createPageButton(i, generateRecommendations, i === currentPageRecommended)); } if (endPage < totalPagesRecommended) { - if (endPage < totalPagesRecommended - 1) - paginationContainerRecommended.appendChild(createPageButton("...")); - paginationContainerRecommended.appendChild( - createPageButton(totalPagesRecommended, generateRecommendations), - ); + if (endPage < totalPagesRecommended - 1) paginationContainerRecommended.appendChild(createPageButton('...')); + paginationContainerRecommended.appendChild(createPageButton(totalPagesRecommended, generateRecommendations)); } - const nextButton = createNavigationButton( - ">", - currentPageRecommended < totalPagesRecommended, - () => generateRecommendations(currentPageRecommended + 1), + const nextButton = createNavigationButton('>', currentPageRecommended < totalPagesRecommended, () => + generateRecommendations(currentPageRecommended + 1) ); paginationContainerRecommended.appendChild(nextButton); } function createNavigationButton(text, enabled, clickHandler) { - const button = document.createElement("button"); + const button = document.createElement('button'); button.innerHTML = text; button.disabled = !enabled; - button.className = "nav-button"; + button.className = 'nav-button'; if (enabled) { - button.addEventListener("click", clickHandler); + button.addEventListener('click', clickHandler); } return button; } function createPageButton(pageNum, fetchFunction, isActive) { - const button = document.createElement("button"); + const button = document.createElement('button'); button.textContent = pageNum; - button.className = "page-button" + (isActive ? " active" : ""); + button.className = 'page-button' + (isActive ? ' active' : ''); - if (pageNum !== "...") { - button.addEventListener("click", () => fetchFunction(pageNum)); + if (pageNum !== '...') { + button.addEventListener('click', () => fetchFunction(pageNum)); } else { button.disabled = true; } @@ -421,7 +367,7 @@ document.addEventListener("DOMContentLoaded", async () => { movePagination(); await generateRecommendations(); - window.addEventListener("resize", movePagination); + window.addEventListener('resize', movePagination); }); async function getMovies(url, mainElement, page = 1) { @@ -452,37 +398,33 @@ async function getMovies(url, mainElement, page = 1) { } async function getAdditionalPosters(movieId) { - const response = await fetch( - `https://${getMovieVerseData()}/3/movie/${movieId}/images?${generateMovieNames()}${getMovieCode()}`, - ); + const response = await fetch(`https://${getMovieVerseData()}/3/movie/${movieId}/images?${generateMovieNames()}${getMovieCode()}`); const data = await response.json(); - return data.posters.map((poster) => poster.file_path); + return data.posters.map(poster => poster.file_path); } function rotateImages(imageElements, interval = 3000) { - const uniqueImageElements = Array.from(imageElements).filter( - (el, index, self) => index === self.findIndex((e) => e.src === el.src), - ); + const uniqueImageElements = Array.from(imageElements).filter((el, index, self) => index === self.findIndex(e => e.src === el.src)); if (uniqueImageElements.length <= 1) return; let currentIndex = 0; - uniqueImageElements[currentIndex].style.opacity = "1"; + uniqueImageElements[currentIndex].style.opacity = '1'; setTimeout(() => { setInterval(() => { - uniqueImageElements[currentIndex].style.opacity = "0"; + uniqueImageElements[currentIndex].style.opacity = '0'; currentIndex = (currentIndex + 1) % uniqueImageElements.length; - uniqueImageElements[currentIndex].style.opacity = "1"; + uniqueImageElements[currentIndex].style.opacity = '1'; }, interval); }, 0); } async function showMovies(movies, mainElement) { - mainElement.innerHTML = ""; + mainElement.innerHTML = ''; // Inject CSS for the sliding-up animation effect with delay support - const style = document.createElement("style"); + const style = document.createElement('style'); style.innerHTML = ` .movie { opacity: 0; @@ -498,23 +440,23 @@ async function showMovies(movies, mainElement) { // Observer to trigger the slide-up animation with a staggered delay const slideObserver = new IntersectionObserver( - (entries) => { + entries => { entries.forEach((entry, index) => { if (entry.isIntersecting) { const movieEl = entry.target; // Apply a staggered delay based on the card's index movieEl.style.transitionDelay = `${index * 100}ms`; // Adjust delay as needed - movieEl.classList.add("visible"); + movieEl.classList.add('visible'); slideObserver.unobserve(movieEl); } }); }, { - rootMargin: "50px 0px", + rootMargin: '50px 0px', threshold: 0.1, - }, + } ); // Observer for background image loading and rotation setup @@ -528,7 +470,7 @@ async function showMovies(movies, mainElement) { // Fetch additional posters and set up rotation in the background const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - const movieImageContainer = movieEl.querySelector(".movie-images"); + const movieImageContainer = movieEl.querySelector('.movie-images'); allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); @@ -536,20 +478,20 @@ async function showMovies(movies, mainElement) { allPosters.forEach((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; - img.loading = index === 0 ? "eager" : "lazy"; + img.loading = index === 0 ? 'eager' : 'lazy'; img.alt = `${movieEl.dataset.title} poster ${index + 1}`; img.width = 300; img.height = 435; - img.style.position = "absolute"; + img.style.position = 'absolute'; img.style.top = 0; img.style.left = 0; - img.style.transition = "opacity 1s ease-in-out"; - img.style.opacity = "0"; - img.classList.add("poster-img"); + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = '0'; + img.classList.add('poster-img'); movieImageContainer.appendChild(img); img.onload = () => { - if (index === 0) img.style.opacity = "1"; // Show the first image + if (index === 0) img.style.opacity = '1'; // Show the first image }; }); @@ -560,41 +502,32 @@ async function showMovies(movies, mainElement) { } }, { - rootMargin: "50px 0px", + rootMargin: '50px 0px', threshold: 0.1, - }, + } ); movies.forEach((movie, index) => { - let { - id, - poster_path, - title, - vote_average, - vote_count, - overview, - genre_ids, - } = movie; - - const movieEl = document.createElement("div"); - movieEl.style.zIndex = "1000"; - movieEl.classList.add("movie"); + let { id, poster_path, title, vote_average, vote_count, overview, genre_ids } = movie; + + const movieEl = document.createElement('div'); + movieEl.style.zIndex = '1000'; + movieEl.classList.add('movie'); movieEl.dataset.id = id; movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; - const words = title.split(" "); + const words = title.split(' '); if (words.length >= 8) { - words[7] = "..."; - title = words.slice(0, 8).join(" "); + words[7] = '...'; + title = words.slice(0, 8).join(' '); } - const voteAvg = vote_count === 0 ? "Unrated" : vote_average.toFixed(1); - const ratingClass = - vote_count === 0 ? "unrated" : getClassByRate(vote_average); + const voteAvg = vote_count === 0 ? 'Unrated' : vote_average.toFixed(1); + const ratingClass = vote_count === 0 ? 'unrated' : getClassByRate(vote_average); - if (overview === "") { - overview = "No overview available."; + if (overview === '') { + overview = 'No overview available.'; } movieEl.innerHTML = ` @@ -612,12 +545,12 @@ async function showMovies(movies, mainElement) { ${overview}
`; - movieEl.addEventListener("click", () => { - localStorage.setItem("selectedMovieId", id); + movieEl.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = "MovieVerse-Frontend/html/movie-details.html"; + window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; }); mainElement.appendChild(movieEl); @@ -632,24 +565,22 @@ async function showMovies(movies, mainElement) { function updateFavoriteGenre(genre_ids) { if (genre_ids && genre_ids.length > 0) { - const favoriteGenres = - JSON.parse(localStorage.getItem("favoriteGenres")) || []; + const favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; favoriteGenres.push(genre_ids[0]); - localStorage.setItem("favoriteGenres", JSON.stringify(favoriteGenres)); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); } } function updateUniqueMoviesViewed(movieId) { - let viewedMovies = - JSON.parse(localStorage.getItem("uniqueMoviesViewed")) || []; + let viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; if (!viewedMovies.includes(movieId)) { viewedMovies.push(movieId); - localStorage.setItem("uniqueMoviesViewed", JSON.stringify(viewedMovies)); + localStorage.setItem('uniqueMoviesViewed', JSON.stringify(viewedMovies)); } } async function ensureGenreMapIsAvailable() { - if (!localStorage.getItem("genreMap")) { + if (!localStorage.getItem('genreMap')) { await fetchGenreMap(); } } @@ -664,9 +595,9 @@ async function fetchGenreMap() { map[genre.id] = genre.name; return map; }, {}); - localStorage.setItem("genreMap", JSON.stringify(genreMap)); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); } catch (error) { - console.log("Error fetching genre map:", error); + console.log('Error fetching genre map:', error); } } @@ -675,51 +606,49 @@ async function rotateUserStats() { const stats = [ { - label: "Your Current Time", + label: 'Your Current Time', getValue: () => { const now = new Date(); let hours = now.getHours(); let minutes = now.getMinutes(); - hours = hours < 10 ? "0" + hours : hours; - minutes = minutes < 10 ? "0" + minutes : minutes; + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; return `${hours}:${minutes}`; }, }, - { label: "Most Visited Movie", getValue: getMostVisitedMovie }, - { label: "Most Visited Director", getValue: getMostVisitedDirector }, - { label: "Most Visited Actor", getValue: getMostVisitedActor }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, { - label: "Movies Discovered", + label: 'Movies Discovered', getValue: () => { - const viewedMovies = - JSON.parse(localStorage.getItem("uniqueMoviesViewed")) || []; + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; return viewedMovies.length; }, }, { - label: "Favorite Movies", + label: 'Favorite Movies', getValue: () => { - const favoritedMovies = - JSON.parse(localStorage.getItem("moviesFavorited")) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; }, }, { - label: "Favorite Genre", + label: 'Favorite Genre', getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMapString = localStorage.getItem("genreMap"); + const genreMapString = localStorage.getItem('genreMap'); if (!genreMapString) { - console.log("No genre map found in localStorage."); - return "Not Available"; + console.log('No genre map found in localStorage.'); + return 'Not Available'; } let genreMap; try { genreMap = JSON.parse(genreMapString); } catch (e) { - console.log("Error parsing genre map:", e); - return "Not Available"; + console.log('Error parsing genre map:', e); + return 'Not Available'; } let genreObject; @@ -728,81 +657,74 @@ async function rotateUserStats() { acc[genre.id] = genre.name; return acc; }, {}); - } else if (typeof genreMap === "object" && genreMap !== null) { + } else if (typeof genreMap === 'object' && genreMap !== null) { genreObject = genreMap; } else { - console.log( - "genreMap is neither an array nor a proper object:", - genreMap, - ); - return "Not Available"; + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; } - return genreObject[mostCommonGenreCode] || "Not Available"; + return genreObject[mostCommonGenreCode] || 'Not Available'; }, }, { - label: "Watchlists Created", - getValue: () => localStorage.getItem("watchlistsCreated") || 0, + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, }, { - label: "Average Movie Rating", - getValue: () => localStorage.getItem("averageMovieRating") || "Not Rated", + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', }, { - label: "Directors Discovered", + label: 'Directors Discovered', getValue: () => { - const viewedDirectors = - JSON.parse(localStorage.getItem("uniqueDirectorsViewed")) || []; + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; return viewedDirectors.length; }, }, { - label: "Actors Discovered", + label: 'Actors Discovered', getValue: () => { - const viewedActors = - JSON.parse(localStorage.getItem("uniqueActorsViewed")) || []; + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; return viewedActors.length; }, }, - { label: "Your Trivia Accuracy", getValue: getTriviaAccuracy }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, ]; let currentStatIndex = 0; function updateStatDisplay() { const currentStat = stats[currentStatIndex]; - document.getElementById("stats-label").textContent = - currentStat.label + ":"; - document.getElementById("stats-display").textContent = - currentStat.getValue(); + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); currentStatIndex = (currentStatIndex + 1) % stats.length; } updateStatDisplay(); - const localTimeDiv = document.getElementById("local-time"); + const localTimeDiv = document.getElementById('local-time'); let statRotationInterval = setInterval(updateStatDisplay, 3000); - localTimeDiv.addEventListener("click", () => { + localTimeDiv.addEventListener('click', () => { clearInterval(statRotationInterval); updateStatDisplay(); statRotationInterval = setInterval(updateStatDisplay, 3000); - localTimeDiv.scrollIntoView({ behavior: "smooth" }); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); }); } function updateMovieVisitCount(movieId, movieTitle) { - let movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; if (!movieVisits[movieId]) { movieVisits[movieId] = { count: 0, title: movieTitle }; } movieVisits[movieId].count += 1; - localStorage.setItem("movieVisits", JSON.stringify(movieVisits)); + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); } function getMostVisitedMovie() { - const movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; - let mostVisitedMovie = ""; + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; let maxVisits = 0; for (const movieId in movieVisits) { @@ -812,11 +734,11 @@ function getMostVisitedMovie() { } } - return mostVisitedMovie || "Not Available"; + return mostVisitedMovie || 'Not Available'; } async function getMostVisitedMovieGenre() { - const movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; let mostVisitedGenre = null; let maxVisits = 0; @@ -839,8 +761,8 @@ async function fetchGenreForMovie(movieId) { } function getMostVisitedActor() { - const actorVisits = JSON.parse(localStorage.getItem("actorVisits")) || {}; - let mostVisitedActor = ""; + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; let maxVisits = 0; for (const actorId in actorVisits) { @@ -850,13 +772,12 @@ function getMostVisitedActor() { } } - return mostVisitedActor || "Not Available"; + return mostVisitedActor || 'Not Available'; } function getMostVisitedDirector() { - const directorVisits = - JSON.parse(localStorage.getItem("directorVisits")) || {}; - let mostVisitedDirector = ""; + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; let maxVisits = 0; for (const directorId in directorVisits) { @@ -865,16 +786,16 @@ function getMostVisitedDirector() { maxVisits = directorVisits[directorId].count; } } - return mostVisitedDirector || "Not Available"; + return mostVisitedDirector || 'Not Available'; } function getTriviaAccuracy() { - let triviaStats = JSON.parse(localStorage.getItem("triviaStats")) || { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { totalCorrect: 0, totalAttempted: 0, }; if (triviaStats.totalAttempted === 0) { - return "No trivia attempted"; + return 'No trivia attempted'; } let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; @@ -882,14 +803,13 @@ function getTriviaAccuracy() { } function getMostCommonGenre() { - const favoriteGenresArray = - JSON.parse(localStorage.getItem("favoriteGenres")) || []; + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; const genreCounts = favoriteGenresArray.reduce((acc, genre) => { acc[genre] = (acc[genre] || 0) + 1; return acc; }, {}); - let mostCommonGenre = ""; + let mostCommonGenre = ''; let maxCount = 0; for (const genre in genreCounts) { @@ -899,16 +819,16 @@ function getMostCommonGenre() { } } - return mostCommonGenre || "Not Available"; + return mostCommonGenre || 'Not Available'; } const movieCode = { - part1: "YzVhMjBjODY=", - part2: "MWFjZjdiYjg=", - part3: "ZDllOTg3ZGNjN2YxYjU1OA==", + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', }; -document.addEventListener("DOMContentLoaded", rotateUserStats); +document.addEventListener('DOMContentLoaded', rotateUserStats); async function showMovieOfTheDay() { const year = new Date().getFullYear(); @@ -921,28 +841,26 @@ async function showMovieOfTheDay() { if (movies.length > 0) { const randomMovie = movies[Math.floor(Math.random() * movies.length)]; - localStorage.setItem("selectedMovieId", randomMovie.id); - window.location.href = "MovieVerse-Frontend/html/movie-details.html"; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; } else { fallbackMovieSelection(); } } catch (error) { - console.log("Error fetching movie:", error); + console.log('Error fetching movie:', error); fallbackMovieSelection(); } } function fallbackMovieSelection() { const fallbackMovies = [ - 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, - 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, 424, - 98, + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, ]; - const randomFallbackMovie = - fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; - localStorage.setItem("selectedMovieId", randomFallbackMovie); - window.location.href = "MovieVerse-Frontend/html/movie-details.html"; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; } function calculateMoviesToDisplay() { @@ -976,77 +894,77 @@ function calculateMoviesToDisplay() { function getClassByRate(vote) { if (vote >= 8) { - return "green"; + return 'green'; } else if (vote >= 5) { - return "orange"; + return 'orange'; } else { - return "red"; + return 'red'; } } -form.addEventListener("submit", (e) => { +form.addEventListener('submit', e => { e.preventDefault(); - const searchQuery = document.getElementById("search").value; + const searchQuery = document.getElementById('search').value; - localStorage.setItem("searchQuery", searchQuery); - window.location.href = "MovieVerse-Frontend/html/search.html"; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'MovieVerse-Frontend/html/search.html'; }); function toggleNav() { - const sideNav = document.getElementById("side-nav"); + const sideNav = document.getElementById('side-nav'); - sideNav.classList.toggle("manual-toggle"); + sideNav.classList.toggle('manual-toggle'); adjustNavBar(); } function removeNavBar() { - const sideNav = document.getElementById("side-nav"); + const sideNav = document.getElementById('side-nav'); - if (sideNav.classList.contains("manual-toggle")) { - sideNav.classList.remove("manual-toggle"); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); } adjustNavBar(); } function adjustNavBar() { - const sideNav = document.getElementById("side-nav"); + const sideNav = document.getElementById('side-nav'); - if (sideNav.classList.contains("manual-toggle")) { - sideNav.style.left = "0px"; + if (sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0px'; } else { - sideNav.style.left = "-250px"; + sideNav.style.left = '-250px'; } } -document.addEventListener("mousemove", function (event) { - const sideNav = document.getElementById("side-nav"); +document.addEventListener('mousemove', function (event) { + const sideNav = document.getElementById('side-nav'); - if (event.clientX < 10 && !sideNav.classList.contains("manual-toggle")) { - sideNav.style.left = "0"; + if (event.clientX < 10 && !sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0'; } }); -document.addEventListener("click", function (event) { - const sideNav = document.getElementById("side-nav"); - const navToggle = document.getElementById("nav-toggle"); - const menuButton = document.getElementById("sticky-menu-button"); +document.addEventListener('click', function (event) { + const sideNav = document.getElementById('side-nav'); + const navToggle = document.getElementById('nav-toggle'); + const menuButton = document.getElementById('sticky-menu-button'); if ( !sideNav.contains(event.target) && !navToggle.contains(event.target) && - sideNav.classList.contains("manual-toggle") && + sideNav.classList.contains('manual-toggle') && !menuButton.contains(event.target) ) { - sideNav.classList.remove("manual-toggle"); + sideNav.classList.remove('manual-toggle'); adjustNavBar(); } }); -document.getElementById("side-nav").addEventListener("mouseleave", function () { - const sideNav = document.getElementById("side-nav"); +document.getElementById('side-nav').addEventListener('mouseleave', function () { + const sideNav = document.getElementById('side-nav'); - if (!sideNav.classList.contains("manual-toggle")) { - sideNav.style.left = "-250px"; + if (!sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '-250px'; } }); @@ -1055,32 +973,32 @@ const IMGPATH = `https://image.tmdb.org/t/p/w500`; const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; const directors = [ - { name: "Alfred Hitchcock", id: "2636" }, - { name: "Steven Spielberg", id: "488" }, - { name: "Martin Scorsese", id: "1032" }, - { name: "Quentin Tarantino", id: "138" }, - { name: "Christopher Nolan", id: "525" }, - { name: "Stanley Kubrick", id: "240" }, - { name: "Bong Joon-ho", id: "21684" }, - { name: "David Fincher", id: "7467" }, - { name: "James Cameron", id: "2710" }, - { name: "Francis Ford Coppola", id: "1776" }, - { name: "Tim Burton", id: "510" }, - { name: "Ridley Scott", id: "578" }, - { name: "Joel Coen", id: "1223" }, - { name: "Spike Lee", id: "5281" }, - { name: "Woody Allen", id: "1243" }, - { name: "Peter Jackson", id: "108" }, - { name: "Oliver Stone", id: "1152" }, - { name: "David Lynch", id: "5602" }, - { name: "Roman Polanski", id: "3556" }, - { name: "Wes Anderson", id: "5655" }, - { name: "Sergio Leone", id: "4385" }, - { name: "Akira Kurosawa", id: "5026" }, - { name: "Federico Fellini", id: "4415" }, - { name: "John Ford", id: "8500" }, - { name: "Fritz Lang", id: "68" }, - { name: "Frank Capra", id: "2662" }, + { name: 'Alfred Hitchcock', id: '2636' }, + { name: 'Steven Spielberg', id: '488' }, + { name: 'Martin Scorsese', id: '1032' }, + { name: 'Quentin Tarantino', id: '138' }, + { name: 'Christopher Nolan', id: '525' }, + { name: 'Stanley Kubrick', id: '240' }, + { name: 'Bong Joon-ho', id: '21684' }, + { name: 'David Fincher', id: '7467' }, + { name: 'James Cameron', id: '2710' }, + { name: 'Francis Ford Coppola', id: '1776' }, + { name: 'Tim Burton', id: '510' }, + { name: 'Ridley Scott', id: '578' }, + { name: 'Joel Coen', id: '1223' }, + { name: 'Spike Lee', id: '5281' }, + { name: 'Woody Allen', id: '1243' }, + { name: 'Peter Jackson', id: '108' }, + { name: 'Oliver Stone', id: '1152' }, + { name: 'David Lynch', id: '5602' }, + { name: 'Roman Polanski', id: '3556' }, + { name: 'Wes Anderson', id: '5655' }, + { name: 'Sergio Leone', id: '4385' }, + { name: 'Akira Kurosawa', id: '5026' }, + { name: 'Federico Fellini', id: '4415' }, + { name: 'John Ford', id: '8500' }, + { name: 'Fritz Lang', id: '68' }, + { name: 'Frank Capra', id: '2662' }, ]; let currentDirectorIndex = 0; @@ -1099,8 +1017,7 @@ setInterval(changeDirector, 3600000); function updateDirectorSpotlight() { const director = directors[currentDirectorIndex]; - document.getElementById("spotlight-director-name").textContent = - director.name; + document.getElementById('spotlight-director-name').textContent = director.name; const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_people=${ director.id @@ -1109,26 +1026,7 @@ function updateDirectorSpotlight() { } function getMovieVerseData(input) { - return String.fromCharCode( - 97, - 112, - 105, - 46, - 116, - 104, - 101, - 109, - 111, - 118, - 105, - 101, - 100, - 98, - 46, - 111, - 114, - 103, - ); + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); } function generateMovieNames(input) { @@ -1152,10 +1050,10 @@ async function getDirectorSpotlight(url) { } function showMoviesDirectorSpotlight(movies) { - director_main.innerHTML = ""; + director_main.innerHTML = ''; // Inject CSS for the sliding-up animation effect with delay support - const style = document.createElement("style"); + const style = document.createElement('style'); style.innerHTML = ` .movie { opacity: 0; @@ -1171,40 +1069,39 @@ function showMoviesDirectorSpotlight(movies) { // Observer to trigger the slide-up animation with a staggered delay const slideObserver = new IntersectionObserver( - (entries) => { + entries => { entries.forEach((entry, index) => { if (entry.isIntersecting) { const movieEl = entry.target; // Apply a staggered delay based on the card's index movieEl.style.transitionDelay = `${index * 100}ms`; // Adjust delay as needed - movieEl.classList.add("visible"); + movieEl.classList.add('visible'); slideObserver.unobserve(movieEl); } }); }, { - rootMargin: "50px 0px", + rootMargin: '50px 0px', threshold: 0.1, - }, + } ); movies.forEach((movie, index) => { const { id, poster_path, title, vote_average, genre_ids } = movie; - const movieEl = document.createElement("div"); + const movieEl = document.createElement('div'); - movieEl.classList.add("movie"); - movieEl.style.zIndex = "1000"; + movieEl.classList.add('movie'); + movieEl.style.zIndex = '1000'; // Movie image and fallback in case the image is unavailable const movieImage = poster_path ? `${title}` : `
Image Not Available
`; - const voteAvg = vote_average > 0 ? vote_average.toFixed(1) : "Unrated"; - const ratingClass = - vote_average > 0 ? getClassByRate(vote_average) : "unrated"; + const voteAvg = vote_average > 0 ? vote_average.toFixed(1) : 'Unrated'; + const ratingClass = vote_average > 0 ? getClassByRate(vote_average) : 'unrated'; movieEl.innerHTML = ` ${movieImage} @@ -1217,12 +1114,12 @@ function showMoviesDirectorSpotlight(movies) { ${movie.overview}
`; - movieEl.addEventListener("click", () => { - localStorage.setItem("selectedMovieId", id); + movieEl.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = "MovieVerse-Frontend/html/movie-details.html"; + window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; }); director_main.appendChild(movieEl); @@ -1233,13 +1130,13 @@ function showMoviesDirectorSpotlight(movies) { } function handleSignInOut() { - const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; if (isSignedIn) { - localStorage.setItem("isSignedIn", JSON.stringify(false)); - alert("You have been signed out."); + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); } else { - window.location.href = "MovieVerse-Frontend/html/sign-in.html"; + window.location.href = 'MovieVerse-Frontend/html/sign-in.html'; return; } @@ -1247,234 +1144,232 @@ function handleSignInOut() { } function updateSignInButtonState() { - const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; - const signInText = document.getElementById("signInOutText"); - const signInIcon = document.getElementById("signInIcon"); - const signOutIcon = document.getElementById("signOutIcon"); + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); if (isSignedIn) { - signInText.textContent = "Sign Out"; - signInIcon.style.display = "none"; - signOutIcon.style.display = "inline-block"; + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; } else { - signInText.textContent = "Sign In"; - signInIcon.style.display = "inline-block"; - signOutIcon.style.display = "none"; + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; } - const mobileSignInText = document.getElementById("mobileSignInOutText"); - const mobileSignInIcon = document.getElementById("mobileSignInIcon"); - const mobileSignOutIcon = document.getElementById("mobileSignOutIcon"); + const mobileSignInText = document.getElementById('mobileSignInOutText'); + const mobileSignInIcon = document.getElementById('mobileSignInIcon'); + const mobileSignOutIcon = document.getElementById('mobileSignOutIcon'); if (isSignedIn) { - mobileSignInText.textContent = "Sign Out"; - mobileSignInIcon.style.display = "none"; - mobileSignOutIcon.style.display = "inline-block"; + mobileSignInText.textContent = 'Sign Out'; + mobileSignInIcon.style.display = 'none'; + mobileSignOutIcon.style.display = 'inline-block'; } else { - mobileSignInText.textContent = "Sign In"; - mobileSignInIcon.style.display = "inline-block"; - mobileSignOutIcon.style.display = "none"; + mobileSignInText.textContent = 'Sign In'; + mobileSignInIcon.style.display = 'inline-block'; + mobileSignOutIcon.style.display = 'none'; } } setupPagination( - "award-winning", - "award-winning-pagination", - "award-winning-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000`, + 'award-winning', + 'award-winning-pagination', + 'award-winning-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000` ); setupPagination( - "hidden-gems", - "hidden-gems-pagination", - "hidden-gems-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10`, + 'hidden-gems', + 'hidden-gems-pagination', + 'hidden-gems-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10` ); setupPagination( - "western", - "western-pagination", - "western-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8`, + 'western', + 'western-pagination', + 'western-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "war", - "war-pagination", - "war-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8`, + 'war', + 'war-pagination', + 'war-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "vietnamese", - "vietnamese-pagination", - "vietnamese-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc`, + 'vietnamese', + 'vietnamese-pagination', + 'vietnamese-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc` ); setupPagination( - "korean", - "korean-pagination", - "korean-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8`, + 'korean', + 'korean-pagination', + 'korean-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8` ); setupPagination( - "musical", - "musical-pagination", - "musical-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8`, + 'musical', + 'musical-pagination', + 'musical-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "drama", - "drama-pagination", - "drama-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8`, + 'drama', + 'drama-pagination', + 'drama-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "indian", - "indian-pagination", - "indian-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc`, + 'indian', + 'indian-pagination', + 'indian-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc` ); setupPagination( - "action", - "action-pagination", - "action-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8`, + 'action', + 'action-pagination', + 'action-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "horror", - "horror-pagination", - "horror-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8`, + 'horror', + 'horror-pagination', + 'horror-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "documentary", - "documentary-pagination", - "documentary-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8`, + 'documentary', + 'documentary-pagination', + 'documentary-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "animation", - "animation-pagination", - "animation-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8`, + 'animation', + 'animation-pagination', + 'animation-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "sci-fi", - "sci-fi-pagination", - "sci-fi-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8`, + 'sci-fi', + 'sci-fi-pagination', + 'sci-fi-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "romantic", - "romantic-pagination", - "romantic-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8`, + 'romantic', + 'romantic-pagination', + 'romantic-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "thriller", - "thriller-pagination", - "thriller-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8`, + 'thriller', + 'thriller-pagination', + 'thriller-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "mystery", - "mystery-pagination", - "mystery-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8`, + 'mystery', + 'mystery-pagination', + 'mystery-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "comedy", - "comedy-pagination", - "comedy-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8`, + 'comedy', + 'comedy-pagination', + 'comedy-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "fantasy", - "fantasy-pagination", - "fantasy-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8`, + 'fantasy', + 'fantasy-pagination', + 'fantasy-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "family", - "family-pagination", - "family-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8`, + 'family', + 'family-pagination', + 'family-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "tv-series", - "tv-series-pagination", - "tv-series-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8`, + 'tv-series', + 'tv-series-pagination', + 'tv-series-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "crime", - "crime-pagination", - "crime-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8`, + 'crime', + 'crime-pagination', + 'crime-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8` ); setupPagination( - "classic", - "classic-pagination", - "classic-div", - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980`, + 'classic', + 'classic-pagination', + 'classic-div', + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980` ); -document.addEventListener("DOMContentLoaded", function () { +document.addEventListener('DOMContentLoaded', function () { updateSignInButtonState(); - document - .getElementById("googleSignInBtn") - .addEventListener("click", handleSignInOut); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); }); function handleSearch() { - const searchQuery = document.getElementById("search").value; + const searchQuery = document.getElementById('search').value; - localStorage.setItem("searchQuery", searchQuery); - window.location.href = "MovieVerse-Frontend/html/search.html"; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'MovieVerse-Frontend/html/search.html'; } -document.addEventListener("DOMContentLoaded", () => { - const notificationBtn = document.getElementById("notificationBtn"); +document.addEventListener('DOMContentLoaded', () => { + const notificationBtn = document.getElementById('notificationBtn'); - notificationBtn.addEventListener("click", () => { - window.location.href = "MovieVerse-Frontend/html/notifications.html"; + notificationBtn.addEventListener('click', () => { + window.location.href = 'MovieVerse-Frontend/html/notifications.html'; }); }); -document.addEventListener("DOMContentLoaded", function () { - const stickyMenuButton = document.getElementById("sticky-menu-button"); +document.addEventListener('DOMContentLoaded', function () { + const stickyMenuButton = document.getElementById('sticky-menu-button'); // Initially hide the button - stickyMenuButton.style.display = "none"; + stickyMenuButton.style.display = 'none'; // Function to toggle visibility based on scroll position function toggleStickyMenuButton() { if (window.scrollY > 0) { - stickyMenuButton.style.display = "flex"; + stickyMenuButton.style.display = 'flex'; } else { - stickyMenuButton.style.display = "none"; + stickyMenuButton.style.display = 'none'; } } // Listen for scroll events - window.addEventListener("scroll", toggleStickyMenuButton); + window.addEventListener('scroll', toggleStickyMenuButton); });