# 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/`, поэтому отметка одного снимает остальные, а «ничего не отмечено» — это чистая ваниль. | Свойство панели | Тип | Описание | |-----------------|-----|----------| | `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() } ``` --- При создании этого документа использовался ИИ.