mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-05-30 02:49:12 -04:00
feat: Add message navigator
This commit is contained in:
@@ -27,6 +27,7 @@ qt_add_qml_module(QodeAssistChatView
|
|||||||
qml/controls/Toast.qml
|
qml/controls/Toast.qml
|
||||||
qml/controls/TopBar.qml
|
qml/controls/TopBar.qml
|
||||||
qml/controls/SplitDropZone.qml
|
qml/controls/SplitDropZone.qml
|
||||||
|
qml/controls/MessageNavigator.qml
|
||||||
|
|
||||||
RESOURCES
|
RESOURCES
|
||||||
icons/attach-file-light.svg
|
icons/attach-file-light.svg
|
||||||
|
|||||||
@@ -335,6 +335,16 @@ void ChatModel::resetModelTo(int index)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariantList ChatModel::userMessageIndices() const
|
||||||
|
{
|
||||||
|
QVariantList result;
|
||||||
|
for (int i = 0; i < m_messages.size(); ++i) {
|
||||||
|
if (m_messages[i].role == ChatRole::User)
|
||||||
|
result.append(i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void ChatModel::addToolExecutionStatus(
|
void ChatModel::addToolExecutionStatus(
|
||||||
const QString &requestId,
|
const QString &requestId,
|
||||||
const QString &toolId,
|
const QString &toolId,
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ public:
|
|||||||
QString lastMessageId() const;
|
QString lastMessageId() const;
|
||||||
|
|
||||||
Q_INVOKABLE void resetModelTo(int index);
|
Q_INVOKABLE void resetModelTo(int index);
|
||||||
|
Q_INVOKABLE QVariantList userMessageIndices() const;
|
||||||
|
|
||||||
void addToolExecutionStatus(
|
void addToolExecutionStatus(
|
||||||
const QString &requestId,
|
const QString &requestId,
|
||||||
|
|||||||
@@ -175,6 +175,27 @@ ChatRootView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
MessageNavigator {
|
||||||
|
id: messageNavigator
|
||||||
|
|
||||||
|
Layout.preferredWidth: 16
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.topMargin: 4
|
||||||
|
Layout.bottomMargin: 4
|
||||||
|
|
||||||
|
chatModel: root.chatModel
|
||||||
|
|
||||||
|
onMessageClicked: function(messageIndex) {
|
||||||
|
chatListView.userScrolledUp = true
|
||||||
|
chatListView.positionViewAtIndex(messageIndex, ListView.Beginning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: chatListView
|
id: chatListView
|
||||||
|
|
||||||
@@ -182,7 +203,7 @@ ChatRootView {
|
|||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
leftMargin: 5
|
leftMargin: 3
|
||||||
model: root.chatModel
|
model: root.chatModel
|
||||||
clip: true
|
clip: true
|
||||||
spacing: 0
|
spacing: 0
|
||||||
@@ -370,6 +391,7 @@ ChatRootView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ScrollView {
|
ScrollView {
|
||||||
id: view
|
id: view
|
||||||
|
|||||||
103
ChatView/qml/controls/MessageNavigator.qml
Normal file
103
ChatView/qml/controls/MessageNavigator.qml
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
// Copyright (C) 2024-2026 Petr Mironychev
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import ChatView
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: nav
|
||||||
|
|
||||||
|
property var chatModel
|
||||||
|
property var userIndices: []
|
||||||
|
property int hoveredDotIndex: -1
|
||||||
|
property color dotColor: "#92BD6C"
|
||||||
|
|
||||||
|
signal messageClicked(int messageIndex)
|
||||||
|
|
||||||
|
implicitWidth: 16
|
||||||
|
|
||||||
|
function rebuild() {
|
||||||
|
if (chatModel)
|
||||||
|
userIndices = chatModel.userMessageIndices()
|
||||||
|
else
|
||||||
|
userIndices = []
|
||||||
|
}
|
||||||
|
|
||||||
|
onChatModelChanged: rebuild()
|
||||||
|
Component.onCompleted: rebuild()
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: nav.chatModel
|
||||||
|
ignoreUnknownSignals: true
|
||||||
|
function onRowsInserted() { nav.rebuild() }
|
||||||
|
function onRowsRemoved() { nav.rebuild() }
|
||||||
|
function onModelReset() { nav.rebuild() }
|
||||||
|
function onModelReseted() { nav.rebuild() }
|
||||||
|
function onLayoutChanged() { nav.rebuild() }
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: spine
|
||||||
|
|
||||||
|
visible: nav.userIndices.length > 1
|
||||||
|
x: nav.width / 2 - width / 2
|
||||||
|
y: 14
|
||||||
|
width: 1
|
||||||
|
height: Math.max(0, nav.height - 28)
|
||||||
|
color: palette.mid
|
||||||
|
opacity: 0.4
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: nav.userIndices
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
id: dotItem
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
width: nav.width
|
||||||
|
height: 14
|
||||||
|
x: 0
|
||||||
|
y: {
|
||||||
|
const count = nav.userIndices.length
|
||||||
|
const dotH = height
|
||||||
|
if (count <= 1)
|
||||||
|
return (nav.height - dotH) / 2
|
||||||
|
const top = 7
|
||||||
|
const bottom = nav.height - dotH - 7
|
||||||
|
return top + (bottom - top) * index / (count - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: dot
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: dotArea.containsMouse ? 10 : 7
|
||||||
|
height: width
|
||||||
|
radius: width / 2
|
||||||
|
color: dotArea.containsMouse ? Qt.lighter(nav.dotColor, 1.15) : nav.dotColor
|
||||||
|
border.color: Qt.darker(nav.dotColor, 1.4)
|
||||||
|
border.width: 1
|
||||||
|
opacity: dotArea.containsMouse ? 1.0 : 0.9
|
||||||
|
|
||||||
|
Behavior on width { NumberAnimation { duration: 120 } }
|
||||||
|
Behavior on color { ColorAnimation { duration: 120 } }
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: dotArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: nav.messageClicked(dotItem.modelData)
|
||||||
|
|
||||||
|
ToolTip.visible: containsMouse
|
||||||
|
ToolTip.delay: 400
|
||||||
|
ToolTip.text: qsTr("Jump to message #%1").arg(dotItem.index + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user