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

243 lines
9.7 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 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){
var popup = profilePopupComponent.createObject(root);
if(parentPopup){
popup.parentPopup = parentPopup;
}
popup.openPopup(userProfile.pubKey !== fromAuthorParam, userNameParam, fromAuthorParam, identiconParam, textParam, nicknameParam);
}
StatusImageModal {
id: imagePopup
onClicked: {
close()
}
}
property Component profilePopupComponent: ProfilePopup {
id: profilePopup
store: root.store
onClosed: {
if(profilePopup.parentPopup){
profilePopup.parentPopup.close();
}
destroy()
}
}
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
}
}
}