documentation rewrite

Signed-off-by: galeon <dertiellis@gmail.com>
This commit is contained in:
galeon committed 2026-10-11 22:32:13 +03:00
1 parent 1943996608
commit f10b654953
34 files changed
+2099 -4576

No files matched your search

+30 -105
View File
@@ -1,120 +1,45 @@
# MicrosoftLoginDialog
# MicrosoftLoginDialog.qml
## Обзор компонента
Окно входа в аккаунт Microsoft. Работает так же, как официальный лаунчер: страница входа
открывается внутри приложения в `WebEngineView`, а лаунчер ждёт, когда браузер перейдёт на
`redirect_uri` с кодом в адресе.
`Minecraft_launcher` — десктопный лаунчер Minecraft на Qt Quick. Он поддерживает несколько
способов входа: офлайн-профиль, сервер Ely.by и учётную запись Microsoft. Последний путь требует
показать пользователю настоящую страницу входа Microsoft и дождаться, пока браузер уйдёт на
`redirect_uri` с кодом авторизации в адресе — ровно так же поступает официальный лаунчер.
Файл попадает в QML-модуль, только если CMake нашёл `Qt6::WebEngineQuick`. Поэтому
[Main](Main.md) не объявляет окно в разметке, а создаёт его через `Qt.createComponent()` при первом
входе (`openMicrosoftLogin()`).
`MicrosoftLoginDialog` — окно с этой страницей. Внутри него живёт `WebEngineView`; диалог следит
за сменой адреса, отдаёт перехваченный код бэкенду и закрывается. Собственной логики разбора
адреса у него нет — она в C++, чтобы правила совпадения совпадали с теми, по которым сервис сам
строит `redirect_uri`.
## Интерфейс
## Место в проекте и зависимости
| | |
|---|---|
| `backend` (required) | `LauncherBackend` |
| `openAt(url)` | открыть страницу входа |
| `failed(message)` | вход не удался. Окно ничего не знает о плашке сообщений главного окна и сообщает о неудаче сигналом |
Импортирует `QtQuick`, `QtQuick.Controls 2.15` и `QtWebEngine`. В начале файла объявлена
`pragma ComponentBehavior: Bound`.
## Как работает
Работает с C++-типом `LauncherBackend` (`launcherbackend.h`, `QML_ELEMENT`), который передаётся
снаружи в свойство `backend`. Вызывает у него `inspectMicrosoftRedirect()`,
`finishMicrosoftLogin()` и `cancelMicrosoftLogin()`.
На каждое `urlChanged` вызывается `handleUrl()`. Он передаёт адрес в
`backend.inspectMicrosoftRedirect()`. Разбор сделан в C++, чтобы правила совпадали с тем, как
[MsaAuthService](../cpp/MsaAuthService.md) строит `redirect_uri`.
**Особенность сборки.** Это единственный QML-файл проекта, который попадает в модуль условно.
`CMakeLists.txt` ищет `Qt6WebEngineQuick` через `find_package(... QUIET)`; модуль объявлен
необязательным сознательно — он ставится отдельной галочкой в установщике Qt и тянет за собой
WebChannel с Positioning, которых в типовой установке нет. Если модуль найден, файл добавляется в
`QML_FILES` и определяется макрос `LAUNCHER_HAS_WEBENGINE`; если нет — лаунчер собирается и
работает как прежде, только без входа через Microsoft. В QML это различие видно через свойство
`backend.microsoftAvailable`, и интерфейс не должен предлагать этот путь, когда оно ложно.
Когда адрес совпал:
Инстанцируется динамически из [Main](Main.md) — главное окно создаёт диалог по требованию, потому
что при сборке без WebEngine самого типа в модуле не существует.
- окно закрывается, `codeTaken` выставляется в `true`;
- если есть код, вызывается `backend.finishMicrosoftLogin(code)`;
- если кода нет, вызывается `backend.cancelMicrosoftLogin()` и испускается `failed` с текстом от
Microsoft или общим «вход не завершён».
## Иерархия и роль
`codeTaken` нужен потому, что `WebEngineView` может сообщить об одном и том же адресе несколько
раз, а отдавать код дважды нельзя.
Корневой тип — `Dialog` из Qt Quick Controls: модальный, 560×680 px, по центру родителя, с нулевым
внутренним отступом и `closePolicy: Popup.NoAutoClose` — окно нельзя закрыть щелчком мимо или
клавишей Escape, выход только через кнопку отмены или успешный вход.
Кнопка «Отмена» выставляет `codeTaken`, закрывает окно и вызывает `cancelMicrosoftLogin()`. Щелчок
мимо окна и Esc его не закрывают.
Оформление задано вручную: тёмный фон со скруглением и акцентной рамкой, заголовок с
разделительной линией, подвал с кнопкой «Отмена».
## Куки
Содержимое — `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)
```
Профиль браузера создаётся через `WebEngineProfilePrototype` без `storageName`, то есть только в
памяти. Куки живут, пока работает лаунчер, и в общий браузер не попадают. Выбрать другой аккаунт
в пределах одного запуска позволяет `prompt=select_account` в адресе входа.
---