diff --git a/bitchat/Localizable.xcstrings b/bitchat/Localizable.xcstrings index e498a20e..5a655c40 100644 --- a/bitchat/Localizable.xcstrings +++ b/bitchat/Localizable.xcstrings @@ -79448,6 +79448,191 @@ } } }, + "mesh_peers.action.copy_nickname" : { + "comment" : "Context menu action that copies a peer's display name", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "نسخ اللقب" + } + }, + "bn" : { + "stringUnit" : { + "state" : "translated", + "value" : "ডাকনাম কপি" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "spitznamen kopieren" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "copy nickname" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "copiar apodo" + } + }, + "fa" : { + "stringUnit" : { + "state" : "translated", + "value" : "کپی نام مستعار" + } + }, + "fil" : { + "stringUnit" : { + "state" : "translated", + "value" : "kopyahin ang palayaw" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "copier le surnom" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "העתק כינוי" + } + }, + "hi" : { + "stringUnit" : { + "state" : "translated", + "value" : "उपनाम कॉपी करें" + } + }, + "id" : { + "stringUnit" : { + "state" : "translated", + "value" : "salin nama panggilan" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "copia soprannome" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ニックネームをコピー" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "닉네임 복사" + } + }, + "ms" : { + "stringUnit" : { + "state" : "translated", + "value" : "salin nama samaran" + } + }, + "ne" : { + "stringUnit" : { + "state" : "translated", + "value" : "उपनाम कपी" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "bijnaam kopiëren" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "kopiuj pseudonim" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "copiar alcunha" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "copiar apelido" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "копировать ник" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "kopiera smeknamn" + } + }, + "ta" : { + "stringUnit" : { + "state" : "translated", + "value" : "புனைப்பெயரை நகலெடு" + } + }, + "th" : { + "stringUnit" : { + "state" : "translated", + "value" : "คัดลอกชื่อเล่น" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "takma adı kopyala" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "копіювати нік" + } + }, + "ur" : { + "stringUnit" : { + "state" : "translated", + "value" : "عرفی نام کاپی کریں" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "sao chép biệt danh" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "复制昵称" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "複製暱稱" + } + } + } + }, "mesh_peers.state.blocked" : { "comment" : "State label for a blocked peer", "extractionState" : "manual", diff --git a/bitchat/Utils/NicknameClipboard.swift b/bitchat/Utils/NicknameClipboard.swift new file mode 100644 index 00000000..8918108b --- /dev/null +++ b/bitchat/Utils/NicknameClipboard.swift @@ -0,0 +1,29 @@ +// +// NicknameClipboard.swift +// bitchat +// +// This is free and unencumbered software released into the public domain. +// For more information, see +// + +import Foundation +#if os(iOS) +import UIKit +#elseif os(macOS) +import AppKit +#endif + +/// Pasteboard writes for people-sheet nickname / display-name copy actions. +/// +/// Callers pass the full `displayName` (including any `#abcd` suffix) so a +/// pasted `/msg` target matches what the roster shows. +enum NicknameClipboard { + static func copy(_ string: String) { + #if os(iOS) + UIPasteboard.general.string = string + #elseif os(macOS) + NSPasteboard.general.clearContents() + NSPasteboard.general.setString(string, forType: .string) + #endif + } +} diff --git a/bitchat/Views/GeohashPeopleList.swift b/bitchat/Views/GeohashPeopleList.swift index 9613f227..d8352200 100644 --- a/bitchat/Views/GeohashPeopleList.swift +++ b/bitchat/Views/GeohashPeopleList.swift @@ -20,6 +20,7 @@ struct GeohashPeopleList: View { static let blockedState = String(localized: "mesh_peers.state.blocked", comment: "State label for a blocked peer") static let youState = String(localized: "geohash_people.state.you", comment: "State label marking your own row in the people list") static let openDMHint = String(localized: "mesh_peers.accessibility.open_dm_hint", comment: "Accessibility hint on a peer row explaining activation opens a private chat") + static let copyNickname = String(localized: "mesh_peers.action.copy_nickname", comment: "Context menu action that copies a peer's display name") } var body: some View { @@ -102,6 +103,9 @@ struct GeohashPeopleList: View { if person.isMe { EmptyView() } else { + Button(Strings.copyNickname) { + NicknameClipboard.copy(person.displayName) + } if person.isBlocked { Button(Strings.unblock) { peerListModel.unblockGeohashUser( @@ -125,6 +129,9 @@ struct GeohashPeopleList: View { .accessibilityHint(person.isMe ? "" : Strings.openDMHint) .accessibilityActions { if !person.isMe { + Button(Strings.copyNickname) { + NicknameClipboard.copy(person.displayName) + } Button(person.isBlocked ? Strings.unblockText : Strings.blockText) { if person.isBlocked { peerListModel.unblockGeohashUser( diff --git a/bitchat/Views/MeshPeerList.swift b/bitchat/Views/MeshPeerList.swift index 1d94af5f..ab888dbe 100644 --- a/bitchat/Views/MeshPeerList.swift +++ b/bitchat/Views/MeshPeerList.swift @@ -34,6 +34,7 @@ struct MeshPeerList: View { static let directMessage = String(localized: "content.actions.direct_message", comment: "Action that opens a private chat with the person") static let block = String(localized: "geohash_people.action.block", comment: "Context menu action to block a person") static let unblock = String(localized: "geohash_people.action.unblock", comment: "Context menu action to unblock a person") + static let copyNickname = String(localized: "mesh_peers.action.copy_nickname", comment: "Context menu action that copies a peer's display name") } var body: some View { @@ -189,6 +190,9 @@ struct MeshPeerList: View { Button(Strings.directMessage) { onTapPeer(peer.peerID) } + Button(Strings.copyNickname) { + NicknameClipboard.copy(peer.displayName) + } Button(peer.isFavorite ? Strings.removeFavorite : Strings.addFavorite) { onToggleFavorite(peer.peerID) } @@ -214,6 +218,9 @@ struct MeshPeerList: View { .accessibilityHint(isMe ? "" : Strings.openDMHint) .accessibilityActions { if !isMe { + Button(Strings.copyNickname) { + NicknameClipboard.copy(peer.displayName) + } Button(peer.isFavorite ? Strings.removeFavorite : Strings.addFavorite) { onToggleFavorite(peer.peerID) }