Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2126d2b3ef |
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "senboost",
|
"name": "senboost",
|
||||||
"version": "0.6.1",
|
"version": "0.6.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "senboost",
|
"name": "senboost",
|
||||||
"version": "0.6.1",
|
"version": "0.6.2",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "senboost",
|
"name": "senboost",
|
||||||
"version": "0.6.1",
|
"version": "0.6.2",
|
||||||
"description": "Кроссплатформенное десктопное приложение на Electron + React + TypeScript",
|
"description": "Кроссплатформенное десктопное приложение на Electron + React + TypeScript",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"desktopName": "senboost.desktop",
|
"desktopName": "senboost.desktop",
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
|
import type { ZapretStatus } from '../shared/ipc-contract'
|
||||||
import * as linux from './app-autostart.linux'
|
import * as linux from './app-autostart.linux'
|
||||||
import * as win32 from './app-autostart.win32'
|
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, каталог автозапуска),
|
* Источник истины — сама система (реестр/планировщик, SMAppService, каталог автозапуска),
|
||||||
* в settings.json ничего не дублируем: после переустановки системы или приложения
|
* в 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`
|
* (`app.setLoginItemSettings`): exe собран с `requestedExecutionLevel: requireAdministrator`
|
||||||
* (см. electron-builder.yml), а UAC при входе в систему не спрашивают — приложение из ключа
|
* (см. electron-builder.yml), а UAC при входе в систему не спрашивают — приложение из ключа
|
||||||
* реестра просто не запустилось бы. Задача с `/RL HIGHEST` поднимает его с правами сразу.
|
* реестра просто не запустилось бы. Задача с `/RL HIGHEST` поднимает его с правами сразу.
|
||||||
|
*
|
||||||
|
* Сама по себе из интерфейса не переключается: её ставит и снимает `followZapretAutoStart`
|
||||||
|
* (`app-autostart.ts`) вслед за автозапуском службы обхода.
|
||||||
*/
|
*/
|
||||||
function taskCommand(): string {
|
function taskCommand(): string {
|
||||||
// В dev первым аргументом electron.exe нужен каталог приложения, в сборке — нет.
|
// В dev первым аргументом electron.exe нужен каталог приложения, в сборке — нет.
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
import { electronApp, optimizer } from '@electron-toolkit/utils'
|
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 { beginQuit, createWindow, showMainWindow } from './window'
|
||||||
import { showFirstRunSupportDialog } from './first-run'
|
import { showFirstRunSupportDialog } from './first-run'
|
||||||
import { registerIpcHandlers } from './ipc'
|
import { registerIpcHandlers } from './ipc'
|
||||||
@@ -61,6 +61,7 @@ if (elevatedTask) {
|
|||||||
// На macOS чинит прокси, оставшийся от аварийно завершённого прошлого запуска,
|
// На macOS чинит прокси, оставшийся от аварийно завершённого прошлого запуска,
|
||||||
// до того как окно вообще откроется.
|
// до того как окно вообще откроется.
|
||||||
void recoverZapret().then(() => {
|
void recoverZapret().then(() => {
|
||||||
|
followZapretAutoStart()
|
||||||
const window = createWindow({ show: !startHidden })
|
const window = createWindow({ show: !startHidden })
|
||||||
// Ждём первого кадра: диалог должен появиться поверх готового окна, а не пустого.
|
// Ждём первого кадра: диалог должен появиться поверх готового окна, а не пустого.
|
||||||
// Свёрнутому в трей приложению показывать модальное окно некуда — пользователь его
|
// Свёрнутому в трей приложению показывать модальное окно некуда — пользователь его
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import { LIST_TITLES } from '../lib/zapretListMeta'
|
|||||||
import ListEditor from './ListEditor'
|
import ListEditor from './ListEditor'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Настройки: списки сайтов + автозапуск (macOS/Windows). Выбор стратегии и проверка
|
* Настройки: списки сайтов + автозапуск (macOS/Windows; на Windows одна кнопка на службу
|
||||||
|
* и приложение в трее). Выбор стратегии и проверка
|
||||||
* соединения переехали на главный экран (ZapretCard.tsx) — рядом с кнопкой
|
* соединения переехали на главный экран (ZapretCard.tsx) — рядом с кнопкой
|
||||||
* включения, где ими и пользуются. Отдельный экран за шестерёнкой в шапке.
|
* включения, где ими и пользуются. Отдельный экран за шестерёнкой в шапке.
|
||||||
*/
|
*/
|
||||||
@@ -72,6 +73,9 @@ export default function SettingsView({
|
|||||||
{background.settings.closeToTray ? 'Включено' : 'Выключено'}
|
{background.settings.closeToTray ? 'Включено' : 'Выключено'}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
{/* На Windows автозапуск приложения идёт в комплекте с автозапуском службы —
|
||||||
|
одна кнопка ниже (см. followZapretAutoStart в main). */}
|
||||||
|
{!isWindows && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="settings-row"
|
className="settings-row"
|
||||||
@@ -87,18 +91,22 @@ export default function SettingsView({
|
|||||||
{background.settings.launchAtLogin ? 'Включён' : 'Выключен'}
|
{background.settings.launchAtLogin ? 'Включён' : 'Выключен'}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
{background.error && <p className="list-editor__error">{background.error}</p>}
|
{background.error && <p className="list-editor__error">{background.error}</p>}
|
||||||
<p className="list-editor__hint">
|
<p className="list-editor__hint">
|
||||||
Приложение открывается свёрнутым в трей и обход можно включить одним кликом по значку.
|
{isWindows
|
||||||
Это не то же самое, что автозапуск обхода ниже: тот работает вообще без запущенного
|
? 'Закрытое окно прячется в трей, обход продолжает работать. Включить и ' +
|
||||||
приложения.
|
'выключить его можно одним кликом по значку.'
|
||||||
|
: 'Приложение открывается свёрнутым в трей и обход можно включить одним кликом ' +
|
||||||
|
'по значку. Это не то же самое, что автозапуск обхода ниже: тот работает ' +
|
||||||
|
'вообще без запущенного приложения.'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{supportsAutoStart && (
|
{supportsAutoStart && (
|
||||||
<div className="settings__group">
|
<div className="settings__group">
|
||||||
<span className="settings__label">Автозапуск обхода</span>
|
<span className="settings__label">{isWindows ? 'Автозапуск' : 'Автозапуск обхода'}</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="settings-row"
|
className="settings-row"
|
||||||
@@ -111,9 +119,10 @@ export default function SettingsView({
|
|||||||
</button>
|
</button>
|
||||||
<p className="list-editor__hint">
|
<p className="list-editor__hint">
|
||||||
{isWindows
|
{isWindows
|
||||||
? 'Меняется через запрос прав администратора. Если выключить обход кнопкой на ' +
|
? 'Обход включается при загрузке Windows, а SenBoost открывается свёрнутым в ' +
|
||||||
'главном экране, при включённом автозапуске он вернётся не раньше следующей ' +
|
'трей, без окна. Меняется через запрос прав администратора. Если выключить ' +
|
||||||
'перезагрузки.'
|
'обход кнопкой на главном экране, при включённом автозапуске он вернётся ' +
|
||||||
|
'не раньше следующей перезагрузки.'
|
||||||
: 'Меняется через пароль администратора. Действует, пока обход включён: ' +
|
: 'Меняется через пароль администратора. Действует, пока обход включён: ' +
|
||||||
'выключение кнопкой на главном экране полностью снимает установку — ' +
|
'выключение кнопкой на главном экране полностью снимает установку — ' +
|
||||||
'автозапуск снова понадобится включить вместе с обходом.'}
|
'автозапуск снова понадобится включить вместе с обходом.'}
|
||||||
|
|||||||
@@ -28,7 +28,10 @@ export interface ThemeState {
|
|||||||
export interface BackgroundSettings {
|
export interface BackgroundSettings {
|
||||||
/** Закрытие окна прячет его в трей, а не завершает приложение. */
|
/** Закрытие окна прячет его в трей, а не завершает приложение. */
|
||||||
closeToTray: boolean
|
closeToTray: boolean
|
||||||
/** Приложение запускается вместе с системой, сразу свёрнутым в трей. */
|
/**
|
||||||
|
* Приложение запускается вместе с системой, сразу свёрнутым в трей. На Windows только
|
||||||
|
* для чтения: следует за `ZapretStatus.autoStart` (см. `followZapretAutoStart`).
|
||||||
|
*/
|
||||||
launchAtLogin: boolean
|
launchAtLogin: boolean
|
||||||
/**
|
/**
|
||||||
* Иконка в трее реально создалась. На Linux без AppIndicator трея нет — тогда прятать
|
* Иконка в трее реально создалась. На Linux без AppIndicator трея нет — тогда прятать
|
||||||
@@ -149,7 +152,10 @@ export interface IpcHandlers {
|
|||||||
* nftables (потребуется пароль через pkexec).
|
* nftables (потребуется пароль через pkexec).
|
||||||
*/
|
*/
|
||||||
'zapret:set-strategy': (strategyId: string) => ZapretStatus
|
'zapret:set-strategy': (strategyId: string) => ZapretStatus
|
||||||
/** macOS/Windows: автозапуск с системой; требует пароль администратора/UAC. */
|
/**
|
||||||
|
* macOS/Windows: автозапуск с системой; требует пароль администратора/UAC. На Windows
|
||||||
|
* вместе со службой при входе поднимается и приложение, свёрнутым в трей.
|
||||||
|
*/
|
||||||
'zapret:set-autostart': (enabled: boolean) => ZapretStatus
|
'zapret:set-autostart': (enabled: boolean) => ZapretStatus
|
||||||
|
|
||||||
'zapret:lists': () => ZapretList[]
|
'zapret:lists': () => ZapretList[]
|
||||||
|
|||||||
Reference in New Issue
Block a user