Copy text to clipboard

This commit is contained in:
Leon Böttger committed 2025-05-17 13:00:42 +02:00
1 parent dbca8d6434
commit ab4af784c4
22 files changed
+215 -23

No files matched your search

+22 -1
View File
@@ -16,6 +16,7 @@ import UserNotifications
@main
class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDelegate, MainAppDelegate {
private var statusItem: NSStatusItem?
private var activeIncomingTransfers: [String: TransferInfo] = [:]
@@ -284,7 +285,21 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
fileStr = String.localizedStringWithFormat(NSLocalizedString("NFiles", value: "%d files", comment: ""), transfer.files.count)
}
let mainMessage = String(format: (acceptAutomatically ? "DeviceCurrentlySendingFiles" : "DeviceSendingFiles").localized(), arguments: [device.name, fileStr])
let mainMessage: String
switch transfer.type {
case .file:
mainMessage = String(format: (acceptAutomatically ? "DeviceCurrentlySendingFiles" : "DeviceSendingFiles").localized(), arguments: [device.name, fileStr])
case .text:
mainMessage = String(format: (acceptAutomatically ? "DeviceCurrentlySendingText" : "DeviceSendingText").localized(), arguments: [device.name, fileStr])
case .url:
mainMessage = String(format: (acceptAutomatically ? "DeviceCurrentlySendingUrl" : "DeviceSendingUrl").localized(), arguments: [device.name, fileStr])
}
let pinCodeMessage = String(format: NSLocalizedString("PinCode", value: "PIN: %@", comment: ""), arguments: [transfer.pinCode ?? "?"])
let transferID = transfer.id
@@ -342,6 +357,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
func showFirewallAlert() {
openAlert(type: .Firewall)
}
func showCopiedToClipboardAlert() {
DispatchQueue.main.async {
BezelNotification.show(messageText: "InsertedIntoClipboard".localized(), icon: .clipboard)
}
}
func incomingTransfer(id: String, didFinishWith error: Error?) {
guard let transfer = activeIncomingTransfers[id] else { return }
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "Clipboard.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ is sending you %2$@";
"DeviceCurrentlySendingText" = "%1$@ inserted \"%2$@\" to your clipboard.";
"DeviceSendingText" = "%1$@ wants to insert \"%2$@\" to your Mac's clipboard.";
"DeviceCurrentlySendingUrl" = "%1$@ opened \"%2$@\".";
"DeviceSendingUrl" = "%1$@ wants to open \"%2$@\" on your Mac.";
"InsertedIntoClipboard" = "Inserted";
/* No comment provided by engineer. */
"Error.Crypto" = "Encryption error";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ يرسل لك %2$@";
"DeviceCurrentlySendingText" = "قام %1$@ بإدراج \"%2$@\" في الحافظة الخاصة بك.";
"DeviceSendingText" = "يرغب %1$@ في إدراج \"%2$@\" في حافظة جهاز Mac الخاص بك.";
"DeviceCurrentlySendingUrl" = "قام %1$@ بفتح \"%2$@\".";
"DeviceSendingUrl" = "يرغب %1$@ في فتح \"%2$@\" على جهاز Mac الخاص بك.";
"InsertedIntoClipboard" = "تم الإدراج";
/* No comment provided by engineer. */
"Error.Crypto" = "خطأ في التشفير";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ möchte dir %2$@ senden";
"DeviceCurrentlySendingText" = "%1$@ hat \"%2$@\" in deine Zwischenablage eingefügt.";
"DeviceSendingText" = "%1$@ möchte \"%2$@\" in die Zwischenablage deines Macs einfügen.";
"DeviceCurrentlySendingUrl" = "%1$@ hat \"%2$@\" geöffnet.";
"DeviceSendingUrl" = "%1$@ möchte \"%2$@\" auf deinem Mac öffnen.";
"InsertedIntoClipboard" = "Eingefügt";
/* No comment provided by engineer. */
"Error.Crypto" = "Verschlüsselungsfehler";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ te quiere mandar %2$@";
"DeviceCurrentlySendingText" = "%1$@ ha insertado \"%2$@\" en tu portapapeles.";
"DeviceSendingText" = "%1$@ quiere insertar \"%2$@\" en el portapapeles de tu Mac.";
"DeviceCurrentlySendingUrl" = "%1$@ ha abierto \"%2$@\".";
"DeviceSendingUrl" = "%1$@ quiere abrir \"%2$@\" en tu Mac.";
"InsertedIntoClipboard" = "Insertado";
/* No comment provided by engineer. */
"Error.Crypto" = " Error de encriptación";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ vous envoie %2$@";
"DeviceCurrentlySendingText" = "%1$@ a inséré \"%2$@\" dans votre presse-papiers.";
"DeviceSendingText" = "%1$@ souhaite insérer \"%2$@\" dans le presse-papiers de votre Mac.";
"DeviceCurrentlySendingUrl" = "%1$@ a ouvert \"%2$@\".";
"DeviceSendingUrl" = "%1$@ souhaite ouvrir \"%2$@\" sur votre Mac.";
"InsertedIntoClipboard" = "Inséré";
/* No comment provided by engineer. */
"Error.Crypto" = "Erreur de cryptage";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ a következőt küldi: %2$@";
"DeviceCurrentlySendingText" = "%1$@ beillesztette a(z) \"%2$@\" szöveget a vágólapodra.";
"DeviceSendingText" = "%1$@ be szeretné illeszteni a(z) \"%2$@\" szöveget a Mac-ed vágólapjára.";
"DeviceCurrentlySendingUrl" = "%1$@ megnyitotta a(z) \"%2$@\" hivatkozást.";
"DeviceSendingUrl" = "%1$@ meg szeretné nyitni a(z) \"%2$@\" hivatkozást a Mac-eden.";
"InsertedIntoClipboard" = "Beillesztve";
/* No comment provided by engineer. */
"Error.Crypto" = "Titkosítási hiba";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ ti sta mandando %2$@";
"DeviceCurrentlySendingText" = "%1$@ ha inserito \"%2$@\" negli appunti.";
"DeviceSendingText" = "%1$@ vuole inserire \"%2$@\" negli appunti del tuo Mac.";
"DeviceCurrentlySendingUrl" = "%1$@ ha aperto \"%2$@\".";
"DeviceSendingUrl" = "%1$@ vuole aprire \"%2$@\" sul tuo Mac.";
"InsertedIntoClipboard" = "Inserito";
/* No comment provided by engineer. */
"Error.Crypto" = "Errore di crittografia";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@が%2$@を送信しています";
"DeviceCurrentlySendingText" = "%1$@ が \"%2$@\" をクリップボードに挿入しました。";
"DeviceSendingText" = "%1$@ が \"%2$@\" をあなたの Mac のクリップボードに挿入しようとしています。";
"DeviceCurrentlySendingUrl" = "%1$@ が \"%2$@\" を開きました。";
"DeviceSendingUrl" = "%1$@ があなたの Mac で \"%2$@\" を開こうとしています。";
"InsertedIntoClipboard" = "挿入されました";
/* No comment provided by engineer. */
"Error.Crypto" = "暗号化エラー";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@에서 %2$@을(를) 공유하려고 합니다.";
"DeviceCurrentlySendingText" = "%1$@이(가) \"%2$@\"을(를) 클립보드에 삽입했습니다.";
"DeviceSendingText" = "%1$@이(가) \"%2$@\"을(를) Mac의 클립보드에 삽입하려고 합니다.";
"DeviceCurrentlySendingUrl" = "%1$@이(가) \"%2$@\"을(를) 열었습니다.";
"DeviceSendingUrl" = "%1$@이(가) Mac에서 \"%2$@\"을(를) 열려고 합니다.";
"InsertedIntoClipboard" = "삽입됨";
/* No comment provided by engineer. */
"Error.Crypto" = "암호화 오류";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ stuurt je %2$@";
"DeviceCurrentlySendingText" = "%1$@ heeft \"%2$@\" in je klembord geplaatst.";
"DeviceSendingText" = "%1$@ wil \"%2$@\" in het klembord van je Mac plaatsen.";
"DeviceCurrentlySendingUrl" = "%1$@ heeft \"%2$@\" geopend.";
"DeviceSendingUrl" = "%1$@ wil \"%2$@\" openen op je Mac.";
"InsertedIntoClipboard" = "Ingevoerd";
/* No comment provided by engineer. */
"Error.Crypto" = "Fout bij codering";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ está te enviando %2$@";
"DeviceCurrentlySendingText" = "%1$@ inseriu \"%2$@\" na sua área de transferência.";
"DeviceSendingText" = "%1$@ deseja inserir \"%2$@\" na área de transferência do seu Mac.";
"DeviceCurrentlySendingUrl" = "%1$@ abriu \"%2$@\".";
"DeviceSendingUrl" = "%1$@ deseja abrir \"%2$@\" no seu Mac.";
"InsertedIntoClipboard" = "Inserido";
/* No comment provided by engineer. */
"Error.Crypto" = "Erro de encriptação";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ está a enviar %2$@";
"DeviceCurrentlySendingText" = "%1$@ inseriu \"%2$@\" na sua área de transferência.";
"DeviceSendingText" = "%1$@ pretende inserir \"%2$@\" na área de transferência do seu Mac.";
"DeviceCurrentlySendingUrl" = "%1$@ abriu \"%2$@\".";
"DeviceSendingUrl" = "%1$@ pretende abrir \"%2$@\" no seu Mac.";
"InsertedIntoClipboard" = "Inserido";
/* No comment provided by engineer. */
"Error.Crypto" = "Erro de encriptação";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ vă trimite %2$@";
"DeviceCurrentlySendingText" = "%1$@ a introdus \"%2$@\" în clipboard-ul tău.";
"DeviceSendingText" = "%1$@ dorește să introducă \"%2$@\" în clipboard-ul Mac-ului tău.";
"DeviceCurrentlySendingUrl" = "%1$@ a deschis \"%2$@\".";
"DeviceSendingUrl" = "%1$@ dorește să deschidă \"%2$@\" pe Mac-ul tău.";
"InsertedIntoClipboard" = "Inserat";
/* No comment provided by engineer. */
"Error.Crypto" = "Eroare de criptare";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ отправляет Вам %2$@";
"DeviceCurrentlySendingText" = "%1$@ вставил \"%2$@\" в ваш буфер обмена.";
"DeviceSendingText" = "%1$@ хочет вставить \"%2$@\" в буфер обмена вашего Mac.";
"DeviceCurrentlySendingUrl" = "%1$@ открыл \"%2$@\".";
"DeviceSendingUrl" = "%1$@ хочет открыть \"%2$@\" на вашем Mac.";
"InsertedIntoClipboard" = "Вставлено";
/* No comment provided by engineer. */
"Error.Crypto" = "Ошибка шифрования";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ กำลังส่งไฟล์ให้คุณ %2$@";
"DeviceCurrentlySendingText" = "%1$@ ได้แทรก \"%2$@\" ไปยังคลิปบอร์ดของคุณแล้ว";
"DeviceSendingText" = "%1$@ ต้องการแทรก \"%2$@\" ไปยังคลิปบอร์ดของ Mac ของคุณ";
"DeviceCurrentlySendingUrl" = "%1$@ ได้เปิด \"%2$@\" แล้ว";
"DeviceSendingUrl" = "%1$@ ต้องการเปิด \"%2$@\" บน Mac ของคุณ";
"InsertedIntoClipboard" = "แทรกแล้ว";
/* No comment provided by engineer. */
"Error.Crypto" = "การเข้ารหัสผิดพลาด";
+7
View File
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ відправляє Вам %2$@";
"DeviceCurrentlySendingText" = "%1$@ вставив \"%2$@\" до вашого буфера обміну.";
"DeviceSendingText" = "%1$@ хоче вставити \"%2$@\" до буфера обміну вашого Mac.";
"DeviceCurrentlySendingUrl" = "%1$@ відкрив \"%2$@\".";
"DeviceSendingUrl" = "%1$@ хоче відкрити \"%2$@\" на вашому Mac.";
"InsertedIntoClipboard" = "Вставлено";
/* No comment provided by engineer. */
"Error.Crypto" = "Помилка шифрування";
@@ -9,6 +9,13 @@
/* No comment provided by engineer. */
"DeviceSendingFiles" = "%1$@ 正向你发送 %2$@";
"DeviceCurrentlySendingText" = "%1$@ 已将 \"%2$@\" 插入到你的剪贴板。";
"DeviceSendingText" = "%1$@ 想要将 \"%2$@\" 插入到你的 Mac 剪贴板。";
"DeviceCurrentlySendingUrl" = "%1$@ 已打开 \"%2$@\"。";
"DeviceSendingUrl" = "%1$@ 想要在你的 Mac 上打开 \"%2$@\"。";
"InsertedIntoClipboard" = "已插入";
/* No comment provided by engineer. */
"Error.Crypto" = "加密出错";
+43 -21
View File
@@ -21,6 +21,7 @@ class InboundNearbyConnection: NearbyConnection {
private var cipherCommitment: Data?
private var textPayloadID: Int64 = 0
private var isPlainTextTransfer = false
enum State {
case initial, receivedConnectionRequest, sentUkeyServerInit, receivedUkeyClientFinish, sentConnectionResponse, sentPairedKeyResult, receivedPairedKeyResult, waitingForUserConsent, receivingFiles, disconnected
@@ -130,9 +131,21 @@ class InboundNearbyConnection: NearbyConnection {
override func processBytesPayload(payload: Data, id: Int64) throws -> Bool {
if id == textPayloadID {
if let urlStr = String(data: payload, encoding: .utf8), let url = URL(string: urlStr) {
NSWorkspace.shared.open(url)
if let urlStr = String(data: payload, encoding: .utf8) {
if isPlainTextTransfer {
// paste to clipboard
let pasteboard = NSPasteboard.general
pasteboard.clearContents()
pasteboard.setString(urlStr, forType: .string)
NearbyConnectionManager.shared.mainAppDelegate?.showCopiedToClipboardAlert()
}
else if let url = URL(string: urlStr) {
NSWorkspace.shared.open(url)
}
}
try sendDisconnectionAndDisconnect()
return true
} else if let fileInfo = transferredFiles[id] {
@@ -151,14 +164,23 @@ class InboundNearbyConnection: NearbyConnection {
}
private func processConnectionRequestFrame(_ frame: Location_Nearby_Connections_OfflineFrame) throws {
guard frame.hasV1 && frame.v1.hasConnectionRequest && frame.v1.connectionRequest.hasEndpointInfo else { throw NearbyError.requiredFieldMissing("connectionRequest.endpointInfo") }
guard case .connectionRequest = frame.v1.type else { throw NearbyError.protocolError("Unexpected frame type \(frame.v1.type)") }
let endpointInfo = frame.v1.connectionRequest.endpointInfo
guard endpointInfo.count > 17 else { throw NearbyError.protocolError("Endpoint info too short") }
let deviceNameLength = Int(endpointInfo[17])
guard endpointInfo.count >= deviceNameLength + 18 else { throw NearbyError.protocolError("Endpoint info too short to contain the device name") }
guard let deviceName = String(data: endpointInfo[18 ..< (18 + deviceNameLength)], encoding: .utf8) else { throw NearbyError.protocolError("Device name is not valid UTF-8") }
let rawDeviceType = Int(endpointInfo[0] & 7) >> 1
remoteDeviceInfo = RemoteDeviceInfo(name: deviceName, type: RemoteDeviceInfo.DeviceType.fromRawValue(value: rawDeviceType))
currentState = .receivedConnectionRequest
}
@@ -329,32 +351,29 @@ class InboundNearbyConnection: NearbyConnection {
DispatchQueue.main.async {
self.delegate?.obtainUserConsent(for: metadata, from: self.remoteDeviceInfo!, connection: self)
}
} else if frame.v1.introduction.textMetadata.count == 1 {
let meta = frame.v1.introduction.textMetadata[0]
if case .url = meta.type {
let metadata = TransferMetadata(files: [], id: id, pinCode: pinCode, textDescription: meta.textTitle)
textPayloadID = meta.payloadID
} else if let textMetadata = frame.v1.introduction.textMetadata.first {
if textMetadata.type == .url || textMetadata.type == .text {
let isClipboardText = textMetadata.type == .text
let metadata = TransferMetadata(files: [], id: id, pinCode: pinCode, textDescription: textMetadata.textTitle, transferType: isClipboardText ? .text : .url)
textPayloadID = textMetadata.payloadID
if isClipboardText{
isPlainTextTransfer = true
}
DispatchQueue.main.async {
self.delegate?.obtainUserConsent(for: metadata, from: self.remoteDeviceInfo!, connection: self)
}
} else if case .text = meta.type {
let saveDirectory = SaveFilesManager.shared.getSaveDirectory()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH.mm.ss"
let dest = makeFileDestinationURL(saveDirectory.appendingPathComponent("\(dateFormatter.string(from: Date())).txt"))
let info = InternalFileInfo(meta: FileMetadata(name: dest.lastPathComponent, size: meta.size, mimeType: "text/plain"),
payloadID: meta.payloadID,
destinationURL: dest)
transferredFiles[meta.payloadID] = info
DispatchQueue.main.async {
self.delegate?.obtainUserConsent(for: TransferMetadata(files: [info.meta], id: self.id, pinCode: self.pinCode), from: self.remoteDeviceInfo!, connection: self)
}
} else {
}
else {
rejectTransfer(with: .unsupportedAttachmentType)
}
} else {
rejectTransfer(with: .unsupportedAttachmentType)
}
}
@@ -409,6 +428,9 @@ class InboundNearbyConnection: NearbyConnection {
}
private func rejectTransfer(with reason: Sharing_Nearby_ConnectionResponseFrame.Status = .reject) {
log("Rejecting transfer because of \( reason)")
var frame = Sharing_Nearby_Frame()
frame.version = .v1
frame.v1.type = .response
+10 -1
View File
@@ -66,12 +66,20 @@ public struct TransferMetadata {
public let id: String
public let pinCode: String?
public let textDescription: String?
public let type: TransferType
init(files: [FileMetadata], id: String, pinCode: String?, textDescription: String? = nil) {
init(files: [FileMetadata], id: String, pinCode: String?, textDescription: String? = nil, transferType: TransferType = .file) {
self.files = files
self.id = id
self.pinCode = pinCode
self.textDescription = textDescription
self.type = transferType
}
public enum TransferType {
case file
case text
case url
}
}
@@ -137,6 +145,7 @@ public protocol MainAppDelegate {
func obtainUserConsent(for transfer: TransferMetadata, from device: RemoteDeviceInfo)
func incomingTransfer(id: String, didFinishWith error: Error?)
func showFirewallAlert()
func showCopiedToClipboardAlert()
}
public protocol ShareExtensionDelegate: AnyObject {