A group where a member is waiting in a support chat has something to read - the
chat list row already flags it - but the unread filter did not list it, so a
moderator filtering for unread silently skipped the member waiting on them.
chatStats.unreadCount is filled by a query scoped to the main conversation
(group_scope_tag IS NULL), so unreadTag cannot see support scopes at all.
Match on Chat.hasUnread, which adds supportUnreadCount to unreadTag, gated on
the chat not being muted to "mute all" - so a support chat waiting in a fully
muted group does not put it in the filter, matching what the profile's unread
count does with that group. Marking such a chat unread by hand still lists it,
through unreadTag's unreadChat branch.
Two consequences of taking supportUnreadCount whole are deliberate. For a
moderator it is membersRequireAttention, which counts members pending approval
as well as unread messages, and only approving or rejecting clears those - so
the group stays listed until the moderator acts. And mentions-only chats still
count support unread, on the view that mentions-only is a statement about group
chatter and the user's own line to the admins is not chatter.
The count is seeded by getUsersInfo, which counts RcvNew items where ntfsEnabled
holds - every item for an unmuted chat, only mentions for a mentions-only one,
none for a muted one. The deltas that maintain it afterwards did not follow that
rule for the active profile: addChatItem incremented for every item regardless
of the chat's notification setting, the mark-read helpers subtracted the full
unread count, removeChat left a deleted chat's unread behind, and changing the
setting moved a chat between rules without moving the count.
Chat.userUnreadCount names what a chat contributes, and it is not a new rule:
totalUnreadCountForAllUsers already computed exactly this inline for the app
badge, and now calls it. Every site that changes a chat's stats, its settings or
its presence reports the contribution before and after, and the count moves by
the difference.
For that to hold the stats it reads have to be maintained, so on Android and
desktop decreaseCounterInPrimaryContext now decrements unreadMentions alongside
unreadCount when the item was a mention. Without it a mentions-only chat's
contribution never moved on any of that function's three paths - a deleted item,
a moderated member item, or an item going from New to Read. iOS already passed
the mention delta on its deletion paths.
This is visible beyond the profile picker, which badges only other profiles: the
desktop tray dot sums the count across profiles including the active one, and on
iOS these same deltas drive the app icon badge. So on iOS, muting a chat with
unread now drops the badge by its contribution, deleting a chat drops it, and a
message in a muted chat no longer raises it - each of which now agrees with
totalUnreadCountForAllUsers, which the badge is also set from.
addChat is deliberately not the mirror of removeChat: adding a chat means it is
being loaded into view, and its items were already counted by the seed, so
counting them again on ChatItemsLoader's addChat would double them. The one
place that removes and re-adds a chat while keeping its items - deleting a
contact in "keep conversation" mode on iOS - now carries its stats across and
restores the contribution explicitly, since the core keeps both the contact row
and its items there and the seed still counts them.
Wherever the chat list is re-read wholesale the counts are re-read with it: both
resume paths, and setting a chat item TTL, which deletes items across every
profile and so leaves every profile's count stale, not just the active one. They
are assigned before the chats, which matters on iOS because updateChats
recomputes the app badge from users there. Reading users is best effort on both
platforms - losing them must not cost us the chats already fetched.
This does not make the count exact. getUsersInfo has no group_scope_tag filter
where the query behind chatStats.unreadCount does, so the seed counts
support-scope items that no client-side rule can, and the count steps up by the
outstanding support unread on each reseed. Two paths also install a whole
chatStats without moving the count: processLoadedChat's updateChatStats on
Android and desktop, and replaceChat on both - from a pre-call snapshot in the
mark-read paths there, and from the server in iOS's contact-request handler.
Group chat and its support chats have the same chat id, so a draft saved
in "chat with admins" was restored in the group chat and shown as its draft
in the chat list. Include chat scope in the draft chat id.
Also save the draft when support chat is closed without changing chat id -
in that case KeyChangeEffect that saves drafts doesn't run.
* core: option to show group as sender of chat item (for the initial items, e.g. welcome message)
* add chat item to contact request chats
* return AChat for prepared chats and contact requests
* update iOS api types, show prepared contact as blue, show preview info when content message is not available (previously was showing feature item)
* ios: remove ContactType
* ios: show group as sender, fix avatar not showing when member message sequence starts with merged items
* ios: update compose UI for all connection scenarios
* address settings
* ios: address settings UI
* fix tests
* fix tests 2
* ios: fix minor issues
* ios: fix toolbar in member support chat
* refactor
* refactor nav buttons
* ios: unread reports, members requiring attention
* top bar destop (special case for 1 support chat)
* put Navigation view higher in hierarchy
* use nav title for knocking
* refactor loading secondary chat, overlay fake toolbar for knocking chats
* fix member reports toolbar
* unread counter for member's support chat
* core: pass event and response error without dedicated constructor
* ios: WIP
* android, desktop: update UI for new API
* ios: fix parser
* fix showing invalid chats
* fix mobile api tests
* ios: split ChatResponse to 3 enums, decode API results on the same thread
* tweak types
* remove throws
* rename
* ios: loading progress moved to chat list
* place
* changes
* large spinner, smaller timeout
---------
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
* android, desktop: archive multiple reports
* ios
* change
* changes
* fix changing counter
* fix changing counter2
* fix changing counter3
* unused
* fix android
* android notification
* simplify
* ios notification
* orange
* orange
* core: update api
* buttons
* ios api
* android api
* fix 4 buttons
* buttons and check for member active status
* android colors and member active
* show delete group button when not in the group anymore
* title
---------
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
* api types
* display for mentions and replys
* picking of mentions
* notifications (wip)
* auto tagging
* show selected mention
* Divider and list bg
* stop keyboard dismiss on scroll from ios 16
* change notification mode in all views
* icon for mentions notification mode
* make unread states work in memory and chat preview
* preview fixes
* fix unread status when mark read manually
* update library
* fixed padding
* fix layout
* use memberName
* remove ChatNtfs, show mentions in context items and in drafts, make mentions a map in ComposeState
* rework mentions (WIP)
* better
* show mention name containing @ in quotes
* editing mentions
* editing
* mentionColor
* opacity
* refactor mention counter
* fix unread layout
---------
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>