cache text during chat sidebar anim + file search with plocate
C++ / fmt (pull_request) Successful in 6s
C++ / build (pull_request) Failing after 2m2s
C++ / clang-tidy (pull_request) Failing after 2m0s
JS/TS / fmt (pull_request) Failing after 11s
JS/TS / lint (pull_request) Successful in 9s
Python / static (pull_request) Successful in 27s
Rust / build (pull_request) Successful in 50s
Python / verify (pull_request) Successful in 1m32s
Rust / fmt (pull_request) Successful in 27s
Rust / clippy (pull_request) Successful in 48s

This commit is contained in:
2026-09-02 19:31:54 +02:00
parent ae5c1fa148
commit dfecaf9cbc
15 changed files with 501 additions and 55 deletions
@@ -16,6 +16,7 @@ Item {
property bool highlight: false
property bool slim: false
signal requestExpand
signal deleteChatRequest(content: ChatSession)
signal loadChatRequest(content: ChatSession, index: int)
signal newChatRequest
@@ -248,16 +249,16 @@ Item {
anchors.margins: Tokens.padding.small
padding: 8
font.pointSize: Math.round(18 * 1.2)
icon: "add"
icon: root.slim ? "left_panel_open" : "add"
isRound: ChatState.fabExpanded
opacity: root.slim ? 0 : 1
visible: opacity > 0
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
}
// opacity: root.slim ? 0 : 1
// visible: opacity > 0
//
// Behavior on opacity {
// Anim {
// type: Anim.DefaultEffects
// }
// }
label.transform: Rotation {
origin.y: fabRoot.label.height / 2
@@ -270,6 +271,11 @@ Item {
}
onClicked: {
if (root.slim && !ChatState.narrowSidebarExpanded) {
root.requestExpand();
return;
}
modelsContainer.expanded = false;
ChatState.fabExpanded = !ChatState.fabExpanded;
}
@@ -14,6 +14,10 @@ Singleton {
property bool inChat: false
property bool fabExpanded: false
property bool isWindow: false
property bool isWide: false
property bool settledSlim: false
property bool settledWide: false
property bool narrowSidebarExpanded: false
property bool windowIsWide: false
property ShellScreen screen
property bool sidebarVisible: Visibilities.getForActive().sidebar
@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Layouts
import ZShell.Llm
import ZShell.Config
import qs.Modules.Notifications.Sidebar.Chat
import qs.Components
import qs.Services
@@ -16,8 +17,6 @@ Item {
required property ChatMessage message
required property ChatGeneration current
// Widest the bubble may grow to; assistant bubbles always use it so
// the markdown blocks have a deterministic width to wrap against.
readonly property real contentMaxWidth: width - Tokens.spacing.extraSmall - Tokens.spacing.extraLarge
signal edit(text: string)
@@ -27,21 +26,51 @@ Item {
CustomClippingRect {
id: bubble
property real liveTargetWidth: root.isUser ? Math.min(msgText.implicitWidth + Tokens.padding.medium * 2, root.contentMaxWidth) : root.contentMaxWidth
property real frozenWidth: 0.0
property bool layoutFrozen: false
property real layoutWidth: root.isUser ? Math.min(msgText.implicitWidth + Tokens.padding.medium * 2, root.contentMaxWidth) : root.contentMaxWidth
radius: Tokens.rounding.medium
color: root.isUser ? Colors.palette.m3primary : Colors.palette.m3surfaceContainer
implicitWidth: root.isUser ? Math.min(msgText.implicitWidth + Tokens.padding.medium * 2, root.contentMaxWidth) : root.contentMaxWidth
implicitWidth: layoutFrozen ? frozenWidth : layoutWidth
implicitHeight: root.isUser ? msgText.contentHeight + Tokens.padding.medium * 2 : blocks.implicitHeight + blocks.anchors.topMargin * 2
anchors.right: root.isUser ? parent.right : undefined
layer.enabled: false
layer.smooth: true
// Behavior on implicitHeight {
// enabled: !root.segment.running
//
// Anim {
// type: Anim.DefaultEffects
// }
// }
transform: Scale {
id: stretchScale
origin.x: root.isUser ? bubble.width : 0
xScale: bubble.layoutFrozen && bubble.frozenWidth > 0 ? bubble.liveTargetWidth / bubble.frozenWidth : 1.0
}
states: [
State {
name: "toSlim"
when: !ChatState.isWide && !ChatState.settledSlim
PropertyChanges {
bubble.layer.enabled: true
bubble.layoutFrozen: true
}
},
State {
name: "toWide"
when: ChatState.isWide && !ChatState.settledWide
PropertyChanges {
bubble.layer.enabled: true
bubble.layoutFrozen: true
}
}
]
onLayoutFrozenChanged: {
if (layoutFrozen)
frozenWidth = width;
}
// User messages stay a plain editable text field.
TextEditBase {
id: msgText
@@ -36,6 +36,7 @@ Item {
}
BlobInvertedRect {
id: invertedRect
anchors.fill: parent
borderBottom: Tokens.padding.small
borderLeft: sidebar.implicitWidth + sidebar.anchors.margins + Tokens.spacing.medium
@@ -53,9 +54,10 @@ Item {
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.margins: Tokens.padding.medium
implicitWidth: root.isWide ? Config.sidebar.sizes.width : root.iconSize
implicitWidth: root.isWide || ChatState.narrowSidebarExpanded ? Config.sidebar.sizes.width : root.iconSize
highlight: true
slim: !root.isWide
slim: !root.isWide && !ChatState.narrowSidebarExpanded
z: 1
Behavior on implicitWidth {
Anim {
@@ -84,6 +86,36 @@ Item {
ChatState.currentIdx = 0;
ChatState.chatSession = data;
}
onRequestExpand: {
ChatState.narrowSidebarExpanded = true;
}
}
CustomClippingRect {
anchors.fill: parent
anchors.leftMargin: invertedRect.borderLeft
anchors.topMargin: invertedRect.borderTop
anchors.bottomMargin: invertedRect.borderBottom
anchors.rightMargin: invertedRect.borderRight
radius: invertedRect.radius
children: [contentArea, dim]
}
CustomRect {
id: dim
anchors.fill: parent
color: Colors.palette.m3shadow
opacity: ChatState.narrowSidebarExpanded && !root.isWide ? 0.3 : 0
z: 1
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
}
}
Item {
@@ -91,12 +123,12 @@ Item {
property int leftMargin: sidebar.implicitWidth
z: 1
z: 0
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.margins: Tokens.padding.medium * 2
anchors.margins: Tokens.padding.medium
anchors.right: parent.right
implicitWidth: root.width - leftMargin - sidebar.anchors.margins - Tokens.spacing.medium * 2 - anchors.margins
implicitWidth: root.width - leftMargin - sidebar.anchors.margins - Tokens.spacing.medium * 2 - anchors.margins * 2
states: State {
name: "wide"
@@ -152,6 +184,13 @@ Item {
color: Colors.tPalette.m3onSurfaceVariant
}
}
MouseArea {
anchors.fill: parent
preventStealing: true
enabled: !root.isWide && ChatState.narrowSidebarExpanded
onClicked: ChatState.narrowSidebarExpanded = false
}
}
Binding {
@@ -160,6 +199,24 @@ Item {
value: root.showList
}
Binding {
target: ChatState
property: "isWide"
value: root.isWide
}
Binding {
target: ChatState
value: contentArea.leftMargin === root.iconSize
property: "settledSlim"
}
Binding {
target: ChatState
value: contentArea.leftMargin === sidebar.implicitWidth
property: "settledWide"
}
Component {
id: conversationView
@@ -110,7 +110,10 @@ ColumnLayout {
onClicked: {
root.visibilities.sidebar = false;
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.playback, recording.modelData.path]);
if (Config.launcher.uwsm)
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.playback, recording.modelData.path]);
else
Quickshell.execDetached([...Config.general.apps.playback, recording.modelData.path]);
}
}
@@ -120,7 +123,10 @@ ColumnLayout {
onClicked: {
root.visibilities.sidebar = false;
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.explorer, recording.modelData.path]);
if (Config.launcher.uwsm)
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.explorer, recording.modelData.path]);
else
Quickshell.execDetached([...Config.general.apps.explorer, recording.modelData.path]);
}
}
}
@@ -135,8 +141,7 @@ ColumnLayout {
}
}
Behavior on implicitHeight {
Anim {
}
Anim {}
}
model: FileSystemModel {
nameFilters: ["recording_*.mp4"]
@@ -162,8 +167,7 @@ ColumnLayout {
opacity: list.count === 0 ? 1 : 0
Behavior on opacity {
Anim {
}
Anim {}
}
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.small
@@ -178,16 +182,13 @@ ColumnLayout {
text: "scan_delete"
Behavior on Layout.preferredHeight {
Anim {
}
Anim {}
}
Behavior on opacity {
Anim {
}
Anim {}
}
Behavior on scale {
Anim {
}
Anim {}
}
}
@@ -203,16 +204,13 @@ ColumnLayout {
text: "scan_delete"
Behavior on Layout.preferredWidth {
Anim {
}
Anim {}
}
Behavior on opacity {
Anim {
}
Anim {}
}
Behavior on scale {
Anim {
}
Anim {}
}
}