From b1826eae002430a5b06979ba39ff6f545502e2e9 Mon Sep 17 00:00:00 2001 From: Administrator Date: Mon, 15 Jun 2026 01:03:37 +0200 Subject: [PATCH] feat(settings): move per-hoster upload settings into the Accounts tab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declutters the Einstellungen tab: the per-hoster panels (Retries, Max Speed, Parallel Uploads, Restart-below, Interval, Max Size, log-to-file) are no longer listed there. Each hoster group in the Accounts tab now has a collapsible "Upload-Einstellungen" section with exactly those controls, so everything about a hoster lives in one place. The Einstellungen tab shows a short pointer to where they moved. Per-hoster edits in Accounts save via a dedicated lightweight handler (scheduleHosterSettingsSave → saveHosterSettings) that touches only hosterSettings — it deliberately does NOT route through the global saveSettings, so tweaking a hoster slider can't re-run the folder-monitor start/stop or clobber global fields. The global saveSettings still reads .hs-input[data-hoster] wherever they live, and global inputs (which have no data-hoster) are unaffected. The new inputs drop the .settings-autosave class and bind via delegation on the persistent accounts container so they survive re-renders. Co-Authored-By: Claude Opus 4.8 (1M context) --- renderer/app.js | 170 ++++++++++++++++++++++++-------------------- renderer/styles.css | 33 +++++++++ 2 files changed, 127 insertions(+), 76 deletions(-) diff --git a/renderer/app.js b/renderer/app.js index 696133a..3596365 100644 --- a/renderer/app.js +++ b/renderer/app.js @@ -3281,81 +3281,10 @@ function renderSettings() { document.getElementById('exportBackupBtn').addEventListener('click', () => doBackupExport()); document.getElementById('importBackupBtn').addEventListener('click', () => doBackupImport()); - // --- Separator before hoster panels --- - const separator = document.createElement('div'); - separator.style.cssText = 'height:16px'; - container.appendChild(separator); - - if (configuredAccounts.length === 0) { - const empty = document.createElement('div'); - empty.className = 'settings-empty'; - empty.innerHTML = '

Noch keine Account-Einstellungen vorhanden.

Sobald du einen Account anlegst, erscheinen hier die passenden Upload-Einstellungen.'; - container.appendChild(empty); - } - - for (const { name } of configuredAccounts) { - const hs = hosterSettings[name] || {}; - const maxSpeedMbs = hs.maxSpeedKbs > 0 ? (hs.maxSpeedKbs / 1024).toFixed(2).replace(/\.00$/, '') : '0'; - - const panel = document.createElement('div'); - panel.className = 'hoster-settings-panel'; - - panel.innerHTML = ` -
- - ${escapeHtml(getHosterLabel(name))} - Aktiv -
- - `; - - container.appendChild(panel); - - // Toggle panel - panel.querySelector('.hoster-panel-header').addEventListener('click', () => { - const body = panel.querySelector('.hoster-panel-body'); - const arrow = panel.querySelector('.panel-arrow'); - const isOpen = body.style.display !== 'none'; - body.style.display = isOpen ? 'none' : 'block'; - arrow.innerHTML = isOpen ? '▶' : '▼'; - }); - } + const hosterPointer = document.createElement('div'); + hosterPointer.className = 'settings-hoster-pointer'; + hosterPointer.innerHTML = 'Die Upload-Einstellungen pro Hoster (Retries, Speed, Parallel, Max-Größe, Log) sind jetzt im Accounts-Tab — direkt bei den jeweiligen Hostern unter „Upload-Einstellungen".'; + container.appendChild(hosterPointer); document.getElementById('chooseLogFilePathBtn')?.addEventListener('click', chooseLogFilePath); document.getElementById('openLogFolderBtn')?.addEventListener('click', () => window.api.openLogFolder()); @@ -3708,6 +3637,78 @@ function _hosterGroupOpenState(name, summary) { const _hosterGroupOpenMemory = new Map(); +let _hosterSettingsSaveTimer = null; +function scheduleHosterSettingsSave() { + clearTimeout(_hosterSettingsSaveTimer); + _hosterSettingsSaveTimer = setTimeout(() => { saveHosterSettingsFromDom().catch(() => {}); }, 350); +} + +async function saveHosterSettingsFromDom() { + const newHosterSettings = { ...(config.hosterSettings || {}) }; + for (const name of HOSTERS) { + const inputs = document.querySelectorAll(`.account-hoster-settings-body .hs-input[data-hoster="${name}"]`); + if (!inputs.length) continue; + const hs = { ...(newHosterSettings[name] || {}) }; + inputs.forEach(input => { + const field = input.dataset.hs; + if (input.type === 'checkbox') hs[field] = input.checked; + else if (field === 'maxSpeedMbs') hs.maxSpeedKbs = Math.max(0, Math.round((parseFloat(input.value) || 0) * 1024)); + else hs[field] = parseInt(input.value, 10) || 0; + }); + newHosterSettings[name] = hs; + } + await window.api.saveHosterSettings(newHosterSettings); + config.hosterSettings = newHosterSettings; + hosterSettings = newHosterSettings; +} + +function _buildHosterSettingsHtml(name) { + const hs = (config.hosterSettings && config.hosterSettings[name]) || {}; + const maxSpeedMbs = hs.maxSpeedKbs > 0 ? String(+(hs.maxSpeedKbs / 1024).toFixed(2)) : '0'; + return ``; +} + function _buildAccountHosterGroupHtml(name, accounts) { const summary = _summarizeHosterGroup(accounts); const isOpen = _hosterGroupOpenState(name, summary); @@ -3734,7 +3735,7 @@ function _buildAccountHosterGroupHtml(name, accounts) { ${summary.error ? `` : ''} ${lifeMeta} - + `; } @@ -3799,6 +3800,17 @@ function bindAccountListeners(container) { } return; } + const settingsHeader = e.target.closest('[data-hoster-settings-toggle]'); + if (settingsHeader) { + const body = settingsHeader.nextElementSibling; + const arrow = settingsHeader.querySelector('.panel-arrow'); + if (body) { + const isOpen = body.style.display !== 'none'; + body.style.display = isOpen ? 'none' : ''; + if (arrow) arrow.innerHTML = isOpen ? '▶' : '▼'; + } + return; + } const btn = e.target.closest('button'); if (!btn) return; if (btn.dataset.accountToggle) return toggleAccount(btn.dataset.accountToggle); @@ -3819,6 +3831,12 @@ function bindAccountListeners(container) { } }); + const onHosterSettingInput = (e) => { + if (e.target && e.target.classList && e.target.classList.contains('hs-input')) scheduleHosterSettingsSave(); + }; + container.addEventListener('input', onHosterSettingInput); + container.addEventListener('change', onHosterSettingInput); + let draggedCard = null; container.addEventListener('dragstart', (e) => { const card = e.target.closest('.account-card[draggable]'); diff --git a/renderer/styles.css b/renderer/styles.css index e2f9af6..89c9135 100644 --- a/renderer/styles.css +++ b/renderer/styles.css @@ -1024,6 +1024,39 @@ select.hs-input { max-width: none; width: auto; min-width: 140px; } .account-card.drag-over-above { border-top: 2px solid var(--accent); } .account-card.drag-over-below { border-bottom: 2px solid var(--accent); } +.account-hoster-settings { + margin-top: 8px; + border-top: 1px solid var(--border); + padding-top: 6px; +} +.account-hoster-settings-header { + display: flex; + align-items: center; + gap: 8px; + padding: 6px 4px; + cursor: pointer; + color: var(--text-muted); + font-size: 12px; + letter-spacing: 0.02em; + text-transform: uppercase; + border-radius: 6px; + transition: background 0.1s, color 0.1s; +} +.account-hoster-settings-header:hover { background: rgba(255,255,255,0.03); color: var(--text); } +.account-hoster-settings-header .panel-arrow { font-size: 10px; color: var(--text-dim); } +.account-hoster-settings-body { padding: 6px 4px 4px; } + +.settings-hoster-pointer { + margin-top: 12px; + padding: 10px 14px; + font-size: 12px; + line-height: 1.5; + color: var(--text-muted); + background: rgba(62, 167, 255, 0.06); + border: 1px solid var(--border); + border-radius: 8px; +} + .account-priority-badge { font-size: 10px; font-weight: 500;