eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1import LChatCore
2import SwiftUI
3
4// One chat row's content — extracted so the UIKit list (ThreadListCollection) can
5// render it inside a UICollectionViewListCell via UIHostingConfiguration. Pure
6// presentation; the cell owns the highlight/selection chrome.
7struct ThreadRow: View {
8 let thread: ChatThread
9
10 var body: some View {
11 HStack(spacing: 12) {
12 // The main list finally shows app identity: Eleven's own threads
13 // wear the brand tile, apps their mark (docs/icons.md), and the
14 // emoji glyph stays the fallback for anything unmapped.
15 Avatar(name: thread.title, size: 44, source: thread.avatar,
16 photo: thread.isEleven ? ElevenBrand.icon : nil,
17 glyph: thread.glyph,
18 symbol: AppIdentity.symbol(for: thread.appId),
19 mark: AppIdentity.mark(for: thread.appId))
20 VStack(alignment: .leading, spacing: 2) {
21 HStack {
22 Text(thread.title).font(.headline).lineLimit(1)
23 if let badge = thread.badge {
24 AgentBadge(badge)
25 }
26 Spacer()
27 HStack(spacing: 4) {
28 if thread.pinned {
29 Image(systemName: "pin.fill")
30 .font(.caption2)
31 .foregroundStyle(.secondary)
32 .accessibilityLabel("Pinned")
33 }
34 if thread.lastAt > 0 {
35 Text(relTime(thread.lastAt)).font(.caption).foregroundStyle(.secondary)
36 }
37 }
38 }
39 // Always rendered, preview or not: two reserved lines keep
40 // every row the same height (à la Mail/Messages — a list of
41 // mixed heights read as jumbled next to app rows with no
42 // recent message). The web keeps its 2-line clamp.
43 HStack(spacing: 6) {
44 Text(thread.preview)
45 .font(.subheadline).foregroundStyle(.secondary)
46 .lineLimit(2, reservesSpace: true)
47 Spacer()
48 // A muted chat never escalates: the slashed bell replaces
49 // the unread dot — the state stays visible (never absence
50 // alone), it just doesn't shout. Web-list parity.
51 if thread.isMuted {
52 Image(systemName: "bell.slash.fill")
53 .font(.caption)
54 .foregroundStyle(.secondary)
55 .accessibilityLabel("Muted")
56 } else if thread.unread {
57 Circle().fill(Color.accentColor).frame(width: 9, height: 9)
58 }
59 }
60 }
61 }
62 }
63}
64
65// relTime moved to LChatCore (Format) — the Mac thread list uses it too.
66