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