mirror of
				https://github.com/Palm1r/QodeAssist.git
				synced 2025-10-31 16:25:26 -04:00 
			
		
		
		
	feat: Add Chat preview scroll bar
This commit is contained in:
		| @ -17,6 +17,7 @@ qt_add_qml_module(QodeAssistChatView | ||||
|     qml/parts/TopBar.qml | ||||
|     qml/parts/BottomBar.qml | ||||
|     qml/parts/AttachedFilesPlace.qml | ||||
|     qml/parts/ChatPreviewBar.qml | ||||
|     RESOURCES | ||||
|     icons/attach-file-light.svg | ||||
|     icons/attach-file-dark.svg | ||||
|  | ||||
| @ -76,6 +76,10 @@ ChatRootView { | ||||
|                 text: qsTr("Latest chat file name: %1").arg(root.chatFileName.length > 0 ? root.chatFileName : "Unsaved") | ||||
|             } | ||||
|             openChatHistory.onClicked: root.openChatHistoryFolder() | ||||
|             expandScrollbar { | ||||
|                 text: scroll.isPreviewMode ? "»" : "«" | ||||
|                 onClicked: scroll.isPreviewMode = !scroll.isPreviewMode | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ListView { | ||||
| @ -114,6 +118,50 @@ ChatRootView { | ||||
|  | ||||
|             ScrollBar.vertical: QQC.ScrollBar { | ||||
|                 id: scroll | ||||
|  | ||||
|                 property bool isPreviewMode: false | ||||
|                 readonly property int previewWidth: 30 | ||||
|  | ||||
|                 implicitWidth: isPreviewMode ? scroll.previewWidth : 16 | ||||
|  | ||||
|                 contentItem: Rectangle { | ||||
|                     implicitWidth: scroll.isPreviewMode ? scroll.previewWidth : 6 | ||||
|                     implicitHeight: 100 | ||||
|                     radius: 3 | ||||
|                     color: scroll.pressed ? palette.dark : | ||||
|                                             scroll.hovered ? palette.mid : | ||||
|                                                              palette.button | ||||
|  | ||||
|                     Behavior on implicitWidth { | ||||
|                         NumberAnimation { duration: 150 } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 background: Rectangle { | ||||
|                     color: scroll.isPreviewMode ? "transparent" : | ||||
|                                                   palette.window.hslLightness > 0.5 ? | ||||
|                                                       Qt.darker(palette.window, 1.1) : | ||||
|                                                       Qt.lighter(palette.window, 1.1) | ||||
|                     radius: 3 | ||||
|                 } | ||||
|  | ||||
|                 ChatPreviewBar { | ||||
|                     anchors.fill: parent | ||||
|                     targetView: chatListView | ||||
|                     visible: parent.isPreviewMode | ||||
|                     opacity: parent.isPreviewMode ? 1 : 0 | ||||
|  | ||||
|                     Behavior on opacity { | ||||
|                         NumberAnimation { duration: 150 } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 Behavior on implicitWidth { | ||||
|                     NumberAnimation { | ||||
|                         duration: 150 | ||||
|                         easing.type: Easing.InOutQuad | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             onCountChanged: { | ||||
|  | ||||
							
								
								
									
										135
									
								
								ChatView/qml/parts/ChatPreviewBar.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								ChatView/qml/parts/ChatPreviewBar.qml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | ||||
| /* | ||||
|  * Copyright (C) 2025 Petr Mironychev | ||||
|  * | ||||
|  * This file is part of QodeAssist. | ||||
|  * | ||||
|  * QodeAssist is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * QodeAssist is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with QodeAssist. If not, see <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| import QtQuick | ||||
| import QtQuick.Controls | ||||
|  | ||||
| Rectangle { | ||||
|     id: root | ||||
|  | ||||
|     property ListView targetView: null | ||||
|     property int previewWidth: 50 | ||||
|     property color userMessageColor: "#92BD6C" | ||||
|     property color assistantMessageColor: palette.button | ||||
|  | ||||
|     width: previewWidth | ||||
|     color: palette.window.hslLightness > 0.5 ? | ||||
|            Qt.darker(palette.window, 1.1) : | ||||
|            Qt.lighter(palette.window, 1.1) | ||||
|  | ||||
|     Behavior on opacity { | ||||
|         NumberAnimation { | ||||
|             duration: 150 | ||||
|             easing.type: Easing.InOutQuad | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     Column { | ||||
|         id: previewContainer | ||||
|         anchors.fill: parent | ||||
|         anchors.margins: 2 | ||||
|         spacing: 2 | ||||
|  | ||||
|         Repeater { | ||||
|             model: targetView ? targetView.model : null | ||||
|  | ||||
|             Rectangle { | ||||
|                 required property int index | ||||
|                 required property var model | ||||
|  | ||||
|                 width: parent.width | ||||
|                 height: { | ||||
|                     if (!targetView || !targetView.count) return 0 | ||||
|                     const availableHeight = root.height - ((targetView.count - 1) * previewContainer.spacing) | ||||
|                     return availableHeight / targetView.count | ||||
|                 } | ||||
|  | ||||
|                 radius: 4 | ||||
|                 color: model.roleType === ChatModel.User ? | ||||
|                        userMessageColor : | ||||
|                        assistantMessageColor | ||||
|  | ||||
|                 opacity: root.opacity | ||||
|                 transform: Translate { | ||||
|                     x: root.opacity * 50 - 50 | ||||
|                 } | ||||
|  | ||||
|                 Behavior on transform { | ||||
|                     NumberAnimation { | ||||
|                         duration: 150 | ||||
|                         easing.type: Easing.InOutQuad | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 MouseArea { | ||||
|                     anchors.fill: parent | ||||
|                     onClicked: { | ||||
|                         if (targetView) { | ||||
|                             targetView.positionViewAtIndex(index, ListView.Center) | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     HoverHandler { | ||||
|                         id: hover | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 Rectangle { | ||||
|                     anchors.fill: parent | ||||
|                     color: palette.highlight | ||||
|                     opacity: hover.hovered ? 0.2 : 0 | ||||
|                     radius: parent.radius | ||||
|  | ||||
|                     Behavior on opacity { | ||||
|                         NumberAnimation { duration: 150 } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 Rectangle { | ||||
|                     anchors.fill: parent | ||||
|                     color: palette.highlight | ||||
|                     opacity: { | ||||
|                         if (!targetView) return 0 | ||||
|                         const viewY = targetView.contentY | ||||
|                         const viewHeight = targetView.height | ||||
|                         const totalHeight = targetView.contentHeight | ||||
|                         const itemPosition = index / targetView.count * totalHeight | ||||
|                         const itemHeight = totalHeight / targetView.count | ||||
|  | ||||
|                         return (itemPosition + itemHeight > viewY && | ||||
|                                 itemPosition < viewY + viewHeight) ? 0.2 : 0 | ||||
|                     } | ||||
|                     radius: parent.radius | ||||
|  | ||||
|                     Behavior on opacity { | ||||
|                         NumberAnimation { duration: 150 } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 ToolTip.visible: hover.hovered | ||||
|                 ToolTip.text: { | ||||
|                     const maxPreviewLength = 100 | ||||
|                     return model.content.length > maxPreviewLength ? | ||||
|                            model.content.substring(0, maxPreviewLength) + "..." : | ||||
|                            model.content | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -30,6 +30,7 @@ Rectangle { | ||||
|     property alias tokensBadge: tokensBadgeId | ||||
|     property alias recentPath: recentPathId | ||||
|     property alias openChatHistory: openChatHistoryId | ||||
|     property alias expandScrollbar: expandScrollbarId | ||||
|  | ||||
|     color: palette.window.hslLightness > 0.5 ? | ||||
|                Qt.darker(palette.window, 1.1) : | ||||
| @ -84,5 +85,12 @@ Rectangle { | ||||
|         Badge { | ||||
|             id: tokensBadgeId | ||||
|         } | ||||
|  | ||||
|         QoAButton { | ||||
|             id: expandScrollbarId | ||||
|  | ||||
|             width: 16 | ||||
|             height: 16 | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user