new docs for project
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
# BuildsDialog
|
||||
|
||||
## Обзор компонента
|
||||
|
||||
`Minecraft_launcher` — десктопный лаунчер Minecraft на Qt Quick. Сборка в нём — это именованный
|
||||
набор «версия игры + модлоадер + адрес сервера» вместе с собственным содержимым `.minecraft`:
|
||||
модами, конфигами и мирами. Активная сборка одна, её содержимое лежит в `.minecraft`, остальные
|
||||
хранятся в архивах и разворачиваются при переключении.
|
||||
|
||||
`BuildsDialog` — окно управления этими сборками: слева список со сменой активной, справа карточка
|
||||
выбранной — имя, сервер, версия Minecraft и модлоадеры. Отсюда же сборка ставится (скачивание
|
||||
версии игры и модлоадера) и удаляется.
|
||||
|
||||
Карточка сохраняет правки по ходу редактирования, отдельной кнопки «Сохранить» нет: иначе
|
||||
появляется неочевидное несохранённое состояние, пока пользователь переключается между сборками в
|
||||
левом списке.
|
||||
|
||||
## Место в проекте и зависимости
|
||||
|
||||
В начале файла объявлена `pragma ComponentBehavior: Bound`. Импортирует `QtQuick`,
|
||||
`QtQuick.Controls 2.15` и `QtQuick.Layouts 2.15`.
|
||||
|
||||
Использует три компонента из того же QML-модуля:
|
||||
|
||||
- [LabelledField](LabelledField.md) — поля названия сборки и адреса сервера;
|
||||
- [LoaderRow](LoaderRow.md) — по одной строке на каждый из четырёх модлоадеров;
|
||||
- [VersionPickerDialog](VersionPickerDialog.md) — вложенное окно выбора версии Minecraft.
|
||||
|
||||
Работает с C++-типом `LauncherBackend` (`launcherbackend.h`, `QML_ELEMENT` в модуле
|
||||
`Minecraft_launcher`) через свойство `backend`. Читает свойства `customBuildNames`,
|
||||
`activeBuildIndex`, `switching` и `busy`; вызывает `customBuildAt()`, `addCustomBuild()`,
|
||||
`updateCustomBuild()`, `customBuildRemovalInfo()`, `removeCustomBuild()`, `checkInstallation()`,
|
||||
`installCustomBuild()` и `refreshVersionCatalog()`; слушает сигнал `installedVersionsChanged`.
|
||||
|
||||
Объявлен в `QML_FILES` модуля (`CMakeLists.txt`); использует ресурс `images/Trash.svg`.
|
||||
Инстанцируется в [Main](Main.md).
|
||||
|
||||
## Иерархия и роль
|
||||
|
||||
Корневой тип — `Dialog`: модальный, 880×600 px, нулевой внутренний отступ, тёмный фон со
|
||||
скруглением и акцентной рамкой. Пока идёт смена активной сборки (`backend.switching`), окно
|
||||
закрывается только кнопкой: архивация и распаковка `.minecraft` не должны прерываться случайным
|
||||
щелчком мимо.
|
||||
|
||||
Содержимое — `RowLayout` из двух частей:
|
||||
|
||||
- **Слева** (260 px) список сборок и строка «+ Новая сборка» под ним. Строка списка показывает имя,
|
||||
пометку «активна» у активной сборки и корзину, появляющуюся при наведении. Вся колонка
|
||||
выключается на время смены активной сборки.
|
||||
- **Справа** карточка выбранной сборки внутри `Flickable` — она может не поместиться по высоте.
|
||||
Карточка выключается и приглушается, когда сборка не выбрана или идёт переключение.
|
||||
|
||||
Карточка сверху вниз: название, адрес сервера, поле версии Minecraft, панель модлоадеров и строка
|
||||
состояния комплектности. Поле версии — не выпадающий список, а прямоугольник, который только
|
||||
показывает выбор и открывает отдельное окно: версий около тысячи, и разбираться в них удобнее в
|
||||
окне с категориями.
|
||||
|
||||
Отдельно объявлен вложенный `Dialog` подтверждения удаления шириной 420 px с красной рамкой,
|
||||
привязанный к тому же родителю, что и само окно.
|
||||
|
||||
Подвал несёт три кнопки: «Установить», «Сделать активной» и «Закрыть».
|
||||
|
||||
## Свойства
|
||||
|
||||
| Свойство | Тип | По умолчанию | Обязательное | Описание |
|
||||
|----------|-----|--------------|--------------|----------|
|
||||
| `backend` | `var` | — | **Да** | Экземпляр `LauncherBackend` — хранилище сборок и исполнитель установки, удаления и переключения. |
|
||||
| `editIndex` | `int` | `-1` | Нет | Индекс сборки, открытой в карточке справа. Значение `-1` означает, что карточка пуста и выключена. С активной сборкой не связан: активную меняет отдельная кнопка, чтобы случайный клик по списку не запускал архивацию `.minecraft`. |
|
||||
| `loading` | `bool` | `false` | Нет | Признак того, что карточка сейчас заполняется данными сборки. Пока он выставлен, обработчики полей не должны писать обратно — иначе открытие сборки немедленно перезаписывало бы её. |
|
||||
|
||||
### Внутренняя панель модлоадеров
|
||||
|
||||
Панель `loaderPanel` — это `Column` с четырьмя строками [LoaderRow](LoaderRow.md) и собственным
|
||||
маленьким API. Лоадеры несовместимы между собой: игра запускается ровно с одним профилем
|
||||
`versions/<id>`, поэтому отметка одного снимает остальные, а «ничего не отмечено» — это чистая
|
||||
ваниль.
|
||||
|
||||
| Свойство панели | Тип | Описание |
|
||||
|-----------------|-----|----------|
|
||||
| `rows` | `var` | Массив из четырёх строк лоадеров в порядке показа: Minecraft Forge (`forge`), Fabric Loader (`fabric`), NeoForge (`neoforge`), Quilt Loader (`quilt`). |
|
||||
|
||||
Функции панели: `applyBuild(loader, loaderVersion)` раздаёт данные сборки всем строкам;
|
||||
`selectedRow()` возвращает отмеченную строку или `null`; `keepOnly(row)` очищает все строки,
|
||||
кроме переданной; `commitSelection()` сохраняет выбор в сборку, записывая ключ лоадера, его версию
|
||||
и пустой `resolvedVersionId` — профиль появится только после установки, а до неё сборка
|
||||
запускается на чистой ванили.
|
||||
|
||||
## Сигналы
|
||||
|
||||
Собственных сигналов компонент не объявляет: все изменения уходят прямо в бэкенд, и о них
|
||||
остальной интерфейс узнаёт по его сигналам.
|
||||
|
||||
## Методы
|
||||
|
||||
#### selectBuild(int index) : void
|
||||
|
||||
Открывает сборку с указанным индексом в карточке. Читает данные через `customBuildAt()`,
|
||||
выставляет `loading` на время заполнения полей, раздаёт лоадеры панели через `applyBuild()` и в
|
||||
конце обновляет строку состояния.
|
||||
|
||||
#### askRemove(int index) : void
|
||||
|
||||
Спрашивает подтверждение перед удалением: оно необратимо и уносит с собой архив сборки. Запрашивает
|
||||
`customBuildRemovalInfo()` и наполняет окно подтверждения именем сборки и тремя признаками — есть
|
||||
ли у неё архив, активна ли она сейчас и последняя ли она. Индекс запоминается в самом окне
|
||||
подтверждения, потому что к моменту ответа строка списка под курсором может быть уже другой.
|
||||
|
||||
Окно подтверждения объясняет последствия по этим признакам: вместе со сборкой удалится её архив, и
|
||||
моды, конфиги и миры восстановить будет нельзя; активная сборка владеет содержимым `.minecraft`,
|
||||
оно будет очищено, а на его место развернётся следующая сборка; для последней сборки содержимое
|
||||
`.minecraft` остаётся на месте.
|
||||
|
||||
#### performRemove(int index) : void
|
||||
|
||||
Удаляет сборку через бэкенд и восстанавливает состояние карточки: если сборок не осталось,
|
||||
сбрасывает `editIndex` в `-1`, иначе открывает соседнюю — ту же позицию или последнюю оставшуюся.
|
||||
|
||||
#### commit(var fields) : void
|
||||
|
||||
Сохраняет часть полей сборки: передаёт `QVariantMap` в `updateCustomBuild()` и обновляет строку
|
||||
состояния. Ничего не делает во время заполнения карточки (`loading`) и при пустом `editIndex` —
|
||||
это и есть защита от записи при открытии сборки.
|
||||
|
||||
Вызывается по завершении правки каждого поля: имени, адреса сервера, версии Minecraft и выбора
|
||||
модлоадера.
|
||||
|
||||
#### refreshStatus() : void
|
||||
|
||||
Пересчитывает строку комплектности под карточкой. Спрашивает у бэкенда `checkInstallation()` и
|
||||
показывает либо сообщение о готовности к запуску, либо число недостающих файлов вместе с первым из
|
||||
них. При пустом `editIndex` очищает строку.
|
||||
|
||||
#### newBuildName() : string
|
||||
|
||||
Придумывает имя для новой сборки: перебирает «Сборка 1», «Сборка 2» и так далее, пока не найдёт
|
||||
свободное среди существующих имён.
|
||||
|
||||
## Взаимодействие с другими компонентами
|
||||
|
||||
**Со стороны родителя.** [Main](Main.md) задаёт `backend` и открывает окно. Начальное состояние
|
||||
окно выбирает само в обработчике `onAboutToShow`: просит обновить каталог версий и открывает
|
||||
активную сборку, а при пустом списке оставляет карточку выключенной.
|
||||
|
||||
**Внутрь — к вложенным компонентам.** Поля [LabelledField](LabelledField.md) сообщают о правке
|
||||
сигналом `editingFinished`, и карточка сразу вызывает `commit()` с обрезанным по краям значением.
|
||||
Поле версии открывает [VersionPickerDialog](VersionPickerDialog.md) вызовом `openFor()` и получает
|
||||
результат сигналом `versionChosen`; запись выбранной версии сама вызывает `commit()` через
|
||||
обработчик изменения. Строки [LoaderRow](LoaderRow.md) получают `gameVersion` привязкой к
|
||||
выбранной версии игры, поэтому смена версии Minecraft автоматически перезапрашивает списки версий
|
||||
лоадеров.
|
||||
|
||||
**Наружу — к бэкенду.** Кнопка «Установить» вызывает `installCustomBuild()`, кнопка «Сделать
|
||||
активной» пишет в свойство `activeBuildIndex`. Обе выключены, пока лаунчер занят (`busy`), а
|
||||
кнопка активации — ещё и когда выбранная сборка уже активна. Ход установки и переключения
|
||||
показывает плашка [ProgressPanel](ProgressPanel.md) главного окна, а не это окно.
|
||||
|
||||
**Обратная связь от бэкенда.** Окно подписано на `installedVersionsChanged` через `Connections`:
|
||||
установка версии или модлоадера меняет комплектность сборки, и строка состояния должна это
|
||||
заметить, не дожидаясь переоткрытия окна.
|
||||
|
||||
## Пример использования
|
||||
|
||||
```qml
|
||||
BuildsDialog {
|
||||
id: buildsDialog
|
||||
parent: Overlay.overlay
|
||||
anchors.centerIn: parent
|
||||
backend: launcherBackend
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("Сборки")
|
||||
onClicked: buildsDialog.open()
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
При создании этого документа использовался ИИ.
|
||||
@@ -0,0 +1,89 @@
|
||||
# DarkCombo
|
||||
|
||||
## Обзор компонента
|
||||
|
||||
`Minecraft_launcher` — десктопный лаунчер Minecraft на Qt Quick. Всё окно оформлено вручную в
|
||||
тёмной теме, а стиль Qt Quick Controls принудительно выставлен в `Basic` (`main.cpp`), потому что
|
||||
нативные стили игнорируют пользовательские `contentItem` и `background`. Из-за этого каждый
|
||||
стандартный элемент управления, попадающий в интерфейс, приходится переопределять самому.
|
||||
|
||||
`DarkCombo` — как раз такое переопределение: выпадающий список в общем тёмном стиле окна.
|
||||
Компонент не добавляет логики, он целиком про внешний вид — фон, рамку, стрелку, делегат строки и
|
||||
всплывающую панель. К нему обращаются всюду, где нужен выпадающий список внутри диалогов: выбор
|
||||
версии модлоадера, выбор Java, поля в настройках.
|
||||
|
||||
## Место в проекте и зависимости
|
||||
|
||||
Импортирует `QtQuick` и `QtQuick.Controls 2.15`; собственных C++-типов не использует.
|
||||
|
||||
Объявлен в `QML_FILES` модуля `Minecraft_launcher` (см. `CMakeLists.txt`), поэтому доступен по
|
||||
имени `DarkCombo` в любом файле того же модуля без явного импорта.
|
||||
|
||||
Используется в [LoaderRow](LoaderRow.md) — список версий модлоадера — и дважды в [Main](Main.md):
|
||||
в выпадающих списках профиля и сборки на главном окне.
|
||||
|
||||
Компонент ссылается на ресурсы `images/Profile_Box/Asset_23.svg` и
|
||||
`images/Profile_Box/Asset_24.svg` — они перечислены в `RESOURCES` того же QML-модуля, отдельного
|
||||
подключения не требуют.
|
||||
|
||||
## Иерархия и роль
|
||||
|
||||
Корневой тип — `ComboBox` из Qt Quick Controls. Всё поведение (модель, `currentIndex`,
|
||||
`activated`, `displayText`, клавиатурная навигация) наследуется без изменений; `DarkCombo`
|
||||
переопределяет только четыре визуальных слота базового типа:
|
||||
|
||||
| Слот | Что даёт `DarkCombo` |
|
||||
|------|----------------------|
|
||||
| `indicator` | стрелка из SVG-ресурса вместо двойного шеврона Basic-стиля; при открытом списке (`down`) картинка меняется |
|
||||
| `contentItem` | текст текущего значения белым, с обрезкой справа многоточием и отступом под стрелку |
|
||||
| `background` | тёмный прямоугольник со скруглением 6 px; рамка подсвечивается акцентным цветом при фокусе |
|
||||
| `delegate` | строка списка: белый текст, подсветка фона у элемента под курсором |
|
||||
| `popup` | всплывающая панель шириной с сам комбобокс, высотой не более 220 px, с вертикальным индикатором прокрутки |
|
||||
|
||||
## Свойства
|
||||
|
||||
Собственных свойств компонент не объявляет — доступен весь набор свойств `ComboBox`
|
||||
(`model`, `currentIndex`, `currentText`, `displayText`, `editable` и прочие).
|
||||
|
||||
Внутри `delegate` объявлены два обязательных свойства делегата, они относятся к строке списка,
|
||||
а не к самому комбобоксу:
|
||||
|
||||
| Свойство | Тип | По умолчанию | Обязательное | Описание |
|
||||
|----------|-----|--------------|--------------|----------|
|
||||
| `modelData` | `var` | — | **Да** | Значение строки модели; выводится текстом в строке списка. Модель ожидается плоской — списком строк, а не объектов. |
|
||||
| `index` | `int` | — | **Да** | Позиция строки; сравнивается с `highlightedIndex` комбобокса, чтобы подсветить строку под курсором. |
|
||||
|
||||
## Сигналы
|
||||
|
||||
Собственных сигналов нет. Наследуются сигналы `ComboBox`, из которых на практике используется
|
||||
`activated(int index)` — выбор строки пользователем (в отличие от `currentIndexChanged`, он не
|
||||
срабатывает при программной смене значения).
|
||||
|
||||
## Методы
|
||||
|
||||
Собственных функций нет.
|
||||
|
||||
## Взаимодействие с другими компонентами
|
||||
|
||||
Компонент самодостаточен и ничего не знает ни о бэкенде, ни о родителе: модель приходит извне
|
||||
через `model`, результат выбора родитель получает через унаследованный `activated`. Так,
|
||||
[LoaderRow](LoaderRow.md) передаёт в `model` список подписей версий модлоадера и в обработчике
|
||||
`activated` переводит индекс обратно в номер версии.
|
||||
|
||||
Поскольку модель ожидается списком строк, вызывающий код обычно сам приводит массив объектов к
|
||||
массиву подписей перед присваиванием.
|
||||
|
||||
## Пример использования
|
||||
|
||||
```qml
|
||||
DarkCombo {
|
||||
width: 200
|
||||
height: 32
|
||||
model: ["1.21.1", "1.20.6", "1.20.4"]
|
||||
onActivated: (index) => console.log("выбрано:", model[index])
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
При создании этого документа использовался ИИ.
|
||||
@@ -0,0 +1,149 @@
|
||||
# JavaPickerDialog
|
||||
|
||||
## Обзор компонента
|
||||
|
||||
`Minecraft_launcher` — десктопный лаунчер Minecraft на Qt Quick. Разным версиям игры нужны разные
|
||||
версии Java, и лаунчер умеет скачивать их сам: официальные сборки Mojang и сборки Temurin в двух
|
||||
вариантах — JDK и JRE. Держать в голове, какая Java нужна какой версии игры, пользователь не
|
||||
обязан.
|
||||
|
||||
`JavaPickerDialog` — окно выбора сборки Java: слева типы сборок, справа сами версии с поиском.
|
||||
Устроено так же, как [VersionPickerDialog](VersionPickerDialog.md), с одним принципиальным
|
||||
отличием: выбранное здесь ещё и качается. У версий игры загрузку начинает сама сборка, а сборка
|
||||
Java, которой нет на диске, запуску ничем не поможет — поэтому кнопка подтверждения при
|
||||
необходимости сразу ставит выбранную сборку в очередь на скачивание.
|
||||
|
||||
Окно также показывает, какая версия Java нужна выбранной версии игры, помечает сборки, которые
|
||||
для неё слишком старые, и позволяет удалять скачанное прямо из списка.
|
||||
|
||||
## Место в проекте и зависимости
|
||||
|
||||
В начале файла объявлена `pragma ComponentBehavior: Bound`. Импортирует `QtQuick`,
|
||||
`QtQuick.Controls 2.15` и `QtQuick.Layouts 2.15`.
|
||||
|
||||
Работает с C++-типом `LauncherBackend` (`launcherbackend.h`, `QML_ELEMENT` в модуле
|
||||
`Minecraft_launcher`), передаваемым снаружи в свойство `backend`. Читает свойства `javaCatalog` и
|
||||
`javaCatalogLoading`, вызывает `refreshJavaCatalog()`, `installJavaRuntime()` и
|
||||
`removeJavaRuntime()`.
|
||||
|
||||
Объявлен в `QML_FILES` модуля (`CMakeLists.txt`); использует ресурс `images/Trash.svg`.
|
||||
Инстанцируется в диалоге настроек внутри [Main](Main.md) — сборка Java выбирается один раз для
|
||||
всего лаунчера, а не отдельно для каждой сборки Minecraft.
|
||||
|
||||
Каталог приходит из C++ уже отсортированным — новые сверху, скачанные первыми, — поэтому окно
|
||||
только отбирает записи и порядок не трогает. Запись каталога содержит поля `id`, `label`, `kind`
|
||||
(тип сборки), `major` (мажорная версия Java числом), `installed`, `downloadable`, `lts`, `sizeMb`,
|
||||
`detail`, `coverage` и `search`.
|
||||
|
||||
## Иерархия и роль
|
||||
|
||||
Корневой тип — `Dialog`: модальный, 720×480 px, нулевой внутренний отступ, закрывается по Escape и
|
||||
щелчку мимо, оформление тёмное со скруглением и акцентной рамкой.
|
||||
|
||||
Содержимое — `RowLayout` из колонки типов шириной 170 px и области версий, разделённых линией.
|
||||
Каждый пункт колонки типов показывает название и пояснение мелким шрифтом, а под списком типов —
|
||||
подсказка о требовании выбранной версии игры, видимая только когда это требование известно.
|
||||
|
||||
Область версий повторяет устройство окна выбора версии Minecraft: поле поиска сверху, флажок
|
||||
«Только скачанные» снизу, `ListView` между ними. Строка списка выше обычной (44 px), потому что
|
||||
содержит две строки текста: подпись сборки с меткой LTS и строку подробностей, где через точку
|
||||
собраны описание, покрытие версий игры, размер в мегабайтах и — при необходимости —
|
||||
предупреждение о том, что сборки не хватит.
|
||||
|
||||
Пустое состояние объясняется текстом по центру и различает загрузку каталога, отсутствие
|
||||
соединения и пустой результат поиска.
|
||||
|
||||
## Свойства
|
||||
|
||||
| Свойство | Тип | По умолчанию | Обязательное | Описание |
|
||||
|----------|-----|--------------|--------------|----------|
|
||||
| `backend` | `var` | — | **Да** | Экземпляр `LauncherBackend` — источник каталога Java, исполнитель установки и удаления. |
|
||||
| `selectedId` | `string` | `""` | Нет | Идентификатор выбранной сборки. Окно открывается с текущей сборкой, и по «Отмене» выбор возвращается к ней. |
|
||||
| `category` | `string` | `"java"` | Нет | Ключ активного типа сборок. Допустимые значения: `java` (сборки Mojang), `jdk` (Temurin с инструментами), `jre` (Temurin, только запуск). |
|
||||
| `filterText` | `string` | `""` | Нет | Текст поиска; сравнивается в нижнем регистре с полем `search` записи внутри активного типа. |
|
||||
| `installedOnly` | `bool` | `false` | Нет | Показывать только скачанные сборки. |
|
||||
| `requiredMajor` | `int` | `0` | Нет | Мажорная версия Java, ниже которой выбранной версии игры не запуститься. Значение `0` означает, что версия игры не выбрана и предупреждать не о чем: подсказка в колонке типов скрывается, пометка «слишком старая» не ставится. |
|
||||
| `categories` | `var` (только чтение) | список из трёх записей | Нет | Описание колонки типов: массив объектов с полями `key`, `title` и `hint`. Задаёт порядок пунктов и набор допустимых значений `category`. |
|
||||
| `visibleEntries` | `var` (только чтение) | вычисляется | Нет | Отобранные строки каталога: записи активного типа, прошедшие флажок «только скачанные» и текст поиска. Модель списка. |
|
||||
| `selectedEntry` | `var` (только чтение) | вычисляется | Нет | Полная запись выбранной сборки из каталога или `null`, если ничего не выбрано. Ищется по всему каталогу, а не по видимым строкам, поэтому выбор не теряется при смене фильтра. От неё зависят подпись в подвале и надпись на кнопке подтверждения. |
|
||||
|
||||
## Сигналы
|
||||
|
||||
#### runtimeChosen(string runtimeId)
|
||||
|
||||
Сборка Java подтверждена — кнопкой, двойным щелчком по строке или клавишей Enter в поле поиска. В
|
||||
параметре приходит идентификатор сборки.
|
||||
|
||||
Обработчик записывает выбранную сборку в настройки лаунчера — сборка Java общая для всех сборок
|
||||
Minecraft, а требование конкретной версии игры влияет только на пометки в списке. Сигнал испускается и для ещё не скачанной сборки — загрузка при
|
||||
этом начинается сама, и обработчику ждать её завершения не нужно.
|
||||
|
||||
## Методы
|
||||
|
||||
#### openFor(string runtimeId, int required) : void
|
||||
|
||||
Открывает окно на переданной сборке. Запоминает её в `selectedId`, выставляет `requiredMajor` из
|
||||
второго аргумента (отсутствующее или нулевое значение означает «требование неизвестно»), очищает
|
||||
поиск, переключается на тип именно этой сборки, просит бэкенд обновить каталог и прокручивает
|
||||
список к выбранной строке.
|
||||
|
||||
#### categoryOf(string runtimeId) : string
|
||||
|
||||
Возвращает тип сборки по каталогу; для неизвестного идентификатора — `java`.
|
||||
|
||||
#### indexOfSelected() : int
|
||||
|
||||
Позиция выбранной сборки в `visibleEntries` или `-1`, если под текущим фильтром её не видно.
|
||||
|
||||
#### revealSelected() : void
|
||||
|
||||
Выставляет текущий индекс списка на выбранную сборку и прокручивает список так, чтобы строка
|
||||
оказалась по центру.
|
||||
|
||||
#### acceptSelection() : void
|
||||
|
||||
Подтверждает выбор. Ничего не делает, если `selectedEntry` пуст. Иначе испускает
|
||||
`runtimeChosen()`, а затем — если сборка не установлена, но доступна для скачивания, — вызывает
|
||||
`installJavaRuntime()` у бэкенда и закрывает окно. Именно поэтому кнопка подтверждения называется
|
||||
«Скачать» для отсутствующей сборки и «Выбрать» для уже скачанной.
|
||||
|
||||
## Взаимодействие с другими компонентами
|
||||
|
||||
**Со стороны родителя.** Вызывающий код задаёт `backend`, открывает окно вызовом `openFor()` с
|
||||
текущей сборкой и требуемой мажорной версией Java (её отдаёт `requiredJavaMajor()` бэкенда) и
|
||||
подписывается на `runtimeChosen()`.
|
||||
|
||||
**Со стороны бэкенда.** `javaCatalog` и `javaCatalogLoading` — привязки, пересчитывающие модель и
|
||||
текст пустого состояния при каждом обновлении каталога. `refreshJavaCatalog()` вызывается при
|
||||
открытии окна, `installJavaRuntime()` — при подтверждении отсутствующей сборки,
|
||||
`removeJavaRuntime()` — по щелчку на корзине в строке. Ход самой загрузки окно не показывает: за
|
||||
это отвечает плашка [ProgressPanel](ProgressPanel.md) в главном окне.
|
||||
|
||||
**Удаление.** Корзина в строке доступна только у скачанных сборок; сборки весят по двести
|
||||
мегабайт, и удалять их нужно прямо здесь, иначе папка лаунчера растёт молча. Если удалена была
|
||||
выбранная сборка, выбор снимается.
|
||||
|
||||
**Слишком старые сборки.** Сборка ниже требования игры остаётся доступной для выбора, но
|
||||
помечается в строке подробностей: она может пригодиться для другой сборки Minecraft.
|
||||
|
||||
## Пример использования
|
||||
|
||||
```qml
|
||||
JavaPickerDialog {
|
||||
id: javaPicker
|
||||
x: (window.width - width) / 2
|
||||
y: (window.height - height) / 2
|
||||
backend: launcherBackend
|
||||
onRuntimeChosen: (runtimeId) => settingsDialog.javaRuntimeId = runtimeId
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: javaField
|
||||
onClicked: javaPicker.openFor(settingsDialog.javaRuntimeId,
|
||||
launcherBackend.requiredJavaMajor(launcherBackend.activeBuildIndex))
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
При создании этого документа использовался ИИ.
|
||||
@@ -0,0 +1,76 @@
|
||||
# LabelledField
|
||||
|
||||
## Обзор компонента
|
||||
|
||||
`Minecraft_launcher` — десктопный лаунчер Minecraft на Qt Quick с полностью самостоятельно
|
||||
оформленным тёмным интерфейсом. В диалоге настроек и в редакторе сборок много однотипных полей
|
||||
ввода: подпись сверху, поле под ней. `LabelledField` собирает эту пару в один компонент, чтобы
|
||||
отступы, цвета и подсветка фокуса не переписывались в каждом месте заново.
|
||||
|
||||
Компонент нужен там, где пользователь вводит короткое значение: имя профиля, объём памяти, путь,
|
||||
аргументы запуска.
|
||||
|
||||
## Место в проекте и зависимости
|
||||
|
||||
Импортирует `QtQuick` и `QtQuick.Controls 2.15`; C++-типы не используются.
|
||||
|
||||
Объявлен в `QML_FILES` модуля `Minecraft_launcher` (`CMakeLists.txt`) и доступен по имени внутри
|
||||
модуля без импорта. Применяется в диалоге настроек и в карточке сборки — см. [Main](Main.md) и
|
||||
[BuildsDialog](BuildsDialog.md).
|
||||
|
||||
## Иерархия и роль
|
||||
|
||||
Корневой тип — `Column` с расстоянием 3 px между элементами. Колонка содержит два потомка:
|
||||
`Text` с подписью (серый, 11 px) и `TextField` фиксированной высоты 32 px с тёмным фоном,
|
||||
скруглением 6 px и рамкой, которая при фокусе поля меняет цвет на акцентный.
|
||||
|
||||
Ширина поля привязана к ширине самой колонки, поэтому размер задаётся снаружи одним свойством
|
||||
`width` корневого элемента. Высоту `Column` вычисляет сам.
|
||||
|
||||
## Свойства
|
||||
|
||||
| Свойство | Тип | По умолчанию | Обязательное | Описание |
|
||||
|----------|-----|--------------|--------------|----------|
|
||||
| `text` | `string` (алиас на `text` внутреннего поля) | `""` | Нет | Содержимое поля ввода. Работает в обе стороны: чтение возвращает введённое значение, запись подставляет новое. |
|
||||
| `validator` | `var` (алиас на `validator` внутреннего поля) | `null` | Нет | Валидатор ввода — например `IntValidator` для числовых полей. Ограничивает то, что пользователь может набрать. |
|
||||
| `label` | `string` | `""` | Нет | Текст подписи над полем. |
|
||||
| `placeholder` | `string` | `""` | Нет | Подсказка, показываемая в пустом поле приглушённым цветом. |
|
||||
|
||||
## Сигналы
|
||||
|
||||
#### editingFinished()
|
||||
|
||||
Проброшен из внутреннего `TextField`: срабатывает, когда правка закончена — поле потеряло фокус
|
||||
или пользователь нажал Enter. Промежуточные нажатия клавиш сигнала не вызывают.
|
||||
|
||||
Обработчик обычно сохраняет введённое значение: читает `text` и передаёт его в бэкенд или в
|
||||
модель родительского диалога. Именно из-за этой семантики поля настроек сохраняются по завершении
|
||||
правки, а не на каждый символ.
|
||||
|
||||
## Методы
|
||||
|
||||
Собственных функций нет.
|
||||
|
||||
## Взаимодействие с другими компонентами
|
||||
|
||||
Компонент не знает ни о бэкенде, ни о содержащем его диалоге. Родитель задаёт `label`,
|
||||
`placeholder`, начальный `text` и при необходимости `validator`, а затем подписывается на
|
||||
`editingFinished`, чтобы записать значение. Двусторонней привязки к бэкенду внутри компонента нет
|
||||
— решение о том, когда и куда сохранять, целиком за родителем.
|
||||
|
||||
## Пример использования
|
||||
|
||||
```qml
|
||||
LabelledField {
|
||||
width: parent.width
|
||||
label: "Оперативная память, МБ"
|
||||
placeholder: "2048"
|
||||
text: String(settings.memoryMb)
|
||||
validator: IntValidator { bottom: 512; top: 32768 }
|
||||
onEditingFinished: settings.memoryMb = parseInt(text)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
При создании этого документа использовался ИИ.
|
||||
@@ -0,0 +1,150 @@
|
||||
# LoaderRow
|
||||
|
||||
## Обзор компонента
|
||||
|
||||
`Minecraft_launcher` — десктопный лаунчер Minecraft на Qt Quick. Кроме чистой игры он умеет
|
||||
ставить модлоадеры: Forge, Fabric, NeoForge и Quilt. В карточке сборки лоадер выбирается
|
||||
чекбоксом, а под ним — конкретная версия лоадера.
|
||||
|
||||
`LoaderRow` — одна такая строка: чекбокс с названием лоадера и, когда он отмечен, выпадающий
|
||||
список версий именно под выбранную версию Minecraft. Компонент берёт на себя всю возню со
|
||||
списком версий: подтягивает его из кэша, обновляет по сети, следит, чтобы выбранная версия
|
||||
всегда существовала под текущую версию игры, и словами объясняет случай «лоадер эту версию игры
|
||||
не поддерживает» вместо показа пустого списка.
|
||||
|
||||
Совместимость компонент не проверяет и проверять не должен: бэкенд отдаёт список, уже собранный
|
||||
под конкретную версию игры, поэтому несовместимой строки в нём не бывает. Пустой список — это и
|
||||
есть отсутствие поддержки.
|
||||
|
||||
## Место в проекте и зависимости
|
||||
|
||||
Импортирует `QtQuick` и `QtQuick.Controls 2.15`.
|
||||
|
||||
Использует компонент [DarkCombo](DarkCombo.md) из того же QML-модуля — выпадающий список версий в
|
||||
тёмном стиле окна.
|
||||
|
||||
Работает с C++-типом `LauncherBackend` (`launcherbackend.h`, зарегистрирован через `QML_ELEMENT`
|
||||
в модуле `Minecraft_launcher`), который передаётся снаружи в свойство `backend`. Из него
|
||||
компонент вызывает `loaderVersions()`, `refreshLoaderVersions()` и `loaderVersionsLoading()`, а
|
||||
также слушает сигнал `loaderVersionsChanged`.
|
||||
|
||||
Объявлен в `QML_FILES` модуля `Minecraft_launcher` (`CMakeLists.txt`). Инстанцируется в
|
||||
[BuildsDialog](BuildsDialog.md) — по одной строке на каждый поддерживаемый лоадер.
|
||||
|
||||
## Иерархия и роль
|
||||
|
||||
Корневой тип — `Column` с расстоянием 4 px. Внутри три потомка, видимость которых
|
||||
взаимоисключающая по нижней части:
|
||||
|
||||
- `CheckBox` с полностью переопределённым индикатором (квадрат со скруглением и галочкой) и
|
||||
подписью. Выключен, пока не выбрана версия игры.
|
||||
- [DarkCombo](DarkCombo.md) со списком версий лоадера — виден, только когда чекбокс отмечен и
|
||||
список непустой.
|
||||
- Текстовая строка на месте списка — видна, когда чекбокс отмечен, а список пуст. Пока идёт
|
||||
запрос, она серая и говорит о загрузке; когда запрос закончен, она красноватая и сообщает, что
|
||||
лоадер не поддерживает выбранную версию Minecraft.
|
||||
|
||||
Ширина внутренних элементов считается от ширины колонки, поэтому снаружи достаточно задать
|
||||
`width`.
|
||||
|
||||
## Свойства
|
||||
|
||||
| Свойство | Тип | По умолчанию | Обязательное | Описание |
|
||||
|----------|-----|--------------|--------------|----------|
|
||||
| `backend` | `var` | — | **Да** | Экземпляр `LauncherBackend`. Через него запрашиваются и обновляются списки версий лоадера. |
|
||||
| `loaderKey` | `string` | — | **Да** | Ключ лоадера, которым он опознаётся в бэкенде и в сохранённой сборке: `forge`, `fabric`, `neoforge`, `quilt`. |
|
||||
| `title` | `string` | — | **Да** | Человекочитаемое название лоадера рядом с чекбоксом; оно же подставляется в сообщения о загрузке и об отсутствии поддержки. |
|
||||
| `gameVersion` | `string` | `""` | Нет | Версия Minecraft, выбранная в карточке. Пустая строка выключает чекбокс. Смена значения сбрасывает выбранную версию лоадера и перезапрашивает список. |
|
||||
| `checked` | `bool` (алиас на чекбокс) | `false` | Нет | Отмечен ли лоадер. Чтение даёт текущее состояние, запись переключает чекбокс программно — без сигнала `userChecked()`. |
|
||||
| `selectedVersion` | `string` | `""` | Нет | Выбранная версия лоадера. Устанавливается только через `applyEntries()`, поэтому всегда либо пуста, либо присутствует в текущем списке. |
|
||||
| `entries` | `var` | `[]` | Нет | Текущий список версий лоадера — массив записей, у каждой есть поля `version` (значение) и `label` (подпись для списка). Заполняется из бэкенда. |
|
||||
| `applying` | `bool` | `false` | Нет | Признак того, что строку сейчас заполняет карточка данными сохранённой сборки. Пока он выставлен, изменения не считаются пользовательскими и сигнал `changed()` не испускается. |
|
||||
|
||||
## Сигналы
|
||||
|
||||
#### userChecked()
|
||||
|
||||
Пользователь сам отметил чекбокс (не программная установка `checked`). Карточка сборки в ответ
|
||||
снимает отметки с остальных строк лоадеров: одновременно в `.minecraft` может жить только один
|
||||
лоадер.
|
||||
|
||||
#### changed()
|
||||
|
||||
Отметка или версия лоадера изменились и это изменение пользовательское. Обработчик — карточка
|
||||
сборки — сохраняет сборку с новыми значениями.
|
||||
|
||||
Сигнал сознательно не испускается, пока выставлен `applying`, то есть при заполнении строки из
|
||||
уже сохранённой сборки: иначе загрузка карточки сразу же приводила бы к её перезаписи.
|
||||
|
||||
## Методы
|
||||
|
||||
#### versionIndex(string version) : int
|
||||
|
||||
Возвращает позицию версии в текущем массиве `entries` или `-1`, если такой версии в списке нет.
|
||||
Вспомогательная функция для синхронизации выбранного значения с выпадающим списком.
|
||||
|
||||
#### applyEntries(var list) : void
|
||||
|
||||
Единственное место, где меняются `entries` и `selectedVersion`. Через него проходят все три пути
|
||||
получения списка — кэш, ответ сети и заполнение из сохранённой сборки, — потому что выбранная
|
||||
версия обязана существовать в списке под текущую версию игры.
|
||||
|
||||
Записывает новый список, а затем проверяет выбранную версию: если её в списке нет, подставляет
|
||||
первую строку (список отсортирован новыми вперёд, поэтому первая — максимально доступная под эту
|
||||
версию игры) или пустую строку для пустого списка. Если подстановка изменила значение и строка не
|
||||
находится в режиме `applying`, испускает `changed()`. В конце синхронизирует `currentIndex`
|
||||
выпадающего списка.
|
||||
|
||||
#### reload() : void
|
||||
|
||||
Перезапрашивает список версий. Если лоадер не отмечен или версия игры не выбрана, очищает список
|
||||
через `applyEntries([])`. Иначе сначала берёт список из кэша бэкенда (`loaderVersions()`) — он
|
||||
появляется мгновенно, — а затем просит обновление по сети (`refreshLoaderVersions()`), результат
|
||||
которого придёт позже сигналом.
|
||||
|
||||
#### applyBuild(string loader, string loaderVersion) : void
|
||||
|
||||
Заполняет строку данными сохранённой сборки, не испуская `changed()`: на время работы выставляет
|
||||
`applying`. Отмечает чекбокс, если ключ лоадера сборки совпадает с `loaderKey`, подставляет версию
|
||||
из сборки как пожелание и вызывает `reload()`. Если под выбранную версию игры такой версии
|
||||
лоадера нет, `applyEntries()` заменит её на максимально доступную.
|
||||
|
||||
## Взаимодействие с другими компонентами
|
||||
|
||||
**Что приходит извне.** Карточка сборки в [BuildsDialog](BuildsDialog.md) задаёт `backend`,
|
||||
`loaderKey`, `title` и привязывает `gameVersion` к версии Minecraft, выбранной в карточке.
|
||||
Заполнение сохранённой сборкой идёт вызовом `applyBuild()` снаружи.
|
||||
|
||||
**Что уходит наружу.** По `userChecked()` карточка снимает отметки с остальных строк — набор
|
||||
строк она держит в собственном списке. По `changed()` карточка сохраняет сборку, читая `checked` и
|
||||
`selectedVersion`.
|
||||
|
||||
**Бэкенд.** Компонент сам подписан на сигнал `loaderVersionsChanged(key, game)` через
|
||||
`Connections`: пришедшее обновление принимается, только если ключ и версия игры совпадают с
|
||||
текущими и чекбокс отмечен, — иначе ответ относится к другой строке или устарел. Текст в пустом
|
||||
состоянии опрашивает `loaderVersionsLoading()`, чтобы отличать «ещё грузим» от «не поддерживается».
|
||||
|
||||
**Реакция на смену версии игры.** Обработчик `onGameVersionChanged` сбрасывает `selectedVersion` и
|
||||
вызывает `reload()`: сборка лоадера привязана к версии игры, поэтому под новой версией прежний
|
||||
выбор недействителен.
|
||||
|
||||
## Пример использования
|
||||
|
||||
```qml
|
||||
LoaderRow {
|
||||
id: forgeRow
|
||||
width: parent.width
|
||||
|
||||
backend: launcherBackend
|
||||
loaderKey: "forge"
|
||||
title: "Forge"
|
||||
gameVersion: buildCard.gameVersion
|
||||
|
||||
onUserChecked: buildCard.keepOnly(forgeRow)
|
||||
onChanged: buildCard.commitSelection()
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
При создании этого документа использовался ИИ.
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
# Main
|
||||
|
||||
## Обзор компонента
|
||||
|
||||
`Minecraft_launcher` — десктопный лаунчер Minecraft на Qt Quick. `Main.qml` — его главное и
|
||||
единственное настоящее окно: точка входа приложения, которую загружает `main.cpp` вызовом
|
||||
`engine.loadFromModule("Minecraft_launcher", "Main")`.
|
||||
|
||||
Окно совмещает четыре роли. Оно держит единственный экземпляр `LauncherBackend` — весь остальной
|
||||
интерфейс получает его от главного окна. Оно рисует сам экран запуска: фоновая картинка, большая
|
||||
кнопка игры по центру, выпадающий список профилей, кнопка активной сборки, кнопки папки модов,
|
||||
настроек и сезонных сборок. Оно показывает обратную связь — всплывающую плашку сообщений и две
|
||||
панели хода долгих операций. И наконец, оно объявляет диалоги, которые не вынесены в отдельные
|
||||
файлы: создание и редактирование профиля, ввод кода двухфакторной аутентификации и настройки
|
||||
запуска.
|
||||
|
||||
## Место в проекте и зависимости
|
||||
|
||||
Импортирует `QtQuick`, `QtQuick.Layouts 2.15`, `QtQuick.Controls 2.15` и сам QML-модуль проекта
|
||||
`Minecraft_launcher`, из которого приходит тип `LauncherBackend`.
|
||||
|
||||
Инстанцирует четыре компонента модуля: [ProgressPanel](ProgressPanel.md) (дважды),
|
||||
[SeasonalBuildsDialog](SeasonalBuildsDialog.md), [BuildsDialog](BuildsDialog.md),
|
||||
[JavaPickerDialog](JavaPickerDialog.md), а также [DarkCombo](DarkCombo.md) и
|
||||
[LabelledField](LabelledField.md) внутри своих диалогов.
|
||||
[MicrosoftLoginDialog](MicrosoftLoginDialog.md) создаётся динамически — см. ниже.
|
||||
|
||||
Стиль Qt Quick Controls принудительно выставлен в `Basic` в `main.cpp`, потому что нативные стили
|
||||
игнорируют пользовательские `contentItem` и `background`; поэтому в этом файле почти каждый
|
||||
элемент управления переопределяет своё оформление вручную.
|
||||
|
||||
Использует ресурсы из `RESOURCES` QML-модуля: фоновую картинку, три состояния кнопки запуска, по
|
||||
три состояния кнопок папки и настроек, стрелки выпадающих списков, `images/Trash.svg` и
|
||||
`images/Pencil.svg`.
|
||||
|
||||
## Иерархия и роль
|
||||
|
||||
Корневой тип — `Window` размером 1280×720 px, видимое при старте. Это не переиспользуемый
|
||||
компонент, а точка входа приложения, поэтому раздел с примером использования здесь неприменим.
|
||||
|
||||
Раскладка держится на якорях относительно центральной кнопки запуска: список профилей — слева
|
||||
сверху от неё, кнопка активной сборки — справа сверху, кнопки папки и настроек — под списком
|
||||
профилей. Кнопка сезонных сборок стоит в правом нижнем углу: это единственная свободная часть
|
||||
окна, потому что панели хода работ висят слева, а всё остальное собрано вокруг кнопки запуска.
|
||||
|
||||
Панели загрузки и смены сборки имеют одни и те же якоря — они взаимоисключающи по построению:
|
||||
признак занятости бэкенда не даёт начать переключение во время установки и наоборот. Панель смены
|
||||
сборки объявлена неотменяемой: отступать после очистки `.minecraft` некуда, операцию нужно довести
|
||||
до конца.
|
||||
|
||||
Заголовки и подвалы всех диалогов сделаны на `Item` с явным `implicitHeight`, а не на
|
||||
`Rectangle`: у прямоугольника `implicitHeight` равен нулю независимо от заданной высоты, и
|
||||
`Dialog` не смог бы вычислить свою полную высоту.
|
||||
|
||||
## Свойства
|
||||
|
||||
| Свойство | Тип | По умолчанию | Обязательное | Описание |
|
||||
|----------|-----|--------------|--------------|----------|
|
||||
| `microsoftLoginDialog` | `var` | `null` | Нет | Созданный по требованию экземпляр окна входа Microsoft либо `null`, пока вход ни разу не запускался. Хранится в свойстве, чтобы окно создавалось один раз за сеанс. |
|
||||
|
||||
### Внутренние диалоги и их состояние
|
||||
|
||||
`Main.qml` объявляет четыре диалога прямо в файле. Их свойства — часть состояния главного окна.
|
||||
|
||||
**Диалог редактирования профиля** (`editProfileDialog`):
|
||||
|
||||
| Свойство | Тип | По умолчанию | Описание |
|
||||
|----------|-----|--------------|----------|
|
||||
| `editIndex` | `int` | `-1` | Индекс редактируемого профиля; `-1` — диалог не открыт ни для кого. |
|
||||
| `msProfile` | `bool` | `false` | Открытый профиль имеет тип «Microsoft». |
|
||||
| `msLinked` | `bool` | `false` | У профиля есть действующая сессия Microsoft — от этого зависит строка статуса и подпись кнопки входа. |
|
||||
| `msName` | `string` | `""` | Ник, полученный при официальной авторизации. Показывается отдельным полем только для чтения, а не подменой поля логина: привязка сломалась бы первым же вводом в поле логина обычного профиля. |
|
||||
|
||||
**Диалог двухфакторной аутентификации** (`twoFactorDialog`):
|
||||
|
||||
| Свойство | Тип | По умолчанию | Описание |
|
||||
|----------|-----|--------------|----------|
|
||||
| `profileName` | `string` | `""` | Имя профиля, для которого запрошен код; подставляется в текст просьбы. |
|
||||
|
||||
**Диалог настроек** (`settingsDialog`):
|
||||
|
||||
| Свойство | Тип | По умолчанию | Описание |
|
||||
|----------|-----|--------------|----------|
|
||||
| `javaRuntimeId` | `string` | `""` | Выбранная сборка Java из папки лаунчера. Живёт в свойстве, а не в поле ввода: её выбирают в отдельном окне, а записывается она только по «Сохранить». Пустая строка означает «искать Java в системе». |
|
||||
| `javaRuntimeInfo` | `var` | `null` | Подробности выбранной сборки для строки поля. Не привязка: `javaRuntimeInfo()` — обычный вызов, и сам он не пересчитается, когда сборка докачается, поэтому значение обновляется по событиям. |
|
||||
|
||||
Типы профилей во всех выпадающих списках кодируются одинаково: позиция 0 — `offline`
|
||||
(офлайн, без пароля), 1 — `elyby` (Ely.by, с логином и паролем), 2 — `microsoft` (лицензия).
|
||||
Третья позиция показывается, только когда лаунчер собран с Qt WebEngine; в диалоге редактирования
|
||||
она показывается ещё и тогда, когда профиль уже сохранён как лицензионный — иначе в сборке без
|
||||
WebEngine он молча стал бы офлайновым.
|
||||
|
||||
## Сигналы
|
||||
|
||||
Собственных сигналов главное окно не объявляет.
|
||||
|
||||
## Методы
|
||||
|
||||
#### showToast(string text, color color, int timeout) : void
|
||||
|
||||
Показывает единую всплывающую плашку сообщений: через неё проходят сообщения о ходе запуска,
|
||||
ошибки и статус игры. Задаёт текст и цвет фона и перезапускает таймер скрытия.
|
||||
|
||||
Параметр `timeout` — время показа в миллисекундах. Пропущенное значение означает четыре секунды;
|
||||
`0` означает «держать до следующего сообщения» — так показываются промежуточные шаги запуска, чтобы
|
||||
сообщение не исчезало посреди долгой операции.
|
||||
|
||||
#### openMicrosoftLogin(url) : void
|
||||
|
||||
Открывает окно входа в аккаунт Microsoft на переданном адресе, создавая его при первом вызове.
|
||||
|
||||
Окно создаётся по требованию, а не вместе с главным: `MicrosoftLoginDialog.qml` попадает в модуль
|
||||
только в сборках с Qt WebEngine, и обычная декларация сломала бы всё главное окно в остальных.
|
||||
Поэтому компонент загружается через `Qt.createComponent()`, и если он не готов — сборка собрана без
|
||||
WebEngine, — вход отменяется у бэкенда, а пользователю показывается сообщение о том, что окно
|
||||
недоступно. При успешном создании окну сразу передаётся бэкенд, а его сигнал `failed`
|
||||
подключается к плашке сообщений.
|
||||
|
||||
#### formatMb(bytes) : string
|
||||
|
||||
Переводит байты в мегабайты с одним знаком после запятой. Используется в строке подробностей
|
||||
панели загрузки.
|
||||
|
||||
## Взаимодействие с другими компонентами
|
||||
|
||||
### Бэкенд
|
||||
|
||||
Единственный экземпляр `LauncherBackend` объявлен прямо в окне и передаётся всем вложенным
|
||||
диалогам через их свойство `backend`. Главное окно — единственное место, где обрабатываются его
|
||||
сигналы:
|
||||
|
||||
| Сигнал бэкенда | Что делает главное окно |
|
||||
|----------------|-------------------------|
|
||||
| `launched(profileName, buildName, serverUrl)` | показывает зелёное сообщение о запуске |
|
||||
| `launchProgress(message)` | показывает сообщение без таймаута — до следующего шага |
|
||||
| `launchError(message)` | показывает ошибку на восемь секунд |
|
||||
| `twoFactorRequired(profileName)` | открывает диалог ввода кода: Ely.by отклонил пароль с пометкой two factor, и код добирается здесь, чтобы продолжить прерванный запуск |
|
||||
| `gameFinished(exitCode, crashed)` | сообщает о закрытии игры; аварийное завершение показывается красным вместе с кодом выхода |
|
||||
| `microsoftLoginUrlReady(url)` | вызывает `openMicrosoftLogin()` |
|
||||
| `microsoftLoginSucceeded(playerName)` | сообщает об успешном входе. Выбор в списке профилей при этом не трогается: новый профиль уже выбран тем, кто его создал, а повторный вход мог быть и не в последний профиль |
|
||||
| `microsoftLoginFailed(message)` | показывает ошибку на восемь секунд |
|
||||
| `microsoftReloginRequired(profileIndex)` | сразу начинает вход заново для этого профиля |
|
||||
| `gameOutput(line)` | пишет строку в консоль |
|
||||
| `seasonalInstallFinished(seasonalId, buildName)` | сообщает, что сезонная сборка установлена и её можно запускать |
|
||||
| `javaRuntimeInstalled(runtimeId)` | обновляет подробности выбранной сборки Java в настройках |
|
||||
|
||||
Привязки к свойствам бэкенда управляют доступностью интерфейса: кнопка запуска выключена, пока
|
||||
лаунчер занят или игра уже идёт; кнопка активной сборки — пока идёт игра или переключение сборок;
|
||||
подпись на ней берётся из `activeBuildName`, а список профилей — из `profileNames`.
|
||||
|
||||
### Профили
|
||||
|
||||
Выпадающий список профилей переопределён целиком: кнопка «+ Добавить профиль» закреплена сверху
|
||||
всплывающей панели, под ней список, где у строки при наведении появляются карандаш и корзина.
|
||||
Карандаш открывает диалог редактирования (`openFor()` заполняет его через `profileAt()`), корзина
|
||||
вызывает `removeProfile()`.
|
||||
|
||||
Создание профиля вызывает `addProfile()`, выбирает новый профиль в списке и, если тип —
|
||||
«Microsoft», сразу начинает вход: такой профиль без входа бесполезен. Скрытые поля при сохранении
|
||||
не читаются — в них мог остаться текст, набранный до переключения типа профиля.
|
||||
|
||||
В диалоге редактирования кнопка входа перед вызовом `startMicrosoftLogin()` сначала сохраняет
|
||||
профиль вызовом `updateProfile()` с типом `microsoft`: тип мог быть только что переключён, и без
|
||||
этого бэкенд приписал бы токены профилю другого типа.
|
||||
|
||||
### Запуск игры
|
||||
|
||||
Кнопка запуска вызывает `launchGame()` с индексом выбранного профиля и индексом активной сборки.
|
||||
Дальше всё идёт через сигналы бэкенда: промежуточные шаги — в плашку сообщений, запрос кода
|
||||
двухфакторной аутентификации — в отдельный диалог, где подтверждение вызывает
|
||||
`submitTwoFactorCode()`, а отмена — `cancelPendingLaunch()`.
|
||||
|
||||
### Настройки
|
||||
|
||||
Диалог настроек открывается методом `load()`, который читает `settings()` бэкенда и раскладывает
|
||||
значения по полям, а также подставляет разрешённый путь папки игры и список найденных в системе
|
||||
сборок Java (`detectedJava()`). Сохранение собирает все поля в один `QVariantMap` и передаёт его
|
||||
в `updateSettings()`.
|
||||
|
||||
Первым пунктом диалога идёт выбор языка интерфейса — настройка уровня приложения, поэтому она
|
||||
стоит над параметрами запуска. Подписи в модели переводятся, а коды (`system`, `ru`, `en`) лежат
|
||||
рядом отдельным списком `codes` и не переводятся. Применяется язык по кнопке «Сохранить», как и
|
||||
всё остальное в этом диалоге, и сразу же, без перезапуска: см. [Localization](../cpp/Localization.md).
|
||||
|
||||
Разрешённый путь папки игры хранится свойством `resolvedGameDir` диалога, а не присваивается
|
||||
тексту напрямую — иначе подпись не пережила бы смену языка.
|
||||
|
||||
Поле выбора сборки Java открывает [JavaPickerDialog](JavaPickerDialog.md), передавая текущий выбор
|
||||
и требование активной сборки (`requiredJavaMajor()`); крестик справа сбрасывает выбор обратно на
|
||||
поиск Java в системе. Само окно выбора объявлено рядом с настройками, а не внутри них: оно шире и
|
||||
центрируется по окну лаунчера.
|
||||
|
||||
Выбранная сборка Java — общая настройка лаунчера: когда она задана, запуск идёт ею, а путь к Java
|
||||
из соседнего поля остаётся запасным вариантом.
|
||||
|
||||
### Тексты
|
||||
|
||||
Все подписи, сообщения и подсказки окна берутся из синглтона `Loc`: `Loc.t.домен.вид.имя`.
|
||||
Ни одного текстового литерала в разметке не осталось, `qsTr` не используется. Модель типов входа
|
||||
в диалогах профиля — тоже ключ каталога (`Loc.t.profile.authTypes`), причём порядок значений
|
||||
в нём значим: код сравнивает `currentIndex` с 1 и 2, а вариант без Microsoft получается из той же
|
||||
модели через `.slice(0, 2)`. Подробности — в [Localization](../cpp/Localization.md).
|
||||
|
||||
### Прочие кнопки
|
||||
|
||||
Кнопка папки вызывает `openMinecraftFolder()`, кнопка настроек открывает диалог настроек, кнопка
|
||||
сезонных сборок — [SeasonalBuildsDialog](SeasonalBuildsDialog.md) методом `openCatalog()`, кнопка
|
||||
активной сборки — [BuildsDialog](BuildsDialog.md).
|
||||
|
||||
---
|
||||
|
||||
При создании этого документа использовался ИИ.
|
||||
@@ -0,0 +1,121 @@
|
||||
# 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)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
При создании этого документа использовался ИИ.
|
||||
@@ -0,0 +1,90 @@
|
||||
# ProgressPanel
|
||||
|
||||
## Обзор компонента
|
||||
|
||||
`Minecraft_launcher` — десктопный лаунчер Minecraft на Qt Quick. Почти каждое действие в нём
|
||||
долгое: скачивание версии игры, установка Java, распаковка и архивация папки `.minecraft` при
|
||||
смене сборки, загрузка сезонной сборки. Лаунчер не блокирует окно на это время, поэтому ход
|
||||
операции нужно показывать неотрывно от остального интерфейса.
|
||||
|
||||
`ProgressPanel` — та самая плашка прогресса. Она размещается в левом нижнем углу главного окна,
|
||||
где не перекрывает кнопку запуска, сообщение по центру и кнопки папки и настроек. Компонент
|
||||
только отображает переданное состояние; сам он ничего не считает и ни за чем не следит.
|
||||
|
||||
## Место в проекте и зависимости
|
||||
|
||||
Импортирует `QtQuick` и `QtQuick.Controls 2.15`; C++-типы напрямую не использует.
|
||||
|
||||
Объявлен в `QML_FILES` модуля `Minecraft_launcher` (`CMakeLists.txt`), поэтому доступен по имени
|
||||
внутри модуля без импорта. Инстанцируется в [Main](Main.md) — по одной плашке на вид долгой
|
||||
операции.
|
||||
|
||||
## Иерархия и роль
|
||||
|
||||
Корневой тип — `Rectangle` фиксированного размера 320×72 px со скруглением 8 px, тёмной заливкой,
|
||||
акцентной рамкой и лёгкой полупрозрачностью, чтобы плашка читалась поверх фонового изображения
|
||||
окна.
|
||||
|
||||
Внутри — пять элементов без внешних зависимостей: заголовок слева сверху, проценты справа сверху,
|
||||
полоса прогресса (дорожка и заполнение с плавной анимацией ширины на 120 мс), строка подробностей
|
||||
снизу и крестик отмены в правом нижнем углу с увеличенной областью нажатия.
|
||||
|
||||
## Свойства
|
||||
|
||||
| Свойство | Тип | По умолчанию | Обязательное | Описание |
|
||||
|----------|-----|--------------|--------------|----------|
|
||||
| `title` | `string` | `""` | Нет | Заголовок операции в левом верхнем углу, полужирным. Длинный текст обрезается справа многоточием. |
|
||||
| `status` | `string` | `""` | Нет | Строка состояния внизу плашки. Показывается только когда `detail` пуст. |
|
||||
| `fraction` | `double` | `-1` | Нет | Доля выполнения от `0` до `1`. Значение `-1` означает «итог ещё неизвестен»: вместо процентов выводится многоточие, а полоса остаётся пустой. |
|
||||
| `detail` | `string` | `""` | Нет | Необязательная вторая строка подробностей — мегабайты у загрузки, путь у архивации. Если задана, вытесняет `status`. Длинный текст обрезается посередине, чтобы у пути были видны и начало, и конец. |
|
||||
| `cancellable` | `bool` | `true` | Нет | Показывать ли крестик отмены. Ставится в `false` для операций, которые прерывать нельзя. |
|
||||
|
||||
## Сигналы
|
||||
|
||||
#### cancelRequested()
|
||||
|
||||
Пользователь нажал крестик в правом нижнем углу. Сигнал сообщает только о намерении: плашка не
|
||||
скрывает себя и не меняет своё состояние.
|
||||
|
||||
Обработчик должен сам остановить операцию в бэкенде и убрать плашку с экрана — как правило, вызвав
|
||||
соответствующий метод отмены у `LauncherBackend`; видимость плашки при этом снимется сама, потому
|
||||
что она привязана к свойству занятости бэкенда.
|
||||
|
||||
Сигнал не испускается при `cancellable: false` — в этом случае крестик скрыт.
|
||||
|
||||
## Методы
|
||||
|
||||
Собственных функций нет.
|
||||
|
||||
## Взаимодействие с другими компонентами
|
||||
|
||||
Все пять свойств плашки — точки внешней привязки. В [Main](Main.md) они связаны со свойствами
|
||||
`LauncherBackend`: у загрузки версии это группа `downloading` / `downloadProgress` /
|
||||
`downloadVersion` / `downloadStatus` / `downloadBytesDone` / `downloadBytesTotal`, у смены сборки —
|
||||
`switching` / `switchProgress` / `switchStage` / `switchStatus`. Байты в мегабайты переводит
|
||||
функция `formatMb()` главного окна, а не сама плашка.
|
||||
|
||||
Видимостью плашки управляет родитель, обычно привязывая её к тому же признаку занятости, который
|
||||
питает `fraction`. Сигнал `cancelRequested` родитель замыкает на метод отмены бэкенда.
|
||||
|
||||
## Пример использования
|
||||
|
||||
```qml
|
||||
ProgressPanel {
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 16
|
||||
visible: backend.downloading
|
||||
|
||||
title: qsTr("Загрузка Minecraft %1").arg(backend.downloadVersion)
|
||||
status: backend.downloadStatus
|
||||
fraction: backend.downloadProgress
|
||||
detail: formatMb(backend.downloadBytesDone) + " / " + formatMb(backend.downloadBytesTotal)
|
||||
|
||||
onCancelRequested: backend.cancelDownload()
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
При создании этого документа использовался ИИ.
|
||||
@@ -0,0 +1,135 @@
|
||||
# SeasonalBuildsDialog
|
||||
|
||||
## Обзор компонента
|
||||
|
||||
`Minecraft_launcher` — десктопный лаунчер Minecraft на Qt Quick. Кроме сборок, которые
|
||||
пользователь собирает сам, он умеет ставить готовые сезонные сборки с сервера лаунчера: набор
|
||||
модов под конкретную версию игры и модлоадер, подготовленный заранее и выдаваемый целиком.
|
||||
|
||||
`SeasonalBuildsDialog` — окно этого каталога: таблица со всем, что нужно знать, чтобы решить,
|
||||
ставить сборку или нет, и одна кнопка, которая делает всё остальное — заводит сборку, ставит
|
||||
версию игры, модлоадер, Java и раскладывает файлы. Окно также показывает, что установленная
|
||||
сборка устарела, и предлагает обновить её до свежей ревизии.
|
||||
|
||||
Таблица собрана из строк `Row` с фиксированными колонками, а не из `TableView`: в проекте нет ни
|
||||
одной модели `QAbstractItemModel`, а строки приходят готовыми `QVariantMap` — заводить ради семи
|
||||
колонок отдельную модель незачем.
|
||||
|
||||
## Место в проекте и зависимости
|
||||
|
||||
В начале файла объявлена `pragma ComponentBehavior: Bound`. Импортирует `QtQuick` и
|
||||
`QtQuick.Controls 2.15` — слои `QtQuick.Layouts` здесь не нужны, вся раскладка на якорях и
|
||||
фиксированных ширинах колонок.
|
||||
|
||||
Работает с C++-типом `LauncherBackend` (`launcherbackend.h`, `QML_ELEMENT` в модуле
|
||||
`Minecraft_launcher`), передаваемым снаружи в свойство `backend`. Читает свойства
|
||||
`seasonalCatalog`, `seasonalCatalogLoading`, `seasonalCatalogError`, `seasonalInstalling` и `busy`,
|
||||
вызывает `refreshSeasonalCatalog()` и `installSeasonalBuild()`.
|
||||
|
||||
Объявлен в `QML_FILES` модуля (`CMakeLists.txt`). Инстанцируется в [Main](Main.md).
|
||||
|
||||
Строки каталога приходят из C++ уже отсортированными и сведёнными с локальными записями — окно
|
||||
показывает статус, не считая ничего само. Запись содержит поля `id`, `name`, `description`,
|
||||
`minecraftVersion`, `loaderTitle`, `loaderVersion`, `modCount`, `seasonStart`, `seasonEnd`,
|
||||
`status`, `revision`, `installedRevision`, `updateAvailable`, `sizeBytes` и `serverUrl`.
|
||||
|
||||
## Иерархия и роль
|
||||
|
||||
Корневой тип — `Dialog`: модальный, 960×560 px, нулевой внутренний отступ, тёмный фон со
|
||||
скруглением и акцентной рамкой.
|
||||
|
||||
Политика закрытия зависит от состояния: пока идёт установка, окно закрывается только кнопкой
|
||||
(`Popup.NoAutoClose`), потому что случайный щелчок мимо не должен спрятать единственную видимую
|
||||
отмену; в остальное время работают Escape и щелчок мимо.
|
||||
|
||||
Содержимое — шапка таблицы (`Row` с `Repeater` по `columns`), разделительная линия, список строк и
|
||||
сообщение по центру для пустого состояния. Строка списка — `Rectangle` высотой 36 px с вложенным
|
||||
`Row`, который повторяет тот же набор колонок; ширины берутся из общего описания `columns`,
|
||||
поэтому шапка и строки не могут разъехаться.
|
||||
|
||||
Подвал высотой 76 px несёт описание и размер выбранной сборки (они длинные и в таблицу не
|
||||
помещаются, а решение принимается именно по ним) и две кнопки — обновления списка и установки.
|
||||
|
||||
## Свойства
|
||||
|
||||
| Свойство | Тип | По умолчанию | Обязательное | Описание |
|
||||
|----------|-----|--------------|--------------|----------|
|
||||
| `backend` | `var` | — | **Да** | Экземпляр `LauncherBackend` — источник каталога сезонных сборок и исполнитель установки. |
|
||||
| `selectedId` | `string` | `""` | Нет | Идентификатор выбранной строки. Хранится по `id`, а не по индексу: список обновляется под руками, и индекс после обновления указывал бы на другую сборку. |
|
||||
| `columns` | `var` (только чтение) | список из семи колонок | Нет | Описание таблицы: массив объектов с полями `key` (поле записи), `title` (заголовок), `width` (ширина в пикселях) и `align` (выравнивание). Колонки: название, версия, загрузчик, число модов, начало и конец сезона, статус. Ширины собраны в одном месте, потому что их повторяют и шапка, и делегат строки. |
|
||||
| `entries` | `var` (только чтение) | `backend.seasonalCatalog` | Нет | Строки каталога напрямую из бэкенда. Отбора и сортировки в окне нет. |
|
||||
| `selectedEntry` | `var` (только чтение) | вычисляется | Нет | Полная запись выбранной сборки или `null`, если ничего не выбрано. От неё зависят подвал и доступность кнопки установки. |
|
||||
|
||||
## Сигналы
|
||||
|
||||
Собственных сигналов компонент не объявляет. Результат работы окна виден через состояние бэкенда:
|
||||
установка меняет список сборок и запускает загрузку, за ходом которой следит главное окно.
|
||||
|
||||
## Методы
|
||||
|
||||
#### openCatalog() : void
|
||||
|
||||
Открывает окно. Обновление каталога происходит само в обработчике `onAboutToShow`, который просит
|
||||
у бэкенда `refreshSeasonalCatalog(false)` — без принудительного обхода кэша: свежий кэш отвечает
|
||||
без сети, поэтому вызов при каждом открытии ничего не стоит.
|
||||
|
||||
#### formatMb(bytes) : string
|
||||
|
||||
Переводит размер в байтах в строку с мегабайтами и одним знаком после запятой. Для нулевого или
|
||||
отсутствующего значения возвращает пустую строку, чтобы размер просто не попал в строку подвала.
|
||||
|
||||
#### cellText(entry, string key) : string
|
||||
|
||||
Возвращает текст ячейки для записи и ключа колонки. Для всех колонок это значение одноимённого
|
||||
поля записи, приведённое к строке; исключение — колонка загрузчика, где название и версия
|
||||
склеиваются в одну подпись, а при пустой версии остаётся только название.
|
||||
|
||||
#### installSelected() : void
|
||||
|
||||
Ставит выбранную сборку. Ничего не делает, если строка не выбрана или лаунчер занят другой
|
||||
операцией: установка занимает и панель загрузки, и `.minecraft` целиком, поэтому вторую начинать
|
||||
нельзя. Иначе вызывает `installSeasonalBuild()` у бэкенда.
|
||||
|
||||
Вызывается кнопкой установки и двойным щелчком по строке.
|
||||
|
||||
## Взаимодействие с другими компонентами
|
||||
|
||||
**Со стороны родителя.** [Main](Main.md) задаёт `backend` и открывает окно вызовом
|
||||
`openCatalog()`. Обратной связи наружу через сигналы нет.
|
||||
|
||||
**Со стороны бэкенда.** Всё содержимое таблицы — привязка к `seasonalCatalog`, поэтому обновление
|
||||
каталога и изменение статуса установленной сборки перерисовывают окно сами. Пустое состояние
|
||||
различает три случая по `seasonalCatalogLoading` и `seasonalCatalogError`: идёт загрузка, сборок
|
||||
пока нет, произошла ошибка — её текст показывается прямо на месте строк, потому что пустой список
|
||||
и ошибка выглядят одинаково пустыми.
|
||||
|
||||
**Занятость.** Кнопка установки выключается по общему признаку `busy`, кнопка обновления списка —
|
||||
по `seasonalCatalogLoading` (её подпись при этом меняется на «Обновление…»). Политика закрытия
|
||||
окна завязана на `seasonalInstalling`.
|
||||
|
||||
**Обновление ревизии.** Если у записи выставлен `updateAvailable`, статус в таблице подсвечивается
|
||||
акцентным цветом, в подвале дописывается установленная ревизия, а кнопка установки называется
|
||||
«Обновить». Отдельного пути обновления нет — это тот же вызов `installSeasonalBuild()`.
|
||||
|
||||
**Ход установки.** Окно не показывает прогресс: за это отвечает плашка
|
||||
[ProgressPanel](ProgressPanel.md) в главном окне, а отмена — метод `cancelSeasonalInstall()`
|
||||
бэкенда.
|
||||
|
||||
## Пример использования
|
||||
|
||||
```qml
|
||||
SeasonalBuildsDialog {
|
||||
id: seasonalDialog
|
||||
parent: Overlay.overlay
|
||||
backend: launcherBackend
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("Сезонные сборки")
|
||||
onClicked: seasonalDialog.openCatalog()
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
При создании этого документа использовался ИИ.
|
||||
@@ -0,0 +1,158 @@
|
||||
# VersionPickerDialog
|
||||
|
||||
## Обзор компонента
|
||||
|
||||
`Minecraft_launcher` — десктопный лаунчер Minecraft на Qt Quick. Каталог версий Mojang — это около
|
||||
тысячи записей: релизы, снапшоты, старые беты и альфы. Раньше выбор версии был обычным выпадающим
|
||||
списком на всю эту тысячу, и найти в нём, скажем, бету 1.7 можно было только поиском по точному
|
||||
номеру.
|
||||
|
||||
`VersionPickerDialog` заменил тот список отдельным окном: слева категории, справа сами версии с
|
||||
поиском сверху. Категории делят каталог на обозримые части, а поиск работает внутри выбранной.
|
||||
Помимо выбора окно умеет удалять уже скачанные версии — с предупреждением о последствиях, потому
|
||||
что версия весит десятки мегабайт, а поверх неё могут стоять профили модлоадеров.
|
||||
|
||||
Окно открывается из карточки сборки, когда пользователь выбирает, на какой версии Minecraft
|
||||
собирается играть.
|
||||
|
||||
## Место в проекте и зависимости
|
||||
|
||||
В начале файла объявлена `pragma ComponentBehavior: Bound`. Импортирует `QtQuick`,
|
||||
`QtQuick.Controls 2.15` и `QtQuick.Layouts 2.15`.
|
||||
|
||||
Работает с C++-типом `LauncherBackend` (`launcherbackend.h`, `QML_ELEMENT` в модуле
|
||||
`Minecraft_launcher`), передаваемым снаружи в свойство `backend`. Читает у него свойства
|
||||
`versionCatalog` и `catalogLoading`, вызывает `refreshVersionCatalog()`, `versionRemovalInfo()` и
|
||||
`removeVersion()`.
|
||||
|
||||
Объявлен в `QML_FILES` модуля (`CMakeLists.txt`); использует ресурс `images/Trash.svg` из
|
||||
`RESOURCES` того же модуля. Инстанцируется в [BuildsDialog](BuildsDialog.md).
|
||||
|
||||
Каталог приходит из C++ уже отсортированным (новые сверху), поэтому окно только отбирает записи и
|
||||
порядок не трогает. Каждая запись каталога — объект с полями `id` (идентификатор версии), `label`
|
||||
(подпись строки), `category` (ключ категории), `installed` (скачана ли) и `search`
|
||||
(предвычисленная строка для поиска в нижнем регистре).
|
||||
|
||||
## Иерархия и роль
|
||||
|
||||
Корневой тип — `Dialog`: модальный, 720×480 px, нулевой внутренний отступ, закрывается по Escape и
|
||||
щелчку мимо. Оформление задано вручную — тёмный фон со скруглением и акцентной рамкой.
|
||||
|
||||
Содержимое — `RowLayout` из двух частей, разделённых вертикальной линией: колонка категорий
|
||||
шириной 150 px (`Repeater` по `categories`) и область версий. В области версий сверху поле поиска,
|
||||
внизу флажок «Только установленные», между ними `ListView` со строками версий. Строка показывает
|
||||
подпись, галочку для установленной версии и корзину удаления; галочка рядом со строкой —
|
||||
единственное место, где видно, что именно скачано.
|
||||
|
||||
Отдельно объявлен вложенный `Dialog` подтверждения удаления шириной 420 px с красной рамкой. Он
|
||||
привязан к тому же родителю, что и само окно, и центрируется в нём вручную, чтобы не оказаться
|
||||
внутри области выбора.
|
||||
|
||||
Пустое состояние списка объясняется текстом по центру, который различает три случая: каталог ещё
|
||||
грузится, каталог пуст (нет соединения) и по фильтру ничего не найдено.
|
||||
|
||||
## Свойства
|
||||
|
||||
| Свойство | Тип | По умолчанию | Обязательное | Описание |
|
||||
|----------|-----|--------------|--------------|----------|
|
||||
| `backend` | `var` | — | **Да** | Экземпляр `LauncherBackend` — источник каталога версий и исполнитель удаления. |
|
||||
| `selectedId` | `string` | `""` | Нет | Идентификатор выбранной версии. Окно открывается с текущей версией, и по «Отмене» выбор возвращается к ней, потому что результат уходит наружу только через сигнал. Пустая строка — версия не выбрана, кнопка подтверждения выключена. |
|
||||
| `category` | `string` | `"release"` | Нет | Ключ активной категории. Допустимые значения: `release` (релизы), `snapshot` (снапшоты), `old_beta` (беты), `old_alpha` (альфы), `other` (прочие — сюда попадают в том числе установленные профили модлоадеров). |
|
||||
| `filterText` | `string` | `""` | Нет | Текст поиска. Сравнивается в нижнем регистре без учёта регистра с полем `search` записи каталога; поиск идёт внутри активной категории. |
|
||||
| `installedOnly` | `bool` | `false` | Нет | Показывать только скачанные версии. |
|
||||
| `categories` | `var` (только чтение) | список из пяти записей | Нет | Описание колонки категорий: массив объектов с полями `key` и переведённым `title`. Задаёт и порядок пунктов, и набор допустимых значений `category`. |
|
||||
| `visibleEntries` | `var` (только чтение) | вычисляется | Нет | Отобранные строки каталога: записи активной категории, прошедшие флажок «только установленные» и текст поиска. Порядок наследуется от каталога. Служит моделью списка. |
|
||||
|
||||
## Сигналы
|
||||
|
||||
#### versionChosen(string versionId)
|
||||
|
||||
Версия подтверждена — кнопкой «Выбрать», двойным щелчком по строке или клавишей Enter в поле
|
||||
поиска. В параметре приходит идентификатор версии.
|
||||
|
||||
Имя не `accepted()` сознательно: такой сигнал у `Dialog` уже есть и переопределить его нельзя.
|
||||
|
||||
Обработчик — карточка сборки — записывает выбранную версию в сборку. К моменту вызова обработчика
|
||||
окно уже закрыто. При отмене сигнал не испускается, поэтому снаружи ничего откатывать не нужно.
|
||||
|
||||
## Методы
|
||||
|
||||
#### openFor(string versionId) : void
|
||||
|
||||
Открывает окно на переданной версии. Запоминает её в `selectedId`, очищает поиск, переключается на
|
||||
категорию именно этой версии (а не всегда на релизы), просит бэкенд обновить каталог и
|
||||
прокручивает список к выбранной строке.
|
||||
|
||||
#### categoryOf(string versionId) : string
|
||||
|
||||
Возвращает ключ категории версии по каталогу; для неизвестной версии — `release`.
|
||||
|
||||
#### indexOfSelected() : int
|
||||
|
||||
Позиция выбранной версии в `visibleEntries` или `-1`, если под текущим фильтром её не видно.
|
||||
|
||||
#### revealSelected() : void
|
||||
|
||||
Выставляет текущий индекс списка на выбранную версию и прокручивает список так, чтобы строка
|
||||
оказалась по центру. Вызывается после каждой смены фильтра, категории или удаления.
|
||||
|
||||
#### acceptSelection() : void
|
||||
|
||||
Подтверждает выбор: испускает `versionChosen()` и закрывает окно. При пустом `selectedId` не
|
||||
делает ничего.
|
||||
|
||||
#### catalogHas(string versionId) : bool
|
||||
|
||||
Есть ли версия в каталоге. Нужен после удаления: профиль модлоадера присутствовал в каталоге
|
||||
только потому, что был установлен, и после удаления строка исчезает совсем.
|
||||
|
||||
#### askRemove(string versionId) : void
|
||||
|
||||
Спрашивает подтверждение перед удалением. Запрашивает у бэкенда `versionRemovalInfo()` и, если
|
||||
версия действительно установлена, наполняет окно подтверждения: занимаемый объём, список
|
||||
зависящих профилей модлоадеров и список сборок, которые эту версию используют. Идентификатор
|
||||
запоминается в самом окне подтверждения, потому что к моменту ответа строка под курсором может
|
||||
быть уже другой.
|
||||
|
||||
Окно подтверждения объясняет три вещи: файлы удалятся из `versions/` и освободится столько-то
|
||||
мегабайт; профили модлоадеров поверх этой версии без неё не запустятся; библиотеки и ресурсы в
|
||||
`libraries/` и `assets/` общие для всех версий и остаются на месте.
|
||||
|
||||
#### performRemove(string versionId) : void
|
||||
|
||||
Удаляет версию через бэкенд. Если удалена была именно выбранная версия и её больше нет в каталоге,
|
||||
снимает выбор. В конце обновляет позицию списка.
|
||||
|
||||
## Взаимодействие с другими компонентами
|
||||
|
||||
**Со стороны родителя.** [BuildsDialog](BuildsDialog.md) задаёт `backend`, открывает окно вызовом
|
||||
`openFor()` с текущей версией сборки и подписывается на `versionChosen()`, чтобы записать выбор.
|
||||
Никаких других точек входа у окна нет — прямая запись `selectedId` снаружи не предполагается.
|
||||
|
||||
**Со стороны бэкенда.** `versionCatalog` и `catalogLoading` — привязки, от которых зависят и
|
||||
модель списка, и текст пустого состояния: пришедшее обновление каталога пересчитывает
|
||||
`visibleEntries` само. `refreshVersionCatalog()` вызывается при открытии окна, `removeVersion()` —
|
||||
после подтверждения удаления.
|
||||
|
||||
**Клавиатура.** Фокус при открытии уходит в поле поиска. Стрелки вверх и вниз двигают выбор по
|
||||
списку функцией `step()`, Enter подтверждает выбор, Escape закрывает окно.
|
||||
|
||||
## Пример использования
|
||||
|
||||
```qml
|
||||
VersionPickerDialog {
|
||||
id: versionPicker
|
||||
parent: Overlay.overlay
|
||||
backend: launcherBackend
|
||||
onVersionChosen: (versionId) => buildCard.gameVersion = versionId
|
||||
}
|
||||
|
||||
Button {
|
||||
text: buildCard.gameVersion || qsTr("Выбрать версию")
|
||||
onClicked: versionPicker.openFor(buildCard.gameVersion)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
При создании этого документа использовался ИИ.
|
||||
Reference in New Issue
Block a user