feat: add replies to the activity center

This commit is contained in:
Jonathan Rainville 2021-06-11 15:50:52 -04:00
parent 447794f0e7
commit b1bcd539a2
13 changed files with 173 additions and 68 deletions

View File

@ -595,7 +595,17 @@ QtObject:
self.messageList[chat].markMessageAsSent(messageId)
else:
error "Message could not be marked as sent", chat, messageId
proc getMessageIndex(self: ChatsView, chatId: string, messageId: string): int {.slot.} =
if (not self.messageList.hasKey(chatId)):
return -1
result = self.messageList[chatId].getMessageIndex(messageId)
proc getMessageData(self: ChatsView, chatId: string, index: int, data: string): string {.slot.} =
if (not self.messageList.hasKey(chatId)):
return
return self.messageList[chatId].getMessageData(index, data)
proc getMessageList(self: ChatsView): QVariant {.slot.} =
self.upsertChannel(self.activeChannel.id)

View File

@ -225,12 +225,12 @@ QtObject:
ChatMessageRoles.GapTo.int:"gapTo"
}.toTable
proc getMessageIndex(self: ChatMessageList, messageId: string): int {.slot.} =
proc getMessageIndex*(self: ChatMessageList, messageId: string): int {.slot.} =
if not self.messageIndex.hasKey(messageId): return -1
result = self.messageIndex[messageId]
# TODO: see how to use data() instead of this function
proc getMessageData(self: ChatMessageList, index: int, data: string): string {.slot.} =
proc getMessageData*(self: ChatMessageList, index: int, data: string): string {.slot.} =
if index < 0 or index >= self.messages.len: return ("")
let message = self.messages[index]

View File

@ -16,6 +16,7 @@ type ActivityCenterNotificationType* {.pure.}= enum
NewOneToOne = 1,
NewPrivateGroupChat = 2,
Mention = 3
Reply = 4
proc isOneToOne*(self: ChatType): bool = self == ChatType.OneToOne
proc isTimeline*(self: ChatType): bool = self == ChatType.Timeline

View File

@ -16,6 +16,9 @@ Popup {
ContactRequests
}
property int currentFilter: ActivityCenter.Filter.All
property bool hasMentions: false
property bool hasReplies: false
property bool hasContactRequests: contactList.count > 0
id: activityCenter
modal: true
@ -111,16 +114,33 @@ Popup {
property int idx: DelegateModel.itemsIndex
Component.onCompleted: {
switch (model.notificationType) {
case Constants.acitivtyCenterNotificationTypeMention:
if (!hasMentions) {
hasMentions = true
}
break
case Constants.acitivtyCenterNotificationTypeReply:
if (!hasReplies) {
hasReplies = true
}
break
}
}
Loader {
id: notifLoader
anchors.top: parent.top
active: !!sourceComponent
width: parent.width
height: active && item.visible ? item.height : 0
sourceComponent: {
switch (model.notificationType) {
// TODO add to constants (mention)
case 3: return messageNotificationComponent
case Constants.acitivtyCenterNotificationTypeMention:return messageNotificationComponent
case Constants.acitivtyCenterNotificationTypeReply: return messageNotificationComponent
default: return null
}
}
@ -130,7 +150,9 @@ Popup {
id: messageNotificationComponent
Rectangle {
visible: activityCenter.currentFilter === ActivityCenter.Filter.All || activityCenter.currentFilter === ActivityCenter.Filter.Mentions
visible: activityCenter.currentFilter === ActivityCenter.Filter.All ||
(model.notificationType === Constants.acitivtyCenterNotificationTypeMention && activityCenter.currentFilter === ActivityCenter.Filter.Mentions) ||
(model.notificationType === Constants.acitivtyCenterNotificationTypeReply && activityCenter.currentFilter === ActivityCenter.Filter.Replies)
width: parent.width
height: childrenRect.height + Style.current.smallPadding
color: model.read ? Style.current.transparent : Utils.setColorAlpha(Style.current.blue, 0.1)
@ -202,6 +224,8 @@ Popup {
ActivityChannelBadge {
name: model.name
chatId: model.chatId
notificationType: model.notificationType
responseTo: model.message.responseTo
anchors.top: notificationMessage.bottom
anchors.left: parent.left
anchors.leftMargin: 61 // TODO find a way to align with the text of the message

View File

@ -31,6 +31,7 @@ Item {
id: mentionsBtn
text: qsTr("Mentions")
type: "secondary"
enabled: hasMentions
size: "small"
highlighted: activityCenter.currentFilter === ActivityCenter.Filter.Mentions
onClicked: activityCenter.currentFilter = ActivityCenter.Filter.Mentions
@ -39,6 +40,7 @@ Item {
StatusButton {
id: repliesbtn
text: qsTr("Replies")
enabled: hasReplies
type: "secondary"
size: "small"
highlighted: activityCenter.currentFilter === ActivityCenter.Filter.Replies
@ -48,6 +50,7 @@ Item {
StatusButton {
id: contactRequestsBtn
text: qsTr("Contact requests")
enabled: hasContactRequests
type: "secondary"
size: "small"
highlighted: activityCenter.currentFilter === ActivityCenter.Filter.ContactRequests

View File

@ -8,6 +8,8 @@ Rectangle {
property string chatId: ""
property string name: "channelName"
property string identicon
property string responseTo
property int notificationType
property int chatType: chatsModel.chats.getChannelType(chatId)
property int realChatType: {
if (chatType === Constants.chatTypeCommunity) {
@ -21,58 +23,115 @@ Rectangle {
id: wrapper
height: 24
width: childrenRect.width + Style.current.smallPadding
width: childrenRect.width + 12
color: Style.current.transparent
border.color: Style.current.borderSecondary
border.width: 1
radius: 11
Connections {
enabled: realChatType === Constants.chatTypeOneToOne
target: profileModel.contacts.list
onContactChanged: {
if (pubkey === wrapper.chatId) {
wrapper.profileImage = appMain.getProfileImage(wrapper.chatId)
Loader {
active: true
height: parent.height
sourceComponent: {
switch (model.notificationType) {
case Constants.acitivtyCenterNotificationTypeMention: return channelComponent
case Constants.acitivtyCenterNotificationTypeReply: return replyComponent
default: return channelComponent
}
}
}
SVGImage {
id: channelIcon
width: 16
height: 16
fillMode: Image.PreserveAspectFit
source: "../../../../img/channel-icon-" + (wrapper.realChatType === Constants.chatTypePublic ? "public-chat.svg" : "group.svg")
anchors.left: parent.left
anchors.leftMargin: 4
anchors.verticalCenter:parent.verticalCenter
Component {
id: replyComponent
Item {
property int replyMessageIndex: chatsModel.getMessageIndex(chatId, responseTo)
property string repliedMessageContent: replyMessageIndex > -1 ? chatsModel.getMessageData(chatId, replyMessageIndex, "message") : "";
width: childrenRect.width
height: parent.height
SVGImage {
id: replyIcon
width: 16
height: 16
source: "../../../../img/reply-small-arrow.svg"
anchors.left: parent.left
anchors.leftMargin: 4
anchors.verticalCenter:parent.verticalCenter
}
StyledTextEdit {
text: Utils.getReplyMessageStyle(Emoji.parse(Utils.linkifyAndXSS(repliedMessageContent), Emoji.size.small), false, appSettings.useCompactMode)
textFormat: Text.RichText
height: 18
width: implicitWidth > 300 ? 300 : implicitWidth
clip: true
anchors.left: replyIcon.right
anchors.leftMargin: 4
color: Style.current.secondaryText
font.weight: Font.Medium
font.pixelSize: 13
anchors.verticalCenter: parent.verticalCenter
selectByMouse: true
}
}
}
StatusIdenticon {
id: contactImage
height: 16
width: 16
chatId: wrapper.chatId
chatName: wrapper.name
chatType: wrapper.realChatType
identicon: wrapper.profileImage || wrapper.identicon
anchors.left: channelIcon.right
anchors.leftMargin: 4
anchors.verticalCenter: parent.verticalCenter
letterSize: 11
}
Component {
id: channelComponent
StyledText {
id: contactInfo
text: wrapper.realChatType !== Constants.chatTypePublic ?
Emoji.parse(Utils.removeStatusEns(Utils.filterXSS(wrapper.name))) :
"#" + Utils.filterXSS(wrapper.name)
anchors.left: contactImage.right
anchors.leftMargin: 4
color: Style.current.secondaryText
font.weight: Font.Medium
font.pixelSize: 13
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: childrenRect.width
height: parent.height
Connections {
enabled: realChatType === Constants.chatTypeOneToOne
target: profileModel.contacts.list
onContactChanged: {
if (pubkey === wrapper.chatId) {
wrapper.profileImage = appMain.getProfileImage(wrapper.chatId)
}
}
}
SVGImage {
id: channelIcon
width: 16
height: 16
fillMode: Image.PreserveAspectFit
source: "../../../../img/channel-icon-" + (wrapper.realChatType === Constants.chatTypePublic ? "public-chat.svg" : "group.svg")
anchors.left: parent.left
anchors.leftMargin: 4
anchors.verticalCenter:parent.verticalCenter
}
StatusIdenticon {
id: contactImage
height: 16
width: 16
chatId: wrapper.chatId
chatName: wrapper.name
chatType: wrapper.realChatType
identicon: wrapper.profileImage || wrapper.identicon
anchors.left: channelIcon.right
anchors.leftMargin: 4
anchors.verticalCenter: parent.verticalCenter
letterSize: 11
}
StyledText {
id: contactInfo
text: wrapper.realChatType !== Constants.chatTypePublic ?
Emoji.parse(Utils.removeStatusEns(Utils.filterXSS(wrapper.name))) :
"#" + Utils.filterXSS(wrapper.name)
anchors.left: contactImage.right
anchors.leftMargin: 4
color: Style.current.secondaryText
font.weight: Font.Medium
font.pixelSize: 13
anchors.verticalCenter: parent.verticalCenter
}
}
}
}

View File

@ -17,7 +17,7 @@ Loader {
property int nameMargin: 6
id: root
active: responseTo != "" && replyMessageIndex > -1
active: responseTo !== "" && replyMessageIndex > -1 && !activityCenterMessage
sourceComponent: Component {
Item {
@ -141,19 +141,7 @@ Loader {
Component.onCompleted: textFieldImplicitWidth = implicitWidth
anchors.top: lblReplyAuthor.bottom
anchors.topMargin: nameMargin
text: `<style type="text/css">`+
`a {`+
`color: ${isCurrentUser && !appSettings.useCompactMode ? Style.current.white : Style.current.textColor};`+
`}`+
`a.mention {`+
`color: ${isCurrentUser ? Style.current.cyan : Style.current.turquoise};`+
`}`+
`</style>`+
`</head>`+
`<body>`+
`${Emoji.parse(Utils.linkifyAndXSS(repliedMessageContent), "26x26")}`+
`</body>`+
`</html>`
text: Utils.getReplyMessageStyle(Emoji.parse(Utils.linkifyAndXSS(repliedMessageContent), Emoji.size.small), isCurrentUser, appSettings.useCompactMode)
textFormat: Text.RichText
color: root.elementsColor
readOnly: true

View File

@ -11,7 +11,7 @@ Item {
property alias textField: chatText
id: root
visible: contentType == Constants.messageType || isEmoji
visible: contentType === Constants.messageType || isEmoji
z: 51
implicitHeight: visible ? (showMoreLoader.active ? childrenRect.height - 10 : chatText.height) : 0

View File

@ -24,10 +24,10 @@ StyledText {
let yesterday = new Date()
yesterday.setDate(now.getDate()-1)
var currentMsgDate = new Date(parseInt(messageTimestamp, 10));
var prevMsgDate = previousMessageTimestamp === "" ? new Date(0) : new Date(parseInt(previousMessageTimestamp, 10));
let currentMsgDate = new Date(parseInt(messageTimestamp, 10));
let prevMsgDate = previousMessageTimestamp === "" ? undefined : new Date(parseInt(previousMessageTimestamp, 10));
if (currentMsgDate.getDay() === prevMsgDate.getDay()) {
if (!!prevMsgDate && currentMsgDate.getDay() === prevMsgDate.getDay()) {
return ""
}

View File

@ -1,3 +0,0 @@
<svg width="22" height="27" viewBox="0 0 22 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.47619 26L1.15528 9.15236C1.07001 4.67527 4.67594 1 9.15383 1H21" stroke="#939BA1" stroke-opacity="0.4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 284 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 5.58946V4.12446C8 3.50346 8.373 3.31246 8.824 3.70246L12.828 7.14746C13.055 7.34246 13.054 7.65746 12.827 7.85146L8.822 11.2975C8.373 11.6855 8 11.4955 8 10.8745V9.49946C5.498 9.49946 4.183 11.3865 3.524 13.0315C3.421 13.2885 3.271 13.2885 3.2 13.0205C3.071 12.5355 3 12.0255 3 11.4995C3 8.52646 5.164 6.06546 8 5.58946Z" fill="#939BA1"/>
</svg>

After

Width:  |  Height:  |  Size: 454 B

View File

@ -13,6 +13,10 @@ QtObject {
readonly property int communityChatInvitationOnlyAccess: 2
readonly property int communityChatOnRequestAccess: 3
readonly property int acitivtyCenterNotificationTypeMention: 3
readonly property int acitivtyCenterNotificationTypeReply: 4
readonly property int maxNbDaysToFetch: 30
readonly property int fetchRangeLast24Hours: 86400
readonly property int fetchRangeLast2Days: 172800

View File

@ -89,6 +89,22 @@ QtObject {
`${msg}`
}
function getReplyMessageStyle(msg, isCurrentUser, useCompactMode) {
return `<style type="text/css">`+
`a {`+
`color: ${isCurrentUser && !useCompactMode ? Style.current.white : Style.current.textColor};`+
`}`+
`a.mention {`+
`color: ${isCurrentUser ? Style.current.cyan : Style.current.turquoise};`+
`}`+
`</style>`+
`</head>`+
`<body>`+
`${msg}`+
`</body>`+
`</html>`
}
function getAppSectionIndex(section) {
let sectionId = -1
switch (section) {