Files
buzz/mobile/lib/shared/read_state/message_read_state.dart
feccf4eabc Polish mobile inbox and media flows (#4512)
## Summary

- make mobile unread state visible with bold channel names, an animated
Inbox badge, and swipe-to-toggle Inbox rows
- add directional transitions for top-level mobile navigation
- let mobile send while media uploads, with cancellable progress UI
- normalize iOS and Android video uploads, attach poster frames, and
improve native video playback

## Validation

- `just mobile-check`
- `just mobile-test`
- `cargo test -p buzz-media`
- Pixel smoke test
- iPhone smoke test

Desktop background uploads moved to #4522 so the two platforms can be
reviewed independently.

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: Tom Brow <tomb@block.xyz>
Co-authored-by: leader <71e9f2c44a6932b6772caaaccda1911d010463c3e2c6c40410b8329956046801@buzz.block.builderlab.xyz>
Co-authored-by: Tom Brow <tomb@block.xyz>
2026-08-04 00:05:13 -07:00

45 lines
1.5 KiB
Dart

import 'read_state_format.dart';
import 'read_state_provider.dart';
/// Effective read timestamp for a single message: the newest of the channel
/// marker, the message's own `msg:` marker, and (for thread replies) the
/// thread's `thread:` marker — the same precedence the unread badge uses via
/// `observedUnreadEventReadAt`.
int? effectiveMessageReadAt(
ReadStateState readState, {
required String channelId,
required String messageId,
String? threadRootId,
}) {
return maxReadAt([
readState.effectiveTimestamp(channelId),
readState.effectiveTimestamp(msgContextKey(messageId)),
if (threadRootId != null)
readState.effectiveTimestamp(threadContextKey(threadRootId)),
]);
}
/// Whether a message should currently show as unread in the actions menu.
///
/// A message-level forced unread (from this menu) wins; otherwise the
/// timestamp precedence decides. A channel-level forced unread (from the
/// channel tile) is deliberately not consulted: it is a channel-scoped
/// choice, and letting it leak in here would make the message-level toggle
/// unable to round-trip without clearing the channel-level choice.
bool isMessageUnread(
ReadStateState readState, {
required String channelId,
required String messageId,
required int createdAt,
String? threadRootId,
}) {
if (readState.isForcedUnread(msgContextKey(messageId))) return true;
final readAt = effectiveMessageReadAt(
readState,
channelId: channelId,
messageId: messageId,
threadRootId: threadRootId,
);
return readAt == null || createdAt > readAt;
}