start initial work on detaching chat to floating window
This commit is contained in:
@@ -11,7 +11,7 @@ import qs.Services
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property ChatSession chatData
|
property ChatSession chatData
|
||||||
property bool following: true
|
property bool following: true
|
||||||
readonly property int messageCount: chatData.messages.length
|
readonly property int messageCount: chatData.messages.length
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ Item {
|
|||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: Tokens.spacing.small
|
spacing: Tokens.spacing.small
|
||||||
visible: root.messageCount === 0 && !Chat.busy
|
visible: (root.messageCount === 0 && !Chat.busy) || !root.chatData
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
@@ -273,7 +273,7 @@ Item {
|
|||||||
CustomText {
|
CustomText {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
color: Colors.tPalette.m3onSurfaceVariant
|
color: Colors.tPalette.m3onSurfaceVariant
|
||||||
text: qsTr("No messages yet")
|
text: !root.chatData ? qsTr("Open a previous chat or start a new one") : qsTr("No messages yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import qs.Services
|
|||||||
CustomRect {
|
CustomRect {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
required property Item chatItem
|
||||||
property alias layout: layout
|
property alias layout: layout
|
||||||
required property ChatSession modelData
|
required property ChatSession modelData
|
||||||
|
|
||||||
@@ -20,6 +21,7 @@ CustomRect {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: Tokens.padding.large
|
anchors.leftMargin: Tokens.padding.large
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
color: root.chatItem.ListView.isCurrentItem ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
||||||
font.pointSize: Tokens.font.size.extraLarge
|
font.pointSize: Tokens.font.size.extraLarge
|
||||||
text: root.modelData.icon || "check"
|
text: root.modelData.icon || "check"
|
||||||
}
|
}
|
||||||
@@ -48,6 +50,7 @@ CustomRect {
|
|||||||
CustomText {
|
CustomText {
|
||||||
id: title
|
id: title
|
||||||
|
|
||||||
|
color: root.chatItem.ListView.isCurrentItem ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
||||||
text: root.modelData.title
|
text: root.modelData.title
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +60,7 @@ CustomRect {
|
|||||||
anchors.left: title.right
|
anchors.left: title.right
|
||||||
anchors.leftMargin: Tokens.spacing.small
|
anchors.leftMargin: Tokens.spacing.small
|
||||||
anchors.verticalCenter: title.verticalCenter
|
anchors.verticalCenter: title.verticalCenter
|
||||||
color: Colors.palette.m3onSurfaceVariant
|
color: root.chatItem.ListView.isCurrentItem ? Qt.alpha(Colors.palette.m3onPrimary, 0.9) : Colors.palette.m3onSurfaceVariant
|
||||||
text: "•"
|
text: "•"
|
||||||
visible: titleContainer.enoughSpace
|
visible: titleContainer.enoughSpace
|
||||||
}
|
}
|
||||||
@@ -70,7 +73,7 @@ CustomRect {
|
|||||||
anchors.top: titleContainer.enoughSpace ? undefined : title.bottom
|
anchors.top: titleContainer.enoughSpace ? undefined : title.bottom
|
||||||
anchors.topMargin: Tokens.spacing.extraSmall
|
anchors.topMargin: Tokens.spacing.extraSmall
|
||||||
anchors.verticalCenter: titleContainer.enoughSpace ? title.verticalCenter : undefined
|
anchors.verticalCenter: titleContainer.enoughSpace ? title.verticalCenter : undefined
|
||||||
color: Colors.palette.m3onSurfaceVariant
|
color: root.chatItem.ListView.isCurrentItem ? Qt.alpha(Colors.palette.m3onPrimary, 0.9) : Colors.palette.m3onSurfaceVariant
|
||||||
font.pointSize: Tokens.font.size.small
|
font.pointSize: Tokens.font.size.small
|
||||||
text: root.modelData.updatedAt.toLocaleString(Qt.locale("en_US"), "MMM d, yyyy - h:mm AP")
|
text: root.modelData.updatedAt.toLocaleString(Qt.locale("en_US"), "MMM d, yyyy - h:mm AP")
|
||||||
}
|
}
|
||||||
@@ -78,7 +81,7 @@ CustomRect {
|
|||||||
|
|
||||||
CustomText {
|
CustomText {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
color: Colors.palette.m3outline
|
color: root.chatItem.ListView.isCurrentItem ? Qt.alpha(Colors.palette.m3onPrimary, 0.9) : Colors.palette.m3onSurfaceVariant
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
font.pointSize: Tokens.font.size.small
|
font.pointSize: Tokens.font.size.small
|
||||||
maximumLineCount: 1
|
maximumLineCount: 1
|
||||||
|
|||||||
@@ -11,10 +11,11 @@ import qs.Components
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property alias list: list
|
||||||
property alias model: list.model
|
property alias model: list.model
|
||||||
|
|
||||||
signal deleteChatRequest(content: ChatSession)
|
signal deleteChatRequest(content: ChatSession)
|
||||||
signal loadChatRequest(content: ChatSession)
|
signal loadChatRequest(content: ChatSession, index: int)
|
||||||
signal newChatRequest
|
signal newChatRequest
|
||||||
|
|
||||||
CustomText {
|
CustomText {
|
||||||
@@ -47,8 +48,10 @@ Item {
|
|||||||
Item {
|
Item {
|
||||||
id: chatItem
|
id: chatItem
|
||||||
|
|
||||||
|
property alias chat: chat
|
||||||
property bool closing: false
|
property bool closing: false
|
||||||
property bool editVisible: false
|
property bool editVisible: false
|
||||||
|
required property int index
|
||||||
required property var modelData
|
required property var modelData
|
||||||
property real startY: 0.0
|
property real startY: 0.0
|
||||||
|
|
||||||
@@ -87,6 +90,7 @@ Item {
|
|||||||
ChatDelegate {
|
ChatDelegate {
|
||||||
id: chat
|
id: chat
|
||||||
|
|
||||||
|
chatItem: chatItem
|
||||||
implicitWidth: chatItem.implicitWidth
|
implicitWidth: chatItem.implicitWidth
|
||||||
modelData: chatItem.modelData
|
modelData: chatItem.modelData
|
||||||
radius: Tokens.rounding.medium
|
radius: Tokens.rounding.medium
|
||||||
@@ -111,7 +115,7 @@ Item {
|
|||||||
if (chatItem.editVisible)
|
if (chatItem.editVisible)
|
||||||
chatItem.editVisible = false;
|
chatItem.editVisible = false;
|
||||||
else
|
else
|
||||||
root.loadChatRequest(chatItem.modelData);
|
root.loadChatRequest(chatItem.modelData, chatItem.index);
|
||||||
}
|
}
|
||||||
onPressed: event => {
|
onPressed: event => {
|
||||||
chatItem.startY = event.y;
|
chatItem.startY = event.y;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import ZShell.Llm
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import qs.Helpers
|
||||||
import qs.Modules.Notifications.Sidebar
|
import qs.Modules.Notifications.Sidebar
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -12,26 +13,49 @@ import qs.Services
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property bool chatOpen: false
|
|
||||||
required property Props props
|
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Tokens.padding.small
|
anchors.margins: Tokens.padding.small
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (root.props.inChat) {
|
if (ChatState.inChat) {
|
||||||
stack.push(chatList);
|
stackLoader.item?.push(chatList);
|
||||||
stack.push(chatContent, {
|
stackLoader.item?.push(chatContent, {
|
||||||
"chatData": root.props.chatSession
|
"chatData": ChatState.chatSession
|
||||||
});
|
});
|
||||||
} else
|
} else
|
||||||
stack.push(chatList);
|
stackLoader.item?.push(chatList);
|
||||||
}
|
}
|
||||||
|
|
||||||
StackView {
|
Loader {
|
||||||
id: stack
|
id: stackLoader
|
||||||
|
|
||||||
|
active: !ChatState.isWindow || root.width <= (ChatState.screen.width / 4)
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
sourceComponent: StackView {
|
||||||
|
id: stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: sidebarViewLoader
|
||||||
|
|
||||||
|
active: ChatState.isWindow && root.width > (ChatState.screen.width / 4)
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
sourceComponent: SidebarView {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
anchors.right: parent.right
|
||||||
|
icon: "close"
|
||||||
|
visible: !ChatState.isWindow
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
Detach.create();
|
||||||
|
Visibilities.getForActive().sidebar = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
@@ -46,19 +70,19 @@ Item {
|
|||||||
Chat.chats.remove(chat);
|
Chat.chats.remove(chat);
|
||||||
}
|
}
|
||||||
onLoadChatRequest: chat => {
|
onLoadChatRequest: chat => {
|
||||||
stack.push(chatContent, {
|
stackLoader.item?.push(chatContent, {
|
||||||
"chatData": chat
|
"chatData": chat
|
||||||
});
|
});
|
||||||
root.props.inChat = true;
|
ChatState.inChat = true;
|
||||||
root.props.chatSession = chat;
|
ChatState.chatSession = chat;
|
||||||
}
|
}
|
||||||
onNewChatRequest: {
|
onNewChatRequest: {
|
||||||
const data = Chat.chats.insert();
|
const data = Chat.chats.insert();
|
||||||
stack.push(chatContent, {
|
stackLoader.item?.push(chatContent, {
|
||||||
"chatData": data
|
"chatData": data
|
||||||
});
|
});
|
||||||
root.props.inChat = true;
|
ChatState.inChat = true;
|
||||||
root.props.chatSession = data;
|
ChatState.chatSession = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,8 +92,8 @@ Item {
|
|||||||
|
|
||||||
ChatContent {
|
ChatContent {
|
||||||
onRequestClose: {
|
onRequestClose: {
|
||||||
stack.pop();
|
stackLoader.item?.pop();
|
||||||
root.props.inChat = false;
|
ChatState.inChat = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import ZShell.Llm
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property ChatSession chatSession
|
||||||
|
property bool inChat: false
|
||||||
|
property bool isWindow: false
|
||||||
|
property ShellScreen screen
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import ZShell.Config
|
||||||
|
import qs.Services
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
function create(parent: Item, props: var): void {
|
||||||
|
chatComp.createObject(parent ?? dummy, props);
|
||||||
|
ChatState.isWindow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: dummy
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: chatComp
|
||||||
|
|
||||||
|
FloatingWindow {
|
||||||
|
id: win
|
||||||
|
|
||||||
|
property var props
|
||||||
|
|
||||||
|
color: Colors.tPalette.m3surface
|
||||||
|
implicitHeight: chat.implicitHeight
|
||||||
|
implicitWidth: chat.implicitWidth
|
||||||
|
minimumSize.height: Config.sidebar.sizes.width
|
||||||
|
minimumSize.width: Config.sidebar.sizes.width
|
||||||
|
surfaceFormat.opaque: false
|
||||||
|
title: qsTr("ZShell - Chat")
|
||||||
|
|
||||||
|
Component.onCompleted: ChatState.screen = screen
|
||||||
|
onVisibleChanged: {
|
||||||
|
if (!visible) {
|
||||||
|
destroy();
|
||||||
|
ChatState.isWindow = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatPanel {
|
||||||
|
id: chat
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import ZShell.Config
|
||||||
|
import ZShell.Llm
|
||||||
|
import qs.Components
|
||||||
|
import qs.Services
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
ChatList {
|
||||||
|
id: chatList
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.maximumWidth: Config.sidebar.sizes.width
|
||||||
|
Layout.minimumWidth: Config.sidebar.sizes.width / 2
|
||||||
|
list.currentIndex: -1
|
||||||
|
list.highlightFollowsCurrentItem: false
|
||||||
|
|
||||||
|
list.highlight: CustomRect {
|
||||||
|
color: Colors.palette.m3primary
|
||||||
|
implicitHeight: chatList.list.currentItem?.implicitHeight ?? 0
|
||||||
|
implicitWidth: chatList.list.width
|
||||||
|
radius: Tokens.rounding.medium
|
||||||
|
x: chatList.list.currentItem?.chat.x ?? 0
|
||||||
|
y: chatList.list.currentItem?.y ?? 0
|
||||||
|
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
duration: Tokens.anim.durations.small
|
||||||
|
easing: Tokens.anim.expressiveDefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model: ScriptModel {
|
||||||
|
values: Chat.chats.values
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoadChatRequest: (chat, index) => {
|
||||||
|
chatList.list.currentIndex = index;
|
||||||
|
chatContent.chatData = chat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatContent {
|
||||||
|
id: chatContent
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumWidth: Config.sidebar.sizes.width
|
||||||
|
Layout.preferredWidth: Math.round(Config.sidebar.sizes.width * 1.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,15 @@ Item {
|
|||||||
required property Props props
|
required property Props props
|
||||||
required property var visibilities
|
required property var visibilities
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onIsWindowChanged(): void {
|
||||||
|
if (ChatState.isWindow)
|
||||||
|
root.props.currentTab = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
target: ChatState
|
||||||
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: layout
|
id: layout
|
||||||
|
|
||||||
@@ -22,8 +31,10 @@ Item {
|
|||||||
|
|
||||||
Tabs {
|
Tabs {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: ChatState.isWindow ? 0 : implicitHeight
|
||||||
dashState: root.props
|
dashState: root.props
|
||||||
nonAnimWidth: layout.width
|
nonAnimWidth: layout.width
|
||||||
|
visible: height > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomClippingRect {
|
CustomClippingRect {
|
||||||
@@ -75,7 +86,6 @@ Item {
|
|||||||
|
|
||||||
ChatPanel {
|
ChatPanel {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
props: root.props
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,8 @@ import Quickshell
|
|||||||
import ZShell.Llm
|
import ZShell.Llm
|
||||||
|
|
||||||
PersistentProperties {
|
PersistentProperties {
|
||||||
property ChatSession chatSession
|
|
||||||
property int currentTab: 0
|
property int currentTab: 0
|
||||||
property list<string> expandedNotifs: []
|
property list<string> expandedNotifs: []
|
||||||
property bool inChat: false
|
|
||||||
|
|
||||||
reloadableId: "sidebar"
|
reloadableId: "sidebar"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user