Merge master

This commit is contained in:
Leon Böttger committed 2025-08-20 10:56:48 +02:00
1 parent 71c6e8bb3a
commit 149c375230
2 files changed
+64 -86

No files matched your search

+15 -11
View File
@@ -14,10 +14,9 @@ import SwiftUI
import UserNotifications
@main
class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDelegate, NSWindowDelegate, MainAppDelegate {
class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDelegate, NSWindowDelegate {
private var statusItem: NSStatusItem?
private var activeIncomingTransfers: [String: TransferInfo] = [:]
var welcomeWindow: NSWindow?
var plusWindow: NSWindow?
@@ -27,6 +26,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
private var errorAlertHandler = ErrorAlertHandler.shared
private var iapManager: IAPManager?
private var receiveModel: ReceiveModel?
var showsFirewallAlert = false
var visibleItem: NSMenuItem? = nil
@@ -65,9 +65,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
statusItem?.menu = menu
statusItem?.behavior = .removalAllowed
NearbyConnectionManager.shared.mainAppDelegate = self
NearbyConnectionManager.shared.becomeVisible()
iapManager = IAPManager.sharedInstance
iapManager?.startObserving()
@@ -112,7 +109,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
let queue2 = DispatchQueue(label: "NetworkConnectionMonitor")
hasConnectionMonitor.start(queue: queue2)
receiveModel = ReceiveModel(controlPlusScreen: { shouldOpen in
if shouldOpen {
self.openPlusScreen()
@@ -136,7 +133,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
welcomeWindow = nil
NSApp.setActivationPolicy(.accessory)
}
}
}
func applicationShouldHandleReopen(_: NSApplication, hasVisibleWindows _: Bool) -> Bool {
@@ -187,8 +184,15 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
let pasteboard = NSPasteboard.general
let clipboardString = pasteboard.string(forType: .string) ?? ""
let sharingService = NSSharingService(named: NSSharingService.Name("com.leonboettger.neardrop.ShareExtension"))
sharingService?.perform(withItems: [clipboardString])
if clipboardString.isEmpty {
DispatchQueue.main.async {
BezelNotification.show(messageText: "ClipboardEmpty".localized(), icon: .clipboard)
}
}
else {
let sharingService = NSSharingService(named: NSSharingService.Name("com.leonboettger.neardrop.ShareExtension"))
sharingService?.perform(withItems: [clipboardString])
}
}
@@ -243,7 +247,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
log("Plus screen already open, bringing to front")
return
}
log("Opening Plus screen")
// Create the welcome screen SwiftUI view
@@ -318,7 +322,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
}
}
// MARK: - Helper Functions
private func performDeviceToDeviceCheck() {
+49 -75
View File
@@ -8,8 +8,10 @@
import Cocoa
import Foundation
import SwiftUI
import QRCode
class ShareViewController: NSViewController, ShareExtensionDelegate {
class ShareViewController: NSViewController, OutboundAppDelegate {
private var urls: [URL] = []
private var textToSend: String? = nil
private var foundDevices: [RemoteDeviceInfo] = []
@@ -46,11 +48,12 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
override func loadView() {
super.loadView()
loadAttachments(with: extensionContext, loadedItems: { result in
log("Loaded attachments: \(result)")
self.urls = result.urls
self.textToSend = result.textToSend
self.filesLabel?.stringValue = result.shortDescription
@@ -93,6 +96,7 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
override func viewDidLoad() {
super.viewDidLoad()
dicoverDevices()
@@ -128,7 +132,27 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
private func openQrCodeView() {
if qrCodeSheetView == nil {
let contentView = SmallSheetView(type: .sendToDeviceQrCode) {
var image: Image? = nil
do {
let qrKey = NearbyConnectionManager.shared.generateQrCodeKey()
let qrCodeImage = try QRCode.build
.text("https://quickshare.google/qrcode#key=\(qrKey)")
.backgroundColor(CGColor(srgbRed: 1, green: 1, blue: 1, alpha: 0))
.quietZonePixelCount(3)
.onPixels.shape(.circle())
.eye.shape(.squircle())
.errorCorrection(.low)
.generate.image(dimension: 1000)
image = Image(nsImage: NSImage(cgImage: qrCodeImage, size: qrCodeImage.size))
}
catch {
log("Error generating QR code: \(error)")
}
let contentView = SmallSheetView(type: .sendToDeviceQrCode, dynamicQrCode: image) {
self.closeQrCodeView()
}
@@ -161,71 +185,11 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
}
private func zipFolderAndSetUpIcon() {
for url in urls {
if url.isFileURL {
let isDirectory = UnsafeMutablePointer<ObjCBool>.allocate(capacity: 1)
if FileManager.default.fileExists(atPath: url.path, isDirectory: isDirectory) && isDirectory.pointee.boolValue {
do {
let zipUrl = try createZipAtTmp(zipFilename: url.lastPathComponent, fromDirectory: url)
let index = urls.firstIndex(of: url)
urls[index!] = zipUrl
} catch {
log("Error creating zip file: \(error)")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
log("Canceling share request because URL \(url) is a directory")
AudioManager.playErrorSound()
let alert = NSAlert()
alert.alertStyle = .critical
alert.messageText = "TypeNotSupported".localized()
alert.informativeText = "TypeNotSupportedDescription".localized()
alert.addButton(withTitle: "TypeNotSupportedButton".localized())
alert.beginSheetModal(for: self.view.window!) { _ in
let cancelError = NSError(domain: NSCocoaErrorDomain, code: NSUserCancelledError, userInfo: nil)
self.extensionContext!.cancelRequest(withError: cancelError)
}
}
return
}
}
}
}
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)
} else if urls[0].scheme == "http" || urls[0].scheme == "https" {
filesLabel!.stringValue = urls[0].absoluteString
filesIcon!.image = NSImage(named: NSImage.networkName)
}
} else {
filesLabel!.stringValue = String.localizedStringWithFormat("NFiles".localized(), urls.count)
filesIcon!.image = NSImage(named: NSImage.multipleDocumentsName)
}
}
func addDevice(device: RemoteDeviceInfo) {
if chosenDevice != nil {
return
}
if foundDevices.isEmpty {
loadingOverlay?.animator().isHidden = true
}
@@ -237,6 +201,7 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
func removeDevice(id: String) {
if chosenDevice != nil {
return
}
@@ -253,6 +218,12 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
}
func startTransferWithQrCode(device: RemoteDeviceInfo) {
closeQrCodeView()
selectDevice(device: device)
}
func connectionWasEstablished(pinCode: String) {
connectionEstablished = true
@@ -291,7 +262,6 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
func selectDevice(device: RemoteDeviceInfo) {
NearbyConnectionManager.shared.stopDeviceDiscovery()
listViewWrapper?.animator().isHidden = true
dontSeeDeviceButton?.animator().isHidden = true
@@ -301,6 +271,7 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
progressProgressBar?.startAnimation(nil)
progressState?.stringValue = "Connecting".localized()
chosenDevice = device
NearbyConnectionManager.shared.stopDeviceDiscovery()
NearbyConnectionManager.shared.startOutgoingTransfer(deviceID: device.id!, delegate: self, urls: urls, textToSend: textToSend)
let timeoutAlert = DispatchWorkItem {
@@ -334,6 +305,7 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
private func dicoverDevices() {
let bundleIdentifier = "com.leonboettger.neardrop"
let runningApps = NSWorkspace.shared.runningApplications
@@ -346,13 +318,13 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
let configuration = NSWorkspace.OpenConfiguration()
NSWorkspace.shared.openApplication(at: url, configuration: configuration) { app, error in
if let error = error {
print("Failed to launch application: \(error)")
log("Failed to launch application: \(error)")
} else {
print("Application launched successfully")
log("Application launched successfully")
}
}
} else {
print("Could not find application with bundle identifier \(bundleIdentifier)")
log("Could not find application with bundle identifier \(bundleIdentifier)")
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
@@ -368,6 +340,7 @@ class ShareViewController: NSViewController, ShareExtensionDelegate {
private func scheduleAutomaticQrCodeView() {
DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) {
if self.foundDevices.isEmpty {
self.openQrCodeView()
@@ -421,9 +394,10 @@ extension ShareViewController: NSCollectionViewDataSource {
func getDeviceName(device: RemoteDeviceInfo) -> String {
if device.name.count <= 1 {
return "Android"
if let name = device.name, name.count > 1 {
return name
}
return device.name
return "Android"
}
}