# MicrosoftLoginDialog ## Обзор компонента `Minecraft_launcher` — десктопный лаунчер Minecraft на Qt Quick. Он поддерживает несколько способов входа: офлайн-профиль, сервер Ely.by и учётную запись Microsoft. Последний путь требует показать пользователю настоящую страницу входа Microsoft и дождаться, пока браузер уйдёт на `redirect_uri` с кодом авторизации в адресе — ровно так же поступает официальный лаунчер. `MicrosoftLoginDialog` — окно с этой страницей. Внутри него живёт `WebEngineView`; диалог следит за сменой адреса, отдаёт перехваченный код бэкенду и закрывается. Собственной логики разбора адреса у него нет — она в C++, чтобы правила совпадения совпадали с теми, по которым сервис сам строит `redirect_uri`. ## Место в проекте и зависимости Импортирует `QtQuick`, `QtQuick.Controls 2.15` и `QtWebEngine`. В начале файла объявлена `pragma ComponentBehavior: Bound`. Работает с C++-типом `LauncherBackend` (`launcherbackend.h`, `QML_ELEMENT`), который передаётся снаружи в свойство `backend`. Вызывает у него `inspectMicrosoftRedirect()`, `finishMicrosoftLogin()` и `cancelMicrosoftLogin()`. **Особенность сборки.** Это единственный QML-файл проекта, который попадает в модуль условно. `CMakeLists.txt` ищет `Qt6WebEngineQuick` через `find_package(... QUIET)`; модуль объявлен необязательным сознательно — он ставится отдельной галочкой в установщике Qt и тянет за собой WebChannel с Positioning, которых в типовой установке нет. Если модуль найден, файл добавляется в `QML_FILES` и определяется макрос `LAUNCHER_HAS_WEBENGINE`; если нет — лаунчер собирается и работает как прежде, только без входа через Microsoft. В QML это различие видно через свойство `backend.microsoftAvailable`, и интерфейс не должен предлагать этот путь, когда оно ложно. Инстанцируется динамически из [Main](Main.md) — главное окно создаёт диалог по требованию, потому что при сборке без WebEngine самого типа в модуле не существует. ## Иерархия и роль Корневой тип — `Dialog` из Qt Quick Controls: модальный, 560×680 px, по центру родителя, с нулевым внутренним отступом и `closePolicy: Popup.NoAutoClose` — окно нельзя закрыть щелчком мимо или клавишей Escape, выход только через кнопку отмены или успешный вход. Оформление задано вручную: тёмный фон со скруглением и акцентной рамкой, заголовок с разделительной линией, подвал с кнопкой «Отмена». Содержимое — `WebEngineView` во всю площадь с отступом 12 px и индикатор занятости по центру, видимый на время загрузки страницы. Рядом объявлен `WebEngineProfilePrototype` без `storageName`: профиль без имени хранилища означает профиль без диска, поэтому куки живут только пока работает лаунчер и в общий браузер не попадают. За выбор аккаунта в пределах сессии отвечает параметр `prompt=select_account` в адресе входа, который формирует бэкенд. ## Свойства | Свойство | Тип | По умолчанию | Обязательное | Описание | |----------|-----|--------------|--------------|----------| | `backend` | `var` | — | **Да** | Экземпляр `LauncherBackend`. Разбирает перехваченный адрес и завершает или отменяет вход. | | `codeTaken` | `bool` | `false` | Нет | Код авторизации уже отдан бэкенду. Защита от повторной обработки: `WebEngineView` успевает сообщить об изменении адреса несколько раз, и без этого признака код ушёл бы дважды. Сбрасывается в `openAt()` и принудительно выставляется при отмене. | ## Сигналы #### failed(string message) Вход не завершён: адрес совпал с `redirect_uri`, но кода в нём нет — например, пользователь отказался выдать разрешение, или Microsoft вернула ошибку. В параметре приходит текст ошибки от бэкенда, а если его нет — сообщение по умолчанию о незавершённом входе. Окно ничего не знает про тосты главного окна, поэтому о неудаче сообщает сигналом. Обработчик в [Main](Main.md) показывает это сообщение пользователю. К моменту испускания сигнала диалог уже закрыт, а вход у бэкенда отменён — обработчику остаётся только уведомить. Отмена по кнопке сигнала не испускает: пользователь и так знает, что закрыл окно. ## Методы #### openAt(string url) : void Открывает диалог на переданном адресе страницы входа. Сбрасывает `codeTaken`, загружает адрес в `WebEngineView` и показывает окно. Адрес формирует бэкенд — в нём уже присутствуют `redirect_uri`, идентификатор клиента и `prompt=select_account`. #### handleUrl(url) : void Обработчик смены адреса в `WebEngineView`; вызывать снаружи не нужно. Ничего не делает, если код уже перехвачен. Иначе передаёт адрес в `backend.inspectMicrosoftRedirect()` и смотрит на поле `matched` ответа: если адрес не является `redirect_uri`, обработка на этом заканчивается — это обычная навигация по страницам входа. При совпадении выставляет `codeTaken`, закрывает окно и дальше расходится по двум путям: непустое поле `code` уходит в `backend.finishMicrosoftLogin()`, иначе вход отменяется через `backend.cancelMicrosoftLogin()` и испускается сигнал `failed()` с текстом из поля `error`. ## Взаимодействие с другими компонентами **Со стороны главного окна.** [Main](Main.md) создаёт диалог динамически (функция `openMicrosoftLogin()`), задаёт `backend`, вызывает `openAt()` с адресом от бэкенда и подписывается на `failed()`, чтобы показать тост с ошибкой. Показывать ли кнопку входа через Microsoft вообще, главное окно решает по `backend.microsoftAvailable`. **Со стороны бэкенда.** Диалог только доставляет код: `inspectMicrosoftRedirect()` — разбор адреса, `finishMicrosoftLogin()` — продолжение обмена кода на токены, `cancelMicrosoftLogin()` — сброс начатой сессии входа. Результат входа диалогу не возвращается: об успехе главное окно узнаёт от бэкенда по его собственным сигналам, а диалог к этому моменту уже закрыт. **Кнопка отмены.** Выставляет `codeTaken`, закрывает окно и отменяет вход у бэкенда. Признак ставится до закрытия, чтобы последний сигнал об изменении адреса при закрытии не был обработан. ## Пример использования ```qml MicrosoftLoginDialog { id: msLogin parent: Overlay.overlay backend: launcherBackend onFailed: (message) => showToast(message, "#cc6666", 4000) } // открывать только в сборке с Qt WebEngine Component.onCompleted: if (launcherBackend.microsoftAvailable) msLogin.openAt(loginUrl) ``` --- При создании этого документа использовался ИИ.