From 8508169cd75b9b794534adfca4cd4a7e2a39e124 Mon Sep 17 00:00:00 2001 From: SethBurkart123 Date: Thu, 2 Nov 2023 17:11:02 +1100 Subject: [PATCH] more robust theme selector --- interface/src/assets/presetBackgrounds.tsx | 70 ++++++++++ interface/src/assets/themes.tsx | 14 ++ .../src/components/BackgroundSelector.tsx | 119 ++++------------- interface/src/components/ThemeSelector.tsx | 123 +++++++++++++++++- src/background.js | 1 - src/seqta/ui/Themes.js | 7 +- src/seqta/utils/MessageListener.js | 21 ++- 7 files changed, 246 insertions(+), 109 deletions(-) create mode 100644 interface/src/assets/presetBackgrounds.tsx create mode 100644 interface/src/assets/themes.tsx diff --git a/interface/src/assets/presetBackgrounds.tsx b/interface/src/assets/presetBackgrounds.tsx new file mode 100644 index 00000000..c73f5053 --- /dev/null +++ b/interface/src/assets/presetBackgrounds.tsx @@ -0,0 +1,70 @@ +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 + } +]; + +export default presetBackgrounds; \ No newline at end of file diff --git a/interface/src/assets/themes.tsx b/interface/src/assets/themes.tsx new file mode 100644 index 00000000..f1ec6b92 --- /dev/null +++ b/interface/src/assets/themes.tsx @@ -0,0 +1,14 @@ +const themes = [ + { + name: "Dark", + url: "https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/themes/dark.json", + coverImage: , + }, + { + name: "Light", + url: "https://raw.githubusercontent.com/SethBurkart123/BetterSEQTA-Themes/main/themes/light.json", + coverImage: , + } +]; + +export default themes; \ No newline at end of file diff --git a/interface/src/components/BackgroundSelector.tsx b/interface/src/components/BackgroundSelector.tsx index 7cd822a9..05aa1c12 100644 --- a/interface/src/components/BackgroundSelector.tsx +++ b/interface/src/components/BackgroundSelector.tsx @@ -1,5 +1,6 @@ import { ChangeEvent, useEffect, useState } from "react"; import { downloadPresetBackground, openDB, readAllData, writeData } from "../hooks/BackgroundDataLoader"; +import presetBackgrounds from "../assets/presetBackgrounds"; import "./BackgroundSelector.css"; // Custom Types and Interfaces @@ -8,7 +9,7 @@ export interface Background { type: string; blob: Blob; url?: string; - previewUrl?: string; // New field + previewUrl?: string; isPreset?: boolean; isDownloaded?: boolean; } @@ -20,76 +21,6 @@ export default function BackgroundSelector() { 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; @@ -112,30 +43,30 @@ export default function BackgroundSelector() { 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]); + 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); } - selectBackground(bg.id); - } -}; + }; const selectBackground = (fileId: string): void => { setSelectedBackground(fileId); diff --git a/interface/src/components/ThemeSelector.tsx b/interface/src/components/ThemeSelector.tsx index 3e3e43ce..2d27e61f 100644 --- a/interface/src/components/ThemeSelector.tsx +++ b/interface/src/components/ThemeSelector.tsx @@ -1,6 +1,35 @@ -const downloadTheme = (themeName: string, themeURL: string) => { +import { useEffect, useState } from "react"; +import themesList from '../assets/themes'; + +interface Theme { + name: string; + url: string; + isDownloaded: boolean; + isLoading: boolean; + coverImage: JSX.Element; +} + +interface ThemeList { + themes: string[]; +} + +const downloadTheme = async (themeName: string, themeURL: string) => { // send message to the background script - chrome.runtime.sendMessage({ + const response = await chrome.runtime.sendMessage({ + type: 'currentTab', + info: 'DownloadTheme', + body: { + themeName: themeName, + themeURL: themeURL + } + }); + + console.log("Response: ", response); +} + +const setTheme = async (themeName: string, themeURL: string) => { + // send message to the background script + const response = await chrome.runtime.sendMessage({ type: 'currentTab', info: 'SetTheme', body: { @@ -8,11 +37,93 @@ const downloadTheme = (themeName: string, themeURL: string) => { themeURL: themeURL } }); + + console.log("Response: ", response); } +const listThemes = async () => { + // send message to the background script + const response: ThemeList = await chrome.runtime.sendMessage({ + type: 'currentTab', + info: 'ListThemes', + body: {} + }); + + // response.themes is an array of strings that are identical to the theme names that we loop over. Use this list to see which ones are downloaded and which ones need to see the download icon. + console.log("Response: ", response); + + return response.themes; +} + +const ThemeSelector = () => { + const [themes, setThemes] = useState([]); + + useEffect(() => { + const initializeThemes = async () => { + const downloaded = await listThemes(); + + const initializedThemes = themesList.map(theme => ({ + ...theme, + isDownloaded: downloaded.includes(theme.name), + isLoading: false + })); + + setThemes(initializedThemes); + }; + + initializeThemes(); + }, []); + + const handleThemeAction = async (themeName: string, themeURL: string) => { + // Find the theme in the state and set its loading property to true + setThemes(prevThemes => prevThemes.map(theme => + theme.name === themeName ? { ...theme, isLoading: true } : theme + )); + + // Call the appropriate method based on whether the theme is downloaded + const theme = themes.find(t => t.name === themeName); + if (theme && theme.isDownloaded) { + await setTheme(themeName, themeURL); + } else { + await downloadTheme(themeName, themeURL); + // After downloading, update the theme to be marked as downloaded + setThemes(prevThemes => prevThemes.map(t => + t.name === themeName ? { ...t, isDownloaded: true } : t + )); + } + + // Once the action is complete, set the theme's loading property to false + setThemes(prevThemes => prevThemes.map(theme => + theme.name === themeName ? { ...theme, isLoading: false } : theme + )); + }; -export default function ThemeSelector() { return ( - - ) -} \ No newline at end of file +
+ {themes.map((theme) => ( + + ))} +
+ ); +}; + +export default ThemeSelector; \ No newline at end of file diff --git a/src/background.js b/src/background.js index 518fa3f8..f9671182 100644 --- a/src/background.js +++ b/src/background.js @@ -104,7 +104,6 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { case "currentTab": chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { chrome.tabs.sendMessage(tabs[0].id, request, function (response) { - // send response from current tab to popup sendResponse(response); }); }); diff --git a/src/seqta/ui/Themes.js b/src/seqta/ui/Themes.js index 2ad5d8ff..c97d6ecf 100644 --- a/src/seqta/ui/Themes.js +++ b/src/seqta/ui/Themes.js @@ -66,16 +66,19 @@ const applyTheme = async (themeName) => { } }; +export const listThemes = async () => { + const themes = await localforage.keys(); + return themes.filter((key) => key.startsWith("css_")).map((key) => key.replace("css_", "")); +}; + 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`); - return; }; export const setTheme = async (themeName, themeUrl) => { - await downloadTheme(themeName, themeUrl); if (!(await themeExistsInDB(themeName))) { await downloadTheme(themeName, themeUrl); } diff --git a/src/seqta/utils/MessageListener.js b/src/seqta/utils/MessageListener.js index 00ad3172..a80727dc 100644 --- a/src/seqta/utils/MessageListener.js +++ b/src/seqta/utils/MessageListener.js @@ -1,14 +1,14 @@ /* global chrome */ import { MenuOptionsOpen, OpenMenuOptions, closeSettings } from "../../SEQTA.js"; -import { downloadTheme, setTheme } from "../ui/Themes.js"; +import { downloadTheme, listThemes, setTheme } from "../ui/Themes.js"; export class MessageHandler { constructor() { chrome.runtime.onMessage.addListener(this.routeMessage.bind(this)); } - routeMessage(request) { + routeMessage(request, sender, sendResponse) { switch (request.info) { case "EditSidebar": @@ -16,11 +16,20 @@ export class MessageHandler { break; case "SetTheme": console.log(request); - setTheme(request.body.themeName, request.body.themeURL); - break; + setTheme(request.body.themeName, request.body.themeURL).then(() => { + sendResponse({ status: "success" }); + }); + return true; case "DownloadTheme": - downloadTheme(request.body.themeURL, request.body.themeName); - break; + downloadTheme(request.body.themeName, request.body.themeURL).then(() => { + sendResponse({ status: "success" }); + }); + return true; + case "ListThemes": + listThemes().then((themes) => { + sendResponse({ themes }); + }); + return true; default: console.log("Unknown request info:", request.info);