diff --git a/VERSION b/VERSION index 359ee08a7..7921aa127 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.87.0 +0.87.1 diff --git a/protocol/chat.go b/protocol/chat.go index 451680227..9a252318d 100644 --- a/protocol/chat.go +++ b/protocol/chat.go @@ -101,6 +101,63 @@ type Chat struct { SyncedFrom uint32 `json:"syncedFrom,omitempty"` } +type ChatPreview struct { + // ID is the id of the chat, for public chats it is the name e.g. status, for one-to-one + // is the hex encoded public key and for group chats is a random uuid appended with + // the hex encoded pk of the creator of the chat + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Color string `json:"color"` + // Active indicates whether the chat has been soft deleted + Active bool `json:"active"` + + ChatType ChatType `json:"chatType"` + + // Timestamp indicates the last time this chat has received/sent a message + Timestamp int64 `json:"timestamp"` + // LastClockValue indicates the last clock value to be used when sending messages + LastClockValue uint64 `json:"lastClockValue"` + // DeletedAtClockValue indicates the clock value at time of deletion, messages + // with lower clock value of this should be discarded + DeletedAtClockValue uint64 `json:"deletedAtClockValue"` + + // Denormalized fields + UnviewedMessagesCount uint `json:"unviewedMessagesCount"` + UnviewedMentionsCount uint `json:"unviewedMentionsCount"` + + // Generated username name of the chat for one-to-ones + Alias string `json:"alias,omitempty"` + // Identicon generated from public key + Identicon string `json:"identicon"` + + // Muted is used to check whether we want to receive + // push notifications for this chat + Muted bool `json:"muted,omitempty"` + + // Public key of user profile + Profile string `json:"profile,omitempty"` + + // CommunityID is the id of the community it belongs to + CommunityID string `json:"communityId,omitempty"` + + // CategoryID is the id of the community category this chat belongs to. + CategoryID string `json:"categoryId,omitempty"` + + // Joined is a timestamp that indicates when the chat was joined + Joined int64 `json:"joined,omitempty"` + + // SyncedTo is the time up until it has synced with a mailserver + SyncedTo uint32 `json:"syncedTo,omitempty"` + + // SyncedFrom is the time from when it was synced with a mailserver + SyncedFrom uint32 `json:"syncedFrom,omitempty"` + + Text string `json:"text,omitempty"` + + ContentType protobuf.ChatMessage_ContentType `json:"contentType,omitempty"` +} + func (c *Chat) PublicKey() (*ecdsa.PublicKey, error) { // For one to one chatID is an encoded public key if c.ChatType != ChatTypeOneToOne { diff --git a/protocol/messenger.go b/protocol/messenger.go index 57ceaf768..d1a0f2850 100644 --- a/protocol/messenger.go +++ b/protocol/messenger.go @@ -97,7 +97,6 @@ type Messenger struct { shouldPublishContactCode bool systemMessagesTranslations *systemMessageTranslationsMap allChats *chatMap - latestNActiveChats []*Chat allContacts *contactMap allInstallations *installationMap modifiedInstallations *stringBoolMap @@ -1031,7 +1030,6 @@ func (m *Messenger) Init() error { // Get chat IDs and public keys from the existing chats. // TODO: Get only active chats by the query. chats, err := m.persistence.Chats() - i := 0 if err != nil { return err } @@ -1043,14 +1041,6 @@ func (m *Messenger) Init() error { m.allChats.Store(chat.ID, chat) - // if a user has thousands of chats - // we want to have quick access to the latest 60 sorted active chats, to show them first to the user - // 60 is the 3 screens of chats, so when user will scroll to the end we'll load all chats - if i < 60 { - m.latestNActiveChats = append(m.latestNActiveChats, chat) - i++ - } - if !chat.Active || chat.Timeline() { continue } diff --git a/protocol/messenger_chats.go b/protocol/messenger_chats.go index 006d9e8c4..aa567e791 100644 --- a/protocol/messenger_chats.go +++ b/protocol/messenger_chats.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/status-im/status-go/protocol/common" + "github.com/status-im/status-go/protocol/protobuf" "github.com/status-im/status-go/protocol/requests" "github.com/status-im/status-go/protocol/transport" ) @@ -20,8 +21,57 @@ func (m *Messenger) Chats() []*Chat { return chats } -func (m *Messenger) LatestActiveChats() []*Chat { - return m.latestNActiveChats +func (m *Messenger) ChatsPreview() []*ChatPreview { + var chats []*ChatPreview + + m.allChats.Range(func(chatID string, chat *Chat) (shouldContinue bool) { + if chat.Active { + chatPreview := &ChatPreview{ + ID: chat.ID, + Name: chat.Name, + Description: chat.Description, + Color: chat.Color, + Active: chat.Active, + ChatType: chat.ChatType, + Timestamp: chat.Timestamp, + LastClockValue: chat.LastClockValue, + DeletedAtClockValue: chat.DeletedAtClockValue, + UnviewedMessagesCount: chat.UnviewedMessagesCount, + UnviewedMentionsCount: chat.UnviewedMentionsCount, + Alias: chat.Alias, + Identicon: chat.Identicon, + Muted: chat.Muted, + Profile: chat.Profile, + CommunityID: chat.CommunityID, + CategoryID: chat.CategoryID, + Joined: chat.Joined, + SyncedTo: chat.SyncedTo, + SyncedFrom: chat.SyncedFrom, + } + if chat.LastMessage != nil { + chatPreview.ContentType = chat.LastMessage.ContentType + if chat.LastMessage.ContentType == protobuf.ChatMessage_TEXT_PLAIN { + if len(chat.LastMessage.Text) > 200 { + chatPreview.Text = chat.LastMessage.Text[:200] + } else { + chatPreview.Text = chat.LastMessage.Text + } + } + } + + chats = append(chats, chatPreview) + } + + return true + }) + + return chats +} + +func (m *Messenger) Chat(chatID string) *Chat { + chat, _ := m.allChats.Load(chatID) + + return chat } func (m *Messenger) ActiveChats() []*Chat { diff --git a/services/ext/api.go b/services/ext/api.go index b7ae2820c..2a0fe2310 100644 --- a/services/ext/api.go +++ b/services/ext/api.go @@ -268,8 +268,12 @@ func (api *PublicAPI) Chats(parent context.Context) []*protocol.Chat { return api.service.messenger.Chats() } -func (api *PublicAPI) LatestActiveChats(parent context.Context) []*protocol.Chat { - return api.service.messenger.LatestActiveChats() +func (api *PublicAPI) ChatsPreview(parent context.Context) []*protocol.ChatPreview { + return api.service.messenger.ChatsPreview() +} + +func (api *PublicAPI) Chat(parent context.Context, chatID string) *protocol.Chat { + return api.service.messenger.Chat(chatID) } func (api *PublicAPI) ActiveChats(parent context.Context) []*protocol.Chat {