mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-08-29 07:27:16 +00:00
Address Jack review on recent DM threads in people sheet (#1576).
This commit is contained in:
parent
71eeaf689f
commit
9832470868
@ -167,6 +167,16 @@ final class PeerListModel: ObservableObject {
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
// New/updated messages in an existing thread must refresh ordering and
|
||||
// preview while the people sheet is open — conversationIDs alone does
|
||||
// not change for those mutations.
|
||||
conversations.changes
|
||||
.debounce(for: .milliseconds(120), scheduler: DispatchQueue.main)
|
||||
.sink { [weak self] _ in
|
||||
self?.refresh()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
chatViewModel.groupStore.$groups
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in
|
||||
@ -274,7 +284,9 @@ final class PeerListModel: ObservableObject {
|
||||
self.groupRows = groupRows
|
||||
renderID = (
|
||||
recentDirectRows.map {
|
||||
"recent:\($0.id)-\($0.hasUnread)-\($0.displayName)-\($0.preview)"
|
||||
// Hash the preview so a `|` inside message text cannot collide
|
||||
// with the render-id separator and skip a re-render.
|
||||
"recent:\($0.id)-\($0.hasUnread)-\($0.displayName)-\($0.preview.stableRenderHash)"
|
||||
} +
|
||||
meshRows.map {
|
||||
"\($0.id)-\($0.displayName)-\($0.isConnected)-\($0.isReachable)-\($0.hasUnread)-\($0.isFavorite)-\($0.isBlocked)"
|
||||
@ -295,25 +307,32 @@ final class PeerListModel: ObservableObject {
|
||||
guard peerID != myPeerID else { return nil }
|
||||
// Already in that thread — no need to list it again here.
|
||||
guard peerID != selected else { return nil }
|
||||
// Match mesh rows: blocked people stay out of the people sheet.
|
||||
guard !chatViewModel.isPeerBlocked(peerID) else { return nil }
|
||||
let messages = messagesByPeer[peerID] ?? []
|
||||
guard let last = messages.last else { return nil }
|
||||
let preview = last.content
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let clipped: String
|
||||
if preview.count > 48 {
|
||||
clipped = String(preview.prefix(45)) + "…"
|
||||
} else {
|
||||
clipped = preview
|
||||
}
|
||||
let preview = Self.friendlyRecentPreview(last.content)
|
||||
return RecentDirectRow(
|
||||
peerID: peerID,
|
||||
displayName: chatViewModel.nicknameForPeer(peerID),
|
||||
hasUnread: chatViewModel.hasUnreadMessages(for: peerID),
|
||||
preview: clipped
|
||||
preview: preview
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Strip media placeholder filenames (`[image] <uuid>.jpg`) down to a
|
||||
/// short type marker so the recent-DM preview stays readable.
|
||||
private static func friendlyRecentPreview(_ content: String) -> String {
|
||||
let trimmed = content.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if trimmed.hasPrefix("[image]") { return "[image]" }
|
||||
if trimmed.hasPrefix("[voice]") { return "[voice]" }
|
||||
if trimmed.count > 48 {
|
||||
return String(trimmed.prefix(45)) + "…"
|
||||
}
|
||||
return trimmed
|
||||
}
|
||||
|
||||
private func buildGroupRows() -> [GroupChatRow] {
|
||||
let myFingerprint = chatViewModel.meshService.noiseIdentityFingerprint()
|
||||
return chatViewModel.groupStore.groups.map { group in
|
||||
@ -352,3 +371,15 @@ final class PeerListModel: ObservableObject {
|
||||
return identity.publicKeyHex.lowercased()
|
||||
}
|
||||
}
|
||||
|
||||
private extension String {
|
||||
/// Stable within-process digest for render-id segments — avoids embedding
|
||||
/// raw message text (and `|` separators) in the joined render token.
|
||||
var stableRenderHash: String {
|
||||
var hash: UInt64 = 5381
|
||||
for byte in utf8 {
|
||||
hash = ((hash << 5) &+ hash) &+ UInt64(byte)
|
||||
}
|
||||
return String(hash, radix: 16)
|
||||
}
|
||||
}
|
||||
|
||||
@ -39029,25 +39029,24 @@
|
||||
}
|
||||
},
|
||||
"content.people.recent_messages" : {
|
||||
"comment" : "People sheet section header for recent private message threads",
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"ar" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "الرسائل الأخيرة"
|
||||
}
|
||||
},
|
||||
"bn" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "সাম্প্রতিক বার্তা"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "letzte nachrichten"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
@ -39059,157 +39058,157 @@
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "mensajes recientes"
|
||||
}
|
||||
},
|
||||
"fa" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "پیامهای اخیر"
|
||||
}
|
||||
},
|
||||
"fil" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "mga kamakailang mensahe"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "messages récents"
|
||||
}
|
||||
},
|
||||
"he" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "הודעות אחרונות"
|
||||
}
|
||||
},
|
||||
"hi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "हाल के संदेश"
|
||||
}
|
||||
},
|
||||
"id" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "pesan terbaru"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "messaggi recenti"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "最近のメッセージ"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "최근 메시지"
|
||||
}
|
||||
},
|
||||
"ms" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "mesej terbaru"
|
||||
}
|
||||
},
|
||||
"ne" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "हालका सन्देशहरू"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "recente berichten"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "ostatnie wiadomości"
|
||||
}
|
||||
},
|
||||
"pt" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "mensagens recentes"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "mensagens recentes"
|
||||
}
|
||||
},
|
||||
"ru" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "недавние сообщения"
|
||||
}
|
||||
},
|
||||
"sv" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "senaste meddelanden"
|
||||
}
|
||||
},
|
||||
"ta" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "சமீபத்திய செய்திகள்"
|
||||
}
|
||||
},
|
||||
"th" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "ข้อความล่าสุด"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "son mesajlar"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "нещодавні повідомлення"
|
||||
}
|
||||
},
|
||||
"ur" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "حالیہ پیغامات"
|
||||
}
|
||||
},
|
||||
"vi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "tin nhắn gần đây"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "最近的消息"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "recent messages"
|
||||
"value" : "最近的訊息"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import SwiftUI
|
||||
import BitFoundation
|
||||
|
||||
/// Compact recent-DM rows for the people sheet — reopen past private threads
|
||||
/// without hunting through the full mesh / favorites lists (#615).
|
||||
@ -49,7 +50,11 @@ struct RecentDirectMessagesList: View {
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel(row.displayName)
|
||||
.accessibilityLabel(
|
||||
row.hasUnread
|
||||
? "\(row.displayName), \(Strings.unread)"
|
||||
: row.displayName
|
||||
)
|
||||
.accessibilityHint(Strings.openDMHint)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user