new builds menu and modloaders implementation
This commit is contained in:
+185
@@ -0,0 +1,185 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user