Add unviewed mentions count

This commit add a field to count the unviewed mentions in a given chat.
The usage pattern is identical to `UnviewedMessagesCount`
This commit is contained in:
Andrea Maria Piana 2021-05-26 08:38:25 +02:00
parent 70cbad6aba
commit 11de62749d
8 changed files with 88 additions and 46 deletions

View File

@ -60,6 +60,7 @@ type Chat struct {
// Denormalized fields
UnviewedMessagesCount uint `json:"unviewedMessagesCount"`
UnviewedMentionsCount uint `json:"unviewedMentionsCount"`
LastMessage *common.Message `json:"lastMessage"`
// Group chat fields

View File

@ -148,18 +148,7 @@ func (m *MessageHandler) HandleMembershipUpdate(messageState *ReceivedMessageSta
chat.updateChatFromGroupMembershipChanges(group)
if !chat.Active {
notification := &ActivityCenterNotification{
ID: types.FromHex(chat.ID),
Name: chat.Name,
LastMessage: chat.LastMessage,
Type: ActivityCenterNotificationTypeNewPrivateGroupChat,
Timestamp: messageState.CurrentMessageState.WhisperTimestamp,
ChatID: chat.ID,
}
err := m.addActivityCenterNotification(messageState, notification)
if err != nil {
m.logger.Warn("failed to create activity center notification", zap.Error(err))
}
m.createMessageNotification(chat, messageState)
}
systemMessages := buildSystemMessages(message.Events, translations)
@ -190,6 +179,28 @@ func (m *MessageHandler) HandleMembershipUpdate(messageState *ReceivedMessageSta
return nil
}
func (m *MessageHandler) createMessageNotification(chat *Chat, messageState *ReceivedMessageState) {
var notificationType ActivityCenterType
if chat.OneToOne() {
notificationType = ActivityCenterNotificationTypeNewOneToOne
} else {
notificationType = ActivityCenterNotificationTypeNewPrivateGroupChat
}
notification := &ActivityCenterNotification{
ID: types.FromHex(chat.ID),
Name: chat.Name,
LastMessage: chat.LastMessage,
Type: notificationType,
Timestamp: messageState.CurrentMessageState.WhisperTimestamp,
ChatID: chat.ID,
}
err := m.addActivityCenterNotification(messageState, notification)
if err != nil {
m.logger.Warn("failed to create activity center notification", zap.Error(err))
}
}
func (m *MessageHandler) handleCommandMessage(state *ReceivedMessageState, message *common.Message) error {
message.ID = state.CurrentMessageState.MessageID
message.From = state.CurrentMessageState.Contact.ID
@ -232,7 +243,7 @@ func (m *MessageHandler) handleCommandMessage(state *ReceivedMessageState, messa
// Increase unviewed count
if !common.IsPubKeyEqual(message.SigPubKey, &m.identity.PublicKey) {
chat.UnviewedMessagesCount++
m.updateUnviewedCounts(chat, message.Mentioned)
message.OutgoingStatus = ""
} else {
// Our own message, mark as sent
@ -245,18 +256,7 @@ func (m *MessageHandler) handleCommandMessage(state *ReceivedMessageState, messa
}
if !chat.Active {
notification := &ActivityCenterNotification{
ID: types.FromHex(chat.ID),
Type: ActivityCenterNotificationTypeNewOneToOne,
Name: chat.Name,
LastMessage: chat.LastMessage,
Timestamp: state.CurrentMessageState.WhisperTimestamp,
ChatID: chat.ID,
}
err := m.addActivityCenterNotification(state, notification)
if err != nil {
m.logger.Warn("failed to save notification", zap.Error(err))
}
m.createMessageNotification(chat, state)
}
// Add to response
@ -625,7 +625,7 @@ func (m *MessageHandler) HandleChatMessage(state *ReceivedMessageState) error {
// Increase unviewed count
if !common.IsPubKeyEqual(receivedMessage.SigPubKey, &m.identity.PublicKey) {
chat.UnviewedMessagesCount++
m.updateUnviewedCounts(chat, receivedMessage.Mentioned)
} else {
// Our own message, mark as sent
receivedMessage.OutgoingStatus = common.OutgoingStatusSent
@ -638,19 +638,9 @@ func (m *MessageHandler) HandleChatMessage(state *ReceivedMessageState) error {
// If the chat is not active, create a notification in the center
if chat.OneToOne() && !chat.Active {
notification := &ActivityCenterNotification{
ID: types.FromHex(chat.ID),
Name: chat.Name,
LastMessage: chat.LastMessage,
Type: ActivityCenterNotificationTypeNewOneToOne,
Timestamp: state.CurrentMessageState.WhisperTimestamp,
ChatID: chat.ID,
}
err := m.addActivityCenterNotification(state, notification)
if err != nil {
m.logger.Warn("failed to create notification", zap.Error(err))
}
m.createMessageNotification(chat, state)
}
// Set in the modified maps chat
state.Response.AddChat(chat)
// TODO(samyoul) remove storing of an updated reference pointer?
@ -1205,3 +1195,10 @@ func (m *MessageHandler) isMessageAllowedFrom(allContacts *contactMap, publicKey
// Otherwise we check if we added it
return contact.IsAdded(), nil
}
func (m *MessageHandler) updateUnviewedCounts(chat *Chat, mentioned bool) {
chat.UnviewedMessagesCount++
if mentioned {
chat.UnviewedMentionsCount++
}
}

View File

@ -1059,7 +1059,7 @@ func (db sqlitePersistence) MarkAllRead(chatID string) error {
if err != nil {
return err
}
_, err = tx.Exec(`UPDATE chats SET unviewed_message_count = 0 WHERE id = ?`, chatID)
_, err = tx.Exec(`UPDATE chats SET unviewed_mentions_count = 0, unviewed_message_count = 0 WHERE id = ?`, chatID)
return err
}
@ -1101,8 +1101,12 @@ func (db sqlitePersistence) MarkMessagesSeen(chatID string, ids []string) (uint6
SET unviewed_message_count =
(SELECT COUNT(1)
FROM user_messages
WHERE local_chat_id = ? AND seen = 0)
WHERE id = ?`, chatID, chatID)
WHERE local_chat_id = ? AND seen = 0),
unviewed_mentions_count =
(SELECT COUNT(1)
FROM user_messages
WHERE local_chat_id = ? AND seen = 0 AND mentioned)
WHERE id = ?`, chatID, chatID, chatID)
return count, err
}
@ -1158,7 +1162,8 @@ func (db sqlitePersistence) BlockContact(contact *Contact) ([]*Chat, error) {
_, err = tx.Exec(`
UPDATE chats
SET
unviewed_message_count = (SELECT COUNT(1) FROM user_messages WHERE seen = 0 AND local_chat_id = chats.id)`)
unviewed_message_count = (SELECT COUNT(1) FROM user_messages WHERE seen = 0 AND local_chat_id = chats.id),
unviewed_mentions_count = (SELECT COUNT(1) FROM user_messages WHERE seen = 0 AND local_chat_id = chats.id AND mentioned)`)
if err != nil {
return nil, err
}
@ -1427,6 +1432,7 @@ func (db sqlitePersistence) clearHistory(chat *Chat, currentClockValue uint64, t
chat.LastMessage = nil
chat.UnviewedMessagesCount = 0
chat.UnviewedMentionsCount = 0
err := db.deleteMessagesByChatID(chat.ID, tx)
if err != nil {

View File

@ -3068,6 +3068,7 @@ func (m *Messenger) MarkAllRead(chatID string) error {
}
chat.UnviewedMessagesCount = 0
chat.UnviewedMentionsCount = 0
// TODO(samyoul) remove storing of an updated reference pointer?
m.allChats.Store(chat.ID, chat)
return nil

View File

@ -334,13 +334,18 @@ func buildTestMessage(chat Chat) *common.Message {
func (s *MessengerSuite) TestMarkMessagesSeen() {
chat := CreatePublicChat("test-chat", s.m.transport)
chat.UnviewedMessagesCount = 2
chat.UnviewedMentionsCount = 3
err := s.m.SaveChat(chat)
s.Require().NoError(err)
inputMessage1 := buildTestMessage(*chat)
inputMessage1.ID = "1"
inputMessage1.Seen = false
inputMessage1.Text = "hey @" + common.PubkeyToHex(&s.m.identity.PublicKey)
inputMessage1.Mentioned = true
inputMessage2 := buildTestMessage(*chat)
inputMessage2.ID = "2"
inputMessage2.Text = "hey @" + common.PubkeyToHex(&s.m.identity.PublicKey)
inputMessage2.Mentioned = true
inputMessage2.Seen = false
err = s.m.SaveMessages([]*common.Message{inputMessage1, inputMessage2})
@ -359,6 +364,7 @@ func (s *MessengerSuite) TestMarkMessagesSeen() {
for _, c := range chats {
if c.ID == chat.ID {
s.Require().Equal(uint(1), c.UnviewedMessagesCount)
s.Require().Equal(uint(1), c.UnviewedMentionsCount)
}
}
}

View File

@ -31,6 +31,7 @@
// 1619094007_add_joined_chat_field.up.sql (101B)
// 1619099821_add_last_synced_field.up.sql (226B)
// 1621933219_add_mentioned.up.sql (70B)
// 1622010048_add_unviewed_mentions_count.up.sql (114B)
// README.md (554B)
// doc.go (850B)
@ -721,6 +722,26 @@ func _1621933219_add_mentionedUpSql() (*asset, error) {
return a, nil
}
var __1622010048_add_unviewed_mentions_countUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\xce\x48\x2c\x29\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x28\xcd\x2b\xcb\x4c\x2d\x4f\x4d\x89\xcf\x4d\xcd\x2b\xc9\xcc\xcf\x2b\x8e\x4f\xce\x2f\xcd\x2b\x51\xf0\xf4\x0b\x51\x70\x71\x75\x73\x0c\xf5\x09\x51\x30\xb0\xe6\x0a\x0d\x70\x71\x0c\x81\x69\x0f\x76\x0d\xc1\xa9\xcf\x16\xa4\x1a\x10\x00\x00\xff\xff\x0f\xdf\x43\x35\x72\x00\x00\x00")
func _1622010048_add_unviewed_mentions_countUpSqlBytes() ([]byte, error) {
return bindataRead(
__1622010048_add_unviewed_mentions_countUpSql,
"1622010048_add_unviewed_mentions_count.up.sql",
)
}
func _1622010048_add_unviewed_mentions_countUpSql() (*asset, error) {
bytes, err := _1622010048_add_unviewed_mentions_countUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1622010048_add_unviewed_mentions_count.up.sql", size: 114, mode: os.FileMode(0644), modTime: time.Unix(1622010095, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7c, 0x16, 0x85, 0xa6, 0x5b, 0xe1, 0x66, 0xb9, 0x84, 0xbe, 0x7f, 0xa, 0x77, 0x23, 0xb9, 0xef, 0x8e, 0x2, 0x8, 0xfc, 0x61, 0xb2, 0x43, 0xa9, 0x63, 0xae, 0xb4, 0xdf, 0x30, 0xb1, 0x61, 0x4b}}
return a, nil
}
var _readmeMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x91\xc1\xce\xd3\x30\x10\x84\xef\x7e\x8a\x91\x7a\x01\xa9\x2a\x8f\xc0\x0d\x71\x82\x03\x48\x1c\xc9\x36\x9e\x36\x96\x1c\x6f\xf0\xae\x93\xe6\xed\x91\xa3\xc2\xdf\xff\x66\xed\xd8\x33\xdf\x78\x4f\xa7\x13\xbe\xea\x06\x57\x6c\x35\x39\x31\xa7\x7b\x15\x4f\x5a\xec\x73\x08\xbf\x08\x2d\x79\x7f\x4a\x43\x5b\x86\x17\xfd\x8c\x21\xea\x56\x5e\x47\x90\x4a\x14\x75\x48\xde\x64\x37\x2c\x6a\x96\xae\x99\x48\x05\xf6\x27\x77\x13\xad\x08\xae\x8a\x51\xe7\x25\xf3\xf1\xa9\x9f\xf9\x58\x58\x2c\xad\xbc\xe0\x8b\x56\xf0\x21\x5d\xeb\x4c\x95\xb3\xae\x84\x60\xd4\xdc\xe6\x82\x5d\x1b\x36\x6d\x39\x62\x92\xf5\xb8\x11\xdb\x92\xd3\x28\xce\xe0\x13\xe1\x72\xcd\x3c\x63\xd4\x65\x87\xae\xac\xe8\xc3\x28\x2e\x67\x44\x66\x3a\x21\x25\xa2\x72\xac\x14\x67\xbc\x84\x9f\x53\x32\x8c\x52\x70\x25\x56\xd6\xfd\x8d\x05\x37\xad\x30\x9d\x9f\xa6\x86\x0f\xcd\x58\x7f\xcf\x34\x93\x3b\xed\x90\x9f\xa4\x1f\xcf\x30\x85\x4d\x07\x58\xaf\x7f\x25\xc4\x9d\xf3\x72\x64\x84\xd0\x7f\xf9\x9b\x3a\x2d\x84\xef\x85\x48\x66\x8d\xd8\x88\x9b\x8c\x8c\x98\x5b\xf6\x74\x14\x4e\x33\x0d\xc9\xe0\x93\x38\xda\x12\xc5\x69\xbd\xe4\xf0\x2e\x7a\x78\x07\x1c\xfe\x13\x9f\x91\x29\x31\x95\x7b\x7f\x62\x59\x37\xb4\xe5\x5e\x25\xfe\x33\xee\xd5\x53\x71\xd6\xda\x3a\xd8\xcb\xde\x2e\xf8\xa1\x90\x55\x53\x0c\xc7\xaa\x0d\xe9\x76\x14\x29\x1c\x7b\x68\xdd\x2f\xe1\x6f\x00\x00\x00\xff\xff\x3c\x0a\xc2\xfe\x2a\x02\x00\x00")
func readmeMdBytes() ([]byte, error) {
@ -914,6 +935,8 @@ var _bindata = map[string]func() (*asset, error){
"1621933219_add_mentioned.up.sql": _1621933219_add_mentionedUpSql,
"1622010048_add_unviewed_mentions_count.up.sql": _1622010048_add_unviewed_mentions_countUpSql,
"README.md": readmeMd,
"doc.go": docGo,
@ -991,8 +1014,9 @@ var _bintree = &bintree{nil, map[string]*bintree{
"1619094007_add_joined_chat_field.up.sql": &bintree{_1619094007_add_joined_chat_fieldUpSql, map[string]*bintree{}},
"1619099821_add_last_synced_field.up.sql": &bintree{_1619099821_add_last_synced_fieldUpSql, map[string]*bintree{}},
"1621933219_add_mentioned.up.sql": &bintree{_1621933219_add_mentionedUpSql, map[string]*bintree{}},
"README.md": &bintree{readmeMd, map[string]*bintree{}},
"doc.go": &bintree{docGo, map[string]*bintree{}},
"1622010048_add_unviewed_mentions_count.up.sql": &bintree{_1622010048_add_unviewed_mentions_countUpSql, map[string]*bintree{}},
"README.md": &bintree{readmeMd, map[string]*bintree{}},
"doc.go": &bintree{docGo, map[string]*bintree{}},
}}
// RestoreAsset restores an asset under the given directory.

View File

@ -0,0 +1,2 @@
ALTER TABLE chats ADD COLUMN unviewed_mentions_count INT DEFAULT 0;
UPDATE chats SET unviewed_mentions_count = 0;

View File

@ -130,8 +130,8 @@ func (db sqlitePersistence) saveChat(tx *sql.Tx, chat Chat) error {
}
// Insert record
stmt, err := tx.Prepare(`INSERT INTO chats(id, name, color, active, type, timestamp, deleted_at_clock_value, unviewed_message_count, last_clock_value, last_message, members, membership_updates, muted, invitation_admin, profile, community_id, joined, synced_from, synced_to)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?,?,?,?,?,?)`)
stmt, err := tx.Prepare(`INSERT INTO chats(id, name, color, active, type, timestamp, deleted_at_clock_value, unviewed_message_count, unviewed_mentions_count, last_clock_value, last_message, members, membership_updates, muted, invitation_admin, profile, community_id, joined, synced_from, synced_to)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?,?,?,?,?,?,?)`)
if err != nil {
return err
}
@ -146,6 +146,7 @@ func (db sqlitePersistence) saveChat(tx *sql.Tx, chat Chat) error {
chat.Timestamp,
chat.DeletedAtClockValue,
chat.UnviewedMessagesCount,
chat.UnviewedMentionsCount,
chat.LastClockValue,
encodedLastMessage,
encodedMembers.Bytes(),
@ -235,6 +236,7 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) {
chats.timestamp,
chats.deleted_at_clock_value,
chats.unviewed_message_count,
chats.unviewed_mentions_count,
chats.last_clock_value,
chats.last_message,
chats.members,
@ -278,6 +280,7 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) {
&chat.Timestamp,
&chat.DeletedAtClockValue,
&chat.UnviewedMessagesCount,
&chat.UnviewedMentionsCount,
&chat.LastClockValue,
&lastMessageBytes,
&encodedMembers,
@ -364,6 +367,7 @@ func (db sqlitePersistence) Chat(chatID string) (*Chat, error) {
timestamp,
deleted_at_clock_value,
unviewed_message_count,
unviewed_mentions_count,
last_clock_value,
last_message,
members,
@ -383,6 +387,7 @@ func (db sqlitePersistence) Chat(chatID string) (*Chat, error) {
&chat.Timestamp,
&chat.DeletedAtClockValue,
&chat.UnviewedMessagesCount,
&chat.UnviewedMentionsCount,
&chat.LastClockValue,
&lastMessageBytes,
&encodedMembers,