eleven / messenger Public

mac,ios: ↑ edits your last message; deletes implode (#305)

* mac,ios: ↑ edits your last message; deletes implode

Up-arrow in an empty composer starts editing your most recent message
(Mac; iOS with a hardware keyboard) — the desktop convention. Deleted
messages now implode — a quick shrink-and-fade where the bubble stood:
rows carry a scale+opacity removal transition, and the delete fold is
the one mutation that publishes inside an animation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* mac,ios: preview-less chat rows centre their title beside the avatar

A chat with no recent message dropped a ghost two-line preview block
under its title, leaving the title floating at the top of the row.
The preview block only renders when there's a preview now (the unread
pip rides alone in that case), so the title sits vertically centred.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell fc11fcd5b5c099b02f5c61ce53a0bc6771c7df4e parent 99b92b9
2 files changed, +26 −13
  • ios/LChat/Views/ThreadRow.swift +17 −8
  • ios/LChatMac/NativeChatView.swift +9 −5
diff --git a/ios/LChat/Views/ThreadRow.swift b/ios/LChat/Views/ThreadRow.swift
index b46b3b6..8db7f32 100644
--- a/ios/LChat/Views/ThreadRow.swift
+++ b/ios/LChat/Views/ThreadRow.swift
@@ -29,14 +29,23 @@ struct ThreadRow: View {
}
}
}
- HStack(spacing: 6) {
- // Up to two lines of preview, height reserved so every row is the
- // same height (à la Mail/Messages) — mirrors the web list's 2-line clamp.
- Text(thread.preview.isEmpty ? " " : thread.preview)
- .font(.subheadline).foregroundStyle(.secondary)
- .lineLimit(2, reservesSpace: true)
- Spacer()
- if thread.unread {
+ // No recent message → no ghost preview block, so the title
+ // centres beside the avatar (the unread pip rides alone).
+ if !thread.preview.isEmpty {
+ HStack(spacing: 6) {
+ // Up to two lines, height reserved so chatty rows stay
+ // uniform (à la Mail/Messages) — the web's 2-line clamp.
+ Text(thread.preview)
+ .font(.subheadline).foregroundStyle(.secondary)
+ .lineLimit(2, reservesSpace: true)
+ Spacer()
+ if thread.unread {
+ Circle().fill(Color.accentColor).frame(width: 9, height: 9)
+ }
+ }
+ } else if thread.unread {
+ HStack {
+ Spacer()
Circle().fill(Color.accentColor).frame(width: 9, height: 9)
}
}
diff --git a/ios/LChatMac/NativeChatView.swift b/ios/LChatMac/NativeChatView.swift
index cf3b9d3..ac3e27c 100644
--- a/ios/LChatMac/NativeChatView.swift
+++ b/ios/LChatMac/NativeChatView.swift
@@ -790,11 +790,15 @@ struct NativeChatView: View {
.foregroundStyle(.tertiary)
}
}
- Text(t.preview)
- .font(.system(size: 12, weight: t.unread ? .medium : .regular))
- .foregroundStyle(t.unread ? .primary : .secondary)
- .lineLimit(2, reservesSpace: true)
- .frame(maxWidth: .infinity, alignment: .leading)
+ // No recent message → no ghost preview block, so the
+ // title centres beside the avatar instead of floating top.
+ if !t.preview.isEmpty {
+ Text(t.preview)
+ .font(.system(size: 12, weight: t.unread ? .medium : .regular))
+ .foregroundStyle(t.unread ? .primary : .secondary)
+ .lineLimit(2, reservesSpace: true)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ }
}
// Outside the text column so the dot centres on the ROW.
if t.unread {