atagen

malice

public
Star0
Watch0
6f8d26e8d14c7991087fe7565acdf3807c3eb6b1
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
web/src/lib/timeline-groups.tsTypescript70 lines2.3 KB
1
import type { PendingMessage } from './pending';
2
import type { SendState, TimelineEvent, TimelineItem } from './types';
3
4
const SENDER_RUN_MS = 5 * 60 * 1000;
5
6
export interface Group {
7
  key: string;
8
  item: TimelineItem;
9
  showSender: boolean;
10
}
11
12
/** Consecutive events from one sender within a few minutes share a header. */
13
export function buildGroups(list: TimelineItem[]): Group[] {
14
  const out: Group[] = [];
15
  let prevSender: string | null = null;
16
  let prevTs = 0;
17
  list.forEach((item, index) => {
18
    if (item.kind === 'event') {
19
      const e = item.event;
20
      const showSender = prevSender !== e.sender.user_id || Math.abs(e.timestamp_ms - prevTs) > SENDER_RUN_MS;
21
      prevSender = e.sender.user_id;
22
      prevTs = e.timestamp_ms;
23
      out.push({ key: e.item_id || e.event_id || `m-${index}`, item, showSender });
24
    } else {
25
      prevSender = null;
26
      const key = item.kind === 'historyGap' ? `gap-${item.gap.id}` : `${item.kind}-${index}`;
27
      out.push({ key, item, showSender: true });
28
    }
29
  });
30
  return out;
31
}
32
33
export function lastOwnSent(list: TimelineItem[]): string | null {
34
  for (let i = list.length - 1; i >= 0; i--) {
35
    const item = list[i];
36
    if (item.kind === 'event' && item.event.own && item.event.send_state.kind === 'Sent') return item.event.item_id;
37
  }
38
  return null;
39
}
40
41
export function lastSenderIs(list: TimelineItem[], userId: string | null): boolean {
42
  for (let i = list.length - 1; i >= 0; i -= 1) {
43
    const item = list[i];
44
    if (item.kind === 'event') return item.event.sender.user_id === userId;
45
  }
46
  return false;
47
}
48
49
export function pendingToEvent(p: PendingMessage, self: string | null, displayName: string | null): TimelineEvent {
50
  const state: SendState = p.status === 'failed' ? { kind: 'Failed', will_retry: false } : { kind: 'Sending' };
51
  return {
52
    item_id: `pending-${p.id}`,
53
    event_id: null,
54
    transaction_id: p.id,
55
    sender: { user_id: self ?? '', display_name: displayName, avatar: null, name_ambiguous: false },
56
    timestamp_ms: p.createdAt,
57
    own: true,
58
    send_state: state,
59
    content: {
60
      kind: 'Message',
61
      message: { kind: 'Text', body: p.body, geo_uri: null, formatted_body: p.formatted, edited: false, media: null, link_previews: [] }
62
    },
63
    reply_to: p.replyTo,
64
    thread_root: null,
65
    thread_summary: null,
66
    reactions: [],
67
    read_by: [],
68
    editable: false
69
  };
70
}