### 已读与未读标记 #### 完全已读标记 某个房间的消息历史可以被划分为三个部分:用户已读(或表示对其不感兴趣)的消息、用户可能只读了一部分的消息,以及用户尚未见过的消息。“完全已读标记”(也称为“已读标记”)标记了第一部分的最后一个事件,而用户的已读回执则标记了第二部分的最后一个事件。 ##### 事件 用户的完全已读标记作为房间[账户数据](#client-config)中的一个事件进行保存。可以通过读取该事件来判断用户当前的完全已读标记在房间中的位置,并且和其他账户数据事件一样,该事件在更新时将通过事件流推送下发。 完全已读标记以 `m.fully_read` 事件的形式保存。如果该事件在用户账户数据中不存在,应将完全已读标记视为用户的已读回执位置。 {{% event event="m.fully_read" %}} ##### 客户端行为 客户端无法通过直接修改 `m.fully_read` 账户数据事件来更新完全已读标记。相反,客户端必须使用已读标记 API 来更改该值。 {{% changed-in v="1.4" %}} 现在可以通过 `/read_markers` 发送 `m.read.private` 回执。 已读标记 API 还可以在设置完全已读标记位置的同时,更新用户的已读回执(`m.read` 或 `m.read.private`)的位置。因为已读回执和已读标记通常会被同时更新,因此客户端可能希望节省一次额外的 HTTP 调用。提供 `m.read` 和/或 `m.read.private` 的效果与对 [`/receipt/{receiptType}/{eventId}`](#post_matrixclientv3roomsroomidreceiptreceipttypeeventid) 的请求相同。 {{% http-api spec="client-server" api="read_markers" %}} ##### 服务器行为 服务器必须阻止客户端在房间账户数据中直接设置 `m.fully_read`。此外,服务器必须确保其对 `/read_markers` 请求中存在的 `m.read` 和 `m.read.private` 的处理方式与对 [`/receipt/{receiptType}/{eventId}`](#post_matrixclientv3roomsroomidreceiptreceipttypeeventid) 的请求完全相同。 当由于 `/read_markers` 请求导致 `m.fully_read` 事件被更新时,服务器必须通过事件流(例如 `/sync`),并在满足任何适用过滤器的前提下,将更新后的账户数据事件发送到客户端。 #### 未读标记 {{% added-in v="1.12" %}} 客户端可以使用“未读标记”允许用户独立于[已读回执](#receipts)或[完全已读标记](#fully-read-markers)对房间进行后续关注的标记。 ##### 事件 用户在某房间中的未读标记通过房间[账户数据](#client-config)中的 `m.marked_unread` 事件进行保存。可通过该事件来确定用户在房间中的当前未读标记状态。和其他账户数据事件一样,该事件在更新时会通过事件流下发。 {{% event event="m.marked_unread" %}} ##### 客户端行为 客户端必须通过直接修改 `m.marked_unread` 房间账户数据事件来更新未读标记。当标记房间为未读时,客户端不应更改 `m.fully_read` 标记,以便保留用户在该房间的已读位置。 当 `unread` 字段为 `true` 时,客户端应以视觉方式标注房间为未读。具体如何实现为实现细节。推荐客户端使用与未读通知房间相似的表现方式。 当打开某房间以展示其时间线时,客户端应通过将 `unread` 设为 `false` 来重置未读标记。 如果客户端提供通过为最新事件发送已读回执将房间标记为“已读”的功能,应同时重置未读标记。 如果 `m.marked_unread` 事件在用户账户数据中不存在,客户端必须视为 `unread` 为 `false` 进行处理。 ##### 服务器行为 此子模块对服务器没有额外要求。