diff --git a/.idea/caches/deviceStreaming.xml b/.idea/caches/deviceStreaming.xml
index b81700b..406736c 100644
--- a/.idea/caches/deviceStreaming.xml
+++ b/.idea/caches/deviceStreaming.xml
@@ -14,6 +14,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app.json b/app.json
index b08cb5b..aef4374 100644
--- a/app.json
+++ b/app.json
@@ -15,7 +15,8 @@
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
- }
+ },
+ "package": "com.smfahimhossen.android"
},
"web": {
"bundler": "metro",
@@ -36,6 +37,14 @@
],
"experiments": {
"typedRoutes": true
+ },
+ "extra": {
+ "router": {
+ "origin": false
+ },
+ "eas": {
+ "projectId": "aefb36d8-7851-4727-8f44-8968f1d51787"
+ }
}
}
}
diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx
index 25bec4a..7e7a53d 100644
--- a/app/(tabs)/index.tsx
+++ b/app/(tabs)/index.tsx
@@ -4,199 +4,295 @@ import { useRef } from "react";
export default function HomeScreen() {
const webviewRef = useRef(null);
- const injectedJavaScript = ` let lastClickTime = 0;
- const COOLDOWN_DURATION = 60000;
- let buttonClicked = false;
- let fullCaption = "";
- let imageUrls = [];
+ 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);
- function collectPostData(post) {
- if (post.dataset.processed === "true") return;
+ // Fact-checking logic
+ let lastClickTime = 0;
+ const COOLDOWN_DURATION = 60000;
+ let buttonClicked = false;
+ let fullCaption = "";
+ let imageUrls = [];
+ let isApiCallInProgress = false;
- const captionElement = post.querySelector("div.m div.m div[data-type='text'] div.native-text");
- let caption = captionElement ? captionElement.textContent.trim() : null;
+ // 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 imageElements = post.querySelectorAll("div.m.bg-s13 img");
- let imageURLs = [];
- imageElements.forEach((imageElement) => {
- if (imageElement.src) imageURLs.push(imageElement.src);
- });
+ const toast = document.createElement('div');
+ toast.className = 'toast';
+ toast.textContent = message;
+ container.appendChild(toast);
- if (buttonClicked) {
- fullCaption = caption;
- imageUrls.push(...imageURLs);
- }
- post.dataset.processed = "true";
+ setTimeout(() => {
+ toast.classList.add('fade-out');
+ toast.addEventListener('transitionend', () => {
+ toast.remove();
+ });
+ }, duration);
+ }
- const button = createButton(post, caption, imageURLs);
+ // 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";
+ });
+ }
- if (caption && imageURLs.length > 0) {
- post.style.position = "relative";
- post.appendChild(button);
- }
- }
+ // Function to enable all buttons
+ function enableAllButtons() {
+ document.querySelectorAll("button").forEach((btn) => {
+ btn.disabled = false;
+ btn.style.opacity = "1";
+ btn.style.cursor = "pointer";
+ });
+ }
- function createButton(post, initialCaption, initialImageURLs) {
- const button = document.createElement("button");
- button.textContent = "Check";
+ // 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 }),
+ });
- 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",
- });
+ if (!response.ok) {
+ throw new Error('Network response was not ok');
+ }
- button.addEventListener("click", (event) => {
- event.stopPropagation();
- const currentTime = new Date().getTime();
+ 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";
+ }
+ }
- if (currentTime - lastClickTime < COOLDOWN_DURATION) {
- const remainingTime = Math.ceil((COOLDOWN_DURATION - (currentTime - lastClickTime)) / 1000);
+ function collectPostData(post) {
+ if (post.dataset.processed === "true") return;
- // Fix template literal issue by using escape characters
- button.textContent = "Wait " + remainingTime + "s"; // Change here
- button.style.background = "linear-gradient(135deg, #a0a0a0, #c0c0c0)";
- button.style.cursor = "not-allowed";
- button.disabled = true;
+ const captionElement = post.querySelector(
+ "div.m div.m div[data-type='text'] div.native-text"
+ );
+ let caption = captionElement ? captionElement.textContent.trim() : null;
- const cooldownTimer = setInterval(() => {
- const updatedRemainingTime = Math.ceil((COOLDOWN_DURATION - (new Date().getTime() - lastClickTime)) / 1000);
+ const imageElements = post.querySelectorAll("div.m.bg-s13 img");
+ let imageURLs = [];
+ imageElements.forEach((imageElement) => {
+ if (imageElement.src) imageURLs.push(imageElement.src);
+ });
- if (updatedRemainingTime <= 0) {
- clearInterval(cooldownTimer);
- button.textContent = "Check";
- button.style.background = "linear-gradient(135deg, #6a11cb, #2575fc)";
- button.style.cursor = "pointer";
- button.disabled = false;
- return;
- }
+ if (buttonClicked) {
+ fullCaption = caption;
+ imageUrls.push(...imageURLs);
+ }
+ post.dataset.processed = "true";
- button.textContent = "Wait " + updatedRemainingTime + "s"; // Change here
- }, 1000);
+ const button = createButton(post, caption, imageURLs);
+ if (caption?.length > 30 || imageURLs.length > 0) {
+ post.style.position = "relative";
+ post.appendChild(button);
+ }
+ }
- return;
- }
+ function createButton(post, initialCaption, initialImageURLs) {
+ const button = document.createElement("button");
+ button.textContent = "Check";
- lastClickTime = currentTime;
+ 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.disabled = true;
- button.textContent = "Processing...";
- button.style.opacity = "0.5";
+ button.addEventListener("click", (event) => {
+ event.stopPropagation();
+ const currentTime = new Date().getTime();
- const seeMoreElement = post.querySelector("span[style*='color:#65676b']");
+ lastClickTime = currentTime;
- if (seeMoreElement) {
- handleSeeMoreClick(seeMoreElement, post, button, initialCaption, initialImageURLs);
- } else {
- collectDataImmediately(post, button, initialCaption, initialImageURLs);
- }
- });
+ button.disabled = true;
+ button.textContent = "Processing...";
+ button.style.opacity = "0.5";
- return button;
- }
+ const seeMoreElement = post.querySelector("span[style*='color:#65676b']");
- function handleSeeMoreClick(seeMoreElement, post, button, initialCaption, initialImageURLs) {
- const currentTime = new Date().getTime();
- setTimeout(() => {
- seeMoreElement.click();
+ if (seeMoreElement) {
+ handleSeeMoreClick(
+ seeMoreElement,
+ post,
+ button,
+ initialCaption,
+ initialImageURLs
+ );
+ } else {
+ collectDataImmediately(post, button, initialCaption, initialImageURLs);
+ }
+ });
- if (currentTime - lastClickTime < COOLDOWN_DURATION) {
- buttonClicked = true;
- }
+ return button;
+ }
- setTimeout(() => {
- if (window.ReactNativeWebView) {
- window.ReactNativeWebView.postMessage(
- JSON.stringify({
- caption: fullCaption,
- imageUrls: imageUrls,
- })
- );
- }
- alert(
- JSON.stringify({
- caption: fullCaption,
- imageUrls: imageUrls,
- }));
- button.textContent = "Processed";
- button.style.opacity = "0.7";
- button.disabled = true;
- }, 2000);
- }, 100);
- }
- function collectDataImmediately(post, button, initialCaption, initialImageURLs) {
- const captionElement = post.querySelector("div.m div.m div[data-type='text'] div.native-text");
- let caption = captionElement ? captionElement.textContent.trim() : initialCaption;
+ async function handleSeeMoreClick(seeMoreElement, post, button, initialCaption, initialImageURLs) {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ seeMoreElement.click();
- const imageElements = post.querySelectorAll("div.m img");
- let imageURLs = [];
- imageElements.forEach((imageElement) => {
- if (imageElement.src) imageURLs.push(imageElement.src);
- });
+ buttonClicked = true;
- if (imageURLs.length === 0) {
- imageURLs = initialImageURLs;
- }
+ setTimeout(async () => {
+ await checkFacts(fullCaption, button);
- alert(
- JSON.stringify({
- caption: fullCaption,
- imageUrls: imageUrls,
- }));
+ button.textContent = "Processed";
+ button.style.opacity = "0.7";
+ button.disabled = true;
- button.textContent = "Processed";
- button.style.opacity = "0.7";
- button.disabled = true;
- }
+ resolve();
+ }, 2000);
+ }, 100);
+ });
+ }
- // 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);
- }
- });
- }
- });
- }
+ async function collectDataImmediately(
+ post,
+ button,
+ initialCaption,
+ initialImageURLs
+ ) {
+ buttonClicked = true;
- const observer = new MutationObserver(handleMutations);
- observer.observe(document.querySelector(".m"), {
- childList: true,
- subtree: true,
- });
+ const captionElement = post.querySelector(
+ "div.m div.m div[data-type='text'] div.native-text"
+ );
+ let caption = captionElement
+ ? captionElement.textContent.trim()
+ : initialCaption;
- document.addEventListener("DOMContentLoaded", () => {
- document.querySelectorAll("div.m.bg-s3").forEach((post) => {
- if (!post.dataset.processed) {
- collectPostData(post);
- }
- });
- });
+ const imageElements = post.querySelectorAll("div.m img");
+ let imageURLs = [];
+ imageElements.forEach((imageElement) => {
+ if (imageElement.src) imageURLs.push(imageElement.src);
+ });
+
+ if (imageURLs.length === 0) {
+ imageURLs = initialImageURLs;
+ }
+
+ 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;
+ }
+ })();
`;
return (
);
-}
+}
\ No newline at end of file
diff --git a/eas.json b/eas.json
new file mode 100644
index 0000000..410c5da
--- /dev/null
+++ b/eas.json
@@ -0,0 +1,21 @@
+{
+ "cli": {
+ "version": ">= 14.2.0",
+ "appVersionSource": "remote"
+ },
+ "build": {
+ "development": {
+ "developmentClient": true,
+ "distribution": "internal"
+ },
+ "preview": {
+ "distribution": "internal"
+ },
+ "production": {
+ "autoIncrement": true
+ }
+ },
+ "submit": {
+ "production": {}
+ }
+}