Версия 0.5.2
Иконки: пересобраны из мастера 1024×1024. В .icns было одно представление 512×512 — macOS домасштабировала остальные сама; теперь все десять, от 16 до 1024. В .ico добавлен размер 24 и своя картинка вместо заглушки Electron. Релиз: differentialPackage и publishAutoUpdate выключены — .blockmap и latest.yml нужны electron-updater, которого в приложении нет, и лежали в ассетах мёртвым грузом. Вместо них CI кладёт рядом с установщиком .md5. Версия в интерфейсе больше не константа: renderer спрашивает её у main через app.getVersion(). Держать константу «в синхроне с package.json» вручную не вышло ни разу — она осталась на 0.4.0, и релизы 0.5.0 и 0.5.1 показали пользователю чужую версию.
This commit is contained in:
@@ -49,7 +49,7 @@ jobs:
|
|||||||
# electron-builder.yml просто копирует resources/zapret, а он у чистого чекаута пуст.
|
# electron-builder.yml просто копирует resources/zapret, а он у чистого чекаута пуст.
|
||||||
- run: node scripts/fetch-zapret.mjs
|
- run: node scripts/fetch-zapret.mjs
|
||||||
|
|
||||||
# electron-builder заливает .exe и .blockmap двумя параллельными publisher'ами: оба
|
# electron-builder заливает артефакты несколькими параллельными publisher'ами: оба
|
||||||
# проверяют, есть ли релиз с этим тегом, оба видят «нет» и оба лезут его создавать —
|
# проверяют, есть ли релиз с этим тегом, оба видят «нет» и оба лезут его создавать —
|
||||||
# второй падает с 422 already_exists и уносит с собой свой файл (на v0.5.0 так потерялся
|
# второй падает с 422 already_exists и уносит с собой свой файл (на v0.5.0 так потерялся
|
||||||
# сам .exe). Создаём релиз заранее, тогда обоим остаётся только залить в готовый.
|
# сам .exe). Создаём релиз заранее, тогда обоим остаётся только залить в готовый.
|
||||||
@@ -74,6 +74,20 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# differentialPackage: false и publishAutoUpdate: false в electron-builder.yml убирают
|
||||||
|
# .blockmap и latest.yml из ассетов (electron-updater в приложении нет — они были бы
|
||||||
|
# мёртвым грузом). В релизе должен остаться только .exe и контрольная сумма к нему.
|
||||||
|
- name: Контрольная сумма
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
exe="$(ls release/*.exe)"
|
||||||
|
md5sum "$exe" | awk '{ print $1 }' > "$exe.md5"
|
||||||
|
gh release upload "$GITHUB_REF_NAME" "$exe.md5" --clobber
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
# Релиз создан с пустым описанием, поэтому список изменений дописываем сами:
|
# Релиз создан с пустым описанием, поэтому список изменений дописываем сами:
|
||||||
# коммиты между предыдущим тегом vX.Y.Z и текущим.
|
# коммиты между предыдущим тегом vX.Y.Z и текущим.
|
||||||
- name: Описание релиза
|
- name: Описание релиза
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 147 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 633 KiB |
@@ -7,9 +7,14 @@ directories:
|
|||||||
# releaseType: release — публиковать релиз сразу, без черновика (draft — поведение по
|
# releaseType: release — публиковать релиз сразу, без черновика (draft — поведение по
|
||||||
# умолчанию у electron-builder). С черновиком параллельная загрузка нескольких файлов иногда
|
# умолчанию у electron-builder). С черновиком параллельная загрузка нескольких файлов иногда
|
||||||
# создаёт два черновика с одним и тем же тегом вместо одного релиза.
|
# создаёт два черновика с одним и тем же тегом вместо одного релиза.
|
||||||
|
#
|
||||||
|
# publishAutoUpdate: false — не заливать latest.yml. Это метаданные для electron-updater,
|
||||||
|
# которого в приложении нет (обновляется пользователь вручную, скачивая новый инсталлятор
|
||||||
|
# со страницы релиза) — файл был бы мёртвым грузом в ассетах.
|
||||||
publish:
|
publish:
|
||||||
provider: github
|
provider: github
|
||||||
releaseType: release
|
releaseType: release
|
||||||
|
publishAutoUpdate: false
|
||||||
|
|
||||||
files:
|
files:
|
||||||
- '!**/.vscode/*'
|
- '!**/.vscode/*'
|
||||||
@@ -54,6 +59,10 @@ nsis:
|
|||||||
# в src/main/zapret/service.win32.ts) — сама установка приложения per-user безопасна.
|
# в src/main/zapret/service.win32.ts) — сама установка приложения per-user безопасна.
|
||||||
oneClick: true
|
oneClick: true
|
||||||
perMachine: false
|
perMachine: false
|
||||||
|
# Без electron-updater (см. publishAutoUpdate выше) differential-обновления не нужны —
|
||||||
|
# differentialPackage: false отключает генерацию .blockmap, который иначе всегда
|
||||||
|
# заливался бы в ассеты релиза рядом с инсталлятором.
|
||||||
|
differentialPackage: false
|
||||||
# Удалять %APPDATA%\rknboost (списки сайтов, метка первого запуска) вместе с приложением.
|
# Удалять %APPDATA%\rknboost (списки сайтов, метка первого запуска) вместе с приложением.
|
||||||
# По умолчанию electron-builder этого НЕ делает, и данные оставались бы в системе после
|
# По умолчанию electron-builder этого НЕ делает, и данные оставались бы в системе после
|
||||||
# удаления. Обновление приложения под это не попадает — в шаблоне деинсталлятора стоит
|
# удаления. Обновление приложения под это не попадает — в шаблоне деинсталлятора стоит
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "rknboost",
|
"name": "rknboost",
|
||||||
"version": "0.5.1",
|
"version": "0.5.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "rknboost",
|
"name": "rknboost",
|
||||||
"version": "0.5.1",
|
"version": "0.5.2",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rknboost",
|
"name": "rknboost",
|
||||||
"version": "0.5.1",
|
"version": "0.5.2",
|
||||||
"description": "Кроссплатформенное десктопное приложение на Electron + React + TypeScript",
|
"description": "Кроссплатформенное десктопное приложение на Electron + React + TypeScript",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "RKNboost",
|
"author": "RKNboost",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 633 KiB |
+5
-1
@@ -1,4 +1,4 @@
|
|||||||
import { BrowserWindow, ipcMain, nativeTheme, type IpcMainInvokeEvent } from 'electron'
|
import { app, BrowserWindow, ipcMain, nativeTheme, type IpcMainInvokeEvent } from 'electron'
|
||||||
import type { IpcChannel, IpcHandlers, ThemeState } from '../shared/ipc-contract'
|
import type { IpcChannel, IpcHandlers, ThemeState } from '../shared/ipc-contract'
|
||||||
import { uninstallApp } from './uninstall.win32'
|
import { uninstallApp } from './uninstall.win32'
|
||||||
import {
|
import {
|
||||||
@@ -46,6 +46,10 @@ function themeState(): ThemeState {
|
|||||||
export function registerIpcHandlers(): void {
|
export function registerIpcHandlers(): void {
|
||||||
handle('theme:get', () => themeState())
|
handle('theme:get', () => themeState())
|
||||||
|
|
||||||
|
// Ровно то же значение, что electron-builder кладёт в имя установщика и в
|
||||||
|
// «Установленные приложения» — оба берут его из "version" в package.json.
|
||||||
|
handle('app:version', () => app.getVersion())
|
||||||
|
|
||||||
// Кнопка «Удалить приложение» есть в интерфейсе только на Windows (SettingsView.tsx),
|
// Кнопка «Удалить приложение» есть в интерфейсе только на Windows (SettingsView.tsx),
|
||||||
// но канал регистрируем всегда — так и должно быть по контракту, просто на других
|
// но канал регистрируем всегда — так и должно быть по контракту, просто на других
|
||||||
// платформах он никогда не вызывается.
|
// платформах он никогда не вызывается.
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ const api = {
|
|||||||
* службы только на Windows (см. SettingsView.tsx). */
|
* службы только на Windows (см. SettingsView.tsx). */
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
|
|
||||||
|
/** Версия запущенной сборки — из package.json через `app.getVersion()` в main. */
|
||||||
|
getAppVersion: (): Promise<string> => invoke('app:version'),
|
||||||
|
|
||||||
getTheme: (): Promise<ThemeState> => invoke('theme:get'),
|
getTheme: (): Promise<ThemeState> => invoke('theme:get'),
|
||||||
onThemeChanged: (listener: (state: ThemeState) => void): (() => void) =>
|
onThemeChanged: (listener: (state: ThemeState) => void): (() => void) =>
|
||||||
subscribe('theme:changed', listener),
|
subscribe('theme:changed', listener),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import type { ZapretListId, ZapretStatus } from '@shared/ipc-contract'
|
import type { ZapretListId, ZapretStatus } from '@shared/ipc-contract'
|
||||||
import { GITHUB_URL } from '@shared/links'
|
import { GITHUB_URL } from '@shared/links'
|
||||||
|
import { useAppVersion } from '../hooks/useAppVersion'
|
||||||
import { useZapretLists } from '../hooks/useZapretLists'
|
import { useZapretLists } from '../hooks/useZapretLists'
|
||||||
import { LIST_TITLES } from '../lib/zapretListMeta'
|
import { LIST_TITLES } from '../lib/zapretListMeta'
|
||||||
import ListEditor from './ListEditor'
|
import ListEditor from './ListEditor'
|
||||||
@@ -12,9 +13,6 @@ import ListEditor from './ListEditor'
|
|||||||
*/
|
*/
|
||||||
const isWindows = window.api.platform === 'win32'
|
const isWindows = window.api.platform === 'win32'
|
||||||
const APP_CHANNEL = 'beta'
|
const APP_CHANNEL = 'beta'
|
||||||
// Держать в синхроне с "version" в package.json — оттуда её берёт electron-builder
|
|
||||||
// для имени установщика и для «Установленные приложения» в Windows.
|
|
||||||
const APP_VERSION = '0.4.0'
|
|
||||||
|
|
||||||
export default function SettingsView({
|
export default function SettingsView({
|
||||||
onBack,
|
onBack,
|
||||||
@@ -27,6 +25,7 @@ export default function SettingsView({
|
|||||||
}): React.JSX.Element {
|
}): React.JSX.Element {
|
||||||
const { lists, autoHostlist, save, reset, clearAuto } = useZapretLists()
|
const { lists, autoHostlist, save, reset, clearAuto } = useZapretLists()
|
||||||
const [openListId, setOpenListId] = useState<ZapretListId | null>(null)
|
const [openListId, setOpenListId] = useState<ZapretListId | null>(null)
|
||||||
|
const appVersion = useAppVersion()
|
||||||
|
|
||||||
const openList = lists.find((list) => list.id === openListId)
|
const openList = lists.find((list) => list.id === openListId)
|
||||||
if (openList) {
|
if (openList) {
|
||||||
@@ -119,9 +118,13 @@ export default function SettingsView({
|
|||||||
<p className="settings__support-hint">Поддержите звёздочкой</p>
|
<p className="settings__support-hint">Поддержите звёздочкой</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<p className="settings__version">
|
{/* Пока версия не пришла из main, строки нет вовсе: иначе на первом кадре
|
||||||
{APP_CHANNEL}-{APP_VERSION}-{window.api.platform}
|
мелькнуло бы «beta--win32» с пустотой на месте номера. */}
|
||||||
</p>
|
{appVersion && (
|
||||||
|
<p className="settings__version">
|
||||||
|
{APP_CHANNEL}-{appVersion}-{window.api.platform}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
{isWindows && (
|
{isWindows && (
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export default function ZapretCard(): React.JSX.Element {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="settings__field">
|
<div className="settings__field">
|
||||||
<span className="settings__label">Стратегия</span>
|
<span className="settings__label">Способ</span>
|
||||||
{/* На время переключения список заблокирован: смена стратегии на работающем
|
{/* На время переключения список заблокирован: смена стратегии на работающем
|
||||||
обходе останавливает и перенастраивает службу, и второй выбор посреди этого
|
обходе останавливает и перенастраивает службу, и второй выбор посреди этого
|
||||||
наложился бы на первый. */}
|
наложился бы на первый. */}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Версия запущенной сборки — та же, что в имени установщика и в «Установленных
|
||||||
|
* приложениях»: main отдаёт её через `app.getVersion()`, то есть прямо из package.json.
|
||||||
|
*
|
||||||
|
* Раньше renderer держал версию своей константой с пометкой «держать в синхроне с
|
||||||
|
* package.json». Синхронизировать вручную забыли: константа осталась на 0.4.0, и релизы
|
||||||
|
* 0.5.0 и 0.5.1 показывали пользователю чужую версию. Спрашивать у main дороже на один
|
||||||
|
* IPC-вызов, зато разъехаться уже нечему.
|
||||||
|
*
|
||||||
|
* `null` — версия ещё не пришла; показывать её в этот момент нечего.
|
||||||
|
*/
|
||||||
|
export function useAppVersion(): string | null {
|
||||||
|
const [version, setVersion] = useState<string | null>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Окно могло закрыться, пока шёл ответ — тогда setState уже некому применять.
|
||||||
|
let cancelled = false
|
||||||
|
void window.api.getAppVersion().then((value) => {
|
||||||
|
if (!cancelled) setVersion(value)
|
||||||
|
})
|
||||||
|
return () => {
|
||||||
|
cancelled = true
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return version
|
||||||
|
}
|
||||||
@@ -101,6 +101,14 @@ export interface ZapretDiagnosticResult extends ZapretDiagnosticTarget {
|
|||||||
export interface IpcHandlers {
|
export interface IpcHandlers {
|
||||||
'theme:get': () => ThemeState
|
'theme:get': () => ThemeState
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Версия приложения — `app.getVersion()`, то есть `"version"` из package.json той сборки,
|
||||||
|
* которая сейчас запущена. Раньше renderer держал её отдельной константой «в синхроне
|
||||||
|
* с package.json» вручную: константа осталась на 0.4.0 и релизы 0.5.0 и 0.5.1 показали
|
||||||
|
* пользователю чужую версию. Спрашивать у main — единственный способ не разъехаться.
|
||||||
|
*/
|
||||||
|
'app:version': () => string
|
||||||
|
|
||||||
/** Windows: подтверждает диалогом ОС, запускает деинсталлятор и закрывает приложение. */
|
/** Windows: подтверждает диалогом ОС, запускает деинсталлятор и закрывает приложение. */
|
||||||
'app:uninstall': () => void
|
'app:uninstall': () => void
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user