Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSC2867: Marking rooms as unread #2867

Merged
merged 7 commits into from
Jun 24, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions proposals/2867-rooms_marked_unread.md
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alphapapa says

My chief objection, again, is that there are already multiple criteria to apply to determine whether a room is "unread," and this proposal would make that more complicated, making a new criteria which may appear to conflict with existing ones, and bloat the spec by adding new metadata to offer a feature which could be offered using existing metadata.

we allow the user to move the unread marker to any position,

This is the m.fully_read marker mentioned in the alternatives? How does this translate into a simple "mark as unread button" for a room that many messengers have? Can you reply to the downsides mentioned for that approach there?

I don't understand your question. I explained how it could work. Do you have a specific question about it?

Can you reply to the downsides mentioned for that approach there?

Sure:

When trying to work around this, by setting the marked at a special location like the room creation event then we completely lose the the user's actual read position in a room when using this feature.

I think the non-fully-read marker would still work. In my client, both markers work (not that it's an easy concept for the user to grok).

It makes it harder to distinguish between rooms which happen to have unread messages that you don't necessarily care about and rooms which were manually marked as such and thus should be shown much more prominently.

That seems true. However, I would argue that, for that purpose, this proposal conflates two things: "unread" and "need to deal with something here later." Other systems, such as Slack, offer "save for later" and "remind me later" features that don't conflate "unread" with "task" or "remember this." Instead, they are offered as distinct actions in menus and distinct statuses, as well as distinct lists of unread channels and saved-for-later events.

So I would suggest, for that purpose, that a new proposal be written to offer a way to mark certain event IDs as "saved for later," "bookmarked," "to-do," etc. without having anything to do with "unread" status. The marked-for-later events could be displayed by a client when the user views the room, regardless of what other events have arrived since then. They could also be displayed in a global saved-for-later list across rooms.

Since message events can already be linked to by URL, this should be a natural way to remind the user about certain events in a room that are significant to the user. Also, it would effectively mirror the relevant features of Slack, which seems like a good idea anyway, if Matrix is to compete with it.

In contrast with this proposal, this alternative would enable more powerful features that would be worth "bloating the spec" for. ;)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I've worked through the thread here, and I understand the concern that this could be implemented by moving back the read markers to some prior point to make it seem that the room is unread. I also understand that there's a separate related feature of "flag this room" or "flag these messages" for future reference feature.

I've tried to imagine how a typical client would implement this using read markers. The user story is presumably that they have opened a room (thus marking it as read), so their m.read will point to the most recent event, and the m.fully_read will either point to the most recent event (if less than a page of msgs has arrived since they last fully read the room), or some previous page.

So, if the user manually marks the room as unread, it's not clear where the client should move the m.read and m.fully_read markers to. For typical client UX, it's not an option to let users manually select which events they want to point the markers at (although it's cool that ement.el supports it) - typical users expect a "mark room as unread" button much as they'd get on WhatsApp or similar.

The best I can come up with is that the client would have to remember and persist the value of m.read (and m.fully_read, i guess) at the point of opening the unread room, and reset the markers to their previous values if the user subsequently marks the room as unread.

This already feels quite fiddly for a client to manage. But for it to work in a predictable manner cross-device, you'd need to persist the previous read marker state somewhere shared between clients. That means either account_data, or possibly new read marker types (m.old_read and m.old_fully_read or something). Otherwise if you try to mark a room as unread on a different client to the one where you read a room, it'll reset the read state to some irrelevant ancient place, which would be an unpleasantly broken UX.

At this point, the implementation complexity (including storing state on the server to synchronise between clients) feels at least as fiddly than the "check for m.marked_unread in room account_data" logic proposed in the original MSC. Yes, it's an additional check to apply, but semantically it preserves the actual data of where the user has really read up to (rather than discarding it), and it avoids the implementer having to wrestle with deciding where to move read markers to. Especially given how error-prone moving read-markers are, as we've seen with stuck notifications.

So, i'm afraid my inclination is to go with the proposed MSC. I'll point the rest of the SCT at this thread to encourage them to reconsider their FCP checkboxes if necessary though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't able to parse the thread to figure out whether the goal is to reverse m.fully_read or m.read, but I don't think either option works:

Receipts (m.read) are currently not reversible. Making them reversible would be very complicated on the server side, which is why it's not considered an option. This is already mentioned in the alternatives section.

As for m.fully_read: it does not affect whether a room is read (at least in most clients). AFAIK the goal of m.fully_read is to allow users to keep their scrollback position even after marking a room as read, which is incompatible with using it to determine if a room is unread.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried to imagine how a typical client would implement this using read markers.

Discord has only the feature to "mark as unread from this message on" and not "mark this room as unread". The feature does make sense on Discord and that platform can be known for having a lot of chats and a lot of messages, and we do want to enable these use cases on Matrix. If the conversation is very long, it makes sense to be able to jump to the first message that you need to read, whether it is because you haven't seen it yet, or because you accidentally opened the conversation and then marked it as unread, or because you intend to return to it again. Here is a video demonstrating the feature: https://www.youtube.com/watch?v=rX9cOGFrzMQ.

On the other hand, simpler clients such as Signal, WhatsApp etc only allow you to mark a whole conversation as unread (as described in the MSC itself):

For example if you have a red circle with small numbers inside for counting notifications next to a room then a room without notifications but marked as unread should have just the red circle.

image

It makes it harder to distinguish between rooms which happen to have unread messages that you don't necessarily care about and rooms which were manually marked as such and thus should be shown much more prominently.

In the case of Discord, the clients make no distinction between "unread messages that you don't necessarily care about and rooms which were manually marked as such", and I don't think such distinction is necessary to show.

That being said, as a user, I'd really like to see this feature at all on the spec and ultimately on clients, but I don't feel inclined much towards either option as long as the feature lands without having to wait more years.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allow users to keep their scrollback position even after marking a room as read

@tulir What is the use of being able to keep your scrollback position on a room that you've already read? Are there any clients currently implementing it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's implemented in some Elements at least, it can simultaneously enable three things:

  • opening the room at the bottom instead of the last read position (which is a better default experience in busy rooms)
  • marking the room as read immediately when opened (to avoid annoying users with random delays)
  • allowing the user to jump back to their last read position even when doing both of the above

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several clients already implement "fully read" markers according to the spec, which is what tulir is describing. Reference: https://spec.matrix.org/v1.10/client-server-api/#fully-read-markers

The history for a given room may be split into three sections: messages the user has read (or indicated they aren’t interested in them), messages the user might have read some but not others, and messages the user hasn’t seen yet. The “fully read marker” (also known as a “read marker”) marks the last event of the first section, whereas the user’s read receipt marks the last event of the second section.

m.read is a read receipt and has a specific protocol function relating to notifications. m.fully_read is a user-only read marker to help the user understand where they last left off, regardless of their notification count/involvement in the room. The fully read marker in Element will be the green bar across the timeline, or the "jump up" button if the green line would not be shown to the user if rendered.

This distinction is meant to provide the user with a better experience for managing unseen vs unread messages, and it's very unfortunate that the technical level has been made confused by using extremely similar terminology for both.

For this thread, if commenters could be careful to use "marker" and "receipt" appropriately, it would be appreciated.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ara4n Thanks for your considered reply. I understand why you don't think using the markers/receipts is a good way to implement this feature. I'd still suggest implementing something a bit more flexible and robust, more similar to Slack's features, than to implement this proposal, because this one seems like something less than a 50% solution to those features, which I think are needed for Matrix to be competitive; and if this were implemented first, it would mean clients' having to support a kind of "legacy" implementation as well as a more robust one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conversely, this feature has been asked for for years and while simple, I think it covers the majority of use cases. I vote for getting this in to people's hands. In the future we can always migrate to something more powerful if that ends up being warranted.

aka. let's avoid letting perfect be the enemy of good and iterate instead of blocking further.

Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# MSC2867: Marking rooms as unread
turt2live marked this conversation as resolved.
Show resolved Hide resolved

There is currently no way to mark a room for later attention. A common use-case is receiving a
notification on the go and opening the corresponding room but then deciding to deal with it at a later time.

This MSC introduces an option to manually mark an room as *Unread*.

In the above use-case the user would just mark the room as unread and when later opening a matrix
client on their desktop PC that room would appear prominently in their room list waiting for attention.

A related use-case solved by this proposal is wanting to mute a room's notifications while there's an
ongoing discussion but still flag it for catching up later.

Both WhatsApp and Telegram offer this functionality.

## Proposal

We add a [room account data](https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-user-userid-rooms-roomid-account-data-type)
field `m.marked_unread` which just stores the following:

```json
{
"unread": true | false
}
```

When this is true a client should show the room with an indeterminate unread marker. This marker should
be of similar visual importance to a non-highlight notification badge without the notification count. For example if
you have a red circle with small numbers inside for counting notifications next to a room, then a room
without notifications but marked as unread should have just the red circle. If a client gets new
notifications after marking a room as unread the notification count should be displayed instead as normal.

The `m.fully_read` marker should not be touched when marking a room as unread to keep the users read position
in the room.

Marking a room as read, if a client implements such a functionality, now involves sending a read receipt for the last
event, as well as setting `m.marked_unread` to false.

The unread flag should be cleared when opening the room again.
anoadragon453 marked this conversation as resolved.
Show resolved Hide resolved

## Potential issues

Client not aware of this feature will not clear the unread flag, when reading the room. In addition they'll obviously
not show the room with a special badge. This seems preferable to the alternative of clearing the unread flag of a room
without intending to because it didn't actually show up as unread.

turt2live marked this conversation as resolved.
Show resolved Hide resolved
This proposal has no support for marking threads as unread. This should be handled in a future MSC.

## Alternatives

There are multiple possible alternatives here:

* Marking individual messages as unread as discussed [here](https://github.com/matrix-org/matrix-doc/issues/2506):
This is a far more complex feature that has possible interactions with server-side implementations and notification
counts. This proposal aims to be a far more lightweight alternative. Looking at other messengers marking a room as
unread is a more common operation than marking messages as unread, so it could be argued that others already found
this to strike a good balance of complexity and use-cases covered.
* Modifying the `m.fully_read` marker instead of introducing a new `m.marked_unread` field:
Another idea was setting the `m.fully_read` marker to some earlier event which would then cause clients to show
unread messages again. This has two problems:
* It makes it harder to distinguish between rooms which happen to have unread messages that you don't necessarily
care about and rooms which were manually marked as such and thus should be shown much more prominently.
* When trying to work around this, by setting the marker at a special location like the room creation event, we completely
lose the user's actual read position in a room whenever they use this feature.
* Read receipts could be allowed to go "backwards" to restore notification
counts, though this is likely to be riddled with bugs and unexpected
behaviour for users. It's better for everyone to keep read receipts linearly
progressing forwards.

Bubu marked this conversation as resolved.
Show resolved Hide resolved
## Security considerations

None.

## Unstable prefix

While this feature is not yet fully specced, implementers can use the `com.famedly.marked_unread` room
account data type.

Implementations using this unstable prefix in a released version should automatically migrate
user's unread rooms to `m.marked_unread` when this is released as stable.
This ensures user's unread rooms are not lost.