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 { try {
const text = event.target.result; const text = event.target.result;
const lines = text.split('\n'); const lines = text.split('\n');
let preamp = 0; let preamp = geqPreamp;
let hasPreamp = false;
const importedPoints = []; const importedPoints = [];
for (const line of lines) { for (const line of lines) {
const preampMatch = line.match(/Preamp:\s*([-\d.]+)\s*dB/i); const preampMatch = line.match(/Preamp:\s*([-\d.]+)\s*dB/i);
if (preampMatch) { if (preampMatch) {
preamp = parseFloat(preampMatch[1]); preamp = parseFloat(preampMatch[1]);
hasPreamp = true;
continue; continue;
} }
// EqualizerAPO format: Filter N: ON PK Fc XXXX Hz Gain X.X dB Q X.XX // EqualizerAPO format: Filter N: ON PK Fc XXXX Hz Gain X.X dB Q X.XX
const filterMatch = line.match( 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) { if (filterMatch) {
importedPoints.push({ freq: parseFloat(filterMatch[1]), gain: parseFloat(filterMatch[2]) }); importedPoints.push({
freq: parseGeqLabelFrequency(filterMatch[1]),
gain: parseFloat(filterMatch[2]),
});
continue; continue;
} }
// Simple two-column format: freq gain (whitespace/tab/comma separated) // 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) { 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; geqGains = newGains;
geqPreamp = Math.max(-20, Math.min(20, preamp));
equalizerSettings.setGraphicEqGains(geqGains); equalizerSettings.setGraphicEqGains(geqGains);
equalizerSettings.setGraphicEqPreamp(geqPreamp);
audioContextManager.setGraphicEqAllGains(geqGains); audioContextManager.setGraphicEqAllGains(geqGains);
audioContextManager.setGraphicEqPreamp(geqPreamp);
geqSyncAllSliders(); geqSyncAllSliders();
geqPreampSliders.forEach((s) => (s.value = geqPreamp)); if (hasPreamp) {
geqPreampValues.forEach((v) => (v.textContent = `${geqPreamp.toFixed(1)} dB`)); 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) => { geqPresetSelects.forEach((s) => {
s.value = ''; s.value = '';
s.dispatchEvent(new Event('change')); s.dispatchEvent(new Event('change'));
@ -1496,7 +1506,17 @@ export async function initializeSettings(scrobbler, player, api, ui) {
} }
// Legacy EQ Custom Presets (Save / Delete) // 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 legacyGeqSavePresetBtn = document.getElementById('legacy-geq-save-preset-btn');
const legacyGeqDeletePresetBtn = document.getElementById('legacy-geq-delete-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) => { 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 */ /** 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) => { geqPresetSelects.forEach((select) => {
select.addEventListener('change', () => { select.addEventListener('change', () => {
const key = select.value; const key = select.value;
if (!key) { if (key) {
updateDeleteBtnVisibility(); // Check custom presets first
return; const customPresets = getLegacyGeqCustomPresets();
} if (customPresets[key]) {
const gains = customPresets[key]?.gains;
// Check custom presets first if (!Array.isArray(gains) || gains.length !== GEQ_FREQUENCIES.length) {
const customPresets = getLegacyGeqCustomPresets(); updateDeleteBtnVisibility();
if (customPresets[key]) { return;
geqGains = [...customPresets[key].gains]; }
equalizerSettings.setGraphicEqGains(geqGains); geqGains = gains.map((g) => {
audioContextManager.setGraphicEqAllGains(geqGains); const n = Number(g);
geqSyncAllSliders(); return Number.isFinite(n)
if (customPresets[key].preamp !== undefined) { ? Math.max(parseFloat(geqRange.min), Math.min(parseFloat(geqRange.max), n))
geqPreamp = customPresets[key].preamp; : 0;
equalizerSettings.setGraphicEqPreamp(geqPreamp); });
audioContextManager.setGraphicEqPreamp(geqPreamp); equalizerSettings.setGraphicEqGains(geqGains);
geqPreampSliders.forEach((s) => (s.value = geqPreamp)); audioContextManager.setGraphicEqAllGains(geqGains);
geqPreampValues.forEach((v) => (v.textContent = `${geqPreamp.toFixed(1)} dB`)); 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); background: rgb(0, 0, 0, 0.15);
border-radius: var(--radius); border-radius: var(--radius);
min-height: 240px; min-height: 240px;
overflow-x: auto;
overscroll-behavior-x: contain;
} }
.graphic-eq-band { .graphic-eq-band {
@ -7986,6 +7988,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--spacing-md); gap: var(--spacing-md);
flex-wrap: wrap;
} }
.graphic-eq-preamp { .graphic-eq-preamp {
@ -8033,6 +8036,15 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
.graphic-eq-band-value { .graphic-eq-band-value {
font-size: 0.5rem; font-size: 0.5rem;
} }
.graphic-eq-bottom-row {
gap: var(--spacing-sm);
}
.graphic-eq-preamp {
min-width: 0;
flex-basis: 100%;
}
} }
/* ======================================== /* ========================================