mirror of
https://github.com/leonboe1/QuickDrop.git
synced 2026-11-12 03:21:09 +00:00
Formatting
This commit is contained in:
1 parent
3a2a8c70b9
commit
dbca8d6434
3 files changed
+282
-355
No files matched your search
+105
-137
@@ -5,89 +5,83 @@
|
||||
// Created by Grishka on 08.04.2023.
|
||||
//
|
||||
|
||||
import Network
|
||||
import Cocoa
|
||||
import UserNotifications
|
||||
import NearbyShare
|
||||
import SwiftUI
|
||||
import StoreKit
|
||||
import AudioToolbox
|
||||
import BezelNotification
|
||||
import Cocoa
|
||||
import NearbyShare
|
||||
import Network
|
||||
import StoreKit
|
||||
import SwiftUI
|
||||
import UserNotifications
|
||||
|
||||
@main
|
||||
class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDelegate, MainAppDelegate {
|
||||
|
||||
private var statusItem: NSStatusItem?
|
||||
private var activeIncomingTransfers: [String : TransferInfo] = [:]
|
||||
|
||||
private var activeIncomingTransfers: [String: TransferInfo] = [:]
|
||||
|
||||
var welcomeWindow: NSWindow?
|
||||
var plusWindow: NSWindow?
|
||||
var firewallAlertWindow: NSWindow?
|
||||
var apIsolationAlertWindow: NSWindow?
|
||||
var networkFilterAlertWindow: NSWindow?
|
||||
private var iapManager: IAPManager?
|
||||
|
||||
|
||||
var showsFirewallAlert = false
|
||||
|
||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||
|
||||
|
||||
func applicationDidFinishLaunching(_: Notification) {
|
||||
let menu = NSMenu()
|
||||
|
||||
|
||||
menu.addItem(withTitle: NSLocalizedString("VisibleToEveryone", value: "Visible to everyone", comment: ""), action: nil, keyEquivalent: "")
|
||||
menu.addItem(withTitle: String(format: NSLocalizedString("DeviceName", value: "Device name: %@", comment: ""), arguments: [Host.current().localizedName ?? "Mac"]), action: nil, keyEquivalent: "")
|
||||
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
|
||||
let sendClipboardItem = NSMenuItem(title: "SendClipboard".localized(), action: #selector(sendClipboard), keyEquivalent: "")
|
||||
menu.addItem(sendClipboardItem)
|
||||
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
|
||||
let userManualItem = NSMenuItem(title: NSLocalizedString("UserManual", value: "User Manual", comment: ""), action: #selector(openWelcomeScreen), keyEquivalent: "")
|
||||
menu.addItem(userManualItem)
|
||||
|
||||
|
||||
menu.addItem(withTitle: NSLocalizedString("Quit", value: "Quit QuickDrop", comment: ""), action: #selector(NSApplication.terminate(_:)), keyEquivalent: "")
|
||||
|
||||
|
||||
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
||||
statusItem?.button?.image = NSImage(named: "MenuBarIcon")
|
||||
statusItem?.menu = menu
|
||||
statusItem?.behavior = .removalAllowed
|
||||
|
||||
NearbyConnectionManager.shared.mainAppDelegate=self
|
||||
|
||||
NearbyConnectionManager.shared.mainAppDelegate = self
|
||||
NearbyConnectionManager.shared.becomeVisible()
|
||||
|
||||
|
||||
iapManager = IAPManager.sharedInstance
|
||||
iapManager?.startObserving()
|
||||
|
||||
|
||||
// app did not lauch before
|
||||
if !UserDefaults.standard.bool(forKey: UserDefaultsKeys.appLaunchedBefore.rawValue){
|
||||
|
||||
if !UserDefaults.standard.bool(forKey: UserDefaultsKeys.appLaunchedBefore.rawValue) {
|
||||
log("Opening Welcome Screen")
|
||||
// open welcome screen
|
||||
openWelcomeScreen()
|
||||
UserDefaults.standard.set(true, forKey: UserDefaultsKeys.appLaunchedBefore.rawValue)
|
||||
|
||||
|
||||
// user installed the app after the IAP was implemented, set the user as eligible for IAP
|
||||
UserDefaults.standard.set(true, forKey: UserDefaultsKeys.isEligibleForIap.rawValue)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// app launched before
|
||||
|
||||
|
||||
// user installed the app before the IAP was implemented, grant the plus version
|
||||
if !UserDefaults.standard.bool(forKey: UserDefaultsKeys.isEligibleForIap.rawValue) {
|
||||
log("Granting QuickDrop+ for old user")
|
||||
UserDefaults.standard.set(true, forKey: UserDefaultsKeys.plusVersion.rawValue)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if !isPlusVersion() {
|
||||
log("New user - QuickDrop+ not available")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BezelNotification.show(messageText: "ReadyToReceive".localized(), icon: .receiveIcon)
|
||||
}
|
||||
|
||||
|
||||
UNUserNotificationCenter.current().delegate = self
|
||||
|
||||
// let monitor = NWPathMonitor()
|
||||
@@ -107,15 +101,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
// } else {
|
||||
// log("Network unavailable")
|
||||
// }
|
||||
//
|
||||
//
|
||||
// monitor.cancel()
|
||||
// }
|
||||
//
|
||||
// let queue = DispatchQueue(label: "NetworkMonitor")
|
||||
// monitor.start(queue: queue)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func performDeviceToDeviceCheck() {
|
||||
let scanner = DeviceToDeviceHeuristicScanner()
|
||||
scanner.scan { allowed in
|
||||
@@ -127,21 +120,18 @@ 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])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@objc func openWelcomeScreen() {
|
||||
// Create the welcome screen SwiftUI view
|
||||
let welcomeView = WelcomeScreen(openPlusScreen: openPlusScreen, checkForNetworkIssues: performDeviceToDeviceCheck)
|
||||
|
||||
|
||||
// Create an NSWindow to host the SwiftUI view
|
||||
welcomeWindow = NSWindow(
|
||||
contentRect: NSRect(x: 0, y: 0, width: 400, height: 280),
|
||||
@@ -149,31 +139,29 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
backing: .buffered,
|
||||
defer: false
|
||||
)
|
||||
|
||||
|
||||
welcomeWindow?.styleMask.insert(.fullSizeContentView)
|
||||
welcomeWindow?.titleVisibility = .hidden
|
||||
welcomeWindow?.titlebarAppearsTransparent = true
|
||||
|
||||
|
||||
welcomeWindow?.center()
|
||||
welcomeWindow?.isReleasedWhenClosed = false
|
||||
welcomeWindow?.setFrameAutosaveName("WelcomeScreen")
|
||||
welcomeWindow?.contentView = NSHostingView(rootView: welcomeView)
|
||||
|
||||
|
||||
// Ensure the window is always on top
|
||||
NSApp.activate(ignoringOtherApps: true) // Brings the whole app to the front
|
||||
welcomeWindow?.makeKeyAndOrderFront(nil)
|
||||
welcomeWindow?.level = .normal
|
||||
}
|
||||
|
||||
|
||||
|
||||
@objc func openPlusScreen() {
|
||||
|
||||
// Create the welcome screen SwiftUI view
|
||||
let plusView = GetPlusView(closeView: {
|
||||
log("Closing plus screen")
|
||||
self.plusWindow?.close()
|
||||
})
|
||||
|
||||
|
||||
// Create an NSWindow to host the SwiftUI view
|
||||
plusWindow = NSWindow(
|
||||
contentRect: NSRect(x: 0, y: 0, width: plusViewWidth, height: plusViewHeight),
|
||||
@@ -181,35 +169,32 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
backing: .buffered,
|
||||
defer: false
|
||||
)
|
||||
|
||||
|
||||
plusWindow?.styleMask.insert(.fullSizeContentView)
|
||||
plusWindow?.titleVisibility = .hidden
|
||||
plusWindow?.titlebarAppearsTransparent = true
|
||||
|
||||
|
||||
plusWindow?.center()
|
||||
plusWindow?.isReleasedWhenClosed = false
|
||||
plusWindow?.setFrameAutosaveName("PlusScreen")
|
||||
plusWindow?.contentView = NSHostingView(rootView: plusView)
|
||||
|
||||
|
||||
// Ensure the window is always on top
|
||||
NSApp.activate(ignoringOtherApps: true) // Brings the whole app to the front
|
||||
plusWindow?.makeKeyAndOrderFront(nil)
|
||||
plusWindow?.level = .normal
|
||||
}
|
||||
|
||||
|
||||
enum AlertType: String {
|
||||
case ApIsolation
|
||||
case NetworkFilter
|
||||
case Firewall
|
||||
}
|
||||
|
||||
|
||||
|
||||
func openAlert(type: AlertType) {
|
||||
|
||||
log("Opening Alert for \(type)")
|
||||
|
||||
|
||||
DispatchQueue.main.async { [self] in
|
||||
|
||||
// Create an NSWindow to host the SwiftUI view
|
||||
let alertWindow = NSWindow(
|
||||
contentRect: NSRect(x: 0, y: 0, width: issueViewWidth, height: issueViewHeight),
|
||||
@@ -217,7 +202,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
backing: .buffered,
|
||||
defer: false
|
||||
)
|
||||
|
||||
|
||||
switch type {
|
||||
case .ApIsolation:
|
||||
apIsolationAlertWindow = alertWindow
|
||||
@@ -229,75 +214,68 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
firewallAlertWindow = alertWindow
|
||||
alertWindow.contentView = NSHostingView(rootView: FirewallIssueView())
|
||||
}
|
||||
|
||||
|
||||
alertWindow.title = "QuickDrop"
|
||||
alertWindow.center()
|
||||
alertWindow.isReleasedWhenClosed = false
|
||||
alertWindow.setFrameAutosaveName(type.rawValue)
|
||||
|
||||
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
alertWindow.makeKeyAndOrderFront(nil)
|
||||
alertWindow.level = .normal
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func transmissionCount() -> Int {
|
||||
return UserDefaults.standard.integer(forKey: UserDefaultsKeys.transmissionCount.rawValue)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Action for "Recommended Apps" menu item
|
||||
@objc func openRecommendedApps() {
|
||||
if let url = URL(string: "https://apps.apple.com/de/developer/leon-boettger/id1537384790") {
|
||||
NSWorkspace.shared.open(url)
|
||||
}
|
||||
}
|
||||
|
||||
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
|
||||
|
||||
|
||||
func applicationShouldHandleReopen(_: NSApplication, hasVisibleWindows _: Bool) -> Bool {
|
||||
openWelcomeScreen()
|
||||
statusItem?.isVisible=true
|
||||
statusItem?.isVisible = true
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
public func userNotificationCenter(_ center: UNUserNotificationCenter,
|
||||
willPresent notification: UNNotification,
|
||||
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
|
||||
completionHandler([.sound, .banner])
|
||||
}
|
||||
|
||||
|
||||
func applicationWillTerminate(_ aNotification: Notification) {
|
||||
|
||||
public func userNotificationCenter(_: UNUserNotificationCenter,
|
||||
willPresent _: UNNotification,
|
||||
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
|
||||
{
|
||||
completionHandler([.sound, .banner])
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_: Notification) {
|
||||
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
|
||||
iapManager?.stopObserving()
|
||||
}
|
||||
|
||||
|
||||
func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
|
||||
|
||||
func applicationSupportsSecureRestorableState(_: NSApplication) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
|
||||
public func continueTransmission(accept: Bool, transferID: String, storeInTemp: Bool = false) {
|
||||
NearbyConnectionManager.shared.submitUserConsent(transferID: transferID, accept: accept, storeInTemp: storeInTemp)
|
||||
|
||||
|
||||
if !accept {
|
||||
activeIncomingTransfers.removeValue(forKey: transferID)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func obtainUserConsent(for transfer: TransferMetadata, from device: RemoteDeviceInfo) {
|
||||
self.activeIncomingTransfers[transfer.id] = TransferInfo(device: device, transfer: transfer)
|
||||
|
||||
activeIncomingTransfers[transfer.id] = TransferInfo(device: device, transfer: transfer)
|
||||
|
||||
AudioManager.playSound()
|
||||
|
||||
|
||||
let acceptAutomatically = UserDefaults.standard.bool(forKey: UserDefaultsKeys.automaticallyAcceptFiles.rawValue)
|
||||
|
||||
|
||||
let fileStr: String
|
||||
|
||||
|
||||
if let textTitle = transfer.textDescription {
|
||||
fileStr = textTitle
|
||||
} else if transfer.files.count == 1 {
|
||||
@@ -305,45 +283,43 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
} else {
|
||||
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 pinCodeMessage = String(format:NSLocalizedString("PinCode", value: "PIN: %@", comment: ""), arguments: [transfer.pinCode ?? "?"])
|
||||
let pinCodeMessage = String(format: NSLocalizedString("PinCode", value: "PIN: %@", comment: ""), arguments: [transfer.pinCode ?? "?"])
|
||||
let transferID = transfer.id
|
||||
|
||||
|
||||
|
||||
if acceptAutomatically {
|
||||
pressAcceptButton(transferID: transfer.id)
|
||||
|
||||
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, err in
|
||||
|
||||
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, _ in
|
||||
if granted {
|
||||
log("User granted notification permissions")
|
||||
|
||||
|
||||
let notificationContent = UNMutableNotificationContent()
|
||||
notificationContent.title = "QuickDrop"
|
||||
notificationContent.body = mainMessage
|
||||
notificationContent.sound = nil
|
||||
let notificationId = UUID().uuidString
|
||||
|
||||
|
||||
let notificationReq = UNNotificationRequest(identifier: notificationId, content: notificationContent, trigger: nil)
|
||||
UNUserNotificationCenter.current().add(notificationReq)
|
||||
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
|
||||
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [notificationId])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
let alert = NSAlert()
|
||||
alert.alertStyle = .informational
|
||||
|
||||
|
||||
alert.messageText = "QuickDrop - \(pinCodeMessage)"
|
||||
alert.informativeText = mainMessage
|
||||
alert.addButton(withTitle: NSLocalizedString("Accept", comment: ""))
|
||||
alert.addButton(withTitle: NSLocalizedString("Decline", comment: ""))
|
||||
|
||||
|
||||
let result = alert.runModal()
|
||||
|
||||
|
||||
if result == .alertFirstButtonReturn {
|
||||
pressAcceptButton(transferID: transferID)
|
||||
} else if result == .alertSecondButtonReturn {
|
||||
@@ -351,38 +327,32 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private func pressAcceptButton(transferID: String) {
|
||||
if false || (!isPlusVersion() && transmissionCount() > 1) {
|
||||
|
||||
self.continueTransmission(accept: true, transferID: transferID, storeInTemp: true)
|
||||
continueTransmission(accept: true, transferID: transferID, storeInTemp: true)
|
||||
log("Showing plus screen...")
|
||||
|
||||
self.openPlusScreen()
|
||||
}
|
||||
else {
|
||||
|
||||
openPlusScreen()
|
||||
} else {
|
||||
continueTransmission(accept: true, transferID: transferID)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func showFirewallAlert() {
|
||||
openAlert(type: .Firewall)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func incomingTransfer(id: String, didFinishWith error: Error?) {
|
||||
guard let transfer = self.activeIncomingTransfers[id] else { return }
|
||||
guard let transfer = activeIncomingTransfers[id] else { return }
|
||||
if let error = error {
|
||||
|
||||
var description = ""
|
||||
|
||||
if let ne = (error as? NearbyError){
|
||||
|
||||
if let ne = (error as? NearbyError) {
|
||||
switch ne {
|
||||
case .inputOutput:
|
||||
description = "I/O Error";
|
||||
case .protocolError(_):
|
||||
description = "I/O Error"
|
||||
case .protocolError:
|
||||
description = NSLocalizedString("Error.Protocol", value: "Communication error", comment: "") + "(\(ne.localizedDescription))"
|
||||
case .packetFilterError:
|
||||
openAlert(type: .NetworkFilter)
|
||||
@@ -398,46 +368,44 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
} else {
|
||||
description = error.localizedDescription
|
||||
}
|
||||
|
||||
|
||||
let alert = NSAlert()
|
||||
alert.alertStyle = .critical
|
||||
|
||||
alert.messageText = String(format: NSLocalizedString("TransferError", value: "Failed to receive files from %@", comment: ""), arguments: [transfer.device.name])
|
||||
alert.informativeText = description
|
||||
|
||||
|
||||
alert.addButton(withTitle: "InformDeveloper".localized())
|
||||
alert.addButton(withTitle: "CloseAlert".localized())
|
||||
|
||||
|
||||
if let plusWindow = plusWindow {
|
||||
log("Closing plus screen because of error")
|
||||
plusWindow.close()
|
||||
}
|
||||
|
||||
|
||||
log("Showing alert with message: \"\(alert.messageText)\" and description: \"\(alert.informativeText)\"")
|
||||
|
||||
|
||||
let result = alert.runModal()
|
||||
|
||||
|
||||
if result == .alertFirstButtonReturn {
|
||||
sendLoggingString()
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
let currentCount = transmissionCount()
|
||||
|
||||
|
||||
if currentCount % 20 == 0 {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
SKStoreReviewController.requestReview()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UserDefaults.standard.set(currentCount + 1, forKey: UserDefaultsKeys.transmissionCount.rawValue)
|
||||
}
|
||||
|
||||
self.activeIncomingTransfers.removeValue(forKey: id)
|
||||
|
||||
activeIncomingTransfers.removeValue(forKey: id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct TransferInfo {
|
||||
let device: RemoteDeviceInfo
|
||||
let transfer: TransferMetadata
|
||||
|
||||
Reference in new issue
Block a user