qt-chat-app

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

MessageThreadView.qml (4367B)


      1 import QtQuick
      2 import QtQuick.Layouts
      3 import "../components"
      4 import "../models"
      5 import "../styles"
      6 
      7 Item {
      8     id: root
      9 
     10     property int chatId: -1
     11     property bool isSending: false
     12     property bool sseConnected: false
     13 
     14     // Dynamic message list model
     15     MessageListModel {
     16         id: messageListModel
     17         chatId: root.chatId
     18     }
     19 
     20     // Handle network responses
     21     Connections {
     22         target: NetworkManager
     23         function onMessageCreated(messageJson) {
     24             // JSON is available via: var messageData = JSON.parse(messageJson)
     25             // Don't add message locally - wait for SSE to receive it
     26             root.isSending = false
     27         }
     28         function onRequestFailed(error) {
     29             root.isSending = false
     30         }
     31 
     32         // Track SSE connection status
     33         function onSseConnected(chatId) {
     34             if (chatId === root.chatId) {
     35                 root.sseConnected = true
     36             }
     37         }
     38         function onSseDisconnected(chatId, reason) {
     39             if (chatId === root.chatId) {
     40                 root.sseConnected = false
     41             }
     42         }
     43     }
     44 
     45     ColumnLayout {
     46         anchors.fill: parent
     47         spacing: 0
     48 
     49         // Top bar
     50         TopBar {
     51             Layout.fillWidth: true
     52             title: {
     53                 var baseTitle = chatId >= 0 ? "Chat " + chatId : "Chat"
     54                 return root.sseConnected ? baseTitle + " • Online" : baseTitle
     55             }
     56             showBackButton: true
     57             showMenuButton: true
     58             onBackClicked: {
     59                 if (typeof stackView !== 'undefined' && stackView) {
     60                     stackView.pop()
     61                 }
     62             }
     63             onMenuClicked: {
     64                 // TODO: implement chat menu
     65             }
     66         }
     67 
     68         // Messages area
     69         Rectangle {
     70             Layout.fillWidth: true
     71             Layout.fillHeight: true
     72             color: TelegramStyle.messageThreadBg
     73 
     74             ListView {
     75                 id: messageList
     76                 anchors.fill: parent
     77                 anchors.margins: TelegramStyle.smallMargin
     78                 spacing: 8
     79                 clip: true
     80 
     81                 model: messageListModel.model
     82 
     83                 // Track if we should auto-scroll (when at bottom or on initial load)
     84                 property bool shouldAutoScroll: true
     85 
     86                 // Detect when user scrolls to top (to load older messages)
     87                 onAtYBeginningChanged: {
     88                     if (atYBeginning && model.count > 0 && messageListModel.hasMore && !messageListModel.isLoadingMore) {
     89                         messageListModel.loadMore()
     90                     }
     91                 }
     92 
     93                 // Detect manual scrolling (disable auto-scroll if user scrolls up)
     94                 onContentYChanged: {
     95                     if (!messageList.atYEnd && !messageListModel.isLoadingMore) {
     96                         shouldAutoScroll = false
     97                     } else if (messageList.atYEnd) {
     98                         shouldAutoScroll = true
     99                     }
    100                 }
    101 
    102                 // Auto-scroll to bottom when new messages arrive
    103                 onCountChanged: {
    104                     if (shouldAutoScroll && count > 0) {
    105                         Qt.callLater(positionViewAtEnd)
    106                     }
    107                 }
    108 
    109                 delegate: MessageBubble {
    110                     width: messageList.width
    111                     messageData: model
    112                 }
    113 
    114                 // Auto-scroll to bottom on load
    115                 Component.onCompleted: {
    116                     Qt.callLater(positionViewAtEnd)
    117                 }
    118 
    119                 // Loading indicator at top (for older messages)
    120                 header: Item {
    121                     width: messageList.width
    122                     implicitHeight: 60
    123                     visible: messageListModel.isLoadingMore
    124                 }
    125             }
    126         }
    127 
    128         // Input area
    129         MessageInput {
    130             Layout.fillWidth: true
    131             enabled: !root.isSending && root.chatId >= 0
    132             onSendMessage: (text) => {
    133                 // Rust validates (trims, checks empty)
    134                 root.isSending = true
    135                 NetworkManager.postMessage(root.chatId, text)
    136             }
    137             onAttachClicked: () => {
    138                 // TODO: implement attachment picker
    139             }
    140         }
    141     }
    142 }