Address Jack review on quote-in-composer (#1570).

Add content.message.quote to the 30-locale catalog; use a plain sender
header (no @) so quotes do not re-ping; drop the shared draft when the
composer target changes; and only skip the newline insert after a real
trailing newline (not a trailing space).
This commit is contained in:
Taksh 2026-07-31 17:50:36 +03:00
parent 6103e3f4e5
commit 333746b08a
4 changed files with 1003 additions and 200 deletions

File diff suppressed because it is too large Load Diff

View File

@ -28,12 +28,15 @@ enum MessageClipboard {
}
/// Builds a composer-ready quote block (`> line` per line, trailing blank).
/// Sender header is plain text (`> alice:`), not `@alice`, so quoting does
/// not re-fire mention notifications for the quoted person or for names
/// inside the quoted body (those stay behind `> ` and are not live tokens).
static func quoteForComposer(_ content: String, sender: String?) -> String {
let body = content.trimmingCharacters(in: .whitespacesAndNewlines)
guard !body.isEmpty else { return "" }
let header: String
if let sender, !sender.isEmpty, sender != "system" {
header = "> @\(sender):\n"
header = "> \(sender):\n"
} else {
header = ""
}
@ -45,11 +48,13 @@ enum MessageClipboard {
}
/// Appends a quote to an existing composer draft without wiping it.
/// Only a trailing newline skips inserting another separator a trailing
/// space must still get a newline so the quote marker starts its own line.
static func appendQuote(to draft: String, content: String, sender: String?) -> String {
let quote = quoteForComposer(content, sender: sender)
guard !quote.isEmpty else { return draft }
if draft.isEmpty { return quote }
if draft.hasSuffix("\n") || draft.hasSuffix(" ") {
if draft.hasSuffix("\n") {
return draft + quote
}
return draft + "\n" + quote

View File

@ -254,12 +254,17 @@ struct ContentView: View {
.frame(minWidth: 600, minHeight: 400)
#endif
.onChange(of: selectedPrivatePeerID) { newValue in
// Shared composer draft must not travel across conversation
// targets (quoting a DM then opening public would otherwise
// one-tap-broadcast private content).
messageText = ""
if newValue != nil {
showSidebar = true
}
sharedContentImportModel.updateDestination(sharedContentDestination)
}
.onChange(of: locationChannelsModel.selectedChannel) { _ in
messageText = ""
sharedContentImportModel.updateDestination(sharedContentDestination)
}
.sheet(

View File

@ -5,7 +5,7 @@ import Testing
struct MessageClipboardTests {
@Test func quoteWrapsEachLineAndAddsSender() {
let quoted = MessageClipboard.quoteForComposer("hello\nworld", sender: "alice")
#expect(quoted == "> @alice:\n> hello\n> world\n\n")
#expect(quoted == "> alice:\n> hello\n> world\n\n")
}
@Test func quoteSkipsSystemSenderHeader() {
@ -23,7 +23,7 @@ struct MessageClipboardTests {
content: "prior message",
sender: "bob"
)
#expect(result == "already typing\n> @bob:\n> prior message\n\n")
#expect(result == "already typing\n> bob:\n> prior message\n\n")
}
@Test func appendQuoteOntoEmptyDraft() {
@ -32,6 +32,15 @@ struct MessageClipboardTests {
content: "solo",
sender: "carol"
)
#expect(result == "> @carol:\n> solo\n\n")
#expect(result == "> carol:\n> solo\n\n")
}
@Test func appendQuoteAfterTrailingSpaceStartsNewLine() {
let result = MessageClipboard.appendQuote(
to: "draft with space ",
content: "quoted",
sender: "dana"
)
#expect(result == "draft with space \n> dana:\n> quoted\n\n")
}
}