status-desktop/ui/app/AppLayouts/Timeline/TimelineLayout.qml

198 lines
6.8 KiB
QML

import QtQuick 2.13
import QtQuick.Controls 2.13
import QtGraphicalEffects 1.13
import QtQml.Models 2.13
import QtQuick.Layouts 1.13
import "../../../imports"
import "../../../shared"
import "../../../shared/status"
import "../Chat/data"
import "../Chat/ChatColumn"
import "../Chat/components"
ScrollView {
id: root
Layout.fillWidth: true
Layout.fillHeight: true
contentHeight: timelineContainer.height + 40
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
property var onActivated: function () {
chatsModel.setActiveChannelToTimeline()
statusUpdateInput.textInput.forceActiveFocus(Qt.MouseFocusReason)
}
Component.onCompleted: {
statusUpdateInput.textInput.forceActiveFocus(Qt.MouseFocusReason)
}
function openProfilePopup(userNameParam, fromAuthorParam, identiconParam, textParam, nicknameParam, parentPopup){
var popup = profilePopupComponent.createObject(root);
if(parentPopup){
popup.parentPopup = parentPopup;
}
popup.openPopup(profileModel.profile.pubKey !== fromAuthorParam, userNameParam, fromAuthorParam, identiconParam, textParam, nicknameParam);
}
MessageContextMenu {
id: messageContextMenu
}
StatusImageModal {
id: imagePopup
}
EmojiReactions {
id: reactionModel
}
property Component profilePopupComponent: ProfilePopup {
id: profilePopup
height: 450
onClosed: {
if(profilePopup.parentPopup){
profilePopup.parentPopup.close();
}
destroy()
}
}
Rectangle {
id: timelineContainer
width: 624
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
height: childrenRect.height
color: "transparent"
StatusChatInput {
id: statusUpdateInput
anchors.top: parent.top
anchors.topMargin: 40
chatType: Constants.chatTypeStatusUpdate
onSendMessage: {
if (statusUpdateInput.fileUrls.length > 0){
chatsModel.sendImage(statusUpdateInput.fileUrls[0], true);
}
var msg = chatsModel.plainText(Emoji.deparse(statusUpdateInput.textInput.text))
if (msg.length > 0){
msg = statusUpdateInput.interpretMessage(msg)
chatsModel.sendMessage(msg, "", Utils.isOnlyEmoji(msg) ? Constants.emojiType : Constants.messageType, true);
statusUpdateInput.textInput.text = "";
if(event) event.accepted = true
statusUpdateInput.messageSound.stop()
Qt.callLater(statusUpdateInput.messageSound.play);
}
}
}
EmptyTimeline {
id: emptyTimeline
anchors.top: statusUpdateInput.bottom
anchors.topMargin: 40
anchors.horizontalCenter: parent.horizontalCenter
visible: chatsModel.messageList.rowCount() === 0
}
ListView {
id: chatLogView
anchors.top: statusUpdateInput.bottom
anchors.topMargin: 40
anchors.left: parent.left
anchors.right: parent.right
height: childrenRect.height + 40
spacing: 10
flickDeceleration: 10000
interactive: false
model: messageListDelegate
section.property: "sectionIdentifier"
section.criteria: ViewSection.FullString
}
DelegateModel {
id: messageListDelegate
property var moreThan: [
function(left, right) { return left.clock > right.clock }
]
property int sortOrder: 0
onSortOrderChanged: items.setGroups(0, items.count, "unsorted")
function insertPosition(moreThan, item) {
var lower = 0
var upper = items.count
while (lower < upper) {
var middle = Math.floor(lower + (upper - lower) / 2)
var result = moreThan(item.model, items.get(middle).model);
if (result) {
upper = middle
} else {
lower = middle + 1
}
}
return lower
}
function sort(moreThan) {
while (unsortedItems.count > 0) {
var item = unsortedItems.get(0)
var index = insertPosition(moreThan, item)
item.groups = "items"
items.move(item.itemsIndex, index)
}
}
items.includeByDefault: false
groups: DelegateModelGroup {
id: unsortedItems
name: "unsorted"
includeByDefault: true
onChanged: {
if (messageListDelegate.sortOrder == messageListDelegate.moreThan.length)
setGroups(0, count, "items")
else {
messageListDelegate.sort(messageListDelegate.moreThan[messageListDelegate.sortOrder])
}
}
}
model: chatsModel.messageList
delegate: Message {
id: msgDelegate
fromAuthor: model.fromAuthor
chatId: model.chatId
userName: model.userName
localName: model.localName
alias: model.alias
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
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
}
}
}
}