add removal of chat sessions, auto title + icon, proper stick-to-bottom as response is streamed

This commit is contained in:
2026-08-20 17:40:33 +02:00
parent 47bab21e22
commit 9657e5092a
12 changed files with 776 additions and 273 deletions
+138 -28
View File
@@ -13,55 +13,165 @@ Item {
property alias model: list.model
signal deleteChatRequest(content: ChatSession)
signal loadChatRequest(content: ChatSession)
signal newChatRequest
CustomText {
id: header
anchors.left: parent.left
anchors.margins: Tokens.padding.extraSmall
anchors.right: parent.right
anchors.top: parent.top
color: Colors.palette.m3outline
font.family: "CaskaydiaCove NF"
font.pointSize: 13
font.weight: 500
text: qsTr("%1 Chat%2").arg(list.count).arg(list.count > 1 ? "s" : "")
}
CustomListView {
id: list
anchors.fill: parent
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.top: header.bottom
anchors.topMargin: Tokens.spacing.medium
cacheBuffer: height * 2
clip: true
spacing: Tokens.spacing.medium
delegate: CustomRect {
id: chatItem
delegate: Component {
Item {
id: chatItem
required property var modelData
property bool closing: false
property bool editVisible: false
required property var modelData
property real startY: 0.0
color: Colors.tPalette.m3surfaceContainer
implicitHeight: layout.implicitHeight + layout.anchors.topMargin + layout.anchors.bottomMargin
implicitWidth: ListView.view.width
radius: Tokens.rounding.medium
anchors.fill: undefined
implicitHeight: chat.layout.implicitHeight + chat.layout.anchors.topMargin + chat.layout.anchors.bottomMargin
implicitWidth: ListView.view.width
ColumnLayout {
id: layout
onEditVisibleChanged: if (!editVisible)
chat.x = 0
anchors.bottomMargin: Tokens.padding.small
anchors.fill: parent
anchors.leftMargin: Tokens.padding.medium
anchors.rightMargin: Tokens.padding.medium
anchors.topMargin: Tokens.padding.small
spacing: 0
ParallelAnimation {
id: removeAnim
CustomText {
id: title
onFinished: root.deleteChatRequest(chatItem.modelData)
onStarted: chatItem.closing = true
text: chatItem.modelData.title
Anim {
property: "implicitHeight"
target: chatItem
to: 0
}
Anim {
property: "x"
target: chat
to: -chat.implicitWidth
}
Anim {
property: "opacity"
target: chatItem
to: 0
}
}
CustomText {
id: timestamp
ChatDelegate {
id: chat
color: Colors.palette.m3outline
font.pointSize: Tokens.font.size.small
text: chatItem.modelData.updatedAt.toLocaleString(Qt.locale("en_US"), "MMM d, yyyy - h:mm AP")
implicitWidth: chatItem.implicitWidth
modelData: chatItem.modelData
radius: Tokens.rounding.medium
Behavior on x {
Anim {
}
}
Behavior on y {
Anim {
}
}
StateLayer {
cursorShape: drag.active ? Qt.ClosedHandCursor : Qt.PointingHandCursor
drag.axis: Drag.XAxis
drag.target: chat
hoverEnabled: true
preventStealing: true
onClicked: {
if (chatItem.editVisible)
chatItem.editVisible = false;
else
root.loadChatRequest(chatItem.modelData);
}
onPressed: event => {
chatItem.startY = event.y;
}
onReleased: event => {
if (chat.x > -(editTools.implicitWidth + Tokens.padding.extraSmall)) {
chat.x = 0;
} else {
chatItem.editVisible = true;
chat.x = -(editTools.implicitWidth + Tokens.spacing.medium + Tokens.padding.extraSmall);
}
}
}
}
}
StateLayer {
onClicked: {
root.loadChatRequest(chatItem.modelData);
CustomClippingRect {
anchors.left: chat.right
anchors.right: parent.right
anchors.rightMargin: Tokens.padding.extraSmall
anchors.verticalCenter: chat.verticalCenter
implicitHeight: editTools.implicitHeight
RowLayout {
id: editTools
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
IconButton {
id: deleteChatBtn
font.pointSize: Tokens.font.size.large
icon: "close"
radius: Tokens.rounding.full
transform: [
Scale {
property bool shouldBeActive: (chat.x < -deleteChatBtn.implicitWidth) && !chatItem.closing
origin.x: deleteChatBtn.implicitWidth / 2
origin.y: deleteChatBtn.implicitWidth / 2
xScale: shouldBeActive ? 1 : 0
yScale: shouldBeActive ? 1 : 0
Behavior on xScale {
Anim {
}
}
Behavior on yScale {
Anim {
}
}
}
]
onClicked: {
removeAnim.start();
}
}
}
}
}
}