From 2e2670f27545984cd37976ef33eef2cc9266e34f Mon Sep 17 00:00:00 2001 From: alexsparkes Date: Tue, 26 Nov 2024 21:56:20 +0000 Subject: [PATCH] refactor(background): Further code readaability improvements --- src/features/background/Background.jsx | 458 ++++-------------- .../background/api/backgroundHelpers.js | 262 ++++++++++ .../background/api/backgroundTypeHandlers.js | 61 +++ .../background/api/useBackgroundAPI.js | 45 ++ 4 files changed, 457 insertions(+), 369 deletions(-) create mode 100644 src/features/background/api/backgroundHelpers.js create mode 100644 src/features/background/api/backgroundTypeHandlers.js create mode 100644 src/features/background/api/useBackgroundAPI.js diff --git a/src/features/background/Background.jsx b/src/features/background/Background.jsx index 04071b2e..0c2c0c5c 100644 --- a/src/features/background/Background.jsx +++ b/src/features/background/Background.jsx @@ -1,199 +1,70 @@ import React, { useState, useEffect, useCallback, useRef } from 'react'; -import variables from 'config/variables'; import PhotoInformation from './components/PhotoInformation'; import EventBus from 'utils/eventbus'; -import { getOfflineImage } from './api/getOfflineImage'; -import { supportsAVIF } from './api/avif'; -import videoCheck from './api/videoCheck'; -import { randomColourStyleBuilder } from './api/randomColour'; -import { decodeBlurHash } from 'fast-blurhash'; import defaults from './options/default'; import Stats from 'features/stats/api/stats'; import BackgroundImage from './components/BackgroundImage'; import BackgroundVideo from './components/BackgroundVideo'; import './scss/index.scss'; +import useBackgroundAPI from './api/useBackgroundAPI'; +import { handleBackgroundType, applyBackground } from './api/backgroundTypeHandlers'; +import { + resetElements, + handleBackgroundVisibility, + handleBackgroundEffectEvent, +} from './api/backgroundHelpers'; + +const initialState = { + blob: null, + style: '', + url: '', + currentAPI: '', + firstTime: false, + photoInfo: { + hidden: false, + offline: false, + photographerURL: '', + photoURL: '', + }, + type: '', + video: false, +}; const Background = () => { - const [state, setState] = useState({ - blob: null, - style: '', - url: '', - currentAPI: '', - firstTime: false, - photoInfo: { - hidden: false, - offline: false, - photographerURL: '', - photoURL: '', - }, - type: '', - video: false, - }); - + const [backgroundState, setBackgroundState] = useState(initialState); const blobRef = useRef(null); - - const getAPIImageData = useCallback(async (currentPun) => { - let apiCategories; - try { - apiCategories = JSON.parse(localStorage.getItem('apiCategories')); - } catch (error) { - apiCategories = localStorage.getItem('apiCategories'); - } - const backgroundAPI = localStorage.getItem('backgroundAPI') || defaults.backgroundAPI; - const apiQuality = localStorage.getItem('apiQuality') || defaults.apiQuality; - let backgroundExclude = JSON.parse(localStorage.getItem('backgroundExclude')); - if (!Array.isArray(backgroundExclude)) { - backgroundExclude = []; - } - if (currentPun) { - backgroundExclude.push(currentPun); - } - - let requestURL; - switch (backgroundAPI) { - case 'unsplash': - case 'pexels': - const collection = - localStorage.getItem('unsplashCollections') || defaults.unsplashCollections; - requestURL = collection - ? `${variables.constants.API_URL}/images/unsplash?collections=${collection}&quality=${apiQuality}` - : `${variables.constants.API_URL}/images/unsplash?categories=${apiCategories || ''}&quality=${apiQuality}`; - break; - default: - requestURL = `${variables.constants.API_URL}/images/random?categories=${apiCategories || ''}&quality=${apiQuality}&excludes=${backgroundExclude}`; - break; - } - - const accept = `application/json, ${supportsAVIF() ? 'image/avif' : 'image/webp'}`; - try { - const response = await fetch(requestURL, { headers: { accept } }); - const data = await response.json(); - let photoURL, photographerURL; - if (backgroundAPI === 'unsplash') { - photoURL = data.photo_page; - photographerURL = data.photographer_page; - } - return { - url: data.file, - type: 'api', - currentAPI: backgroundAPI, - photoInfo: { - hidden: false, - category: data.category, - credit: data.photographer, - location: data.location.name, - camera: data.camera, - url: data.file, - photographerURL, - photoURL, - latitude: data.location.latitude || null, - longitude: data.location.longitude || null, - views: data.views || null, - downloads: data.downloads || null, - likes: data.likes || null, - description: data.description || null, - colour: data.colour, - blur_hash: data.blur_hash, - pun: data.pun || null, - }, - }; - } catch (e) { - setState(getOfflineImage('api')); - Stats.postEvent('background', 'image', 'offline'); - return null; - } - }, []); + const { getAPIImageData } = useBackgroundAPI(setBackgroundState); const setBackground = useCallback(async () => { - // Clean up previous blob URL if (blobRef.current) { URL.revokeObjectURL(blobRef.current); blobRef.current = null; } - const backgroundImage = document.getElementById('backgroundImage'); - const blurhashOverlay = document.getElementById('blurhashOverlay'); - const backgroundImageActual = document.getElementById('backgroundImageActual'); - const photoInformation = document.querySelector('.photoInformation'); + const elements = { + backgroundImage: document.getElementById('backgroundImage'), + blurhashOverlay: document.getElementById('blurhashOverlay'), + backgroundImageActual: document.getElementById('backgroundImageActual'), + photoInformation: document.querySelector('.photoInformation'), + }; - // Reset elements to default state - backgroundImageActual.style.opacity = 0; - blurhashOverlay.style.backgroundImage = ''; - blurhashOverlay.style.backgroundColor = ''; + resetElements(elements.backgroundImageActual, elements.blurhashOverlay); - // Handle different background types try { - switch (state.type) { - case 'api': - // Handle API image with blurhash - if (state.url) { - if (localStorage.getItem('bgtransition') === 'false') { - if (photoInformation) { - photoInformation.style.display = 'flex'; - } - backgroundImage.style.background = `url(${state.url})`; - return; - } + await applyBackground(backgroundState, elements); - // Set blurhash overlay if available - if (state.photoInfo.blur_hash) { - blurhashOverlay.style.backgroundColor = state.photoInfo.colour; - const canvas = document.createElement('canvas'); - canvas.width = 32; - canvas.height = 32; - const ctx = canvas.getContext('2d'); - const imageData = ctx.createImageData(32, 32); - imageData.data.set(decodeBlurHash(state.photoInfo.blur_hash, 32, 32)); - ctx.putImageData(imageData, 0, 0); - blurhashOverlay.style.backgroundImage = `url(${canvas.toDataURL()})`; - } - - // Load actual image - const newBlob = URL.createObjectURL(await (await fetch(state.url)).blob()); - blobRef.current = newBlob; - backgroundImageActual.src = newBlob; - } - break; - - case 'colour': - case 'random_colour': - case 'random_gradient': - backgroundImage.style.background = state.style; - backgroundImageActual.src = ''; - Stats.postEvent('background', 'colour', 'set'); - break; - - case 'custom': - case 'photo_pack': - if (state.url) { - backgroundImage.style.background = `url(${state.url})`; - if (photoInformation && !state.photoInfo.hidden) { - photoInformation.style.display = 'flex'; - } - } - Stats.postEvent('background', state.type, 'set'); - break; - - default: - // Fallback to solid color - backgroundImage.style.background = state.style || 'rgb(0,0,0)'; - Stats.postEvent('background', 'colour', 'set'); - } - - // Set up image load handler for all image types - if (backgroundImageActual.src) { - backgroundImageActual.onload = () => { - backgroundImageActual.style.opacity = 1; - blurhashOverlay.style.opacity = 0; + if (elements.backgroundImageActual.src) { + elements.backgroundImageActual.onload = () => { + elements.backgroundImageActual.style.opacity = 1; + elements.blurhashOverlay.style.opacity = 0; Stats.postEvent('feature', 'background-image', 'shown'); }; } } catch (error) { console.error('Error setting background:', error); - // Fallback to solid black background - backgroundImage.style.background = 'rgb(0,0,0)'; + elements.backgroundImage.style.background = 'rgb(0,0,0)'; } - }, [state]); + }, [backgroundState]); const getBackground = useCallback(async () => { let offline = localStorage.getItem('offlineMode') === 'true'; @@ -201,206 +72,68 @@ const Background = () => { offline = true; } - const setFavourited = ({ type, url, credit, location, camera, pun, offline }) => { - if (type === 'random_colour' || type === 'random_gradient') { - setState({ - type: 'colour', - style: url, - }); - } else { - setState({ - url, - photoInfo: { - credit, - location, - camera, - pun, - offline, - url, - }, - }); - } - Stats.postEvent('background', 'favourite', 'set'); - }; - const favourited = JSON.parse(localStorage.getItem('favourite')); if (favourited) { - setFavourited(favourited); + setFavouritedBackground(favourited); return; } const type = localStorage.getItem('backgroundType') || defaults.backgroundType; - switch (type) { - case 'api': - if (offline) { - setState(getOfflineImage('api')); - Stats.postEvent('background', 'image', 'offline'); - return; - } - let data = JSON.parse(localStorage.getItem('nextImage')) || (await getAPIImageData()); - localStorage.setItem('nextImage', null); - if (data) { - setState(data); - localStorage.setItem('currentBackground', JSON.stringify(data)); - localStorage.setItem( - 'nextImage', - JSON.stringify(await getAPIImageData(data.photoInfo.pun)), - ); - Stats.postEvent('background', 'image', 'api'); - } - break; - case 'colour': - let customBackgroundColour = localStorage.getItem('customBackgroundColour'); - if (customBackgroundColour && customBackgroundColour.startsWith('{')) { - const customBackground = JSON.parse(customBackgroundColour); - try { - localStorage.setItem('customBackgroundColour', customBackground.gradient[0].colour); - customBackgroundColour = customBackground.gradient.colour; - } catch (e) { - customBackgroundColour = 'rgb(0,0,0)'; - } - } - setState({ - type: 'colour', - style: customBackgroundColour || 'rgb(0,0,0)', - }); - Stats.postEvent('background', 'colour', 'custom'); - break; - case 'random_colour': - case 'random_gradient': - const randomStyle = randomColourStyleBuilder(type); - setState({ - type: 'colour', - style: randomStyle, - }); - Stats.postEvent('background', 'colour', 'random'); - break; - case 'custom': - let customBackground = []; - const customSaved = localStorage.getItem('customBackground') || defaults.customBackground; - try { - customBackground = JSON.parse(customSaved); - } catch (e) { - if (customSaved !== '') { - customBackground = [customSaved]; - } - localStorage.setItem('customBackground', JSON.stringify(customBackground)); - } - customBackground = customBackground[Math.floor(Math.random() * customBackground.length)]; - if (offline && !customBackground.startsWith('data:')) { - setState(getOfflineImage('custom')); - Stats.postEvent('background', 'image', 'offline'); - return; - } - if ( - customBackground !== '' && - customBackground !== 'undefined' && - customBackground !== undefined - ) { - const object = { - url: customBackground, - type: 'custom', - video: videoCheck(customBackground), - photoInfo: { - hidden: true, - }, - }; - setState(object); - localStorage.setItem('currentBackground', JSON.stringify(object)); - Stats.postEvent('background', 'image', 'custom'); - } - break; - case 'photo_pack': - if (offline) { - setState(getOfflineImage('photo')); - Stats.postEvent('background', 'image', 'offline'); - return; - } - const photoPack = []; - const installed = JSON.parse(localStorage.getItem('installed')); - installed.forEach((item) => { - if (item.type === 'photos') { - const photos = item.photos.map((photo) => photo); - photoPack.push(...photos); - } - }); - if (photoPack.length === 0) { - setState(getOfflineImage('photo')); - Stats.postEvent('background', 'image', 'offline'); - return; - } - const photo = photoPack[Math.floor(Math.random() * photoPack.length)]; - setState({ - url: photo.url.default, - type: 'photo_pack', - video: videoCheck(photo.url.default), - photoInfo: { - photographer: photo.photographer, - }, - }); - Stats.postEvent('background', 'image', 'photo_pack'); - break; - default: - break; - } + await handleBackgroundType(type, offline, getAPIImageData, setBackgroundState); }, [getAPIImageData]); + const setFavouritedBackground = ({ type, url, credit, location, camera, pun, offline }) => { + if (type === 'random_colour' || type === 'random_gradient') { + setBackgroundState({ + type: 'colour', + style: url, + }); + } else { + setBackgroundState({ + url, + photoInfo: { + credit, + location, + camera, + pun, + offline, + url, + }, + }); + } + Stats.postEvent('background', 'favourite', 'set'); + }; + const handleRefreshEvent = useCallback( (data) => { const element = document.getElementById('backgroundImage'); const refresh = () => { element.classList.remove('fade-in'); - setState({ - url: '', - style: '', - type: '', - video: false, - photoInfo: { - hidden: true, - }, - }); + setBackgroundState(initialState); getBackground(); }; if (data === 'welcomeLanguage') { - localStorage.setItem('welcomeImage', JSON.stringify(state)); + localStorage.setItem('welcomeImage', JSON.stringify(backgroundState)); } if (data === 'background') { - if (localStorage.getItem('background') === 'false') { - if (state.photoInfo.hidden === false) { - document.querySelector('.photoInformation').style.display = 'none'; - } - if (state.video === true) { - document.getElementById('backgroundVideo').style.display = 'none'; - } else { - element.style.display = 'none'; - } - return; - } - if (state.video === true) { - document.getElementById('backgroundVideo').style.display = 'block'; - } else { - if (state.photoInfo.hidden === false) { - try { - document.querySelector('.photoInformation').style.display = 'flex'; - } catch (e) { - // Disregard exception - } - } - element.style.display = 'block'; - } + handleBackgroundVisibility(backgroundState, element); const backgroundType = localStorage.getItem('backgroundType') || defaults.backgroundType; - if (state.photoInfo.offline !== true) { + if (backgroundState.photoInfo.offline !== true) { if ( - backgroundType !== state.type || - (state.type === 'api' && localStorage.getItem('backgroundAPI') !== state.currentAPI) || - (state.type === 'custom' && localStorage.getItem('customBackground') !== state.url) || - JSON.parse(localStorage.getItem('backgroundExclude')).includes(state.photoInfo.pun) + backgroundType !== backgroundState.type || + (backgroundState.type === 'api' && + localStorage.getItem('backgroundAPI') !== backgroundState.currentAPI) || + (backgroundState.type === 'custom' && + localStorage.getItem('customBackground') !== backgroundState.url) || + JSON.parse(localStorage.getItem('backgroundExclude')).includes( + backgroundState.photoInfo.pun, + ) ) { refresh(); return; } - } else if (backgroundType !== state.type) { + } else if (backgroundType !== backgroundState.type) { refresh(); return; } @@ -413,29 +146,12 @@ const Background = () => { refresh(); } }, - [state, getBackground], + [backgroundState, getBackground], ); - const handleBackgroundEffectEvent = useCallback(() => { - const element = document.getElementById('backgroundImage'); - const backgroundFilterSetting = - localStorage.getItem('backgroundFilter') || defaults.backgroundFilter; - const backgroundFilter = backgroundFilterSetting && backgroundFilterSetting !== 'none'; - const filterValue = `blur(${localStorage.getItem('blur')}px) brightness(${localStorage.getItem('brightness')}%) ${ - backgroundFilter - ? backgroundFilterSetting + '(' + localStorage.getItem('backgroundFilterAmount') + '%)' - : '' - }`; - if (state.video === true) { - document.getElementById('backgroundVideo').style.filter = filterValue; - } else { - element.style.filter = filterValue; - } - }, [state.video]); - useEffect(() => { if (localStorage.getItem('welcomeTab')) { - setState(JSON.parse(localStorage.getItem('welcomeImage'))); + setBackgroundState(JSON.parse(localStorage.getItem('welcomeImage'))); return; } getBackground(); @@ -449,23 +165,27 @@ const Background = () => { EventBus.off('refresh', handleRefreshEvent); EventBus.off('backgroundeffect', handleBackgroundEffectEvent); }; - }, [handleRefreshEvent, handleBackgroundEffectEvent]); + }, [handleRefreshEvent]); useEffect(() => { - if (state.video !== true) { + if (backgroundState.video !== true) { setBackground(); } - }, [state, setBackground]); + }, [backgroundState, setBackground]); - if (state.video === true) { - return ; + if (backgroundState.video === true) { + return ; } return ( <> - {state.photoInfo && state.photoInfo.credit && ( - + {backgroundState.photoInfo && backgroundState.photoInfo.credit && ( + )} ); diff --git a/src/features/background/api/backgroundHelpers.js b/src/features/background/api/backgroundHelpers.js new file mode 100644 index 00000000..dd2c235f --- /dev/null +++ b/src/features/background/api/backgroundHelpers.js @@ -0,0 +1,262 @@ +import { decodeBlurHash } from 'fast-blurhash'; +import { getOfflineImage } from './getOfflineImage'; +import { supportsAVIF } from './avif'; +import videoCheck from './videoCheck'; +import { randomColourStyleBuilder } from './randomColour'; +import defaults from '../options/default'; +import variables from 'config/variables'; +import Stats from 'features/stats/api/stats'; + +export const getRequestURL = (backgroundAPI, apiCategories, apiQuality, backgroundExclude) => { + switch (backgroundAPI) { + case 'unsplash': + case 'pexels': + const collection = + localStorage.getItem('unsplashCollections') || defaults.unsplashCollections; + return collection + ? `${variables.constants.API_URL}/images/unsplash?collections=${collection}&quality=${apiQuality}` + : `${variables.constants.API_URL}/images/unsplash?categories=${apiCategories || ''}&quality=${apiQuality}`; + default: + return `${variables.constants.API_URL}/images/random?categories=${apiCategories || ''}&quality=${apiQuality}&excludes=${backgroundExclude}`; + } +}; + +export const formatAPIData = (data, backgroundAPI) => { + let photoURL, photographerURL; + if (backgroundAPI === 'unsplash') { + photoURL = data.photo_page; + photographerURL = data.photographer_page; + } + return { + url: data.file, + type: 'api', + currentAPI: backgroundAPI, + photoInfo: { + hidden: false, + category: data.category, + credit: data.photographer, + location: data.location.name, + camera: data.camera, + url: data.file, + photographerURL, + photoURL, + latitude: data.location.latitude || null, + longitude: data.location.longitude || null, + views: data.views || null, + downloads: data.downloads || null, + likes: data.likes || null, + description: data.description || null, + colour: data.colour, + blur_hash: data.blur_hash, + pun: data.pun || null, + }, + }; +}; + +export const resetElements = (backgroundImageActual, blurhashOverlay) => { + backgroundImageActual.style.opacity = 0; + blurhashOverlay.style.backgroundImage = ''; + blurhashOverlay.style.backgroundColor = ''; +}; + +export const handleAPIBackground = async ( + state, + backgroundImage, + blurhashOverlay, + backgroundImageActual, + photoInformation, +) => { + if (state.url) { + if (localStorage.getItem('bgtransition') === 'false') { + if (photoInformation) { + photoInformation.style.display = 'flex'; + } + backgroundImage.style.background = `url(${state.url})`; + return; + } + + if (state.photoInfo.blur_hash) { + blurhashOverlay.style.backgroundColor = state.photoInfo.colour; + const canvas = document.createElement('canvas'); + canvas.width = 32; + canvas.height = 32; + const ctx = canvas.getContext('2d'); + const imageData = ctx.createImageData(32, 32); + imageData.data.set(decodeBlurHash(state.photoInfo.blur_hash, 32, 32)); + ctx.putImageData(imageData, 0, 0); + blurhashOverlay.style.backgroundImage = `url(${canvas.toDataURL()})`; + } + + const newBlob = URL.createObjectURL(await (await fetch(state.url)).blob()); + backgroundImageActual.src = newBlob; + } +}; + +export const handleColourBackground = (state, backgroundImage) => { + backgroundImage.style.background = state.style; + Stats.postEvent('background', 'colour', 'set'); +}; + +export const handleCustomBackground = (state, backgroundImage, photoInformation) => { + if (state.url) { + backgroundImage.style.background = `url(${state.url})`; + if (photoInformation && !state.photoInfo.hidden) { + photoInformation.style.display = 'flex'; + } + } + Stats.postEvent('background', state.type, 'set'); +}; + +export const handleDefaultBackground = (state, backgroundImage) => { + backgroundImage.style.background = state.style || 'rgb(0,0,0)'; + Stats.postEvent('background', 'colour', 'set'); +}; + +export const handleAPIBackgroundType = async (offline, getAPIImageData, setState) => { + if (offline) { + setState(getOfflineImage('api')); + Stats.postEvent('background', 'image', 'offline'); + return; + } + let data = JSON.parse(localStorage.getItem('nextImage')) || (await getAPIImageData()); + localStorage.setItem('nextImage', null); + if (data) { + setState(data); + localStorage.setItem('currentBackground', JSON.stringify(data)); + localStorage.setItem('nextImage', JSON.stringify(await getAPIImageData(data.photoInfo.pun))); + Stats.postEvent('background', 'image', 'api'); + } +}; + +export const handleColourBackgroundType = (setState) => { + let customBackgroundColour = localStorage.getItem('customBackgroundColour'); + if (customBackgroundColour && customBackgroundColour.startsWith('{')) { + const customBackground = JSON.parse(customBackgroundColour); + try { + localStorage.setItem('customBackgroundColour', customBackground.gradient[0].colour); + customBackgroundColour = customBackground.gradient.colour; + } catch (e) { + customBackgroundColour = 'rgb(0,0,0)'; + } + } + setState({ + type: 'colour', + style: customBackgroundColour || 'rgb(0,0,0)', + }); + Stats.postEvent('background', 'colour', 'custom'); +}; + +export const handleRandomColourBackgroundType = (type, setState) => { + const randomStyle = randomColourStyleBuilder(type); + setState({ + type: 'colour', + style: randomStyle, + }); + Stats.postEvent('background', 'colour', 'random'); +}; + +export const handleCustomBackgroundType = async (offline, setState) => { + let customBackground = []; + const customSaved = localStorage.getItem('customBackground') || defaults.customBackground; + try { + customBackground = JSON.parse(customSaved); + } catch (e) { + if (customSaved !== '') { + customBackground = [customSaved]; + } + localStorage.setItem('customBackground', JSON.stringify(customBackground)); + } + customBackground = customBackground[Math.floor(Math.random() * customBackground.length)]; + if (offline && !customBackground.startsWith('data:')) { + setState(getOfflineImage('custom')); + Stats.postEvent('background', 'image', 'offline'); + return; + } + if (customBackground) { + const object = { + url: customBackground, + type: 'custom', + video: videoCheck(customBackground), + photoInfo: { + hidden: true, + }, + }; + setState(object); + localStorage.setItem('currentBackground', JSON.stringify(object)); + Stats.postEvent('background', 'image', 'custom'); + } +}; + +export const handlePhotoPackBackgroundType = async (offline, setState) => { + if (offline) { + setState(getOfflineImage('photo')); + Stats.postEvent('background', 'image', 'offline'); + return; + } + const photoPack = []; + const installed = JSON.parse(localStorage.getItem('installed')); + installed.forEach((item) => { + if (item.type === 'photos') { + const photos = item.photos.map((photo) => photo); + photoPack.push(...photos); + } + }); + if (photoPack.length === 0) { + setState(getOfflineImage('photo')); + Stats.postEvent('background', 'image', 'offline'); + return; + } + const photo = photoPack[Math.floor(Math.random() * photoPack.length)]; + setState({ + url: photo.url.default, + type: 'photo_pack', + video: videoCheck(photo.url.default), + photoInfo: { + photographer: photo.photographer, + }, + }); + Stats.postEvent('background', 'image', 'photo_pack'); +}; + +export const handleBackgroundVisibility = (state, element) => { + if (localStorage.getItem('background') === 'false') { + if (state.photoInfo.hidden === false) { + document.querySelector('.photoInformation').style.display = 'none'; + } + if (state.video === true) { + document.getElementById('backgroundVideo').style.display = 'none'; + } else { + element.style.display = 'none'; + } + return; + } + if (state.video === true) { + document.getElementById('backgroundVideo').style.display = 'block'; + } else { + if (state.photoInfo.hidden === false) { + try { + document.querySelector('.photoInformation').style.display = 'flex'; + } catch (e) { + // Disregard exception + } + } + element.style.display = 'block'; + } +}; + +export const handleBackgroundEffectEvent = (state) => { + const element = document.getElementById('backgroundImage'); + const backgroundFilterSetting = + localStorage.getItem('backgroundFilter') || defaults.backgroundFilter; + const backgroundFilter = backgroundFilterSetting && backgroundFilterSetting !== 'none'; + const filterValue = `blur(${localStorage.getItem('blur')}px) brightness(${localStorage.getItem('brightness')}%) ${ + backgroundFilter + ? backgroundFilterSetting + '(' + localStorage.getItem('backgroundFilterAmount') + '%)' + : '' + }`; + if (state.video === true) { + document.getElementById('backgroundVideo').style.filter = filterValue; + } else { + element.style.filter = filterValue; + } +}; diff --git a/src/features/background/api/backgroundTypeHandlers.js b/src/features/background/api/backgroundTypeHandlers.js new file mode 100644 index 00000000..f21f3641 --- /dev/null +++ b/src/features/background/api/backgroundTypeHandlers.js @@ -0,0 +1,61 @@ +import { + handleAPIBackground, + handleColourBackground, + handleCustomBackground, + handleDefaultBackground, + handleAPIBackgroundType, + handleColourBackgroundType, + handleRandomColourBackgroundType, + handleCustomBackgroundType, + handlePhotoPackBackgroundType, +} from './backgroundHelpers'; + +export const handleBackgroundType = async (type, offline, getAPIImageData, setState) => { + switch (type) { + case 'api': + await handleAPIBackgroundType(offline, getAPIImageData, setState); + break; + case 'colour': + handleColourBackgroundType(setState); + break; + case 'random_colour': + case 'random_gradient': + handleRandomColourBackgroundType(type, setState); + break; + case 'custom': + await handleCustomBackgroundType(offline, setState); + break; + case 'photo_pack': + await handlePhotoPackBackgroundType(offline, setState); + break; + default: + break; + } +}; + +export const applyBackground = async (backgroundState, elements) => { + const { backgroundImage, blurhashOverlay, backgroundImageActual, photoInformation } = elements; + + switch (backgroundState.type) { + case 'api': + await handleAPIBackground( + backgroundState, + backgroundImage, + blurhashOverlay, + backgroundImageActual, + photoInformation, + ); + break; + case 'colour': + case 'random_colour': + case 'random_gradient': + handleColourBackground(backgroundState, backgroundImage); + break; + case 'custom': + case 'photo_pack': + handleCustomBackground(backgroundState, backgroundImage, photoInformation); + break; + default: + handleDefaultBackground(backgroundState, backgroundImage); + } +}; diff --git a/src/features/background/api/useBackgroundAPI.js b/src/features/background/api/useBackgroundAPI.js new file mode 100644 index 00000000..de6c5e5c --- /dev/null +++ b/src/features/background/api/useBackgroundAPI.js @@ -0,0 +1,45 @@ +import { useCallback } from 'react'; +import { getRequestURL, formatAPIData } from './backgroundHelpers'; +import { getOfflineImage } from './getOfflineImage'; +import { supportsAVIF } from './avif'; +import defaults from '../options/default'; +import Stats from 'features/stats/api/stats'; + +const useBackgroundAPI = (setBackgroundState) => { + const getAPIImageData = useCallback( + async (currentPun) => { + let apiCategories; + try { + apiCategories = JSON.parse(localStorage.getItem('apiCategories')); + } catch (error) { + apiCategories = localStorage.getItem('apiCategories'); + } + + const backgroundAPI = localStorage.getItem('backgroundAPI') || defaults.backgroundAPI; + const apiQuality = localStorage.getItem('apiQuality') || defaults.apiQuality; + let backgroundExclude = JSON.parse(localStorage.getItem('backgroundExclude')) || []; + + if (currentPun) { + backgroundExclude.push(currentPun); + } + + const requestURL = getRequestURL(backgroundAPI, apiCategories, apiQuality, backgroundExclude); + const accept = `application/json, ${supportsAVIF() ? 'image/avif' : 'image/webp'}`; + + try { + const response = await fetch(requestURL, { headers: { accept } }); + const data = await response.json(); + return formatAPIData(data, backgroundAPI); + } catch (e) { + setBackgroundState(getOfflineImage('api')); + Stats.postEvent('background', 'image', 'offline'); + return null; + } + }, + [setBackgroundState], + ); + + return { getAPIImageData }; +}; + +export default useBackgroundAPI;