Flutter UI components
Use immutable presentation models and responsive widgets while keeping product state and authorization in your host app.
Map snapshots into display models
final rows = conversationSnapshots.map(
(snapshot) => VChatUiConversation.fromSnapshot(
snapshot,
title: resolveConversationTitle(snapshot),
preview: resolveConversationPreview(snapshot),
timestampLabel: formatConversationTime(snapshot),
),
).toList(growable: false);
final messages = messageSnapshots.map(
(snapshot) => VChatUiMessage.fromSnapshot(
snapshot,
currentUserId: currentUserId,
authorLabel: resolveAuthorLabel(snapshot),
timestampLabel: formatMessageTime(snapshot),
),
).toList(growable: false);Presentation models copy only released display state and do not retain arbitrary custom payloads. The host chooses safe labels, timestamps, optimistic delivery state, and reconciliation behavior.
Widget building blocks
| Widget area | Purpose |
|---|---|
| Conversation list | Responsive conversation rows, unread state, selection, loading, and empty/error presentation |
| Message list | Accessible message grouping, sent/pending/failed state, reactions, and thread affordances |
| Composer | Host-controlled text entry and send action without credential or authorization inference |
| Adaptive layout | Single-pane mobile and split-pane larger-screen composition |
| Status/activity | Connection banner, typing indicator, and host-owned recovery actions |
State and accessibility ownership
- Do not infer authorization from cached rows or widget visibility.
- Supply display-safe labels; never place raw server errors, secrets, or private URLs in semantics.
- Test product strings, text scale, RTL, keyboard navigation, contrast, and screen-reader behavior in the host app.
- Dispose controllers, focus nodes, and stream subscriptions allocated by the host.