2020-06-17 15:18:31 -04:00
import QtQuick 2.13
import QtQuick . Controls 2.13
2020-11-20 13:39:14 -04:00
import QtQuick . Window 2.13
2020-06-17 15:18:31 -04:00
import QtQuick . Layouts 1.13
import QtQml . Models 2.13
2020-09-24 11:05:17 -04:00
import QtGraphicalEffects 1.13
2020-11-30 23:24:01 +02:00
import QtQuick . Dialogs 1.3
2021-10-28 00:27:49 +03:00
2022-07-14 14:03:36 +03:00
import StatusQ . Core 0.1
import StatusQ . Controls 0.1
import StatusQ . Components 0.1
2021-10-28 00:27:49 +03:00
import utils 1.0
import shared 1.0
2021-10-28 23:23:30 +03:00
import shared . views 1.0
2021-10-28 00:27:49 +03:00
import shared . panels 1.0
import shared . popups 1.0
import shared . status 1.0
import shared . controls 1.0
2021-10-28 23:23:30 +03:00
import shared . views . chat 1.0
2021-09-28 18:04:06 +03:00
2021-10-01 18:58:36 +03:00
import "../controls"
2021-07-22 17:53:19 +03:00
Item {
2021-08-02 16:38:03 +03:00
id: root
2021-07-22 17:53:19 +03:00
2021-10-01 18:58:36 +03:00
property var store
2021-12-09 13:53:40 +01:00
property var messageStore
2022-02-08 13:08:02 +01:00
property var usersStore
2022-01-04 13:06:05 +01:00
property var contactsStore
2022-03-14 15:32:52 -04:00
property string channelEmoji
2021-10-22 01:39:53 +03:00
2022-04-13 12:59:16 +03:00
property var emojiPopup
2021-12-08 23:20:43 +02:00
property bool stickersLoaded: false
2020-11-19 14:30:09 -04:00
property alias chatLogView: chatLogView
2022-02-24 13:15:02 +01:00
property bool isChatBlocked: false
2022-06-23 11:47:30 -04:00
property bool isActiveChannel: false
2021-07-08 11:20:03 -04:00
2021-07-16 18:02:47 +03:00
property var messageContextMenuInst
2021-08-05 17:05:47 -04:00
2020-06-15 08:51:04 -04:00
property real scrollY: chatLogView . visibleArea . yPosition * chatLogView . contentHeight
2020-09-24 11:05:17 -04:00
property int newMessages: 0
2021-05-26 13:36:24 -04:00
2021-12-08 23:20:43 +02:00
property int countOnStartUp: 0
signal openStickerPackPopup ( string stickerPackId )
2022-01-12 15:55:26 +03:00
signal showReplyArea ( string messageId , string author )
2021-12-08 23:20:43 +02:00
2022-01-27 12:28:27 +01:00
Connections {
target: root . messageStore . messageModule
onMessageSuccessfullySent: {
chatLogView . scrollToBottom ( true )
}
onSendingMessageFailed: {
sendingMsgFailedPopup . open ( ) ;
}
2022-01-27 13:44:33 +01:00
onScrollMessagesUp: {
chatLogView . positionViewAtEnd ( )
}
onScrollToMessage: {
2022-01-27 12:28:27 +01:00
chatLogView . positionViewAtIndex ( messageIndex , ListView . Center ) ;
chatLogView . itemAtIndex ( messageIndex ) . startMessageFoundAnimation ( ) ;
}
// Not Refactored Yet
// onNewMessagePushed: {
// if (!chatLogView.scrollToBottom()) {
// newMessages++
// }
// }
}
2021-12-22 13:00:44 +01:00
Item {
id: loadingMessagesIndicator
2022-02-07 17:55:14 -04:00
visible: root . store . loadingHistoryMessagesInProgress
2021-12-22 13:00:44 +01:00
anchors.top: parent . top
anchors.left: parent . left
height: visible ? 20 : 0
width: parent . width
Loader {
2022-02-07 17:55:14 -04:00
active: root . store . loadingHistoryMessagesInProgress
2021-12-22 13:00:44 +01:00
anchors.horizontalCenter: parent . horizontalCenter
anchors.verticalCenter: parent . verticalCenter
sourceComponent: Component {
LoadingAnimation {
width: 18
height: 18
}
}
}
}
2022-07-14 14:03:36 +03:00
StatusListView {
2021-08-02 16:38:03 +03:00
id: chatLogView
2022-07-20 14:14:50 +02:00
objectName: "chatLogView"
2021-12-22 13:00:44 +01:00
anchors.top: loadingMessagesIndicator . bottom
anchors.bottom: parent . bottom
anchors.left: parent . left
anchors.right: parent . right
2021-12-10 12:29:33 +01:00
spacing: 0
2021-08-02 16:38:03 +03:00
verticalLayoutDirection: ListView . BottomToTop
// This header and Connections is to create an invisible padding so that the chat identifier is at the top
// The Connections is necessary, because doing the check inside the header created a binding loop (the contentHeight includes the header height
// If the content height is smaller than the full height, we "show" the padding so that the chat identifier is at the top, otherwise we disable the Connections
header: Item {
height: 0
width: chatLogView . width
}
2020-07-23 16:22:45 -04:00
2021-08-02 16:38:03 +03:00
function checkHeaderHeight ( ) {
if ( ! chatLogView . headerItem ) {
return
2020-07-23 16:22:45 -04:00
}
2020-09-24 11:05:17 -04:00
2021-08-02 16:38:03 +03:00
if ( chatLogView . contentItem . height - chatLogView . headerItem . height < chatLogView . height ) {
chatLogView . headerItem . height = chatLogView . height - ( chatLogView . contentItem . height - chatLogView . headerItem . height ) - 36
} else {
chatLogView . headerItem . height = 0
2020-07-23 16:22:45 -04:00
}
2021-08-02 16:38:03 +03:00
}
2020-09-24 11:05:17 -04:00
2022-07-14 14:03:36 +03:00
ScrollBar.vertical: StatusScrollBar {
2021-12-22 13:00:44 +01:00
visible: chatLogView . visibleArea . heightRatio < 1
}
2021-12-09 13:53:40 +01:00
// Connections {
// id: contentHeightConnection
// enabled: true
// target: chatLogView
// onContentHeightChanged: {
// chatLogView.checkHeaderHeight()
// }
// onHeightChanged: {
// chatLogView.checkHeaderHeight()
// }
// }
2020-07-22 14:37:43 -04:00
2021-08-02 16:38:03 +03:00
Timer {
id: timer
}
2021-06-23 13:30:57 -04:00
2021-12-22 13:00:44 +01:00
Button {
readonly property int buttonPadding: 5
id: scrollDownButton
visible: false
height: 32
width: nbMessages . width + arrowImage . width + 2 * Style . current . halfPadding + ( nbMessages . visible ? scrollDownButton.buttonPadding : 0 )
anchors.bottom: parent . bottom
anchors.right: parent . right
anchors.rightMargin: Style . current . padding
background: Rectangle {
color: Style . current . buttonSecondaryColor
border.width: 0
radius: 16
}
onClicked: {
newMessages = 0
scrollDownButton . visible = false
chatLogView . scrollToBottom ( true )
}
2021-12-09 13:53:40 +01:00
2021-12-22 13:00:44 +01:00
StyledText {
id: nbMessages
visible: newMessages > 0
width: visible ? implicitWidth : 0
text: newMessages
anchors.verticalCenter: parent . verticalCenter
anchors.left: parent . left
color: Style . current . pillButtonTextColor
font.pixelSize: 15
anchors.leftMargin: Style . current . halfPadding
}
2021-12-09 13:53:40 +01:00
2021-12-22 13:00:44 +01:00
SVGImage {
id: arrowImage
width: 24
height: 24
anchors.verticalCenter: parent . verticalCenter
anchors.left: nbMessages . right
source: Style . svg ( "leave_chat" )
anchors.leftMargin: nbMessages . visible ? scrollDownButton.buttonPadding : 0
rotation: - 90
ColorOverlay {
anchors.fill: parent
source: parent
color: Style . current . pillButtonTextColor
}
}
2021-12-09 13:53:40 +01:00
2021-12-22 13:00:44 +01:00
MouseArea {
cursorShape: Qt . PointingHandCursor
anchors.fill: parent
onPressed: mouse . accepted = false
}
}
2020-11-30 23:24:01 +02:00
2021-08-02 16:38:03 +03:00
function scrollToBottom ( force , caller ) {
2021-12-22 13:00:44 +01:00
if ( ! force && ! chatLogView . atYEnd ) {
// User has scrolled up, we don't want to scroll back
return false
}
if ( caller && caller !== chatLogView . itemAtIndex ( chatLogView . count - 1 ) ) {
// If we have a caller, only accept its request if it's the last message
return false
}
// Call this twice and with a timer since the first scroll to bottom might have happened before some stuff loads
// meaning that the scroll will not actually be at the bottom on switch
// Add a small delay because images, even though they say they say they are loaed, they aren't shown yet
Qt . callLater ( chatLogView . positionViewAtBeginning )
timer . setTimeout ( function ( ) {
Qt . callLater ( chatLogView . positionViewAtBeginning )
} , 100 ) ;
2021-08-02 16:38:03 +03:00
return true
}
2021-07-08 11:20:03 -04:00
2021-12-09 13:53:40 +01:00
// Connections {
// Not Refactored Yet
// target: root.store.chatsModelInst
// onAppReady: {
// chatLogView.scrollToBottom(true)
// }
// }
2021-12-22 13:00:44 +01:00
onContentYChanged: {
scrollDownButton . visible = contentHeight - ( scrollY + height ) > 400
let loadMore = scrollDownButton . visible && scrollY < 500
if ( loadMore ) {
messageStore . loadMoreMessages ( )
}
}
2021-07-16 20:00:06 +03:00
2021-12-22 13:00:44 +01:00
model: messageStore . messagesModel
2021-09-21 16:59:39 +02:00
2022-06-23 11:47:30 -04:00
Component.onCompleted: chatLogView . scrollToBottom ( true )
2021-08-02 16:38:03 +03:00
2021-10-01 18:58:36 +03:00
delegate: MessageView {
2021-08-02 16:38:03 +03:00
id: msgDelegate
2022-07-21 12:16:25 -04:00
objectName: "chatMessageViewDelegate"
2022-02-11 16:41:34 -05:00
store: root . store
2021-12-09 13:53:40 +01:00
messageStore: root . messageStore
2022-02-08 13:08:02 +01:00
usersStore: root . usersStore
2022-01-04 13:06:05 +01:00
contactsStore: root . contactsStore
2022-03-14 15:32:52 -04:00
channelEmoji: root . channelEmoji
2022-04-13 12:59:16 +03:00
emojiPopup: root . emojiPopup
2022-07-25 14:43:05 +02:00
chatLogView: ListView . view
2022-01-04 13:06:05 +01:00
2022-06-29 12:50:10 -04:00
isActiveChannel: root . isActiveChannel
2022-02-24 13:15:02 +01:00
isChatBlocked: root . isChatBlocked
2021-12-14 15:19:55 +01:00
messageContextMenu: messageContextMenuInst
2021-12-09 13:53:40 +01:00
2022-03-09 11:02:28 +01:00
itemIndex: index
2021-12-09 13:53:40 +01:00
messageId: model . id
2022-02-24 10:04:59 -05:00
communityId: model . communityId
2021-12-09 13:53:40 +01:00
responseToMessageWithId: model . responseToMessageWithId
senderId: model . senderId
senderDisplayName: model . senderDisplayName
senderLocalName: model . senderLocalName
senderIcon: model . senderIcon
2022-03-04 16:33:48 -05:00
senderIsAdded: model . senderIsAdded
2021-12-09 13:53:40 +01:00
amISender: model . amISender
message: model . messageText
messageImage: model . messageImage
messageTimestamp: model . timestamp
messageOutgoingStatus: model . outgoingStatus
messageContentType: model . contentType
2022-06-28 14:11:18 -04:00
senderTrustStatus: model . senderTrustStatus
2021-12-09 13:53:40 +01:00
pinnedMessage: model . pinned
2022-01-05 16:50:03 +01:00
messagePinnedBy: model . pinnedBy
2021-12-20 15:21:35 +01:00
reactionsModel: model . reactions
2022-01-13 14:25:38 -05:00
sticker: model . sticker
stickerPack: model . stickerPack
2022-01-17 19:46:46 +01:00
editModeOn: model . editMode
isEdited: model . isEdited
2022-01-25 13:56:53 +01:00
linkUrls: model . links
2022-02-09 01:04:49 +01:00
transactionParams: model . transactionParameters
2021-12-09 13:53:40 +01:00
2022-02-25 11:42:32 +01:00
gapFrom: model . gapFrom
gapTo: model . gapTo
2021-12-09 13:53:40 +01:00
// This is possible since we have all data loaded before we load qml.
// When we fetch messages to fulfill a gap we have to set them at once.
2022-01-14 12:38:45 +01:00
// Also one important thing here is that messages are set in descending order
// in terms of `timestamp` of a message, that means a message with the most
// recent time is added at index 0.
2022-06-09 20:38:08 +02:00
prevMessageIndex: model . prevMsgIndex
prevMessageAsJsonObj: messageStore . getMessageByIndexAsJson ( model . prevMsgIndex )
2022-08-02 14:34:46 +03:00
prevMsgTimestamp: model . prevMsgTimestamp
2022-06-09 20:38:08 +02:00
nextMessageIndex: model . nextMsgIndex
nextMessageAsJsonObj: messageStore . getMessageByIndexAsJson ( model . nextMsgIndex )
2021-12-08 23:20:43 +02:00
onOpenStickerPackPopup: {
root . openStickerPackPopup ( stickerPackId ) ;
}
2022-01-05 16:50:03 +01:00
2022-01-12 15:55:26 +03:00
onShowReplyArea: {
root . showReplyArea ( messageId , author )
}
2022-02-01 14:10:24 +01:00
onImageClicked: Global . openImagePopup ( image , messageContextMenuInst )
2022-01-18 22:02:47 +01:00
2022-01-05 16:50:03 +01:00
stickersLoaded: root . stickersLoaded
2022-01-17 19:46:46 +01:00
onVisibleChanged: {
if ( ! visible && model . editMode )
messageStore . setEditModeOff ( model . id )
}
2021-08-02 16:38:03 +03:00
}
2021-06-30 14:46:26 -04:00
}
2021-12-10 17:11:18 +01:00
2021-12-22 13:00:44 +01:00
MessageDialog {
id: sendingMsgFailedPopup
standardButtons: StandardButton . Ok
2022-04-04 13:26:30 +02:00
text: qsTr ( "Failed to send message." )
2021-12-22 13:00:44 +01:00
icon: StandardIcon . Critical
}
2020-05-27 18:59:17 -04:00
}