import { ChangeEvent, memo, useEffect, useState } from "react"; import { downloadPresetBackground, openDB, readAllData, writeData } from "../hooks/BackgroundDataLoader"; import presetBackgrounds from "../assets/presetBackgrounds"; import "./BackgroundSelector.css"; import { disableTheme } from "../hooks/ThemeManagment"; import browser from "webextension-polyfill"; // Custom Types and Interfaces export interface Background { id: string; type: string; blob: Blob; url?: string; previewUrl?: string; isPreset?: boolean; isDownloaded?: boolean; } interface BackgroundSelectorProps { selectedType: "background" | "theme"; setSelectedType: (type: "background" | "theme") => void; isEditMode: boolean; } async function GetTheme() { return localStorage.getItem('selectedBackground'); } async function SetTheme(theme: string) { localStorage.setItem('selectedBackground', theme); await browser.storage.local.set({ theme }); } function BackgroundSelector({ selectedType, setSelectedType, isEditMode }: BackgroundSelectorProps) { const [backgrounds, setBackgrounds] = useState([]); const [selectedBackground, setSelectedBackground] = useState(); const [downloadedPresetIds, setDownloadedPresetIds] = useState([]); const [downloadProgress, setDownloadProgress] = useState>({}); const [BackgroundsBlocked, setBackgroundsBlocked] = useState(false); useEffect(() => { GetTheme().then((theme) => { setSelectedBackground(theme); }); }, []); 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 indexed DB is accessible or whether cross site cookies blocks it try { await openDB(); } catch (error) { // @ts-expect-error - Brave is not in the navigator type (unless you are actually using brave browser, then it is there) if (navigator.brave && await navigator.brave.isBrave() || false) { console.log('[BetterSEQTA+] Brave browser is blocking access to IndexedDB. Please disable the "Cross-site cookies blocked" setting in the Shields panel. (or you can just disable brave shields for SEQTA)'); setBackgroundsBlocked(true); return; } alert("[BetterSEQTA+] IndexedDB is not accessible. Please check your browser settings (It's probably cross-site cookies that are blocked)."); return; } // 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 => { 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 => { if (selectedType == 'background' && selectedBackground == fileId) { selectNoBackground(); return; } disableTheme(); setSelectedType('background'); setSelectedBackground(fileId); SetTheme(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 => { setSelectedType('background'); disableTheme(); setSelectedBackground(null); SetTheme(''); }; const calcCircumference = (radius: number) => 2 * Math.PI * radius; useEffect(() => { loadBackgrounds(); }, []); return ( <> {BackgroundsBlocked && (

File Storage Blocked

Brave browser is blocking access to IndexedDB. Please disable the "Cross-site cookies blocked" setting in the Shields panel. (or you can just disable brave shields for SEQTA)

Brave browser logo
)}

Background 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 && selectedType === "background" ? '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 => ( ))}

Background 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 && selectedType === "background" ? '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 hidden' : 'opacity-100'}`}> {bg.isPreset && downloadProgress[bg.id] !== undefined && (
)}
{downloadProgress[bg.id] === undefined ? '' : ''}
))}
); } export default memo(BackgroundSelector);