mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-17 06:00:20 +02:00
refactor butterchurn state to prevent rerender flicker on cycle
This commit is contained in:
@@ -5,7 +5,12 @@ import styles from './visualizer.module.css';
|
|||||||
import { useWebAudio } from '/@/renderer/features/player/hooks/use-webaudio';
|
import { useWebAudio } from '/@/renderer/features/player/hooks/use-webaudio';
|
||||||
import { openVisualizerSettingsModal } from '/@/renderer/features/player/utils/open-visualizer-settings-modal';
|
import { openVisualizerSettingsModal } from '/@/renderer/features/player/utils/open-visualizer-settings-modal';
|
||||||
import { ComponentErrorBoundary } from '/@/renderer/features/shared/components/component-error-boundary';
|
import { ComponentErrorBoundary } from '/@/renderer/features/shared/components/component-error-boundary';
|
||||||
import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store';
|
import {
|
||||||
|
subscribeButterchurnPreset,
|
||||||
|
useButterchurnSettings,
|
||||||
|
useSettingsStore,
|
||||||
|
useSettingsStoreActions,
|
||||||
|
} from '/@/renderer/store';
|
||||||
import {
|
import {
|
||||||
useFullScreenPlayerStore,
|
useFullScreenPlayerStore,
|
||||||
useFullScreenPlayerStoreActions,
|
useFullScreenPlayerStoreActions,
|
||||||
@@ -39,7 +44,7 @@ const VisualizerInner = () => {
|
|||||||
const cycleStartTimeRef = useRef<number | undefined>(undefined);
|
const cycleStartTimeRef = useRef<number | undefined>(undefined);
|
||||||
const pauseTimerRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
const pauseTimerRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||||
const initialPresetLoadedRef = useRef(false);
|
const initialPresetLoadedRef = useRef(false);
|
||||||
const butterchurnSettings = useSettingsStore((store) => store.visualizer.butterchurn);
|
const butterchurnSettings = useButterchurnSettings();
|
||||||
const opacity = useSettingsStore((store) => store.visualizer.butterchurn.opacity);
|
const opacity = useSettingsStore((store) => store.visualizer.butterchurn.opacity);
|
||||||
const { setSettings } = useSettingsStoreActions();
|
const { setSettings } = useSettingsStoreActions();
|
||||||
const playerStatus = usePlayerStatus();
|
const playerStatus = usePlayerStatus();
|
||||||
@@ -249,10 +254,9 @@ const VisualizerInner = () => {
|
|||||||
const presetNames = Object.keys(presets);
|
const presetNames = Object.keys(presets);
|
||||||
|
|
||||||
if (presetNames.length > 0) {
|
if (presetNames.length > 0) {
|
||||||
|
const currentPreset = useSettingsStore.getState().visualizer.butterchurn.currentPreset;
|
||||||
const presetName =
|
const presetName =
|
||||||
butterchurnSettings.currentPreset && presets[butterchurnSettings.currentPreset]
|
currentPreset && presets[currentPreset] ? currentPreset : presetNames[0];
|
||||||
? butterchurnSettings.currentPreset
|
|
||||||
: presetNames[0];
|
|
||||||
const preset = presets[presetName];
|
const preset = presets[presetName];
|
||||||
|
|
||||||
if (preset) {
|
if (preset) {
|
||||||
@@ -261,53 +265,14 @@ const VisualizerInner = () => {
|
|||||||
initialPresetLoadedRef.current = true;
|
initialPresetLoadedRef.current = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [isVisualizerReady, butterchurnSettings.blendTime, librariesLoaded]);
|
||||||
isVisualizerReady,
|
|
||||||
butterchurnSettings.currentPreset,
|
|
||||||
butterchurnSettings.blendTime,
|
|
||||||
librariesLoaded,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Update preset when currentPreset or blendTime changes (but not when cycling)
|
|
||||||
const isCyclingRef = useRef(false);
|
const isCyclingRef = useRef(false);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const visualizer = visualizerRef.current;
|
|
||||||
if (
|
|
||||||
!visualizer ||
|
|
||||||
!butterchurnSettings.currentPreset ||
|
|
||||||
!initialPresetLoadedRef.current ||
|
|
||||||
!librariesLoaded
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Skip if we're currently cycling (to avoid reloading preset)
|
|
||||||
if (isCyclingRef.current) {
|
|
||||||
isCyclingRef.current = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const presets = butterchurnPresetsRef.current;
|
|
||||||
if (!presets) return;
|
|
||||||
const preset = presets[butterchurnSettings.currentPreset];
|
|
||||||
|
|
||||||
if (preset) {
|
|
||||||
visualizer.loadPreset(preset, butterchurnSettings.blendTime || 0.0);
|
|
||||||
// Reset cycle timer when preset changes manually
|
|
||||||
cycleStartTimeRef.current = Date.now();
|
|
||||||
}
|
|
||||||
}, [butterchurnSettings.currentPreset, butterchurnSettings.blendTime, librariesLoaded]);
|
|
||||||
|
|
||||||
// Handle preset cycling
|
// Handle preset cycling
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const visualizer = visualizerRef.current;
|
const visualizer = visualizerRef.current;
|
||||||
if (
|
if (!visualizer || !butterchurnSettings.cyclePresets || !librariesLoaded) {
|
||||||
!visualizer ||
|
|
||||||
!butterchurnSettings.cyclePresets ||
|
|
||||||
!initialPresetLoadedRef.current ||
|
|
||||||
!librariesLoaded
|
|
||||||
) {
|
|
||||||
// Clear cycle timer if cycling is disabled or visualizer not ready
|
|
||||||
if (cycleTimerRef.current) {
|
if (cycleTimerRef.current) {
|
||||||
clearInterval(cycleTimerRef.current);
|
clearInterval(cycleTimerRef.current);
|
||||||
cycleTimerRef.current = undefined;
|
cycleTimerRef.current = undefined;
|
||||||
@@ -316,6 +281,7 @@ const VisualizerInner = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const presets = butterchurnPresetsRef.current;
|
const presets = butterchurnPresetsRef.current;
|
||||||
|
|
||||||
if (!presets) return;
|
if (!presets) return;
|
||||||
const allPresetNames = Object.keys(presets);
|
const allPresetNames = Object.keys(presets);
|
||||||
|
|
||||||
@@ -342,7 +308,8 @@ const VisualizerInner = () => {
|
|||||||
const currentVisualizer = visualizerRef.current;
|
const currentVisualizer = visualizerRef.current;
|
||||||
if (!currentVisualizer) return;
|
if (!currentVisualizer) return;
|
||||||
|
|
||||||
const currentPresetName = butterchurnSettings.currentPreset;
|
const currentPresetName =
|
||||||
|
useSettingsStore.getState().visualizer.butterchurn.currentPreset;
|
||||||
let nextPresetName: string;
|
let nextPresetName: string;
|
||||||
|
|
||||||
if (butterchurnSettings.randomizeNextPreset) {
|
if (butterchurnSettings.randomizeNextPreset) {
|
||||||
@@ -365,16 +332,12 @@ const VisualizerInner = () => {
|
|||||||
|
|
||||||
const nextPreset = presets[nextPresetName];
|
const nextPreset = presets[nextPresetName];
|
||||||
if (nextPreset) {
|
if (nextPreset) {
|
||||||
// Get current settings to ensure we use the latest blendTime
|
|
||||||
const currentSettings = useSettingsStore.getState().visualizer.butterchurn;
|
const currentSettings = useSettingsStore.getState().visualizer.butterchurn;
|
||||||
|
|
||||||
// Mark that we're cycling to prevent the preset change effect from running
|
|
||||||
isCyclingRef.current = true;
|
isCyclingRef.current = true;
|
||||||
|
|
||||||
// Load the preset with blending
|
|
||||||
currentVisualizer.loadPreset(nextPreset, currentSettings.blendTime || 0.0);
|
currentVisualizer.loadPreset(nextPreset, currentSettings.blendTime || 0.0);
|
||||||
|
|
||||||
// Update currentPreset in settings
|
|
||||||
setSettings({
|
setSettings({
|
||||||
visualizer: {
|
visualizer: {
|
||||||
butterchurn: {
|
butterchurn: {
|
||||||
@@ -387,7 +350,6 @@ const VisualizerInner = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check every second if it's time to cycle
|
|
||||||
cycleTimerRef.current = setInterval(() => {
|
cycleTimerRef.current = setInterval(() => {
|
||||||
if (cycleStartTimeRef.current === undefined) {
|
if (cycleStartTimeRef.current === undefined) {
|
||||||
cycleStartTimeRef.current = Date.now();
|
cycleStartTimeRef.current = Date.now();
|
||||||
@@ -413,7 +375,6 @@ const VisualizerInner = () => {
|
|||||||
butterchurnSettings.selectedPresets,
|
butterchurnSettings.selectedPresets,
|
||||||
butterchurnSettings.ignoredPresets,
|
butterchurnSettings.ignoredPresets,
|
||||||
butterchurnSettings.randomizeNextPreset,
|
butterchurnSettings.randomizeNextPreset,
|
||||||
butterchurnSettings.currentPreset,
|
|
||||||
setSettings,
|
setSettings,
|
||||||
librariesLoaded,
|
librariesLoaded,
|
||||||
]);
|
]);
|
||||||
@@ -453,8 +414,40 @@ const VisualizerInner = () => {
|
|||||||
};
|
};
|
||||||
}, [isVisualizerReady, butterchurnSettings.maxFPS]);
|
}, [isVisualizerReady, butterchurnSettings.maxFPS]);
|
||||||
|
|
||||||
// Render container when playing (for initialization) or when visualizer exists
|
// Handle preset changes via subscriber
|
||||||
// Canvas must always be rendered when container is rendered so refs are available
|
useEffect(() => {
|
||||||
|
const unsubscribe = subscribeButterchurnPreset((presetName) => {
|
||||||
|
const visualizer = visualizerRef.current;
|
||||||
|
if (
|
||||||
|
!visualizer ||
|
||||||
|
!isVisualizerReady ||
|
||||||
|
!librariesLoaded ||
|
||||||
|
!presetName ||
|
||||||
|
!initialPresetLoadedRef.current
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCyclingRef.current) {
|
||||||
|
isCyclingRef.current = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const presets = butterchurnPresetsRef.current;
|
||||||
|
if (!presets) return;
|
||||||
|
|
||||||
|
const preset = presets[presetName];
|
||||||
|
if (preset && typeof preset === 'object') {
|
||||||
|
visualizer.loadPreset(preset, butterchurnSettings.blendTime || 0.0);
|
||||||
|
cycleStartTimeRef.current = Date.now();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribe();
|
||||||
|
};
|
||||||
|
}, [isVisualizerReady, librariesLoaded, butterchurnSettings.blendTime]);
|
||||||
|
|
||||||
const shouldRenderContainer = isPlaying || isVisualizerReady;
|
const shouldRenderContainer = isPlaying || isVisualizerReady;
|
||||||
|
|
||||||
if (!shouldRenderContainer) {
|
if (!shouldRenderContainer) {
|
||||||
@@ -468,20 +461,25 @@ const VisualizerInner = () => {
|
|||||||
style={{ opacity: isVisualizerReady ? opacity : 0 }}
|
style={{ opacity: isVisualizerReady ? opacity : 0 }}
|
||||||
>
|
>
|
||||||
<canvas className={styles.canvas} ref={canvasRef} />
|
<canvas className={styles.canvas} ref={canvasRef} />
|
||||||
{isVisualizerReady && butterchurnSettings.currentPreset && (
|
{isVisualizerReady && <CurrentPresetDisplay />}
|
||||||
<Text className={styles['preset-overlay']} isNoSelect size="sm">
|
|
||||||
{butterchurnSettings.currentPreset}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CurrentPresetDisplay = () => {
|
||||||
|
const currentPreset = useSettingsStore.getState().visualizer.butterchurn.currentPreset;
|
||||||
|
return (
|
||||||
|
<Text className={styles['preset-overlay']} isNoSelect size="sm">
|
||||||
|
{currentPreset}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const Visualizer = () => {
|
export const Visualizer = () => {
|
||||||
const { visualizerExpanded } = useFullScreenPlayerStore();
|
const { visualizerExpanded } = useFullScreenPlayerStore();
|
||||||
const { setStore } = useFullScreenPlayerStoreActions();
|
const { setStore } = useFullScreenPlayerStoreActions();
|
||||||
const { setSettings } = useSettingsStoreActions();
|
const { setSettings } = useSettingsStoreActions();
|
||||||
const butterchurnSettings = useSettingsStore((store) => store.visualizer.butterchurn);
|
const butterchurnSettings = useButterchurnSettings();
|
||||||
const [presetsLoaded, setPresetsLoaded] = useState(false);
|
const [presetsLoaded, setPresetsLoaded] = useState(false);
|
||||||
const butterchurnPresetsRef = useRef<any>(null);
|
const butterchurnPresetsRef = useRef<any>(null);
|
||||||
|
|
||||||
@@ -542,7 +540,7 @@ export const Visualizer = () => {
|
|||||||
const presetList = getPresetList();
|
const presetList = getPresetList();
|
||||||
if (presetList.length === 0) return;
|
if (presetList.length === 0) return;
|
||||||
|
|
||||||
const currentPresetName = butterchurnSettings.currentPreset;
|
const currentPresetName = useSettingsStore.getState().visualizer.butterchurn.currentPreset;
|
||||||
const currentIndex = currentPresetName ? presetList.indexOf(currentPresetName) : -1;
|
const currentIndex = currentPresetName ? presetList.indexOf(currentPresetName) : -1;
|
||||||
const nextIndex =
|
const nextIndex =
|
||||||
currentIndex >= 0 && currentIndex < presetList.length - 1 ? currentIndex + 1 : 0;
|
currentIndex >= 0 && currentIndex < presetList.length - 1 ? currentIndex + 1 : 0;
|
||||||
@@ -563,7 +561,7 @@ export const Visualizer = () => {
|
|||||||
const presetList = getPresetList();
|
const presetList = getPresetList();
|
||||||
if (presetList.length === 0) return;
|
if (presetList.length === 0) return;
|
||||||
|
|
||||||
const currentPresetName = butterchurnSettings.currentPreset;
|
const currentPresetName = useSettingsStore.getState().visualizer.butterchurn.currentPreset;
|
||||||
const currentIndex = currentPresetName ? presetList.indexOf(currentPresetName) : -1;
|
const currentIndex = currentPresetName ? presetList.indexOf(currentPresetName) : -1;
|
||||||
const prevIndex = currentIndex > 0 ? currentIndex - 1 : presetList.length - 1;
|
const prevIndex = currentIndex > 0 ? currentIndex - 1 : presetList.length - 1;
|
||||||
const prevPresetName = presetList[prevIndex];
|
const prevPresetName = presetList[prevIndex];
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import mergeWith from 'lodash/mergeWith';
|
|||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import { generatePath } from 'react-router';
|
import { generatePath } from 'react-router';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { devtools, persist } from 'zustand/middleware';
|
import { devtools, persist, subscribeWithSelector } from 'zustand/middleware';
|
||||||
import { immer } from 'zustand/middleware/immer';
|
import { immer } from 'zustand/middleware/immer';
|
||||||
import { shallow } from 'zustand/shallow';
|
import { shallow } from 'zustand/shallow';
|
||||||
import { createWithEqualityFn } from 'zustand/traditional';
|
import { createWithEqualityFn } from 'zustand/traditional';
|
||||||
@@ -1631,98 +1631,102 @@ const initialState: SettingsState = {
|
|||||||
export const useSettingsStore = createWithEqualityFn<SettingsSlice>()(
|
export const useSettingsStore = createWithEqualityFn<SettingsSlice>()(
|
||||||
persist(
|
persist(
|
||||||
devtools(
|
devtools(
|
||||||
immer((set) => ({
|
subscribeWithSelector(
|
||||||
actions: {
|
immer((set) => ({
|
||||||
reset: () => {
|
actions: {
|
||||||
localStorage.removeItem('store_settings');
|
reset: () => {
|
||||||
window.location.reload();
|
localStorage.removeItem('store_settings');
|
||||||
},
|
window.location.reload();
|
||||||
resetSampleRate: () => {
|
},
|
||||||
set((state) => {
|
resetSampleRate: () => {
|
||||||
state.playback.mpvProperties.audioSampleRateHz = 0;
|
set((state) => {
|
||||||
});
|
state.playback.mpvProperties.audioSampleRateHz = 0;
|
||||||
},
|
});
|
||||||
setArtistItems: (items) => {
|
},
|
||||||
set((state) => {
|
setArtistItems: (items) => {
|
||||||
state.general.artistItems = items;
|
set((state) => {
|
||||||
});
|
state.general.artistItems = items;
|
||||||
},
|
});
|
||||||
setArtistReleaseTypeItems: (items: SortableItem<ArtistReleaseTypeItem>[]) => {
|
},
|
||||||
set((state) => {
|
setArtistReleaseTypeItems: (
|
||||||
state.general.artistReleaseTypeItems = items;
|
items: SortableItem<ArtistReleaseTypeItem>[],
|
||||||
});
|
) => {
|
||||||
},
|
set((state) => {
|
||||||
setGenreBehavior: (target: GenreTarget) => {
|
state.general.artistReleaseTypeItems = items;
|
||||||
set((state) => {
|
});
|
||||||
state.general.genreTarget = target;
|
},
|
||||||
});
|
setGenreBehavior: (target: GenreTarget) => {
|
||||||
},
|
set((state) => {
|
||||||
setHomeItems: (items: SortableItem<HomeItem>[]) => {
|
state.general.genreTarget = target;
|
||||||
set((state) => {
|
});
|
||||||
state.general.homeItems = items;
|
},
|
||||||
});
|
setHomeItems: (items: SortableItem<HomeItem>[]) => {
|
||||||
},
|
set((state) => {
|
||||||
setList: (type: ItemListKey, data: DeepPartial<ItemListSettings>) => {
|
state.general.homeItems = items;
|
||||||
set((state) => {
|
});
|
||||||
const listState = state.lists[type];
|
},
|
||||||
|
setList: (type: ItemListKey, data: DeepPartial<ItemListSettings>) => {
|
||||||
|
set((state) => {
|
||||||
|
const listState = state.lists[type];
|
||||||
|
|
||||||
if (listState && data.table) {
|
if (listState && data.table) {
|
||||||
Object.assign(listState.table, data.table);
|
Object.assign(listState.table, data.table);
|
||||||
delete data.table;
|
delete data.table;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listState && data.grid) {
|
if (listState && data.grid) {
|
||||||
Object.assign(listState.grid, data.grid);
|
Object.assign(listState.grid, data.grid);
|
||||||
delete data.grid;
|
delete data.grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listState) {
|
if (listState) {
|
||||||
Object.assign(listState, data);
|
Object.assign(listState, data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
setPlaybackFilters: (filters: PlayerFilter[]) => {
|
||||||
|
set((state) => {
|
||||||
|
state.playback.filters = filters;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setSettings: (data) => {
|
||||||
|
set((state) => {
|
||||||
|
deepMergeIntoState(state, data);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setSidebarItems: (items: SidebarItemType[]) => {
|
||||||
|
set((state) => {
|
||||||
|
state.general.sidebarItems = items;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setTable: (type: ItemListKey, data: DataTableProps) => {
|
||||||
|
set((state) => {
|
||||||
|
const listState = state.lists[type];
|
||||||
|
if (listState) {
|
||||||
|
listState.table = data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setTranscodingConfig: (config) => {
|
||||||
|
set((state) => {
|
||||||
|
state.playback.transcode = config;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
toggleMediaSession: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.playback.mediaSession = !state.playback.mediaSession;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
toggleSidebarCollapseShare: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.general.sidebarCollapseShared =
|
||||||
|
!state.general.sidebarCollapseShared;
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setPlaybackFilters: (filters: PlayerFilter[]) => {
|
...initialState,
|
||||||
set((state) => {
|
})),
|
||||||
state.playback.filters = filters;
|
),
|
||||||
});
|
|
||||||
},
|
|
||||||
setSettings: (data) => {
|
|
||||||
set((state) => {
|
|
||||||
deepMergeIntoState(state, data);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setSidebarItems: (items: SidebarItemType[]) => {
|
|
||||||
set((state) => {
|
|
||||||
state.general.sidebarItems = items;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setTable: (type: ItemListKey, data: DataTableProps) => {
|
|
||||||
set((state) => {
|
|
||||||
const listState = state.lists[type];
|
|
||||||
if (listState) {
|
|
||||||
listState.table = data;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setTranscodingConfig: (config) => {
|
|
||||||
set((state) => {
|
|
||||||
state.playback.transcode = config;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
toggleMediaSession: () => {
|
|
||||||
set((state) => {
|
|
||||||
state.playback.mediaSession = !state.playback.mediaSession;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
toggleSidebarCollapseShare: () => {
|
|
||||||
set((state) => {
|
|
||||||
state.general.sidebarCollapseShared =
|
|
||||||
!state.general.sidebarCollapseShared;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
...initialState,
|
|
||||||
})),
|
|
||||||
{ name: 'store_settings' },
|
{ name: 'store_settings' },
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
@@ -2175,3 +2179,30 @@ export const useShowVisualizerInSidebar = () =>
|
|||||||
export const useAutoDJSettings = () => useSettingsStore((store) => store.autoDJ, shallow);
|
export const useAutoDJSettings = () => useSettingsStore((store) => store.autoDJ, shallow);
|
||||||
|
|
||||||
export const useVisualizerSettings = () => useSettingsStore((store) => store.visualizer, shallow);
|
export const useVisualizerSettings = () => useSettingsStore((store) => store.visualizer, shallow);
|
||||||
|
|
||||||
|
export const subscribeButterchurnPreset = (
|
||||||
|
onChange: (preset: string | undefined, prevPreset: string | undefined) => void,
|
||||||
|
) => {
|
||||||
|
return useSettingsStore.subscribe(
|
||||||
|
(state) => state.visualizer.butterchurn.currentPreset,
|
||||||
|
(preset, prevPreset) => {
|
||||||
|
onChange(preset, prevPreset);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useButterchurnSettings = () => {
|
||||||
|
return useSettingsStore((store) => {
|
||||||
|
return {
|
||||||
|
blendTime: store.visualizer.butterchurn.blendTime,
|
||||||
|
cyclePresets: store.visualizer.butterchurn.cyclePresets,
|
||||||
|
cycleTime: store.visualizer.butterchurn.cycleTime,
|
||||||
|
ignoredPresets: store.visualizer.butterchurn.ignoredPresets,
|
||||||
|
includeAllPresets: store.visualizer.butterchurn.includeAllPresets,
|
||||||
|
maxFPS: store.visualizer.butterchurn.maxFPS,
|
||||||
|
opacity: store.visualizer.butterchurn.opacity,
|
||||||
|
randomizeNextPreset: store.visualizer.butterchurn.randomizeNextPreset,
|
||||||
|
selectedPresets: store.visualizer.butterchurn.selectedPresets,
|
||||||
|
};
|
||||||
|
}, shallow);
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user