chore(qr-pairing): drop unrelated PageStart churn and trim overlay logs

Remove tab bar/PageStart changes that were not needed for QR pairing (restore
dev baseline). Quiet iOS pairing scanner console output while keeping a few
failure logs. Record the dead-code audit status in docs/plans.
This commit is contained in:
dranik
2026-05-20 12:09:10 +03:00
parent b09a4ecd8d
commit d670bca9d4
3 changed files with 238 additions and 44 deletions
@@ -550,7 +550,6 @@ static UIBezierPath *amneziaScanBracketStrokePath(int corner, CGFloat x0, CGFloa
}
NSError *err = nil;
if (![device lockForConfiguration:&err]) {
NSLog(@"[PairingQrOverlay] torch lock failed: %@", err.localizedDescription);
return;
}
if (on) {
@@ -597,7 +596,7 @@ static UIBezierPath *amneziaScanBracketStrokePath(int corner, CGFloat x0, CGFloa
[session stopRunning];
}
} @catch (NSException *ex) {
NSLog(@"[PairingQrOverlay] stopRunning exception: %@", ex);
NSLog(@"Stop running exception: %@", ex);
}
});
}
@@ -609,19 +608,16 @@ static UIBezierPath *amneziaScanBracketStrokePath(int corner, CGFloat x0, CGFloa
[self stopCapturePipelineOnMainThread];
if (!self.cameraContainer) {
NSLog(@"[PairingQrOverlay] no cameraContainer");
return NO;
}
NSError *error = nil;
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if (!device) {
NSLog(@"[PairingQrOverlay] no default video device");
return NO;
}
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!input) {
NSLog(@"[PairingQrOverlay] deviceInput failed: %@", error.localizedDescription);
return NO;
}
self.videoDevice = device;
@@ -635,7 +631,6 @@ static UIBezierPath *amneziaScanBracketStrokePath(int corner, CGFloat x0, CGFloa
AVCaptureMetadataOutput *meta = [[AVCaptureMetadataOutput alloc] init];
if (![session canAddOutput:meta]) {
NSLog(@"[PairingQrOverlay] cannot add metadata output");
return NO;
}
[session addOutput:meta];
@@ -665,7 +660,7 @@ static UIBezierPath *amneziaScanBracketStrokePath(int corner, CGFloat x0, CGFloa
@try {
[runningSession startRunning];
} @catch (NSException *ex) {
NSLog(@"[PairingQrOverlay] startRunning exception: %@", ex);
NSLog(@"Start running exception: %@", ex);
}
const BOOL running = [runningSession isRunning];
dispatch_async(dispatch_get_main_queue(), ^{
@@ -759,7 +754,6 @@ void amneziaIosPairingQrOverlayPresent(AmneziaPairingQrScannedUtf8Handler onScan
UIWindowScene *scene = amneziaForegroundWindowScene();
if (!scene) {
NSLog(@"[PairingQrOverlay] present: no UIWindowScene");
gOnScanned = nullptr;
gOnBack = nullptr;
return;
@@ -790,7 +784,7 @@ void amneziaIosPairingQrOverlayPresent(AmneziaPairingQrScannedUtf8Handler onScan
gPairingQrOverlayKeySince = CFAbsoluteTimeGetCurrent();
if (![vc startCapturePipelineOnMainThread]) {
NSLog(@"[PairingQrOverlay] startCapture failed");
NSLog(@"Start capture failed");
}
});
}
@@ -846,7 +840,7 @@ void amneziaIosPairingQrOverlayRestartCapture()
AmneziaPairingQrOverlayViewController *vc = (AmneziaPairingQrOverlayViewController *)root;
[vc stopCapturePipelineOnMainThread];
if (![vc startCapturePipelineOnMainThread]) {
NSLog(@"[PairingQrOverlay] restart startCapture failed");
NSLog(@"Restart startCapture failed");
}
});
}
+13 -34
View File
@@ -2,7 +2,6 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Shapes
import QtQuick.Window
import PageEnum 1.0
import Style 1.0
@@ -270,7 +269,6 @@ PageType {
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: tabBar.top
anchors.bottomMargin: 0
enabled: !root.isControlsDisabled
@@ -317,8 +315,6 @@ PageType {
id: tabBar
objectName: "tabBar"
clip: false
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
@@ -335,41 +331,24 @@ PageType {
enabled: !root.isControlsDisabled && !root.isTabBarDisabled
background: Item {
id: tabBarBackgroundRoot
objectName: "tabBarBackgroundRoot"
background: Shape {
objectName: "backgroundShape"
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
width: parent.width
height: parent.height
Rectangle {
anchors.fill: parent
color: AmneziaStyle.color.onyxBlack
}
Shape {
id: tabBarChromeShape
objectName: "backgroundShape"
visible: true
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: tabBar.height
ShapePath {
startX: 0
startY: 0
ShapePath {
startX: 0
startY: 0
PathLine { x: width; y: 0 }
PathLine { x: width; y: tabBar.height - 1 }
PathLine { x: 0; y: tabBar.height - 1 }
PathLine { x: 0; y: 0 }
PathLine { x: tabBarChromeShape.width; y: 0 }
PathLine { x: tabBarChromeShape.width; y: tabBarChromeShape.height - 1 }
PathLine { x: 0; y: tabBarChromeShape.height - 1 }
PathLine { x: 0; y: 0 }
strokeWidth: 1
strokeColor: AmneziaStyle.color.slateGray
fillColor: "transparent"
}
strokeWidth: 1
strokeColor: AmneziaStyle.color.slateGray
fillColor: AmneziaStyle.color.onyxBlack
}
}
+221
View File
@@ -0,0 +1,221 @@
# QR pairing — аудит и инвентарь PR
**Дата:** 2026-05-19
**PR:** [amnezia-vpn/amnezia-client#2580](https://github.com/amnezia-vpn/amnezia-client/pull/2580) — *Feat: Implement qr code generation and scanning*
**Ветка:** `feat/implement-QR-code-generation-and-scanning`**`dev`**
**Объём PR (GitHub / `git diff origin/dev...HEAD`):** 68 файлов, **+6641 / 169** строк
**База для инвентаря «что добавил автор»:** `origin/dev...HEAD` (не первый коммит `2f6714e` и не сравнение с `main`).
---
## Что НЕ входит в PR #2580 (не удалять при чистке pairing)
Эти пути **отсутствуют** в diff PR против `dev`. Попадали в старый аудит из‑за сравнения с `2f6714e` или локального merge — **это прилетело с `dev`, не ваш QR-diff:**
| Путь | Примечание |
|------|------------|
| `client/server_scripts/serverScripts.qrc` (+ telemt, mtproxy) | Контейнеры с ветки **dev****оставить** |
| `client/client_scripts/clientScripts.qrc` (`linux_installer.sh`) | Не в PR #2580 |
При ревью pairing **не предлагать** откат telemt/mtproxy в `server_scripts.qrc`.
---
## Продукт: что делает фича
| Сценарий | UI | Gateway API |
|----------|-----|-------------|
| **Receive (TV / второе устройство)** | `PageSetupWizardApiQrPairingReceive` (+ wizard `PageSetupWizardConfigSource`) | `POST v1/generate_qr` (long-poll), импорт конфига |
| **Send (телефон с Premium)** | `PageSettingsApiQrPairingSend` (вход с `PageSettingsApiDevices`) | `POST v1/scan_qr` после скана session UUID |
| **Desktop** | Текст «доступно в mobile app» | — |
**Сканирование на prod Send:**
| Платформа | Реализация |
|-----------|------------|
| iOS | `iosPairingQrOverlayWindow` (native UIWindow) |
| Android | `CameraActivity` + `openPairingQrScanner()` |
| Desktop | Без камеры |
---
## Инвентарь PR #2580 (68 файлов)
Легенда: **A** = новый файл, **M** = изменён существующий.
### Корень
| | Файл |
|---|------|
| M | `CMakeLists.txt` |
### Core — API pairing
| | Файл | Назначение |
|---|------|------------|
| A | `client/core/controllers/api/pairingController.{h,cpp}` | Payload/parse `generate_qr`, `scan_qr` |
| A | `client/ui/controllers/api/pairingUiController.{h,cpp}` | QML API, TV/phone сессии, камера, gateway |
| M | `client/core/controllers/api/subscriptionController.{h,cpp}` | `importServerFromQrPairingResponse` |
| M | `client/core/controllers/gatewayController.{h,cpp}` | `postAsync` keepAlive, dev proxy/plaintext |
| M | `client/core/controllers/updateController.cpp` | Пропуск updater на dev AGW |
| M | `client/core/controllers/coreController.{h,cpp}`, `coreSignalHandlers.cpp` | Регистрация `PairingUiController` |
| M | `client/core/controllers/api/newsController.cpp` | (смежная правка в ветке) |
| M | `client/core/repositories/secureAppSettingsRepository.cpp` | Dev gateway endpoint |
| M | `client/core/utils/qrCodeUtils.{h,cpp}` | `generateQrCodeImageSeriesPlainText` (UUID в QR) |
| M | `client/core/utils/errorCodes.h`, `errorStrings.cpp` | Коды 11171122 pairing |
| M | `client/core/utils/api/apiUtils.{h,cpp}` | HTTP → pairing error codes |
| M | `client/core/utils/constants/apiKeys.h` | Ключи metadata |
| M | `client/core/utils/networkUtilities.{h,cpp}` | (смежно) |
| M | `client/amneziaApplication.cpp` | (смежно) |
### UI — QML
| | Файл | Назначение |
|---|------|------------|
| A | `PageSettingsApiQrPairingSend.qml` | Prod Send |
| A | `PageSetupWizardApiQrPairingReceive.qml` | Prod Receive |
| A | `PageSettingsApiQrPairingDev.qml` | Dev: TV+phone на одной странице |
| M | `PageSettingsApiDevices.qml` | Кнопка → Send |
| M | `PageSetupWizardConfigSource.qml` | Wizard → Receive, `canOpenTvQrPairingPage` |
| M | `PageDevMenu.qml` | Пункт Dev → pairing (если Dev-страница в PR) |
| M | `PageStart.qml`, `main2.qml`, `TabImageButtonType.qml`, `StackViewType.qml` | Chrome/навигация (часть — под embedded, см. уровень 1) |
| M | `client/ui/qml/qml.qrc` | Регистрация страниц |
| M | `pageController.h` | Enum страниц pairing |
| M | `subscriptionUiController.cpp`, `apiAccountInfoModel.{h,cpp}` | Устройства / аккаунт после pairing |
### iOS
| | Файл | Назначение |
|---|------|------------|
| A | `iosPairingQrOverlayWindow.{h,mm}` | Prod scanner overlay |
| A | `iosPairingCameraAccess.{h,mm,stub}` | Permissions + embedded underlay (legacy/Dev) |
| M | `QRCodeReaderBase.{h,cpp,mm}` | Torch, relayout; wizard reader |
### Android
| | Файл | Назначение |
|---|------|------------|
| A | `PairingQrScanGeometry.kt`, `PairingQrScanBracketPaths.kt`, `PairingQrScanOverlayView.kt` | Рамка «дырки» в превью |
| A | `PairingQrEmbeddedCamera.kt` | Embedded камера в Qt (кандидат на удаление в уровне 1) |
| A | `ic_pairing_back.xml`, `torch_fab_bg.xml` | UI CameraActivity |
| M | `CameraActivity.kt`, `camera_preview.xml` | Prod fullscreen scan |
| M | `AmneziaActivity.kt`, `QtAndroidController.kt` | `startPairingQrCodeReader`, JNI callbacks |
| M | `android_controller.{h,cpp}` | JNI |
| M | `values/strings.xml`, `values-ru/strings.xml` | Строки pairing |
### Сборка и тесты
| | Файл |
|---|------|
| M | `client/cmake/sources.cmake`, `ios.cmake`, `macos_ne.cmake` |
| A | `client/tests/testPairingParsers.cpp` |
| M | `client/tests/CMakeLists.txt` |
| M | `client/translations/amneziavpn_ru_RU.ts` |
### Удалено в истории PR (не в финальном diff как добавление)
- Старая `PageSettingsApiQrPairing.qml` (коммит `b46a9e38` remove old file)
- `AMNEZIA_QR_PAIRING_ALLOW` и mock (коммит `d8668742`)
- `tvPairingUiPhase`, `amneziaIosPairingQrOverlayIsPresented()` (локальная чистка)
---
## Архитектура: что лишнее на prod Send (после упрощения)
На **текущем упрощённом Send** (локально ~361 строка) дубли из **исходного PR** не участвуют:
| Платформа | Рабочий путь | Не используется на prod Send |
|-----------|--------------|------------------------------|
| iOS | Overlay | Embedded `QRCodeReader`, `scanStep`, underlay |
| Android | `CameraActivity` | `PairingQrEmbeddedCamera`, embedded QML |
| Desktop | Текст | Scanner UI |
Это **кандидаты на удаление в уровне 1**, не «ошибка PR» — эволюция к одному scanner на платформу.
---
## Аудит: оставить / убрать / под вопросом
### Ядро PR — не удалять
`pairingController`, `pairingUiController`, Send/Receive QML, `iosPairingQrOverlayWindow`, Android `CameraActivity` + geometry/overlay, `gatewayController` keepAlive, `importServerFromQrPairingResponse`, error codes, `testPairingParsers`, `qrCodeUtils` PlainText, навигация Devices/ConfigSource.
### Кандидаты на удаление (уровень 1 или follow-up)
| Объект | В PR #2580 | Уровень 1 / примечание |
|--------|------------|-------------------------|
| `PageSettingsApiQrPairingDev.qml` + Dev menu | **A** | R8 — убрать из релиза (локально **D**, не закоммичено) |
| `PairingQrEmbeddedCamera.kt` + JNI embedded | **A** | R9 — локально **D** |
| `pairingQrChromeDebug`, embedded chrome в `main2`/`PageStart`/`TabImageButton` | **M** | R1, R10 — локально убрано |
| Verbose `qInfo` / `NSLog` | **M** | R2R4 |
| `scanStep` / `QRCodeReader` в Send (если ещё есть в remote) | в ранних версиях Send | R11 — локально убрано |
| `tryDecodeLegacyChunkedPairingQrPayload` | в `pairingUiController` | **P1** — продуктовое решение |
| `canOpenTvQrPairingPage``v1/news` | в `pairingUiController` | **P2** |
### Не трогать (не из PR pairing)
- `server_scripts.qrc` telemt/mtproxy — **dev**, см. таблицу выше.
---
## Уровень 1 (R1R12)
Цель: prod Send/Receive без Dev/embedded/debug; **без отката telemt/mtproxy**.
| ID | Задача | PR #2580 | Локально |
|----|--------|----------|----------|
| **R1** | `pairingQrChromeDebug` + debug-цвета | M Send/Start | ✅ |
| **R2** | Урезать `qInfo` `[PairingUi]` | M | ✅ |
| **R3** | Урезать `NSLog` `[PairingQrOverlay]` | A overlay | ✅ (10 строк ошибок) |
| **R4** | Урезать `NSLog` `[PairingCamera]` | A camera access | ✅ (1 строка: no root VC) |
| **R5** | ~~Откат `client_scripts.qrc`~~ | **N/A — не в PR** | — |
| **R6** | ~~Откат `server_scripts` telemt/mtproxy~~ | **N/A — не в PR, не удалять** | — |
| **R7** | Нет `PageSettingsApiQrPairing` / enum | удалено в PR | ✅ |
| **R8** | Dev-страница + menu + enum + qrc | **A** Dev.qml | ✅ удалено |
| **R9** | `PairingQrEmbeddedCamera` + JNI | **A** | ✅ удалено |
| **R10** | embedded chrome main2/PageStart/TabImage | M | ✅ |
| **R11** | Упростить Send (overlay/Activity only) | A Send | ✅ ~361 строк |
| **R12** | Убрать API embedded из `pairingUiController` | A | ✅ |
| **R13** | Срезать `iosPairingCameraAccess` до permissions | A | ✅ 2026-05-19 |
| **R14** | `QRCodeReaderBase`: убрать relayout underlay | M | ✅ |
| **R15** | `StackViewType`: убрать `clip: false` (embedded dim) | M | ✅ |
| **R16** | Дубль `getAccountInfo` в Devices `onPhonePairingSucceeded` | M | ✅ |
| **P1** | `tryDecodeLegacyChunkedPairingQrPayload` | — | ✅ удалено |
| **R17** | `QRCodeReader::setTorchEnabled` + torch в `QRCodeReaderBase.mm` | M | ✅ 2026-05-19 |
| **R18** | `PairingController::gatewayStringMetadataArray` + тесты | — | ✅ |
| **R19** | `NetworkUtilities::hostIsPrivateLanAddress` | M | ✅ |
| **R20** | Q_PROPERTY `tvSessionUuid`/`tvPairingBusy`/`tvStatusMessage`/`phoneStatusMessage`; `iosNative*`/`androidNative*` build flags | M | ✅ |
| **R21** | `ApiAccountInfoModel::AvailableDeviceSlotsRole` | M | ✅ |
**Уровень 1 + R17–R21 закрыты** (логи R2–R4 — отдельный проход).
---
## P2–P6 (опционально)
| ID | Тема |
|----|------|
| ~~P1~~ | ~~`tryDecodeLegacyChunkedPairingQrPayload`~~**удалено** |
| P2 | Probe `canOpenTvQrPairingPage``POST v1/news` |
| P3 | Упростить `iosNativePairingQrOverlayBuild` / `androidNativePairingQrOverlayBuild` |
| P4 | `iosPairingCameraAccess` — оставить только для `QRCodeReaderBase` / wizard |
| P5 | `tvStatusMessage` / `tvPairingBusy` только для Dev или убрать |
| P6 | Сократить `iosPairingQrOverlayWindow.mm` после стабилизации UI |
---
## Статус
| Элемент | Статус |
|---------|--------|
| Документ привязан к **PR #2580 vs dev** | ✅ 2026-05-19 |
| telemt/mtproxy | **Вне scope удаления** |
| `tvPairingUiPhase`, `amneziaIosPairingQrOverlayIsPresented` | Удалено |
| **Уровень 1** | **Закрыт** (2026-05-19): R8R21, P1 |
| **P2P6** | По необходимости (`canOpenTvQrPairingPage``v1/news` оставлен) |
| **Доп. чистка 2026-05-21** | `PageStart.qml` откат к `origin/dev` (churn не для pairing); `NSLog` torch / no-camera только под `#if DEBUG` в `iosPairingQrOverlayWindow.mm` (утверждённый план). |
---
*Правки в `client/` — по «Утверждаю план» / «Утверждаю действие». Обновления этого файла в `docs/plans/` — по задаче планирования.*