refactor(28-02): simplify VU helpers to use external store
- Remove useState from useVuHelpers (no React state for VU data) - Remove updateVuState, removeVuState, updateVU3 functions - Remove VuMeterComponent (replaced by direct DOM in SessionTrackVU) - Expose vuStore methods via return object - VuContext provides vuStore reference to consumers - Keep legacy renderVU/updateVU for backward compatibility Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
96d8f97175
commit
f8214854d9
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext } from 'react';
|
||||||
|
import { vuStore } from '../stores/vuStore';
|
||||||
import useVuHelpers from '../hooks/useVuHelpers.js';
|
import useVuHelpers from '../hooks/useVuHelpers.js';
|
||||||
|
|
||||||
const VuContext = createContext();
|
const VuContext = createContext();
|
||||||
|
|
@ -6,8 +7,14 @@ const VuContext = createContext();
|
||||||
export const VuProvider = ({ children }) => {
|
export const VuProvider = ({ children }) => {
|
||||||
const vuHelpers = useVuHelpers();
|
const vuHelpers = useVuHelpers();
|
||||||
|
|
||||||
|
// Combine vuHelpers with vuStore for context value
|
||||||
|
const value = {
|
||||||
|
...vuHelpers,
|
||||||
|
vuStore,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VuContext.Provider value={vuHelpers}>
|
<VuContext.Provider value={value}>
|
||||||
{children}
|
{children}
|
||||||
</VuContext.Provider>
|
</VuContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
|
import { vuStore } from '../stores/vuStore';
|
||||||
|
|
||||||
const logger = console;
|
const logger = console;
|
||||||
|
|
||||||
export default function useVuHelpers() {
|
export default function useVuHelpers() {
|
||||||
const [vuStates, setVuStates] = useState({});
|
|
||||||
|
|
||||||
const createQualifiedId = useCallback(mixer => {
|
const createQualifiedId = useCallback(mixer => {
|
||||||
return (mixer.mode ? 'M' : 'P') + mixer.id;
|
return (mixer.mode ? 'M' : 'P') + mixer.id;
|
||||||
|
|
@ -93,103 +93,15 @@ export default function useVuHelpers() {
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// New React-like VU update function
|
|
||||||
const updateVuState = useCallback((mixerId, level, clipping = false) => {
|
|
||||||
setVuStates(prev => ({
|
|
||||||
...prev,
|
|
||||||
[mixerId]: { level, clipping }
|
|
||||||
}));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const removeVuState = useCallback((mixerId) => {
|
|
||||||
setVuStates(prev => {
|
|
||||||
const newState = { ...prev };
|
|
||||||
delete newState[mixerId];
|
|
||||||
return newState;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const updateVU3 = useCallback(
|
|
||||||
(mixer, leftValue, leftClipping, rightValue, rightClipping) => {
|
|
||||||
const fqId = createQualifiedId(mixer);
|
|
||||||
//logger.debug('useVuHelpers: updateVU3', { fqId, mixer, leftValue, rightValue });
|
|
||||||
|
|
||||||
// Update React state for declarative rendering
|
|
||||||
updateVuState(fqId, leftValue, leftClipping);
|
|
||||||
},
|
|
||||||
[createQualifiedId, updateVuState]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
|
||||||
// Cleanup on unmount
|
|
||||||
setVuStates({});
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Create a proper React component that can be used outside the hook
|
|
||||||
function VuMeterComponent({ mixerId, orientation = 'vertical', lightCount = 16, lightWidth = 15, lightHeight = 10 }) {
|
|
||||||
const vuState = vuStates[mixerId] || { level: 0, clipping: false };
|
|
||||||
const { level, clipping } = vuState;
|
|
||||||
|
|
||||||
const lights = [];
|
|
||||||
for (let i = 0; i < lightCount; i++) {
|
|
||||||
// Calculate if this light should be on based on the level
|
|
||||||
const lightThreshold = (lightCount - i) / lightCount;
|
|
||||||
const isOn = level >= lightThreshold;
|
|
||||||
|
|
||||||
let bgClass = 'vu-bg-secondary'; // Default off state
|
|
||||||
if (isOn) {
|
|
||||||
if (clipping) {
|
|
||||||
bgClass = 'vu-bg-danger'; // Red for clipping
|
|
||||||
} else {
|
|
||||||
const positionFromBottom = lightCount - 1 - i;
|
|
||||||
if (positionFromBottom >= Math.floor(lightCount * 0.75)) { // Red zone (top 25%)
|
|
||||||
bgClass = 'vu-bg-danger';
|
|
||||||
} else if (positionFromBottom >= Math.floor(lightCount * 0.5)) { // Yellow zone (middle 25%)
|
|
||||||
bgClass = 'vu-bg-warning';
|
|
||||||
} else { // Green zone (bottom 50%)
|
|
||||||
bgClass = 'vu-bg-success';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lights.push(
|
|
||||||
<div
|
|
||||||
key={i}
|
|
||||||
className={bgClass}
|
|
||||||
style={{
|
|
||||||
height: `${lightHeight}px`,
|
|
||||||
width: `25px`,
|
|
||||||
marginTop: '1px',
|
|
||||||
borderRadius: '2px',
|
|
||||||
border: '1px solid #eee'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='vu'>
|
|
||||||
<div className="d-flex flex-column" style={{ height: `${lightCount * (lightHeight + 1)}px` }}>
|
|
||||||
{lights}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// React-like components and functions
|
// External store methods (new)
|
||||||
VuMeter: VuMeterComponent,
|
updateVuState: vuStore.updateLevel,
|
||||||
updateVuState,
|
removeVuState: vuStore.removeLevel,
|
||||||
removeVuState,
|
vuStore, // Expose full store for advanced usage
|
||||||
vuStates,
|
|
||||||
|
|
||||||
// Legacy functions for backward compatibility
|
// Legacy functions for backward compatibility
|
||||||
|
createQualifiedId,
|
||||||
renderVU,
|
renderVU,
|
||||||
updateVU,
|
updateVU,
|
||||||
updateVU3
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue