add removal of chat sessions, auto title + icon, proper stick-to-bottom as response is streamed
This commit is contained in:
@@ -17,10 +17,6 @@ Item {
|
||||
|
||||
signal requestClose
|
||||
|
||||
function atBottom(): bool {
|
||||
return list.contentHeight - list.height - list.contentY < 48;
|
||||
}
|
||||
|
||||
function send(): void {
|
||||
if (Chat.busy || input.text.trim() === "")
|
||||
return;
|
||||
@@ -29,30 +25,62 @@ Item {
|
||||
input.text = "";
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: header
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
spacing: Tokens.spacing.large
|
||||
|
||||
IconButton {
|
||||
icon: "arrow_back"
|
||||
inactiveColor: Colors.tPalette.m3surfaceContainerHigh
|
||||
inactiveOnColor: Colors.palette.m3onSurfaceVariant
|
||||
isRound: true
|
||||
type: IconButton.Tonal
|
||||
|
||||
onClicked: root.requestClose()
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: Tokens.font.size.larger
|
||||
text: qsTr(root.chatData.title)
|
||||
}
|
||||
}
|
||||
|
||||
VerticalFadeListView {
|
||||
id: list
|
||||
|
||||
readonly property real bottomThreshold: Tokens.spacing.extraSmall
|
||||
property bool stickToBottom: true
|
||||
|
||||
function scrollToEnd(animated: bool): void {
|
||||
const target = Math.max(0, list.contentHeight - list.height);
|
||||
if (!animated) {
|
||||
scrollAnim.stop();
|
||||
list.contentY = target;
|
||||
return;
|
||||
}
|
||||
scrollAnim.to = target;
|
||||
scrollAnim.restart();
|
||||
}
|
||||
|
||||
anchors.bottom: inputRow.top
|
||||
anchors.bottomMargin: Tokens.spacing.medium
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.top: header.bottom
|
||||
cacheBuffer: height * 20
|
||||
clip: true
|
||||
currentIndex: messages.values.length - 1
|
||||
fadeAmount: 0.1
|
||||
highlightFollowsCurrentItem: true
|
||||
highlightRangeMode: ListView.ApplyRange
|
||||
preferredHighlightEnd: list.height
|
||||
spacing: Tokens.spacing.medium
|
||||
|
||||
CustomScrollBar.vertical: CustomScrollBar {
|
||||
flickable: list
|
||||
}
|
||||
Behavior on contentY {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
delegate: ColumnLayout {
|
||||
id: messageRow
|
||||
|
||||
@@ -176,6 +204,7 @@ Item {
|
||||
anchors.top: parent.top
|
||||
color: messageRow.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
||||
text: messageRow.modelData.content
|
||||
textFormat: CustomText.MarkdownText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
@@ -204,7 +233,23 @@ Item {
|
||||
values: root.chatData.messages
|
||||
}
|
||||
|
||||
Component.onCompleted: positionViewAtEnd()
|
||||
Component.onCompleted: scrollToEnd(false)
|
||||
onContentHeightChanged: {
|
||||
if (list.stickToBottom)
|
||||
list.scrollToEnd(false);
|
||||
}
|
||||
onMovementEnded: {
|
||||
list.stickToBottom = (list.contentY >= list.contentHeight - list.height - list.bottomThreshold);
|
||||
}
|
||||
onMovementStarted: list.stickToBottom = false
|
||||
|
||||
Anim {
|
||||
id: scrollAnim
|
||||
|
||||
property: "contentY"
|
||||
target: list
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
@@ -236,6 +281,31 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
IconButton {
|
||||
id: scrollToBottom
|
||||
|
||||
anchors.bottom: inputRow.top
|
||||
anchors.bottomMargin: Tokens.spacing.extraLarge
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pointSize: Tokens.font.size.large
|
||||
icon: "arrow_downward"
|
||||
isRound: true
|
||||
padding: Tokens.padding.extraSmall
|
||||
scale: list.visibleArea.yPosition + list.visibleArea.heightRatio < 1 ? 1 : 0
|
||||
type: IconButton.Filled
|
||||
visible: scale > 0
|
||||
|
||||
Behavior on scale {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
list.stickToBottom = true;
|
||||
list.scrollToEnd(true);
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: inputRow
|
||||
|
||||
@@ -258,23 +328,12 @@ Item {
|
||||
id: actionBtn
|
||||
|
||||
enabled: Chat.busy || input.text.trim() !== ""
|
||||
font.pointSize: 20
|
||||
font.pointSize: Tokens.font.size.normal * 2
|
||||
icon: Chat.busy ? "stop" : "send"
|
||||
isRound: true
|
||||
type: IconButton.Filled
|
||||
|
||||
onClicked: Chat.busy ? Chat.stop() : root.send()
|
||||
}
|
||||
}
|
||||
|
||||
IconButton {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
icon: "arrow_back"
|
||||
inactiveColor: Colors.tPalette.m3surfaceContainerHigh
|
||||
inactiveOnColor: Colors.palette.m3onSurfaceVariant
|
||||
isRound: true
|
||||
type: IconButton.Tonal
|
||||
|
||||
onClicked: root.requestClose()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user