Представьте: вечером вы открыли группу, в которой за день накопилось пятьдесят сообщений. Прочитали несколько последних, пролистали вверх и задержались на старом голосовом. На одном сообщении оставили реакцию. Что теперь считать прочитанным — все пятьдесят, всё до последнего просмотренного или только те сообщения, которые действительно попали на экран?
Ответ влияет сразу на несколько вещей: на цифру рядом с чатом, на отметку у отдельного сообщения и на подробную статистику. Чтобы эти сигналы не спорили друг с другом, системе приходится различать открытие чата, визит в него и подтверждение просмотра конкретной записи.
Открытие, визит и просмотр — разные события
Открытие чата говорит только о том, что перед вами появилась переписка. Вы могли сразу отвлечься, не прокрутить её до старых сообщений или открыть чат на пару секунд, чтобы проверить имя собеседника. Поэтому само открытие не доказывает, что вы прочли всё, что в нём накопилось.
Граница последнего визита помогает отделить новые непрочитанные сообщения от старых. Обычное открытие уже существующего чата само по себе её не передвигает: без нового подтверждения счётчики могут остаться прежними.
Просмотр — точечное подтверждение: конкретное чужое сообщение оказалось в видимой части открытой переписки. Позднее сообщение не служит закладкой, которая автоматически «прочитает» всё до него. Если вы перешли прямо к вчерашнему ответу, это не означает, что каждое сообщение между ним и сегодняшним днём тоже было у вас на экране.

Все непрочитанные — это доступные обычные сообщения от других участников без подтверждённого просмотра. Новые непрочитанные — часть таких сообщений, расположенная после границы последнего визита; если границы ещё нет, новой считается вся доступная непрочитанная история. Значок в списке чатов показывает именно новые непрочитанные. Сообщение может остаться в полном счётчике, но перестать быть новым после продвижения границы — от этого оно не становится просмотренным.
Что нужно, чтобы просмотр подтвердился
Приложение не принимает кивок в сторону экрана за прочитанное. Оно проверяет, что переписка сейчас действительно открыта и активна, страница видна, список сообщений уже занял своё место, а карточка конкретного сообщения оказалась внутри рабочей области прокрутки. Сообщения автора, системные записи и черновики в этот учёт не входят.
Зачем столько оговорок? При загрузке список может на мгновение перескочить, карточка — пройти мимо из-за восстановления позиции, а соседняя вкладка — оказаться поверх той, что вы видите. Подтверждение ждёт, пока экран стабилизируется и сообщение можно действительно рассмотреть. Несколько таких подтверждений приложение отправляет вместе, но каждое сохраняет свой точный номер.
Как множество просмотров превращается в несколько диапазонов
В примере ниже сообщения 101, 102 и 103 уже показались читателю. За ними он пропустил 104, затем просмотрел 105, 106 и 107. Удобно хранить три номера слева одним отрезком и три справа другим. Сообщение 104 остаётся отдельным пробелом, а не теряется между ними.
Диапазон экономит место, но не означает «прочитано всё между двумя известными точками». Если посередине остаётся сообщение, которое должно считаться непрочитанным, диапазоны сохраняются раздельно. Это похоже на закладку между несколькими прочитанными страницами: короткая запись о границах удобна, пока она не стирает страницу, которую читатель пропустил.
Есть и безопасные промежутки. Например, между двумя просмотренными сообщениями численно могут оказаться уже удалённые записи, собственные сообщения или системные отметки. Если там не осталось непросмотренного входящего сообщения, препятствовать объединению незачем. Система может постепенно проверить и такой промежуток в фоне. Пока вся его длина не проверена, диапазоны не склеиваются; проверка меняет только компактность записи, а не то, что человек действительно видел.
Граница последнего визита делит непрочитанное на новое и старое
Для участника, который уже состоит в переписке, обычное открытие чата не передвигает границу к последнему сообщению. Она поднимается, когда подтверждён просмотр конкретного доступного входящего сообщения от другого участника: например, сообщение оказалось в видимой области переписки, на него поставили реакцию или подтвердили прослушивание его голосового вложения.
Продвижение границы и отметка о просмотре — связанные, но разные результаты. Для границы берётся самое позднее по порядку подходящее сообщение из текущего подтверждения, и она движется только вперёд. Отметка просмотра относится к конкретному сообщению. Поэтому переход к более позднему сообщению может передвинуть границу через промежуток, не отмечая пропущенные записи просмотренными. Даже повторное подтверждение уже просмотренного сообщения способно поднять границу, если она ещё ниже него. Свои сообщения, служебные записи, «Сохранённое» и недоступные сообщения её не передвигают.
Граница не говорит, сколько времени человек провёл в приложении, видел ли уведомление и прочитал ли всё, что находится до неё. Она нужна только для деления непрочитанного на новое и старое: более ранние записи всё ещё могут оставаться без просмотра и учитываться в полном счётчике.
Представим, что в группе накопилось пятьдесят новых входящих сообщений. Если подтвердить сначала первые пять, а затем сразу два самых поздних, середина останется непросмотренной, хотя граница уже пройдёт дальше неё:
- До открытия чата: все непрочитанные — 50; новые — 50.
- Чат открыт, но новых просмотров не подтверждено: все непрочитанные — 50; новые — 50.
- Подтверждён просмотр первых пяти: все непрочитанные — 45; новые — 45.
- Затем подтверждён просмотр двух самых последних: все непрочитанные — 43; новые — 0.
- Позже пришли ещё десять входящих сообщений, и их просмотр не подтверждали: все непрочитанные — 53; новые — 10.
Во второй строке специально нет новых подтверждений: в реальном интерфейсе при открытии некоторые сообщения могут сразу оказаться в видимой области и получить отметку просмотра. После подтверждения двух последних сорок три сообщения из середины всё ещё непрочитаны и остаются в полном счётчике, хотя уже не считаются новыми. Так открытие не обнуляет остаток само по себе, а продвижение границы не создаёт просмотры для пропущенных сообщений.
Отдельное правило действует при создании нового периода участия, в том числе при повторном вступлении в группу или канал: начальную границу устанавливают по последнему сообщению чата на тот момент. Доступная старая история без подтверждённого просмотра может остаться в полном счётчике, но не попадёт в число новых. Это правило вступления, а не результат обычного открытия уже существующего чата.
Факт просмотра переживает время; точное время — нет
У просмотра есть два разных слоя. Первый отвечает на вопрос «видел ли этот участник это сообщение?». У факта точного просмотра нет семидневного срока хранения. Второй слой отвечает на вопрос «когда именно это случилось?». Дата и время первого просмотра хранятся семь суток, затем временная отметка удаляется.
Эти сроки не противоречат друг другу. Можно перестать хранить часы и минуты, но оставить ответ «да, просмотр был». Истечение семи дней поэтому не уменьшает счётчик просмотревших, не передвигает границу непрочитанного и не заставляет старое сообщение снова выглядеть непрочитанным. Меняется только доступность точного времени в подробностях.
Прослушивание относится к голосовому вложению
У голосового сообщения есть собственная история. Подтверждённое прослушивание привязывается не просто к сообщению целиком, а к конкретному голосовому вложению в нём. Поэтому число рядом с волной показывает прослушивания именно этой записи. У другого вложения — свой счётчик и свои участники.

Когда запуск воспроизведения подтверждён, сервер записывает событие прослушивания и его время. Это подтверждение работы плеера, а не свидетельство, что запись дослушали до конца. Повторное прослушивание не создаёт ещё один персональный факт, не прибавляет второе прослушивание к общему счётчику за всё время и не заменяет время первого раза. В старых записях, созданных до появления постоянной отметки времени, точной даты может не быть; восстановить её задним числом нельзя.
Подтверждённое прослушивание чужого сообщения может заодно подтвердить и просмотр самого сообщения. Это два разных ответа на два разных вопроса: «увидел ли человек карточку?» и «прослушал ли он вот это вложение?». Получить первый ответ только из счётчика прослушиваний нельзя — эти факты учитываются отдельно, хотя один поступок иногда создаёт оба.
Одно сообщение, два голосовых и две истории
Вот необычный случай из редактора. Допустим, сообщение с номером 58 уже видели несколько участников, а голосовое A успели прослушать. Автор оставляет текст на месте, но удаляет A и записывает новое голосовое B. Для читателя это всё ещё та же реплика в переписке. Для статистики вложений — уже другой объект.
Когда старое вложение удаляется при сохранении сообщения, исчезают и привязанные к нему факты прослушивания. Новое вложение получает новый идентификатор, поэтому его счётчик и список прослушавших начинаются с нуля. История просмотра сообщения не стирается: номер самой реплики остался прежним.
Если автор изменил только текст и оставил прежнее голосовое вложение, сохранённый идентификатор аудио тоже остаётся прежним — вместе с ним сохраняются его прослушивания и время первого подтверждённого прослушивания. Такая разница не видна по одним только словам «сообщение отредактировано»: важно, заменили саму запись или лишь поменяли текст рядом с ней.
Реакция хранит только своё текущее состояние
Реакция тоже может подсказать, что участник обратил внимание на конкретное сообщение, но устроена иначе, чем просмотр. Для неё важны выбранный emoji и время, когда реакцию поставили или изменили. Если заменить один знак на другой, время обновится: это новое подтверждённое действие, а не просто другой способ показать старое.
Снятая реакция больше не является текущей отметкой. В отличие от времени просмотра, у неё нет семидневного срока: реакция остаётся, пока её не заменят или не снимут. Если человек позже поставит её снова, у нового состояния появится новое время. А если сеть повторно отправит тот же запрос из-за обрыва связи, сервер распознает его как повтор попытки: счётчик и порядок действий не должны сдвинуться второй раз.
Подтверждённое действие с реакцией на чужом сообщении также может зафиксировать просмотр этой реплики. И снова это не значит, что одно заменяет другое: просмотр остаётся фактом о сообщении, а реакция — текущим ответом человека на него.
Что может показать подробная статистика
В группах участнику с подходящим текущим доступом может быть доступен персональный список подтверждённых действий с сообщением. Он объединяет сведения о просмотре, прослушивании отдельных вложений и текущей реакции. Участники располагаются по последнему сохранённому действию: новый подтверждённый просмотр или первое прослушивание поднимает человека выше, а новая реакция меняет его позицию.

В каналах задача другая: подписчиков может быть много, и подробный персональный список читателей там не предоставляется. Вместо него доступны агрегированные числа просмотров сообщения и прослушиваний вложения, а реакции сгруппированы по emoji. Число «5» и перечень пяти конкретных людей — не одно и то же, даже если сейчас оба ответа случайно совпали.
Постоянный общий счётчик тоже не равен числу имён в списке, который можно открыть сегодня. Список ограничен текущими правами и доступностью истории; его отображение может меняться, если удалено сообщение или вложение, изменился доступ участника либо исчезли связанные данные аккаунта. Поэтому система не обещает, что личность каждого просмотревшего будет всегда доступна всем и при любых обстоятельствах.
Почему здесь нет одного общего «прочитано»
Ни открытый экран, ни граница последнего визита, ни число у голосового по отдельности не описывают весь разговор. Вместе они дают более аккуратную картину: граница делит непрочитанные сообщения на новые и старые, подтверждённый просмотр относится к конкретной карточке, вложение — к конкретному прослушиванию, а реакция показывает то, что человек оставил видимым сейчас.
Та же идея — привязывать действие к конкретному объекту — в принципе может пригодиться новым форматам медиа. Например, у будущего видео может появиться собственная статистика просмотра. Это лишь возможное развитие модели, а не описание уже работающей функции.