fix: address remaining PR #519 review comments

- Preserve existing preamp when importing files without Preamp line
- Extend import regex to accept k/kHz/Hz suffixes and +signed gains
- Rename localStorage key to monochrome- prefix for backup/restore compat
- Add try/catch to localStorage writes for quota/disabled storage
- Validate custom preset gains array before applying
- Fix delete button visibility for all preset change paths
- Add overflow-x: auto for mobile EQ band scrolling
- Add flex-wrap and responsive sizing for bottom controls on mobile
This commit is contained in:
tryptz 2026-04-06 22:52:07 +00:00 committed by edideaur
parent 452b810efd
commit cb49904a21
2 changed files with 78 additions and 35 deletions

View file

@ -1422,27 +1422,35 @@ export async function initializeSettings(scrobbler, player, api, ui) {
try {
const text = event.target.result;
const lines = text.split('\n');
let preamp = 0;
let preamp = geqPreamp;
let hasPreamp = false;
const importedPoints = [];
for (const line of lines) {
const preampMatch = line.match(/Preamp:\s*([-\d.]+)\s*dB/i);
if (preampMatch) {
preamp = parseFloat(preampMatch[1]);
hasPreamp = true;
continue;
}
// EqualizerAPO format: Filter N: ON PK Fc XXXX Hz Gain X.X dB Q X.XX
const filterMatch = line.match(
/Filter\s+\d+:\s*ON\s+\w+\s+Fc\s+([\d.]+)\s*Hz\s+Gain\s+([-\d.]+)\s*dB/i
/Filter\s+\d+:\s*ON\s+\w+\s+Fc\s+([\d.]+[kK]?)\s*(?:Hz)?\s+Gain\s+([+-]?[\d.]+)\s*dB/i
);
if (filterMatch) {
importedPoints.push({ freq: parseFloat(filterMatch[1]), gain: parseFloat(filterMatch[2]) });
importedPoints.push({
freq: parseGeqLabelFrequency(filterMatch[1]),
gain: parseFloat(filterMatch[2]),
});
continue;
}
// Simple two-column format: freq gain (whitespace/tab/comma separated)
const simpleMatch = line.trim().match(/^([\d.]+)[,\s\t]+([-\d.]+)/);
const simpleMatch = line.trim().match(/^([\d.]+[kK]?)\s*(?:Hz|kHz)?\s*[,\s\t]+([+-]?[\d.]+)/);
if (simpleMatch) {
importedPoints.push({ freq: parseFloat(simpleMatch[1]), gain: parseFloat(simpleMatch[2]) });
importedPoints.push({
freq: parseGeqLabelFrequency(simpleMatch[1]),
gain: parseFloat(simpleMatch[2]),
});
}
}
@ -1474,14 +1482,16 @@ export async function initializeSettings(scrobbler, player, api, ui) {
});
geqGains = newGains;
geqPreamp = Math.max(-20, Math.min(20, preamp));
equalizerSettings.setGraphicEqGains(geqGains);
equalizerSettings.setGraphicEqPreamp(geqPreamp);
audioContextManager.setGraphicEqAllGains(geqGains);
audioContextManager.setGraphicEqPreamp(geqPreamp);
geqSyncAllSliders();
geqPreampSliders.forEach((s) => (s.value = geqPreamp));
geqPreampValues.forEach((v) => (v.textContent = `${geqPreamp.toFixed(1)} dB`));
if (hasPreamp) {
geqPreamp = Math.max(-20, Math.min(20, preamp));
equalizerSettings.setGraphicEqPreamp(geqPreamp);
audioContextManager.setGraphicEqPreamp(geqPreamp);
geqPreampSliders.forEach((s) => (s.value = geqPreamp));
geqPreampValues.forEach((v) => (v.textContent = `${geqPreamp.toFixed(1)} dB`));
}
geqPresetSelects.forEach((s) => {
s.value = '';
s.dispatchEvent(new Event('change'));
@ -1496,7 +1506,17 @@ export async function initializeSettings(scrobbler, player, api, ui) {
}
// Legacy EQ Custom Presets (Save / Delete)
const LEGACY_GEQ_CUSTOM_PRESETS_KEY = 'legacy-geq-custom-presets';
const LEGACY_GEQ_CUSTOM_PRESETS_KEY = 'monochrome-legacy-geq-custom-presets';
// Migrate from old key if present
try {
const oldData = localStorage.getItem('legacy-geq-custom-presets');
if (oldData && !localStorage.getItem(LEGACY_GEQ_CUSTOM_PRESETS_KEY)) {
localStorage.setItem(LEGACY_GEQ_CUSTOM_PRESETS_KEY, oldData);
localStorage.removeItem('legacy-geq-custom-presets');
}
} catch {
/* ignore */
}
const legacyGeqSavePresetBtn = document.getElementById('legacy-geq-save-preset-btn');
const legacyGeqDeletePresetBtn = document.getElementById('legacy-geq-delete-preset-btn');
@ -1510,7 +1530,12 @@ export async function initializeSettings(scrobbler, player, api, ui) {
};
const saveLegacyGeqCustomPresets = (presets) => {
localStorage.setItem(LEGACY_GEQ_CUSTOM_PRESETS_KEY, JSON.stringify(presets));
try {
localStorage.setItem(LEGACY_GEQ_CUSTOM_PRESETS_KEY, JSON.stringify(presets));
} catch (e) {
console.error('[Legacy GEQ] Failed to save presets:', e);
alert('Failed to save preset. Storage may be full.');
}
};
/** Rebuild custom preset options in all legacy GEQ preset dropdowns */
@ -1555,31 +1580,37 @@ export async function initializeSettings(scrobbler, player, api, ui) {
geqPresetSelects.forEach((select) => {
select.addEventListener('change', () => {
const key = select.value;
if (!key) {
updateDeleteBtnVisibility();
return;
}
// Check custom presets first
const customPresets = getLegacyGeqCustomPresets();
if (customPresets[key]) {
geqGains = [...customPresets[key].gains];
equalizerSettings.setGraphicEqGains(geqGains);
audioContextManager.setGraphicEqAllGains(geqGains);
geqSyncAllSliders();
if (customPresets[key].preamp !== undefined) {
geqPreamp = customPresets[key].preamp;
equalizerSettings.setGraphicEqPreamp(geqPreamp);
audioContextManager.setGraphicEqPreamp(geqPreamp);
geqPreampSliders.forEach((s) => (s.value = geqPreamp));
geqPreampValues.forEach((v) => (v.textContent = `${geqPreamp.toFixed(1)} dB`));
if (key) {
// Check custom presets first
const customPresets = getLegacyGeqCustomPresets();
if (customPresets[key]) {
const gains = customPresets[key]?.gains;
if (!Array.isArray(gains) || gains.length !== GEQ_FREQUENCIES.length) {
updateDeleteBtnVisibility();
return;
}
geqGains = gains.map((g) => {
const n = Number(g);
return Number.isFinite(n)
? Math.max(parseFloat(geqRange.min), Math.min(parseFloat(geqRange.max), n))
: 0;
});
equalizerSettings.setGraphicEqGains(geqGains);
audioContextManager.setGraphicEqAllGains(geqGains);
geqSyncAllSliders();
if (customPresets[key].preamp !== undefined) {
geqPreamp = customPresets[key].preamp;
equalizerSettings.setGraphicEqPreamp(geqPreamp);
audioContextManager.setGraphicEqPreamp(geqPreamp);
geqPreampSliders.forEach((s) => (s.value = geqPreamp));
geqPreampValues.forEach((v) => (v.textContent = `${geqPreamp.toFixed(1)} dB`));
}
geqPresetSelects.forEach((s) => {
if (s !== select) s.value = key;
});
}
geqPresetSelects.forEach((s) => {
if (s !== select) s.value = key;
});
updateDeleteBtnVisibility();
return;
}
updateDeleteBtnVisibility();
});
});

View file

@ -7934,6 +7934,8 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
background: rgb(0, 0, 0, 0.15);
border-radius: var(--radius);
min-height: 240px;
overflow-x: auto;
overscroll-behavior-x: contain;
}
.graphic-eq-band {
@ -7986,6 +7988,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
display: flex;
align-items: center;
gap: var(--spacing-md);
flex-wrap: wrap;
}
.graphic-eq-preamp {
@ -8033,6 +8036,15 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
.graphic-eq-band-value {
font-size: 0.5rem;
}
.graphic-eq-bottom-row {
gap: var(--spacing-sm);
}
.graphic-eq-preamp {
min-width: 0;
flex-basis: 100%;
}
}
/* ========================================