mirror of
https://github.com/mue/mue.git
synced 2026-07-04 13:42:11 +02:00
refactor(background): Further code readaability improvements
This commit is contained in:
@@ -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 <BackgroundVideo url={state.url} />;
|
||||
if (backgroundState.video === true) {
|
||||
return <BackgroundVideo url={backgroundState.url} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<BackgroundImage />
|
||||
{state.photoInfo && state.photoInfo.credit && (
|
||||
<PhotoInformation info={state.photoInfo} api={state.currentAPI} url={state.url} />
|
||||
{backgroundState.photoInfo && backgroundState.photoInfo.credit && (
|
||||
<PhotoInformation
|
||||
info={backgroundState.photoInfo}
|
||||
api={backgroundState.currentAPI}
|
||||
url={backgroundState.url}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
262
src/features/background/api/backgroundHelpers.js
Normal file
262
src/features/background/api/backgroundHelpers.js
Normal file
@@ -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;
|
||||
}
|
||||
};
|
||||
61
src/features/background/api/backgroundTypeHandlers.js
Normal file
61
src/features/background/api/backgroundTypeHandlers.js
Normal file
@@ -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);
|
||||
}
|
||||
};
|
||||
45
src/features/background/api/useBackgroundAPI.js
Normal file
45
src/features/background/api/useBackgroundAPI.js
Normal file
@@ -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;
|
||||
Reference in New Issue
Block a user