From 115a8bb83a0c42cfaadabe2ae0a87bf96f671c54 Mon Sep 17 00:00:00 2001 From: SethBurkart123 Date: Tue, 17 Oct 2023 10:02:26 +1100 Subject: [PATCH] work on image and video backgrounds! Not laggy anymore with large files --- interface/src/App.tsx | 8 +-- interface/src/pages/Settings.tsx | 4 +- interface/src/pages/Themes.tsx | 54 +++++++-------- public/backgrounds/background.html | 21 ++++++ public/backgrounds/background.js | 60 ++++++++++++++++ public/manifest.json | 4 ++ src/SEQTA.js | 3 + src/background.js | 7 +- src/inject/injected.css | 20 ++++-- src/inject/injected/popup.css | 1 + src/seqta/ui/ImageBackgrounds.js | 108 +++++++++++++++-------------- src/seqta/ui/colors/Manager.js | 6 +- 12 files changed, 192 insertions(+), 104 deletions(-) create mode 100644 public/backgrounds/background.html create mode 100644 public/backgrounds/background.js diff --git a/interface/src/App.tsx b/interface/src/App.tsx index 2ee0a92b..57a58b22 100644 --- a/interface/src/App.tsx +++ b/interface/src/App.tsx @@ -6,8 +6,8 @@ import logoDark from './assets/betterseqta-light-full.png'; import Shortcuts from './pages/Shortcuts'; import { useSettingsContext } from './SettingsContext'; import Picker from './components/Picker'; -//import Themes from './pages/Themes'; -import About from './pages/About'; +import Themes from './pages/Themes'; +//import About from './pages/About'; //import About from './pages/About'; const App: React.FC = () => { @@ -32,8 +32,8 @@ const App: React.FC = () => { content: }, { - title: 'About', - content: + title: 'Themes', + content: } ]; diff --git a/interface/src/pages/Settings.tsx b/interface/src/pages/Settings.tsx index d0a9f332..46d2b4c4 100644 --- a/interface/src/pages/Settings.tsx +++ b/interface/src/pages/Settings.tsx @@ -48,11 +48,11 @@ const Settings: React.FC = () => { description: "Customise the overall theme colour of SEQTA Learn.", modifyElement: }, - /* { + { title: "Transparency Effects", description: "Enables transparency effects on certain elements such as blur. (May impact battery life)", modifyElement: switchChange('betterSEQTAPlus', isOn)} /> - }, */ + }, { title: "BetterSEQTA+", description: "Enables BetterSEQTA+ features", diff --git a/interface/src/pages/Themes.tsx b/interface/src/pages/Themes.tsx index 3827d45c..2f670e43 100644 --- a/interface/src/pages/Themes.tsx +++ b/interface/src/pages/Themes.tsx @@ -15,14 +15,13 @@ const openDB = () => { }); }; -const writeData = async (type: string, data: any) => { +const writeData = async (type: string, blob: Blob) => { return new Promise((resolve, reject) => { openDB().then(async db => { const tx = db.transaction('backgrounds', 'readwrite'); const store = tx.objectStore('backgrounds'); - const request = store.put({ id: 'customBackground', type, data }); + const request = store.put({ id: 'customBackground', type, blob }); - // Wait for the transaction to complete await new Promise((res, rej) => { tx.oncomplete = () => res(request.result); tx.onerror = () => rej(tx.error); @@ -32,13 +31,12 @@ const writeData = async (type: string, data: any) => { }); }; - const readData = async () => { const db = await openDB(); const tx = db.transaction('backgrounds', 'readonly'); const store = tx.objectStore('backgrounds'); const request = store.get('customBackground'); - + return await new Promise((resolve, reject) => { request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); @@ -52,39 +50,35 @@ const Themes: React.FC = () => { const handleFileChange = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; - + const fileType = file.type.split('/')[0]; - console.log(fileType); - - // Directly save the Blob object (file) - await writeData(fileType, file); - - // For displaying purpose, you might still want to convert it to Data URL - const reader = new FileReader(); - reader.onload = () => { - setImageSrc(reader.result as string); - }; - reader.readAsDataURL(file); + const blob = new Blob([file], { type: file.type }); + + // Save blob to IndexedDB + await writeData(fileType, blob); + + // For displaying purpose + const url = URL.createObjectURL(blob); + if (fileType === 'image') { + setVideoSrc(null); + setImageSrc(url); + } else if (fileType === 'video') { + setImageSrc(null); + setVideoSrc(url); + } }; - + useEffect(() => { (async () => { const data = await readData(); + const url = URL.createObjectURL(data.blob); if (data?.type === 'image') { - const reader = new FileReader(); - reader.onload = () => { - setImageSrc(reader.result as string); - }; - reader.readAsDataURL(data.data); + setImageSrc(url); } else if (data?.type === 'video') { - const reader = new FileReader(); - reader.onload = () => { - setVideoSrc(reader.result as string); - }; - reader.readAsDataURL(data.data); + setVideoSrc(url); } })(); - }, []); + }, []); return (
@@ -111,4 +105,4 @@ const Themes: React.FC = () => { ); }; -export default Themes; \ No newline at end of file +export default Themes; diff --git a/public/backgrounds/background.html b/public/backgrounds/background.html new file mode 100644 index 00000000..76b94f20 --- /dev/null +++ b/public/backgrounds/background.html @@ -0,0 +1,21 @@ + + + + + Background Fetcher + + + + + +
+ +
+ + + + diff --git a/public/backgrounds/background.js b/public/backgrounds/background.js new file mode 100644 index 00000000..53385a44 --- /dev/null +++ b/public/backgrounds/background.js @@ -0,0 +1,60 @@ +// Open the database +const openDB = () => { + return new Promise((resolve, reject) => { + const request = indexedDB.open("MyDatabase", 1); + + request.onerror = () => reject(request.error); + request.onsuccess = () => resolve(request.result); + + request.onupgradeneeded = (event) => { + const db = event.target.result; + db.createObjectStore("backgrounds", { keyPath: "id" }); + }; + }); +}; + +// Read data from IndexedDB +const readData = async () => { + const db = await openDB(); + const tx = db.transaction("backgrounds", "readonly"); + const store = tx.objectStore("backgrounds"); + const request = store.get("customBackground"); + + return await new Promise((resolve, reject) => { + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }); +}; + +// Main function to run on page load +const main = async () => { + try { + const data = await readData(); + if (!data) { + console.log("No data found in IndexedDB."); + return; + } + + const url = URL.createObjectURL(data.blob); + const container = document.getElementById("media-container"); + + if (data.type === "image") { + const imgElement = document.createElement("img"); + imgElement.src = url; + imgElement.alt = "Uploaded content"; + container.appendChild(imgElement); + } else if (data.type === "video") { + const videoElement = document.createElement("video"); + videoElement.src = url; + videoElement.autoplay = true; + videoElement.loop = true; + videoElement.muted = true; + container.appendChild(videoElement); + } + } catch (error) { + console.error("An error occurred:", error); + } +}; + +// Run the main function when the document is ready +document.addEventListener("DOMContentLoaded", main); diff --git a/public/manifest.json b/public/manifest.json index a3f5e5ee..5869299b 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -70,6 +70,10 @@ { "resources": ["resources/*"], "matches": ["*://*/*"] + }, + { + "resources": ["backgrounds/*"], + "matches": ["*://*/*"] } ] } diff --git a/src/SEQTA.js b/src/SEQTA.js index f3e3b16e..85ea9a9c 100644 --- a/src/SEQTA.js +++ b/src/SEQTA.js @@ -1330,6 +1330,9 @@ function AddBetterSEQTAElements(toggle) { if (element.getAttribute("excludeDarkCheck") == "true") { continue; } + + console.log(element); + console.log(element.contentDocument.documentElement); element.contentDocument.documentElement.childNodes[1].style.color = "white"; diff --git a/src/background.js b/src/background.js index 0a205dde..df175f7a 100644 --- a/src/background.js +++ b/src/background.js @@ -132,12 +132,7 @@ function HandleIntexedDB(request, sendResponse) { case "read": readData().then((data) => { - const reader = new FileReader(); - reader.onload = () => { - const arrayBuffer = reader.result; - sendResponse({ data: arrayBuffer, type: data.type }); - }; - reader.readAsArrayBuffer(data.data); + sendResponse(data); }); return true; } diff --git a/src/inject/injected.css b/src/inject/injected.css index 9350d186..89c5b790 100644 --- a/src/inject/injected.css +++ b/src/inject/injected.css @@ -431,7 +431,7 @@ td.colourBar { } ol > [data-message] { - padding-left: 4px !important; + padding-left: 8px !important; padding-right: 4px !important; } @@ -872,11 +872,11 @@ div > ol:has(.uiFileHandlerWrapper) { } .ais-description { - color: var(--text-primary); + color: var(--text-primary) !important; } .ais-signature { - color: var(--text-primary); + color: var(--text-primary) !important; } .ais-btnSearch i { @@ -1428,8 +1428,8 @@ ul { overflow: hidden; } -.header .days .title { - color: var(--text-primary); +.title { + color: var(--text-primary) !important; } div.entry.class { @@ -1683,8 +1683,14 @@ body { display: none; } -.MessageList__MessageList___3DxoC > ol > li.MessageList__unread___3imtO { - box-shadow: inset 3px 0 var(--better-main); +.MessageList__MessageList___3DxoC > ol > li.MessageList__unread___3imtO::before { + content: ""; + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 3px; /* Same width as your box-shadow */ + background: var(--better-main); } .connectedNotificationsWrapper > div > button { diff --git a/src/inject/injected/popup.css b/src/inject/injected/popup.css index 80772243..6c4976d6 100644 --- a/src/inject/injected/popup.css +++ b/src/inject/injected/popup.css @@ -26,4 +26,5 @@ height: 100%; object-fit: cover; pointer-events: none; + border: none !important; } \ No newline at end of file diff --git a/src/seqta/ui/ImageBackgrounds.js b/src/seqta/ui/ImageBackgrounds.js index 95e3ac14..e2fbd3e6 100644 --- a/src/seqta/ui/ImageBackgrounds.js +++ b/src/seqta/ui/ImageBackgrounds.js @@ -1,82 +1,84 @@ -/* // global chrome */ -/* function isValidBase64(str) { - const len = str.length; - if (len % 4 !== 0) { - return false; - } - for (let i = 0; i < len; i++) { - if (!(/[A-Za-z0-9+/=]/.test(str[i]))) { - return false; - } - } - return true; -} - -function base64ToArrayBuffer(base64) { - console.log(base64); - if (!isValidBase64(base64)) { - console.error("Invalid base64 string"); - return null; - } - const binaryString = atob(base64); - const len = binaryString.length; - const bytes = new Uint8Array(len); - for (let i = 0; i < len; i++) { - bytes[i] = binaryString.charCodeAt(i); - } - return bytes.buffer; -} */ +/* global chrome */ export async function appendBackgroundToUI() { + console.log("Starting appendBackgroundToUI..."); + + const parent = document.getElementById("container"); + + // embed background.html + const background = document.createElement("iframe"); + background.id = "background"; + background.classList.add("imageBackground"); + background.setAttribute("excludeDarkCheck", "true"); + background.src = chrome.runtime.getURL("backgrounds/background.html"); + parent.appendChild(background); + /* const response = await new Promise((resolve, reject) => { + console.log("Sending message to background script..."); chrome.runtime.sendMessage({ type: "IndexedDB", action: "read", fileName: "customBackground" }, (response) => { if (chrome.runtime.lastError) { + console.error("Error from background script:", chrome.runtime.lastError); return reject(chrome.runtime.lastError); } + console.log("Received response from background script:", response); resolve(response); }); }); - console.log("response:", response); - let data = response.data; // response.data is the image base64 string + let data = response.data; // response.data is the image Data URL + + // Extract the pure base64 string from the Data URL + const base64Marker = ";base64,"; + const base64Index = data.indexOf(base64Marker) + base64Marker.length; + const base64 = data.substring(base64Index); + let type = response.type; // response.type is the image type [ video | image ] - - if (data) { - // check if it is video from its base64 string + + if (base64) { + console.log("Data exists, proceeding..."); + const mount = document.getElementById("container"); - console.log("Starting to append background"); + + // Convert base64 to ArrayBuffer + console.log("Converting base64 to ArrayBuffer..."); + const byteCharacters = atob(base64); + const byteNumbers = Array.from(byteCharacters).map(char => char.charCodeAt(0)); + const byteArray = new Uint8Array(byteNumbers); + + // Create blob + console.log("Creating blob..."); + const blob = new Blob([byteArray], { type: type === "video" ? "video/mp4" : "image/jpeg" }); + + // Create blob URL + console.log("Creating blob URL..."); + const blobUrl = URL.createObjectURL(blob); + let backgroundElement; + if (type === "video") { - console.log("Data type:", typeof data); - console.log("Data instance:", data instanceof Blob); - - if (data instanceof Blob) { - console.log("Blob size:", data.size); - console.log("Blob type:", data.type); - } - - console.log("Starting blob."); - const blob = new Blob([new Uint8Array(response.data)]); // Adjust the MIME type accordingly - console.log("Made blob."); - const blobUrl = URL.createObjectURL(blob); - console.log(blobUrl); + console.log("Appending video element..."); backgroundElement = document.createElement("video"); backgroundElement.src = blobUrl; backgroundElement.autoplay = true; backgroundElement.loop = true; backgroundElement.muted = true; - console.log(backgroundElement); - mount.appendChild(backgroundElement); - // Remember to revoke the blob URL to avoid memory leaks + + // Revoke blob URL to free memory backgroundElement.addEventListener("ended", () => { + console.log("Video ended, revoking blob URL..."); URL.revokeObjectURL(blobUrl); }); } else { + console.log("Appending image element..."); backgroundElement = document.createElement("img"); - backgroundElement.src = data; + backgroundElement.src = blobUrl; backgroundElement.alt = "Custom Background"; backgroundElement.classList.add("imageBackground"); - mount.appendChild(backgroundElement); } + + console.log("Appending background element to the DOM..."); + mount.appendChild(backgroundElement); + } else { + console.warn("No data received. Background not appended."); } */ -} \ No newline at end of file +} diff --git a/src/seqta/ui/colors/Manager.js b/src/seqta/ui/colors/Manager.js index 5ec33f28..8cc77e41 100644 --- a/src/seqta/ui/colors/Manager.js +++ b/src/seqta/ui/colors/Manager.js @@ -8,10 +8,12 @@ const setCSSVar = (varName, value) => document.documentElement.style.setProperty const getChromeURL = (path) => chrome.runtime.getURL(path); const applyProperties = (props) => Object.entries(props).forEach(([key, value]) => setCSSVar(key, value)); +let DarkMode = null; + export function updateAllColors(storedSetting, newColor = null) { // Determine the color to use const selectedColor = newColor || storedSetting.selectedColor; - const DarkMode = storedSetting ? storedSetting.DarkMode : null; + DarkMode = storedSetting ? storedSetting.DarkMode : DarkMode; // Common properties, always applied const commonProps = { @@ -22,7 +24,7 @@ export function updateAllColors(storedSetting, newColor = null) { // Mode-based properties, applied if storedSetting is provided let modeProps = {}; - console.log(DarkMode); + console.log("Darkmode: ", DarkMode); if (DarkMode !== null) { modeProps = DarkMode ? { "--background-primary": "#232323",