From 76ebe0f771674e95ed29171e8242a0d4758c6a21 Mon Sep 17 00:00:00 2001 From: Blake Oliver Date: Fri, 10 Apr 2026 16:55:40 -0600 Subject: [PATCH] Fix DM's tab * add haptics, sound and keyboard fix from other tabs * fix display of unanswered DM conversations you've started --- KDChat/Views/DMConversationView.swift | 25 +++++++++++++++++++++++-- KDChat/Views/DMListView.swift | 16 +++++++++++----- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/KDChat/Views/DMConversationView.swift b/KDChat/Views/DMConversationView.swift index 4ac71cf..1a4cf90 100644 --- a/KDChat/Views/DMConversationView.swift +++ b/KDChat/Views/DMConversationView.swift @@ -7,6 +7,7 @@ struct DMConversationView: View { @Environment(ConnectionManager.self) private var manager @Query private var messages: [SavedMessage] @State private var messageText = "" + @FocusState private var isInputFocused: Bool init(partnerId: String, partnerName: String) { self.partnerId = partnerId @@ -34,14 +35,33 @@ struct DMConversationView: View { .padding() } .onChange(of: messages.count) { - if let last = messages.last { - proxy.scrollTo(last.persistentModelID, anchor: .bottom) + guard let last = messages.last, last.sessionId == manager.sessionId else { return } + proxy.scrollTo(last.persistentModelID, anchor: .bottom) + + // Sound + if UserDefaults.standard.bool(forKey: "sounds_enabled", default: true), + UserDefaults.standard.bool(forKey: "sounds_dm", default: true) { + SoundPlayer.play("direct-message") + } + + // VoiceOver announcement + if !last.isSystem { + AccessibilityNotification.Announcement( + "\(last.senderName): \(last.content)" + ).post() + } + + // Haptic + if UserDefaults.standard.bool(forKey: "haptics_enabled", default: true), + UserDefaults.standard.bool(forKey: "haptics_messages", default: true) { + UIImpactFeedbackGenerator(style: .soft).impactOccurred() } } } HStack(spacing: 8) { TextField("Message \(partnerName)...", text: $messageText, axis: .vertical) + .focused($isInputFocused) .textFieldStyle(.roundedBorder) .lineLimit(1...4) .onSubmit { sendMessage() } @@ -66,5 +86,6 @@ struct DMConversationView: View { guard !text.isEmpty else { return } manager.sendDirectMessage(recipientId: partnerId, message: text) messageText = "" + isInputFocused = true } } diff --git a/KDChat/Views/DMListView.swift b/KDChat/Views/DMListView.swift index 1b75670..dd5e9f4 100644 --- a/KDChat/Views/DMListView.swift +++ b/KDChat/Views/DMListView.swift @@ -11,15 +11,21 @@ struct DMListView: View { ) private var dmMessages: [SavedMessage] private var conversations: [(id: String, name: String, lastMessage: SavedMessage)] { - var latest: [String: (name: String, message: SavedMessage)] = [:] + var latest: [String: (name: String?, message: SavedMessage)] = [:] for message in dmMessages { - guard let senderId = message.senderId, !message.senderIsRecipient else { continue } - if latest[senderId] == nil { - latest[senderId] = (message.senderName, message) + guard let partnerId = message.characterId else { continue } + if let existing = latest[partnerId] { + // Prefer the partner's display name over the ID + if existing.name == nil, !message.senderIsRecipient { + latest[partnerId] = (message.senderName, existing.message) + } + } else { + let name: String? = message.senderIsRecipient ? nil : message.senderName + latest[partnerId] = (name, message) } } return latest - .map { (id: $0.key, name: $0.value.name, lastMessage: $0.value.message) } + .map { (id: $0.key, name: $0.value.name ?? $0.key, lastMessage: $0.value.message) } .sorted { $0.lastMessage.timestamp > $1.lastMessage.timestamp } }