mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-26 04:45:20 +00:00
Give private DMs an unmistakable visual signature (#1357)
* Give private DMs an unmistakable visual signature An open DM renders identically to the public room — same view, same green-on-black surface, with a small header name and two orange icons as the only cues. For this audience the cost of misreading "am I in the encrypted DM or the public channel?" is severe: sensitive text typed into the wrong composer. Four presentation-layer cues; no formatter or cache changes: - The composer placeholder states the destination instead of a generic prompt: "message @jack — private" in a DM, "message #mesh — public, nearby" on mesh, "message #9q8yy — public" in a geohash channel. - A persistent lock caption sits above the DM composer. It reads "private · end-to-end encrypted" only once the Noise session is actually secured or verified, and "private conversation" before that — the caption must not overstate encryption mid-handshake. - The DM sheet header carries a faint orange wash (6%), extending the existing orange self-accent to the chrome. - Each private message row is prefixed with a small orange lock glyph (view-layer, hidden from VoiceOver — the caption carries the semantic; the cached AttributedString formatter is untouched). New strings are added source-language (en) only. * Fix geohash-DM caption and placeholder Two carve/review follow-ups: - The privacy caption showed "private conversation" for geohash DMs, implying they are not encrypted — but geohash DMs are NIP-17 gift-wrapped (always end-to-end encrypted), they just carry no Noise session status. Show the encrypted caption for geohash DMs and for secured Noise sessions; the pre-secured wording now applies only while a mesh handshake is still in progress. - The private-chat placeholder prepended "@" to the partner name, which for a geohash DM (whose display name is already "#geohash/@name") produced a doubled "@". The "@" is now added only for mesh nicknames. * Make the DM header orange wash visible in the matrix theme The 6% orange background was chained after .themedSurface(), so in the default matrix theme (whose themedSurface paints an opaque background) the wash sat behind the surface and never rendered — it was only visible in liquid glass. Apply the orange tint before .themedSurface() so it layers in front of the themed background. * Align DM lock glyph across text and media rows; keep header wash visible under glass Media rows in a private conversation now get the same leading lock glyph as text rows, so left edges line up instead of misaligning by the glyph's width. The DM header's orange wash gets a higher opacity under the liquid-glass theme, where themedSurface() adds no opaque backing and 6% orange disappears into the backdrop gradient. Also drops the dead sender != "system" guard in TextMessageView — system messages are routed to systemMessageRow before this view is built. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Remove orphaned content.input.message_placeholder from the string catalog The destination-stating placeholders replaced its last code reference; nothing on the branch resolves this key anymore. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: jack <212554440+jackjackbits@users.noreply.github.com> Co-authored-by: jack <jackjackbits@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
jack
jack
Claude Fable 5
parent
9ccff9cce4
commit
c8ceac1968
@@ -6,6 +6,7 @@ import UIKit
|
||||
struct ContentComposerView: View {
|
||||
@EnvironmentObject private var conversationUIModel: ConversationUIModel
|
||||
@EnvironmentObject private var privateConversationModel: PrivateConversationModel
|
||||
@EnvironmentObject private var locationChannelsModel: LocationChannelsModel
|
||||
@Environment(\.appTheme) private var theme
|
||||
@ThemedPalette private var palette
|
||||
|
||||
@@ -60,10 +61,8 @@ struct ContentComposerView: View {
|
||||
TextField(
|
||||
"",
|
||||
text: $messageText,
|
||||
prompt: Text(
|
||||
String(localized: "content.input.message_placeholder", comment: "Placeholder shown in the chat composer")
|
||||
)
|
||||
.foregroundColor(palette.secondary.opacity(0.6))
|
||||
prompt: Text(placeholderText)
|
||||
.foregroundColor(palette.secondary.opacity(0.6))
|
||||
)
|
||||
.textFieldStyle(.plain)
|
||||
.bitchatFont(size: 15)
|
||||
@@ -110,6 +109,33 @@ struct ContentComposerView: View {
|
||||
}
|
||||
|
||||
private extension ContentComposerView {
|
||||
/// States where a message will land: the DM partner's name for private
|
||||
/// chats, the channel (and its public nature) otherwise — so a stressed
|
||||
/// user never has to guess who can read what they're typing.
|
||||
var placeholderText: String {
|
||||
if let header = privateConversationModel.selectedHeaderState {
|
||||
// A geohash-DM display name already carries its own "#geohash/@name"
|
||||
// form, so it must not get another "@" prefix; a mesh nickname does.
|
||||
let isGeoDM = privateConversationModel.selectedPeerID?.isGeoDM == true
|
||||
let target = isGeoDM ? header.displayName : "@\(header.displayName)"
|
||||
return String(
|
||||
format: String(localized: "content.input.placeholder.private", comment: "Composer placeholder inside a private chat, naming the conversation partner"),
|
||||
locale: .current,
|
||||
target
|
||||
)
|
||||
}
|
||||
switch locationChannelsModel.selectedChannel {
|
||||
case .mesh:
|
||||
return String(localized: "content.input.placeholder.mesh", comment: "Composer placeholder for the public mesh channel")
|
||||
case .location(let channel):
|
||||
return String(
|
||||
format: String(localized: "content.input.placeholder.location", comment: "Composer placeholder for a public geohash channel, naming it"),
|
||||
locale: .current,
|
||||
channel.geohash
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var recordingIndicator: some View {
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: "waveform.circle.fill")
|
||||
|
||||
Reference in New Issue
Block a user