feat: add replies to the activity center
This commit is contained in:
parent
447794f0e7
commit
b1bcd539a2
|
@ -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)
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ""
|
||||
}
|
||||
|
||||
|
|
|
@ -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 |
|
@ -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 |
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue