From ca0a47b16053dce9d8f3451d4562f2f22ae051a1 Mon Sep 17 00:00:00 2001 From: Petr Mironychev <9195189+Palm1r@users.noreply.github.com> Date: Thu, 23 Apr 2026 01:48:17 +0200 Subject: [PATCH] feat: Improve Chat UI Move send and compress button to right bottom corner --- ChatView/qml/RootItem.qml | 22 +++++++-- ChatView/qml/controls/BottomBar.qml | 76 ++++++++++++++++++++++++----- ChatView/qml/controls/TopBar.qml | 53 -------------------- UIControls/CMakeLists.txt | 1 + UIControls/qml/QoABusyOverlay.qml | 43 ++++++++++++++++ 5 files changed, 128 insertions(+), 67 deletions(-) create mode 100644 UIControls/qml/QoABusyOverlay.qml diff --git a/ChatView/qml/RootItem.qml b/ChatView/qml/RootItem.qml index 9c2f3a0..3fbd0f9 100644 --- a/ChatView/qml/RootItem.qml +++ b/ChatView/qml/RootItem.qml @@ -62,7 +62,22 @@ ChatRootView { } } + QoABusyOverlay { + id: compressingOverlay + + z: 50 + + anchors.fill: mainColumn + anchors.topMargin: topBar.height + anchors.bottomMargin: bottomBar.height + + active: root.isCompressing + text: qsTr("Compressing chat…") + } + ColumnLayout { + id: mainColumn + anchors.fill: parent spacing: 0 @@ -72,12 +87,9 @@ ChatRootView { Layout.preferredWidth: parent.width Layout.preferredHeight: childrenRect.height + 10 - isCompressing: root.isCompressing saveButton.onClicked: root.showSaveDialog() loadButton.onClicked: root.showLoadDialog() clearButton.onClicked: root.clearChat() - compressButton.onClicked: compressConfirmDialog.open() - cancelCompressButton.onClicked: root.cancelCompression() tokensBadge { text: qsTr("%1/%2").arg(root.inputTokensCount).arg(root.chatModel.tokensThreshold) } @@ -477,12 +489,16 @@ ChatRootView { Layout.preferredWidth: parent.width Layout.preferredHeight: 40 + isCompressing: root.isCompressing sendButton.onClicked: !root.isRequestInProgress ? root.sendChatMessage() : root.cancelRequest() sendButton.icon.source: !root.isRequestInProgress ? "qrc:/qt/qml/ChatView/icons/chat-icon.svg" : "qrc:/qt/qml/ChatView/icons/chat-pause-icon.svg" + sendButton.text: !root.isRequestInProgress ? qsTr("Send") : qsTr("Stop") sendButton.ToolTip.text: !root.isRequestInProgress ? qsTr("Send message to LLM %1").arg(Qt.platform.os === "osx" ? "Cmd+Return" : "Ctrl+Return") : qsTr("Stop") + compressButton.onClicked: compressConfirmDialog.open() + cancelCompressButton.onClicked: root.cancelCompression() syncOpenFiles { checked: root.isSyncOpenFiles onCheckedChanged: root.setIsSyncOpenFiles(bottomBar.syncOpenFiles.checked) diff --git a/ChatView/qml/controls/BottomBar.qml b/ChatView/qml/controls/BottomBar.qml index 736828e..cc8a1a9 100644 --- a/ChatView/qml/controls/BottomBar.qml +++ b/ChatView/qml/controls/BottomBar.qml @@ -15,6 +15,10 @@ Rectangle { property alias attachFiles: attachFilesId property alias attachImages: attachImagesId property alias linkFiles: linkFilesId + property alias compressButton: compressButtonId + property alias cancelCompressButton: cancelCompressButtonId + + property bool isCompressing: false color: palette.window.hslLightness > 0.5 ? Qt.darker(palette.window, 1.1) : @@ -33,17 +37,6 @@ Rectangle { spacing: 10 - QoAButton { - id: sendButtonId - - icon { - height: 15 - width: 15 - } - ToolTip.visible: hovered - ToolTip.delay: 250 - } - QoAButton { id: attachFilesId @@ -95,5 +88,66 @@ Rectangle { Item { Layout.fillWidth: true } + + Row { + id: compressingRow + + visible: root.isCompressing + spacing: 6 + + BusyIndicator { + id: compressBusyIndicator + + anchors.verticalCenter: parent.verticalCenter + running: root.isCompressing + width: 16 + height: 16 + } + + Text { + text: qsTr("Compressing...") + anchors.verticalCenter: parent.verticalCenter + color: palette.text + font.pixelSize: 12 + } + + QoAButton { + id: cancelCompressButtonId + + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Cancel") + + ToolTip.visible: hovered + ToolTip.delay: 250 + ToolTip.text: qsTr("Cancel compression") + } + } + + QoAButton { + id: compressButtonId + + visible: !root.isCompressing + text: qsTr("Compress") + + icon { + source: "qrc:/qt/qml/ChatView/icons/compress-icon.svg" + height: 15 + width: 15 + } + ToolTip.visible: hovered + ToolTip.delay: 250 + ToolTip.text: qsTr("Compress chat (create summarized copy using LLM)") + } + + QoAButton { + id: sendButtonId + + icon { + height: 15 + width: 15 + } + ToolTip.visible: hovered + ToolTip.delay: 250 + } } } diff --git a/ChatView/qml/controls/TopBar.qml b/ChatView/qml/controls/TopBar.qml index ab1f69c..a783150 100644 --- a/ChatView/qml/controls/TopBar.qml +++ b/ChatView/qml/controls/TopBar.qml @@ -13,8 +13,6 @@ Rectangle { property alias saveButton: saveButtonId property alias loadButton: loadButtonId property alias clearButton: clearButtonId - property alias compressButton: compressButtonId - property alias cancelCompressButton: cancelCompressButtonId property alias tokensBadge: tokensBadgeId property alias recentPath: recentPathId property alias openChatHistory: openChatHistoryId @@ -26,8 +24,6 @@ Rectangle { property alias configSelector: configSelectorId property alias roleSelector: roleSelector - property bool isCompressing: false - color: palette.window.hslLightness > 0.5 ? Qt.darker(palette.window, 1.1) : Qt.lighter(palette.window, 1.1) @@ -242,55 +238,6 @@ Rectangle { QoASeparator {} - QoAButton { - id: compressButtonId - - visible: !root.isCompressing - - icon { - source: "qrc:/qt/qml/ChatView/icons/compress-icon.svg" - height: 15 - width: 15 - } - ToolTip.visible: hovered - ToolTip.delay: 250 - ToolTip.text: qsTr("Compress chat (create summarized copy using LLM)") - } - - Row { - id: compressingRow - - visible: root.isCompressing - spacing: 6 - - BusyIndicator { - id: compressBusyIndicator - - anchors.verticalCenter: parent.verticalCenter - running: root.isCompressing - width: 16 - height: 16 - } - - Text { - text: qsTr("Compressing...") - height: parent.height - color: palette.text - font.pixelSize: 12 - verticalAlignment: Text.AlignVCenter - } - - QoAButton { - id: cancelCompressButtonId - - text: qsTr("Cancel") - - ToolTip.visible: hovered - ToolTip.delay: 250 - ToolTip.text: qsTr("Cancel compression") - } - } - QoAButton { id: contextButtonId diff --git a/UIControls/CMakeLists.txt b/UIControls/CMakeLists.txt index c22c9ab..4864a3c 100644 --- a/UIControls/CMakeLists.txt +++ b/UIControls/CMakeLists.txt @@ -10,6 +10,7 @@ qt_add_qml_module(QodeAssistUIControls QML_FILES qml/Badge.qml qml/QoAButton.qml + qml/QoABusyOverlay.qml qml/QoATextSlider.qml qml/QoAComboBox.qml qml/FadeListItemAnimation.qml diff --git a/UIControls/qml/QoABusyOverlay.qml b/UIControls/qml/QoABusyOverlay.qml new file mode 100644 index 0000000..35cc269 --- /dev/null +++ b/UIControls/qml/QoABusyOverlay.qml @@ -0,0 +1,43 @@ +// Copyright (C) 2024-2026 Petr Mironychev +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Controls + +Rectangle { + id: root + + property alias text: label.text + property bool active: false + + visible: active + color: Qt.rgba(palette.window.r, palette.window.g, palette.window.b, 0.75) + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.AllButtons + hoverEnabled: true + preventStealing: true + onWheel: function(wheel) { wheel.accepted = true } + } + + Column { + anchors.centerIn: parent + spacing: 10 + + BusyIndicator { + anchors.horizontalCenter: parent.horizontalCenter + running: root.active + implicitWidth: 36 + implicitHeight: 36 + } + + Text { + id: label + + anchors.horizontalCenter: parent.horizontalCenter + color: palette.text + font.pixelSize: 13 + } + } +}