Files
minecraft-launcher/doc/qml/MicrosoftLoginDialog.md
T
2026-09-03 09:16:56 +03:00

9.6 KiB
Raw Blame History

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 — главное окно создаёт диалог по требованию, потому что при сборке без 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 показывает это сообщение пользователю. К моменту испускания сигнала диалог уже закрыт, а вход у бэкенда отменён — обработчику остаётся только уведомить.

Отмена по кнопке сигнала не испускает: пользователь и так знает, что закрыл окно.

Методы

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 создаёт диалог динамически (функция openMicrosoftLogin()), задаёт backend, вызывает openAt() с адресом от бэкенда и подписывается на failed(), чтобы показать тост с ошибкой. Показывать ли кнопку входа через Microsoft вообще, главное окно решает по backend.microsoftAvailable.

Со стороны бэкенда. Диалог только доставляет код: inspectMicrosoftRedirect() — разбор адреса, finishMicrosoftLogin() — продолжение обмена кода на токены, cancelMicrosoftLogin() — сброс начатой сессии входа. Результат входа диалогу не возвращается: об успехе главное окно узнаёт от бэкенда по его собственным сигналам, а диалог к этому моменту уже закрыт.

Кнопка отмены. Выставляет codeTaken, закрывает окно и отменяет вход у бэкенда. Признак ставится до закрытия, чтобы последний сигнал об изменении адреса при закрытии не был обработан.

Пример использования

MicrosoftLoginDialog {
    id: msLogin
    parent: Overlay.overlay
    backend: launcherBackend
    onFailed: (message) => showToast(message, "#cc6666", 4000)
}

// открывать только в сборке с Qt WebEngine
Component.onCompleted: if (launcherBackend.microsoftAvailable) msLogin.openAt(loginUrl)

При создании этого документа использовался ИИ.