New Alert for receiving files, rename to QuickDrop

This commit is contained in:
Leon Böttger committed 2025-03-01 16:06:08 +01:00
1 parent 79b359fb64
commit 4929a96134
71 files changed
+1521 -413

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 51 KiB

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>backingScale</key>
<real>1</real>
<key>mode</key>
<integer>0</integer>
<key>shapeSelectionFilename</key>
<string>shapeSelection</string>
<key>size</key>
<data>
NC10UHpTVFAQAAAAQGHAAAAAAABALAAAAAAAAA==
</data>
<key>softness</key>
<real>0.0</real>
<key>timestamp</key>
<real>762463132.862221</real>
<key>transform</key>
<array>
<real>1</real>
<real>0.0</real>
<real>0.0</real>
<real>1.2142857142857142</real>
<real>0.0</real>
<real>-271.07142857142844</real>
<real>0.0</real>
<real>0.0</real>
</array>
<key>version</key>
<integer>2</integer>
</dict>
</plist>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>backingScale</key>
<real>1</real>
<key>pathFilename</key>
<string>path</string>
<key>version</key>
<integer>1</integer>
</dict>
</plist>
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.
Binary file not shown.
+147
View File
@@ -0,0 +1,147 @@
//
// Logger.swift
// QuickDrop
//
// Created by Leon Böttger on 26.02.25.
//
import Foundation
import os
fileprivate let loggerQueue = DispatchQueue(label: "loggerQueue")
/// Manages logging functionality
final class LogManager {
/// The URL of the log file
let logFileURL: URL?
/// The private initializer
private init() {
/// Get documents directory
let directory = getDocumentsDirectory()
/// Create file name from date
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-yyyy"
let dateString = formatter.string(from: Date())
let fileName = "\(dateString).log"
/// Create file URL from file name
self.logFileURL = directory.appendingPathComponent(fileName)
}
/// The shared instance.
public static let sharedInstance = LogManager()
@Published var loggingEnabled = true
/// Writes a specified string to the log file.
func writeToFile(string: String) {
/// Make sure the URL is not nil
guard let logFileURL = logFileURL else {
return
}
/// Get current timestamp
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss"
let timestamp = formatter.string(from: Date())
/// Create data from string and timestamp
guard let data = (timestamp + " - " + string + "\n").data(using: .utf8) else { return }
/// a log file exists already
if FileManager.default.fileExists(atPath: logFileURL.path) {
/// we try to get a handle to write to the log file
if let file = try? FileHandle(forWritingTo: logFileURL) {
/// go to end of file
file.seekToEndOfFile()
/// write string to end
file.write(data)
///close file
file.closeFile()
}
} else {
/// Clean up older logs
deleteLogs()
/// create new log file
try? data.write(to: logFileURL, options: .atomicWrite)
}
}
func getLogString() -> String {
if let logFileURL = logFileURL {
let fileURL = URL(fileURLWithPath: logFileURL.path)
do {
let content = try String(contentsOf: fileURL, encoding: .utf8)
return String(content.suffix(10000))
} catch {
log("[LUI] Error reading file: \(error.localizedDescription)")
}
}
return ""
}
/// Deletes all log files.
func deleteLogs() {
log("[LUI] Deleting all logs...")
let fileManager = FileManager.default
let documentsDirectory = getDocumentsDirectory()
guard let allFiles = try? fileManager.contentsOfDirectory(at: documentsDirectory, includingPropertiesForKeys: nil) else {
return
}
let logFiles = allFiles.filter { $0.pathExtension.elementsEqual("log") }
for file in logFiles {
do {
log("[LUI] Removing \(file.description)")
try fileManager.removeItem(at: file)
} catch {
print(error.localizedDescription)
}
}
}
}
/// Logs a specified string.
public func log(_ text: String) {
let logger = LogManager.sharedInstance
if logger.loggingEnabled {
loggerQueue.async {
print(text)
// Weird bug?
#if !os(tvOS)
logger.writeToFile(string: text)
#endif
}
}
}
/// Returns the URL of the documents directory.
func getDocumentsDirectory() -> URL {
return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
}
+181 -104
View File
@@ -1,6 +1,6 @@
//
// AppDelegate.swift
// NearDrop
// QuickDrop
//
// Created by Grishka on 08.04.2023.
//
@@ -12,11 +12,13 @@ import SwiftUI
import StoreKit
@main
class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDelegate, MainAppDelegate{
class AppDelegate: NSObject, NSApplicationDelegate, MainAppDelegate{
private var statusItem:NSStatusItem?
private var activeIncomingTransfers:[String:TransferInfo]=[:]
var window: NSWindow?
var welcomeWindow: NSWindow?
var plusWindow: NSWindow?
private var iapManager: IAPManager?
func applicationDidFinishLaunching(_ aNotification: Notification) {
let menu=NSMenu()
@@ -24,9 +26,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
menu.addItem(withTitle: String(format: NSLocalizedString("DeviceName", value: "Device name: %@", comment: ""), arguments: [Host.current().localizedName!]), action: nil, keyEquivalent: "")
menu.addItem(NSMenuItem.separator())
// Add "Recommended Apps" menu item
let recommendedAppsItem = NSMenuItem(title: NSLocalizedString("RecommendedApps", value: "Recommended Apps", comment: ""), action: #selector(openRecommendedApps), keyEquivalent: "")
menu.addItem(recommendedAppsItem)
// // Add "Recommended Apps" menu item
// let recommendedAppsItem = NSMenuItem(title: NSLocalizedString("RecommendedApps", value: "Recommended Apps", comment: ""), action: #selector(openRecommendedApps), keyEquivalent: "")
// menu.addItem(recommendedAppsItem)
// Add "Privacy Policy" menu item
let privacyPolicyItem = NSMenuItem(title: NSLocalizedString("PrivacyPolicy", value: "Privacy Policy", comment: ""), action: #selector(openPrivacyPolicy), keyEquivalent: "")
@@ -37,7 +39,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
let userManualItem = NSMenuItem(title: NSLocalizedString("UserManual", value: "User Manual", comment: ""), action: #selector(openWelcomeScreen), keyEquivalent: "")
menu.addItem(userManualItem)
menu.addItem(withTitle: NSLocalizedString("Quit", value: "Quit NearDrop", comment: ""), action: #selector(NSApplication.terminate(_:)), keyEquivalent: "")
menu.addItem(withTitle: NSLocalizedString("Quit", value: "Quit QuickDrop", comment: ""), action: #selector(NSApplication.terminate(_:)), keyEquivalent: "")
statusItem=NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
@@ -45,50 +47,101 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
statusItem?.menu=menu
statusItem?.behavior = .removalAllowed
let nc=UNUserNotificationCenter.current()
nc.requestAuthorization(options: [.alert, .sound]) { granted, err in
if !granted{
DispatchQueue.main.async {
self.showNotificationsDeniedAlert()
}
}
}
nc.delegate=self
let incomingTransfersCategory=UNNotificationCategory(identifier: "INCOMING_TRANSFERS", actions: [
UNNotificationAction(identifier: "ACCEPT", title: NSLocalizedString("Accept", comment: ""), options: UNNotificationActionOptions.authenticationRequired)
], intentIdentifiers: [])
let errorsCategory=UNNotificationCategory(identifier: "ERRORS", actions: [], intentIdentifiers: [])
nc.setNotificationCategories([incomingTransfersCategory, errorsCategory])
NearbyConnectionManager.shared.mainAppDelegate=self
NearbyConnectionManager.shared.becomeVisible()
if !UserDefaults.standard.bool(forKey: "ShowedWelcomeScreen"){
iapManager = IAPManager.sharedInstance
iapManager?.startObserving()
// app did not lauch before
if !UserDefaults.standard.bool(forKey: UserDefaultsKeys.appLaunchedBefore.rawValue){
log("Opening welcome screen")
// open welcome screen
openWelcomeScreen()
UserDefaults.standard.set(true, forKey: "ShowedWelcomeScreen")
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 {
// 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 plus version for old user")
UserDefaults.standard.set(true, forKey: UserDefaultsKeys.plusVersion.rawValue)
}
else {
if !isPlusVersion() {
log("New user - plus version cannot be granted")
}
}
}
}
@objc func openWelcomeScreen() {
// Create the welcome screen SwiftUI view
let welcomeView = WelcomeScreen()
let welcomeView = WelcomeScreen {
self.openPlusScreen(continueTransfer: {})
}
// Create an NSWindow to host the SwiftUI view
window = NSWindow(
welcomeWindow = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 400, height: 300),
styleMask: [.titled, .closable],
backing: .buffered,
defer: false
)
window?.center()
window?.isReleasedWhenClosed = false
window?.setFrameAutosaveName("WelcomeScreen")
window?.contentView = NSHostingView(rootView: welcomeView)
welcomeWindow?.center()
welcomeWindow?.isReleasedWhenClosed = false
welcomeWindow?.setFrameAutosaveName("WelcomeScreen")
welcomeWindow?.contentView = NSHostingView(rootView: welcomeView)
welcomeWindow?.isOpaque = false
welcomeWindow?.backgroundColor = .clear
// Ensure the window is always on top
window?.level = .floating
NSApp.activate(ignoringOtherApps: true) // Brings the whole app to the front
welcomeWindow?.makeKeyAndOrderFront(nil)
welcomeWindow?.level = .normal
}
@objc func openPlusScreen(continueTransfer: @escaping () -> Void) {
// Create the welcome screen SwiftUI view
let plusView = GetPlusView(closeView: {
self.plusWindow?.close()
continueTransfer()
})
window?.makeKeyAndOrderFront(nil)
// Create an NSWindow to host the SwiftUI view
plusWindow = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 400, height: 300),
styleMask: [.titled, .closable],
backing: .buffered,
defer: false
)
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
}
func isPlusVersion() -> Bool {
return UserDefaults.standard.bool(forKey: UserDefaultsKeys.plusVersion.rawValue)
}
func transmissionCount() -> Int {
return UserDefaults.standard.integer(forKey: UserDefaultsKeys.transmissionCount.rawValue)
}
@@ -113,106 +166,130 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
func applicationWillTerminate(_ aNotification: Notification) {
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
iapManager?.stopObserving()
}
func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
func showNotificationsDeniedAlert(){
let alert=NSAlert()
alert.alertStyle = .critical
alert.messageText=NSLocalizedString("NotificationsDenied.Title", value: "Notification Permission Required", comment: "")
alert.informativeText=NSLocalizedString("NotificationsDenied.Message", value: "NearDrop needs to be able to display notifications for incoming file transfers. Please allow notifications in System Settings.", comment: "")
alert.addButton(withTitle: NSLocalizedString("NotificationsDenied.OpenSettings", value: "Open settings", comment: ""))
alert.addButton(withTitle: NSLocalizedString("Quit", value: "Quit NearDrop", comment: ""))
let result=alert.runModal()
if result==NSApplication.ModalResponse.alertFirstButtonReturn{
NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.preference.notifications")!)
}else if result==NSApplication.ModalResponse.alertSecondButtonReturn{
NSApplication.shared.terminate(nil)
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let transferID=response.notification.request.content.userInfo["transferID"]! as! String
NearbyConnectionManager.shared.submitUserConsent(transferID: transferID, accept: response.actionIdentifier=="ACCEPT")
if response.actionIdentifier != "ACCEPT"{
public func continueTransmission(accept: Bool, transferID: String) {
NearbyConnectionManager.shared.submitUserConsent(transferID: transferID, accept: accept)
if !accept {
activeIncomingTransfers.removeValue(forKey: transferID)
}
completionHandler()
}
public func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.sound, .banner])
}
func obtainUserConsent(for transfer: TransferMetadata, from device: RemoteDeviceInfo) {
let fileStr:String
if let textTitle=transfer.textDescription{
fileStr=textTitle
}else if transfer.files.count==1{
fileStr=transfer.files[0].name
}else{
fileStr=String.localizedStringWithFormat(NSLocalizedString("NFiles", value: "%d files", comment: ""), transfer.files.count)
self.activeIncomingTransfers[transfer.id] = TransferInfo(device: device, transfer: transfer)
NSSound(named: NSSound.Name("NSUserNotificationDefaultSoundName"))?.play()
let alert = NSAlert()
alert.alertStyle = .informational
let fileStr: String
if let textTitle = transfer.textDescription{
fileStr = textTitle
} else if transfer.files.count == 1 {
fileStr = transfer.files[0].name
} else {
fileStr = String.localizedStringWithFormat(NSLocalizedString("NFiles", value: "%d files", comment: ""), transfer.files.count)
}
let notificationContent=UNMutableNotificationContent()
notificationContent.title="NearDrop"
notificationContent.subtitle=String(format:NSLocalizedString("PinCode", value: "PIN: %@", comment: ""), arguments: [transfer.pinCode!])
notificationContent.body=String(format: NSLocalizedString("DeviceSendingFiles", value: "%1$@ is sending you %2$@", comment: ""), arguments: [device.name, fileStr])
notificationContent.sound = .default
notificationContent.categoryIdentifier="INCOMING_TRANSFERS"
notificationContent.userInfo=["transferID": transfer.id]
if #available(macOS 11.0, *){
NDNotificationCenterHackery.removeDefaultAction(notificationContent)
let mainMessage = String(format: NSLocalizedString("DeviceSendingFiles", value: "%1$@ is sending you %2$@", comment: ""), arguments: [device.name, fileStr])
let pinCodeMessage = String(format:NSLocalizedString("PinCode", value: "PIN: %@", comment: ""), arguments: [transfer.pinCode!])
let transferID = transfer.id
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 {
if !isPlusVersion() && transmissionCount() > 0 {
self.openPlusScreen {
self.continueTransmission(accept: self.isPlusVersion(), transferID: transferID)
}
}
else {
continueTransmission(accept: true, transferID: transferID)
}
} else if result == .alertSecondButtonReturn {
continueTransmission(accept: false, transferID: transferID)
}
let notificationReq=UNNotificationRequest(identifier: "transfer_"+transfer.id, content: notificationContent, trigger: nil)
UNUserNotificationCenter.current().add(notificationReq)
self.activeIncomingTransfers[transfer.id]=TransferInfo(device: device, transfer: transfer)
}
func incomingTransfer(id: String, didFinishWith error: Error?) {
guard let transfer=self.activeIncomingTransfers[id] else {return}
if let error=error{
let notificationContent=UNMutableNotificationContent()
notificationContent.title=String(format: NSLocalizedString("TransferError", value: "Failed to receive files from %@", comment: ""), arguments: [transfer.device.name])
if let ne=(error as? NearbyError){
switch ne{
guard let transfer = self.activeIncomingTransfers[id] else { return }
if let error = error {
let alert = NSAlert()
alert.alertStyle = .critical
alert.messageText = String(format: NSLocalizedString("TransferError", value: "Failed to receive files from %@", comment: ""), arguments: [transfer.device.name])
var description = ""
if let ne = (error as? NearbyError){
switch ne {
case .inputOutput:
notificationContent.body="I/O Error";
description = "I/O Error";
case .protocolError(_):
notificationContent.body=NSLocalizedString("Error.Protocol", value: "Communication error", comment: "")
description = NSLocalizedString("Error.Protocol", value: "Communication error", comment: "")
case .requiredFieldMissing:
notificationContent.body=NSLocalizedString("Error.Protocol", value: "Communication error", comment: "")
description = NSLocalizedString("Error.Protocol", value: "Communication error", comment: "")
case .ukey2:
notificationContent.body=NSLocalizedString("Error.Crypto", value: "Encryption error", comment: "")
description = NSLocalizedString("Error.Crypto", value: "Encryption error", comment: "")
case .canceled(reason: _):
break; // can't happen for incoming transfers
}
}else{
notificationContent.body=error.localizedDescription
} else {
description = error.localizedDescription
}
notificationContent.categoryIdentifier="ERRORS"
UNUserNotificationCenter.current().add(UNNotificationRequest(identifier: "transferError_"+id, content: notificationContent, trigger: nil))
alert.informativeText = description
let _ = alert.runModal()
}
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: ["transfer_"+id])
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)
let currentCount = UserDefaults.standard.integer(forKey: "reviewRequestCountKey")
if currentCount % 20 == 0 {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
SKStoreReviewController.requestReview()
}
}
UserDefaults.standard.set(currentCount + 1, forKey: "reviewRequestCountKey")
}
}
struct TransferInfo{
let device:RemoteDeviceInfo
let transfer:TransferMetadata
struct TransferInfo {
let device: RemoteDeviceInfo
let transfer: TransferMetadata
}
class WindowDelegate: NSObject, NSWindowDelegate {
let willClose: () -> Void
init(willClose: @escaping () -> Void) {
self.willClose = willClose
}
func windowWillClose(_ notification: Notification) {
print("Window closed!")
// Perform any cleanup or state updates here
willClose()
}
}
@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.200",
"green" : "0.200",
"red" : "0.200"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

+22 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d files";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDrop needs to be able to display notifications for incoming file transfers. Please allow notifications in System Settings.";
"NotificationsDenied.Message" = "QuickDrop needs to be able to display notifications for incoming file transfers. Please allow notifications in System Settings.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "Open settings";
@@ -32,7 +32,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "Quit NearDrop";
"Quit" = "Close QuickDrop";
/* No comment provided by engineer. */
"TransferError" = "Failed to receive files from %@";
@@ -40,20 +40,38 @@
/* No comment provided by engineer. */
"VisibleToEveryone" = "Visible to everyone";
"WelcomeToNearDrop" = "Welcome to NearDrop";
"WelcomeToQuickDrop" = "Welcome to QuickDrop";
"Acknowledgements" = "Acknowledgements";
"SupportQuickDrop" = "Support QuickDrop";
"RecommendedApps" = "Recommended Apps";
"PrivacyPolicy" = "Privacy Policy";
"UserManual" = "User Manual";
"UserManualDescription" = "When NearDrop is running, it will appear in the menu bar at the top of your screen. Click the NearDrop icon if you would like to stop receiving files.
"UserManualDescription" = "When QuickDrop is running, it will appear in the menu bar at the top of your screen. Click the QuickDrop icon if you would like to stop receiving files.
Important: Your Android device and your Mac need to be on the same WiFi network to transfer files. If you are promted to allow incoming connections, please allow them.
To send files from your Android device to your Mac, tap on the share icon on your phone, and select \"Quick Share\" or \"Nearby Share\". Your Mac will be listed as an available device.
After that, you will see a notification on your Mac. Hover over the notification to accept or decline the file transfer.";
"plusview_title" = "Thanks for using QuickDrop!";
"plusview_description" = "Unlock QuickDrop+ to continue receiving files. QuickDrop+ is a one-time purchase – you can keep the app forever, no subscription required.";
"plusview_success_title" = "Thanks for your purchase!";
"plusview_success_description" = "You can now continue receiving files without restrictions.";
"plusview_success_button" = "Got it!";
"plusview_unlock_label" = "Support QuickDrop";
"plusview_restorepurchase" = "Already bought?";
"plusview_restorefailed" = "There was a problem restoring your purchase";
"plusview_restorefailed_proceed" = "Okay";
"plusview_purchasefailed" = "Purchase failed";
"plusview_purchasefaileddescription" = "If this message appeared unexpectedly, please make sure that you are connected to the Internet and In-App-Purchases are enabled for your device and then try again.";
"plusview_nothingtorestore" = "There is nothing to restore!";
"plusview_productRequestFailed" = "Unable to fetch In-App Purchases at the moment.";
+245
View File
@@ -0,0 +1,245 @@
//
// GetPlusView.swift
// QuickDrop
//
// Created by Leon Böttger on 23.02.25.
//
import SwiftUI
import StoreKit
struct GetPlusView: View {
@AppStorage(UserDefaultsKeys.plusVersion.rawValue) var isPlusVersion = false
@ObservedObject private var iaphelper = IAPManager.sharedInstance
let closeView: () -> Void
@State private var restoring = false
@State private var showRestoreError = false
@State private var restoreError = ""
@Environment(\.colorScheme) var colorScheme
@State var products = [SKProduct]()
@State var price: String = ""
@State var warning = false
@State var buying = false
@State var errorText = ""
@State var boughtSuccessAlert = false
var body: some View {
ZStack {
Color.defaultBackground
.edgesIgnoringSafeArea(.all)
let validPrice = price != ""
VStack(spacing: 12) {
Text("plusview_title")
.font(.title)
.bold()
Text("plusview_description")
.multilineTextAlignment(.center)
.padding()
.padding(.top, -10)
.alert(isPresented: $boughtSuccessAlert, content: {
Alert(title: Text("plusview_success_title"), message: Text("plusview_success_description"), dismissButton: .default(Text("plusview_success_button"), action: {
closeView()
}))
})
HStack(spacing: 10) {
Button("plusview_restorepurchase") {
restorePurchases()
}
.keyboardShortcut(.cancelAction)
.alert(isPresented: $showRestoreError, content: {
Alert(title: Text("plusview_restorefailed"), message: Text(restoreError), dismissButton: .default(Text("plusview_restorefailed_proceed")))
})
.opacity(restoring ? 0 : 1)
.overlay(
ProgressView()
.scaleEffect(0.5)
.opacity(restoring ? 1 : 0)
)
let priceString = validPrice ? " (\(price))" : ""
Button("plusview_unlock_label".localized() + priceString) {
buttonAction()
}
.keyboardShortcut(.defaultAction)
.alert(isPresented: $warning, content: {
Alert(title: Text("plusview_purchasefailed"), message: Text("plusview_purchasefaileddescription".localized() + (errorText != "" ? " Error: " : "") + errorText), dismissButton: .default(Text("plusview_restorefailed_proceed")))
})
}
.opacity(buying || restoring ? 0 : 1)
.overlay(
ProgressView()
.scaleEffect(0.5)
.opacity(buying || restoring ? 1 : 0)
)
}
.onAppear {
loadProducts(shouldBuy: false)
}
.animation(.default, value: validPrice)
.padding()
}
.frame(width: 400, height: 200)
}
func restorePurchases() {
withAnimation {
restoring = true
}
iaphelper.restorePurchases { result in
DispatchQueue.main.async {
switch result {
case .success(let success):
if success {
withAnimation {
isPlusVersion = true
}
boughtSuccessAlert = true
} else {
//nothing to restore
restoreFailed(message: "plusview_nothingtorestore")
}
case .failure(let error):
log(error.localizedDescription)
restoreFailed(message: error.localizedDescription)
}
}
}
func restoreFailed(message: String) {
#if targetEnvironment(simulator)
isPlusVersion = true
dismissView()
#else
// now, try to convert from old version
IAPConverter.shared.restoreIAPfromPreviousPurchase { success in
DispatchQueue.main.async {
if success {
withAnimation {
isPlusVersion = true
}
boughtSuccessAlert = true
}
else {
restoreError = message
showRestoreError = true
withAnimation {
restoring = false
}
}
}
}
#endif
}
}
func buttonAction() {
if let product = products.first {
purchase(product: product)
}
else {
loadProducts(shouldBuy: true)
}
}
func purchase(product: SKProduct) {
if !iaphelper.canMakePayments() {
warning = true
} else {
withAnimation{
buying = true
}
iaphelper.buy(product: product) { (result) in
DispatchQueue.main.async {
withAnimation{
buying = false
}
switch result {
case .success(_):
withAnimation {
isPlusVersion = true
boughtSuccessAlert = true
warning = false
}
case .failure(let error):
warning = true
errorText = error.localizedDescription
}
}
}
}
}
func loadProducts(shouldBuy: Bool) {
iaphelper.getProducts { (result) in
DispatchQueue.main.async {
switch result {
case .success(let products):
self.products = products
price = products.first?.localizedPrice ?? ""
if let product = products.first, shouldBuy {
purchase(product: product)
}
case .failure(let error):
errorText = error.localizedDescription
if(shouldBuy){
warning = true
}
withAnimation{
buying = false
}
}
}
}
}
}
extension SKProduct {
var localizedPrice: String {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = priceLocale
if let price = formatter.string(from: price) {
return price
}
return ""
}
}
#Preview {
GetPlusView(closeView: {})
}
+66
View File
@@ -0,0 +1,66 @@
//
// StoreChecker.swift
// LUI
//
// Created by Leon Böttger on 19.08.24.
//
import StoreKit
class IAPConverter: NSObject, SKRequestDelegate {
let switchToIAPAfterBundleVersion = "6"
static let shared = IAPConverter()
private override init() {
super.init()
}
func restoreIAPfromPreviousPurchase(success: ((Bool) -> ())? = nil) {
Task {
do {
// Get the appTransaction.
if #available(macOS 13.0, *) {
let shared = try await AppTransaction.shared
if case .verified(let appTransaction) = shared {
let originalVersion = appTransaction.originalAppVersion
let newModelVersion = switchToIAPAfterBundleVersion
log("[LUI] Original Purchased Version: \(originalVersion) | New Model Version: \(newModelVersion)")
if originalVersion.compare(newModelVersion, options: .numeric) == .orderedAscending {
grant(success: success)
return
}
}
} else {
// Fallback on earlier versions
// Grant IAP, as we cannot check the original purchase date.
DispatchQueue.main.async {
log("[LUI] Cannot check version - Plus Version Granted!")
success?(true)
}
}
}
catch {
// Handle errors.
log("[LUI] Error: \(error.localizedDescription)")
}
DispatchQueue.main.async {
log("[LUI] Plus Version Denied!")
success?(false)
}
}
}
private func grant(success: ((Bool) -> ())? = nil) {
log("[LUI] Existing User - Plus Version Granted!")
DispatchQueue.main.async {
success?(true)
}
}
}
+195
View File
@@ -0,0 +1,195 @@
//
// PurchaseHelper.swift
// Loop
//
// Created by Leon Böttger on 26.10.20.
// Copyright © 2020 Leon Böttger. All rights reserved.
//
import StoreKit
let iapName = "plusversion"
class IAPManager: NSObject, ObservableObject {
enum IAPManagerError: Error {
case noProductIDsFound
case noProductsFound
case paymentWasCancelled
case productRequestFailed
}
static let plusVersionID = iapName
static let sharedInstance = IAPManager()
var onReceiveProductsHandler: ((Result<[SKProduct], IAPManagerError>) -> Void)?
var onBuyProductHandler: ((Result<Bool, Error>) -> Void)?
var totalRestoredPurchases = 0
var isActive = false
private override init() {
super.init()
getProducts { _ in }
}
fileprivate func getProductIDs() -> [String]? {
return [IAPManager.plusVersionID]
}
func startObserving() {
SKPaymentQueue.default().add(self)
}
func stopObserving() {
SKPaymentQueue.default().remove(self)
}
func canMakePayments() -> Bool {
return SKPaymentQueue.canMakePayments()
}
func getProducts(withHandler productsReceiveHandler: @escaping (_ result: Result<[SKProduct], IAPManagerError>) -> Void) {
// Keep the handler (closure) that will be called when requesting for
// products on the App Store is finished.
onReceiveProductsHandler = productsReceiveHandler
// Get the product identifiers.
guard let productIDs = getProductIDs() else {
productsReceiveHandler(.failure(.noProductIDsFound))
return
}
// Initialize a product request.
let request = SKProductsRequest(productIdentifiers: Set(productIDs))
// Set self as the its delegate.
request.delegate = self
// Make the request.
request.start()
}
func buy(product: SKProduct, withHandler handler: @escaping ((_ result: Result<Bool, Error>) -> Void)) {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
// Keep the completion handler.
onBuyProductHandler = handler
}
func restorePurchases(withHandler handler: @escaping ((_ result: Result<Bool, Error>) -> Void)) {
onBuyProductHandler = handler
totalRestoredPurchases = 0
SKPaymentQueue.default().restoreCompletedTransactions()
}
}
extension IAPManager: SKPaymentTransactionObserver {
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
transactions.forEach { (transaction) in
switch transaction.transactionState {
case .purchased:
onBuyProductHandler?(.success(true))
SKPaymentQueue.default().finishTransaction(transaction)
case .restored:
totalRestoredPurchases += 1
onBuyProductHandler?(.success(true))
SKPaymentQueue.default().finishTransaction(transaction)
case .failed:
log("[LUI] IAP failed")
if let error = transaction.error as? SKError {
if error.code != .paymentCancelled {
onBuyProductHandler?(.failure(error))
} else {
onBuyProductHandler?(.failure(IAPManagerError.paymentWasCancelled))
}
log("[LUI] IAP Error:" + error.localizedDescription)
}
onBuyProductHandler?(.failure(transaction.error ?? IAPManagerError.productRequestFailed))
SKPaymentQueue.default().finishTransaction(transaction)
case .deferred, .purchasing: log("[LUI] other cases")
@unknown default: log("[LUI] other default cases")
}
}
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
if totalRestoredPurchases != 0 {
onBuyProductHandler?(.success(true))
} else {
log("[LUI] IAP: No purchases to restore!")
onBuyProductHandler?(.success(false))
}
}
func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
if let error = error as? SKError {
if error.code != .paymentCancelled {
log("[LUI] IAP Restore Error:" + error.localizedDescription)
onBuyProductHandler?(.failure(error))
} else {
onBuyProductHandler?(.failure(IAPManagerError.paymentWasCancelled))
}
}
}
}
extension IAPManager: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
// Get the available products contained in the response.
let products = response.products
// Check if there are any products available.
if products.count > 0 {
// Call the following handler passing the received products.
onReceiveProductsHandler?(.success(products))
} else {
// No products were found.
onReceiveProductsHandler?(.failure(.noProductsFound))
}
}
func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool {
return true
}
func request(_ request: SKRequest, didFailWithError error: Error) {
onReceiveProductsHandler?(.failure(.productRequestFailed))
}
func requestDidFinish(_ request: SKRequest) {
// Implement this method OPTIONALLY and add any custom logic
// you want to apply when a product request is finished.
}
}
extension IAPManager.IAPManagerError: LocalizedError {
var errorDescription: String? {
switch self {
case .noProductIDsFound: return "No In-App Purchase product identifiers were found."
case .noProductsFound: return "No In-App Purchases were found."
case .productRequestFailed: return "plusview_productRequestFailed".localized()
case .paymentWasCancelled: return "In-App Purchase process was cancelled."
}
}
}
public extension String {
func localized() -> String {
let localizedString = NSLocalizedString(self, comment: "")
return localizedString
}
}
-19
View File
@@ -1,19 +0,0 @@
//
// NDNotificationCenterHackery.h
// NearDrop
//
// Created by Grishka on 10.04.2023.
//
#import <Foundation/Foundation.h>
#import <UserNotifications/UserNotifications.h>
NS_ASSUME_NONNULL_BEGIN
@interface NDNotificationCenterHackery : NSObject
+ (void)removeDefaultAction:(UNMutableNotificationContent*) content;
@end
NS_ASSUME_NONNULL_END
-42
View File
@@ -1,42 +0,0 @@
//
// NDNotificationCenterHackery.m
// NearDrop
//
// Created by Grishka on 10.04.2023.
//
#import <UserNotifications/UserNotifications.h>
#import <AppKit/AppKit.h>
#import "NDNotificationCenterHackery.h"
@interface UNMutableNotificationCategory : UNNotificationCategory
@property(copy) NSString *actionsMenuTitle;
@property(copy) UNNotificationAction *alternateAction;
@property(copy) NSArray *minimalActions;
@property unsigned long long backgroundStyle;
@property(copy) NSArray *actions;
@end
@interface UNNotificationIcon : NSObject
+ (id)iconForApplicationIdentifier:(id)arg1;
+ (id)iconAtPath:(id)arg1;
+ (id)iconNamed:(id)arg1;
@end
@interface UNMutableNotificationContent (NDPrivateAPIs)
@property BOOL hasDefaultAction;
@property(copy) NSString *defaultActionTitle;
@property(copy) NSString *header;
@property (assign,nonatomic) BOOL shouldDisplayActionsInline;
@property (assign,nonatomic) BOOL shouldShowSubordinateIcon;
@property (nonatomic,copy) NSString * accessoryImageName;
@property(copy) UNNotificationIcon *icon;
@end
@implementation NDNotificationCenterHackery
+ (void)removeDefaultAction:(UNMutableNotificationContent*) content{
content.hasDefaultAction=false;
}
@end
-5
View File
@@ -1,5 +0,0 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "NDNotificationCenterHackery.h"
+15
View File
@@ -0,0 +1,15 @@
//
// UserDefaultKeys.swift
// QuickDrop
//
// Created by Leon Böttger on 26.02.25.
//
import Foundation
enum UserDefaultsKeys: String, CaseIterable {
case isEligibleForIap = "isEligibleForIap"
case appLaunchedBefore = "ShowedWelcomeScreen"
case plusVersion = "isPlusVersion"
case transmissionCount = "reviewRequestCountKey"
}
+104 -19
View File
@@ -1,6 +1,6 @@
//
// WelcomeScreen.swift
// NearDrop
// QuickDrop
//
// Created by Leon Böttger on 03.01.25.
//
@@ -10,9 +10,18 @@ import SwiftUI
struct WelcomeScreen: View {
@State private var newWindow: NSWindow? // Retain the NSWindow object
@AppStorage(UserDefaultsKeys.plusVersion.rawValue) var isPlusVersion = false
@Environment(\.colorScheme) var colorScheme
@State var taps = 0
let openIAP: () -> Void
var body: some View {
ZStack {
Color.defaultBackground
.edgesIgnoringSafeArea(.all)
ScrollView {
VStack {
@@ -20,8 +29,18 @@ struct WelcomeScreen: View {
.resizable()
.frame(width: 150, height: 150)
.padding(.top, 50)
.onTapGesture {
taps += 1
print("Tapped \(taps) times")
if taps == 5 {
let logString = LogManager.sharedInstance.getLogString()
copyToClipboard(logString)
print("Copied log to clipboard")
}
}
Text("WelcomeToNearDrop")
Text("WelcomeToQuickDrop")
.font(.largeTitle)
.padding()
@@ -29,27 +48,65 @@ struct WelcomeScreen: View {
.multilineTextAlignment(.center)
.padding()
Button {
openNewWindow()
} label: {
Text("Acknowledgements")
.underline()
.font(.footnote)
.opacity(0.5)
HStack(spacing: 30) {
Button {
openNewWindow()
} label: {
Text("Acknowledgements")
.underline()
.font(.footnote)
.opacity(0.5)
}
.buttonStyle(.plain)
if !isPlusVersion {
Button {
openIAP()
} label: {
Text("SupportQuickDrop")
.underline()
.font(.footnote)
.opacity(0.5)
}
.buttonStyle(.plain)
}
#if DEBUG
Button {
for key in UserDefaultsKeys.allCases {
UserDefaults.standard.removeObject(forKey: key.rawValue)
}
} label: {
Text("Reset UD")
.underline()
.font(.footnote)
.opacity(0.5)
}
.buttonStyle(.plain)
#endif
}
.onAppear {
// #if DEBUG
// isPlusVersion = false
// #endif
}
.buttonStyle(.plain)
.padding()
}
.frame(maxWidth: 500)
.frame(maxWidth: .infinity)
}
}
.frame(width: 1000, height: 600)
}
func copyToClipboard(_ text: String) {
let pasteboard = NSPasteboard.general
pasteboard.clearContents()
pasteboard.setString(text, forType: .string)
}
func openNewWindow() {
// Create a new NSWindow and retain it in the `newWindow` property
let window = NSWindow(
@@ -62,19 +119,46 @@ struct WelcomeScreen: View {
window.isReleasedWhenClosed = false
window.title = NSLocalizedString("Acknowledgements", value: "Acknowledgements", comment: "")
window.contentView = NSHostingView(rootView: LicensePage())
window.level = .floating
// Ensure the window is always on top
NSApp.activate(ignoringOtherApps: true) // Brings the whole app to the front
window.makeKeyAndOrderFront(nil)
window.level = .normal
// Retain the window to prevent deallocation
newWindow = window
}
}
import SwiftUI
import AppKit
struct VisualEffectBlur: NSViewRepresentable {
var material: NSVisualEffectView.Material
var blendingMode: NSVisualEffectView.BlendingMode
func makeNSView(context: Context) -> NSVisualEffectView {
let view = NSVisualEffectView()
view.material = material
view.blendingMode = blendingMode
view.state = .active
return view
}
func updateNSView(_ nsView: NSVisualEffectView, context: Context) {
nsView.material = material
nsView.blendingMode = blendingMode
}
}
struct LicensePage: View {
var body: some View {
ScrollView {
Text("""
ZStack {
Color.defaultBackground
.edgesIgnoringSafeArea(.all)
ScrollView {
Text("""
NearDrop
https://github.com/grishka/NearDrop
@@ -193,12 +277,13 @@ See the License for the specific language governing permissions and
limitations under the License.
""")
.padding()
.padding()
}
}
}
}
#Preview {
WelcomeScreen()
WelcomeScreen(openIAP: {})
}
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d ملفات";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "يحتاج NearDrop إلى القدرة على عرض الإشعارات لنقل الملفات الواردة. يرجى السماح بالإشعارات في إعدادات النظام.";
"NotificationsDenied.Message" = "يحتاج QuickDrop إلى القدرة على عرض الإشعارات لنقل الملفات الواردة. يرجى السماح بالإشعارات في إعدادات النظام.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "افتح الإعدادات";
@@ -32,7 +32,7 @@
"PinCode" = "الرمز السري: %@";
/* No comment provided by engineer. */
"Quit" = "إنهاء NearDrop";
"Quit" = "إنهاء QuickDrop";
/* No comment provided by engineer. */
"TransferError" = "فشل في استقبال الملفات من %@";
@@ -44,14 +44,30 @@
"PrivacyPolicy" = "سياسة الخصوصية";
"UserManual" = "دليل المستخدم";
"WelcomeToNearDrop" = "مرحبًا بك في NearDrop";
"WelcomeToQuickDrop" = "مرحبًا بك في QuickDrop";
"Acknowledgements" = "الشكر والتقدير";
"SupportQuickDrop" = "ادعم QuickDrop";
"UserManualDescription" = "عندما يكون NearDrop قيد التشغيل، سيظهر في شريط القائمة في الجزء العلوي من شاشتك. انقر على أيقونة NearDrop إذا كنت ترغب في التوقف عن تلقي الملفات.
"UserManualDescription" = "عندما يكون QuickDrop قيد التشغيل، سيظهر في شريط القائمة في الجزء العلوي من شاشتك. انقر على أيقونة QuickDrop إذا كنت ترغب في التوقف عن تلقي الملفات.
مهم: يجب أن يكون جهاز Android الخاص بك وMac متصلين بنفس شبكة Wi-Fi لنقل الملفات. إذا تم مطالبتك بالسماح بالاتصالات الواردة، يرجى السماح بها.
لإرسال الملفات من جهاز Android إلى جهاز Mac، انقر على أيقونة المشاركة في هاتفك واختر \"Quick Share\" أو \"Nearby Share\". سيظهر جهاز Mac الخاص بك كجهاز متاح.
بعد ذلك، سترى إشعارًا على جهاز Mac الخاص بك. مرر الماوس فوق الإشعار لقبول أو رفض نقل الملفات.";
"plusview_title" = "شكرًا لاستخدامك QuickDrop!";
"plusview_description" = "قم بفتح QuickDrop+ لمواصلة استقبال الملفات. QuickDrop+ هو عملية شراء لمرة واحدة – يمكنك الاحتفاظ بالتطبيق إلى الأبد بدون اشتراك.";
"plusview_success_title" = "شكرًا لشرائك!";
"plusview_success_description" = "يمكنك الآن متابعة استقبال الملفات بدون قيود.";
"plusview_success_button" = "حسنًا!";
"plusview_unlock_label" = "ادعم QuickDrop";
"plusview_restorepurchase" = "هل اشتريته بالفعل؟";
"plusview_restorefailed" = "حدثت مشكلة أثناء استعادة عملية الشراء";
"plusview_restorefailed_proceed" = "موافق";
"plusview_purchasefailed" = "فشل الشراء";
"plusview_purchasefaileddescription" = "إذا ظهر هذا الرسالة بشكل غير متوقع، يرجى التأكد من اتصالك بالإنترنت وأن عمليات الشراء داخل التطبيق مفعّلة على جهازك، ثم حاول مرة أخرى.";
"plusview_nothingtorestore" = "لا يوجد شيء لاستعادته!";
"plusview_productRequestFailed" = "تعذر جلب عمليات الشراء داخل التطبيق في الوقت الحالي.";
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d Dateien";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDrop benötigt die Erlaubnis, Mitteilungen für eingehende Übertragungen anzuzeigen. Bitte erlaube Mitteilungen in den Systemeinstellungen.";
"NotificationsDenied.Message" = "QuickDrop benötigt die Erlaubnis, Mitteilungen für eingehende Übertragungen anzuzeigen. Bitte erlaube Mitteilungen in den Systemeinstellungen.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "Einstellungen öffnen";
@@ -32,7 +32,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "NearDrop beenden";
"Quit" = "QuickDrop beenden";
/* No comment provided by engineer. */
"TransferError" = "Die Daten von %@ konnten nicht empfangen werden";
@@ -46,14 +46,30 @@
"UserManual" = "Benutzerhandbuch";
"WelcomeToNearDrop" = "Willkommen bei NearDrop";
"WelcomeToQuickDrop" = "Willkommen bei QuickDrop";
"Acknowledgements" = "Danksagungen";
"SupportQuickDrop" = "QuickDrop unterstützen";
"UserManualDescription" = "Wenn NearDrop ausgeführt wird, wird es in der Menüleiste am oberen Rand des Bildschirms angezeigt. Klicke auf das NearDrop-Symbol, um den Empfang von Dateien zu beenden.
"UserManualDescription" = "Wenn QuickDrop ausgeführt wird, wird es in der Menüleiste am oberen Rand des Bildschirms angezeigt. Klicke auf das QuickDrop-Symbol, um den Empfang von Dateien zu beenden.
Wichtig: Dein Android-Gerät und dein Mac müssen sich im selben Netzwerk befinden, um Dateien zu übertragen. Wenn du aufgefordert wirst, eingehende Verbindungen zuzulassen, lasse sie bitte zu.
Um Dateien von deinem Android-Gerät an deinen Mac zu senden, tippe auf deinem Handy auf das Teilen-Symbol und wähle „Quick Share“ oder „Nearby Share“. Dein Mac wird als verfügbares Gerät aufgelistet.
Daraufhin wird eine Benachrichtigung auf deinem Mac angezeigt. Bewege den Mauszeiger über die Benachrichtigung, um die Dateiübertragung zu akzeptieren oder abzulehnen.";
"plusview_title" = "Danke, dass du QuickDrop benutzt!";
"plusview_description" = "Schalte QuickDrop+ frei, um weiterhin Dateien zu empfangen. QuickDrop+ ist ein einmaliger Kauf – du kannst die App für immer behalten, kein Abonnement erforderlich.";
"plusview_success_title" = "Danke für deinen Kauf!";
"plusview_success_description" = "Du kannst nun weiterhin Dateien ohne Einschränkungen empfangen.";
"plusview_success_button" = "Alles klar!";
"plusview_unlock_label" = "Unterstütze QuickDrop";
"plusview_restorepurchase" = "Bereits gekauft?";
"plusview_restorefailed" = "Es gab ein Problem beim Wiederherstellen deines Kaufs";
"plusview_restorefailed_proceed" = "Okay";
"plusview_purchasefailed" = "Kauf fehlgeschlagen";
"plusview_purchasefaileddescription" = "Falls diese Nachricht unerwartet erscheint, stelle sicher, dass du mit dem Internet verbunden bist und In-App-Käufe auf deinem Gerät aktiviert sind, und versuche es erneut.";
"plusview_nothingtorestore" = "Es gibt nichts wiederherzustellen!";
"plusview_productRequestFailed" = "In-App-Käufe können momentan nicht abgerufen werden.";
+21 -4
View File
@@ -20,7 +20,7 @@
//"NFiles" = "%d files";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDrop necesita poder mostrar notificaciones para las transferencias de archivos entrantes. Permite las notificaciones en la configuración del sistema.";
"NotificationsDenied.Message" = "QuickDrop necesita poder mostrar notificaciones para las transferencias de archivos entrantes. Permite las notificaciones en la configuración del sistema.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "Abrir la configuración del sistema";
@@ -32,7 +32,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "Salir de NearDrop";
"Quit" = "Salir de QuickDrop";
/* No comment provided by engineer. */
"TransferError" = "Error al recibir archivos de %@";
@@ -44,14 +44,31 @@
"PrivacyPolicy" = "Política de privacidad";
"UserManual" = "Manual de usuario";
"WelcomeToNearDrop" = "Bienvenido a NearDrop";
"WelcomeToQuickDrop" = "Bienvenido a QuickDrop";
"Acknowledgements" = "Agradecimientos";
"SupportQuickDrop" = "Apoyar QuickDrop";
"UserManualDescription" = "Cuando NearDrop está en ejecución, aparecerá en la barra de menú en la parte superior de tu pantalla. Haz clic en el icono de NearDrop si deseas dejar de recibir archivos.
"UserManualDescription" = "Cuando QuickDrop está en ejecución, aparecerá en la barra de menú en la parte superior de tu pantalla. Haz clic en el icono de QuickDrop si deseas dejar de recibir archivos.
Importante: Tu dispositivo Android y tu Mac deben estar conectados a la misma red WiFi para transferir archivos. Si se te solicita permitir conexiones entrantes, por favor, acéptalas.
Para enviar archivos desde tu dispositivo Android a tu Mac, toca el icono de compartir en tu teléfono y selecciona \"Quick Share\" o \"Nearby Share\". Tu Mac aparecerá como un dispositivo disponible.
Después de esto, verás una notificación en tu Mac. Pasa el cursor sobre la notificación para aceptar o rechazar la transferencia del archivo.";
"plusview_title" = "¡Gracias por usar QuickDrop!";
"plusview_description" = "Desbloquea QuickDrop+ para seguir recibiendo archivos. QuickDrop+ es una compra única: puedes conservar la aplicación para siempre, sin necesidad de suscripción.";
"plusview_success_title" = "¡Gracias por tu compra!";
"plusview_success_description" = "Ahora puedes seguir recibiendo archivos sin restricciones.";
"plusview_success_button" = "¡Entendido!";
"plusview_unlock_label" = "Apoyar QuickDrop";
"plusview_restorepurchase" = "¿Ya lo compraste?";
"plusview_restorefailed" = "Hubo un problema al restaurar tu compra";
"plusview_restorefailed_proceed" = "Aceptar";
"plusview_purchasefailed" = "La compra ha fallado";
"plusview_purchasefaileddescription" = "Si este mensaje apareció inesperadamente, asegúrate de estar conectado a Internet y que las compras dentro de la aplicación estén habilitadas en tu dispositivo, luego intenta nuevamente.";
"plusview_nothingtorestore" = "¡No hay nada que restaurar!";
"plusview_productRequestFailed" = "No se pueden recuperar las compras dentro de la aplicación en este momento.";
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d fichiers";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDrop doit pouvoir afficher des notifications pour les transferts de fichiers entrants. Veuillez autoriser les notifications dans les paramètres système.";
"NotificationsDenied.Message" = "QuickDrop doit pouvoir afficher des notifications pour les transferts de fichiers entrants. Veuillez autoriser les notifications dans les paramètres système.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "Ouvrir les paramètres";
@@ -32,7 +32,7 @@
"PinCode" = "CODE PIN : %@";
/* No comment provided by engineer. */
"Quit" = "Quitter NearDrop";
"Quit" = "Quitter QuickDrop";
/* No comment provided by engineer. */
"TransferError" = "Échec de la réception des fichiers de %@";
@@ -44,14 +44,30 @@
"PrivacyPolicy" = "Politique de confidentialité";
"UserManual" = "Manuel d'utilisateur";
"WelcomeToNearDrop" = "Bienvenue sur NearDrop";
"WelcomeToQuickDrop" = "Bienvenue sur QuickDrop";
"Acknowledgements" = "Remerciements";
"SupportQuickDrop" = "Soutenir QuickDrop";
"UserManualDescription" = "Lorsque NearDrop est en cours d'exécution, il apparaît dans la barre de menu en haut de votre écran. Cliquez sur l'icône NearDrop si vous souhaitez arrêter de recevoir des fichiers.
"UserManualDescription" = "Lorsque QuickDrop est en cours d'exécution, il apparaît dans la barre de menu en haut de votre écran. Cliquez sur l'icône QuickDrop si vous souhaitez arrêter de recevoir des fichiers.
Important : Votre appareil Android et votre Mac doivent être connectés au même réseau Wi-Fi pour transférer des fichiers. Si vous êtes invité à autoriser les connexions entrantes, veuillez les autoriser.
Pour envoyer des fichiers de votre appareil Android vers votre Mac, appuyez sur l'icône de partage sur votre téléphone et sélectionnez \"Quick Share\" ou \"Nearby Share\". Votre Mac sera affiché comme un appareil disponible.
Après cela, vous verrez une notification sur votre Mac. Survolez la notification pour accepter ou refuser le transfert de fichiers.";
"plusview_title" = "Merci d'utiliser QuickDrop !";
"plusview_description" = "Débloquez QuickDrop+ pour continuer à recevoir des fichiers. QuickDrop+ est un achat unique – vous pourrez conserver l'application à vie, sans abonnement.";
"plusview_success_title" = "Merci pour votre achat !";
"plusview_success_description" = "Vous pouvez maintenant continuer à recevoir des fichiers sans restrictions.";
"plusview_success_button" = "D'accord !";
"plusview_unlock_label" = "Soutenir QuickDrop";
"plusview_restorepurchase" = "Déjà acheté ?";
"plusview_restorefailed" = "Un problème est survenu lors de la restauration de votre achat";
"plusview_restorefailed_proceed" = "OK";
"plusview_purchasefailed" = "Échec de l'achat";
"plusview_purchasefaileddescription" = "Si ce message est apparu de manière inattendue, assurez-vous d'être connecté à Internet et que les achats intégrés sont activés sur votre appareil, puis réessayez.";
"plusview_nothingtorestore" = "Aucun achat à restaurer !";
"plusview_productRequestFailed" = "Impossible de récupérer les achats intégrés pour le moment.";
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d fájl";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "A NearDrop-nak szüksége van értesítéseket küldeni a bejövő fájlok fogadásához. Kérlek engedélyezd az értesítésekhez való hozzáférést a Rendszerbeállításokban.";
"NotificationsDenied.Message" = "A QuickDrop-nak szüksége van értesítéseket küldeni a bejövő fájlok fogadásához. Kérlek engedélyezd az értesítésekhez való hozzáférést a Rendszerbeállításokban.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "Beállítások megnyitása";
@@ -32,7 +32,7 @@
"PinCode" = "JELKÓD: %@";
/* No comment provided by engineer. */
"Quit" = "NearDrop bezárása";
"Quit" = "QuickDrop bezárása";
/* No comment provided by engineer. */
"TransferError" = "Nem sikerült %@-tól/től fájlokat fogadni";
@@ -44,14 +44,30 @@
"PrivacyPolicy" = "Adatvédelmi irányelvek";
"UserManual" = "Felhasználói kézikönyv";
"WelcomeToNearDrop" = "Üdvözlünk a NearDropban";
"WelcomeToQuickDrop" = "Üdvözlünk a QuickDropban";
"Acknowledgements" = "Köszönetnyilvánítás";
"SupportQuickDrop" = "Támogasd a QuickDropot";
"UserManualDescription" = "Amikor a NearDrop fut, az megjelenik a képernyő tetején található menüsorban. Kattints a NearDrop ikonra, ha szeretnéd leállítani a fájlok fogadását.
"UserManualDescription" = "Amikor a QuickDrop fut, az megjelenik a képernyő tetején található menüsorban. Kattints a QuickDrop ikonra, ha szeretnéd leállítani a fájlok fogadását.
Fontos: Az Android-eszközödnek és a Mac számítógépednek ugyanarra a Wi-Fi hálózatra kell csatlakozniuk a fájlok átviteléhez. Ha megjelenik egy kérdés a bejövő kapcsolatok engedélyezésére, kérjük, engedélyezd azokat.
Fájlok küldéséhez az Android-eszközödről a Mac-re érintsd meg a megosztás ikont a telefonodon, majd válaszd a \"Quick Share\" vagy a \"Nearby Share\" lehetőséget. A Mac-ed elérhető eszközként fog megjelenni.
Ezt követően értesítést fogsz látni a Mac-en. Vidd az egérmutatót az értesítés fölé, hogy elfogadd vagy elutasítsd a fájlátvitelt.";
"plusview_title" = "Köszönjük, hogy használod a QuickDropot!";
"plusview_description" = "Oldd fel a QuickDrop+ funkciót, hogy továbbra is fogadhass fájlokat. A QuickDrop+ egy egyszeri vásárlás – az alkalmazást örökre megtarthatod, előfizetés nélkül.";
"plusview_success_title" = "Köszönjük a vásárlást!";
"plusview_success_description" = "Mostantól korlátozások nélkül fogadhatsz fájlokat.";
"plusview_success_button" = "Értettem!";
"plusview_unlock_label" = "Támogasd a QuickDropot";
"plusview_restorepurchase" = "Már megvásároltad?";
"plusview_restorefailed" = "Hiba történt a vásárlás visszaállítása során";
"plusview_restorefailed_proceed" = "Rendben";
"plusview_purchasefailed" = "A vásárlás sikertelen";
"plusview_purchasefaileddescription" = "Ha ez az üzenet váratlanul jelent meg, ellenőrizd az internetkapcsolatot, és győződj meg róla, hogy az alkalmazáson belüli vásárlások engedélyezve vannak az eszközödön, majd próbáld újra.";
"plusview_nothingtorestore" = "Nincs visszaállítható vásárlás!";
"plusview_productRequestFailed" = "Jelenleg nem lehet lekérni az alkalmazáson belüli vásárlásokat.";
+21 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d files";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDrop deve essere in grado di visualizzare le notifiche per i trasferimenti di file in entrata. Consenti le notifiche nelle Impostazioni di sistema.";
"NotificationsDenied.Message" = "QuickDrop deve essere in grado di visualizzare le notifiche per i trasferimenti di file in entrata. Consenti le notifiche nelle Impostazioni di sistema.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "Apri le impostazioni";
@@ -32,7 +32,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "Esci da NearDrop";
"Quit" = "Esci da QuickDrop";
/* No comment provided by engineer. */
"TransferError" = "Impossibile ricevere i file da %@";
@@ -44,14 +44,31 @@
"PrivacyPolicy" = "Informativa sulla privacy";
"UserManual" = "Manuale utente";
"WelcomeToNearDrop" = "Benvenuto su NearDrop";
"WelcomeToQuickDrop" = "Benvenuto su QuickDrop";
"Acknowledgements" = "Ringraziamenti";
"SupportQuickDrop" = "Supporta QuickDrop";
"UserManualDescription" = "Quando NearDrop è in esecuzione, verrà visualizzato nella barra dei menu in alto sullo schermo. Fai clic sull'icona di NearDrop se desideri interrompere la ricezione dei file.
"UserManualDescription" = "Quando QuickDrop è in esecuzione, verrà visualizzato nella barra dei menu in alto sullo schermo. Fai clic sull'icona di QuickDrop se desideri interrompere la ricezione dei file.
Importante: Il tuo dispositivo Android e il tuo Mac devono essere connessi alla stessa rete WiFi per trasferire file. Se ti viene richiesto di consentire connessioni in entrata, per favore consenti.
Per inviare file dal tuo dispositivo Android al tuo Mac, tocca l'icona di condivisione sul tuo telefono e seleziona \"Quick Share\" o \"Nearby Share\". Il tuo Mac verrà elencato come dispositivo disponibile.
Dopo di ciò, vedrai una notifica sul tuo Mac. Passa il cursore sulla notifica per accettare o rifiutare il trasferimento del file.";
"plusview_title" = "Grazie per aver usato QuickDrop!";
"plusview_description" = "Sblocca QuickDrop+ per continuare a ricevere file. QuickDrop+ è un acquisto unico: puoi tenere l'app per sempre, senza bisogno di un abbonamento.";
"plusview_success_title" = "Grazie per il tuo acquisto!";
"plusview_success_description" = "Ora puoi continuare a ricevere file senza restrizioni.";
"plusview_success_button" = "Capito!";
"plusview_unlock_label" = "Supporta QuickDrop";
"plusview_restorepurchase" = "Già acquistato?";
"plusview_restorefailed" = "Si è verificato un problema durante il ripristino dell'acquisto";
"plusview_restorefailed_proceed" = "Ok";
"plusview_purchasefailed" = "Acquisto non riuscito";
"plusview_purchasefaileddescription" = "Se questo messaggio è apparso inaspettatamente, assicurati di essere connesso a Internet e che gli acquisti in-app siano abilitati sul tuo dispositivo, quindi riprova.";
"plusview_nothingtorestore" = "Non c'è nulla da ripristinare!";
"plusview_productRequestFailed" = "Impossibile recuperare gli acquisti in-app al momento.";
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%dつのファイル";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDropでファイル受信の通知を表示できる必要があります。システム設定で通知を許可してください。";
"NotificationsDenied.Message" = "QuickDropでファイル受信の通知を表示できる必要があります。システム設定で通知を許可してください。";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "設定を開く";
@@ -32,7 +32,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "NearDropを終了";
"Quit" = "QuickDropを終了";
/* No comment provided by engineer. */
"TransferError" = "%@からのファイル受信に失敗しました。";
@@ -44,14 +44,30 @@
"PrivacyPolicy" = "プライバシーポリシー";
"UserManual" = "ユーザーマニュアル";
"WelcomeToNearDrop" = "NearDropへようこそ";
"WelcomeToQuickDrop" = "QuickDropへようこそ";
"Acknowledgements" = "謝辞";
"SupportQuickDrop" = "QuickDrop をサポート";
"UserManualDescription" = "NearDropが実行中の場合、画面上部のメニューバーに表示されます。ファイルの受信を停止したい場合は、NearDropのアイコンをクリックしてください。
"UserManualDescription" = "QuickDropが実行中の場合、画面上部のメニューバーに表示されます。ファイルの受信を停止したい場合は、QuickDropのアイコンをクリックしてください。
重要: AndroidデバイスとMacは、ファイルを転送するために同じWi-Fiネットワークに接続している必要があります。接続の許可を求められた場合は、それを許可してください。
AndroidデバイスからMacにファイルを送信するには、電話の共有アイコンをタップし、\"クイックシェア\"Quick Share\"Nearby Share\"を選択してください。Macは利用可能なデバイスとして表示されます。
その後、Macに通知が表示されます。通知にカーソルを合わせて、ファイル転送を承認または拒否してください。";
"plusview_title" = "QuickDropをご利用いただきありがとうございます!";
"plusview_description" = "QuickDrop+をアンロックして、引き続きファイルを受信しましょう。QuickDrop+は一度購入すれば、サブスクリプションなしで永久にアプリを利用できます。";
"plusview_success_title" = "ご購入ありがとうございます!";
"plusview_success_description" = "これで、制限なくファイルを受信できます。";
"plusview_success_button" = "了解!";
"plusview_unlock_label" = "QuickDropをサポート";
"plusview_restorepurchase" = "すでに購入済みですか?";
"plusview_restorefailed" = "購入の復元中に問題が発生しました";
"plusview_restorefailed_proceed" = "OK";
"plusview_purchasefailed" = "購入に失敗しました";
"plusview_purchasefaileddescription" = "このメッセージが予期せず表示された場合、インターネット接続を確認し、アプリ内購入が有効になっていることを確認した上で再試行してください。";
"plusview_nothingtorestore" = "復元するものがありません!";
"plusview_productRequestFailed" = "現在、アプリ内購入情報を取得できません。";
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d개의 파일";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDrop에서 파일 수신에 대한 알림을 표시할 수 있어야 합니다. 시스템 설정에서 알림을 허용하세요.";
"NotificationsDenied.Message" = "QuickDrop에서 파일 수신에 대한 알림을 표시할 수 있어야 합니다. 시스템 설정에서 알림을 허용하세요.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "설정 열기";
@@ -32,7 +32,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "NearDrop 종료";
"Quit" = "QuickDrop 종료";
/* No comment provided by engineer. */
"TransferError" = "%@에서 전송한 Nearby Share가 실패했습니다.";
@@ -44,14 +44,30 @@
"PrivacyPolicy" = "개인정보 처리방침";
"UserManual" = "사용자 매뉴얼";
"WelcomeToNearDrop" = "NearDrop에 오신 것을 환영합니다";
"WelcomeToQuickDrop" = "QuickDrop에 오신 것을 환영합니다";
"Acknowledgements" = "감사의 말";
"SupportQuickDrop" = "QuickDrop 지원하기";
"UserManualDescription" = "NearDrop이 실행 중이면 화면 상단 메뉴 막대에 나타납니다. 파일 수신을 중지하려면 NearDrop 아이콘을 클릭하세요.
"UserManualDescription" = "QuickDrop이 실행 중이면 화면 상단 메뉴 막대에 나타납니다. 파일 수신을 중지하려면 QuickDrop 아이콘을 클릭하세요.
중요: Android 기기와 Mac이 파일을 전송하려면 동일한 WiFi 네트워크에 연결되어 있어야 합니다. 들어오는 연결을 허용하라는 메시지가 표시되면 허용하세요.
Android 기기에서 Mac으로 파일을 전송하려면 휴대전화에서 공유 아이콘을 탭한 다음 \"Quick Share\" 또는 \"Nearby Share\"를 선택하세요. Mac이 사용 가능한 장치로 표시됩니다.
그 후, Mac에서 알림이 표시됩니다. 알림 위에 커서를 올려 파일 전송을 수락하거나 거부하세요.";
"plusview_title" = "QuickDrop을 사용해 주셔서 감사합니다!";
"plusview_description" = "QuickDrop+를 잠금 해제하여 파일을 계속 받을 수 있습니다. QuickDrop+는 1회 구매로, 구독 없이 앱을 영구적으로 사용할 수 있습니다.";
"plusview_success_title" = "구매해 주셔서 감사합니다!";
"plusview_success_description" = "이제 제한 없이 파일을 받을 수 있습니다.";
"plusview_success_button" = "알겠습니다!";
"plusview_unlock_label" = "QuickDrop 지원하기";
"plusview_restorepurchase" = "이미 구매하셨나요?";
"plusview_restorefailed" = "구매 복원 중 문제가 발생했습니다.";
"plusview_restorefailed_proceed" = "확인";
"plusview_purchasefailed" = "구매 실패";
"plusview_purchasefaileddescription" = "이 메시지가 예상치 않게 나타난 경우, 인터넷에 연결되어 있는지 확인하고 기기에서 인앱 결제가 활성화되어 있는지 확인한 후 다시 시도해 주세요.";
"plusview_nothingtorestore" = "복원할 항목이 없습니다!";
"plusview_productRequestFailed" = "현재 인앱 구매 정보를 가져올 수 없습니다.";
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d bestanden";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDrop moet meldingen kunnen weergeven voor inkomende bestandsoverdrachten. Sta meldingen toe in de systeeminstellingen.";
"NotificationsDenied.Message" = "QuickDrop moet meldingen kunnen weergeven voor inkomende bestandsoverdrachten. Sta meldingen toe in de systeeminstellingen.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "Instellingen openen";
@@ -32,7 +32,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "NearDrop afsluiten";
"Quit" = "QuickDrop afsluiten";
/* No comment provided by engineer. */
"TransferError" = "Mislukt om bestanden te ontvangen van %@";
@@ -46,14 +46,30 @@
"UserManual" = "Gebruikershandleiding";
"WelcomeToNearDrop" = "Welkom bij NearDrop";
"WelcomeToQuickDrop" = "Welkom bij QuickDrop";
"Acknowledgements" = "Erkenningen";
"SupportQuickDrop" = "Ondersteun QuickDrop";
"UserManualDescription" = "Wanneer NearDrop actief is, verschijnt het in de menubalk bovenaan je scherm. Klik op het NearDrop-pictogram als je wilt stoppen met het ontvangen van bestanden.
"UserManualDescription" = "Wanneer QuickDrop actief is, verschijnt het in de menubalk bovenaan je scherm. Klik op het QuickDrop-pictogram als je wilt stoppen met het ontvangen van bestanden.
Belangrijk: Je Android-apparaat en je Mac moeten verbonden zijn met hetzelfde WiFi-netwerk om bestanden over te dragen. Als je wordt gevraagd om inkomende verbindingen toe te staan, geef dan toestemming.
Om bestanden van je Android-apparaat naar je Mac te verzenden, tik op het deelpictogram op je telefoon en selecteer \"Quick Share\" of \"Nearby Share\". Je Mac wordt weergegeven als een beschikbaar apparaat.
Daarna zie je een melding op je Mac. Beweeg de muis over de melding om het bestandsoverdracht te accepteren of te weigeren.";
"plusview_title" = "Bedankt voor het gebruiken van QuickDrop!";
"plusview_description" = "Ontgrendel QuickDrop+ om bestanden te blijven ontvangen. QuickDrop+ is een eenmalige aankoop – je kunt de app voor altijd behouden, geen abonnement nodig.";
"plusview_success_title" = "Bedankt voor je aankoop!";
"plusview_success_description" = "Je kunt nu bestanden blijven ontvangen zonder beperkingen.";
"plusview_success_button" = "Begrepen!";
"plusview_unlock_label" = "Ondersteun QuickDrop";
"plusview_restorepurchase" = "Al gekocht?";
"plusview_restorefailed" = "Er was een probleem bij het herstellen van je aankoop";
"plusview_restorefailed_proceed" = "Oké";
"plusview_purchasefailed" = "Aankoop mislukt";
"plusview_purchasefaileddescription" = "Als dit bericht onverwachts verschijnt, controleer dan of je verbonden bent met internet en of in-app aankopen zijn ingeschakeld op je apparaat, en probeer het opnieuw.";
"plusview_nothingtorestore" = "Er is niets om te herstellen!";
"plusview_productRequestFailed" = "In-app aankopen kunnen momenteel niet worden opgehaald.";
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d arquivos";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "O NearDrop precisa ser capaz de exibir notificações para o recebimento de arquivos. Por favor, habilite as notificações em Ajustes do Sistema.";
"NotificationsDenied.Message" = "O QuickDrop precisa ser capaz de exibir notificações para o recebimento de arquivos. Por favor, habilite as notificações em Ajustes do Sistema.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "Abrir configurações";
@@ -32,7 +32,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "Sair do NearDrop";
"Quit" = "Sair do QuickDrop";
/* No comment provided by engineer. */
"TransferError" = "Falha ao receber arquivos de %@";
@@ -44,14 +44,30 @@
"PrivacyPolicy" = "Política de Privacidade";
"UserManual" = "Manual do Usuário";
"WelcomeToNearDrop" = "Bem-vindo ao NearDrop";
"WelcomeToQuickDrop" = "Bem-vindo ao QuickDrop";
"Acknowledgements" = "Agradecimentos";
"SupportQuickDrop" = "Apoie o QuickDrop";
"UserManualDescription" = "Quando o NearDrop estiver em execução, ele aparecerá na barra de menu na parte superior da sua tela. Clique no ícone do NearDrop se quiser parar de receber arquivos.
"UserManualDescription" = "Quando o QuickDrop estiver em execução, ele aparecerá na barra de menu na parte superior da sua tela. Clique no ícone do QuickDrop se quiser parar de receber arquivos.
Importante: Seu dispositivo Android e seu Mac precisam estar conectados à mesma rede Wi-Fi para transferir arquivos. Se for solicitado que você permita conexões de entrada, por favor, permita.
Para enviar arquivos do seu dispositivo Android para o seu Mac, toque no ícone de compartilhamento no seu telefone e selecione \"Quick Share\" ou \"Nearby Share\". O seu Mac será exibido como um dispositivo disponível.
Depois disso, você verá uma notificação no seu Mac. Passe o cursor sobre a notificação para aceitar ou recusar a transferência do arquivo.";
"plusview_title" = "Obrigado por usar o QuickDrop!";
"plusview_description" = "Desbloqueie o QuickDrop+ para continuar recebendo arquivos. O QuickDrop+ é uma compra única – você pode ficar com o aplicativo para sempre, sem necessidade de assinatura.";
"plusview_success_title" = "Obrigado pela sua compra!";
"plusview_success_description" = "Agora você pode continuar recebendo arquivos sem restrições.";
"plusview_success_button" = "Entendi!";
"plusview_unlock_label" = "Apoie o QuickDrop";
"plusview_restorepurchase" = "Já comprou?";
"plusview_restorefailed" = "Houve um problema ao restaurar sua compra";
"plusview_restorefailed_proceed" = "OK";
"plusview_purchasefailed" = "Falha na compra";
"plusview_purchasefaileddescription" = "Se esta mensagem apareceu inesperadamente, verifique se você está conectado à internet e se as compras dentro do app estão ativadas no seu dispositivo e tente novamente.";
"plusview_nothingtorestore" = "Nada para restaurar!";
"plusview_productRequestFailed" = "Não foi possível recuperar as compras dentro do aplicativo no momento.";
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d ficheiros";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "O NearDrop precisa ser capaz de mostrar notificações para receber ficheiros. Por favor, active as notificações em Definições do Sistema.";
"NotificationsDenied.Message" = "O QuickDrop precisa ser capaz de mostrar notificações para receber ficheiros. Por favor, active as notificações em Definições do Sistema.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "Abrir definições";
@@ -32,7 +32,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "Sair do NearDrop";
"Quit" = "Sair do QuickDrop";
/* No comment provided by engineer. */
"TransferError" = "Falha ao receber ficheiros de %@";
@@ -44,14 +44,30 @@
"PrivacyPolicy" = "Política de privacidade";
"UserManual" = "Manual do usuário";
"WelcomeToNearDrop" = "Bem-vindo ao NearDrop";
"WelcomeToQuickDrop" = "Bem-vindo ao QuickDrop";
"Acknowledgements" = "Agradecimentos";
"SupportQuickDrop" = "Apoie o QuickDrop";
"UserManualDescription" = "Quando o NearDrop estiver em execução, ele aparecerá na barra de menu na parte superior da sua tela. Clique no ícone do NearDrop se quiser parar de receber arquivos.
"UserManualDescription" = "Quando o QuickDrop estiver em execução, ele aparecerá na barra de menu na parte superior da sua tela. Clique no ícone do QuickDrop se quiser parar de receber arquivos.
Importante: Seu dispositivo Android e seu Mac precisam estar conectados à mesma rede Wi-Fi para transferir arquivos. Se for solicitado que você permita conexões de entrada, por favor, permita.
Para enviar arquivos do seu dispositivo Android para o seu Mac, toque no ícone de compartilhamento no seu telefone e selecione \"Quick Share\" ou \"Nearby Share\". O seu Mac será exibido como um dispositivo disponível.
Depois disso, você verá uma notificação no seu Mac. Passe o cursor sobre a notificação para aceitar ou recusar a transferência do arquivo.";
"plusview_title" = "Obrigado por usar o QuickDrop!";
"plusview_description" = "Desbloqueie o QuickDrop+ para continuar recebendo arquivos. QuickDrop+ é uma compra única – você pode manter o app para sempre, sem necessidade de assinatura.";
"plusview_success_title" = "Obrigado pela sua compra!";
"plusview_success_description" = "Agora você pode continuar enviando arquivos sem restrições.";
"plusview_success_button" = "Entendido!";
"plusview_unlock_label" = "Apoiar QuickDrop";
"plusview_restorepurchase" = "Já comprou?";
"plusview_restorefailed" = "Houve um problema ao restaurar sua compra";
"plusview_restorefailed_proceed" = "Ok";
"plusview_purchasefailed" = "Falha na compra";
"plusview_purchasefaileddescription" = "Se esta mensagem apareceu inesperadamente, certifique-se de estar conectado à Internet e que as compras dentro do app estejam ativadas no seu dispositivo, depois tente novamente.";
"plusview_nothingtorestore" = "Não há nada para restaurar!";
"plusview_productRequestFailed" = "Não foi possível recuperar as compras dentro do app no momento.";
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d fișiere";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDrop trebuie să poată afișa notificări pentru transferurile de fișiere primite. Vă rugăm să permiteți notificările în Setările Sistemului.";
"NotificationsDenied.Message" = "QuickDrop trebuie să poată afișa notificări pentru transferurile de fișiere primite. Vă rugăm să permiteți notificările în Setările Sistemului.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "Deschide setările";
@@ -32,7 +32,7 @@
"PinCode" = "COD PIN : %@";
/* No comment provided by engineer. */
"Quit" = "Închide NearDrop";
"Quit" = "Închide QuickDrop";
/* No comment provided by engineer. */
"TransferError" = "Recepționarea fișierelor de la %@ a eșuat";
@@ -44,14 +44,30 @@
"PrivacyPolicy" = "Politica de confidențialitate";
"UserManual" = "Manualul utilizatorului";
"WelcomeToNearDrop" = "Bine ai venit la NearDrop";
"WelcomeToQuickDrop" = "Bine ai venit la QuickDrop";
"Acknowledgements" = "Mulțumiri";
"SupportQuickDrop" = "Susține QuickDrop";
"UserManualDescription" = "Când NearDrop este în funcțiune, va apărea în bara de meniu din partea de sus a ecranului. Fă clic pe iconița NearDrop dacă dorești să oprești primirea fișierelor.
"UserManualDescription" = "Când QuickDrop este în funcțiune, va apărea în bara de meniu din partea de sus a ecranului. Fă clic pe iconița QuickDrop dacă dorești să oprești primirea fișierelor.
Important: Dispozitivul tău Android și Mac-ul tău trebuie să fie conectate la aceeași rețea Wi-Fi pentru a transfera fișiere. Dacă ți se solicită să permiți conexiunile intrante, te rugăm să le permiți.
Pentru a trimite fișiere de pe dispozitivul tău Android pe Mac, apasă pe iconița de partajare de pe telefon și selectează „Quick Share” sau „Nearby Share”. Mac-ul tău va apărea ca dispozitiv disponibil.
După aceea, vei vedea o notificare pe Mac. Plasează cursorul peste notificare pentru a accepta sau a respinge transferul fișierelor.";
"plusview_title" = "Mulțumim că folosești QuickDrop!";
"plusview_description" = "Deblochează QuickDrop+ pentru a continua să primești fișiere. QuickDrop+ este o achiziție unică – poți păstra aplicația pentru totdeauna, fără abonament.";
"plusview_success_title" = "Mulțumim pentru achiziție!";
"plusview_success_description" = "Acum poți continua să primești fișiere fără restricții.";
"plusview_success_button" = "Înțeles!";
"plusview_unlock_label" = "Susține QuickDrop";
"plusview_restorepurchase" = "Deja cumpărat?";
"plusview_restorefailed" = "A apărut o problemă la restaurarea achiziției";
"plusview_restorefailed_proceed" = "OK";
"plusview_purchasefailed" = "Achiziția a eșuat";
"plusview_purchasefaileddescription" = "Dacă acest mesaj a apărut neașteptat, asigură-te că ești conectat la internet și că achizițiile în aplicație sunt activate pe dispozitivul tău, apoi încearcă din nou.";
"plusview_nothingtorestore" = "Nu există nimic de restaurat!";
"plusview_productRequestFailed" = "Momentan, nu se pot obține informații despre achizițiile în aplicație.";
+20 -4
View File
@@ -23,7 +23,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "Завершить NearDrop";
"Quit" = "Завершить QuickDrop";
/* No comment provided by engineer. */
"TransferError" = "Не удалость принять файлы от %@";
@@ -32,7 +32,7 @@
"VisibleToEveryone" = "Видимость: все";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDrop необходима возможность показывать уведомления о входящих файлах. Пожалуйста, разрешите уведомления в Системных настройках.";
"NotificationsDenied.Message" = "QuickDrop необходима возможность показывать уведомления о входящих файлах. Пожалуйста, разрешите уведомления в Системных настройках.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "Открыть настройки";
@@ -46,14 +46,30 @@
"UserManual" = "Руководство пользователя";
"WelcomeToNearDrop" = "Добро пожаловать в NearDrop";
"WelcomeToQuickDrop" = "Добро пожаловать в QuickDrop";
"Acknowledgements" = "Благодарности";
"SupportQuickDrop" = "Поддержать QuickDrop";
"UserManualDescription" = "Когда NearDrop запущен, он отображается в строке меню в верхней части экрана. Нажмите на значок NearDrop, если вы хотите прекратить получение файлов.
"UserManualDescription" = "Когда QuickDrop запущен, он отображается в строке меню в верхней части экрана. Нажмите на значок QuickDrop, если вы хотите прекратить получение файлов.
Важно: Ваше устройство Android и Mac должны быть подключены к одной и той же сети Wi-Fi для передачи файлов. Если появится запрос на разрешение входящих подключений, пожалуйста, разрешите их.
Чтобы отправить файлы с вашего устройства Android на Mac, нажмите на значок «Поделиться» на вашем телефоне и выберите \"Quick Share\" или \"Nearby Share\". Ваш Mac отобразится в списке доступных устройств.
После этого на вашем Mac появится уведомление. Наведите курсор на уведомление, чтобы принять или отклонить передачу файла.";
"plusview_title" = "Спасибо за использование QuickDrop!";
"plusview_description" = "Разблокируйте QuickDrop+, чтобы продолжать получать файлы. QuickDrop+ — это разовая покупка: приложение останется у вас навсегда, без подписки.";
"plusview_success_title" = "Спасибо за покупку!";
"plusview_success_description" = "Теперь вы можете продолжать получать файлы без ограничений.";
"plusview_success_button" = "Понял!";
"plusview_unlock_label" = "Поддержать QuickDrop";
"plusview_restorepurchase" = "Уже куплено?";
"plusview_restorefailed" = "Произошла ошибка при восстановлении покупки";
"plusview_restorefailed_proceed" = "Окей";
"plusview_purchasefailed" = "Ошибка покупки";
"plusview_purchasefaileddescription" = "Если это сообщение появилось неожиданно, убедитесь, что у вас есть доступ к интернету и включены встроенные покупки на вашем устройстве, затем попробуйте снова.";
"plusview_nothingtorestore" = "Нет покупок для восстановления!";
"plusview_productRequestFailed" = "Не удалось получить данные о встроенных покупках.";
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d ไฟล์";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDrop ไม่สามารถแสดงการแจ้งเตือนไฟล์ที่เข้ามาได้ โปรดให้สิทธิ์การแจ้งเตือน ในการตั้งค่าระบบ";
"NotificationsDenied.Message" = "QuickDrop ไม่สามารถแสดงการแจ้งเตือนไฟล์ที่เข้ามาได้ โปรดให้สิทธิ์การแจ้งเตือน ในการตั้งค่าระบบ";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "การตั้งค่า";
@@ -32,7 +32,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "ออก NearDrop";
"Quit" = "ออก QuickDrop";
/* No comment provided by engineer. */
"TransferError" = "เกิดข้อผิดพลาดในการรับไฟล์จาก %@";
@@ -44,14 +44,30 @@
"PrivacyPolicy" = "นโยบายความเป็นส่วนตัว";
"UserManual" = "คู่มือการใช้งาน";
"WelcomeToNearDrop" = "ยินดีต้อนรับสู่ NearDrop";
"WelcomeToQuickDrop" = "ยินดีต้อนรับสู่ QuickDrop";
"Acknowledgements" = "คำขอบคุณ";
"SupportQuickDrop" = "สนับสนุน QuickDrop";
"UserManualDescription" = "เมื่อ NearDrop กำลังทำงานอยู่ ไอคอนจะปรากฏในแถบเมนูที่ด้านบนของหน้าจอของคุณ คลิกที่ไอคอน NearDrop หากคุณต้องการหยุดรับไฟล์
"UserManualDescription" = "เมื่อ QuickDrop กำลังทำงานอยู่ ไอคอนจะปรากฏในแถบเมนูที่ด้านบนของหน้าจอของคุณ คลิกที่ไอคอน QuickDrop หากคุณต้องการหยุดรับไฟล์
สำคัญ: อุปกรณ์ Android และ Mac ของคุณจะต้องเชื่อมต่อกับเครือข่าย WiFi เดียวกันเพื่อถ่ายโอนไฟล์ หากมีการแจ้งเตือนให้อนุญาตการเชื่อมต่อขาเข้า โปรดอนุญาต
ในการส่งไฟล์จากอุปกรณ์ Android ของคุณไปยัง Mac ให้แตะที่ไอคอนแชร์บนโทรศัพท์ของคุณ และเลือก \"Quick Share\" หรือ \"Nearby Share\" Mac ของคุณจะแสดงในรายการอุปกรณ์ที่พร้อมใช้งาน
หลังจากนั้น คุณจะเห็นการแจ้งเตือนบน Mac ของคุณ วางเคอร์เซอร์เหนือการแจ้งเตือนเพื่อยอมรับหรือปฏิเสธการถ่ายโอนไฟล์";
"plusview_title" = "ขอบคุณที่ใช้ QuickDrop!";
"plusview_description" = "ปลดล็อก QuickDrop+ เพื่อรับไฟล์ต่อไป QuickDrop+ เป็นการซื้อครั้งเดียว – คุณสามารถใช้แอปได้ตลอดไปโดยไม่ต้องสมัครสมาชิก";
"plusview_success_title" = "ขอบคุณสำหรับการซื้อ!";
"plusview_success_description" = "คุณสามารถรับไฟล์ได้ต่อไปโดยไม่มีข้อจำกัดแล้ว";
"plusview_success_button" = "รับทราบ!";
"plusview_unlock_label" = "สนับสนุน QuickDrop";
"plusview_restorepurchase" = "เคยซื้อแล้ว?";
"plusview_restorefailed" = "เกิดปัญหาในการกู้คืนการซื้อของคุณ";
"plusview_restorefailed_proceed" = "ตกลง";
"plusview_purchasefailed" = "การซื้อล้มเหลว";
"plusview_purchasefaileddescription" = "หากข้อความนี้ปรากฏขึ้นโดยไม่คาดคิด โปรดตรวจสอบว่าคุณเชื่อมต่ออินเทอร์เน็ตและเปิดใช้งานการซื้อภายในแอปในอุปกรณ์ของคุณแล้วลองอีกครั้ง";
"plusview_nothingtorestore" = "ไม่มีรายการที่ต้องกู้คืน!";
"plusview_productRequestFailed" = "ไม่สามารถดึงข้อมูลการซื้อภายในแอปได้ในขณะนี้";
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d files";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDrop потрібна можливість показувати сповіщення про вхідні файли. Будь ласка, дозвольте сповіщення у Системних налаштуваннях.";
"NotificationsDenied.Message" = "QuickDrop потрібна можливість показувати сповіщення про вхідні файли. Будь ласка, дозвольте сповіщення у Системних налаштуваннях.";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "Відкрити налаштування";
@@ -32,7 +32,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "Завершити NearDrop";
"Quit" = "Завершити QuickDrop";
/* No comment provided by engineer. */
"TransferError" = "Не вдалося отримати файли від %@";
@@ -45,14 +45,30 @@
"UserManual" = "Посібник користувача";
"WelcomeToNearDrop" = "Ласкаво просимо до NearDrop";
"WelcomeToQuickDrop" = "Ласкаво просимо до QuickDrop";
"Acknowledgements" = "Подяки";
"SupportQuickDrop" = "Підтримати QuickDrop";
"UserManualDescription" = "Коли NearDrop працює, він з'являється в рядку меню в верхній частині екрана. Клікніть на значок NearDrop, якщо ви хочете припинити отримувати файли.
"UserManualDescription" = "Коли QuickDrop працює, він з'являється в рядку меню в верхній частині екрана. Клікніть на значок QuickDrop, якщо ви хочете припинити отримувати файли.
Важливо: Ваш пристрій Android і Mac повинні бути підключені до однієї WiFi-мережі для передачі файлів. Якщо вам запропонують дозволити вхідні підключення, будь ласка, дозвольте їх.
Щоб надіслати файли з вашого пристрою Android на Mac, торкніться іконки спільного доступу на вашому телефоні та виберіть \"Quick Share\" або \"Nearby Share\". Ваш Mac буде відображатися як доступний пристрій.
Після цього ви побачите сповіщення на вашому Mac. Наведіть курсор на сповіщення, щоб прийняти або відхилити передачу файлів.";
"plusview_title" = "Дякуємо за використання QuickDrop!";
"plusview_description" = "Розблокуйте QuickDrop+, щоб продовжити отримання файлів. QuickDrop+ — це одноразова покупка, додаток залишиться у вас назавжди, без необхідності підписки.";
"plusview_success_title" = "Дякуємо за покупку!";
"plusview_success_description" = "Тепер ви можете продовжувати отримувати файли без обмежень.";
"plusview_success_button" = "Зрозуміло!";
"plusview_unlock_label" = "Підтримати QuickDrop";
"plusview_restorepurchase" = "Вже куплено?";
"plusview_restorefailed" = "Сталася помилка під час відновлення покупки";
"plusview_restorefailed_proceed" = "Гаразд";
"plusview_purchasefailed" = "Помилка покупки";
"plusview_purchasefaileddescription" = "Якщо це повідомлення з’явилося несподівано, переконайтеся, що у вас є підключення до Інтернету, а покупки в додатках увімкнені на вашому пристрої, і спробуйте ще раз.";
"plusview_nothingtorestore" = "Немає покупок для відновлення!";
"plusview_productRequestFailed" = "Наразі неможливо отримати інформацію про покупки в додатку.";
+20 -4
View File
@@ -20,7 +20,7 @@
"NFiles" = "%d files";
/* No comment provided by engineer. */
"NotificationsDenied.Message" = "NearDrop 需显示是否接收文件传输的通知。请在 系统设置 中允许通知。";
"NotificationsDenied.Message" = "QuickDrop 需显示是否接收文件传输的通知。请在 系统设置 中允许通知。";
/* No comment provided by engineer. */
"NotificationsDenied.OpenSettings" = "打开设置";
@@ -32,7 +32,7 @@
"PinCode" = "PIN: %@";
/* No comment provided by engineer. */
"Quit" = "退出 NearDrop";
"Quit" = "退出 QuickDrop";
/* No comment provided by engineer. */
"TransferError" = "无法从 %@ 接收文件";
@@ -44,14 +44,30 @@
"PrivacyPolicy" = "隐私政策";
"UserManual" = "用户手册";
"WelcomeToNearDrop" = "欢迎使用 NearDrop";
"WelcomeToQuickDrop" = "欢迎使用 QuickDrop";
"Acknowledgements" = "致谢";
"SupportQuickDrop" = "支持 QuickDrop";
"UserManualDescription" = "当 NearDrop 运行时,它会出现在屏幕顶部的菜单栏中。如果您想停止接收文件,请点击 NearDrop 图标。
"UserManualDescription" = "当 QuickDrop 运行时,它会出现在屏幕顶部的菜单栏中。如果您想停止接收文件,请点击 QuickDrop 图标。
重要提示:您的 Android 设备和 Mac 需要连接到同一个 WiFi 网络才能传输文件。如果系统提示允许传入连接,请选择允许。
要将文件从 Android 设备发送到 Mac,请点击手机上的分享图标,然后选择“Quick Share”或“Nearby Share”。您的 Mac 将显示为可用设备。
之后,您将在 Mac 上看到一条通知。将鼠标悬停在通知上以接受或拒绝文件传输。";
"plusview_title" = "感谢使用 QuickDrop!";
"plusview_description" = "解锁 QuickDrop+ 以继续接收文件。QuickDrop+ 是一次性购买 – 无需订阅,你可以永久保留此应用。";
"plusview_success_title" = "感谢您的购买!";
"plusview_success_description" = "您现在可以无限制地接收文件了。";
"plusview_success_button" = "知道了!";
"plusview_unlock_label" = "支持 QuickDrop";
"plusview_restorepurchase" = "已购买?";
"plusview_restorefailed" = "恢复购买时出现问题";
"plusview_restorefailed_proceed" = "确定";
"plusview_purchasefailed" = "购买失败";
"plusview_purchasefaileddescription" = "如果此消息意外出现,请确保您已连接到互联网,并且设备已启用应用内购买功能,然后重试。";
"plusview_nothingtorestore" = "没有可恢复的购买!";
"plusview_productRequestFailed" = "暂时无法获取应用内购买信息。";
@@ -1,3 +0,0 @@
/* Bundle name */
"CFBundleName" = "NearDrop";
+1 -1
View File
@@ -1,6 +1,6 @@
//
// Data+URLSafeBase64.swift
// NearDrop
// QuickDrop
//
// Created by Grishka on 08.04.2023.
//
+8 -8
View File
@@ -1,6 +1,6 @@
//
// InboundNearbyConnection.swift
// NearDrop
// QuickDrop
//
// Created by Grishka on 08.04.2023.
//
@@ -37,7 +37,7 @@ class InboundNearbyConnection: NearbyConnection{
do{
try deletePartiallyReceivedFiles()
}catch{
print("Error deleting partially received files: \(error)")
log("Error deleting partially received files: \(error)")
}
DispatchQueue.main.async {
self.delegate?.connectionWasTerminated(connection: self, error: self.lastError)
@@ -66,7 +66,7 @@ class InboundNearbyConnection: NearbyConnection{
}
}catch{
lastError=error
print("Deserialization error: \(error) in state \(currentState)")
log("Deserialization error: \(error) in state \(currentState)")
#if !DEBUG
protocolError()
#endif
@@ -75,7 +75,7 @@ class InboundNearbyConnection: NearbyConnection{
override internal func processTransferSetupFrame(_ frame:Sharing_Nearby_Frame) throws{
if frame.hasV1 && frame.v1.hasType, case .cancel = frame.v1.type {
print("Transfer canceled")
log("Transfer canceled")
try sendDisconnectionAndDisconnect()
return
}
@@ -87,8 +87,8 @@ class InboundNearbyConnection: NearbyConnection{
case .receivedPairedKeyResult:
try processIntroductionFrame(frame)
default:
print("Unexpected connection state in processTransferSetupFrame: \(currentState)")
print(frame)
log("Unexpected connection state in processTransferSetupFrame: \(currentState)")
log(frame.debugDescription)
}
}
@@ -259,7 +259,7 @@ class InboundNearbyConnection: NearbyConnection{
try sendTransferSetupFrame(pairedEncryption)
currentState = .sentConnectionResponse
} else {
print("Unhandled offline frame plaintext: \(frame)")
log("Unhandled offline frame plaintext: \(frame)")
}
}
@@ -390,7 +390,7 @@ class InboundNearbyConnection: NearbyConnection{
try sendTransferSetupFrame(frame)
try sendDisconnectionAndDisconnect()
}catch{
print("Error \(error)")
log("Error \(error)")
protocolError()
}
}
+7 -7
View File
@@ -1,6 +1,6 @@
//
// NearbyConnection.swift
// NearDrop
// QuickDrop
//
// Created by Grishka on 09.04.2023.
//
@@ -16,7 +16,7 @@ import BigInt
class NearbyConnection{
internal static let SANE_FRAME_LENGTH=5*1024*1024
private static let dispatchQueue=DispatchQueue(label: "me.grishka.NearDrop.queue", qos: .utility) // FIFO (non-concurrent) queue to avoid those exciting concurrency bugs
private static let dispatchQueue=DispatchQueue(label: "com.leonboettger.quickdrop.queue", qos: .utility) // FIFO (non-concurrent) queue to avoid those exciting concurrency bugs
internal let connection:NWConnection
internal var remoteDeviceInfo:RemoteDeviceInfo?
@@ -57,7 +57,7 @@ class NearbyConnection{
self.receiveFrameAsync()
} else if case .failed(let err) = state {
self.lastError=err
print("Error opening socket: \(err)")
log("Error opening socket: \(err)")
self.handleConnectionClosure()
}
}
@@ -68,7 +68,7 @@ class NearbyConnection{
func connectionReady(){}
internal func handleConnectionClosure(){
print("Connection closed")
log("Connection closed")
}
internal func protocolError(){
@@ -295,11 +295,11 @@ class NearbyConnection{
}
}else if offlineFrame.hasV1 && offlineFrame.v1.hasType, case .keepAlive = offlineFrame.v1.type{
#if DEBUG
print("Sent keep-alive")
log("Sent keep-alive")
#endif
sendKeepAlive(ack: true)
}else{
print("Unhandled offline frame encrypted: \(offlineFrame)")
log("Unhandled offline frame encrypted: \(offlineFrame)")
}
}
@@ -444,7 +444,7 @@ class NearbyConnection{
sendFrameAsync(try offlineFrame.serializedData())
}
}catch{
print("Error sending KEEP_ALIVE: \(error)")
log("Error sending KEEP_ALIVE: \(error)")
}
}
}
+4 -4
View File
@@ -1,6 +1,6 @@
//
// NearbyConnectionManager.swift
// NearDrop
// QuickDrop
//
// Created by Grishka on 08.04.2023.
//
@@ -296,19 +296,19 @@ public class NearbyConnectionManager : NSObject, NetServiceDelegate, InboundNear
private func maybeAddFoundDevice(service:NWBrowser.Result){
#if DEBUG
print("found service \(service)")
log("found service \(service)")
#endif
for interface in service.interfaces{
if case .loopback=interface.type{
#if DEBUG
print("ignoring localhost service")
log("ignoring localhost service")
#endif
return
}
}
guard let endpointID=endpointID(for: service) else {return}
#if DEBUG
print("service name is valid, endpoint ID \(endpointID)")
log("service name is valid, endpoint ID \(endpointID)")
#endif
var foundService=FoundServiceInfo(service: service)
+8 -8
View File
@@ -80,7 +80,7 @@ class OutboundNearbyConnection:NearbyConnection{
override func processReceivedFrame(frameData: Data) {
do{
#if DEBUG
print("received \(frameData), state is \(currentState)")
log("received \(frameData), state is \(currentState)")
#endif
switch currentState {
case .initial:
@@ -105,12 +105,12 @@ class OutboundNearbyConnection:NearbyConnection{
override func processTransferSetupFrame(_ frame: Sharing_Nearby_Frame) throws {
if frame.hasV1 && frame.v1.hasType, case .cancel = frame.v1.type {
print("Transfer canceled")
log("Transfer canceled")
try sendDisconnectionAndDisconnect()
delegate?.outboundConnection(connection: self, failedWithError: NearbyError.canceled(reason: .userCanceled))
return
}
print(frame)
log(frame.debugDescription)
switch currentState{
case .sentPairedKeyEncryption:
try processPairedKeyEncryption(frame: frame)
@@ -224,7 +224,7 @@ class OutboundNearbyConnection:NearbyConnection{
private func processConnectionResponse(frame:Location_Nearby_Connections_OfflineFrame) throws{
#if DEBUG
print("connection response: \(frame)")
log("connection response: \(frame)")
#endif
guard frame.version == .v1 else {throw NearbyError.protocolError("Unexpected offline frame version \(frame.version)")}
guard frame.v1.type == .connectionResponse else {throw NearbyError.protocolError("Unexpected frame type \(frame.v1.type)")}
@@ -306,7 +306,7 @@ class OutboundNearbyConnection:NearbyConnection{
}
}
#if DEBUG
print("sent introduction: \(introduction)")
log("sent introduction: \(introduction)")
#endif
try sendTransferSetupFrame(introduction)
@@ -355,7 +355,7 @@ class OutboundNearbyConnection:NearbyConnection{
}
if queue.isEmpty{
#if DEBUG
print("Disconnecting because all files have been transferred")
log("Disconnecting because all files have been transferred")
#endif
try sendDisconnectionAndDisconnect()
delegate?.outboundConnectionTransferFinished(connection: self)
@@ -399,7 +399,7 @@ class OutboundNearbyConnection:NearbyConnection{
}
})
#if DEBUG
print("sent file chunk, current transfer: \(String(describing: currentTransfer))")
log("sent file chunk, current transfer: \(String(describing: currentTransfer))")
#endif
totalBytesSent+=Int64(fileBuffer.count)
delegate?.outboundConnection(connection: self, transferProgress: Double(totalBytesSent)/Double(totalBytesToSend))
@@ -422,7 +422,7 @@ class OutboundNearbyConnection:NearbyConnection{
wrapper.v1.payloadTransfer=transfer
try encryptAndSendOfflineFrame(wrapper)
#if DEBUG
print("sent EOF, current transfer: \(String(describing: currentTransfer))")
log("sent EOF, current transfer: \(String(describing: currentTransfer))")
#endif
}
}
@@ -3,22 +3,19 @@
archiveVersion = 1;
classes = {
};
objectVersion = 56;
objectVersion = 70;
objects = {
/* Begin PBXBuildFile section */
18637D0E2AC2A25300AF8072 /* NearDrop-InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 18637D0C2AC2A25300AF8072 /* NearDrop-InfoPlist.strings */; };
18637D112AC2A25300AF8072 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 18637D0F2AC2A25300AF8072 /* InfoPlist.strings */; };
691F53BB2ABB70840089FD92 /* DeviceListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 691F53B92ABB70840089FD92 /* DeviceListCell.swift */; };
691F53BC2ABB70840089FD92 /* DeviceListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 691F53BA2ABB70840089FD92 /* DeviceListCell.xib */; };
691F53BE2ABF03820089FD92 /* OutboundNearbyConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 691F53BD2ABF03820089FD92 /* OutboundNearbyConnection.swift */; };
691F53C72AC2594E0089FD92 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 691F53C52AC2594E0089FD92 /* Localizable.strings */; };
691F53CB2AC2599B0089FD92 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 691F53C92AC2599B0089FD92 /* Localizable.stringsdict */; };
698DFB0329E362140064F247 /* NDNotificationCenterHackery.m in Sources */ = {isa = PBXBuildFile; fileRef = 698DFB0229E362140064F247 /* NDNotificationCenterHackery.m */; };
699B03452AB5FBA300E0D718 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 699B03442AB5FBA300E0D718 /* Assets.xcassets */; };
699DEBA62AB0573200115D22 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 699DEBA52AB0573200115D22 /* ShareViewController.swift */; };
699DEBA92AB0573200115D22 /* ShareViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 699DEBA72AB0573200115D22 /* ShareViewController.xib */; };
699DEBAE2AB0573200115D22 /* NearDropShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 699DEBA12AB0573200115D22 /* NearDropShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
699DEBAE2AB0573200115D22 /* QuickDropShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 699DEBA12AB0573200115D22 /* QuickDropShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
69D2C32D29E77F2200EC7E30 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 69D2C32B29E77F2200EC7E30 /* Localizable.strings */; };
69D2C32F29E7898C00EC7E30 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 69D2C32E29E7898C00EC7E30 /* MainMenu.xib */; };
69D2C33829E78DF400EC7E30 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 69D2C33629E78DF400EC7E30 /* Localizable.stringsdict */; };
@@ -40,6 +37,10 @@
69DCF49C2AB8C58500CBE2CC /* SwiftECC in Frameworks */ = {isa = PBXBuildFile; productRef = 69DCF49B2AB8C58500CBE2CC /* SwiftECC */; };
69DCF49D2AB8C9A500CBE2CC /* libNearbyShare.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 69DCF4812AB70D0600CBE2CC /* libNearbyShare.dylib */; };
69DCF49E2AB8C9A500CBE2CC /* libNearbyShare.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 69DCF4812AB70D0600CBE2CC /* libNearbyShare.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
EB7CD1432D6FAEB400CB0CB5 /* UserDefaultsKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7CD1422D6FAEAF00CB0CB5 /* UserDefaultsKeys.swift */; };
EB7CD1452D6FB0C300CB0CB5 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */; };
EB7CD1462D6FB0E800CB0CB5 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */; };
EB7CD1472D6FB0E800CB0CB5 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */; };
EBD2A2172D2860C100BCB8E2 /* WelcomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBD2A2162D2860BE00BCB8E2 /* WelcomeScreen.swift */; };
/* End PBXBuildFile section */
@@ -74,7 +75,7 @@
dstPath = "";
dstSubfolderSpec = 13;
files = (
699DEBAE2AB0573200115D22 /* NearDropShareExtension.appex in Embed Foundation Extensions */,
699DEBAE2AB0573200115D22 /* QuickDropShareExtension.appex in Embed Foundation Extensions */,
);
name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0;
@@ -119,8 +120,6 @@
15C3ECC82AC269FB00FC5082 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
15C3ECC92AC269FB00FC5082 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nl; path = nl.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
15C3ECCA2AC269FB00FC5082 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
18637D0D2AC2A25300AF8072 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/NearDrop-InfoPlist.strings"; sourceTree = "<group>"; };
18637D102AC2A25300AF8072 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
1884486A2AC294C3003EC2A3 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/ShareViewController.strings"; sourceTree = "<group>"; };
1884486B2AC294C3003EC2A3 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
1884486C2AC294C3003EC2A3 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
@@ -150,11 +149,8 @@
698DFAE529E2F91A0064F247 /* NearbyConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearbyConnection.swift; sourceTree = "<group>"; };
698DFAED29E353220064F247 /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
698DFAEF29E353220064F247 /* UserNotificationsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotificationsUI.framework; path = System/Library/Frameworks/UserNotificationsUI.framework; sourceTree = SDKROOT; };
698DFB0029E362140064F247 /* NearDrop-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NearDrop-Bridging-Header.h"; sourceTree = "<group>"; };
698DFB0129E362140064F247 /* NDNotificationCenterHackery.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NDNotificationCenterHackery.h; sourceTree = "<group>"; };
698DFB0229E362140064F247 /* NDNotificationCenterHackery.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NDNotificationCenterHackery.m; sourceTree = "<group>"; };
699B03442AB5FBA300E0D718 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
699DEBA12AB0573200115D22 /* NearDropShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NearDropShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
699DEBA12AB0573200115D22 /* QuickDropShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = QuickDropShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
699DEBA52AB0573200115D22 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
699DEBA82AB0573200115D22 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ShareViewController.xib; sourceTree = "<group>"; };
699DEBAA2AB0573200115D22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -164,7 +160,7 @@
69D2C33029E789AF00EC7E30 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
69D2C33729E78DF400EC7E30 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = Base; path = Base.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
69D2C33929E78DFD00EC7E30 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = ru.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
69DA9A0E29E0BF5100A442DA /* NearDrop.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NearDrop.app; sourceTree = BUILT_PRODUCTS_DIR; };
69DA9A0E29E0BF5100A442DA /* QuickDrop.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QuickDrop.app; sourceTree = BUILT_PRODUCTS_DIR; };
69DA9A1129E0BF5100A442DA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
69DA9A1329E0BF5200A442DA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
69DA9A1829E0BF5200A442DA /* NearDrop.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NearDrop.entitlements; sourceTree = "<group>"; };
@@ -210,10 +206,16 @@
E9C8C6D52CFF66650053474D /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ro; path = ro.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
E9C8C6D62CFF66650053474D /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = "<group>"; };
EB4ACE3C2D345A0800A0AF4C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
EB7CD1422D6FAEAF00CB0CB5 /* UserDefaultsKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsKeys.swift; sourceTree = "<group>"; };
EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
EBD2A2162D2860BE00BCB8E2 /* WelcomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreen.swift; sourceTree = "<group>"; };
EBD2A2182D28619200BCB8E2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
EB7CD13B2D6F8B6500CB0CB5 /* IAP */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = IAP; sourceTree = "<group>"; };
/* End PBXFileSystemSynchronizedRootGroup section */
/* Begin PBXFrameworksBuildPhase section */
699DEB9E2AB0573200115D22 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
@@ -263,7 +265,6 @@
691F53C92AC2599B0089FD92 /* Localizable.stringsdict */,
691F53C52AC2594E0089FD92 /* Localizable.strings */,
699DEBAA2AB0573200115D22 /* Info.plist */,
18637D0F2AC2A25300AF8072 /* InfoPlist.strings */,
699DEBAB2AB0573200115D22 /* ShareExtension.entitlements */,
);
path = ShareExtension;
@@ -272,20 +273,20 @@
69DA9A0529E0BF5100A442DA = {
isa = PBXGroup;
children = (
18637D0C2AC2A25300AF8072 /* NearDrop-InfoPlist.strings */,
69DA9A1029E0BF5100A442DA /* NearDrop */,
699DEBA22AB0573200115D22 /* ShareExtension */,
69DCF4822AB70D0600CBE2CC /* NearbyShare */,
698DFAEC29E353220064F247 /* Frameworks */,
69DA9A0F29E0BF5100A442DA /* Products */,
EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */,
);
sourceTree = "<group>";
};
69DA9A0F29E0BF5100A442DA /* Products */ = {
isa = PBXGroup;
children = (
69DA9A0E29E0BF5100A442DA /* NearDrop.app */,
699DEBA12AB0573200115D22 /* NearDropShareExtension.appex */,
69DA9A0E29E0BF5100A442DA /* QuickDrop.app */,
699DEBA12AB0573200115D22 /* QuickDropShareExtension.appex */,
69DCF4812AB70D0600CBE2CC /* libNearbyShare.dylib */,
);
name = Products;
@@ -297,13 +298,12 @@
EBD2A2182D28619200BCB8E2 /* Info.plist */,
69DA9A1129E0BF5100A442DA /* AppDelegate.swift */,
EBD2A2162D2860BE00BCB8E2 /* WelcomeScreen.swift */,
EB7CD1422D6FAEAF00CB0CB5 /* UserDefaultsKeys.swift */,
EB7CD13B2D6F8B6500CB0CB5 /* IAP */,
69DA9A1329E0BF5200A442DA /* Assets.xcassets */,
69D2C33629E78DF400EC7E30 /* Localizable.stringsdict */,
69D2C32B29E77F2200EC7E30 /* Localizable.strings */,
698DFB0129E362140064F247 /* NDNotificationCenterHackery.h */,
698DFB0229E362140064F247 /* NDNotificationCenterHackery.m */,
69DA9A1829E0BF5200A442DA /* NearDrop.entitlements */,
698DFB0029E362140064F247 /* NearDrop-Bridging-Header.h */,
69D2C32E29E7898C00EC7E30 /* MainMenu.xib */,
);
path = NearDrop;
@@ -348,9 +348,9 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
699DEBA02AB0573200115D22 /* NearDropShareExtension */ = {
699DEBA02AB0573200115D22 /* QuickDropShareExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = 699DEBB12AB0573200115D22 /* Build configuration list for PBXNativeTarget "NearDropShareExtension" */;
buildConfigurationList = 699DEBB12AB0573200115D22 /* Build configuration list for PBXNativeTarget "QuickDropShareExtension" */;
buildPhases = (
699DEB9D2AB0573200115D22 /* Sources */,
699DEB9E2AB0573200115D22 /* Frameworks */,
@@ -362,14 +362,14 @@
dependencies = (
69DCF4A02AB8C9A500CBE2CC /* PBXTargetDependency */,
);
name = NearDropShareExtension;
name = QuickDropShareExtension;
productName = ShareExtension;
productReference = 699DEBA12AB0573200115D22 /* NearDropShareExtension.appex */;
productReference = 699DEBA12AB0573200115D22 /* QuickDropShareExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
69DA9A0D29E0BF5100A442DA /* NearDrop */ = {
69DA9A0D29E0BF5100A442DA /* QuickDrop */ = {
isa = PBXNativeTarget;
buildConfigurationList = 69DA9A1B29E0BF5200A442DA /* Build configuration list for PBXNativeTarget "NearDrop" */;
buildConfigurationList = 69DA9A1B29E0BF5200A442DA /* Build configuration list for PBXNativeTarget "QuickDrop" */;
buildPhases = (
69DA9A0A29E0BF5100A442DA /* Sources */,
69DA9A0B29E0BF5100A442DA /* Frameworks */,
@@ -384,11 +384,14 @@
699DEBAD2AB0573200115D22 /* PBXTargetDependency */,
69DCF4972AB8BF7B00CBE2CC /* PBXTargetDependency */,
);
name = NearDrop;
fileSystemSynchronizedGroups = (
EB7CD13B2D6F8B6500CB0CB5 /* IAP */,
);
name = QuickDrop;
packageProductDependencies = (
);
productName = NearDrop;
productReference = 69DA9A0E29E0BF5100A442DA /* NearDrop.app */;
productReference = 69DA9A0E29E0BF5100A442DA /* QuickDrop.app */;
productType = "com.apple.product-type.application";
};
69DCF4802AB70D0600CBE2CC /* NearbyShare */ = {
@@ -434,7 +437,7 @@
};
};
};
buildConfigurationList = 69DA9A0929E0BF5100A442DA /* Build configuration list for PBXProject "NearDrop" */;
buildConfigurationList = 69DA9A0929E0BF5100A442DA /* Build configuration list for PBXProject "QuickDrop" */;
compatibilityVersion = "Xcode 14.0";
developmentRegion = en;
hasScannedForEncodings = 0;
@@ -467,8 +470,8 @@
projectDirPath = "";
projectRoot = "";
targets = (
69DA9A0D29E0BF5100A442DA /* NearDrop */,
699DEBA02AB0573200115D22 /* NearDropShareExtension */,
69DA9A0D29E0BF5100A442DA /* QuickDrop */,
699DEBA02AB0573200115D22 /* QuickDropShareExtension */,
69DCF4802AB70D0600CBE2CC /* NearbyShare */,
);
};
@@ -480,7 +483,6 @@
buildActionMask = 2147483647;
files = (
699B03452AB5FBA300E0D718 /* Assets.xcassets in Resources */,
18637D112AC2A25300AF8072 /* InfoPlist.strings in Resources */,
691F53C72AC2594E0089FD92 /* Localizable.strings in Resources */,
691F53BC2ABB70840089FD92 /* DeviceListCell.xib in Resources */,
691F53CB2AC2599B0089FD92 /* Localizable.stringsdict in Resources */,
@@ -495,7 +497,6 @@
69DA9A1429E0BF5200A442DA /* Assets.xcassets in Resources */,
69D2C33829E78DF400EC7E30 /* Localizable.stringsdict in Resources */,
69D2C32D29E77F2200EC7E30 /* Localizable.strings in Resources */,
18637D0E2AC2A25300AF8072 /* NearDrop-InfoPlist.strings in Resources */,
69D2C32F29E7898C00EC7E30 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -508,6 +509,7 @@
buildActionMask = 2147483647;
files = (
699DEBA62AB0573200115D22 /* ShareViewController.swift in Sources */,
EB7CD1462D6FB0E800CB0CB5 /* Logger.swift in Sources */,
691F53BB2ABB70840089FD92 /* DeviceListCell.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -517,8 +519,9 @@
buildActionMask = 2147483647;
files = (
EBD2A2172D2860C100BCB8E2 /* WelcomeScreen.swift in Sources */,
698DFB0329E362140064F247 /* NDNotificationCenterHackery.m in Sources */,
EB7CD1432D6FAEB400CB0CB5 /* UserDefaultsKeys.swift in Sources */,
69DA9A1229E0BF5100A442DA /* AppDelegate.swift in Sources */,
EB7CD1452D6FB0C300CB0CB5 /* Logger.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -533,6 +536,7 @@
69DCF48E2AB70E8C00CBE2CC /* securegcm.pb.swift in Sources */,
691F53BE2ABF03820089FD92 /* OutboundNearbyConnection.swift in Sources */,
69DCF48C2AB70E8C00CBE2CC /* device_to_device_messages.pb.swift in Sources */,
EB7CD1472D6FB0E800CB0CB5 /* Logger.swift in Sources */,
69DCF4902AB70E9700CBE2CC /* InboundNearbyConnection.swift in Sources */,
69DCF48B2AB70E8C00CBE2CC /* ukey.pb.swift in Sources */,
69DCF48A2AB70E8C00CBE2CC /* wire_format.pb.swift in Sources */,
@@ -545,7 +549,7 @@
/* Begin PBXTargetDependency section */
699DEBAD2AB0573200115D22 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 699DEBA02AB0573200115D22 /* NearDropShareExtension */;
target = 699DEBA02AB0573200115D22 /* QuickDropShareExtension */;
targetProxy = 699DEBAC2AB0573200115D22 /* PBXContainerItemProxy */;
};
69DCF4972AB8BF7B00CBE2CC /* PBXTargetDependency */ = {
@@ -561,23 +565,6 @@
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
18637D0C2AC2A25300AF8072 /* NearDrop-InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
18637D0D2AC2A25300AF8072 /* zh-Hans */,
);
name = "NearDrop-InfoPlist.strings";
path = NearDrop;
sourceTree = "<group>";
};
18637D0F2AC2A25300AF8072 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
18637D102AC2A25300AF8072 /* zh-Hans */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
691F53C52AC2594E0089FD92 /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
@@ -687,13 +674,13 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5;
CURRENT_PROJECT_VERSION = "${SHARED_BUILD}";
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 92SDAWLN76;
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = NearDrop;
INFOPLIST_KEY_CFBundleDisplayName = QuickDrop;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -701,7 +688,7 @@
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.1;
MARKETING_VERSION = "${SHARED_VERSION}";
PRODUCT_BUNDLE_IDENTIFIER = com.leonboettger.neardrop.ShareExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -716,13 +703,13 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5;
CURRENT_PROJECT_VERSION = "${SHARED_BUILD}";
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 92SDAWLN76;
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = NearDrop;
INFOPLIST_KEY_CFBundleDisplayName = QuickDrop;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -730,7 +717,7 @@
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.1;
MARKETING_VERSION = "${SHARED_VERSION}";
PRODUCT_BUNDLE_IDENTIFIER = com.leonboettger.neardrop.ShareExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -798,6 +785,8 @@
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SHARED_BUILD = 7;
SHARED_VERSION = 1.2;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
@@ -855,6 +844,8 @@
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SHARED_BUILD = 7;
SHARED_VERSION = 1.2;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
@@ -867,18 +858,19 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = NearDrop/NearDrop.entitlements;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5;
CURRENT_PROJECT_VERSION = "${SHARED_BUILD}";
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 92SDAWLN76;
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = NearDrop/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = NearDrop;
INFOPLIST_KEY_CFBundleDisplayName = QuickDrop;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
INFOPLIST_KEY_LSUIElement = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSHumanReadableCopyright = "2025 Leon Böttger - Huge thanks to developers of NearDrop";
INFOPLIST_KEY_NSMainNibFile = MainMenu;
INFOPLIST_KEY_NSPrincipalClass = NSApplication;
LD_RUNPATH_SEARCH_PATHS = (
@@ -886,11 +878,11 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.1;
MARKETING_VERSION = "${SHARED_VERSION}";
PRODUCT_BUNDLE_IDENTIFIER = com.leonboettger.neardrop;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "NearDrop/NearDrop-Bridging-Header.h";
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
@@ -903,18 +895,19 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = NearDrop/NearDrop.entitlements;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5;
CURRENT_PROJECT_VERSION = "${SHARED_BUILD}";
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 92SDAWLN76;
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = NearDrop/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = NearDrop;
INFOPLIST_KEY_CFBundleDisplayName = QuickDrop;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
INFOPLIST_KEY_LSUIElement = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSHumanReadableCopyright = "2025 Leon Böttger - Huge thanks to developers of NearDrop";
INFOPLIST_KEY_NSMainNibFile = MainMenu;
INFOPLIST_KEY_NSPrincipalClass = NSApplication;
LD_RUNPATH_SEARCH_PATHS = (
@@ -922,11 +915,11 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.1;
MARKETING_VERSION = "${SHARED_VERSION}";
PRODUCT_BUNDLE_IDENTIFIER = com.leonboettger.neardrop;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "NearDrop/NearDrop-Bridging-Header.h";
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_VERSION = 5.0;
};
name = Release;
@@ -968,7 +961,7 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
699DEBB12AB0573200115D22 /* Build configuration list for PBXNativeTarget "NearDropShareExtension" */ = {
699DEBB12AB0573200115D22 /* Build configuration list for PBXNativeTarget "QuickDropShareExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
699DEBAF2AB0573200115D22 /* Debug */,
@@ -977,7 +970,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
69DA9A0929E0BF5100A442DA /* Build configuration list for PBXProject "NearDrop" */ = {
69DA9A0929E0BF5100A442DA /* Build configuration list for PBXProject "QuickDrop" */ = {
isa = XCConfigurationList;
buildConfigurations = (
69DA9A1929E0BF5200A442DA /* Debug */,
@@ -986,7 +979,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
69DA9A1B29E0BF5200A442DA /* Build configuration list for PBXNativeTarget "NearDrop" */ = {
69DA9A1B29E0BF5200A442DA /* Build configuration list for PBXNativeTarget "QuickDrop" */ = {
isa = XCConfigurationList;
buildConfigurations = (
69DA9A1C29E0BF5200A442DA /* Debug */,
@@ -4,7 +4,8 @@
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
@@ -15,9 +16,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "69DA9A0D29E0BF5100A442DA"
BuildableName = "NearDrop.app"
BlueprintName = "NearDrop"
ReferencedContainer = "container:NearDrop.xcodeproj">
BuildableName = "QuickDrop.app"
BlueprintName = "QuickDrop"
ReferencedContainer = "container:QuickDrop.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@@ -33,7 +34,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = "de"
language = "en"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
@@ -45,9 +46,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "69DA9A0D29E0BF5100A442DA"
BuildableName = "NearDrop.app"
BlueprintName = "NearDrop"
ReferencedContainer = "container:NearDrop.xcodeproj">
BuildableName = "QuickDrop.app"
BlueprintName = "QuickDrop"
ReferencedContainer = "container:QuickDrop.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
@@ -62,9 +63,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "69DA9A0D29E0BF5100A442DA"
BuildableName = "NearDrop.app"
BlueprintName = "NearDrop"
ReferencedContainer = "container:NearDrop.xcodeproj">
BuildableName = "QuickDrop.app"
BlueprintName = "QuickDrop"
ReferencedContainer = "container:QuickDrop.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
@@ -16,9 +16,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "699DEBA02AB0573200115D22"
BuildableName = "NearDropShareExtension.appex"
BlueprintName = "NearDropShareExtension"
ReferencedContainer = "container:NearDrop.xcodeproj">
BuildableName = "QuickDropShareExtension.appex"
BlueprintName = "QuickDropShareExtension"
ReferencedContainer = "container:QuickDrop.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
@@ -30,9 +30,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "69DA9A0D29E0BF5100A442DA"
BuildableName = "NearDrop.app"
BlueprintName = "NearDrop"
ReferencedContainer = "container:NearDrop.xcodeproj">
BuildableName = "QuickDrop.app"
BlueprintName = "QuickDrop"
ReferencedContainer = "container:QuickDrop.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@@ -60,9 +60,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "69DA9A0D29E0BF5100A442DA"
BuildableName = "NearDrop.app"
BlueprintName = "NearDrop"
ReferencedContainer = "container:NearDrop.xcodeproj">
BuildableName = "QuickDrop.app"
BlueprintName = "QuickDrop"
ReferencedContainer = "container:QuickDrop.xcodeproj">
</BuildableReference>
</MacroExpansion>
</LaunchAction>
@@ -79,9 +79,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "69DA9A0D29E0BF5100A442DA"
BuildableName = "NearDrop.app"
BlueprintName = "NearDrop"
ReferencedContainer = "container:NearDrop.xcodeproj">
BuildableName = "QuickDrop.app"
BlueprintName = "QuickDrop"
ReferencedContainer = "container:QuickDrop.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
File renamed without changes.

Before

Width:  |  Height:  |  Size: 752 KiB

After

Width:  |  Height:  |  Size: 752 KiB

@@ -47,7 +47,7 @@ Gw
</connections>
</button>
<stackView distribution="fill" orientation="horizontal" alignment="top" spacing="5" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1xF-vr-5sH">
<rect key="frame" x="160" y="222" width="84" height="16"/>
<rect key="frame" x="157" y="222" width="90" height="16"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="4M6-D5-WIf">
<rect key="frame" x="0.0" y="0.0" width="16" height="16"/>
@@ -55,11 +55,11 @@ Gw
<constraint firstAttribute="width" constant="16" id="BOe-aZ-Njc"/>
<constraint firstAttribute="height" constant="16" id="zLg-1a-wlZ"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NearDropIcon" id="q3u-Am-ZIA"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="QuickDropIcon" id="q3u-Am-ZIA"/>
</imageView>
<textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aNc-0i-CWK">
<rect key="frame" x="19" y="0.0" width="67" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="NearDrop" allowsEditingTextAttributes="YES" id="0xp-rC-2gr">
<rect key="frame" x="19" y="0.0" width="73" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="QuickDrop" allowsEditingTextAttributes="YES" id="0xp-rC-2gr">
<font key="font" metaFont="systemBold"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
@@ -234,7 +234,7 @@ Gw
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<clipView key="contentView" id="cCr-8P-Lya">
<rect key="frame" x="1" y="1" width="269" height="170"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<collectionView id="gZI-Zb-Blx">
<rect key="frame" x="0.0" y="0.0" width="269" height="170"/>
@@ -259,6 +259,6 @@ Gw
</objects>
<resources>
<image name="NSCaution" width="32" height="32"/>
<image name="NearDropIcon" width="1024" height="1024"/>
<image name="QuickDropIcon" width="1024" height="1024"/>
</resources>
</document>
+1 -1
View File
@@ -127,7 +127,7 @@ class ShareViewController: NSViewController, ShareExtensionDelegate{
if url.isFileURL{
let isDirectory=UnsafeMutablePointer<ObjCBool>.allocate(capacity: 1)
if FileManager.default.fileExists(atPath: url.path, isDirectory: isDirectory) && isDirectory.pointee.boolValue{
print("Canceling share request because URL \(url) is a directory")
log("Canceling share request because URL \(url) is a directory")
let cancelError = NSError(domain: NSCocoaErrorDomain, code: NSUserCancelledError, userInfo: nil)
self.extensionContext!.cancelRequest(withError: cancelError)
return
@@ -1,5 +1,5 @@
/* Class = "NSTextFieldCell"; title = "NearDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "NearDrop";
/* Class = "NSTextFieldCell"; title = "QuickDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "QuickDrop";
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "6Up-t3-mwm"; */
"6Up-t3-mwm.title" = "إلغاء";
Binary file not shown.
@@ -1,6 +1,6 @@
/* Class = "NSTextFieldCell"; title = "NearDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "NearDrop";
/* Class = "NSTextFieldCell"; title = "QuickDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "QuickDrop";
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "6Up-t3-mwm"; */
"6Up-t3-mwm.title" = "キャンセル";
@@ -1,6 +1,6 @@
/* Class = "NSTextFieldCell"; title = "NearDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "NearDrop";
/* Class = "NSTextFieldCell"; title = "QuickDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "QuickDrop";
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "6Up-t3-mwm"; */
"6Up-t3-mwm.title" = "취소";
@@ -1,6 +1,6 @@
/* Class = "NSTextFieldCell"; title = "NearDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "NearDrop";
/* Class = "NSTextFieldCell"; title = "QuickDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "QuickDrop";
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "6Up-t3-mwm"; */
"6Up-t3-mwm.title" = "Annuleren";
@@ -1,6 +1,6 @@
/* Class = "NSTextFieldCell"; title = "NearDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "NearDrop";
/* Class = "NSTextFieldCell"; title = "QuickDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "QuickDrop";
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "6Up-t3-mwm"; */
"6Up-t3-mwm.title" = "Cancelar";
@@ -1,6 +1,6 @@
/* Class = "NSTextFieldCell"; title = "NearDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "NearDrop";
/* Class = "NSTextFieldCell"; title = "QuickDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "QuickDrop";
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "6Up-t3-mwm"; */
"6Up-t3-mwm.title" = "Anulare";
@@ -1,6 +1,6 @@
/* Class = "NSTextFieldCell"; title = "NearDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "NearDrop";
/* Class = "NSTextFieldCell"; title = "QuickDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "QuickDrop";
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "6Up-t3-mwm"; */
"6Up-t3-mwm.title" = "Отменить";
@@ -1,6 +1,6 @@
/* Class = "NSTextFieldCell"; title = "NearDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "NearDrop";
/* Class = "NSTextFieldCell"; title = "QuickDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "QuickDrop";
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "6Up-t3-mwm"; */
"6Up-t3-mwm.title" = "Скасувати";
@@ -1,6 +0,0 @@
/* Bundle display name */
"CFBundleDisplayName" = "NearDrop 分享";
/* Bundle name */
"CFBundleName" = "分享扩展";
@@ -1,5 +1,5 @@
/* Class = "NSTextFieldCell"; title = "NearDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "NearDrop";
/* Class = "NSTextFieldCell"; title = "QuickDrop"; ObjectID = "0xp-rC-2gr"; */
"0xp-rC-2gr.title" = "QuickDrop";
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "6Up-t3-mwm"; */
"6Up-t3-mwm.title" = "取消";