From 966cd46049a373a6e55405b3d626366c6d73e5db Mon Sep 17 00:00:00 2001 From: galeon Date: Tue, 16 Jun 2026 12:16:59 +0300 Subject: [PATCH] added editing for profiles\versions --- CMakeLists.txt | 4 +- Main.qml | 347 +++++++++++++++++++++++++++++++++++++++++++- images/Pencil.svg | 4 + launcherbackend.cpp | 37 +++++ launcherbackend.h | 5 + 5 files changed, 393 insertions(+), 4 deletions(-) create mode 100644 images/Pencil.svg diff --git a/CMakeLists.txt b/CMakeLists.txt index 553a0d6..7a4e939 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,8 +19,8 @@ qt_add_qml_module(appMinecraft_launcher launcherbackend.cpp QML_FILES Main.qml - RESOURCES images/Folder/Folder_Active.svg images/Folder/Folder_Idle.svg images/Folder/Folder_Pressed.svg images/Options/Options_active.svg images/Options/Options_Idle.svg images/Options/Options_Pressed.svg images/Play_Button/Play_Active.svg images/Play_Button/Play_Idle.svg images/Play_Button/Play_pressed.svg images/Profile_Box/Asset_23.svg images/Profile_Box/Asset_24.svg images/Profile_Box/Kishka_Profile_Active.svg images/Profile_Box/Kishka_Profile_Idle.svg images/Profile_Box/Kishka_Profile_open.svg images/Scroll/Scroll_Lever.svg images/Scroll/Scroll_palka.svg images/Version_box/Kishka_Profile_Open.svg images/Version_box/Kishka_Ver_Active.svg images/Version_box/Kishka_Ver_idle.svg images/Trash.svg images/GovuztTW8AAHqBf.jpeg images/photo_2025-12-16_15-04-17.jpg images/photo_2025-12-21_02-30-09.jpg - RESOURCES images/Folder/Folder_Active.svg images/Folder/Folder_Idle.svg images/Folder/Folder_Pressed.svg images/Options/Options_active.svg images/Options/Options_Idle.svg images/Options/Options_Pressed.svg images/Play_Button/Play_Active.svg images/Play_Button/Play_Idle.svg images/Play_Button/Play_pressed.svg images/Profile_Box/Asset_23.jpg images/Profile_Box/Asset_23.svg images/Profile_Box/Asset_24.jpg images/Profile_Box/Asset_24.svg images/Profile_Box/Kishka_Profile_Active.svg images/Profile_Box/Kishka_Profile_Idle.svg images/Profile_Box/Kishka_Profile_open.svg images/Scroll/Scroll_Lever.svg images/Scroll/Scroll_palka.svg images/Version_box/Kishka_Profile_Open.svg images/Version_box/Kishka_Ver_Active.svg images/Version_box/Kishka_Ver_idle.svg images/Trash.svg images/GovuztTW8AAHqBf.jpeg images/photo_2025-12-16_15-04-17.jpg images/photo_2025-12-21_02-30-09.jpg + RESOURCES images/Folder/Folder_Active.svg images/Folder/Folder_Idle.svg images/Folder/Folder_Pressed.svg images/Options/Options_active.svg images/Options/Options_Idle.svg images/Options/Options_Pressed.svg images/Play_Button/Play_Active.svg images/Play_Button/Play_Idle.svg images/Play_Button/Play_pressed.svg images/Profile_Box/Asset_23.svg images/Profile_Box/Asset_24.svg images/Profile_Box/Kishka_Profile_Active.svg images/Profile_Box/Kishka_Profile_Idle.svg images/Profile_Box/Kishka_Profile_open.svg images/Scroll/Scroll_Lever.svg images/Scroll/Scroll_palka.svg images/Version_box/Kishka_Profile_Open.svg images/Version_box/Kishka_Ver_Active.svg images/Version_box/Kishka_Ver_idle.svg images/Trash.svg images/Pencil.svg images/GovuztTW8AAHqBf.jpeg images/photo_2025-12-16_15-04-17.jpg images/photo_2025-12-21_02-30-09.jpg + RESOURCES images/Folder/Folder_Active.svg images/Folder/Folder_Idle.svg images/Folder/Folder_Pressed.svg images/Options/Options_active.svg images/Options/Options_Idle.svg images/Options/Options_Pressed.svg images/Play_Button/Play_Active.svg images/Play_Button/Play_Idle.svg images/Play_Button/Play_pressed.svg images/Profile_Box/Asset_23.jpg images/Profile_Box/Asset_23.svg images/Profile_Box/Asset_24.jpg images/Profile_Box/Asset_24.svg images/Profile_Box/Kishka_Profile_Active.svg images/Profile_Box/Kishka_Profile_Idle.svg images/Profile_Box/Kishka_Profile_open.svg images/Scroll/Scroll_Lever.svg images/Scroll/Scroll_palka.svg images/Version_box/Kishka_Profile_Open.svg images/Version_box/Kishka_Ver_Active.svg images/Version_box/Kishka_Ver_idle.svg images/Trash.svg images/Pencil.svg images/GovuztTW8AAHqBf.jpeg images/photo_2025-12-16_15-04-17.jpg images/photo_2025-12-21_02-30-09.jpg ) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. diff --git a/Main.qml b/Main.qml index de6892a..1264e80 100644 --- a/Main.qml +++ b/Main.qml @@ -190,7 +190,7 @@ Window { horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter leftPadding: 8 - rightPadding: 36 + rightPadding: 62 } background: Rectangle { color: (profileBox.currentIndex === profileItem.index || profileItem.hovered) @@ -202,6 +202,28 @@ Window { profileBox.popup.close() } + // ── Карандаш — видна при наведении на строку ──── + Image { + id: profilePencil + width: 16; height: 16 + anchors.right: profileTrash.left + anchors.rightMargin: 12 + anchors.verticalCenter: parent.verticalCenter + visible: profileItem.hovered + opacity: profilePencilArea.containsMouse ? 1.0 : 0.7 + source: "images/Pencil.svg" + sourceSize.width: 16; sourceSize.height: 16 + fillMode: Image.PreserveAspectFit + + MouseArea { + id: profilePencilArea + anchors.fill: parent + anchors.margins: -6 + hoverEnabled: true + onClicked: editProfileDialog.openFor(profileItem.index) + } + } + // ── Корзина — видна при наведении на строку ───── Image { id: profileTrash @@ -354,7 +376,7 @@ Window { horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter leftPadding: 8 - rightPadding: 36 + rightPadding: 62 } background: Rectangle { color: (versionBox.currentIndex === versionItem.index || versionItem.hovered) @@ -366,6 +388,28 @@ Window { versionBox.popup.close() } + // ── Карандаш — видна при наведении на строку ──── + Image { + id: versionPencil + width: 16; height: 16 + anchors.right: versionTrash.left + anchors.rightMargin: 12 + anchors.verticalCenter: parent.verticalCenter + visible: versionItem.hovered + opacity: versionPencilArea.containsMouse ? 1.0 : 0.7 + source: "images/Pencil.svg" + sourceSize.width: 16; sourceSize.height: 16 + fillMode: Image.PreserveAspectFit + + MouseArea { + id: versionPencilArea + anchors.fill: parent + anchors.margins: -6 + hoverEnabled: true + onClicked: editVersionDialog.openFor(versionItem.index) + } + } + // ── Корзина — видна при наведении на строку ───── Image { id: versionTrash @@ -680,4 +724,303 @@ Window { verName.text = ""; verServer.text = "" } } + + // ── Edit Profile Dialog ──────────────────────────────────────────────── + // Идентичен диалогу создания, но с предзаполненными данными выбранного + // профиля. По нажатию ОК данные перезаписываются под тем же индексом. + Dialog { + id: editProfileDialog + modal: true + width: 320 + x: (window.width - width) / 2 + y: (window.height - height) / 2 + padding: 0 + + property int editIndex: -1 + + function openFor(index) { + const data = backend.profileAt(index) + editIndex = index + epName.text = data.name || "" + epLogin.text = data.login || "" + epPassword.text = data.password || "" + profileBox.popup.close() + open() + } + + background: Rectangle { + color: "#1e1e1e" + radius: 10 + border.color: "#91B315" + border.width: 1 + } + + header: Item { + implicitHeight: 52 + Text { + anchors.centerIn: parent + text: "Редактирование профиля" + color: "#ffffff" + font.pixelSize: 17 + font.bold: true + } + Rectangle { + anchors.bottom: parent.bottom + width: parent.width + height: 1 + color: "#333333" + } + } + + contentItem: Column { + spacing: 12 + topPadding: 20 + bottomPadding: 20 + + TextField { + id: epName + x: 20 + width: parent.width - 40 + placeholderText: "Имя профиля" + color: "#ffffff" + placeholderTextColor: "#666666" + background: Rectangle { + color: "#2a2a2a" + radius: 6 + border.color: epName.activeFocus ? "#91B315" : "#444444" + border.width: 1 + } + } + + TextField { + id: epLogin + x: 20 + width: parent.width - 40 + placeholderText: "Логин" + color: "#ffffff" + placeholderTextColor: "#666666" + background: Rectangle { + color: "#2a2a2a" + radius: 6 + border.color: epLogin.activeFocus ? "#91B315" : "#444444" + border.width: 1 + } + } + + TextField { + id: epPassword + x: 20 + width: parent.width - 40 + placeholderText: "Пароль" + echoMode: TextInput.Password + color: "#ffffff" + placeholderTextColor: "#666666" + background: Rectangle { + color: "#2a2a2a" + radius: 6 + border.color: epPassword.activeFocus ? "#91B315" : "#444444" + border.width: 1 + } + } + } + + footer: Item { + implicitHeight: 60 + Rectangle { + anchors.top: parent.top + width: parent.width + height: 1 + color: "#333333" + } + Row { + anchors.centerIn: parent + spacing: 12 + + Button { + text: "Отмена" + 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: editProfileDialog.reject() + } + + Button { + text: "ОК" + width: 110; height: 36 + contentItem: Text { + text: parent.text + color: "#ffffff" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + background: Rectangle { + color: parent.pressed ? "#6a8510" : "#91B315" + radius: 6 + } + onClicked: editProfileDialog.accept() + } + } + } + + onAccepted: { + const name = epName.text.trim() + if (editIndex >= 0 && name !== "") + backend.updateProfile(editIndex, name, epLogin.text.trim(), epPassword.text) + editIndex = -1 + epName.text = ""; epLogin.text = ""; epPassword.text = "" + } + onRejected: { + editIndex = -1 + epName.text = ""; epLogin.text = ""; epPassword.text = "" + } + } + + // ── Edit Version Dialog ──────────────────────────────────────────────── + // Идентичен диалогу создания, но с предзаполненными данными выбранной + // версии. По нажатию ОК данные перезаписываются под тем же индексом. + Dialog { + id: editVersionDialog + modal: true + width: 320 + x: (window.width - width) / 2 + y: (window.height - height) / 2 + padding: 0 + + property int editIndex: -1 + + function openFor(index) { + const data = backend.versionAt(index) + editIndex = index + evName.text = data.name || "" + evServer.text = data.serverUrl || "" + versionBox.popup.close() + open() + } + + background: Rectangle { + color: "#1e1e1e" + radius: 10 + border.color: "#91B315" + border.width: 1 + } + + header: Item { + implicitHeight: 52 + Text { + anchors.centerIn: parent + text: "Редактирование версии" + color: "#ffffff" + font.pixelSize: 17 + font.bold: true + } + Rectangle { + anchors.bottom: parent.bottom + width: parent.width + height: 1 + color: "#333333" + } + } + + contentItem: Column { + spacing: 12 + topPadding: 20 + bottomPadding: 20 + + TextField { + id: evName + x: 20 + width: parent.width - 40 + placeholderText: "Название версии" + color: "#ffffff" + placeholderTextColor: "#666666" + background: Rectangle { + color: "#2a2a2a" + radius: 6 + border.color: evName.activeFocus ? "#91B315" : "#444444" + border.width: 1 + } + } + + TextField { + id: evServer + x: 20 + width: parent.width - 40 + placeholderText: "URL сервера загрузки" + color: "#ffffff" + placeholderTextColor: "#666666" + background: Rectangle { + color: "#2a2a2a" + radius: 6 + border.color: evServer.activeFocus ? "#91B315" : "#444444" + border.width: 1 + } + } + } + + footer: Item { + implicitHeight: 60 + Rectangle { + anchors.top: parent.top + width: parent.width + height: 1 + color: "#333333" + } + Row { + anchors.centerIn: parent + spacing: 12 + + Button { + text: "Отмена" + 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: editVersionDialog.reject() + } + + Button { + text: "ОК" + width: 110; height: 36 + contentItem: Text { + text: parent.text + color: "#ffffff" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + background: Rectangle { + color: parent.pressed ? "#6a8510" : "#91B315" + radius: 6 + } + onClicked: editVersionDialog.accept() + } + } + } + + onAccepted: { + const name = evName.text.trim() + if (editIndex >= 0 && name !== "") + backend.updateVersion(editIndex, name, evServer.text.trim()) + editIndex = -1 + evName.text = ""; evServer.text = "" + } + onRejected: { + editIndex = -1 + evName.text = ""; evServer.text = "" + } + } } diff --git a/images/Pencil.svg b/images/Pencil.svg new file mode 100644 index 0000000..c74fff9 --- /dev/null +++ b/images/Pencil.svg @@ -0,0 +1,4 @@ + + + + diff --git a/launcherbackend.cpp b/launcherbackend.cpp index b8b61c5..6203eb3 100644 --- a/launcherbackend.cpp +++ b/launcherbackend.cpp @@ -46,6 +46,43 @@ void LauncherBackend::addVersion(const QString &name, const QString &serverUrl) emit versionsChanged(); } +void LauncherBackend::updateProfile(int index, const QString &name, const QString &login, const QString &password) +{ + if (index < 0 || index >= m_profiles.size()) + return; + m_profiles[index].name = name; + m_profiles[index].login = login; + m_profiles[index].password = password; + saveProfiles(); + emit profilesChanged(); +} + +void LauncherBackend::updateVersion(int index, const QString &name, const QString &serverUrl) +{ + if (index < 0 || index >= m_versions.size()) + return; + m_versions[index].name = name; + m_versions[index].serverUrl = serverUrl; + saveVersions(); + emit versionsChanged(); +} + +QVariantMap LauncherBackend::profileAt(int index) const +{ + if (index < 0 || index >= m_profiles.size()) + return {}; + const auto &p = m_profiles[index]; + return {{"name", p.name}, {"login", p.login}, {"password", p.password}}; +} + +QVariantMap LauncherBackend::versionAt(int index) const +{ + if (index < 0 || index >= m_versions.size()) + return {}; + const auto &v = m_versions[index]; + return {{"name", v.name}, {"serverUrl", v.serverUrl}}; +} + void LauncherBackend::removeProfile(int index) { if (index < 0 || index >= m_profiles.size()) diff --git a/launcherbackend.h b/launcherbackend.h index 5035c8f..34bbec4 100644 --- a/launcherbackend.h +++ b/launcherbackend.h @@ -2,6 +2,7 @@ #include #include +#include #include class LauncherBackend : public QObject @@ -20,6 +21,10 @@ public: Q_INVOKABLE void addProfile(const QString &name, const QString &login, const QString &password); Q_INVOKABLE void addVersion(const QString &name, const QString &serverUrl); + Q_INVOKABLE void updateProfile(int index, const QString &name, const QString &login, const QString &password); + Q_INVOKABLE void updateVersion(int index, const QString &name, const QString &serverUrl); + Q_INVOKABLE QVariantMap profileAt(int index) const; + Q_INVOKABLE QVariantMap versionAt(int index) const; Q_INVOKABLE void removeProfile(int index); Q_INVOKABLE void removeVersion(int index); Q_INVOKABLE void launchGame(int profileIndex, int versionIndex);