diff --git a/VERSION b/VERSION index 021c2636b..28cfb23fc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.91.2 +0.91.3 diff --git a/protocol/activity_center_persistence.go b/protocol/activity_center_persistence.go index 85e3d2327..1dc932bad 100644 --- a/protocol/activity_center_persistence.go +++ b/protocol/activity_center_persistence.go @@ -85,7 +85,8 @@ func (db sqlitePersistence) SaveActivityCenterNotification(notification *Activit _ = tx.Rollback() }() - if notification.Type == ActivityCenterNotificationTypeNewOneToOne { + if notification.Type == ActivityCenterNotificationTypeNewOneToOne || + notification.Type == ActivityCenterNotificationTypeNewPrivateGroupChat { // Delete other notifications so it pop us again if not currently dismissed _, err = tx.Exec(`DELETE FROM activity_center_notifications WHERE id = ? AND (dismissed OR accepted)`, notification.ID) if err != nil { diff --git a/protocol/messenger_handler.go b/protocol/messenger_handler.go index 7c07cd967..7c01071ea 100644 --- a/protocol/messenger_handler.go +++ b/protocol/messenger_handler.go @@ -62,7 +62,11 @@ func (m *Messenger) HandleMembershipUpdate(messageState *ReceivedMessageState, c //we need to create a new chat instance like we don't have a chat and just use a regular invitation flow waitingForApproval := chat != nil && len(chat.InvitationAdmin) > 0 ourKey := contactIDFromPublicKey(&m.identity.PublicKey) + isActive := messageState.CurrentMessageState.Contact.Added || messageState.CurrentMessageState.Contact.ID == ourKey || waitingForApproval + showPushNotification := isActive && messageState.CurrentMessageState.Contact.ID != ourKey + // wasUserAdded indicates whether the user has been added to the group with this update + wasUserAdded := false if chat == nil || waitingForApproval { if len(message.Events) == 0 { return errors.New("can't create new group chat without events") @@ -102,10 +106,11 @@ func (m *Messenger) HandleMembershipUpdate(messageState *ReceivedMessageState, c if !group.IsMember(ourKey) { return errors.New("can't create a new group chat without us being a member") } + // A new chat always adds us + wasUserAdded = true newChat := CreateGroupChat(messageState.Timesource) // We set group chat inactive and create a notification instead // unless is coming from us or a contact or were waiting for approval - isActive := messageState.CurrentMessageState.Contact.Added || messageState.CurrentMessageState.Contact.ID == ourKey || waitingForApproval newChat.Active = isActive chat = &newChat @@ -115,14 +120,6 @@ func (m *Messenger) HandleMembershipUpdate(messageState *ReceivedMessageState, c return errors.Wrap(err, "failed to get group creator") } - profilePicturesVisibility, err := m.settings.GetProfilePicturesVisibility() - if err != nil { - return errors.Wrap(err, "failed to get profilePicturesVisibility setting") - } - - if chat.Active && messageState.CurrentMessageState.Contact.ID != ourKey { - messageState.Response.AddNotification(NewPrivateGroupInviteNotification(chat.ID, chat, messageState.CurrentMessageState.Contact, profilePicturesVisibility)) - } } else { existingGroup, err := newProtocolGroupFromChat(chat) if err != nil { @@ -138,12 +135,34 @@ func (m *Messenger) HandleMembershipUpdate(messageState *ReceivedMessageState, c return errors.Wrap(err, "failed to create a group with new membership updates") } chat.updateChatFromGroupMembershipChanges(group) + + wasUserAdded = !existingGroup.IsMember(ourKey) && + updateGroup.IsMember(ourKey) + + // Reactivate deleted group chat on re-invite from contact + chat.Active = chat.Active || (isActive && wasUserAdded) + + // Show push notifications when our key is added to members list and chat is Active + showPushNotification = showPushNotification && wasUserAdded } - if !chat.Active { + // Only create a message notification when the user is added, not when removed + if !chat.Active && wasUserAdded { + chat.Highlight = true m.createMessageNotification(chat, messageState) } + profilePicturesVisibility, err := m.settings.GetProfilePicturesVisibility() + if err != nil { + return errors.Wrap(err, "failed to get profilePicturesVisibility setting") + } + + if showPushNotification { + // chat is highlighted for new group invites or group re-invites + chat.Highlight = true + messageState.Response.AddNotification(NewPrivateGroupInviteNotification(chat.ID, chat, messageState.CurrentMessageState.Contact, profilePicturesVisibility)) + } + systemMessages := buildSystemMessages(message.Events, translations) for _, message := range systemMessages { diff --git a/protocol/messenger_handler_test.go b/protocol/messenger_handler_test.go index 0f1f3f08e..735e62602 100644 --- a/protocol/messenger_handler_test.go +++ b/protocol/messenger_handler_test.go @@ -1,6 +1,7 @@ package protocol import ( + "context" "crypto/ecdsa" "testing" @@ -176,4 +177,23 @@ func (s *EventToSystemMessageSuite) TestHandleMembershipUpdate() { s.Require().NoError(err) s.Require().Len(state.Response.Notifications(), 1) s.Require().Equal(state.Response.Notifications()[0].Category, localnotifications.CategoryGroupInvite) + s.Require().Len(state.Response.Chats(), 1) + + chat := state.Response.Chats()[0] + + // Decline event, setting chat inactive + response, err := s.m.LeaveGroupChat(context.Background(), chat.ID, true) + s.Require().NoError(err) + + s.Require().Len(response.Chats(), 1) + + chat = response.Chats()[0] + + // If the same response is handled, it should not show another notification & the chat should remain inactive + state.Response = &MessengerResponse{} + err = s.m.HandleMembershipUpdate(state, chat, *rawMembershipUpdateMessage2, defaultSystemMessagesTranslations) + s.Require().NoError(err) + s.Require().Len(state.Response.Notifications(), 0) + s.Require().Len(state.Response.Chats(), 1) + s.Require().False(state.Response.Chats()[0].Active) }