diff --git a/interface/src/pages/Themes.css b/interface/src/components/BackgroundSelector.css similarity index 100% rename from interface/src/pages/Themes.css rename to interface/src/components/BackgroundSelector.css diff --git a/interface/src/components/BackgroundSelector.tsx b/interface/src/components/BackgroundSelector.tsx new file mode 100644 index 00000000..7cd822a9 --- /dev/null +++ b/interface/src/components/BackgroundSelector.tsx @@ -0,0 +1,271 @@ +import { ChangeEvent, useEffect, useState } from "react"; +import { downloadPresetBackground, openDB, readAllData, writeData } from "../hooks/BackgroundDataLoader"; +import "./BackgroundSelector.css"; + +// Custom Types and Interfaces +export interface Background { + id: string; + type: string; + blob: Blob; + url?: string; + previewUrl?: string; // New field + isPreset?: boolean; + isDownloaded?: boolean; +} + +export default function BackgroundSelector() { + const [backgrounds, setBackgrounds] = useState([]); + const [selectedBackground, setSelectedBackground] = useState(localStorage.getItem('selectedBackground')); + const [downloadedPresetIds, setDownloadedPresetIds] = useState([]); + const [downloadProgress, setDownloadProgress] = useState>({}); + const [isEditMode, setIsEditMode] = useState(false); + + + const presetBackgrounds = [ + // Images + { + id: 'image-preset-1', + type: 'image', + url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-1.jpg', + previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-1-thumb.jpg', + isPreset: true + }, + { + id: 'image-preset-2', + type: 'image', + url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-2.jpg', + previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-2-thumb.jpg', + isPreset: true + }, + { + id: 'image-preset-3', + type: 'image', + url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-3.jpg', + previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-3-thumb.jpg', + isPreset: true + }, + { + id: 'image-preset-4', + type: 'image', + url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-4.jpg', + previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-4-thumb.jpg', + isPreset: true + }, + { + id: 'image-preset-5', + type: 'image', + url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-5.jpg', + previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-5-thumb.jpg', + isPreset: true + }, + { + id: 'image-preset-6', + type: 'image', + url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-6.jpg', + previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-6-thumb.jpg', + isPreset: true + }, + { + id: 'image-preset-7', + type: 'image', + url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-7.jpg', + previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-7-thumb.jpg', + isPreset: true + }, + + // Videos + { + id: 'video-preset-1', + type: 'video', + url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/videos/animated-1.mp4', + previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/videos/animation-1-thumb.mp4', + isPreset: true + }, + { + id: 'video-preset-2', + type: 'video', + url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/videos/animation-2.mp4', + previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/videos/animation-2-thumb.mp4', + isPreset: true + } + ]; + + const handleFileChange = async (e: ChangeEvent): Promise => { + const file = e.target.files?.[0]; + if (!file) return; + + const fileId = `${Date.now()}-${file.name}`; + const fileType = file.type.split('/')[0]; + const blob = new Blob([file], { type: file.type }); + + await writeData(fileId, fileType, blob); + setBackgrounds(prev => [...prev, { id: fileId, type: fileType, blob, url: URL.createObjectURL(blob) }]); + }; + + const loadBackgrounds = async (): Promise => { + const data = await readAllData(); + const dataWithUrls = data.map(bg => ({ ...bg, url: URL.createObjectURL(bg.blob) })); + + // Update downloaded preset IDs + setDownloadedPresetIds(data.map(bg => bg.id)); + + setBackgrounds(dataWithUrls); + }; + +const handlePresetClick = async (bg: Background): Promise => { + if (bg.isPreset) { + // Check if already exists in IndexedDB or is currently being downloaded + const existingBackgrounds = await readAllData(); + const alreadyExists = existingBackgrounds.some(ebg => ebg.id === bg.id) || downloadProgress[bg.id] !== undefined; + + if (!alreadyExists) { + setDownloadProgress(prev => ({ ...prev, [bg.id]: 0 })); + const downloadedBg = await downloadPresetBackground(bg, progress => { + console.log(`${bg}, ${progress}`); + setDownloadProgress(prev => ({ ...prev, [bg.id]: progress })); + }); + setDownloadProgress(prev => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { [bg.id]: _, ...rest } = prev; + return rest; + }); + await writeData(downloadedBg.id, downloadedBg.type, downloadedBg.blob); + setBackgrounds(prev => [...prev, downloadedBg]); + setDownloadedPresetIds(prev => [...prev, downloadedBg.id]); + } + selectBackground(bg.id); + } +}; + + const selectBackground = (fileId: string): void => { + setSelectedBackground(fileId); + localStorage.setItem('selectedBackground', fileId); + }; + + const deleteBackground = async (fileId: string): Promise => { + const db = await openDB(); + const tx = db.transaction('backgrounds', 'readwrite'); + const store = tx.objectStore('backgrounds'); + store.delete(fileId); + setBackgrounds(prev => prev.filter(bg => bg.id !== fileId)); + + // Check if the background being deleted is currently selected + if (fileId === selectedBackground) { + selectNoBackground(); // Disable the current background + } + }; + + const selectNoBackground = (): void => { + setSelectedBackground(null); + localStorage.removeItem('selectedBackground'); + }; + + const calcCircumference = (radius: number) => 2 * Math.PI * radius; + + useEffect(() => { + loadBackgrounds(); + }, []); + + return ( + <> + +
+ +

Images

+
+ {/* Image uploader swatch */} +
+
+ {/* Plus icon */} +  +
+ +
+ {backgrounds.filter(bg => bg.type === 'image').map(bg => ( +
selectBackground(bg.id)} + className={`relative w-16 h-16 cursor-pointer rounded-xl transition ring dark:ring-white ring-zinc-300 ${isEditMode ? 'animate-shake' : ''} ${selectedBackground === bg.id ? 'dark:ring-2 ring-4' : 'ring-0'}`}> + {isEditMode && ( +
deleteBackground(bg.id)}> +
+
+ )} + swatch +
+ ))} + {backgrounds.concat(presetBackgrounds as Background[]).filter(bg => bg.type === 'image' && bg.isPreset && !bg.isDownloaded && !downloadedPresetIds.includes(bg.id)).map(bg => ( +
handlePresetClick(bg)} + className={`relative w-16 h-16 transition cursor-pointer rounded-xl duration-300 ${ isEditMode ? 'opacity-0 pointer-events-none' : 'opacity-100'}`}> + {bg.isPreset && downloadProgress[bg.id] !== undefined && ( +
+ + + + +
+ )} +
+ + {downloadProgress[bg.id] === undefined ? '' : ''} + +
+ swatch +
+ ))} +
+ +

Videos

+
+ {/* Video uploader swatch */} +
+
+ {/* Plus icon */} +  +
+ +
+ {backgrounds.filter(bg => bg.type === 'video').map(bg => ( +
selectBackground(bg.id)} className={`relative w-16 h-16 cursor-pointer rounded-xl transition ring dark:ring-white ring-zinc-300 ${isEditMode ? 'animate-shake' : ''} ${selectedBackground === bg.id ? 'dark:ring-2 ring-4' : 'ring-0'}`}> + {isEditMode && ( +
deleteBackground(bg.id)}> +
+
+ )} +
+ ))} + {backgrounds.concat(presetBackgrounds as Background[]).filter(bg => bg.type === 'video' && bg.isPreset && !bg.isDownloaded && !downloadedPresetIds.includes(bg.id)).map(bg => ( +
handlePresetClick(bg)} + className={`relative w-16 h-16 transition cursor-pointer rounded-xl duration-300 ${ isEditMode ? 'opacity-0 pointer-events-none' : 'opacity-100'}`}> + {bg.isPreset && downloadProgress[bg.id] !== undefined && ( +
+ + + + +
+ )} +
+ + {downloadProgress[bg.id] === undefined ? '' : ''} + +
+
+ ))} +
+
+ + ); +} \ No newline at end of file diff --git a/interface/src/hooks/BackgroundDataLoader.tsx b/interface/src/hooks/BackgroundDataLoader.tsx new file mode 100644 index 00000000..dc26b266 --- /dev/null +++ b/interface/src/hooks/BackgroundDataLoader.tsx @@ -0,0 +1,73 @@ +import { Background } from "../components/BackgroundSelector"; + +export const downloadPresetBackground = async (background: Background, onProgress: (progress: number) => void): Promise => { + const response = await fetch(background.url as string); + + const totalLength = +response.headers.get('Content-Length')!; + let receivedLength = 0; + + const reader = response.body?.getReader(); + const chunks = []; + + // eslint-disable-next-line no-constant-condition + while (true) { + const { done, value } = await reader!.read(); + + if (done) break; + + chunks.push(value!); + receivedLength += value!.length; + + onProgress(Math.ceil(receivedLength / totalLength * 100)); + } + + const blob = new Blob(chunks); + await writeData(background.id, background.type, blob); + + return { + id: background.id, + type: background.type, + blob, + url: URL.createObjectURL(blob), + }; +}; +// IndexedDB utility functions +export 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 as IDBOpenDBRequest).result; + db.createObjectStore('backgrounds', { keyPath: 'id' }); + }; + }); +}; +export const writeData = async (fileId: string, 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: fileId, type, blob }); + + await new Promise((res, rej) => { + tx.oncomplete = () => res(request.result); + tx.onerror = () => rej(tx.error); + }).then(resolve, reject); + + }).catch(reject); + }); +}; +export const readAllData = async (): Promise => { + const db = await openDB(); + const tx = db.transaction('backgrounds', 'readonly'); + const store = tx.objectStore('backgrounds'); + const request = store.getAll(); + + return await new Promise((resolve, reject) => { + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }); +}; diff --git a/interface/src/pages/Themes.tsx b/interface/src/pages/Themes.tsx index 2e2e5859..020e4a47 100644 --- a/interface/src/pages/Themes.tsx +++ b/interface/src/pages/Themes.tsx @@ -1,345 +1,11 @@ -import { useState, useEffect, ChangeEvent, FC } from 'react'; -import './Themes.css'; - -// Custom Types and Interfaces -interface Background { - id: string; - type: string; - blob: Blob; - url?: string; - previewUrl?: string; // New field - isPreset?: boolean; - isDownloaded?: boolean; -} - -const downloadPresetBackground = async (background: Background, onProgress: (progress: number) => void): Promise => { - const response = await fetch(background.url as string); - - const totalLength = +response.headers.get('Content-Length')!; - let receivedLength = 0; - - const reader = response.body?.getReader(); - const chunks = []; - - // eslint-disable-next-line no-constant-condition - while (true) { - const { done, value } = await reader!.read(); - - if (done) break; - - chunks.push(value!); - receivedLength += value!.length; - - onProgress(Math.ceil(receivedLength / totalLength * 100)); - } - - const blob = new Blob(chunks); - await writeData(background.id, background.type, blob); - - return { - id: background.id, - type: background.type, - blob, - url: URL.createObjectURL(blob), - }; -}; - -// IndexedDB utility functions -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 as IDBOpenDBRequest).result; - db.createObjectStore('backgrounds', { keyPath: 'id' }); - }; - }); -}; - -const writeData = async (fileId: string, 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: fileId, type, blob }); - - await new Promise((res, rej) => { - tx.oncomplete = () => res(request.result); - tx.onerror = () => rej(tx.error); - }).then(resolve, reject); - - }).catch(reject); - }); -}; - -const readAllData = async (): Promise => { - const db = await openDB(); - const tx = db.transaction('backgrounds', 'readonly'); - const store = tx.objectStore('backgrounds'); - const request = store.getAll(); - - return await new Promise((resolve, reject) => { - request.onsuccess = () => resolve(request.result); - request.onerror = () => reject(request.error); - }); -}; +import { FC } from 'react'; +import BackgroundSelector from '../components/BackgroundSelector'; const Themes: FC = () => { - const [backgrounds, setBackgrounds] = useState([]); - const [selectedBackground, setSelectedBackground] = useState(localStorage.getItem('selectedBackground')); - const [downloadedPresetIds, setDownloadedPresetIds] = useState([]); - const [downloadProgress, setDownloadProgress] = useState>({}); - const [isEditMode, setIsEditMode] = useState(false); - - - const presetBackgrounds = [ - // Images - { - id: 'image-preset-1', - type: 'image', - url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-1.jpg', - previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-1-thumb.jpg', - isPreset: true - }, - { - id: 'image-preset-2', - type: 'image', - url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-2.jpg', - previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-2-thumb.jpg', - isPreset: true - }, - { - id: 'image-preset-3', - type: 'image', - url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-3.jpg', - previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-3-thumb.jpg', - isPreset: true - }, - { - id: 'image-preset-4', - type: 'image', - url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-4.jpg', - previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-4-thumb.jpg', - isPreset: true - }, - { - id: 'image-preset-5', - type: 'image', - url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-5.jpg', - previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-5-thumb.jpg', - isPreset: true - }, - { - id: 'image-preset-6', - type: 'image', - url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-6.jpg', - previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-6-thumb.jpg', - isPreset: true - }, - { - id: 'image-preset-7', - type: 'image', - url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-7.jpg', - previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/images/background-7-thumb.jpg', - isPreset: true - }, - - // Videos - { - id: 'video-preset-1', - type: 'video', - url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/videos/animated-1.mp4', - previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/videos/animation-1-thumb.mp4', - isPreset: true - }, - { - id: 'video-preset-2', - type: 'video', - url: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/videos/animation-2.mp4', - previewUrl: 'https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/backgrounds/videos/animation-2-thumb.mp4', - isPreset: true - } - ]; - - const handleFileChange = async (e: ChangeEvent): Promise => { - const file = e.target.files?.[0]; - if (!file) return; - - const fileId = `${Date.now()}-${file.name}`; - const fileType = file.type.split('/')[0]; - const blob = new Blob([file], { type: file.type }); - - await writeData(fileId, fileType, blob); - setBackgrounds(prev => [...prev, { id: fileId, type: fileType, blob, url: URL.createObjectURL(blob) }]); - }; - - const loadBackgrounds = async (): Promise => { - const data = await readAllData(); - const dataWithUrls = data.map(bg => ({ ...bg, url: URL.createObjectURL(bg.blob) })); - - // Update downloaded preset IDs - setDownloadedPresetIds(data.map(bg => bg.id)); - - setBackgrounds(dataWithUrls); - }; - -const handlePresetClick = async (bg: Background): Promise => { - if (bg.isPreset) { - // Check if already exists in IndexedDB or is currently being downloaded - const existingBackgrounds = await readAllData(); - const alreadyExists = existingBackgrounds.some(ebg => ebg.id === bg.id) || downloadProgress[bg.id] !== undefined; - - if (!alreadyExists) { - setDownloadProgress(prev => ({ ...prev, [bg.id]: 0 })); - const downloadedBg = await downloadPresetBackground(bg, progress => { - console.log(`${bg}, ${progress}`); - setDownloadProgress(prev => ({ ...prev, [bg.id]: progress })); - }); - setDownloadProgress(prev => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { [bg.id]: _, ...rest } = prev; - return rest; - }); - await writeData(downloadedBg.id, downloadedBg.type, downloadedBg.blob); - setBackgrounds(prev => [...prev, downloadedBg]); - setDownloadedPresetIds(prev => [...prev, downloadedBg.id]); - } - selectBackground(bg.id); - } -}; - - const selectBackground = (fileId: string): void => { - setSelectedBackground(fileId); - localStorage.setItem('selectedBackground', fileId); - }; - - const deleteBackground = async (fileId: string): Promise => { - const db = await openDB(); - const tx = db.transaction('backgrounds', 'readwrite'); - const store = tx.objectStore('backgrounds'); - store.delete(fileId); - setBackgrounds(prev => prev.filter(bg => bg.id !== fileId)); - - // Check if the background being deleted is currently selected - if (fileId === selectedBackground) { - selectNoBackground(); // Disable the current background - } - }; - - const selectNoBackground = (): void => { - setSelectedBackground(null); - localStorage.removeItem('selectedBackground'); - }; - - const calcCircumference = (radius: number) => 2 * Math.PI * radius; - - useEffect(() => { - loadBackgrounds(); - }, []); return (
- -
- -

Images

-
- {/* Image uploader swatch */} -
-
- {/* Plus icon */} -  -
- -
- {backgrounds.filter(bg => bg.type === 'image').map(bg => ( -
selectBackground(bg.id)} - className={`relative w-16 h-16 cursor-pointer rounded-xl transition ring dark:ring-white ring-zinc-300 ${isEditMode ? 'animate-shake' : ''} ${selectedBackground === bg.id ? 'dark:ring-2 ring-4' : 'ring-0'}`}> - {isEditMode && ( -
deleteBackground(bg.id)}> -
-
- )} - swatch -
- ))} - {backgrounds.concat(presetBackgrounds as Background[]).filter(bg => bg.type === 'image' && bg.isPreset && !bg.isDownloaded && !downloadedPresetIds.includes(bg.id)).map(bg => ( -
handlePresetClick(bg)} - className={`relative w-16 h-16 transition cursor-pointer rounded-xl duration-300 ${ isEditMode ? 'opacity-0 pointer-events-none' : 'opacity-100'}`}> - {bg.isPreset && downloadProgress[bg.id] !== undefined && ( -
- - - - -
- )} -
- - {downloadProgress[bg.id] === undefined ? '' : ''} - -
- swatch -
- ))} -
- -

Videos

-
- {/* Video uploader swatch */} -
-
- {/* Plus icon */} -  -
- -
- {backgrounds.filter(bg => bg.type === 'video').map(bg => ( -
selectBackground(bg.id)} className={`relative w-16 h-16 cursor-pointer rounded-xl transition ring dark:ring-white ring-zinc-300 ${isEditMode ? 'animate-shake' : ''} ${selectedBackground === bg.id ? 'dark:ring-2 ring-4' : 'ring-0'}`}> - {isEditMode && ( -
deleteBackground(bg.id)}> -
-
- )} -
- ))} - {backgrounds.concat(presetBackgrounds as Background[]).filter(bg => bg.type === 'video' && bg.isPreset && !bg.isDownloaded && !downloadedPresetIds.includes(bg.id)).map(bg => ( -
handlePresetClick(bg)} - className={`relative w-16 h-16 transition cursor-pointer rounded-xl duration-300 ${ isEditMode ? 'opacity-0 pointer-events-none' : 'opacity-100'}`}> - {bg.isPreset && downloadProgress[bg.id] !== undefined && ( -
- - - - -
- )} -
- - {downloadProgress[bg.id] === undefined ? '' : ''} - -
-
- ))} -
-
+
); }; diff --git a/safari/BetterSEQTA+.xcodeproj/project.xcworkspace/xcuserdata/sethburkart.xcuserdatad/UserInterfaceState.xcuserstate b/safari/BetterSEQTA+.xcodeproj/project.xcworkspace/xcuserdata/sethburkart.xcuserdatad/UserInterfaceState.xcuserstate index 1a9e8eb3..da751e9b 100644 Binary files a/safari/BetterSEQTA+.xcodeproj/project.xcworkspace/xcuserdata/sethburkart.xcuserdatad/UserInterfaceState.xcuserstate and b/safari/BetterSEQTA+.xcodeproj/project.xcworkspace/xcuserdata/sethburkart.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/safari/BetterSEQTA+.xcodeproj/xcuserdata/sethburkart.xcuserdatad/xcschemes/xcschememanagement.plist b/safari/BetterSEQTA+.xcodeproj/xcuserdata/sethburkart.xcuserdatad/xcschemes/xcschememanagement.plist index 4865fbf4..cc3d30cf 100644 --- a/safari/BetterSEQTA+.xcodeproj/xcuserdata/sethburkart.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/safari/BetterSEQTA+.xcodeproj/xcuserdata/sethburkart.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ BetterSEQTA+ (iOS).xcscheme_^#shared#^_ orderHint - 1 + 0 BetterSEQTA+ (macOS).xcscheme_^#shared#^_ orderHint - 0 + 1 diff --git a/src/SEQTA.js b/src/SEQTA.js index f544b1ba..cc5a4313 100644 --- a/src/SEQTA.js +++ b/src/SEQTA.js @@ -15,7 +15,7 @@ import { MessageHandler } from "./seqta/utils/MessageListener.js"; import { updateBgDurations } from "./seqta/ui/Animation.js"; import { updateAllColors } from "./seqta/ui/colors/Manager.js"; import { appendBackgroundToUI } from "./seqta/ui/ImageBackgrounds.js"; -import { EnableThemes } from "./seqta/ui/Themes.js"; +import { enableCurrentTheme } from "./seqta/ui/Themes.js"; export let isChrome = window.chrome; let SettingsClicked = false; @@ -774,7 +774,7 @@ document.addEventListener( chrome.storage.local.get(null, function (items) { main(items); - EnableThemes(); + enableCurrentTheme(); }); } if ( diff --git a/src/seqta/ui/Themes.js b/src/seqta/ui/Themes.js index d88985fa..3169b698 100644 --- a/src/seqta/ui/Themes.js +++ b/src/seqta/ui/Themes.js @@ -45,10 +45,6 @@ const saveToIndexedDB = async (theme, themeName) => { // Apply theme from storage via localForage to document const applyTheme = async (themeName) => { const { css, className, images } = await localforage.getItem(`css_${themeName}`); - console.log(`Applying theme ${themeName}`); - console.log(`CSS: ${css}`); - console.log(`className: ${className}`); - console.log(`images: ${images}`); // Apply CSS const style = document.createElement("style"); @@ -56,7 +52,7 @@ const applyTheme = async (themeName) => { document.head.appendChild(style); // Apply className - document.body.classList.add(className); + if (className) document.body.classList.add(className); // Apply images if (images) { @@ -70,8 +66,41 @@ const applyTheme = async (themeName) => { } }; +export const downloadTheme = async (themeName, themeUrl) => { + console.log(`Fetching theme ${themeName} from ${themeUrl}...`); + const themeData = await fetchThemeJSON(themeUrl); + await saveToIndexedDB(themeData, themeName); + console.log(`Theme ${themeName} saved to IndexedDB`); + setTheme(themeName); + return; +}; + +export const setTheme = async (themeName, themeUrl) => { + if (!(await themeExistsInDB(themeName))) { + await downloadTheme(themeName, themeUrl); + } + + localStorage.setItem("selectedTheme", themeName); + await applyTheme(themeName).catch((error) => { + console.error(`Failed to apply theme: ${error}`); + }); +}; + +export const enableCurrentTheme = async () => { + const currentTheme = localStorage.getItem("selectedTheme"); + + if (currentTheme) { + console.log(`Enabling current theme: ${currentTheme}`); + await applyTheme(currentTheme).catch((error) => { + console.error(`Failed to apply current theme: ${error}`); + }); + } else { + console.log("No current theme set in localStorage."); + } +}; + // 🚀 Main function to orchestrate everything 🚀 -export const EnableThemes = async () => { +/* export const EnableThemes = async () => { const availableThemes = [ { name: "dark", url: "https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/themes/test.json" } ]; @@ -95,4 +124,4 @@ export const EnableThemes = async () => { await applyTheme(themeToApply).catch((error) => { console.error(`Failed to apply theme: ${error}`); }); -}; \ No newline at end of file +}; */ \ No newline at end of file diff --git a/src/seqta/utils/MessageListener.js b/src/seqta/utils/MessageListener.js index d39a3d61..3952a1a7 100644 --- a/src/seqta/utils/MessageListener.js +++ b/src/seqta/utils/MessageListener.js @@ -1,6 +1,7 @@ /* global chrome */ import { MenuOptionsOpen, OpenMenuOptions, closeSettings } from "../../SEQTA.js"; +import { downloadTheme, setTheme } from "../ui/Themes.js"; export class MessageHandler { constructor() { @@ -13,8 +14,11 @@ export class MessageHandler { case "EditSidebar": this.editSidebar(); break; - case "Theme": - console.log("Theme message received"); + case "SetTheme": + setTheme(request.body.themeName, request.body.themeURL); + break; + case "DownloadTheme": + downloadTheme(request.body.themeURL, request.body.themeName); break; default: