import QtQuick 2.13 import QtQuick.Controls 2.13 import QtGraphicalEffects 1.13 import QtQml.Models 2.13 import QtQuick.Layouts 1.13 import utils 1.0 import shared 1.0 import shared.views 1.0 import shared.status 1.0 import shared.popups 1.0 import shared.controls 1.0 import shared.views.chat 1.0 import "../Chat/stores" import "../Chat/popups" import "stores" import "panels" ScrollView { id: root property RootStore store: RootStore { } property var chatSectionModule Layout.fillWidth: true Layout.fillHeight: true contentHeight: chatLogView.contentHeight + 140 clip: true ScrollBar.horizontal.policy: ScrollBar.AlwaysOff property var rootStore property var messageStore property var onActivated: function () { store.setActiveChannelToTimeline() statusUpdateInput.textInput.forceActiveFocus(Qt.MouseFocusReason) } Component.onCompleted: { statusUpdateInput.textInput.forceActiveFocus(Qt.MouseFocusReason) } function openProfilePopup(userNameParam, fromAuthorParam, identiconParam, textParam, nicknameParam, parentPopup){ Global.openProfilePopup(fromAuthorParam) } StatusImageModal { id: imagePopup onClicked: { close() } } Item { id: timelineContainer width: 624 anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom // TODO: Replace this with StatusQ component once it lives there. StatusChatInput { id: statusUpdateInput anchors.top: parent.top anchors.topMargin: 40 chatType: Constants.chatType.profile imageErrorMessageLocation: StatusChatInput.ImageErrorMessageLocation.Bottom z: 1 onSendMessage: { if (statusUpdateInput.fileUrls.length > 0){ statusUpdateInput.fileUrls.forEach(url => { root.store.sendImage(url); }) } var msg = root.store.getPlainTextFromRichText(Emoji.deparse(statusUpdateInput.textInput.text)) if (msg.length > 0){ msg = statusUpdateInput.interpretMessage(msg) root.store.sendMessage(msg, Utils.isOnlyEmoji(msg) ? Constants.messageContentType.emojiType : Constants.messageContentType.messageType); statusUpdateInput.textInput.text = ""; if(event) event.accepted = true sendMessageSound.stop() Qt.callLater(sendMessageSound.play); } } } EmptyTimelinePanel { id: emptyTimeline anchors.top: statusUpdateInput.bottom anchors.topMargin: 40 anchors.horizontalCenter: parent.horizontalCenter visible: chatLogView.count === 0 } ListView { id: chatLogView anchors.top: statusUpdateInput.bottom anchors.topMargin: Style.current.bigPadding anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom spacing: Style.current.halfPadding flickDeceleration: 10000 interactive: false model: messageListDelegate section.property: "sectionIdentifier" section.criteria: ViewSection.FullString // Not Refactored Yet // Connections { // target: root.store.chatsModelInst.messageView // onMessagesLoaded: { // Qt.callLater(chatLogView.positionViewAtBeginning) // } // } } Timer { id: ageUpdateTimer property int epoch: 0 running: true repeat: true interval: 60000 // 1 min onTriggered: epoch = epoch + 1 } DelegateModelGeneralized { id: messageListDelegate lessThan: [ function(left, right) { return left.clock > right.clock } ] // Not Refactored Yet // model: root.store.chatsModelInst.messageView.messageList // TODO: Replace with StatusQ component once it lives there. delegate: MessageView { id: msgDelegate // Not Refactored Yet // rootStore: root.rootStore // messageStore: root.messageStore // fromAuthor: model.fromAuthor // chatId: model.chatId // userName: model.userName // alias: model.alias // localName: model.localName // message: model.message // plainText: model.plainText // identicon: model.identicon // isCurrentUser: model.isCurrentUser // timestamp: model.timestamp // sticker: model.sticker // contentType: model.contentType // outgoingStatus: model.outgoingStatus // responseTo: model.responseTo // authorCurrentMsg: msgDelegate.ListView.section // authorPrevMsg: msgDelegate.ListView.previousSection // imageClick: imagePopup.openPopup.bind(imagePopup) // messageId: model.messageId // emojiReactions: model.emojiReactions // isStatusUpdate: true // statusAgeEpoch: ageUpdateTimer.epoch // // This is used in order to have access to the previous message and determine the timestamp // // we can't rely on the index because the sequence of messages is not ordered on the nim side // prevMessageIndex: { // // This is used in order to have access to the previous message and determine the timestamp // // we can't rely on the index because the sequence of messages is not ordered on the nim side // if(msgDelegate.DelegateModel.itemsIndex > 0){ // return messageListDelegate.items.get(msgDelegate.DelegateModel.itemsIndex - 1).model.index // } // return -1; // } // timeout: model.timeout // messageContextMenu: msgCntxtMenu // Component.onCompleted: { // messageStore.fromAuthor = model.fromAuthor; // messageStore.chatId = model.chatId; // messageStore.userName = model.userName; // messageStore.alias = model.alias; // messageStore.localName = model.localName; // messageStore.message = model.message; // messageStore.plainText = model.plainText; // messageStore.identicon = model.identicon; // messageStore.isCurrentUser = model.isCurrentUser; // messageStore.timestamp = model.timestamp; // messageStore.sticker = model.sticker; // messageStore.contentType = model.contentType; // messageStore.outgoingStatus = model.outgoingStatus; // messageStore.responseTo = model.responseTo; // messageStore.authorCurrentMsg = msgDelegate.ListView.section; // messageStore.authorPrevMsg = msgDelegate.ListView.previousSection; // messageStore.imageClick = imagePopup.openPopup.bind(imagePopup); // messageStore.messageId = model.messageId; // messageStore.emojiReactions = model.emojiReactions; // messageStore.isStatusUpdate = true; // messageStore.statusAgeEpoch = ageUpdateTimer.epoch; // // This is used in order to have access to the previous message and determine the timestamp // // we can't rely on the index because the sequence of messages is not ordered on the nim side // messageStore.prevMessageIndex = // // This is used in order to have access to the previous message and determine the timestamp // // we can't rely on the index because the sequence of messages is not ordered on the nim side // (msgDelegate.DelegateModel.itemsIndex > 0) ? // messageListDelegate.items.get(msgDelegate.DelegateModel.itemsIndex - 1).model.index : -1; // messageStore.timeout = model.timeout; // messageStore.messageContextMenu = msgCntxtMenu; // } // MessageContextMenuView { // id: msgCntxtMenu // store: root.store // chatSectionModule: root.chatSectionModule // reactionModel: EmojiReactions { } // } } } Loader { active: root.store.chatsModelInst.messageView.loadingMessages // TODO: replace with StatusLoadingIndicator sourceComponent: LoadingAnimation {} anchors.right: timelineContainer.right anchors.top: statusUpdateInput.bottom anchors.rightMargin: Style.current.padding anchors.topMargin: Style.current.padding } } }