update for backend integration
This commit is contained in:
parent
a8591c027b
commit
5743e4b703
3 changed files with 343 additions and 255 deletions
2
app.json
2
app.json
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"expo": {
|
||||
"name": "fake-check-bd",
|
||||
"name": "FactChecker",
|
||||
"slug": "fake-check-bd",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
|
|
|
|||
|
|
@ -1,219 +1,228 @@
|
|||
import { WebView } from "react-native-webview";
|
||||
import { useRef } from "react";
|
||||
import { useRef, useState } from "react";
|
||||
import { Alert, StyleSheet, View } from "react-native";
|
||||
|
||||
export default function HomeScreen() {
|
||||
const webviewRef = useRef(null);
|
||||
const [postData, setPostData] = useState([]);
|
||||
const [isApiCallInProgress, setIsApiCallInProgress] = useState(false);
|
||||
|
||||
// Function to call the fact-check API
|
||||
const checkFacts = async (caption) => {
|
||||
try {
|
||||
|
||||
const response = await fetch('https://factcheck.planpostai.com/check-facts', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ query: caption }),
|
||||
});
|
||||
|
||||
const responseText = await response.text();
|
||||
console.log('Raw API Response:', responseText);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status} - ${responseText}`);
|
||||
}
|
||||
|
||||
const result = JSON.parse(responseText);
|
||||
|
||||
// Send the result back to WebView to show toast
|
||||
webviewRef.current?.injectJavaScript(`
|
||||
(function() {
|
||||
showToast('${result.evidence.replace(/'/g, "\\'")}');
|
||||
return true;
|
||||
})();
|
||||
`);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('API Error Details:', {
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
name: error.name
|
||||
});
|
||||
|
||||
// Show error in WebView
|
||||
webviewRef.current?.injectJavaScript(`
|
||||
(function() {
|
||||
showToast('Error: ${error.message.replace(/'/g, "\\'")}', 5000, true);
|
||||
return true;
|
||||
})();
|
||||
`);
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const handleMessage = async (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.nativeEvent.data);
|
||||
|
||||
switch (data.type) {
|
||||
case 'postData':
|
||||
setPostData(prevData => [...prevData, {
|
||||
caption: data.caption,
|
||||
imageUrls: data.imageUrls,
|
||||
postId: data.postId
|
||||
}]);
|
||||
|
||||
if (isApiCallInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsApiCallInProgress(true);
|
||||
|
||||
try {
|
||||
const result = await checkFacts(data.caption);
|
||||
|
||||
setIsApiCallInProgress(false);
|
||||
webviewRef.current?.injectJavaScript(`
|
||||
(function() {
|
||||
enableAllButtons();
|
||||
const button = document.querySelector('button[data-post-id="${data.postId}"]');
|
||||
if (button) {
|
||||
button.textContent = 'Processed';
|
||||
button.style.background="green";
|
||||
button.style.color="white";
|
||||
button.style.padding="5px 5px";
|
||||
button.style.opacity = '0.7';
|
||||
button.disabled = true;
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
`);
|
||||
} catch (error) {
|
||||
setIsApiCallInProgress(false);
|
||||
webviewRef.current?.injectJavaScript(`
|
||||
(function() {
|
||||
enableAllButtons();
|
||||
const button = document.querySelector('button[data-post-id="${data.postId}"]');
|
||||
if (button) {
|
||||
button.disabled = false;
|
||||
button.style.opacity = '1';
|
||||
button.textContent = 'Check';
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
`);
|
||||
} finally {
|
||||
setIsApiCallInProgress(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
console.error(`WebView Error: ${data.message}`);
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error handling message:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const injectedJavaScript = `
|
||||
(function() {
|
||||
try {
|
||||
// Inject CSS for toast notifications
|
||||
const style = document.createElement('style');
|
||||
style.innerHTML = \`
|
||||
#toast-container {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
right: 20px;
|
||||
left: 20px;
|
||||
z-index: 999999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.toast {
|
||||
background-color: #1db146;
|
||||
color: #fff;
|
||||
font-weight: 800;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||
font-size: 16px;
|
||||
opacity: 1;
|
||||
position: relative;
|
||||
width: 90%;
|
||||
z-index: 99999999999;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
.toast.fade-out {
|
||||
opacity: 0;
|
||||
}
|
||||
\`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// Fact-checking logic
|
||||
let lastClickTime = 0;
|
||||
const COOLDOWN_DURATION = 60000;
|
||||
let buttonClicked = false;
|
||||
let fullCaption = "";
|
||||
let imageUrls = [];
|
||||
let isApiCallInProgress = false;
|
||||
|
||||
// Toast notification function
|
||||
function showToast(message, duration = 5000) {
|
||||
const container = document.getElementById('toast-container') ||
|
||||
(() => {
|
||||
const cont = document.createElement('div');
|
||||
cont.id = 'toast-container';
|
||||
document.body.appendChild(cont);
|
||||
return cont;
|
||||
})();
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = 'toast';
|
||||
toast.textContent = message;
|
||||
container.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.add('fade-out');
|
||||
toast.addEventListener('transitionend', () => {
|
||||
toast.remove();
|
||||
});
|
||||
}, duration);
|
||||
// Add toast CSS
|
||||
const style = document.createElement('style');
|
||||
style.innerHTML = \`
|
||||
#toast-container {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
right: 20px;
|
||||
left: 20px;
|
||||
z-index: 999999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
// Function to disable all buttons
|
||||
function disableAllButtons() {
|
||||
document.querySelectorAll("button").forEach((btn) => {
|
||||
btn.disabled = true;
|
||||
btn.style.opacity = "0.5";
|
||||
btn.style.cursor = "not-allowed";
|
||||
});
|
||||
.toast {
|
||||
background-color: #1db146;
|
||||
color: #fff;
|
||||
font-weight: 800;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||
font-size: 16px;
|
||||
opacity: 1;
|
||||
position: relative;
|
||||
width: 90%;
|
||||
z-index: 99999999999;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
.toast.fade-out {
|
||||
opacity: 0;
|
||||
}
|
||||
.error-toast {
|
||||
background-color: #ff4444;
|
||||
}
|
||||
\`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// Function to enable all buttons
|
||||
function enableAllButtons() {
|
||||
document.querySelectorAll("button").forEach((btn) => {
|
||||
// Function to disable all buttons
|
||||
window.disableAllButtons = function() {
|
||||
document.querySelectorAll("button").forEach((btn) => {
|
||||
btn.disabled = true;
|
||||
btn.style.opacity = "0.5";
|
||||
btn.style.cursor = "not-allowed";
|
||||
});
|
||||
};
|
||||
|
||||
// Function to enable all buttons
|
||||
window.enableAllButtons = function() {
|
||||
document.querySelectorAll("button").forEach((btn) => {
|
||||
if (btn.textContent !== "Processed") {
|
||||
btn.disabled = false;
|
||||
btn.style.opacity = "1";
|
||||
btn.style.cursor = "pointer";
|
||||
});
|
||||
}
|
||||
|
||||
// Fact-checking API call
|
||||
async function checkFacts(caption, button) {
|
||||
try {
|
||||
isApiCallInProgress = true;
|
||||
disableAllButtons();
|
||||
const response = await fetch('http://localhost:8000/check-facts', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ query: caption }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
showToast(result.evidence);
|
||||
button.textContent = 'Processed';
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
showToast('An error occurred while checking facts');
|
||||
} finally {
|
||||
isApiCallInProgress = false;
|
||||
enableAllButtons();
|
||||
button.disabled = false;
|
||||
button.style.opacity = "1";
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function collectPostData(post) {
|
||||
if (post.dataset.processed === "true") return;
|
||||
// Toast notification function
|
||||
window.showToast = function(message, duration = 5000, isError = false) {
|
||||
const container = document.getElementById('toast-container') ||
|
||||
(() => {
|
||||
const cont = document.createElement('div');
|
||||
cont.id = 'toast-container';
|
||||
document.body.appendChild(cont);
|
||||
return cont;
|
||||
})();
|
||||
|
||||
const captionElement = post.querySelector(
|
||||
"div.m div.m div[data-type='text'] div.native-text"
|
||||
);
|
||||
let caption = captionElement ? captionElement.textContent.trim() : null;
|
||||
const toast = document.createElement('div');
|
||||
toast.className = 'toast' + (isError ? ' error-toast' : '');
|
||||
toast.textContent = message;
|
||||
container.appendChild(toast);
|
||||
|
||||
const imageElements = post.querySelectorAll("div.m.bg-s13 img");
|
||||
let imageURLs = [];
|
||||
imageElements.forEach((imageElement) => {
|
||||
if (imageElement.src) imageURLs.push(imageElement.src);
|
||||
setTimeout(() => {
|
||||
toast.classList.add('fade-out');
|
||||
toast.addEventListener('transitionend', () => {
|
||||
toast.remove();
|
||||
});
|
||||
}, duration);
|
||||
};
|
||||
|
||||
if (buttonClicked) {
|
||||
fullCaption = caption;
|
||||
imageUrls.push(...imageURLs);
|
||||
}
|
||||
post.dataset.processed = "true";
|
||||
|
||||
const button = createButton(post, caption, imageURLs);
|
||||
if (caption?.length > 30 || imageURLs.length > 0) {
|
||||
post.style.position = "relative";
|
||||
post.appendChild(button);
|
||||
}
|
||||
}
|
||||
|
||||
function createButton(post, initialCaption, initialImageURLs) {
|
||||
const button = document.createElement("button");
|
||||
button.textContent = "Check";
|
||||
|
||||
Object.assign(button.style, {
|
||||
position: "absolute",
|
||||
fontSize: "20px",
|
||||
right: "10px",
|
||||
bottom: "10px",
|
||||
background: "linear-gradient(135deg, #6a11cb, #2575fc)",
|
||||
color: "#fff",
|
||||
border: "none",
|
||||
padding: "12px 20px",
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer",
|
||||
zIndex: 1000000,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
gap: "8px",
|
||||
pointerEvents: "auto",
|
||||
transition: "all 0.3s",
|
||||
});
|
||||
|
||||
button.addEventListener("click", (event) => {
|
||||
event.stopPropagation();
|
||||
const currentTime = new Date().getTime();
|
||||
|
||||
lastClickTime = currentTime;
|
||||
|
||||
button.disabled = true;
|
||||
button.textContent = "Processing...";
|
||||
button.style.opacity = "0.5";
|
||||
|
||||
const seeMoreElement = post.querySelector("span[style*='color:#65676b']");
|
||||
|
||||
if (seeMoreElement) {
|
||||
handleSeeMoreClick(
|
||||
seeMoreElement,
|
||||
post,
|
||||
button,
|
||||
initialCaption,
|
||||
initialImageURLs
|
||||
);
|
||||
} else {
|
||||
collectDataImmediately(post, button, initialCaption, initialImageURLs);
|
||||
}
|
||||
});
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
async function handleSeeMoreClick(seeMoreElement, post, button, initialCaption, initialImageURLs) {
|
||||
// Function to handle "See More" click
|
||||
async function handleSeeMoreClick(seeMoreElement, post, button, initialCaption, initialImageURLs, postId) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
seeMoreElement.click();
|
||||
|
||||
buttonClicked = true;
|
||||
setTimeout(() => {
|
||||
const captionElement = post.querySelector(
|
||||
"div.m div.m div[data-type='text'] div.native-text"
|
||||
);
|
||||
fullCaption = captionElement ? captionElement.textContent.trim() : initialCaption;
|
||||
|
||||
setTimeout(async () => {
|
||||
await checkFacts(fullCaption, button);
|
||||
|
||||
button.textContent = "Processed";
|
||||
button.style.opacity = "0.7";
|
||||
button.disabled = true;
|
||||
// Send data to React Native
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({
|
||||
type: 'postData',
|
||||
caption: fullCaption,
|
||||
imageUrls: initialImageURLs,
|
||||
postId
|
||||
}));
|
||||
|
||||
resolve();
|
||||
}, 2000);
|
||||
|
|
@ -221,78 +230,157 @@ export default function HomeScreen() {
|
|||
});
|
||||
}
|
||||
|
||||
async function collectDataImmediately(
|
||||
post,
|
||||
button,
|
||||
initialCaption,
|
||||
initialImageURLs
|
||||
) {
|
||||
buttonClicked = true;
|
||||
|
||||
// Function to collect post data immediately
|
||||
function collectDataImmediately(post, button, initialCaption, initialImageURLs, postId) {
|
||||
const captionElement = post.querySelector(
|
||||
"div.m div.m div[data-type='text'] div.native-text"
|
||||
);
|
||||
let caption = captionElement
|
||||
? captionElement.textContent.trim()
|
||||
: initialCaption;
|
||||
const caption = captionElement ? captionElement.textContent.trim() : initialCaption;
|
||||
|
||||
const imageElements = post.querySelectorAll("div.m img");
|
||||
let imageURLs = [];
|
||||
imageElements.forEach((imageElement) => {
|
||||
if (imageElement.src) imageURLs.push(imageElement.src);
|
||||
});
|
||||
// Send data to React Native
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({
|
||||
type: 'postData',
|
||||
caption,
|
||||
imageUrls: initialImageURLs,
|
||||
postId
|
||||
}));
|
||||
}
|
||||
|
||||
if (imageURLs.length === 0) {
|
||||
imageURLs = initialImageURLs;
|
||||
const svgCode=\`<svg width="100" height="35" viewBox="0 0 100 35" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="100" height="35" rx="17.5" fill="#F9BF32"/>
|
||||
<path d="M38.716 14.824C38.372 14.824 38.064 14.892 37.792 15.028C37.528 15.164 37.304 15.36 37.12 15.616C36.936 15.864 36.796 16.168 36.7 16.528C36.612 16.888 36.568 17.292 36.568 17.74C36.568 18.348 36.64 18.868 36.784 19.3C36.936 19.724 37.172 20.048 37.492 20.272C37.812 20.496 38.22 20.608 38.716 20.608C39.068 20.608 39.416 20.568 39.76 20.488C40.112 20.408 40.492 20.296 40.9 20.152V21.676C40.524 21.828 40.152 21.94 39.784 22.012C39.416 22.084 39.004 22.12 38.548 22.12C37.668 22.12 36.94 21.94 36.364 21.58C35.796 21.212 35.376 20.7 35.104 20.044C34.832 19.38 34.696 18.608 34.696 17.728C34.696 17.08 34.784 16.488 34.96 15.952C35.136 15.408 35.392 14.94 35.728 14.548C36.072 14.156 36.492 13.852 36.988 13.636C37.492 13.42 38.068 13.312 38.716 13.312C39.14 13.312 39.564 13.368 39.988 13.48C40.42 13.584 40.832 13.728 41.224 13.912L40.636 15.388C40.316 15.236 39.992 15.104 39.664 14.992C39.344 14.88 39.028 14.824 38.716 14.824ZM44.3646 14.74C44.3646 15.06 44.3526 15.368 44.3286 15.664C44.3126 15.96 44.2966 16.168 44.2806 16.288H44.3766C44.5206 16.064 44.6886 15.884 44.8806 15.748C45.0726 15.604 45.2846 15.5 45.5166 15.436C45.7566 15.364 46.0086 15.328 46.2726 15.328C46.7446 15.328 47.1566 15.412 47.5086 15.58C47.8606 15.748 48.1326 16.008 48.3246 16.36C48.5246 16.712 48.6246 17.168 48.6246 17.728V22H46.8366V18.172C46.8366 17.7 46.7486 17.348 46.5726 17.116C46.4046 16.876 46.1406 16.756 45.7806 16.756C45.4206 16.756 45.1366 16.84 44.9286 17.008C44.7286 17.176 44.5846 17.42 44.4966 17.74C44.4086 18.06 44.3646 18.452 44.3646 18.916V22H42.5766V12.88H44.3646V14.74ZM53.1633 15.328C53.7713 15.328 54.2913 15.444 54.7233 15.676C55.1633 15.908 55.5033 16.244 55.7433 16.684C55.9833 17.124 56.1033 17.664 56.1033 18.304V19.168H51.8793C51.8953 19.672 52.0433 20.068 52.3233 20.356C52.6113 20.644 53.0073 20.788 53.5113 20.788C53.9353 20.788 54.3193 20.748 54.6633 20.668C55.0073 20.58 55.3633 20.448 55.7313 20.272V21.652C55.4113 21.812 55.0713 21.928 54.7113 22C54.3593 22.08 53.9313 22.12 53.4273 22.12C52.7713 22.12 52.1913 22 51.6873 21.76C51.1833 21.512 50.7873 21.14 50.4993 20.644C50.2113 20.148 50.0673 19.524 50.0673 18.772C50.0673 18.004 50.1953 17.368 50.4513 16.864C50.7153 16.352 51.0793 15.968 51.5433 15.712C52.0073 15.456 52.5473 15.328 53.1633 15.328ZM53.1753 16.6C52.8313 16.6 52.5433 16.712 52.3113 16.936C52.0873 17.16 51.9553 17.508 51.9153 17.98H54.4233C54.4233 17.716 54.3753 17.48 54.2793 17.272C54.1913 17.064 54.0553 16.9 53.8713 16.78C53.6873 16.66 53.4553 16.6 53.1753 16.6ZM60.2172 22.12C59.5692 22.12 59.0172 22.004 58.5612 21.772C58.1052 21.532 57.7572 21.164 57.5172 20.668C57.2772 20.172 57.1572 19.536 57.1572 18.76C57.1572 17.96 57.2932 17.308 57.5652 16.804C57.8372 16.3 58.2132 15.928 58.6932 15.688C59.1812 15.448 59.7412 15.328 60.3732 15.328C60.8212 15.328 61.2092 15.372 61.5372 15.46C61.8732 15.548 62.1652 15.652 62.4132 15.772L61.8852 17.152C61.6052 17.04 61.3412 16.948 61.0932 16.876C60.8532 16.804 60.6132 16.768 60.3732 16.768C60.0612 16.768 59.8012 16.844 59.5932 16.996C59.3852 17.14 59.2292 17.36 59.1252 17.656C59.0292 17.944 58.9812 18.308 58.9812 18.748C58.9812 19.18 59.0332 19.54 59.1372 19.828C59.2492 20.108 59.4092 20.32 59.6172 20.464C59.8252 20.6 60.0772 20.668 60.3732 20.668C60.7492 20.668 61.0812 20.62 61.3692 20.524C61.6572 20.42 61.9372 20.28 62.2092 20.104V21.628C61.9372 21.804 61.6492 21.928 61.3452 22C61.0492 22.08 60.6732 22.12 60.2172 22.12ZM65.5053 16.96C65.5053 17.208 65.4933 17.456 65.4693 17.704C65.4533 17.944 65.4333 18.188 65.4093 18.436H65.4333C65.5133 18.324 65.5933 18.212 65.6733 18.1C65.7613 17.988 65.8493 17.876 65.9373 17.764C66.0253 17.652 66.1173 17.544 66.2133 17.44L68.0493 15.448H70.0653L67.4613 18.292L70.2213 22H68.1573L66.2733 19.348L65.5053 19.96V22H63.7173V12.88H65.5053V16.96ZM70.5827 19.516V18.052H73.7267V19.516H70.5827ZM76.8138 15.448V22H75.0258V15.448H76.8138ZM75.9258 12.88C76.1898 12.88 76.4178 12.944 76.6098 13.072C76.8018 13.192 76.8978 13.42 76.8978 13.756C76.8978 14.084 76.8018 14.312 76.6098 14.44C76.4178 14.568 76.1898 14.632 75.9258 14.632C75.6538 14.632 75.4218 14.568 75.2298 14.44C75.0458 14.312 74.9538 14.084 74.9538 13.756C74.9538 13.42 75.0458 13.192 75.2298 13.072C75.4218 12.944 75.6538 12.88 75.9258 12.88ZM82.4021 15.328C83.1061 15.328 83.6701 15.52 84.0941 15.904C84.5181 16.28 84.7301 16.888 84.7301 17.728V22H82.9421V18.172C82.9421 17.7 82.8581 17.348 82.6901 17.116C82.5221 16.876 82.2541 16.756 81.8861 16.756C81.3421 16.756 80.9701 16.944 80.7701 17.32C80.5701 17.688 80.4701 18.22 80.4701 18.916V22H78.6821V15.448H80.0501L80.2901 16.288H80.3861C80.5301 16.064 80.7061 15.884 80.9141 15.748C81.1221 15.604 81.3541 15.5 81.6101 15.436C81.8661 15.364 82.1301 15.328 82.4021 15.328Z" fill="white"/>
|
||||
<path d="M16.7778 23.4545L12.3333 19.0909L13.9 17.5527L16.7778 20.3673L24.1 13.1782L25.6667 14.7273M19 6L9 10.3636V16.9091C9 22.9636 13.2667 28.6255 19 30C24.7333 28.6255 29 22.9636 29 16.9091V10.3636L19 6Z" fill="white"/>
|
||||
</svg>
|
||||
\`
|
||||
|
||||
|
||||
// Function to collect post data and send to React Native
|
||||
function collectPostData(post) {
|
||||
if (post.dataset.processed === "true") return;
|
||||
|
||||
// Get the caption
|
||||
const captionElement = post.querySelector(
|
||||
"div.m div.m div[data-type='text'] div.native-text"
|
||||
);
|
||||
const caption = captionElement ? captionElement.textContent.trim() : null;
|
||||
|
||||
// Get the first image (if exists)
|
||||
const singleImageElement = post.querySelector("div.m.bg-s13 img");
|
||||
const singleImageURL = singleImageElement && singleImageElement.src ? singleImageElement.src : null;
|
||||
|
||||
// Collect all image elements
|
||||
const imageElements = post.querySelectorAll("div.m.bg-s13 img");
|
||||
const imageURLs = Array.from(imageElements)
|
||||
.filter(img => img.src)
|
||||
.map(img => img.src);
|
||||
|
||||
post.dataset.processed = "true";
|
||||
|
||||
// Prioritize using a single image if only one exists, otherwise use all images
|
||||
let imagesToUse = [];
|
||||
if (singleImageURL) {
|
||||
imagesToUse = [singleImageURL];
|
||||
} else if (imageURLs.length > 0) {
|
||||
imagesToUse = imageURLs;
|
||||
}
|
||||
|
||||
// Create button if there's a caption or at least one image
|
||||
if ((caption && caption.length > 40) || imagesToUse.length > 0) {
|
||||
const postId = 'post_' + Math.random().toString(36).substr(2, 9);
|
||||
createButton(post, caption, imagesToUse, postId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create check button
|
||||
function createButton(post, caption, imageURLs, postId) {
|
||||
post.style.position = "relative";
|
||||
|
||||
const button = document.createElement("button");
|
||||
button.textContent = "Check";
|
||||
button.setAttribute('data-post-id', postId);
|
||||
button.innerHTML=svgCode
|
||||
|
||||
Object.assign(button.style, {
|
||||
position: "absolute",
|
||||
right: "5px",
|
||||
top: "-30px",
|
||||
border: "none",
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer",
|
||||
zIndex: 1000000,
|
||||
pointerEvents: "auto",
|
||||
transition: "all 0.3s",
|
||||
});
|
||||
|
||||
button.addEventListener("click", async () => {
|
||||
disableAllButtons();
|
||||
button.textContent = "Processing...";
|
||||
button.style.opacity = "0.5";
|
||||
button.style.color="white";
|
||||
button.style.padding="5px 5px";
|
||||
button.style.background="blue";
|
||||
|
||||
const seeMoreElement = post.querySelector("span[style*='color:#65676b']");
|
||||
|
||||
if (seeMoreElement) {
|
||||
await handleSeeMoreClick(seeMoreElement, post, button, caption, imageURLs, postId);
|
||||
} else {
|
||||
collectDataImmediately(post, button, caption, imageURLs, postId);
|
||||
}
|
||||
|
||||
await checkFacts(caption, button);
|
||||
button.textContent = "Processed";
|
||||
button.style.opacity = "0.7";
|
||||
button.disabled = true;
|
||||
}
|
||||
|
||||
// Mutation observer to handle new posts
|
||||
function handleMutations(mutationsList) {
|
||||
mutationsList.forEach((mutation) => {
|
||||
if (mutation.type === "childList" || mutation.type === "subtree") {
|
||||
document.querySelectorAll("div.m.bg-s3").forEach((post) => {
|
||||
if (!post.querySelector("button")) {
|
||||
collectPostData(post);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const observer = new MutationObserver(handleMutations);
|
||||
observer.observe(document.querySelector(".m"), {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.querySelectorAll("div.m.bg-s3").forEach((post) => {
|
||||
if (!post.dataset.processed) {
|
||||
collectPostData(post);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
true; // Successful injection
|
||||
} catch (error) {
|
||||
console.error('Injection error:', error);
|
||||
false;
|
||||
post.appendChild(button);
|
||||
}
|
||||
|
||||
// Mutation observer to handle new posts
|
||||
function handleMutations(mutationsList) {
|
||||
mutationsList.forEach((mutation) => {
|
||||
if (mutation.type === "childList" || mutation.type === "subtree") {
|
||||
document.querySelectorAll("div.m.bg-s3").forEach((post) => {
|
||||
if (!post.querySelector("button")) {
|
||||
collectPostData(post);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const observer = new MutationObserver(handleMutations);
|
||||
observer.observe(document.querySelector(".m"), {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.querySelectorAll("div.m.bg-s3").forEach((post) => {
|
||||
if (!post.dataset.processed) {
|
||||
collectPostData(post);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return true;
|
||||
})();
|
||||
`;
|
||||
|
||||
return (
|
||||
<WebView
|
||||
ref={webviewRef}
|
||||
source={{ uri: "https://m.facebook.com" }}
|
||||
injectedJavaScript={injectedJavaScript}
|
||||
startInLoadingState={true}
|
||||
/>
|
||||
<View style={styles.container}>
|
||||
<WebView
|
||||
ref={webviewRef}
|
||||
source={{ uri: "https://m.facebook.com" }}
|
||||
injectedJavaScript={injectedJavaScript}
|
||||
startInLoadingState={true}
|
||||
onMessage={handleMessage}
|
||||
webviewDebuggingEnabled={__DEV__}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
marginTop: 30,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "fake-check-bd",
|
||||
"name": "fact-checker",
|
||||
"main": "expo-router/entry",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue