Supporting sending of plain text

This commit is contained in:
Leon Böttger committed 2025-05-17 13:58:31 +02:00
1 parent 6b883e9457
commit dd28d21134
4 files changed
+66 -20

No files matched your search

+6 -4
View File
@@ -123,10 +123,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
}
@objc func sendClipboard() {
if let fileURL = ClipboardManager.saveClipboardToTempFile() {
let sharingService = NSSharingService(named: NSSharingService.Name("com.leonboettger.neardrop.ShareExtension"))
sharingService?.perform(withItems: [fileURL])
}
let pasteboard = NSPasteboard.general
let clipboardString = pasteboard.string(forType: .string) ?? ""
let sharingService = NSSharingService(named: NSSharingService.Name("com.leonboettger.neardrop.ShareExtension"))
sharingService?.perform(withItems: [clipboardString])
}
@objc func openWelcomeScreen() {
+2 -2
View File
@@ -385,12 +385,12 @@ public class NearbyConnectionManager: NSObject, NetServiceDelegate, InboundNearb
}
}
public func startOutgoingTransfer(deviceID: String, delegate: ShareExtensionDelegate, urls: [URL]) {
public func startOutgoingTransfer(deviceID: String, delegate: ShareExtensionDelegate, urls: [URL], textToSend: String?) {
guard let info = foundServices[deviceID] else { return }
let tcp = NWProtocolTCP.Options()
tcp.noDelay = true
let nwconn = NWConnection(to: info.service.endpoint, using: NWParameters(tls: .none, tcp: tcp))
let conn = OutboundNearbyConnection(connection: nwconn, id: deviceID, urlsToSend: urls)
let conn = OutboundNearbyConnection(connection: nwconn, id: deviceID, urlsToSend: urls, textToSend: textToSend)
conn.delegate = self
let transfer = OutgoingTransferInfo(service: info.service, device: info.device!, connection: conn, delegate: delegate)
outgoingTransfers[deviceID] = transfer
+37 -7
View File
@@ -15,26 +15,33 @@ import UniformTypeIdentifiers
import BigInt
import SwiftECC
class OutboundNearbyConnection: NearbyConnection {
private var currentState: State = .initial
private let urlsToSend: [URL]
private let textToSend: String?
private var ukeyClientFinishMsgData: Data?
private var queue: [OutgoingFileTransfer] = []
private var currentTransfer: OutgoingFileTransfer?
public var delegate: OutboundNearbyConnectionDelegate?
private var totalBytesToSend: Int64 = 0
private var totalBytesSent: Int64 = 0
private var cancelled: Bool = false
private var textPayloadID: Int64 = 0
public var delegate: OutboundNearbyConnectionDelegate?
enum State {
case initial, sentUkeyClientInit, sentUkeyClientFinish, sentPairedKeyEncryption, sentPairedKeyResult, sentIntroduction, sendingFiles
}
init(connection: NWConnection, id: String, urlsToSend: [URL]) {
init(connection: NWConnection, id: String, urlsToSend: [URL], textToSend: String?) {
self.urlsToSend = urlsToSend
self.textToSend = textToSend
super.init(connection: connection, id: id)
if urlsToSend.count == 1 && !urlsToSend[0].isFileURL {
if hasURL() || textToSend != nil {
textPayloadID = Int64.random(in: Int64.min ... Int64.max)
}
}
@@ -93,7 +100,9 @@ class OutboundNearbyConnection: NearbyConnection {
}
} catch {
if case NearbyError.ukey2 = error {
} else if currentState == .sentUkeyClientInit {
// do nothing
}
else if currentState == .sentUkeyClientInit {
sendUkey2Alert(type: .badMessage)
}
lastError = error
@@ -256,7 +265,16 @@ class OutboundNearbyConnection: NearbyConnection {
var introduction = Sharing_Nearby_Frame()
introduction.version = .v1
introduction.v1.type = .introduction
if urlsToSend.count == 1 && !urlsToSend[0].isFileURL {
if let textToSend = textToSend {
var meta = Sharing_Nearby_TextMetadata()
meta.type = .text
meta.textTitle = textToSend
meta.size = Int64(textToSend.utf8.count)
meta.payloadID = textPayloadID
introduction.v1.introduction.textMetadata.append(meta)
} else if hasURL() {
var meta = Sharing_Nearby_TextMetadata()
meta.type = .url
meta.textTitle = urlsToSend[0].host ?? "URL"
@@ -313,7 +331,11 @@ class OutboundNearbyConnection: NearbyConnection {
case .accept:
currentState = .sendingFiles
delegate?.outboundConnectionTransferAccepted(connection: self)
if urlsToSend.count == 1 && !urlsToSend[0].isFileURL {
if let textToSend = textToSend {
try sendText(text: textToSend)
}
if hasURL() {
try sendURL()
} else {
try sendNextFileChunk()
@@ -332,9 +354,17 @@ class OutboundNearbyConnection: NearbyConnection {
try sendDisconnectionAndDisconnect()
}
}
private func hasURL() -> Bool {
urlsToSend.count == 1 && !urlsToSend[0].isFileURL
}
private func sendURL() throws {
try sendBytesPayload(data: Data(urlsToSend[0].absoluteString.utf8), id: textPayloadID)
try sendText(text: urlsToSend[0].absoluteString)
}
private func sendText(text: String) throws {
try sendBytesPayload(data: Data(text.utf8), id: textPayloadID)
delegate?.outboundConnectionTransferFinished(connection: self)
try sendDisconnectionAndDisconnect()
}
+21 -7
View File
@@ -12,6 +12,7 @@ import SwiftUI
class ShareViewController: NSViewController, ShareExtensionDelegate {
private var urls: [URL] = []
private var textToSend: String? = nil
private var foundDevices: [RemoteDeviceInfo] = []
private var chosenDevice: RemoteDeviceInfo?
private var lastError: Error?
@@ -47,11 +48,11 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
let item = extensionContext!.inputItems[0] as! NSExtensionItem
if let attachments = item.attachments {
if let text = item.attributedContentText?.string, attachments.isEmpty, let tempUrl = ClipboardManager.saveTextToTempFile(text: text) {
urls.append(tempUrl)
if let text = item.attributedContentText?.string, attachments.isEmpty {
textToSend = text
DispatchQueue.main.async {
self.urlsReady()
self.zipFolderAndSetUpIcon()
}
} else {
for attachment in attachments {
@@ -67,7 +68,7 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
if self.urls.count == attachments.count {
DispatchQueue.main.async {
self.urlsReady()
self.zipFolderAndSetUpIcon()
}
}
}
@@ -177,7 +178,7 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
}
}
private func urlsReady() {
private func zipFolderAndSetUpIcon() {
for url in urls {
if url.isFileURL {
let isDirectory = UnsafeMutablePointer<ObjCBool>.allocate(capacity: 1)
@@ -212,7 +213,20 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
}
}
if urls.count == 1 {
if let textToSend = textToSend {
let maxLength = 50
let cleanedText = textToSend.replacingOccurrences(of: "\n", with: " ").replacingOccurrences(of: "\r", with: "")
if cleanedText.count > maxLength {
let index = cleanedText.index(cleanedText.startIndex, offsetBy: maxLength)
filesLabel!.stringValue = String(cleanedText[..<index]) + "..."
} else {
filesLabel!.stringValue = cleanedText
}
filesIcon!.image = NSImage(named: NSImage.multipleDocumentsName)
}
else if urls.count == 1 {
if urls[0].isFileURL {
filesLabel!.stringValue = urls[0].lastPathComponent
filesIcon!.image = NSWorkspace.shared.icon(forFile: urls[0].path)
@@ -315,7 +329,7 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
progressProgressBar?.startAnimation(nil)
progressState?.stringValue = NSLocalizedString("Connecting", value: "Connecting...", comment: "")
chosenDevice = device
NearbyConnectionManager.shared.startOutgoingTransfer(deviceID: device.id!, delegate: self, urls: urls)
NearbyConnectionManager.shared.startOutgoingTransfer(deviceID: device.id!, delegate: self, urls: urls, textToSend: textToSend)
let timeoutAlert = DispatchWorkItem {
if !self.connectionEstablished {