Revision control
Copy as Markdown
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Material
import chat_example
pragma ComponentBehavior: Bound
Item {
id: root
anchors.fill: parent
signal goBack();
onGoBack: {
conversationModel.clear()
messageField.clear()
OpenAIChatManager.customUserCharacter = ""
}
//! [0]
function editingFinished() {
var messageObject = {"name": "Me", "message": messageField.text };
conversationModel.append(messageObject);
OpenAIChatManager.userRequest = messageField.text;
OpenAIChatManager.sendUserRequest();
messageField.text = "";
}
//! [0]
ListModel {
id: conversationModel
}
Connections {
target: OpenAIChatManager
function onResponseReady(response) {
var responseMessage = {"name": OpenAIChatManager.modelName, "message": response };
conversationModel.append(responseMessage)
listView.positionViewAtEnd()
}
}
Item {
id: chatBgBorder
anchors.top: parent.top
anchors.topMargin: 20
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width * 0.93
height: parent.height * 0.70
Pane {
id: chatPane
anchors.fill: chatBgBorder
anchors.margins: 10
background: Rectangle {
radius: 10
color: Material.backgroundColor
}
ListView {
id: listView
anchors.fill: parent
verticalLayoutDirection: ListView.TopToBottom
spacing: 12
clip: true
model: conversationModel
delegate: Column {
id: columnElement
anchors.right: sentByMe ? listView.contentItem.right : undefined
anchors.left: !sentByMe ? listView.contentItem.left : undefined
spacing: 6
required property string name
required property string message
readonly property bool sentByMe: name === "Me"
Row {
id: messageRow
spacing: 6
anchors.right: columnElement.sentByMe ? parent.right : undefined
anchors.rightMargin: 30
anchors.left: !columnElement.sentByMe ? parent.left : undefined
anchors.leftMargin: 10
Rectangle {
width: Math.min(messageText.implicitWidth + 24,
listView.width - messageRow.spacing - 30)
height: messageText.implicitHeight + 24
color: "#1E1E1E"
radius: 10
gradient: Gradient {
GradientStop { position: 0.0; color: columnElement.sentByMe
? "#4A148C" : "#1C2B3A" }
GradientStop { position: 1.0; color: columnElement.sentByMe
? "#7B1FA2" : "#16222E" }
}
Behavior on gradient {
NumberAnimation { duration: 150 }
}
Label {
id: messageText
anchors.fill: parent
anchors.margins: 12
text: columnElement.message
font.pointSize: 16
wrapMode: Label.Wrap
}
}
}
}
ScrollBar.vertical: ScrollBar {
id: messagesScroll
width: 15
policy: ScrollBar.AsNeeded
contentItem: Rectangle {
radius: 10
color: messagesScroll.pressed ? "#1C2B3A" : "#16222E"
}
background: Rectangle {
color: "#2C2C2C"
radius: 9
}
}
}
}
}
Item {
id: editPanel
anchors.top: chatBgBorder.bottom
anchors.topMargin: 10
anchors.horizontalCenter: root.horizontalCenter
width: parent.width * 0.93 - 20
height: parent.height * 0.25 - backButton.height
ScrollView {
id: textBg
width: editPanel.width
height: editPanel.height
anchors.centerIn: parent
anchors.margins: 10
background: Rectangle {
color: "#1E1E1E"
radius: 10
gradient: Gradient {
GradientStop { position: 0.0; color: "#4A148C" }
GradientStop { position: 1.0; color: "#7B1FA2" }
}
Behavior on gradient {
NumberAnimation { duration: 150 }
}
}
TextArea {
id: messageField
font.pointSize: 16
placeholderText: qsTr("Enter your question")
wrapMode: TextArea.Wrap
Keys.onPressed: function(event) {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
if (event.modifiers === Qt.NoModifier) {
event.accepted = true
sendButton.click()
} else if (event.modifiers & Qt.ShiftModifier) {
event.accepted = false
}
}
}
}
}
}
Row {
id: buttonLayout
anchors.top: editPanel.bottom
anchors.horizontalCenter : parent.horizontalCenter
anchors.margins: 10
spacing: 100
Button {
id: backButton
text: qsTr("Back")
font.pointSize: 16
onClicked: {
root.goBack()
}
}
Button {
id: sendButton
text: qsTr("Send")
font.pointSize: 16
enabled: messageField.length > 0
onClicked: {
root.editingFinished();
listView.positionViewAtEnd()
}
}
}
}