9.6 KiB
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)
При создании этого документа использовался ИИ.