import QtQuick import QtQuick.Controls 2.15 // Один модлоадер в карточке сборки: чекбокс и, когда он отмечен, список версий // именно под выбранную версию Minecraft. // // Совместимость проверять не нужно: backend.loaderVersions() отдаёт список уже // под конкретную версию игры, поэтому несовместимой строки в нём не бывает. // Пустой список — это «лоадер не поддерживает эту версию игры», и он тоже // показывается словами, а не пустым выпадающим списком. Column { id: loaderRow required property var backend required property string loaderKey required property string title // Версия Minecraft, выбранная в карточке. Её смена сбрасывает выбор. property string gameVersion: "" property alias checked: box.checked property string selectedVersion: "" property var entries: [] // Пользователь щёлкнул чекбокс — карточка снимет отметки с остальных // лоадеров: одновременно в .minecraft может жить только один. signal userChecked() // Отметка или версия изменились — карточке пора сохранить сборку. signal changed() // Ставится, пока карточка заполняет строку данными сборки: в это время // обработчики не должны считать изменения пользовательскими. property bool applying: false spacing: 4 function versionIndex(version) { for (var i = 0; i < loaderRow.entries.length; ++i) { if (loaderRow.entries[i].version === version) return i } return -1 } // Самая свежая стабильная сборка, а если стабильных нет — просто самая // свежая. Список отсортирован новыми вперёд, поэтому хватает первого // совпадения. function preferredIndex() { for (var i = 0; i < loaderRow.entries.length; ++i) { if (loaderRow.entries[i].recommended) return i } for (var j = 0; j < loaderRow.entries.length; ++j) { if (loaderRow.entries[j].stable) return j } return loaderRow.entries.length > 0 ? 0 : -1 } function syncCombo() { const index = loaderRow.versionIndex(loaderRow.selectedVersion) combo.currentIndex = index } function reload() { if (!box.checked || loaderRow.gameVersion === "") { loaderRow.entries = [] return } // Сначала из кэша — список появляется мгновенно, — потом обновление сети. loaderRow.entries = loaderRow.backend.loaderVersions(loaderRow.loaderKey, loaderRow.gameVersion) loaderRow.syncCombo() loaderRow.backend.refreshLoaderVersions(loaderRow.loaderKey, loaderRow.gameVersion) } // Заполнение из сохранённой сборки: без сигналов changed(). function applyBuild(loader, loaderVersion) { loaderRow.applying = true box.checked = loader === loaderRow.loaderKey loaderRow.selectedVersion = box.checked ? loaderVersion : "" loaderRow.reload() loaderRow.applying = false } onGameVersionChanged: { // Сборка лоадера привязана к версии игры — при её смене выбор // сбрасывается, и список перезапрашивается под новую версию. loaderRow.entries = [] loaderRow.selectedVersion = "" combo.currentIndex = -1 loaderRow.reload() } Connections { target: loaderRow.backend function onLoaderVersionsChanged(key, game) { if (key !== loaderRow.loaderKey || game !== loaderRow.gameVersion || !box.checked) return loaderRow.entries = loaderRow.backend.loaderVersions(key, game) if (loaderRow.selectedVersion === "" || loaderRow.versionIndex(loaderRow.selectedVersion) < 0) { const preferred = loaderRow.preferredIndex() if (preferred >= 0) { loaderRow.selectedVersion = loaderRow.entries[preferred].version if (!loaderRow.applying) loaderRow.changed() } } loaderRow.syncCombo() } } CheckBox { id: box text: loaderRow.title enabled: loaderRow.gameVersion !== "" indicator: Rectangle { implicitWidth: 18 implicitHeight: 18 x: 0 y: (box.height - height) / 2 radius: 4 color: box.checked ? "#91B315" : "#2a2a2a" border.color: box.checked ? "#91B315" : "#444444" border.width: 1 Text { anchors.centerIn: parent visible: box.checked text: "✓" color: "#1e1e1e" font.pixelSize: 13 font.bold: true } } contentItem: Text { leftPadding: box.indicator.width + 8 text: box.text color: box.enabled ? "#ffffff" : "#666666" font.pixelSize: 12 verticalAlignment: Text.AlignVCenter } onToggled: { if (box.checked) loaderRow.userChecked() else loaderRow.selectedVersion = "" loaderRow.reload() loaderRow.changed() } } DarkCombo { id: combo visible: box.checked && loaderRow.entries.length > 0 width: loaderRow.width - 26 height: 32 x: 26 model: loaderRow.entries.map(entry => entry.label) onActivated: (index) => { if (index < 0 || index >= loaderRow.entries.length) return loaderRow.selectedVersion = loaderRow.entries[index].version loaderRow.changed() } } Text { visible: box.checked && loaderRow.entries.length === 0 x: 26 width: loaderRow.width - 26 wrapMode: Text.Wrap font.pixelSize: 11 color: loaderRow.backend.loaderVersionsLoading(loaderRow.loaderKey, loaderRow.gameVersion) ? "#888888" : "#cc6666" text: loaderRow.backend.loaderVersionsLoading(loaderRow.loaderKey, loaderRow.gameVersion) ? qsTr("Загрузка списка версий %1…").arg(loaderRow.title) : qsTr("%1 не поддерживает Minecraft %2").arg(loaderRow.title) .arg(loaderRow.gameVersion) } }