// Страница настроек desktop-обёртки. // // Локальная страница (tauri://localhost) внутри главного окна: команды обёртки // вызываются через встроенный IPC Tauri. Ничего, кроме настроек платформы, // здесь нет — настройки клиента живут в самом клиенте. /** Вызов команды обёртки: тонкая обёртка над IPC Tauri v2. */ const invoke = (command, args) => window.__TAURI_INTERNALS__.invoke(command, args); /** Варианты комбинаций: пустая строка — «выключено». */ const OFF = { value: '', label: 'Выключено' }; const PTT_OPTIONS = [ OFF, { value: 'CommandOrControl+Shift+Space', label: 'Cmd/Ctrl + Shift + Пробел' }, { value: 'CommandOrControl+Shift+M', label: 'Cmd/Ctrl + Shift + M' }, { value: 'CommandOrControl+Shift+V', label: 'Cmd/Ctrl + Shift + V' }, { value: 'CommandOrControl+Shift+B', label: 'Cmd/Ctrl + Shift + B' }, { value: 'Control+Shift+Space', label: 'Ctrl + Shift + Пробел' }, ]; const MUTE_OPTIONS = [ OFF, { value: 'CommandOrControl+Shift+M', label: 'Cmd/Ctrl + Shift + M' }, { value: 'CommandOrControl+Shift+U', label: 'Cmd/Ctrl + Shift + U' }, { value: 'Control+Shift+M', label: 'Ctrl + Shift + M' }, ]; const DEAFEN_OPTIONS = [ OFF, { value: 'CommandOrControl+Shift+D', label: 'Cmd/Ctrl + Shift + D' }, { value: 'CommandOrControl+Shift+F', label: 'Cmd/Ctrl + Shift + F' }, { value: 'Control+Shift+D', label: 'Ctrl + Shift + D' }, ]; /** Поля формы и соответствующие настройки. */ const fields = { instanceUrl: document.getElementById('instance-url'), autostart: document.getElementById('autostart'), closeToTray: document.getElementById('close-to-tray'), notifications: document.getElementById('notifications'), pttShortcut: document.getElementById('ptt-shortcut'), muteShortcut: document.getElementById('mute-shortcut'), deafenShortcut: document.getElementById('deafen-shortcut'), }; const status = document.getElementById('status'); const version = document.getElementById('version'); const updatesHint = document.getElementById('updates-hint'); /** Заполняет выпадающий список комбинаций. */ function fillSelect(select, options, current) { select.replaceChildren(); for (const option of options) { const node = document.createElement('option'); node.value = option.value; node.textContent = option.label; select.append(node); } // Комбинация могла быть задана вручную (например, прежней версией) — не теряем её. if (current && !options.some((option) => option.value === current)) { const node = document.createElement('option'); node.value = current; node.textContent = current; select.append(node); } select.value = current ?? ''; } /** Показывает состояние сохранения. */ function setStatus(text, isError = false) { status.textContent = text; status.classList.toggle('error', isError); } /** Переносит настройки в форму. */ function render(settings) { fields.instanceUrl.value = settings.instanceUrl ?? ''; fields.autostart.checked = Boolean(settings.autostart); fields.closeToTray.checked = Boolean(settings.closeToTray); fields.notifications.checked = Boolean(settings.notifications); fillSelect(fields.pttShortcut, PTT_OPTIONS, settings.pttShortcut); fillSelect(fields.muteShortcut, MUTE_OPTIONS, settings.muteShortcut); fillSelect(fields.deafenShortcut, DEAFEN_OPTIONS, settings.deafenShortcut); } /** Собирает настройки из формы. */ function collect() { return { instanceUrl: fields.instanceUrl.value.trim(), autostart: fields.autostart.checked, closeToTray: fields.closeToTray.checked, notifications: fields.notifications.checked, pttShortcut: fields.pttShortcut.value, muteShortcut: fields.muteShortcut.value, deafenShortcut: fields.deafenShortcut.value, }; } /** Сохраняет настройки и, если нужно, открывает клиент. */ async function save({ openClient = false } = {}) { setStatus('Сохраняем…'); try { const saved = await invoke('desktop_save_settings', { settings: collect() }); render(saved); setStatus('Сохранено'); if (openClient) { await invoke('desktop_open_instance'); } } catch (error) { setStatus(String(error), true); } } document.getElementById('save').addEventListener('click', () => { void save(); }); document.getElementById('open-client').addEventListener('click', () => { void save({ openClient: true }); }); document.getElementById('reload-client').addEventListener('click', async () => { await save(); try { await invoke('desktop_reload'); } catch (error) { setStatus(String(error), true); } }); document.getElementById('check-updates').addEventListener('click', async () => { updatesHint.textContent = 'Проверяем обновления…'; try { await invoke('desktop_check_updates'); updatesHint.textContent = 'Проверка завершена: результат показан в системном диалоге.'; } catch (error) { updatesHint.textContent = String(error); } }); // Автосохранение переключателей и списков: отдельная кнопка нужна только для адреса. for (const node of [ fields.autostart, fields.closeToTray, fields.notifications, fields.pttShortcut, fields.muteShortcut, fields.deafenShortcut, ]) { node.addEventListener('change', () => { void save(); }); } async function start() { try { render(await invoke('desktop_settings')); version.textContent = `Версия обёртки: ${await invoke('desktop_version')}`; } catch (error) { setStatus(`Не удалось прочитать настройки: ${error}`, true); } } void start();