mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 03:34:40 +00:00
implement vanilla js SettingsState class to optimise code and clean up source :DDD
This commit is contained in:
+8
-6
@@ -12,7 +12,7 @@ import { MessageHandler } from './seqta/utils/listeners/MessageListener'
|
||||
import { SettingsState } from "./types/storage"
|
||||
import ShortcutLinks from './seqta/content/links.json'
|
||||
import Sortable from 'sortablejs'
|
||||
import StorageListener from './seqta/utils/listeners/StorageListener'
|
||||
//import StorageListener from './seqta/utils/listeners/StorageChanges'
|
||||
import { appendBackgroundToUI } from './seqta/ui/ImageBackgrounds'
|
||||
import assessmentsicon from './seqta/icons/assessmentsIcon'
|
||||
import browser from 'webextension-polyfill'
|
||||
@@ -28,6 +28,8 @@ import { SettingsResizer } from "./seqta/ui/SettingsResizer";
|
||||
import documentLoadCSS from './css/documentload.scss?inline'
|
||||
import injectedCSS from './css/injected.scss?inline'
|
||||
import { injectYouTubeVideo } from './seqta/ui/VideoLoader'
|
||||
import { settingsState } from './seqta/utils/listeners/SettingsState'
|
||||
import { StorageChangeHandler } from './seqta/utils/listeners/StorageChanges'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@@ -788,7 +790,7 @@ function main(storedSetting: SettingsState) {
|
||||
|
||||
document.querySelector('.legacy-root')?.classList.add('hidden')
|
||||
|
||||
new StorageListener()
|
||||
new StorageChangeHandler();
|
||||
new MessageHandler()
|
||||
|
||||
updateAllColors(storedSetting)
|
||||
@@ -1379,13 +1381,13 @@ async function AddBetterSEQTAElements(toggle: any) {
|
||||
result.then(resolve, onError)
|
||||
})
|
||||
|
||||
const newDarkMode = !result!.DarkMode
|
||||
browser.storage.local.set({ DarkMode: newDarkMode })
|
||||
console.log(!settingsState.DarkMode)
|
||||
settingsState.DarkMode = !settingsState.DarkMode;
|
||||
|
||||
updateAllColors(newDarkMode, result.selectedColor)
|
||||
updateAllColors(!settingsState.DarkMode, result.selectedColor)
|
||||
|
||||
const darklightText = document.getElementById('darklighttooliptext')
|
||||
darklightText!.innerText = GetLightDarkModeString(newDarkMode)
|
||||
darklightText!.innerText = GetLightDarkModeString(!settingsState.DarkMode)
|
||||
})
|
||||
|
||||
// Locate the menuToggle element
|
||||
|
||||
@@ -2,7 +2,7 @@ import browser from 'webextension-polyfill'
|
||||
import { GetThresholdOfColor } from '../../../SEQTA';
|
||||
import { lightenAndPaleColor } from './lightenAndPaleColor';
|
||||
import ColorLuminance from './ColorLuminance';
|
||||
import { SettingsState } from '../../../types/storage';
|
||||
import { settingsState } from '../../utils/listeners/SettingsState';
|
||||
|
||||
import icon48 from '../../../resources/icons/icon-48.png';
|
||||
|
||||
@@ -14,7 +14,6 @@ const setCSSVar = (varName: any, value: any) => document.documentElement.style.s
|
||||
const getChromeURL = (path: any) => browser.runtime.getURL(path);
|
||||
const applyProperties = (props: any) => Object.entries(props).forEach(([key, value]) => setCSSVar(key, value));
|
||||
|
||||
let DarkMode: any = null;
|
||||
|
||||
export function updateAllColors(storedSetting: any, newColor = null) {
|
||||
// Determine the color to use
|
||||
@@ -24,30 +23,24 @@ export function updateAllColors(storedSetting: any, newColor = null) {
|
||||
document.documentElement.classList.add('transparencyEffects');
|
||||
}
|
||||
|
||||
DarkMode = (typeof storedSetting?.DarkMode === 'boolean') ? storedSetting.DarkMode : DarkMode;
|
||||
|
||||
if (typeof storedSetting === 'boolean') {
|
||||
DarkMode = storedSetting;
|
||||
}
|
||||
|
||||
// Common properties, always applied
|
||||
const commonProps = {
|
||||
'--better-sub': '#161616',
|
||||
'--better-alert-highlight': '#c61851',
|
||||
'--better-main': selectedColor
|
||||
'--better-main': settingsState.selectedColor
|
||||
};
|
||||
|
||||
// Mode-based properties, applied if storedSetting is provided
|
||||
let modeProps = {};
|
||||
if (DarkMode !== null) {
|
||||
modeProps = DarkMode ? {
|
||||
if (settingsState.DarkMode) {
|
||||
modeProps = settingsState.DarkMode ? {
|
||||
'--betterseqta-logo': `url(${browser.runtime.getURL(darkLogo)})`
|
||||
} : {
|
||||
'--better-pale': lightenAndPaleColor(selectedColor),
|
||||
'--betterseqta-logo': `url(${browser.runtime.getURL(lightLogo)})`
|
||||
};
|
||||
|
||||
if (DarkMode) {
|
||||
if (settingsState.DarkMode) {
|
||||
document.documentElement.style.removeProperty('--better-pale');
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
@@ -67,7 +60,7 @@ export function updateAllColors(storedSetting: any, newColor = null) {
|
||||
applyProperties({ ...commonProps, ...modeProps, ...dynamicProps });
|
||||
|
||||
// Set favicon, if storedSetting is provided
|
||||
if (DarkMode !== null) {
|
||||
if (settingsState.DarkMode !== null) {
|
||||
(document.querySelector('link[rel*=\'icon\']')! as HTMLLinkElement).href = getChromeURL(icon48);
|
||||
}
|
||||
|
||||
@@ -80,19 +73,10 @@ export function updateAllColors(storedSetting: any, newColor = null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DarkMode) {
|
||||
if (settingsState.DarkMode) {
|
||||
element.contentDocument?.body.classList.add('dark');
|
||||
} else {
|
||||
element.contentDocument?.body.classList.remove('dark');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getDarkMode() {
|
||||
try {
|
||||
const result = await browser.storage.local.get() as SettingsState;
|
||||
return result.DarkMode;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import browser from 'webextension-polyfill';
|
||||
import { SettingsState } from '../../../types/storage';
|
||||
|
||||
type ChangeListener = (newValue: any, oldValue: any) => void;
|
||||
|
||||
class StorageManager {
|
||||
private static instance: StorageManager;
|
||||
private data: SettingsState;
|
||||
private listeners: { [key: string]: ChangeListener[] };
|
||||
|
||||
private constructor() {
|
||||
this.data = {} as SettingsState;
|
||||
this.listeners = {};
|
||||
this.loadFromStorage();
|
||||
|
||||
const handler: ProxyHandler<StorageManager> = {
|
||||
get: (target, prop: keyof SettingsState | 'register') => {
|
||||
if (prop in target) {
|
||||
return (target as any)[prop];
|
||||
}
|
||||
return Reflect.get(target.data, prop);
|
||||
},
|
||||
set: (target, prop: keyof SettingsState, value) => {
|
||||
Reflect.set(target.data, prop, value);
|
||||
target.saveToStorage();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
this.initStorageListener();
|
||||
|
||||
return new Proxy(this, handler) as StorageManager & SettingsState;
|
||||
}
|
||||
|
||||
public static getInstance(): StorageManager & SettingsState {
|
||||
if (!StorageManager.instance) {
|
||||
StorageManager.instance = new StorageManager();
|
||||
}
|
||||
return StorageManager.instance as StorageManager & SettingsState;
|
||||
}
|
||||
|
||||
private async loadFromStorage(): Promise<void> {
|
||||
const result = await browser.storage.local.get();
|
||||
this.data = { ...this.data, ...result };
|
||||
}
|
||||
|
||||
private async saveToStorage(): Promise<void> {
|
||||
await browser.storage.local.set(this.data);
|
||||
}
|
||||
|
||||
private initStorageListener(): void {
|
||||
browser.storage.onChanged.addListener((changes, areaName) => {
|
||||
if (areaName === 'local') {
|
||||
for (const [key, { oldValue, newValue }] of Object.entries(changes)) {
|
||||
if (newValue !== undefined) {
|
||||
(this.data as any)[key] = newValue;
|
||||
} else {
|
||||
delete (this.data as any)[key];
|
||||
}
|
||||
if (this.listeners[key]) {
|
||||
for (const listener of this.listeners[key]) {
|
||||
listener(newValue, oldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public register(prop: keyof SettingsState, listener: ChangeListener): void {
|
||||
if (!this.listeners[prop]) {
|
||||
this.listeners[prop] = [];
|
||||
}
|
||||
this.listeners[prop].push(listener);
|
||||
}
|
||||
}
|
||||
|
||||
export const settingsState = StorageManager.getInstance();
|
||||
@@ -0,0 +1,115 @@
|
||||
import { settingsState } from './SettingsState';
|
||||
import { updateAllColors } from '../../ui/colors/Manager';
|
||||
import {
|
||||
CreateBackground,
|
||||
CreateCustomShortcutDiv,
|
||||
RemoveBackground,
|
||||
RemoveShortcutDiv,
|
||||
addShortcuts,
|
||||
disableNotificationCollector,
|
||||
enableNotificationCollector,
|
||||
} from '../../../SEQTA';
|
||||
import { updateBgDurations } from '../../ui/Animation';
|
||||
import browser from 'webextension-polyfill';
|
||||
|
||||
export class StorageChangeHandler {
|
||||
constructor() {
|
||||
this.registerHandlers();
|
||||
}
|
||||
|
||||
private registerHandlers() {
|
||||
console.log(settingsState.onoff);
|
||||
settingsState.register('selectedColor', this.handleSelectedColorChange.bind(this));
|
||||
settingsState.register('onoff', this.handleOnOffChange.bind(this));
|
||||
settingsState.register('shortcuts', this.handleShortcutsChange.bind(this));
|
||||
settingsState.register('customshortcuts', this.handleCustomShortcutsChange.bind(this));
|
||||
settingsState.register('notificationcollector', this.handleNotificationCollectorChange.bind(this));
|
||||
settingsState.register('bksliderinput', this.handleBksliderInputChange.bind(this));
|
||||
settingsState.register('animatedbk', this.handleAnimatedBkChange.bind(this));
|
||||
settingsState.register('transparencyEffects', this.handleTransparencyEffectsChange.bind(this));
|
||||
}
|
||||
|
||||
private handleSelectedColorChange(newColor: any) {
|
||||
try {
|
||||
updateAllColors(newColor);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
private handleOnOffChange() {
|
||||
browser.runtime.sendMessage({ type: 'reloadTabs' });
|
||||
}
|
||||
|
||||
private handleNotificationCollectorChange(newValue: any) {
|
||||
if (newValue) {
|
||||
enableNotificationCollector();
|
||||
} else {
|
||||
disableNotificationCollector();
|
||||
}
|
||||
}
|
||||
|
||||
private handleCustomShortcutsChange(oldValue: any, newValue: any) {
|
||||
if (newValue) {
|
||||
if (newValue.length > oldValue.length) {
|
||||
CreateCustomShortcutDiv(newValue[oldValue.length]);
|
||||
} else if (newValue.length < oldValue.length) {
|
||||
const removedElement = oldValue.find(
|
||||
(oldItem: any) => !newValue.some((newItem: any) => JSON.stringify(oldItem) === JSON.stringify(newItem))
|
||||
);
|
||||
|
||||
if (removedElement) {
|
||||
RemoveShortcutDiv([removedElement]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private handleShortcutsChange(oldValue: any, newValue: any) {
|
||||
const addedShortcuts = newValue.filter((newItem: any) => {
|
||||
const isAdded = oldValue.some((oldItem: any) => {
|
||||
const match = oldItem.name === newItem.name;
|
||||
const wasDisabled = !oldItem.enabled;
|
||||
const isEnabled = newItem.enabled;
|
||||
return match && wasDisabled && isEnabled;
|
||||
});
|
||||
|
||||
return isAdded;
|
||||
});
|
||||
|
||||
const removedShortcuts = newValue.filter((newItem: any) => {
|
||||
const isRemoved = oldValue.some((oldItem: any) => {
|
||||
const match = oldItem.name === newItem.name;
|
||||
const wasEnabled = oldItem.enabled;
|
||||
const isDisabled = !newItem.enabled;
|
||||
return match && wasEnabled && isDisabled;
|
||||
});
|
||||
|
||||
return isRemoved;
|
||||
});
|
||||
|
||||
addShortcuts(addedShortcuts);
|
||||
RemoveShortcutDiv(removedShortcuts);
|
||||
}
|
||||
|
||||
private handleBksliderInputChange(newValue: any) {
|
||||
updateBgDurations(newValue);
|
||||
}
|
||||
|
||||
private handleAnimatedBkChange(newValue: boolean) {
|
||||
if (newValue) {
|
||||
CreateBackground();
|
||||
} else {
|
||||
RemoveBackground();
|
||||
document.getElementById('container')!.style.background = 'var(--background-secondary)';
|
||||
}
|
||||
}
|
||||
|
||||
private handleTransparencyEffectsChange(newValue: boolean) {
|
||||
if (newValue) {
|
||||
document.documentElement.classList.add('transparencyEffects');
|
||||
} else {
|
||||
document.documentElement.classList.remove('transparencyEffects');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
import browser from 'webextension-polyfill'
|
||||
|
||||
import {
|
||||
CreateBackground,
|
||||
CreateCustomShortcutDiv,
|
||||
RemoveBackground,
|
||||
RemoveShortcutDiv,
|
||||
addShortcuts,
|
||||
disableNotificationCollector,
|
||||
enableNotificationCollector,
|
||||
} from '../../../SEQTA';
|
||||
import { updateBgDurations } from '../../ui/Animation';
|
||||
import { getDarkMode, updateAllColors } from '../../ui/colors/Manager';
|
||||
|
||||
|
||||
export default class StorageListener {
|
||||
darkMode: any;
|
||||
constructor() {
|
||||
this.darkMode = getDarkMode();
|
||||
browser.storage.onChanged.addListener(this.handleStorageChanges.bind(this));
|
||||
}
|
||||
|
||||
handleStorageChanges(changes: any) {
|
||||
Object.keys(changes).forEach((changeKey) => {
|
||||
switch (changeKey) {
|
||||
|
||||
case 'selectedColor':
|
||||
this.handleSelectedColorChange(changes.selectedColor.newValue);
|
||||
break;
|
||||
|
||||
case 'onoff':
|
||||
this.handleOnOffChange();
|
||||
break;
|
||||
|
||||
case 'shortcuts':
|
||||
this.handleShortcutsChange(
|
||||
changes.shortcuts.oldValue,
|
||||
changes.shortcuts.newValue
|
||||
);
|
||||
break;
|
||||
|
||||
case 'DarkMode':
|
||||
this.darkMode = changes.DarkMode.newValue;
|
||||
break;
|
||||
|
||||
case 'customshortcuts':
|
||||
if (changes.customshortcuts.newValue) {
|
||||
this.handleCustomShortcutsChange(
|
||||
changes.customshortcuts.oldValue,
|
||||
changes.customshortcuts.newValue
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'notificationcollector':
|
||||
this.handleNotificationCollectorChange(changes.notificationcollector);
|
||||
break;
|
||||
|
||||
case 'bksliderinput':
|
||||
updateBgDurations(changes.bksliderinput.newValue);
|
||||
break;
|
||||
|
||||
case 'animatedbk':
|
||||
if (changes.animatedbk.newValue) {
|
||||
CreateBackground();
|
||||
} else {
|
||||
RemoveBackground();
|
||||
document.getElementById('container')!.style.background = 'var(--background-secondary)';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'transparencyEffects':
|
||||
if (changes.transparencyEffects.newValue) {
|
||||
document.documentElement.classList.add('transparencyEffects');
|
||||
} else {
|
||||
document.documentElement.classList.remove('transparencyEffects');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'theme':
|
||||
console.debug(changes.theme.newValue)
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleSelectedColorChange(newColor: any) {
|
||||
try {
|
||||
updateAllColors(this.darkMode, newColor);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
handleOnOffChange() {
|
||||
browser.runtime.sendMessage({ type: 'reloadTabs' })
|
||||
}
|
||||
|
||||
handleNotificationCollectorChange(details: any) {
|
||||
if (details.newValue) {
|
||||
enableNotificationCollector();
|
||||
} else {
|
||||
disableNotificationCollector();
|
||||
}
|
||||
}
|
||||
|
||||
handleCustomShortcutsChange(oldValue: any, newValue: any) {
|
||||
// Check for addition
|
||||
if (newValue.length > oldValue.length) {
|
||||
CreateCustomShortcutDiv(newValue[oldValue.length]);
|
||||
}
|
||||
// Check for removal
|
||||
else if (newValue.length < oldValue.length) {
|
||||
const removedElement = oldValue.find(
|
||||
(oldItem: any) =>
|
||||
!newValue.some(
|
||||
(newItem: any) => JSON.stringify(oldItem) === JSON.stringify(newItem)
|
||||
)
|
||||
);
|
||||
|
||||
if (removedElement) {
|
||||
RemoveShortcutDiv([ removedElement ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleShortcutsChange(oldValue: any, newValue: any) {
|
||||
// Find Added Shortcuts
|
||||
const addedShortcuts = newValue.filter((newItem: any) => {
|
||||
const isAdded = oldValue.some((oldItem: any) => {
|
||||
const match = oldItem.name === newItem.name;
|
||||
const wasDisabled = !oldItem.enabled;
|
||||
const isEnabled = newItem.enabled;
|
||||
return match && wasDisabled && isEnabled;
|
||||
});
|
||||
|
||||
return isAdded;
|
||||
});
|
||||
|
||||
// Find Removed Shortcuts
|
||||
const removedShortcuts = newValue.filter((newItem: any) => {
|
||||
const isRemoved = oldValue.some((oldItem: any) => {
|
||||
const match = oldItem.name === newItem.name;
|
||||
const wasEnabled = oldItem.enabled; // Was enabled in the old array
|
||||
const isDisabled = !newItem.enabled; // Is disabled in the new array
|
||||
|
||||
return match && wasEnabled && isDisabled;
|
||||
});
|
||||
|
||||
return isRemoved;
|
||||
});
|
||||
|
||||
// Add new shortcuts to the UI
|
||||
addShortcuts(addedShortcuts);
|
||||
|
||||
// Remove deleted shortcuts from the UI
|
||||
RemoveShortcutDiv(removedShortcuts);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user