builds fixes
This commit is contained in:
@@ -0,0 +1,413 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 2.15
|
||||
|
||||
// Выбор версии Minecraft отдельным окном: слева категории, справа сами версии
|
||||
// с поиском сверху.
|
||||
//
|
||||
// Раньше это был выпадающий список на всю тысячу версий: найти в нём бету 1.7
|
||||
// можно было только поиском по точному номеру. Категории делят список на
|
||||
// обозримые части, а поиск работает внутри выбранной.
|
||||
Dialog {
|
||||
id: picker
|
||||
|
||||
required property var backend
|
||||
|
||||
// Версия, с которой окно открылось: по «Отмене» выбор к ней и возвращается.
|
||||
property string selectedId: ""
|
||||
property string category: "release"
|
||||
property string filterText: ""
|
||||
property bool installedOnly: false
|
||||
|
||||
// Выбранная версия подтверждена кнопкой или двойным щелчком. Имя не
|
||||
// accepted(): такой сигнал у Dialog уже есть, и переопределить его нельзя.
|
||||
signal versionChosen(string versionId)
|
||||
|
||||
modal: true
|
||||
padding: 0
|
||||
width: 720
|
||||
height: 480
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
|
||||
background: Rectangle {
|
||||
color: "#1e1e1e"
|
||||
radius: 10
|
||||
border.color: "#91B315"
|
||||
border.width: 1
|
||||
}
|
||||
|
||||
readonly property var categories: [
|
||||
{ key: "release", title: qsTr("Релизы") },
|
||||
{ key: "snapshot", title: qsTr("Снапшоты") },
|
||||
{ key: "old_beta", title: qsTr("Беты") },
|
||||
{ key: "old_alpha", title: qsTr("Альфы") },
|
||||
{ key: "other", title: qsTr("Прочие") }
|
||||
]
|
||||
|
||||
// Каталог приходит из C++ уже отсортированным (новые сверху), поэтому здесь
|
||||
// только отбор — порядок не трогаем.
|
||||
readonly property var visibleEntries: {
|
||||
const query = picker.filterText.trim().toLowerCase()
|
||||
const source = picker.backend.versionCatalog
|
||||
const out = []
|
||||
for (var i = 0; i < source.length; ++i) {
|
||||
const entry = source[i]
|
||||
if (entry.category !== picker.category)
|
||||
continue
|
||||
if (picker.installedOnly && !entry.installed)
|
||||
continue
|
||||
if (query !== "" && entry.search.indexOf(query) === -1)
|
||||
continue
|
||||
out.push(entry)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
function openFor(versionId) {
|
||||
picker.selectedId = versionId
|
||||
picker.filterText = ""
|
||||
searchField.text = ""
|
||||
// Открываемся на категории текущей версии, а не всегда на релизах.
|
||||
picker.category = picker.categoryOf(versionId)
|
||||
picker.backend.refreshVersionCatalog()
|
||||
picker.open()
|
||||
picker.revealSelected()
|
||||
}
|
||||
|
||||
function categoryOf(versionId) {
|
||||
const source = picker.backend.versionCatalog
|
||||
for (var i = 0; i < source.length; ++i) {
|
||||
if (source[i].id === versionId)
|
||||
return source[i].category
|
||||
}
|
||||
return "release"
|
||||
}
|
||||
|
||||
function indexOfSelected() {
|
||||
const list = picker.visibleEntries
|
||||
for (var i = 0; i < list.length; ++i) {
|
||||
if (list[i].id === picker.selectedId)
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
function revealSelected() {
|
||||
const index = picker.indexOfSelected()
|
||||
versionList.currentIndex = index
|
||||
if (index >= 0)
|
||||
versionList.positionViewAtIndex(index, ListView.Center)
|
||||
}
|
||||
|
||||
function acceptSelection() {
|
||||
if (picker.selectedId === "")
|
||||
return
|
||||
picker.versionChosen(picker.selectedId)
|
||||
picker.close()
|
||||
}
|
||||
|
||||
header: Item {
|
||||
implicitHeight: 52
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Версия Minecraft")
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 17
|
||||
font.bold: true
|
||||
}
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: "#333333"
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: 0
|
||||
|
||||
// ── Категории ───────────────────────────────────────────────────
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 150
|
||||
Layout.fillHeight: true
|
||||
color: "transparent"
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
spacing: 2
|
||||
|
||||
Repeater {
|
||||
model: picker.categories
|
||||
|
||||
delegate: Rectangle {
|
||||
id: categoryRow
|
||||
required property var modelData
|
||||
|
||||
width: parent.width
|
||||
height: 34
|
||||
radius: 5
|
||||
color: picker.category === categoryRow.modelData.key ? "#91B315"
|
||||
: categoryArea.containsMouse ? "#2d2d2d" : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: categoryRow.modelData.title
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 13
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: categoryArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
picker.category = categoryRow.modelData.key
|
||||
picker.revealSelected()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 1
|
||||
Layout.fillHeight: true
|
||||
color: "#333333"
|
||||
}
|
||||
|
||||
// ── Версии ──────────────────────────────────────────────────────
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
TextField {
|
||||
id: searchField
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 8
|
||||
height: 32
|
||||
placeholderText: qsTr("Поиск версии…")
|
||||
color: "#ffffff"
|
||||
placeholderTextColor: "#666666"
|
||||
background: Rectangle {
|
||||
color: "#232323"
|
||||
radius: 5
|
||||
border.color: searchField.activeFocus ? "#91B315" : "#444444"
|
||||
border.width: 1
|
||||
}
|
||||
onTextChanged: {
|
||||
picker.filterText = text
|
||||
versionList.currentIndex = picker.indexOfSelected()
|
||||
}
|
||||
Keys.onEscapePressed: picker.close()
|
||||
Keys.onReturnPressed: picker.acceptSelection()
|
||||
Keys.onEnterPressed: picker.acceptSelection()
|
||||
Keys.onDownPressed: versionList.step(1)
|
||||
Keys.onUpPressed: versionList.step(-1)
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: installedOnlyBox
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 8
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 4
|
||||
height: 28
|
||||
checked: picker.installedOnly
|
||||
onToggled: {
|
||||
picker.installedOnly = checked
|
||||
picker.revealSelected()
|
||||
}
|
||||
|
||||
indicator: Rectangle {
|
||||
implicitWidth: 16
|
||||
implicitHeight: 16
|
||||
x: 0
|
||||
y: (installedOnlyBox.height - height) / 2
|
||||
radius: 4
|
||||
color: installedOnlyBox.checked ? "#91B315" : "#2a2a2a"
|
||||
border.color: installedOnlyBox.checked ? "#91B315" : "#444444"
|
||||
border.width: 1
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: installedOnlyBox.checked
|
||||
text: "✓"
|
||||
color: "#1e1e1e"
|
||||
font.pixelSize: 12
|
||||
font.bold: true
|
||||
}
|
||||
}
|
||||
contentItem: Text {
|
||||
leftPadding: installedOnlyBox.indicator.width + 8
|
||||
text: qsTr("Только установленные")
|
||||
color: "#aaaaaa"
|
||||
font.pixelSize: 11
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: versionList
|
||||
anchors.top: searchField.bottom
|
||||
anchors.topMargin: 6
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: installedOnlyBox.top
|
||||
anchors.leftMargin: 8
|
||||
anchors.rightMargin: 8
|
||||
clip: true
|
||||
spacing: 1
|
||||
model: picker.visibleEntries
|
||||
ScrollIndicator.vertical: ScrollIndicator {}
|
||||
|
||||
function step(delta) {
|
||||
const next = versionList.currentIndex + delta
|
||||
if (next < 0 || next >= versionList.count)
|
||||
return
|
||||
versionList.currentIndex = next
|
||||
versionList.positionViewAtIndex(next, ListView.Contain)
|
||||
picker.selectedId = picker.visibleEntries[next].id
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
id: versionRow
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
width: versionList.width
|
||||
height: 32
|
||||
radius: 4
|
||||
color: picker.selectedId === versionRow.modelData.id ? "#91B315"
|
||||
: versionArea.containsMouse ? "#2d2d2d" : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
anchors.right: installedMark.left
|
||||
anchors.rightMargin: 6
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: versionRow.modelData.label
|
||||
color: "#ffffff"
|
||||
elide: Text.ElideRight
|
||||
font.pixelSize: 13
|
||||
}
|
||||
|
||||
Text {
|
||||
id: installedMark
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: versionRow.modelData.installed
|
||||
text: "✓"
|
||||
color: picker.selectedId === versionRow.modelData.id ? "#1e1e1e" : "#91B315"
|
||||
font.pixelSize: 13
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: versionArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
picker.selectedId = versionRow.modelData.id
|
||||
versionList.currentIndex = versionRow.index
|
||||
}
|
||||
onDoubleClicked: {
|
||||
picker.selectedId = versionRow.modelData.id
|
||||
picker.acceptSelection()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Пустая категория, ничего не нашлось или манифест ещё не пришёл.
|
||||
Text {
|
||||
anchors.centerIn: versionList
|
||||
width: versionList.width - 20
|
||||
visible: picker.visibleEntries.length === 0
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
color: "#888888"
|
||||
font.pixelSize: 12
|
||||
font.italic: true
|
||||
text: picker.backend.catalogLoading
|
||||
? qsTr("Загрузка списка версий…")
|
||||
: picker.backend.versionCatalog.length === 0
|
||||
? qsTr("Список версий недоступен — проверьте соединение")
|
||||
: qsTr("Ничего не найдено")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer: Item {
|
||||
implicitHeight: 60
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: "#333333"
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 20
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width - 300
|
||||
elide: Text.ElideRight
|
||||
color: picker.selectedId === "" ? "#666666" : "#91B315"
|
||||
font.pixelSize: 13
|
||||
text: picker.selectedId === "" ? qsTr("Версия не выбрана") : picker.selectedId
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 20
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 12
|
||||
|
||||
Button {
|
||||
text: qsTr("Отмена")
|
||||
width: 110; height: 36
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
color: "#ffffff"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
background: Rectangle {
|
||||
color: parent.pressed ? "#444444" : "#333333"
|
||||
radius: 6
|
||||
}
|
||||
onClicked: picker.close()
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("Выбрать")
|
||||
width: 110; height: 36
|
||||
enabled: picker.selectedId !== ""
|
||||
opacity: enabled ? 1.0 : 0.45
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
color: "#ffffff"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
background: Rectangle {
|
||||
color: parent.pressed ? "#6a8510" : "#91B315"
|
||||
radius: 6
|
||||
}
|
||||
onClicked: picker.acceptSelection()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onOpened: searchField.forceActiveFocus()
|
||||
}
|
||||
Reference in New Issue
Block a user