diff --git a/Dev_Docs/Pending_Features/2026-06-14_2035_ui_подключение_по_коду.md b/Dev_Docs/Pending_Features/2026-06-14_2035_ui_подключение_по_коду.md
index 99fda0a..0c7afd2 100644
--- a/Dev_Docs/Pending_Features/2026-06-14_2035_ui_подключение_по_коду.md
+++ b/Dev_Docs/Pending_Features/2026-06-14_2035_ui_подключение_по_коду.md
@@ -22,6 +22,9 @@
- убедиться, что без онлайн доверённой сессии новое устройство сразу получает явную ошибку и код вообще не создаётся;
- убедиться, что countdown под кодом убывает в реальном времени;
- убедиться, что кнопка `Отмена` на новом устройстве действительно снимает заявку и она пропадает у доверённого устройства без ожидания TTL.
+ - убедиться, что на экране `Подключить по коду` блок дополнительного пароля показывает два понятных состояния: пароль не задан / пароль установлен;
+ - убедиться, что `Задать пароль` и `Изменить пароль` открывают верхний диалог с двумя полями и кнопками-глазами;
+ - убедиться, что `Убрать пароль` не выключает pairing целиком, а переводит его в режим без дополнительного пароля.
- ожидаемый результат:
- новое устройство получает код, доверённое устройство видит ту же заявку и может её подтвердить или отклонить;
diff --git a/VERSION.properties b/VERSION.properties
index 5a753b1..5963aaf 100644
--- a/VERSION.properties
+++ b/VERSION.properties
@@ -1,2 +1,2 @@
-client.version=1.2.200
-server.version=1.2.189
+client.version=1.2.201
+server.version=1.2.190
diff --git a/shine-UI/js/app.js b/shine-UI/js/app.js
index 8948d07..35e6c55 100644
--- a/shine-UI/js/app.js
+++ b/shine-UI/js/app.js
@@ -55,7 +55,7 @@ import * as serverSettingsView from './pages/server-settings-view.js';
import * as toolsSettingsView from './pages/tools-settings-view.js';
import * as deviceView from './pages/device-view.js?v=202606131435';
import * as connectDeviceView from './pages/connect-device-view.js?v=202606142055';
-import * as devicePairingView from './pages/device-pairing-view.js?v=202606150045';
+import * as devicePairingView from './pages/device-pairing-view.js?v=202606151000';
import * as deviceQrView from './pages/device-qr-view.js';
import * as deviceCameraView from './pages/device-camera-view.js';
import * as showKeysView from './pages/show-keys-view.js';
diff --git a/shine-UI/js/pages/device-pairing-view.js b/shine-UI/js/pages/device-pairing-view.js
index 1dd5bad..b3f3188 100644
--- a/shine-UI/js/pages/device-pairing-view.js
+++ b/shine-UI/js/pages/device-pairing-view.js
@@ -17,6 +17,8 @@ import { toUserMessage } from '../services/ui-error-texts.js';
export const pageMeta = { id: 'device-pairing-view', title: 'Подключить по коду' };
+const PAIRING_PASSWORD_STATE_PREFIX = 'shine_pairing_password_state_v1';
+
function setStatus(statusEl, message, kind = 'info') {
statusEl.classList.toggle('is-unavailable', kind === 'error');
statusEl.classList.toggle('is-available', kind !== 'error');
@@ -71,6 +73,48 @@ function requestCardHtml(request) {
`;
}
+function makePasswordToggleIcons() {
+ return {
+ eye: `
+
+ `,
+ eyeOff: `
+
+ `,
+ };
+}
+
+function localPairingPasswordStateKey(login, serverUrl) {
+ return `${PAIRING_PASSWORD_STATE_PREFIX}:${String(serverUrl || '').trim()}:${String(login || '').trim().toLowerCase()}`;
+}
+
+function loadLocalPairingPasswordState(login, serverUrl) {
+ try {
+ const raw = localStorage.getItem(localPairingPasswordStateKey(login, serverUrl));
+ if (!raw) return false;
+ const parsed = JSON.parse(raw);
+ return !!parsed?.hasPassword;
+ } catch {
+ return false;
+ }
+}
+
+function saveLocalPairingPasswordState(login, serverUrl, hasPassword) {
+ try {
+ localStorage.setItem(localPairingPasswordStateKey(login, serverUrl), JSON.stringify({
+ hasPassword: !!hasPassword,
+ updatedAtMs: Date.now(),
+ }));
+ } catch {}
+}
+
export function render({ navigate }) {
const screen = document.createElement('section');
screen.className = 'stack';
@@ -78,6 +122,9 @@ export function render({ navigate }) {
let requests = [];
let cleanupEvent = () => {};
let disposed = false;
+ let settingsBusy = false;
+ let pairingPasswordConfigured = loadLocalPairingPasswordState(state.session.login, state.entrySettings.shineServer);
+ let dialogMode = '';
screen.append(
renderHeader({
@@ -88,22 +135,7 @@ export function render({ navigate }) {
const settingsCard = document.createElement('div');
settingsCard.className = 'card stack';
- settingsCard.innerHTML = `
-
Пароль подключения
-
-
-
-
-
-
-
Чтобы включить pairing без пароля: оставьте галочку выключенной и нажмите "Включить / обновить". Чтобы включить pairing с паролем: включите галочку, введите пароль и нажмите ту же кнопку.
Дополнительный пароль не даёт права на подключение сам по себе. Он только отсекает лишние заявки, чтобы посторонние не могли засыпать ваш аккаунт запросами. Обычно он не нужен, поэтому при желании можно задать и что-то простое, что легко запомнить.