Добавлена работа в трее и версия 0.6.1

Приложение теперь может сворачиваться в трей вместо закрытия: обход
продолжает работать в фоне, иконка в трее показывает статус и
позволяет включить/выключить обход без открытия окна. Добавлен
автозапуск самого приложения вместе с системой (свёрнутым в трей).
This commit is contained in:
2026-09-04 20:01:05 +03:00
parent 30248656a8
commit 781d8a574f
23 changed files with 793 additions and 36 deletions
+16 -1
View File
@@ -10,6 +10,20 @@ import { rememberPreferences, type AppSettings } from '../settings'
/** Сколько строк вывода бинарника держим для UI. */
const LOG_LIMIT = 200
const statusListeners = new Set<(status: ZapretStatus) => void>()
/**
* Подписка на изменение статуса внутри main-процесса. Окнам статус уходит событием
* `zapret:status-changed`, но трей — не окно (`src/main/tray.ts`), а знать о включении
* и выключении ему нужно ровно так же. Возвращает функцию отписки.
*/
export function onZapretStatusChanged(listener: (status: ZapretStatus) => void): () => void {
statusListeners.add(listener)
return () => {
statusListeners.delete(listener)
}
}
/** Общая часть обоих движков: хранение статуса и рассылка событий в окна. */
export abstract class ZapretEngine {
protected status: ZapretStatus
@@ -39,7 +53,7 @@ export abstract class ZapretEngine {
*
* `null` в поле означает «не выбирали» — тогда остаётся то, что решил конструктор движка.
*/
restorePreferences(settings: AppSettings): void {
restorePreferences(settings: Pick<AppSettings, 'strategyId' | 'autoStart'>): void {
this.patch({
strategyId: settings.strategyId ?? this.status.strategyId,
autoStart: settings.autoStart ?? this.status.autoStart
@@ -81,6 +95,7 @@ export abstract class ZapretEngine {
// проходит через patch, так что забыть сохранить выбор здесь просто негде.
rememberPreferences({ strategyId: this.status.strategyId, autoStart: this.status.autoStart })
this.broadcast('zapret:status-changed', this.status)
for (const listener of statusListeners) listener(this.getStatus())
return this.getStatus()
}
+6 -3
View File
@@ -7,10 +7,10 @@ import type {
ZapretStatus,
ZapretStrategy
} from '../../shared/ipc-contract'
import { loadSettings } from '../settings'
import { getSettings } from '../settings'
import { DIAGNOSTIC_TARGETS, runDiagnostics } from './diagnostics'
import { DarwinEngine } from './engine.darwin'
import { ZapretEngine, UnsupportedEngine } from './engine'
import { ZapretEngine, UnsupportedEngine, onZapretStatusChanged } from './engine'
import { LinuxEngine } from './engine.linux'
import { Win32Engine } from './engine.win32'
import { readAllLists, resetList, seedLists, writeList } from './lists'
@@ -46,7 +46,8 @@ export async function recoverZapret(): Promise<void> {
// Сохранённый выбор применяем ДО sync(): у уже установленной службы/демона реальное
// состояние (стратегия в strategy.cfg, автозапуск) важнее записанного нами и перекроет его.
const settings = await loadSettings()
// Файл к этому моменту уже прочитан в `app.whenReady()` (см. `src/main/index.ts`).
const settings = getSettings()
engine.restorePreferences({
// Стратегия могла исчезнуть в обновлении (подборка Flowseal меняется) или остаться от
// запуска на другой платформе — тогда безопаснее вернуться к умолчанию движка, чем
@@ -71,6 +72,8 @@ function knownStrategyId(strategyId: string | null): string | null {
return known ? strategyId : null
}
export { onZapretStatusChanged }
export function zapretStatus(): ZapretStatus {
return engine.getStatus()
}