Windows: одна кнопка автозапуска и версия 0.6.2
На Windows в настройках было две похожие кнопки: автозапуск службы обхода и автозапуск самого приложения (задача планировщика). Теперь это одна кнопка «Запускать вместе с Windows»: при загрузке поднимается служба, а SenBoost открывается свёрнутым в трей, без окна. Задача планировщика больше не переключается отдельно — followZapretAutoStart ставит и снимает её вслед за автозапуском службы (без лишнего UAC: приложение и так работает с правами администратора). На macOS и Linux ничего не меняется.
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
import { app } from 'electron'
|
||||
import type { ZapretStatus } from '../shared/ipc-contract'
|
||||
import * as linux from './app-autostart.linux'
|
||||
import * as win32 from './app-autostart.win32'
|
||||
import { isTrayActive } from './tray'
|
||||
import { onZapretStatusChanged, zapretStatus } from './zapret'
|
||||
|
||||
/**
|
||||
* Автозапуск САМОГО приложения вместе с системой — не путать с автозапуском обхода
|
||||
@@ -8,6 +11,9 @@ import * as win32 from './app-autostart.win32'
|
||||
* приложения, а этот открывает приложение свёрнутым в трей, чтобы обход можно было включить
|
||||
* и выключить одним кликом.
|
||||
*
|
||||
* На Windows отдельного переключателя у него нет — он следует за автозапуском службы
|
||||
* (см. `followZapretAutoStart`), в настройках одна кнопка «Запускать вместе с Windows».
|
||||
*
|
||||
* Источник истины — сама система (реестр/планировщик, SMAppService, каталог автозапуска),
|
||||
* в settings.json ничего не дублируем: после переустановки системы или приложения
|
||||
* сохранённое значение всё равно разошлось бы с реальностью.
|
||||
@@ -43,6 +49,43 @@ export async function setAppAutoStart(enabled: boolean): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Windows: служба обхода стартует при загрузке — значит, и приложение должно подняться
|
||||
* при входе, свёрнутым в трей, чтобы обход было чем выключить. Две кнопки для этого путали:
|
||||
* обе назывались «запускать вместе с Windows», а по отдельности смысла почти не имели.
|
||||
*
|
||||
* Задача планировщика существует ровно тогда, когда служба установлена и стоит на `Auto`.
|
||||
* Приложение и так работает с правами администратора, так что лишнего UAC это не добавляет —
|
||||
* пользователь видит один запрос, на смену типа запуска службы. Подписка на статус, а не
|
||||
* вызов из IPC: обход включают и из меню трея, и первое включение ставит службу уже с `Auto`.
|
||||
*
|
||||
* Вызывать после `recoverZapret()` — до него статус ещё не знает о службе.
|
||||
*/
|
||||
export function followZapretAutoStart(): void {
|
||||
if (process.platform !== 'win32') return
|
||||
|
||||
let applied: boolean | null = null
|
||||
let queue = Promise.resolve()
|
||||
|
||||
const sync = (status: ZapretStatus): void => {
|
||||
const wanted = status.serviceInstalled && status.autoStart && isTrayActive()
|
||||
if (wanted === applied) return
|
||||
applied = wanted
|
||||
queue = queue
|
||||
.then(async () => {
|
||||
if ((await win32.isAppAutoStartEnabled()) !== wanted) await win32.setAppAutoStart(wanted)
|
||||
})
|
||||
.catch((error) => {
|
||||
// Главное — служба, она уже настроена. Без задачи обход всё равно поднимется при
|
||||
// загрузке, просто без значка в трее; в dev-режиме сюда попадаем всегда (нет прав).
|
||||
console.warn('[autostart] не удалось синхронизировать задачу планировщика:', error)
|
||||
})
|
||||
}
|
||||
|
||||
onZapretStatusChanged(sync)
|
||||
sync(zapretStatus())
|
||||
}
|
||||
|
||||
/**
|
||||
* Запуск пришёл из автозапуска — окно показывать не нужно, приложение садится в трей.
|
||||
*
|
||||
|
||||
@@ -13,6 +13,9 @@ const TASK_NAME = 'SenBoost Autostart'
|
||||
* (`app.setLoginItemSettings`): exe собран с `requestedExecutionLevel: requireAdministrator`
|
||||
* (см. electron-builder.yml), а UAC при входе в систему не спрашивают — приложение из ключа
|
||||
* реестра просто не запустилось бы. Задача с `/RL HIGHEST` поднимает его с правами сразу.
|
||||
*
|
||||
* Сама по себе из интерфейса не переключается: её ставит и снимает `followZapretAutoStart`
|
||||
* (`app-autostart.ts`) вслед за автозапуском службы обхода.
|
||||
*/
|
||||
function taskCommand(): string {
|
||||
// В dev первым аргументом electron.exe нужен каталог приложения, в сборке — нет.
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
import { app } from 'electron'
|
||||
import { electronApp, optimizer } from '@electron-toolkit/utils'
|
||||
import { shouldStartHidden } from './app-autostart'
|
||||
import { followZapretAutoStart, shouldStartHidden } from './app-autostart'
|
||||
import { beginQuit, createWindow, showMainWindow } from './window'
|
||||
import { showFirstRunSupportDialog } from './first-run'
|
||||
import { registerIpcHandlers } from './ipc'
|
||||
@@ -61,6 +61,7 @@ if (elevatedTask) {
|
||||
// На macOS чинит прокси, оставшийся от аварийно завершённого прошлого запуска,
|
||||
// до того как окно вообще откроется.
|
||||
void recoverZapret().then(() => {
|
||||
followZapretAutoStart()
|
||||
const window = createWindow({ show: !startHidden })
|
||||
// Ждём первого кадра: диалог должен появиться поверх готового окна, а не пустого.
|
||||
// Свёрнутому в трей приложению показывать модальное окно некуда — пользователь его
|
||||
|
||||
@@ -8,7 +8,8 @@ import { LIST_TITLES } from '../lib/zapretListMeta'
|
||||
import ListEditor from './ListEditor'
|
||||
|
||||
/**
|
||||
* Настройки: списки сайтов + автозапуск (macOS/Windows). Выбор стратегии и проверка
|
||||
* Настройки: списки сайтов + автозапуск (macOS/Windows; на Windows одна кнопка на службу
|
||||
* и приложение в трее). Выбор стратегии и проверка
|
||||
* соединения переехали на главный экран (ZapretCard.tsx) — рядом с кнопкой
|
||||
* включения, где ими и пользуются. Отдельный экран за шестерёнкой в шапке.
|
||||
*/
|
||||
@@ -72,33 +73,40 @@ export default function SettingsView({
|
||||
{background.settings.closeToTray ? 'Включено' : 'Выключено'}
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="settings-row"
|
||||
disabled={background.busy}
|
||||
onClick={() =>
|
||||
void background.save({ launchAtLogin: !background.settings?.launchAtLogin })
|
||||
}
|
||||
>
|
||||
<span>Запускать приложение вместе с системой</span>
|
||||
<span
|
||||
className={`chip ${background.settings.launchAtLogin ? 'chip--success' : 'chip--neutral'}`}
|
||||
{/* На Windows автозапуск приложения идёт в комплекте с автозапуском службы —
|
||||
одна кнопка ниже (см. followZapretAutoStart в main). */}
|
||||
{!isWindows && (
|
||||
<button
|
||||
type="button"
|
||||
className="settings-row"
|
||||
disabled={background.busy}
|
||||
onClick={() =>
|
||||
void background.save({ launchAtLogin: !background.settings?.launchAtLogin })
|
||||
}
|
||||
>
|
||||
{background.settings.launchAtLogin ? 'Включён' : 'Выключен'}
|
||||
</span>
|
||||
</button>
|
||||
<span>Запускать приложение вместе с системой</span>
|
||||
<span
|
||||
className={`chip ${background.settings.launchAtLogin ? 'chip--success' : 'chip--neutral'}`}
|
||||
>
|
||||
{background.settings.launchAtLogin ? 'Включён' : 'Выключен'}
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
{background.error && <p className="list-editor__error">{background.error}</p>}
|
||||
<p className="list-editor__hint">
|
||||
Приложение открывается свёрнутым в трей и обход можно включить одним кликом по значку.
|
||||
Это не то же самое, что автозапуск обхода ниже: тот работает вообще без запущенного
|
||||
приложения.
|
||||
{isWindows
|
||||
? 'Закрытое окно прячется в трей, обход продолжает работать. Включить и ' +
|
||||
'выключить его можно одним кликом по значку.'
|
||||
: 'Приложение открывается свёрнутым в трей и обход можно включить одним кликом ' +
|
||||
'по значку. Это не то же самое, что автозапуск обхода ниже: тот работает ' +
|
||||
'вообще без запущенного приложения.'}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{supportsAutoStart && (
|
||||
<div className="settings__group">
|
||||
<span className="settings__label">Автозапуск обхода</span>
|
||||
<span className="settings__label">{isWindows ? 'Автозапуск' : 'Автозапуск обхода'}</span>
|
||||
<button
|
||||
type="button"
|
||||
className="settings-row"
|
||||
@@ -111,9 +119,10 @@ export default function SettingsView({
|
||||
</button>
|
||||
<p className="list-editor__hint">
|
||||
{isWindows
|
||||
? 'Меняется через запрос прав администратора. Если выключить обход кнопкой на ' +
|
||||
'главном экране, при включённом автозапуске он вернётся не раньше следующей ' +
|
||||
'перезагрузки.'
|
||||
? 'Обход включается при загрузке Windows, а SenBoost открывается свёрнутым в ' +
|
||||
'трей, без окна. Меняется через запрос прав администратора. Если выключить ' +
|
||||
'обход кнопкой на главном экране, при включённом автозапуске он вернётся ' +
|
||||
'не раньше следующей перезагрузки.'
|
||||
: 'Меняется через пароль администратора. Действует, пока обход включён: ' +
|
||||
'выключение кнопкой на главном экране полностью снимает установку — ' +
|
||||
'автозапуск снова понадобится включить вместе с обходом.'}
|
||||
|
||||
@@ -28,7 +28,10 @@ export interface ThemeState {
|
||||
export interface BackgroundSettings {
|
||||
/** Закрытие окна прячет его в трей, а не завершает приложение. */
|
||||
closeToTray: boolean
|
||||
/** Приложение запускается вместе с системой, сразу свёрнутым в трей. */
|
||||
/**
|
||||
* Приложение запускается вместе с системой, сразу свёрнутым в трей. На Windows только
|
||||
* для чтения: следует за `ZapretStatus.autoStart` (см. `followZapretAutoStart`).
|
||||
*/
|
||||
launchAtLogin: boolean
|
||||
/**
|
||||
* Иконка в трее реально создалась. На Linux без AppIndicator трея нет — тогда прятать
|
||||
@@ -149,7 +152,10 @@ export interface IpcHandlers {
|
||||
* nftables (потребуется пароль через pkexec).
|
||||
*/
|
||||
'zapret:set-strategy': (strategyId: string) => ZapretStatus
|
||||
/** macOS/Windows: автозапуск с системой; требует пароль администратора/UAC. */
|
||||
/**
|
||||
* macOS/Windows: автозапуск с системой; требует пароль администратора/UAC. На Windows
|
||||
* вместе со службой при входе поднимается и приложение, свёрнутым в трей.
|
||||
*/
|
||||
'zapret:set-autostart': (enabled: boolean) => ZapretStatus
|
||||
|
||||
'zapret:lists': () => ZapretList[]
|
||||
|
||||
Reference in New Issue
Block a user