buildRows function
- ChatState state,
- HatangChatStrings strings, {
- DateTime? now,
Rows for state: day separators, greeting when empty, notice / handoff /
rated events only, "Seen" under the last read own message, sender names
for the team, pending bubbles and the typing indicator.
Implementation
List<ChatRow> buildRows(ChatState state, HatangChatStrings strings, {DateTime? now}) {
final rows = <ChatRow>[];
final locale = state.locale;
final items = state.timeline.items;
final at = now ?? clock.now();
if (items.isEmpty) {
final greeting = greetingRowFor(state.config, locale, online: state.online);
if (greeting != null) rows.add(greeting);
}
var lastVisitorRead = 0;
for (final i in items) {
if (i is MessageDto && i.isMine && i.readAt != null && i.seq > lastVisitorRead) lastVisitorRead = i.seq;
}
DateTime? lastDay;
final newest = items.isEmpty ? null : items.last;
final marks = PaidMarks.of(items);
for (final i in items) {
final day = dayOf(i.createdAt);
if (lastDay != day) {
lastDay = day;
rows.add(DayRow(dayLabel(i.createdAt, locale, strings, now: at), day));
}
switch (i) {
case ConversationEventDto():
switch (i.type) {
case 'notice':
final key = i.data['key'];
final text = key is String ? strings.t(key, locale) : '${i.data['text'] ?? ''}';
if (text.isNotEmpty) rows.add(SystemRow(i.id, text));
case 'handoff':
rows.add(SystemRow(i.id, strings.transferredToAgent));
case 'rated':
rows.add(SystemRow(i.id, strings.rateThanks));
default:
break;
}
case MessageDto():
final mine = i.isMine;
String? label;
if (!mine && i.senderName != null && i.senderName!.isNotEmpty) {
label = i.senderType == SenderType.bot ? '${i.senderName} ยท ${strings.aiLabel}' : i.senderName;
} else if (!mine && i.senderType == SenderType.bot) {
label = strings.aiLabel;
}
var card = mine ? null : cardOf(i.metadata);
if (card is QuickRepliesCard && !identical(i, newest)) card = null;
final intro = i.metadata?['intro'];
rows.add(
MessageRow(
// A card the SDK draws replaces the plain-text copy the gateway
// stores for other channels.
card == null
? i
: i.copyWith(content: cardBubbleText(i.content, card, intro: intro is String ? intro : null)),
card: card,
paid: card is PaymentCard && card.isPaid(marks),
mine: mine,
showSender: label != null,
showSeen: mine && lastVisitorRead == i.seq,
senderLabel: label,
askEmail: !mine && i.metadata?['kind'] == 'email_request' && (state.visitorEmail ?? '').isEmpty,
),
);
}
}
for (final p in state.pending) {
rows.add(PendingRow(p));
}
final typing = state.typingAgent;
if (typing != null) rows.add(TypingRow(typing));
return rows;
}