project-robius / robrix

A Matrix chat client written in pure Rust using the Makepad UI toolkit and the Robius app dev framework
MIT License
67 stars 11 forks source link

Add typing notifications: "user XYZ is typing..." #99

Open kevinaboos opened 1 month ago

kevinaboos commented 1 month ago

The desired feature is to display when one or more users are currently typing a message in the currently-viewed room.

Implementation ideas

Fortunately, this is relatively straightforward thanks to the Matrix SDK's ability to subscribe to typing notifications for a given Room.

When opening up a room_screen and showing a room's timeline, we should use our submit_async_request() function (and add a corresponding new variant to the MatrixRequest enum) to create a background async task that calls the subscribe_to_typing_notifications() function. This must be done on a background async task because the returned Receiver object only offers an async recv() function.

On that async background task, when a new vector of User IDs is received, it should send an update to that timeline by using the timeline_update_sender in the RoomInfo struct: https://github.com/project-robius/robrix/blob/a3fe45319e97a637cf6f5cb9d41e63c3756992dd/src/sliding_sync.rs#L490

There are examples of using the timeline_update_sender in sliding_sync.rs, for example: https://github.com/project-robius/robrix/blob/a3fe45319e97a637cf6f5cb9d41e63c3756992dd/src/sliding_sync.rs#L192

Then, a new variant should be added to the TimelineUpdate enum to represent a newly-received set of User IDs who are typing, perhaps TimelineUpdate::TypingUsers{...}. Here is that enum in the code: https://github.com/project-robius/robrix/blob/a3fe45319e97a637cf6f5cb9d41e63c3756992dd/src/home/room_screen.rs#L707

The async background task should send an instance of that new enum variant on every async recv(), and then the UI thread should handle it along with the other TimelineUpdate variants. The update handling is done in the Timeline::handle_event() code here: https://github.com/project-robius/robrix/blob/a3fe45319e97a637cf6f5cb9d41e63c3756992dd/src/home/room_screen.rs#L972


In terms of UI behavior, we should add another View (that contains a simple Label) in between the timeline and the View holding the message_input view. That part of the code is here: https://github.com/project-robius/robrix/blob/a3fe45319e97a637cf6f5cb9d41e63c3756992dd/src/home/room_screen.rs#L440-L444

So, the new view for the typing notifications should be inserted at Line 442 above.

That new view should be hidden by default, and only set to visible when one or more users are actually typing.

As a visual example, this is how Discord displays the typing notification, which I think is a very pleasant way of doing so. This is what we should imitate:

image

Here's how Element displays the typing notification, which I think is a bit too bulky/spacious from a UI standpoint.

image

So we should prefer the Discord-style single line label that sits above the message input box. If the number of users concurrently typing is too large to fit on one line (or is more than 2 users), the text displayed should be something like "User A, User B, and N others are typing ..."