mirror of
https://github.com/leonboe1/QuickDrop.git
synced 2026-11-11 11:01:07 +00:00
Add StoreKit 2
This commit is contained in:
1 parent
488f898d7b
commit
f5e3c88daf
43 files changed
+2389
-5303
No files matched your search
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"appPolicies" : {
|
||||
"eula" : "",
|
||||
"policies" : [
|
||||
{
|
||||
"locale" : "en_US",
|
||||
"policyText" : "",
|
||||
"policyURL" : ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"identifier" : "E6E18FE5",
|
||||
"nonRenewingSubscriptions" : [
|
||||
|
||||
],
|
||||
"products" : [
|
||||
{
|
||||
"displayPrice" : "4.99",
|
||||
"familyShareable" : true,
|
||||
"internalID" : "E7870357",
|
||||
"localizations" : [
|
||||
{
|
||||
"description" : "Unlock all settings!",
|
||||
"displayName" : "QuickDrop+ Lifetime",
|
||||
"locale" : "en_US"
|
||||
}
|
||||
],
|
||||
"productID" : "plusversion",
|
||||
"referenceName" : "QuickDrop+",
|
||||
"type" : "NonConsumable"
|
||||
}
|
||||
],
|
||||
"settings" : {
|
||||
"_askToBuyEnabled" : false,
|
||||
"_billingGracePeriodEnabled" : false,
|
||||
"_billingIssuesEnabled" : false,
|
||||
"_disableDialogs" : false,
|
||||
"_failTransactionsEnabled" : false,
|
||||
"_locale" : "en_US",
|
||||
"_renewalBillingIssuesEnabled" : false,
|
||||
"_storefront" : "USA",
|
||||
"_storeKitErrors" : [
|
||||
|
||||
],
|
||||
"_timeRate" : 0
|
||||
},
|
||||
"subscriptionGroups" : [
|
||||
{
|
||||
"id" : "DBA408BD",
|
||||
"localizations" : [
|
||||
|
||||
],
|
||||
"name" : "QuickDrop+",
|
||||
"subscriptions" : [
|
||||
{
|
||||
"adHocOffers" : [
|
||||
|
||||
],
|
||||
"codeOffers" : [
|
||||
|
||||
],
|
||||
"displayPrice" : "4.99",
|
||||
"familyShareable" : true,
|
||||
"groupNumber" : 1,
|
||||
"internalID" : "514B2EA4",
|
||||
"introductoryOffer" : {
|
||||
"internalID" : "D44066CC",
|
||||
"paymentMode" : "free",
|
||||
"subscriptionPeriod" : "P3D"
|
||||
},
|
||||
"localizations" : [
|
||||
{
|
||||
"description" : "Unlock all settings!",
|
||||
"displayName" : "QuickDrop+ (1 Year)",
|
||||
"locale" : "en_US"
|
||||
}
|
||||
],
|
||||
"productID" : "quickdrop.yearly",
|
||||
"recurringSubscriptionPeriod" : "P1Y",
|
||||
"referenceName" : "QuickDrop+",
|
||||
"subscriptionGroupID" : "DBA408BD",
|
||||
"type" : "RecurringSubscription",
|
||||
"winbackOffers" : [
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"version" : {
|
||||
"major" : 4,
|
||||
"minor" : 0
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import Network
|
||||
import System
|
||||
import BigInt
|
||||
import SwiftECC
|
||||
import LUI
|
||||
|
||||
#if os(macOS)
|
||||
import AppKit
|
||||
|
||||
@@ -12,6 +12,7 @@ import Network
|
||||
import System
|
||||
import BigInt
|
||||
import SwiftECC
|
||||
import LUI
|
||||
|
||||
class NearbyConnection {
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import SwiftECC
|
||||
import CryptoKit
|
||||
import SwiftUI
|
||||
import QRCode
|
||||
import LUI
|
||||
|
||||
public class NearbyConnectionManager: NSObject, NetServiceDelegate, InboundNearbyConnectionDelegate, OutboundNearbyConnectionDelegate, ObservableObject {
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ import UniformTypeIdentifiers
|
||||
import BigInt
|
||||
import SwiftECC
|
||||
import ASN1
|
||||
import BigInt // required dependency of ASN1
|
||||
import BigInt
|
||||
import LUI
|
||||
|
||||
|
||||
class OutboundNearbyConnection: NearbyConnection {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import Foundation
|
||||
import ImageIO
|
||||
import LUI
|
||||
|
||||
struct EXIFUtils {
|
||||
|
||||
|
||||
@@ -111,8 +111,7 @@ extension String {
|
||||
|
||||
|
||||
public func fullVersion() -> Bool {
|
||||
// Enable full functionality if app distributed directly
|
||||
return Settings.shared.gotPlus || DistributionDetector.isDirectDistributionEnabled
|
||||
return Settings.shared.gotPlus
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import Foundation
|
||||
import SwiftECC
|
||||
import Security
|
||||
import CryptoKit
|
||||
import LUI
|
||||
|
||||
class IdentityManager {
|
||||
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
//
|
||||
// Logger.swift
|
||||
// QuickDrop
|
||||
//
|
||||
// Created by Leon Böttger on 26.02.25.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import os
|
||||
|
||||
fileprivate let loggerQueue = DispatchQueue(label: "loggerQueue", qos: .utility)
|
||||
|
||||
/// Manages logging functionality
|
||||
final class LogManager {
|
||||
|
||||
/// The URL of the log file
|
||||
let logFileURL: URL?
|
||||
|
||||
/// Shared instance
|
||||
public static let sharedInstance = LogManager()
|
||||
|
||||
@Published var loggingEnabled = true
|
||||
|
||||
|
||||
/// Private initializer
|
||||
private init() {
|
||||
// Use the App Group container
|
||||
let directory = AppGroup.appGroupDirectory
|
||||
|
||||
// Create file name from date
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "dd-MM-yyyy"
|
||||
let dateString = formatter.string(from: Date())
|
||||
let fileName = "\(dateString).log"
|
||||
|
||||
// Full path in app group container
|
||||
self.logFileURL = directory?.appendingPathComponent(fileName)
|
||||
}
|
||||
|
||||
|
||||
/// Writes a specified string to the log file.
|
||||
func writeToFile(string: String) {
|
||||
guard let logFileURL = logFileURL else { return }
|
||||
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "HH:mm:ss"
|
||||
let timestamp = formatter.string(from: Date())
|
||||
guard let data = (timestamp + " - " + string + "\n").data(using: .utf8) else { return }
|
||||
|
||||
loggerQueue.async {
|
||||
let fileManager = FileManager.default
|
||||
|
||||
if !fileManager.fileExists(atPath: logFileURL.path) {
|
||||
// Clean up older logs
|
||||
self.deleteLogs()
|
||||
// Create file atomically
|
||||
try? data.write(to: logFileURL, options: .atomicWrite)
|
||||
return
|
||||
}
|
||||
|
||||
// Atomic append with file locking using FileHandle
|
||||
do {
|
||||
let fileHandle = try FileHandle(forWritingTo: logFileURL)
|
||||
defer { try? fileHandle.close() }
|
||||
|
||||
// Locking is handled by the serial dispatch queue
|
||||
try fileHandle.seekToEnd()
|
||||
try fileHandle.write(contentsOf: data)
|
||||
} catch {
|
||||
print("[Logger] Failed to write to log file: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Gets the contents of the log file.
|
||||
func getLogString() -> String {
|
||||
guard let logFileURL = logFileURL else { return "" }
|
||||
do {
|
||||
return try String(contentsOf: logFileURL, encoding: .utf8)
|
||||
} catch {
|
||||
log("[LUI] Error reading file: \(error.localizedDescription)")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Deletes all log files in the shared container.
|
||||
func deleteLogs() {
|
||||
log("[LUI] Deleting all logs...")
|
||||
|
||||
guard let directory = AppGroup.appGroupDirectory else { return }
|
||||
let fileManager = FileManager.default
|
||||
|
||||
guard let allFiles = try? fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil) else {
|
||||
return
|
||||
}
|
||||
|
||||
let logFiles = allFiles.filter { $0.pathExtension == "log" }
|
||||
for file in logFiles {
|
||||
do {
|
||||
log("[LUI] Removing \(file.lastPathComponent)")
|
||||
try fileManager.removeItem(at: file)
|
||||
} catch {
|
||||
print("[Logger] Failed to delete file: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Logs a specified string
|
||||
public func log(_ text: String) {
|
||||
let logger = LogManager.sharedInstance
|
||||
|
||||
if logger.loggingEnabled {
|
||||
loggerQueue.async {
|
||||
print(text)
|
||||
#if !os(tvOS)
|
||||
let isAppExtension = Bundle.main.bundlePath.hasSuffix(".appex")
|
||||
let prefix = isAppExtension ? "[EXT]" : "[APP]"
|
||||
logger.writeToFile(string: "\(prefix) \(text)")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import IOKit.pwr_mgt
|
||||
#elseif os(iOS)
|
||||
import UIKit
|
||||
#endif
|
||||
import LUI
|
||||
|
||||
class SleepManager {
|
||||
public static let shared = SleepManager()
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
EB16B77A2E59BAA1007D9792 /* AppGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB16B7762E59BA9F007D9792 /* AppGroup.swift */; };
|
||||
EB2F9BFE2DA05F48004010A2 /* BezelNotification in Frameworks */ = {isa = PBXBuildFile; productRef = EB2F9BFD2DA05F48004010A2 /* BezelNotification */; };
|
||||
EB3643602D73A2A2009CDFF8 /* AudioManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB36435F2D73A29F009CDFF8 /* AudioManager.swift */; };
|
||||
EB4F9D1D2EC113EA00A74A0F /* DistributionDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB704A812E4A7BAE008E608F /* DistributionDetector.swift */; };
|
||||
EB4F9D1F2EC26C8100A74A0F /* EXIFUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB4F9D1E2EC26C7C00A74A0F /* EXIFUtils.swift */; };
|
||||
EB4F9D202EC26C8100A74A0F /* EXIFUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB4F9D1E2EC26C7C00A74A0F /* EXIFUtils.swift */; };
|
||||
EB4F9D212EC26C8100A74A0F /* EXIFUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB4F9D1E2EC26C7C00A74A0F /* EXIFUtils.swift */; };
|
||||
@@ -98,7 +97,6 @@
|
||||
EB5C37FA2E377CE70052EFD7 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB2F9BFA2DA04B67004010A2 /* Helpers.swift */; };
|
||||
EB5C37FB2E377CE70052EFD7 /* InboundNearbyConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A2229E17F0400A442DA /* InboundNearbyConnection.swift */; };
|
||||
EB5C37FC2E377CE70052EFD7 /* OutboundNearbyConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 691F53BD2ABF03820089FD92 /* OutboundNearbyConnection.swift */; };
|
||||
EB5C37FD2E377CE70052EFD7 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */; };
|
||||
EB5C37FE2E377CE70052EFD7 /* offline_wire_formats.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A2B29E18CB500A442DA /* offline_wire_formats.pb.swift */; };
|
||||
EB5C37FF2E377CE70052EFD7 /* wire_format.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A2929E18CB500A442DA /* wire_format.pb.swift */; };
|
||||
EB5C38002E377CE70052EFD7 /* DataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB5C36E82E3546100052EFD7 /* DataModel.swift */; };
|
||||
@@ -115,17 +113,12 @@
|
||||
EB6E6B212ECBA95000E71D57 /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = EB6E6B202ECBA95000E71D57 /* InfoPlist.xcstrings */; };
|
||||
EB6E6B222ECBA95000E71D57 /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = EB6E6B202ECBA95000E71D57 /* InfoPlist.xcstrings */; };
|
||||
EB6F62D72D91F4AF00534EC2 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB6F62D62D91F4AC00534EC2 /* SettingsView.swift */; };
|
||||
EB704A822E4A7BB3008E608F /* DistributionDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB704A812E4A7BAE008E608F /* DistributionDetector.swift */; };
|
||||
EB704A832E4B10D4008E608F /* DistributionDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB704A812E4A7BAE008E608F /* DistributionDetector.swift */; };
|
||||
EB704A842E4B10D4008E608F /* DistributionDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB704A812E4A7BAE008E608F /* DistributionDetector.swift */; };
|
||||
EB721F242E75AFA900F2099F /* QuickDropIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = EB721F232E75AFA900F2099F /* QuickDropIcon.icon */; };
|
||||
EB721F252E75AFA900F2099F /* QuickDropIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = EB721F232E75AFA900F2099F /* QuickDropIcon.icon */; };
|
||||
EB7654782E525ACC006B4AA3 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = EB7654772E525ACC006B4AA3 /* MainMenu.xib */; };
|
||||
EB7654A12E53252D006B4AA3 /* AttachmentDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB950B762E521712002D68FA /* AttachmentDetails.swift */; };
|
||||
EB7654C02E534A8E006B4AA3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 69DA9A1329E0BF5200A442DA /* Assets.xcassets */; };
|
||||
EB7654C12E534A8E006B4AA3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 69DA9A1329E0BF5200A442DA /* Assets.xcassets */; };
|
||||
EB7CD1452D6FB0C300CB0CB5 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */; };
|
||||
EB7CD1462D6FB0E800CB0CB5 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */; };
|
||||
EB7F54122D78E96000989564 /* TutorialView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7F54112D78E95C00989564 /* TutorialView.swift */; };
|
||||
EB7F54142D78E9E700989564 /* LicenseWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7F54132D78E9E400989564 /* LicenseWindow.swift */; };
|
||||
EB821C992E76FE5300036963 /* SmallSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8A2D7F7CF4004B3FF1 /* SmallSheetView.swift */; };
|
||||
@@ -157,7 +150,6 @@
|
||||
EB950B4B2E520436002D68FA /* offline_wire_formats.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A2B29E18CB500A442DA /* offline_wire_formats.pb.swift */; };
|
||||
EB950B4C2E520436002D68FA /* InboundNearbyConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A2229E17F0400A442DA /* InboundNearbyConnection.swift */; };
|
||||
EB950B4D2E520436002D68FA /* NearbyConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 698DFAE529E2F91A0064F247 /* NearbyConnection.swift */; };
|
||||
EB950B4F2E520436002D68FA /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */; };
|
||||
EB950B502E520436002D68FA /* wire_format.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A2929E18CB500A442DA /* wire_format.pb.swift */; };
|
||||
EB950B512E520436002D68FA /* securemessage.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A2D29E18CB500A442DA /* securemessage.pb.swift */; };
|
||||
EB950B522E520436002D68FA /* NearbyConnectionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A1E29E0C0B300A442DA /* NearbyConnectionManager.swift */; };
|
||||
@@ -211,9 +203,6 @@
|
||||
EBBEE1462EC9D93400AA7831 /* PhotoManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBBEE1452EC9D92F00AA7831 /* PhotoManager.swift */; };
|
||||
EBC05C5B2E33937200EECC18 /* ErrorAlertHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBC05C5A2E33936C00EECC18 /* ErrorAlertHandler.swift */; };
|
||||
EBC05C5C2E3394EF00EECC18 /* ErrorAlertHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBC05C5A2E33936C00EECC18 /* ErrorAlertHandler.swift */; };
|
||||
EBC05C712E33B57D00EECC18 /* Converter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBC05C6D2E33B57D00EECC18 /* Converter.swift */; };
|
||||
EBC05C722E33B57D00EECC18 /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBC05C6E2E33B57D00EECC18 /* Helper.swift */; };
|
||||
EBC05C732E33B57D00EECC18 /* PlusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBC05C6F2E33B57D00EECC18 /* PlusView.swift */; };
|
||||
EBC05C822E33B58300EECC18 /* ApIsolationIssueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBC05C7D2E33B58300EECC18 /* ApIsolationIssueView.swift */; };
|
||||
EBC05C832E33B58300EECC18 /* FirewallIssueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBC05C7E2E33B58300EECC18 /* FirewallIssueView.swift */; };
|
||||
EBC05C842E33B58300EECC18 /* IssueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBC05C7F2E33B58300EECC18 /* IssueView.swift */; };
|
||||
@@ -225,6 +214,15 @@
|
||||
EBC05C8C2E33B59E00EECC18 /* timeIsNow.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = EBC05C8A2E33B59E00EECC18 /* timeIsNow.mp3 */; };
|
||||
EBCC27F92D80C9F90079C478 /* Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBCC27F82D80C9F70079C478 /* Zip.swift */; };
|
||||
EBD2A2172D2860C100BCB8E2 /* WelcomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBD2A2162D2860BE00BCB8E2 /* WelcomeScreen.swift */; };
|
||||
EBE5FF3F2EDB6F550019B380 /* LUI in Frameworks */ = {isa = PBXBuildFile; productRef = EBE5FF3E2EDB6F550019B380 /* LUI */; };
|
||||
EBE5FF412EDB6F5D0019B380 /* LUI in Frameworks */ = {isa = PBXBuildFile; productRef = EBE5FF402EDB6F5D0019B380 /* LUI */; };
|
||||
EBE5FF422EDB6F6F0019B380 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB979F8D2E50CA23008B8C5C /* Configuration.swift */; };
|
||||
EBE5FF432EDB71810019B380 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB979F8D2E50CA23008B8C5C /* Configuration.swift */; };
|
||||
EBE5FF442EDB877C0019B380 /* License.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB886E662E4F2F7C0052B7D9 /* License.swift */; };
|
||||
EBE5FF4B2EDB8D4B0019B380 /* Config.storekit in Resources */ = {isa = PBXBuildFile; fileRef = EBE5FF4A2EDB8D4B0019B380 /* Config.storekit */; };
|
||||
EBE5FF4C2EDB8D4B0019B380 /* Config.storekit in Resources */ = {isa = PBXBuildFile; fileRef = EBE5FF4A2EDB8D4B0019B380 /* Config.storekit */; };
|
||||
EBE5FF4D2EDB8D4B0019B380 /* Config.storekit in Resources */ = {isa = PBXBuildFile; fileRef = EBE5FF4A2EDB8D4B0019B380 /* Config.storekit */; };
|
||||
EBE5FF4E2EDB8D4B0019B380 /* Config.storekit in Resources */ = {isa = PBXBuildFile; fileRef = EBE5FF4A2EDB8D4B0019B380 /* Config.storekit */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -347,10 +345,8 @@
|
||||
EB5C383E2E38C49D0052EFD7 /* LaunchAtLogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAtLogin.swift; sourceTree = "<group>"; };
|
||||
EB6E6B202ECBA95000E71D57 /* InfoPlist.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = InfoPlist.xcstrings; sourceTree = "<group>"; };
|
||||
EB6F62D62D91F4AC00534EC2 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
||||
EB704A812E4A7BAE008E608F /* DistributionDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DistributionDetector.swift; sourceTree = "<group>"; };
|
||||
EB721F232E75AFA900F2099F /* QuickDropIcon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = QuickDropIcon.icon; sourceTree = "<group>"; };
|
||||
EB7654772E525ACC006B4AA3 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = "<group>"; };
|
||||
EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
|
||||
EB7F54112D78E95C00989564 /* TutorialView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TutorialView.swift; sourceTree = "<group>"; };
|
||||
EB7F54132D78E9E400989564 /* LicenseWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicenseWindow.swift; sourceTree = "<group>"; };
|
||||
EB869DB42E92AA33009AAAD4 /* QuickDropToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickDropToastView.swift; sourceTree = "<group>"; };
|
||||
@@ -378,9 +374,6 @@
|
||||
EBBC93B12EC8B75F00F541A1 /* LocalNetworkPermissionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNetworkPermissionView.swift; sourceTree = "<group>"; };
|
||||
EBBEE1452EC9D92F00AA7831 /* PhotoManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoManager.swift; sourceTree = "<group>"; };
|
||||
EBC05C5A2E33936C00EECC18 /* ErrorAlertHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorAlertHandler.swift; sourceTree = "<group>"; };
|
||||
EBC05C6D2E33B57D00EECC18 /* Converter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Converter.swift; sourceTree = "<group>"; };
|
||||
EBC05C6E2E33B57D00EECC18 /* Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helper.swift; sourceTree = "<group>"; };
|
||||
EBC05C6F2E33B57D00EECC18 /* PlusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlusView.swift; sourceTree = "<group>"; };
|
||||
EBC05C7D2E33B58300EECC18 /* ApIsolationIssueView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApIsolationIssueView.swift; sourceTree = "<group>"; };
|
||||
EBC05C7E2E33B58300EECC18 /* FirewallIssueView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirewallIssueView.swift; sourceTree = "<group>"; };
|
||||
EBC05C7F2E33B58300EECC18 /* IssueView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssueView.swift; sourceTree = "<group>"; };
|
||||
@@ -388,6 +381,7 @@
|
||||
EBC05C8A2E33B59E00EECC18 /* timeIsNow.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = timeIsNow.mp3; sourceTree = "<group>"; };
|
||||
EBCC27F82D80C9F70079C478 /* Zip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Zip.swift; sourceTree = "<group>"; };
|
||||
EBD2A2162D2860BE00BCB8E2 /* WelcomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreen.swift; sourceTree = "<group>"; };
|
||||
EBE5FF4A2EDB8D4B0019B380 /* Config.storekit */ = {isa = PBXFileReference; lastKnownFileType = text; path = Config.storekit; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -396,6 +390,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
EB5C37D82E377ACF0052EFD7 /* SwiftECC in Frameworks */,
|
||||
EBE5FF412EDB6F5D0019B380 /* LUI in Frameworks */,
|
||||
EB5C37D62E377ACF0052EFD7 /* SwiftProtobuf in Frameworks */,
|
||||
EB9925852E45EF0900357055 /* QRCode in Frameworks */,
|
||||
);
|
||||
@@ -409,6 +404,7 @@
|
||||
EB2F9BFE2DA05F48004010A2 /* BezelNotification in Frameworks */,
|
||||
EB5C37DC2E377AD60052EFD7 /* SwiftECC in Frameworks */,
|
||||
EB5C37DA2E377AD60052EFD7 /* SwiftProtobuf in Frameworks */,
|
||||
EBE5FF3F2EDB6F550019B380 /* LUI in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -465,6 +461,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EB721F232E75AFA900F2099F /* QuickDropIcon.icon */,
|
||||
EBE5FF4A2EDB8D4B0019B380 /* Config.storekit */,
|
||||
69DA9A1029E0BF5100A442DA /* QuickDrop */,
|
||||
699DEBA22AB0573200115D22 /* ShareExtension */,
|
||||
69DCF4822AB70D0600CBE2CC /* NearbyShare */,
|
||||
@@ -495,7 +492,6 @@
|
||||
EB644B852EA507CF006C2E6C /* ViewModel */,
|
||||
EBC05C6A2E33B55100EECC18 /* View */,
|
||||
EBC05C6B2E33B57100EECC18 /* Util */,
|
||||
EBC05C702E33B57D00EECC18 /* Plus */,
|
||||
69DA9A1329E0BF5200A442DA /* Assets.xcassets */,
|
||||
EB6E6B202ECBA95000E71D57 /* InfoPlist.xcstrings */,
|
||||
EB5C36922E34EBBD0052EFD7 /* Localizable.xcstrings */,
|
||||
@@ -550,7 +546,6 @@
|
||||
EB886E512E4E19390052B7D9 /* HKDF.swift */,
|
||||
EB4F9D232EC27CF000A74A0F /* FileManager+DocumentsOpener.swift */,
|
||||
EB4F9D1E2EC26C7C00A74A0F /* EXIFUtils.swift */,
|
||||
EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */,
|
||||
EB2F9BFA2DA04B67004010A2 /* Helpers.swift */,
|
||||
);
|
||||
path = Util;
|
||||
@@ -668,17 +663,6 @@
|
||||
path = Util;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EBC05C702E33B57D00EECC18 /* Plus */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EBC05C6D2E33B57D00EECC18 /* Converter.swift */,
|
||||
EB704A812E4A7BAE008E608F /* DistributionDetector.swift */,
|
||||
EBC05C6E2E33B57D00EECC18 /* Helper.swift */,
|
||||
EBC05C6F2E33B57D00EECC18 /* PlusView.swift */,
|
||||
);
|
||||
path = Plus;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EBC05C812E33B58300EECC18 /* IssueViews */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -743,6 +727,7 @@
|
||||
EB5C37D92E377AD60052EFD7 /* SwiftProtobuf */,
|
||||
EB5C37DB2E377AD60052EFD7 /* SwiftECC */,
|
||||
EB9925862E45F12F00357055 /* QRCode */,
|
||||
EBE5FF3E2EDB6F550019B380 /* LUI */,
|
||||
);
|
||||
productName = NearDrop;
|
||||
productReference = 69DA9A0E29E0BF5100A442DA /* QuickDrop.app */;
|
||||
@@ -873,6 +858,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
EBE5FF4D2EDB8D4B0019B380 /* Config.storekit in Resources */,
|
||||
EB5C36942E34EBBD0052EFD7 /* Localizable.xcstrings in Resources */,
|
||||
EB5C36E52E34EC0E0052EFD7 /* License.txt in Resources */,
|
||||
691F53BC2ABB70840089FD92 /* DeviceListCell.xib in Resources */,
|
||||
@@ -888,6 +874,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
EBE5FF4C2EDB8D4B0019B380 /* Config.storekit in Resources */,
|
||||
69DA9A1429E0BF5200A442DA /* Assets.xcassets in Resources */,
|
||||
EB5C36E42E34EC0E0052EFD7 /* License.txt in Resources */,
|
||||
EB5C36932E34EBBD0052EFD7 /* Localizable.xcstrings in Resources */,
|
||||
@@ -903,6 +890,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
EBE5FF4B2EDB8D4B0019B380 /* Config.storekit in Resources */,
|
||||
EB5C383B2E38C1F60052EFD7 /* justMaybe.mp3 in Resources */,
|
||||
EB1325FD2E7034B000FD749C /* InfoPlist.xcstrings in Resources */,
|
||||
EB97A0142E51DD00008B8C5C /* License.txt in Resources */,
|
||||
@@ -919,6 +907,7 @@
|
||||
files = (
|
||||
EB950B5B2E52065A002D68FA /* timeIsNow.mp3 in Resources */,
|
||||
EB1325FE2E7034B000FD749C /* InfoPlist.xcstrings in Resources */,
|
||||
EBE5FF4E2EDB8D4B0019B380 /* Config.storekit in Resources */,
|
||||
EB950B702E520734002D68FA /* Localizable.xcstrings in Resources */,
|
||||
EB950B5C2E52065A002D68FA /* justMaybe.mp3 in Resources */,
|
||||
EB950B5D2E52065A002D68FA /* License.txt in Resources */,
|
||||
@@ -933,19 +922,19 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
EB704A832E4B10D4008E608F /* DistributionDetector.swift in Sources */,
|
||||
EBE5FF442EDB877C0019B380 /* License.swift in Sources */,
|
||||
EB96ED902D7F8114004B3FF1 /* Localized.swift in Sources */,
|
||||
EB1325F82E70288300FD749C /* SendToExtension.swift in Sources */,
|
||||
EB16B6172E58B4C8007D9792 /* TrustStore.swift in Sources */,
|
||||
EB886E542E4E19390052B7D9 /* HKDF.swift in Sources */,
|
||||
EBC05C862E33B58300EECC18 /* NetworkFilterIssueView.swift in Sources */,
|
||||
EBE5FF432EDB71810019B380 /* Configuration.swift in Sources */,
|
||||
EBC05C872E33B58300EECC18 /* IssueView.swift in Sources */,
|
||||
EBC05C882E33B58300EECC18 /* FirewallIssueView.swift in Sources */,
|
||||
EBC05C892E33B58300EECC18 /* ApIsolationIssueView.swift in Sources */,
|
||||
699DEBA62AB0573200115D22 /* ShareViewController.swift in Sources */,
|
||||
EB96ED8B2D7F7CF7004B3FF1 /* SmallSheetView.swift in Sources */,
|
||||
EBCC27F92D80C9F90079C478 /* Zip.swift in Sources */,
|
||||
EB7CD1462D6FB0E800CB0CB5 /* Logger.swift in Sources */,
|
||||
EB5C37C52E377A780052EFD7 /* securemessage.pb.swift in Sources */,
|
||||
EB5C37C62E377A780052EFD7 /* securegcm.pb.swift in Sources */,
|
||||
EB5C37C72E377A780052EFD7 /* wire_format.pb.swift in Sources */,
|
||||
@@ -990,10 +979,7 @@
|
||||
EB16B6182E58B4C8007D9792 /* TrustStore.swift in Sources */,
|
||||
EBC05C5B2E33937200EECC18 /* ErrorAlertHandler.swift in Sources */,
|
||||
EB1325D42E701D8E00FD749C /* Settings.swift in Sources */,
|
||||
EBC05C712E33B57D00EECC18 /* Converter.swift in Sources */,
|
||||
EB886E5D2E4F13EB0052B7D9 /* Zip.swift in Sources */,
|
||||
EBC05C722E33B57D00EECC18 /* Helper.swift in Sources */,
|
||||
EBC05C732E33B57D00EECC18 /* PlusView.swift in Sources */,
|
||||
EB5C37BF2E377A780052EFD7 /* ukey.pb.swift in Sources */,
|
||||
EB5C37C02E377A780052EFD7 /* securemessage.pb.swift in Sources */,
|
||||
EB5C37C12E377A780052EFD7 /* offline_wire_formats.pb.swift in Sources */,
|
||||
@@ -1007,6 +993,7 @@
|
||||
EB5C37CD2E377A7F0052EFD7 /* OutboundNearbyConnection.swift in Sources */,
|
||||
EB5C37CE2E377A7F0052EFD7 /* InboundNearbyConnection.swift in Sources */,
|
||||
EB5C37CF2E377A7F0052EFD7 /* NearbyConnectionManager.swift in Sources */,
|
||||
EBE5FF422EDB6F6F0019B380 /* Configuration.swift in Sources */,
|
||||
EB7654A12E53252D006B4AA3 /* AttachmentDetails.swift in Sources */,
|
||||
EB886E522E4E19390052B7D9 /* HKDF.swift in Sources */,
|
||||
EB96ED8C2D7F7E7B004B3FF1 /* SmallSheetView.swift in Sources */,
|
||||
@@ -1016,11 +1003,9 @@
|
||||
69DA9A1229E0BF5100A442DA /* AppDelegate.swift in Sources */,
|
||||
EB6F62D72D91F4AF00534EC2 /* SettingsView.swift in Sources */,
|
||||
EB7F54122D78E96000989564 /* TutorialView.swift in Sources */,
|
||||
EB704A822E4A7BB3008E608F /* DistributionDetector.swift in Sources */,
|
||||
EB9925812E45D53E00357055 /* sharing_enums.pb.swift in Sources */,
|
||||
EB6E6AB42ECBA46D00E71D57 /* PhotoManager.swift in Sources */,
|
||||
EB96ED8F2D7F8105004B3FF1 /* Localized.swift in Sources */,
|
||||
EB7CD1452D6FB0C300CB0CB5 /* Logger.swift in Sources */,
|
||||
EB16B77A2E59BAA1007D9792 /* AppGroup.swift in Sources */,
|
||||
EBC05C822E33B58300EECC18 /* ApIsolationIssueView.swift in Sources */,
|
||||
EBC05C832E33B58300EECC18 /* FirewallIssueView.swift in Sources */,
|
||||
@@ -1047,7 +1032,6 @@
|
||||
EB5C37F42E377CE70052EFD7 /* NearbyConnectionManager.swift in Sources */,
|
||||
EB5C37F52E377CE70052EFD7 /* securemessage.pb.swift in Sources */,
|
||||
EB5C37F62E377CE70052EFD7 /* device_to_device_messages.pb.swift in Sources */,
|
||||
EB704A842E4B10D4008E608F /* DistributionDetector.swift in Sources */,
|
||||
EB886E532E4E19390052B7D9 /* HKDF.swift in Sources */,
|
||||
EB5C37F82E377CE70052EFD7 /* SleepManager.swift in Sources */,
|
||||
EB5C38012E377DE60052EFD7 /* Localized.swift in Sources */,
|
||||
@@ -1057,7 +1041,6 @@
|
||||
EB9925802E45D53E00357055 /* sharing_enums.pb.swift in Sources */,
|
||||
EB5C37FC2E377CE70052EFD7 /* OutboundNearbyConnection.swift in Sources */,
|
||||
EB1325D62E701D8E00FD749C /* Settings.swift in Sources */,
|
||||
EB5C37FD2E377CE70052EFD7 /* Logger.swift in Sources */,
|
||||
EBBC93B32EC8B76600F541A1 /* LocalNetworkPermissionView.swift in Sources */,
|
||||
EB97A00F2E511124008B8C5C /* ReceiveModel.swift in Sources */,
|
||||
EB5C37FE2E377CE70052EFD7 /* offline_wire_formats.pb.swift in Sources */,
|
||||
@@ -1098,7 +1081,6 @@
|
||||
EB16B6132E58B4B9007D9792 /* IdentityManager.swift in Sources */,
|
||||
EB4F9D212EC26C8100A74A0F /* EXIFUtils.swift in Sources */,
|
||||
EB950B4D2E520436002D68FA /* NearbyConnection.swift in Sources */,
|
||||
EB950B4F2E520436002D68FA /* Logger.swift in Sources */,
|
||||
EB950B502E520436002D68FA /* wire_format.pb.swift in Sources */,
|
||||
EB950B582E5205B4002D68FA /* Zip.swift in Sources */,
|
||||
EB950B512E520436002D68FA /* securemessage.pb.swift in Sources */,
|
||||
@@ -1123,7 +1105,6 @@
|
||||
EB950B6F2E5206E2002D68FA /* ShareViewController.swift in Sources */,
|
||||
EB950B432E52038A002D68FA /* ContentView.swift in Sources */,
|
||||
EB950B442E520414002D68FA /* License.swift in Sources */,
|
||||
EB4F9D1D2EC113EA00A74A0F /* DistributionDetector.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1187,7 +1168,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MARKETING_VERSION = "${SHARED_VERSION}";
|
||||
OTHER_SWIFT_FLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.leonboettger.neardrop.ShareExtension;
|
||||
@@ -1239,7 +1220,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MARKETING_VERSION = "${SHARED_VERSION}";
|
||||
OTHER_SWIFT_FLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.leonboettger.neardrop.ShareExtension;
|
||||
@@ -1321,8 +1302,8 @@
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
SHARED_BUILD = 92;
|
||||
SHARED_VERSION = 2.7.2;
|
||||
SHARED_BUILD = 94;
|
||||
SHARED_VERSION = 2.8;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -1384,8 +1365,8 @@
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
SHARED_BUILD = 92;
|
||||
SHARED_VERSION = 2.7.2;
|
||||
SHARED_BUILD = 94;
|
||||
SHARED_VERSION = 2.8;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -1437,7 +1418,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MARKETING_VERSION = "${SHARED_VERSION}";
|
||||
OTHER_SWIFT_FLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.leonboettger.neardrop;
|
||||
@@ -1501,7 +1482,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MARKETING_VERSION = "${SHARED_VERSION}";
|
||||
OTHER_SWIFT_FLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.leonboettger.neardrop;
|
||||
@@ -1860,6 +1841,16 @@
|
||||
package = EBADEB8B2E8029420021B5E4 /* XCRemoteSwiftPackageReference "DeviceKit" */;
|
||||
productName = DeviceKit;
|
||||
};
|
||||
EBE5FF3E2EDB6F550019B380 /* LUI */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = EB886E562E4E66420052B7D9 /* XCRemoteSwiftPackageReference "LUI" */;
|
||||
productName = LUI;
|
||||
};
|
||||
EBE5FF402EDB6F5D0019B380 /* LUI */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = EB886E562E4E66420052B7D9 /* XCRemoteSwiftPackageReference "LUI" */;
|
||||
productName = LUI;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 69DA9A0629E0BF5100A442DA /* Project object */;
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
"location" : "https://github.com/leonboe1/LUI.git",
|
||||
"state" : {
|
||||
"branch" : "main",
|
||||
"revision" : "1490442fc11be90a3418355b81db783abeb9a6c2"
|
||||
"revision" : "1c507e431e4b73cee127165a1fbd4a930abecd7d"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
ReferencedContainer = "container:QuickDrop.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<StoreKitConfigurationFileReference
|
||||
identifier = "../../Config.storekit">
|
||||
</StoreKitConfigurationFileReference>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
+17
-14
@@ -12,6 +12,7 @@ import Network
|
||||
import StoreKit
|
||||
import SwiftUI
|
||||
import UserNotifications
|
||||
import LUI
|
||||
|
||||
@main
|
||||
class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDelegate, NSWindowDelegate {
|
||||
@@ -34,7 +35,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
|
||||
// MARK: NSApplicationDelegate functions
|
||||
|
||||
func applicationWillFinishLaunching(_: Notification) {
|
||||
LUIInit(configuration: configuration)
|
||||
}
|
||||
|
||||
|
||||
func applicationDidFinishLaunching(_: Notification) {
|
||||
|
||||
let menu = NSMenu()
|
||||
|
||||
let visibleItem = NSMenuItem(
|
||||
@@ -67,14 +74,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
statusItem?.behavior = .removalAllowed
|
||||
|
||||
iapManager = IAPManager.sharedInstance
|
||||
iapManager?.startObserving()
|
||||
|
||||
if DistributionDetector.isDirectDistributionEnabled {
|
||||
log("[AppDelegate] Downloaded from GitHub.")
|
||||
}
|
||||
else {
|
||||
log("[AppDelegate] Downloaded from App Store.")
|
||||
}
|
||||
|
||||
// app did not lauch before
|
||||
if !Settings.shared.appLaunchedBefore {
|
||||
@@ -92,6 +91,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
if !Settings.shared.isEligibleForIap {
|
||||
log("[AppDelegate] Granting QuickDrop+ for old user")
|
||||
Settings.shared.gotPlus = true
|
||||
UserDefaults.standard.set(true, forKey: Settings.UserDefaultsKeys.plusVersionLegacy.rawValue)
|
||||
} else {
|
||||
if !fullVersion() {
|
||||
log("[AppDelegate] New user - QuickDrop+ not available")
|
||||
@@ -160,7 +160,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
|
||||
func applicationWillTerminate(_: Notification) {
|
||||
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
|
||||
iapManager?.stopObserving()
|
||||
}
|
||||
|
||||
|
||||
@@ -258,11 +257,15 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
log("Opening Plus screen")
|
||||
|
||||
// Create the welcome screen SwiftUI view
|
||||
let plusView = PlusView(closeView: {
|
||||
log("Closing plus screen")
|
||||
self.plusWindow?.close()
|
||||
self.plusWindow = nil
|
||||
})
|
||||
let plusView = GetPlusViewV4(showSheet: Binding(get: { self.plusWindow != nil }, set: { newValue in
|
||||
if !newValue {
|
||||
self.plusWindow?.close()
|
||||
self.plusWindow = nil
|
||||
}
|
||||
}), hasSheet: false)
|
||||
|
||||
let plusViewWidth: CGFloat = 550
|
||||
let plusViewHeight: CGFloat = 650
|
||||
|
||||
// Create an NSWindow to host the SwiftUI view
|
||||
let window = NSWindow(
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 672 KiB |
@@ -12,15 +12,6 @@
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"filename" : "1024-1024.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "FileTransfer Kopie-512.png",
|
||||
"filename" : "iDroidIcon-iOS-Default-1024x1024@1x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 111 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
+2176
-4498
File diff suppressed because it is too large.
Load diff
@@ -1,66 +0,0 @@
|
||||
//
|
||||
// StoreChecker.swift
|
||||
// LUI
|
||||
//
|
||||
// Created by Leon Böttger on 19.08.24.
|
||||
//
|
||||
import StoreKit
|
||||
|
||||
class IAPConverter: NSObject, SKRequestDelegate {
|
||||
|
||||
let switchToIAPAfterAppVersion = "1.2"
|
||||
|
||||
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 = switchToIAPAfterAppVersion
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
//
|
||||
// DistributionDetector.swift
|
||||
// QuickDrop
|
||||
//
|
||||
// Created by Leon Böttger on 11.08.25.
|
||||
//
|
||||
|
||||
import Security
|
||||
import Foundation
|
||||
|
||||
class DistributionDetector {
|
||||
|
||||
static var isDirectDistributionEnabled: Bool {
|
||||
get {
|
||||
#if os(macOS)
|
||||
if let cached = _directDistributionCached {
|
||||
return cached
|
||||
}
|
||||
|
||||
let result = isDirectDistribution()
|
||||
self._directDistributionCached = result
|
||||
|
||||
return result
|
||||
#else
|
||||
return false
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static var _directDistributionCached: Bool? = nil
|
||||
|
||||
#if os(macOS)
|
||||
private static func isDirectDistribution() -> Bool {
|
||||
// 1. Get dynamic code object for our process
|
||||
var code: SecCode?
|
||||
var status = SecCodeCopySelf([], &code)
|
||||
guard status == errSecSuccess, let codeRef = code else {
|
||||
log("[DistributionDetector] Could not get code object)")
|
||||
return false
|
||||
}
|
||||
|
||||
// 2. Convert to static code object
|
||||
var staticCode: SecStaticCode?
|
||||
status = SecCodeCopyStaticCode(codeRef, [], &staticCode)
|
||||
guard status == errSecSuccess, let staticCodeRef = staticCode else {
|
||||
log("[DistributionDetector] Could not get static code object)")
|
||||
return false
|
||||
}
|
||||
|
||||
// 3. Get signing info
|
||||
var infoCF: CFDictionary?
|
||||
status = SecCodeCopySigningInformation(staticCodeRef,
|
||||
SecCSFlags(rawValue: kSecCSSigningInformation),
|
||||
&infoCF)
|
||||
guard status == errSecSuccess, let info = infoCF as? [String: Any] else {
|
||||
log("[DistributionDetector] Could not get signing info")
|
||||
return false
|
||||
}
|
||||
|
||||
// 4. Look at the first certificate's common name
|
||||
if let certificates = info[kSecCodeInfoCertificates as String] as? [SecCertificate],
|
||||
let firstCert = certificates.first {
|
||||
var commonName: CFString?
|
||||
status = SecCertificateCopyCommonName(firstCert, &commonName)
|
||||
if status == errSecSuccess, let commonNameStr = commonName as String? {
|
||||
if commonNameStr.contains("Developer ID Application") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
//
|
||||
// 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]) {
|
||||
|
||||
log("IAP updatedTransactions")
|
||||
|
||||
transactions.forEach { (transaction) in
|
||||
|
||||
switch transaction.transactionState {
|
||||
case .purchased:
|
||||
log("IAP purchased")
|
||||
onBuyProductHandler?(.success(true))
|
||||
SKPaymentQueue.default().finishTransaction(transaction)
|
||||
|
||||
case .restored:
|
||||
log("IAP 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) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||||
if self.totalRestoredPurchases == 0 {
|
||||
log("[LUI] IAP: No purchases to restore!")
|
||||
self.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."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
//
|
||||
// PlusView.swift
|
||||
// QuickDrop
|
||||
//
|
||||
// Created by Leon Böttger on 23.02.25.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import StoreKit
|
||||
|
||||
let plusViewWidth: CGFloat = 440
|
||||
let plusViewHeight: CGFloat = 200
|
||||
|
||||
struct PlusView: View {
|
||||
|
||||
@ObservedObject private var settings = Settings.shared
|
||||
@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()
|
||||
}
|
||||
.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: plusViewWidth, height: plusViewHeight)
|
||||
}
|
||||
|
||||
func restorePurchases() {
|
||||
|
||||
withAnimation {
|
||||
restoring = true
|
||||
}
|
||||
|
||||
iaphelper.restorePurchases { result in
|
||||
DispatchQueue.main.async {
|
||||
|
||||
switch result {
|
||||
case .success(let success):
|
||||
if success {
|
||||
log("[LUI] Restored purchases successfully")
|
||||
withAnimation {
|
||||
settings.gotPlus = true
|
||||
}
|
||||
boughtSuccessAlert = true
|
||||
} else {
|
||||
log("[LUI] Nothing to restore")
|
||||
//nothing to restore
|
||||
restoreFailed(message: "plusview_nothingtorestore".localized())
|
||||
}
|
||||
|
||||
case .failure(let error):
|
||||
log("[LUI] Error restoring purchases: \(error.localizedDescription)")
|
||||
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 {
|
||||
settings.gotPlus = 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 {
|
||||
settings.gotPlus = 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 {
|
||||
PlusView(closeView: {})
|
||||
}
|
||||
@@ -55,9 +55,11 @@ class Settings: ObservableObject {
|
||||
// MARK: - Debug
|
||||
|
||||
func deleteAllUserDefaults() {
|
||||
for key in UserDefaultsKeys.allCases {
|
||||
UserDefaults.standard.removeObject(forKey: key.rawValue)
|
||||
let defaults = UserDefaults.standard
|
||||
if let bundleID = Bundle.main.bundleIdentifier {
|
||||
defaults.removePersistentDomain(forName: bundleID)
|
||||
}
|
||||
defaults.synchronize()
|
||||
|
||||
Settings.shared = Settings()
|
||||
}
|
||||
@@ -69,11 +71,14 @@ class Settings: ObservableObject {
|
||||
public enum UserDefaultsKeys: String, CaseIterable {
|
||||
case isEligibleForIap = "isEligibleForIap"
|
||||
case appLaunchedBefore = "ShowedWelcomeScreen"
|
||||
case plusVersion = "isPlusVersion"
|
||||
case plusVersion = "plusVersion"
|
||||
case transmissionCount = "reviewRequestCountKey"
|
||||
case automaticallyAcceptFiles = "automaticallyAcceptFiles"
|
||||
case saveFolderBookmark = "saveFolderBookmark"
|
||||
case openFinderAfterReceiving = "openFinderAfterReceiving"
|
||||
case endpointID = "endpointID"
|
||||
|
||||
// Plus version used before StoreKit 2 update. New key is fetched from App Store directly.
|
||||
case plusVersionLegacy = "isPlusVersion"
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
import LUI
|
||||
|
||||
class AudioManager {
|
||||
static private var incomingFileSoundPlayer: AVAudioPlayer?
|
||||
|
||||
@@ -10,12 +10,11 @@ import Network
|
||||
import StoreKit
|
||||
import SwiftUI
|
||||
import UserNotifications
|
||||
import LUI
|
||||
|
||||
#if os(macOS)
|
||||
import BezelNotification
|
||||
import Cocoa
|
||||
#else
|
||||
import LUI
|
||||
#endif
|
||||
|
||||
class ErrorAlertHandler {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import SwiftUI
|
||||
import ServiceManagement
|
||||
import os.log
|
||||
import LUI
|
||||
|
||||
@available(macOS 13.0, *)
|
||||
public enum LaunchAtLogin {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import LUI
|
||||
|
||||
/// Returns the name of the currently active network interface (e.g. "en0", "en1")
|
||||
func getActiveNetworkInterface() -> String? {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import Foundation
|
||||
import Network
|
||||
import LUI
|
||||
|
||||
class IPv6DeviceScanner {
|
||||
/// Scans for IPv6 devices using `ping6 ff02::1` multicast on the given interface.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import Foundation
|
||||
import Network
|
||||
import LUI
|
||||
|
||||
class DeviceToDeviceHeuristicScanner {
|
||||
private let scanQueue = DispatchQueue(label: "DeviceToDeviceScanQueue")
|
||||
|
||||
@@ -9,6 +9,7 @@ import SwiftUI
|
||||
import Foundation
|
||||
import AppKit
|
||||
import Network
|
||||
import LUI
|
||||
|
||||
fileprivate let routerCheckQueue = DispatchQueue(label: "routerCheckQueue")
|
||||
|
||||
|
||||
@@ -90,7 +90,15 @@ struct QuickDropToastView: View {
|
||||
}
|
||||
|
||||
HStack {
|
||||
CapsuleProgress(value: receiveModel.progress ?? 1.0)
|
||||
ZStack {
|
||||
CapsuleProgress(value: 0.5)
|
||||
.opacity(0)
|
||||
|
||||
if let progress = receiveModel.progress {
|
||||
CapsuleProgress(value: progress)
|
||||
}
|
||||
}
|
||||
.animation(.easeInOut, value: receiveModel.progress == nil)
|
||||
|
||||
Button(action: onCancel) {
|
||||
Image(systemName: "xmark")
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import SwiftUI
|
||||
import AppKit
|
||||
import LUI
|
||||
|
||||
struct SettingsView: View {
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import LUI
|
||||
|
||||
struct TutorialView: View {
|
||||
|
||||
@@ -81,10 +82,8 @@ struct LargeAppIconView<Content: View>: View {
|
||||
ScrollView {
|
||||
|
||||
VStack {
|
||||
Image("AppIconHighRes")
|
||||
.resizable()
|
||||
.frame(width: 150, height: 150)
|
||||
.padding(.top, 40)
|
||||
AppIconView(hasPlusIcon: false, size: 120)
|
||||
.padding(.top, 35)
|
||||
|
||||
Text(title.localized())
|
||||
.font(.largeTitle)
|
||||
|
||||
@@ -8,11 +8,10 @@
|
||||
import SwiftUI
|
||||
import StoreKit
|
||||
import UserNotifications
|
||||
import LUI
|
||||
|
||||
#if os(macOS)
|
||||
import BezelNotification
|
||||
#else
|
||||
import LUI
|
||||
#endif
|
||||
|
||||
class ReceiveModel: ObservableObject, InboundAppDelegate {
|
||||
@@ -290,9 +289,7 @@ class ReceiveModel: ObservableObject, InboundAppDelegate {
|
||||
|
||||
#if os(macOS)
|
||||
func showReviewIfAppropriate(currentTransmissionCount: Int) {
|
||||
// If distributed directly, do not request review here as it does not work
|
||||
if pendingReview && !DistributionDetector.isDirectDistributionEnabled {
|
||||
|
||||
if pendingReview {
|
||||
// Dont request review again
|
||||
pendingReview = false
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import Foundation
|
||||
let configuration = LUIConfiguration(
|
||||
appName: "QuickDrop",
|
||||
|
||||
plusVersionInfo: GetPlusViewInformation(lifetimeID: "plusversion", description: "plusview_description_phone", plusVersionFeatures: [], settingsLabelColor: .orange, settingsFooter: "plusview_footer_phone"),
|
||||
plusVersionInfo: GetPlusViewInformation(lifetimeID: "plusversion", yearlyID: "quickdrop.yearly", plusViewHeader: isMac() ? "plusview_title" : nil, description: isMac() ? "plusview_description" : "plusview_description_phone", onBoughtPlusVersionAlertMessage: "plusview_success_description", plusVersionFeatures: [], settingsLabelColor: .orange, settingsFooter: "plusview_footer_phone"),
|
||||
|
||||
setPlusVersion: { result in
|
||||
DispatchQueue.main.async {
|
||||
@@ -21,6 +21,8 @@ let configuration = LUIConfiguration(
|
||||
|
||||
hasRoundedFont: false,
|
||||
|
||||
switchedToIAPafterBundleVersion: AppVersionBundle(appVersion: "1.2", buildVersion: 0, legacyUserDefaultsKey: Settings.UserDefaultsKeys.plusVersionLegacy.rawValue),
|
||||
|
||||
copyrightInformation: licenseText,
|
||||
|
||||
loggingUrl: AppGroup.appGroupDirectory,
|
||||
|
||||
@@ -11,9 +11,7 @@ import LUI
|
||||
@main
|
||||
struct QuickDropiOSApp: App {
|
||||
|
||||
#if !os(macOS)
|
||||
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
||||
#endif
|
||||
|
||||
init() {
|
||||
LUIInit(configuration: configuration)
|
||||
|
||||
@@ -11,6 +11,7 @@ import UIKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
import LUI
|
||||
import Photos
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
import LUI
|
||||
|
||||
// MARK: - UIKit Alert Presenter
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import Foundation
|
||||
import UniformTypeIdentifiers
|
||||
import SwiftUI
|
||||
import LUI
|
||||
#if os(macOS)
|
||||
import Cocoa
|
||||
#endif
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import Cocoa
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import LUI
|
||||
|
||||
class ShareViewController: NSViewController, OutboundAppDelegate {
|
||||
|
||||
@@ -49,6 +50,8 @@ class ShareViewController: NSViewController, OutboundAppDelegate {
|
||||
override func loadView() {
|
||||
|
||||
super.loadView()
|
||||
LUIInit(configuration: configuration)
|
||||
|
||||
loadAttachments(with: extensionContext, loadedItems: { result in
|
||||
|
||||
log("Loaded attachments: \(result)")
|
||||
|
||||
@@ -10,6 +10,16 @@ import SwiftUI
|
||||
import LUI
|
||||
|
||||
class ShareViewController: UIViewController {
|
||||
|
||||
override func loadView() {
|
||||
super.loadView()
|
||||
|
||||
// skip introduction for share extension
|
||||
LUIInit(configuration: configuration)
|
||||
LUISettings.sharedInstance.appLaunchedBefore = true
|
||||
}
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
@@ -29,10 +39,6 @@ class ShareViewController: UIViewController {
|
||||
NearbyConnectionManager.shared.attachments = attachmentDetails
|
||||
}
|
||||
})
|
||||
|
||||
// skip introduction for share extension
|
||||
LUIInit(configuration: configuration)
|
||||
LUISettings.sharedInstance.appLaunchedBefore = true
|
||||
|
||||
let hostingController = UIHostingController(rootView: ContentView())
|
||||
|
||||
|
||||
Reference in new issue
Block a user