Fix ZIP creation for certain file types, improve UX for outgoing transfer

This commit is contained in:
Leon Böttger committed 2025-12-18 21:31:36 +01:00
1 parent a5e1030c1f
commit 8393a7495f
9 files changed
+254 -185

No files matched your search

+22 -42
View File
@@ -6,63 +6,43 @@
//
import Foundation
import ZIPFoundation
class Zip {
final class Zip {
static func createAtTemporaryDirectory(zipFilename: String, zipExtension: String = "zip", fromDirectory directoryURL: URL) throws -> URL {
static func createAtTemporaryDirectory(
zipFilename: String,
zipExtension: String = "zip",
fromDirectory directoryURL: URL
) throws -> URL {
let finalURL = FileManager.default.temporaryDirectory
guard directoryURL.isDirectory else { throw CreateZipError.urlNotADirectory(directoryURL) }
let zipFinalURL = FileManager.default.temporaryDirectory
.appendingPathComponent(zipFilename)
.appendingPathExtension(zipExtension)
return try createAt(
zipFinalURL: finalURL,
fromDirectory: directoryURL
if FileManager.default.fileExists(atPath: zipFinalURL.path) {
try FileManager.default.removeItem(at: zipFinalURL)
}
try FileManager.default.zipItem(
at: directoryURL,
to: zipFinalURL,
shouldKeepParent: true,
compressionMethod: .deflate
)
}
static func createAt(zipFinalURL: URL, fromDirectory directoryURL: URL) throws -> URL {
guard directoryURL.isDirectory else {
throw CreateZipError.urlNotADirectory(directoryURL)
}
var fileManagerError: Swift.Error?
var coordinatorError: NSError?
let coordinator = NSFileCoordinator()
coordinator.coordinate(readingItemAt: directoryURL, options: .forUploading, error: &coordinatorError) { zipCreatedURL in
do {
// clean if file exists
if FileManager.default.fileExists(atPath: zipFinalURL.path) {
try FileManager.default.removeItem(at: zipFinalURL)
}
try FileManager.default.moveItem(at: zipCreatedURL, to: zipFinalURL)
} catch {
fileManagerError = error
}
}
if let error = coordinatorError ?? fileManagerError {
throw CreateZipError.failedToCreateZIP(error)
}
return zipFinalURL
}
enum CreateZipError: Swift.Error {
enum CreateZipError: Error {
case urlNotADirectory(URL)
case failedToCreateZIP(Swift.Error)
}
}
extension URL {
private extension URL {
var isDirectory: Bool {
(try? resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory == true
(try? resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory == true
}
}
+49 -2
View File
@@ -51,6 +51,11 @@
EB4F9D222EC26C8100A74A0F /* EXIFUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB4F9D1E2EC26C7C00A74A0F /* EXIFUtils.swift */; };
EB4F9D252EC27CFB00A74A0F /* FileManager+DocumentsOpener.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB4F9D232EC27CF000A74A0F /* FileManager+DocumentsOpener.swift */; };
EB4F9D272EC27CFB00A74A0F /* FileManager+DocumentsOpener.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB4F9D232EC27CF000A74A0F /* FileManager+DocumentsOpener.swift */; };
EB53D8C42EF496AB004C95BA /* ZIPFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = EB53D8C32EF496AB004C95BA /* ZIPFoundation */; };
EB53D8C62EF496CA004C95BA /* ZIPFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = EB53D8C52EF496CA004C95BA /* ZIPFoundation */; };
EB53D8C82EF496D1004C95BA /* ZIPFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = EB53D8C72EF496D1004C95BA /* ZIPFoundation */; };
EB53D8CA2EF49703004C95BA /* BezelNotification in Frameworks */ = {isa = PBXBuildFile; productRef = EB53D8C92EF49703004C95BA /* BezelNotification */; };
EB53D8CC2EF49707004C95BA /* ZIPFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = EB53D8CB2EF49707004C95BA /* ZIPFoundation */; };
EB5C36932E34EBBD0052EFD7 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = EB5C36922E34EBBD0052EFD7 /* Localizable.xcstrings */; };
EB5C36942E34EBBD0052EFD7 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = EB5C36922E34EBBD0052EFD7 /* Localizable.xcstrings */; };
EB5C36E42E34EC0E0052EFD7 /* License.txt in Resources */ = {isa = PBXBuildFile; fileRef = EB5C36E32E34EC0E0052EFD7 /* License.txt */; };
@@ -395,8 +400,10 @@
files = (
EB5C37D82E377ACF0052EFD7 /* SwiftECC in Frameworks */,
EBE5FF412EDB6F5D0019B380 /* LUI in Frameworks */,
EB53D8CA2EF49703004C95BA /* BezelNotification in Frameworks */,
EB5C37D62E377ACF0052EFD7 /* SwiftProtobuf in Frameworks */,
EB9925852E45EF0900357055 /* QRCode in Frameworks */,
EB53D8CC2EF49707004C95BA /* ZIPFoundation in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -409,6 +416,7 @@
EB5C37DC2E377AD60052EFD7 /* SwiftECC in Frameworks */,
EB5C37DA2E377AD60052EFD7 /* SwiftProtobuf in Frameworks */,
EBE5FF3F2EDB6F550019B380 /* LUI in Frameworks */,
EB53D8C42EF496AB004C95BA /* ZIPFoundation in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -421,6 +429,7 @@
EB886E582E4E66420052B7D9 /* LUI in Frameworks */,
EB5C37EE2E377C3F0052EFD7 /* SwiftProtobuf in Frameworks */,
EB9925892E45F13500357055 /* QRCode in Frameworks */,
EB53D8C62EF496CA004C95BA /* ZIPFoundation in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -433,6 +442,7 @@
EB950B652E52067D002D68FA /* LUI in Frameworks */,
EB950B5F2E520671002D68FA /* SwiftProtobuf in Frameworks */,
EB950B632E52067A002D68FA /* QRCode in Frameworks */,
EB53D8C82EF496D1004C95BA /* ZIPFoundation in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -733,6 +743,7 @@
EB5C37DB2E377AD60052EFD7 /* SwiftECC */,
EB9925862E45F12F00357055 /* QRCode */,
EBE5FF3E2EDB6F550019B380 /* LUI */,
EB53D8C32EF496AB004C95BA /* ZIPFoundation */,
);
productName = NearDrop;
productReference = 69DA9A0E29E0BF5100A442DA /* QuickDrop.app */;
@@ -759,6 +770,7 @@
EB9925882E45F13500357055 /* QRCode */,
EB886E572E4E66420052B7D9 /* LUI */,
EBADEB8E2E8029750021B5E4 /* DeviceKit */,
EB53D8C52EF496CA004C95BA /* ZIPFoundation */,
);
productName = QuickDropiOS;
productReference = EB5C37E22E377C2E0052EFD7 /* QuickDropiOS.app */;
@@ -783,6 +795,7 @@
EB950B622E52067A002D68FA /* QRCode */,
EB950B642E52067D002D68FA /* LUI */,
EBADEB902E802A830021B5E4 /* DeviceKit */,
EB53D8C72EF496D1004C95BA /* ZIPFoundation */,
);
productName = iOSShareExtension;
productReference = EB950B2D2E52027F002D68FA /* iOSShareExtension.appex */;
@@ -845,6 +858,7 @@
EB9925832E45EF0900357055 /* XCRemoteSwiftPackageReference "qrcode" */,
EB886E562E4E66420052B7D9 /* XCRemoteSwiftPackageReference "LUI" */,
EBADEB8B2E8029420021B5E4 /* XCRemoteSwiftPackageReference "DeviceKit" */,
EB53D8C22EF496AB004C95BA /* XCRemoteSwiftPackageReference "ZIPFoundation" */,
);
productRefGroup = 69DA9A0F29E0BF5100A442DA /* Products */;
projectDirPath = "";
@@ -1311,7 +1325,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SHARED_BUILD = 97;
SHARED_VERSION = 2.9;
SHARED_VERSION = 2.9.1;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -1374,7 +1388,7 @@
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SHARED_BUILD = 97;
SHARED_VERSION = 2.9;
SHARED_VERSION = 2.9.1;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -1737,6 +1751,14 @@
minimumVersion = 2.1.0;
};
};
EB53D8C22EF496AB004C95BA /* XCRemoteSwiftPackageReference "ZIPFoundation" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/weichsel/ZIPFoundation.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.9.20;
};
};
EB886E562E4E66420052B7D9 /* XCRemoteSwiftPackageReference "LUI" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/leonboe1/LUI.git";
@@ -1769,6 +1791,31 @@
package = EB2F9BFC2DA05F48004010A2 /* XCRemoteSwiftPackageReference "BezelNotification" */;
productName = BezelNotification;
};
EB53D8C32EF496AB004C95BA /* ZIPFoundation */ = {
isa = XCSwiftPackageProductDependency;
package = EB53D8C22EF496AB004C95BA /* XCRemoteSwiftPackageReference "ZIPFoundation" */;
productName = ZIPFoundation;
};
EB53D8C52EF496CA004C95BA /* ZIPFoundation */ = {
isa = XCSwiftPackageProductDependency;
package = EB53D8C22EF496AB004C95BA /* XCRemoteSwiftPackageReference "ZIPFoundation" */;
productName = ZIPFoundation;
};
EB53D8C72EF496D1004C95BA /* ZIPFoundation */ = {
isa = XCSwiftPackageProductDependency;
package = EB53D8C22EF496AB004C95BA /* XCRemoteSwiftPackageReference "ZIPFoundation" */;
productName = ZIPFoundation;
};
EB53D8C92EF49703004C95BA /* BezelNotification */ = {
isa = XCSwiftPackageProductDependency;
package = EB2F9BFC2DA05F48004010A2 /* XCRemoteSwiftPackageReference "BezelNotification" */;
productName = BezelNotification;
};
EB53D8CB2EF49707004C95BA /* ZIPFoundation */ = {
isa = XCSwiftPackageProductDependency;
package = EB53D8C22EF496AB004C95BA /* XCRemoteSwiftPackageReference "ZIPFoundation" */;
productName = ZIPFoundation;
};
EB5C37D52E377ACF0052EFD7 /* SwiftProtobuf */ = {
isa = XCSwiftPackageProductDependency;
package = 69DA9A2429E189EF00A442DA /* XCRemoteSwiftPackageReference "swift-protobuf" */;
@@ -1,5 +1,5 @@
{
"originHash" : "270e8bfd245fae589b12faf08b86042cbbe7c809d59c5b0b8b735c7fb3a8d4bd",
"originHash" : "85c9b997510f22b553d79f68fb6d51d149ac9324df643dbf1475023b39da33b3",
"pins" : [
{
"identity" : "applewatchscreensize",
@@ -126,6 +126,15 @@
"branch" : "main",
"revision" : "b10fc8a284abb9bd908d77243d2ba3b3d8ea6ebc"
}
},
{
"identity" : "zipfoundation",
"kind" : "remoteSourceControl",
"location" : "https://github.com/weichsel/ZIPFoundation.git",
"state" : {
"revision" : "22787ffb59de99e5dc1fbfe80b19c97a904ad48d",
"version" : "0.9.20"
}
}
],
"version" : 3
+114 -114
View File
@@ -10487,229 +10487,229 @@
"ar" : {
"stringUnit" : {
"state" : "translated",
"value" : "تم إيقاف الاتصال بواسطة هاتفك."
"value" : "تم إنهاء الاتصال من قبل جهازك الآخر."
}
},
"ca" : {
"stringUnit" : {
"state" : "translated",
"value" : "La connexió ha estat interrompuda pel teu telèfon."
"value" : "La connexió ha estat interrompuda per l'altre dispositiu."
}
},
"cs" : {
"stringUnit" : {
"state" : "translated",
"value" : "Připojení bylo ukončeno vaším telefonem."
"value" : "Připojení bylo přerušeno vaším druhým zařízením."
}
},
"da" : {
"stringUnit" : {
"state" : "translated",
"value" : "Forbindelsen blev afbrudt af din telefon."
"value" : "Forbindelsen blev afbrudt af din anden enhed."
}
},
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Die Verbindung wurde von deinem Telefon abgebrochen."
"value" : "Die Verbindung wurde von deinem anderen Gerät abgebrochen."
}
},
"el" : {
"stringUnit" : {
"state" : "translated",
"value" : "Η σύνδεση διεκόπη από το τηλέφωνό σας."
"value" : "Η σύνδεση διακόπηκε από την άλλη συσκευή σας."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The connection was aborted by your phone."
"value" : "The connection was aborted by your other device."
}
},
"en-AU" : {
"stringUnit" : {
"state" : "translated",
"value" : "The connection was stopped by your phone."
"value" : "The connection was aborted by your other device."
}
},
"en-CA" : {
"stringUnit" : {
"state" : "translated",
"value" : "The connection was interrupted by your phone."
"value" : "The connection was aborted by your other device."
}
},
"en-GB" : {
"stringUnit" : {
"state" : "translated",
"value" : "The connection was aborted by your phone."
"value" : "The connection was aborted by your other device."
}
},
"es" : {
"stringUnit" : {
"state" : "translated",
"value" : "La conexión fue abortada por tu teléfono."
"value" : "La conexión fue interrumpida por tu otro dispositivo."
}
},
"es-419" : {
"stringUnit" : {
"state" : "translated",
"value" : "La conexión fue abortada por tu teléfono."
"value" : "La conexión fue abortada por tu otro dispositivo."
}
},
"fi" : {
"stringUnit" : {
"state" : "translated",
"value" : "Puhelimesi keskeytti yhteyden."
"value" : "Yhteys katkaistiin toisella laitteellasi."
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "La connexion a été interrompue par votre téléphone."
"value" : "La connexion a été interrompue par votre autre appareil."
}
},
"fr-CA" : {
"stringUnit" : {
"state" : "translated",
"value" : "La connexion a été interrompue par votre téléphone."
"value" : "La connexion a été interrompue par votre autre appareil."
}
},
"he" : {
"stringUnit" : {
"state" : "translated",
"value" : "החיבור הופסק על ידי הטלפון שלך."
"value" : "החיבור נותק על ידי המכשיר השני שלך."
}
},
"hi" : {
"stringUnit" : {
"state" : "translated",
"value" : "कनेक्शन आपके फोन द्वारा रद्द कर दिया गया।"
"value" : "कनेक्शन आपके दूसरे डिवाइस द्वारा समाप्त कर दिया गया था।"
}
},
"hr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Veza je prekinuta od strane vašeg telefona."
"value" : "Vaš drugi uređaj je prekinuo vezu."
}
},
"hu" : {
"stringUnit" : {
"state" : "translated",
"value" : "A kapcsolatot megszakította a telefonod."
"value" : "A másik eszköz szakította meg a kapcsolatot."
}
},
"id" : {
"stringUnit" : {
"state" : "translated",
"value" : "Koneksi dibatalkan oleh ponsel Anda."
"value" : "Koneksi terputus oleh perangkat Anda yang lain."
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "La connessione è stata interrotta dal tuo telefono."
"value" : "La connessione è stata interrotta dall'altro dispositivo."
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "接続はあなたの電話によって中断されました。"
"value" : "接続が他のデバイスによって中断されました。"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "연결이 휴대폰에 의해 중단되었습니다."
"value" : "다른 기기에서 연결이 중단되었습니다."
}
},
"ms" : {
"stringUnit" : {
"state" : "translated",
"value" : "Sambungan telah dihentikan oleh telefon anda."
"value" : "Sambungan telah dibatalkan oleh peranti anda yang lain."
}
},
"nb" : {
"stringUnit" : {
"state" : "translated",
"value" : "Tilkoblingen ble avbrutt av telefonen din."
"value" : "Tilkoblingen ble avbrutt av den andre enheten din."
}
},
"nl" : {
"stringUnit" : {
"state" : "translated",
"value" : "De verbinding is door uw telefoon afgebroken."
"value" : "De verbinding is afgebroken door je andere apparaat."
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Połączenie zostało przerwane przez telefon."
"value" : "Połączenie zostało przerwane przez inne urządzenie."
}
},
"pt-BR" : {
"stringUnit" : {
"state" : "translated",
"value" : "A conexão foi interrompida pelo seu telefone."
"value" : "A conexão foi abortada pelo seu outro dispositivo."
}
},
"pt-PT" : {
"stringUnit" : {
"state" : "translated",
"value" : "A ligação foi interrompida pelo seu telemóvel."
"value" : "A ligação foi interrompida pelo seu outro dispositivo."
}
},
"ro" : {
"stringUnit" : {
"state" : "translated",
"value" : "Conexiunea a fost întreruptă de telefonul dumneavoastră."
"value" : "Conexiunea a fost întreruptă de către celălalt dispozitiv."
}
},
"ru" : {
"stringUnit" : {
"state" : "translated",
"value" : "Соединение было прервано вашим телефоном."
"value" : "Соединение было прервано другим вашим устройством."
}
},
"sv" : {
"stringUnit" : {
"state" : "translated",
"value" : "Förbindelsen avbröts av din telefon."
"value" : "Anslutningen avbröts av din andra enhet."
}
},
"th" : {
"stringUnit" : {
"state" : "translated",
"value" : "การเชื่อมต่อล้มเลิกโดยโทรศัพท์ของคุณ"
"value" : "การเชื่อมต่อถูกยกเลิกโดยอุปกรณ์อีกเครื่องของคุณ"
}
},
"tr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Bağlantı telefonunuz tarafından kesildi."
"value" : "Bağlantı diğer cihazınız tarafından sonlandırıldı."
}
},
"uk" : {
"stringUnit" : {
"state" : "translated",
"value" : "З'єднання було перервано вашим телефоном."
"value" : "З'єднання було перервано вашим іншим пристроєм."
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "Kết nối bị hủy bởi điện thoại của bạn."
"value" : "Kết nối đã bị thiết bị kia của bạn hủy."
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "连接被您的手机中断。"
"value" : "连接已被你的另一台设备中断。"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "連接已被您的手機中止。"
"value" : "連線已被您的其他裝置中止。"
}
}
}
@@ -10953,229 +10953,229 @@
"ar" : {
"stringUnit" : {
"state" : "translated",
"value" : "إذا تكرر هذا الأمر، يرجى إعادة تشغيل هاتفك أو محاولة تنزيل تطبيق QuickDrop للأندرويد من متجر Google Play."
"value" : "إذا تكرر ذلك، يرجى إعادة تشغيل جهازك الآخر أو محاولة تنزيل تطبيق QuickDrop للأندرويد من متجر Google Play."
}
},
"ca" : {
"stringUnit" : {
"state" : "translated",
"value" : "Si això passa repetidament, reinicia el telèfon o prova de descarregar l'app QuickDrop per a Android des de Google Play."
"value" : "Si això passa repetidament, reinicia l'altre dispositiu o prova de descarregar l'app QuickDrop per a Android des de Google Play."
}
},
"cs" : {
"stringUnit" : {
"state" : "translated",
"value" : "Pokud se to opakuje, restartujte prosím svůj telefon nebo zkuste stáhnout aplikaci QuickDrop pro Android z Google Play."
"value" : "Pokud se to opakuje, restartujte své druhé zařízení nebo zkuste stáhnout aplikaci QuickDrop pro Android z Google Play."
}
},
"da" : {
"stringUnit" : {
"state" : "translated",
"value" : "Hvis dette sker gentagne gange, så genstart venligst din telefon eller prøv at downloade QuickDrop Android-appen fra Google Play."
"value" : "Hvis dette sker gentagne gange, genstart venligst din anden enhed eller prøv at downloade QuickDrop Android-appen fra Google Play."
}
},
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Wenn dies wiederholt passiert, starte bitte dein Handy neu oder lade die QuickDrop Android-App aus dem Google Play Store herunter."
"value" : "Wenn das wiederholt passiert, starte bitte dein anderes Gerät neu oder lade die QuickDrop Android-App aus dem Google Play Store herunter."
}
},
"el" : {
"stringUnit" : {
"state" : "translated",
"value" : "Αν αυτό συμβαίνει επανειλημμένα, επανεκκινήστε το τηλέφωνό σας ή δοκιμάστε να κατεβάσετε την εφαρμογή QuickDrop για Android από το Google Play."
"value" : "Αν αυτό συμβαίνει επαναλαμβανόμενα, παρακαλώ επανεκκινήστε τη συσκευή σας ή δοκιμάστε να κατεβάσετε την εφαρμογή QuickDrop για Android από το Google Play."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "If this happens repeatedly, please restart your phone or try downloading the QuickDrop Android app from Google Play."
"value" : "If this happens repeatedly, please restart your other device or try downloading the QuickDrop Android app from Google Play."
}
},
"en-AU" : {
"stringUnit" : {
"state" : "translated",
"value" : "If this happens repeatedly, please restart your phone or try downloading the QuickDrop Android app from Google Play Store."
"value" : "If this happens repeatedly, please restart your other device or try downloading the QuickDrop Android app from Google Play."
}
},
"en-CA" : {
"stringUnit" : {
"state" : "translated",
"value" : "If this keeps happening, please restart your phone or try downloading the QuickDrop Android app from Google Play."
"value" : "If this happens repeatedly, please restart your other device or try downloading the QuickDrop Android app from Google Play."
}
},
"en-GB" : {
"stringUnit" : {
"state" : "translated",
"value" : "If this happens repeatedly, please restart your phone or try downloading the QuickDrop Android app from Google Play Store."
"value" : "If this happens repeatedly, please restart your other device or try downloading the QuickDrop Android app from Google Play."
}
},
"es" : {
"stringUnit" : {
"state" : "translated",
"value" : "Si esto ocurre repetidamente, reinicia tu teléfono o intenta descargar la app QuickDrop para Android desde Google Play."
"value" : "Si esto ocurre repetidamente, reinicia tu otro dispositivo o intenta descargar la aplicación QuickDrop para Android desde Google Play."
}
},
"es-419" : {
"stringUnit" : {
"state" : "translated",
"value" : "Si esto ocurre repetidamente, reinicia tu teléfono o intenta descargar la app QuickDrop para Android desde Google Play."
"value" : "Si esto ocurre repetidamente, por favor reinicia tu otro dispositivo o intenta descargar la app QuickDrop para Android desde Google Play."
}
},
"fi" : {
"stringUnit" : {
"state" : "translated",
"value" : "Jos tämä tapahtuu toistuvasti, käynnistä puhelin uudelleen tai kokeile ladata QuickDrop Android -sovellus Google Playsta."
"value" : "Jos tämä toistuu, käynnistä toinen laitteesi uudelleen tai kokeile ladata QuickDrop Android -sovellus Google Playsta."
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Si cela se produit à plusieurs reprises, veuillez redémarrer votre téléphone ou essayer de télécharger l'application QuickDrop pour Android depuis Google Play."
"value" : "Si cela se produit à plusieurs reprises, veuillez redémarrer votre autre appareil ou essayer de télécharger l'application QuickDrop pour Android depuis Google Play."
}
},
"fr-CA" : {
"stringUnit" : {
"state" : "translated",
"value" : "Si cela se produit à plusieurs reprises, veuillez redémarrer votre téléphone ou essayer de télécharger l'application QuickDrop pour Android depuis Google Play."
"value" : "Si cela se produit souvent, veuillez redémarrer votre autre appareil ou essayez de télécharger l’application QuickDrop pour Android sur Google Play."
}
},
"he" : {
"stringUnit" : {
"state" : "translated",
"value" : "אם זה קורה שוב ושוב, נא להפעיל את הטלפון מחדש או לנסות להוריד את אפליקציית QuickDrop לאנדרואיד מגוגל פליי."
"value" : "אם זה קורה שוב ושוב, נא הפעל מחדש את המכשיר השני או נסה להוריד את אפליקציית QuickDrop לאנדרואיד מ-Google Play."
}
},
"hi" : {
"stringUnit" : {
"state" : "translated",
"value" : "यदि ऐसा बार-बार होता है, तो कृपया अपने फोन को रीस्टार्ट करें या Google Play से QuickDrop Android ऐप डाउनलोड करने की कोशिश करें।"
"value" : "अगर यह बार-बार होता है, तो कृपया अपने दूसरे डिवाइस को पुनः प्रारंभ करें या Google Play से QuickDrop Android ऐप डाउनलोड करने का प्रयास करें।"
}
},
"hr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Ako se ovo ponavlja, ponovno pokrenite svoj telefon ili pokušajte preuzeti QuickDrop Android aplikaciju s Google Playa."
"value" : "Ako se ovo ponavlja, ponovno pokrenite drugi uređaj ili pokušajte preuzeti QuickDrop Android aplikaciju s Google Playa."
}
},
"hu" : {
"stringUnit" : {
"state" : "translated",
"value" : "Ha ez ismétlődően előfordul, indítsd újra a telefonodat, vagy próbáld meg letölteni a QuickDrop Android alkalmazást a Google Play-ről."
"value" : "Ha ez ismétlődően előfordul, indítsa újra a másik eszközt, vagy próbálja letölteni a QuickDrop Android alkalmazást a Google Play-ről."
}
},
"id" : {
"stringUnit" : {
"state" : "translated",
"value" : "Jika ini terjadi berulang kali, silakan mulai ulang ponsel Anda atau coba unduh aplikasi QuickDrop untuk Android dari Google Play."
"value" : "Jika ini terjadi berulang kali, silakan mulai ulang perangkat Anda yang lain atau coba unduh aplikasi QuickDrop Android dari Google Play."
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "Se questo accade ripetutamente, riavvia il telefono o prova a scaricare l'app QuickDrop per Android da Google Play."
"value" : "Se questo accade ripetutamente, riavvia il tuo altro dispositivo o prova a scaricare l'app QuickDrop per Android da Google Play."
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "この問題が繰り返し発生する場合は、スマートフォンを再起動するか、Google Play から QuickDrop Android アプリをダウンロードしてください。"
"value" : "この問題が繰り返し発生する場合は、他のデバイスを再起動するか、Google Play から QuickDrop Android アプリをダウンロードしてください。"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "이 현상이 반복되면 휴대폰을 재시작하거나 Google Play에서 QuickDrop Android 앱을 다운로드해 보세요."
"value" : "이 문제가 반복된다면, 다른 기기를 재시작하거나 Google Play에서 QuickDrop Android 앱을 다운로드해보세요."
}
},
"ms" : {
"stringUnit" : {
"state" : "translated",
"value" : "Jika ini berlaku berulang kali, sila mulakan semula telefon anda atau cuba muat turun aplikasi QuickDrop Android dari Google Play."
"value" : "Jika ini berlaku berulang kali, sila mulakan semula peranti anda yang lain atau cuba muat turun aplikasi QuickDrop Android dari Google Play."
}
},
"nb" : {
"stringUnit" : {
"state" : "translated",
"value" : "Hvis dette skjer gjentatte ganger, start telefonen på nytt eller prøv å laste ned QuickDrop-appen for Android fra Google Play."
"value" : "Hvis dette skjer gjentatte ganger, start den andre enheten på nytt eller prøv å laste ned QuickDrop Android-appen fra Google Play."
}
},
"nl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Als dit herhaaldelijk gebeurt, start dan je telefoon opnieuw op of download de QuickDrop Android-app via Google Play."
"value" : "Als dit herhaaldelijk gebeurt, start dan je andere apparaat opnieuw op of download de QuickDrop Android-app via Google Play."
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Jeśli to się powtarza, uruchom ponownie telefon lub spróbuj pobrać aplikację QuickDrop na Androida z Google Play."
"value" : "Jeśli to się powtarza, uruchom ponownie inne urządzenie lub spróbuj pobrać aplikację QuickDrop na Androida ze Sklepu Google Play."
}
},
"pt-BR" : {
"stringUnit" : {
"state" : "translated",
"value" : "Se isso acontecer repetidamente, reinicie seu telefone ou tente baixar o aplicativo QuickDrop para Android na Google Play."
"value" : "Se isso acontecer repetidamente, reinicie seu outro dispositivo ou tente baixar o app QuickDrop para Android na Google Play."
}
},
"pt-PT" : {
"stringUnit" : {
"state" : "translated",
"value" : "Se isto acontecer repetidamente, reinicie o seu telemóvel ou tente instalar a aplicação QuickDrop para Android a partir da Google Play."
"value" : "Se isto acontecer repetidamente, reinicie o seu outro dispositivo ou tente descarregar a app QuickDrop para Android na Google Play."
}
},
"ro" : {
"stringUnit" : {
"state" : "translated",
"value" : "Dacă se întâmplă în mod repetat, repornește telefonul sau încearcă să descarci aplicația QuickDrop pentru Android din Google Play."
"value" : "Dacă se întâmplă frecvent, repornește celălalt dispozitiv sau încearcă să descarci aplicația QuickDrop pentru Android din Google Play."
}
},
"ru" : {
"stringUnit" : {
"state" : "translated",
"value" : "Если это происходит неоднократно, перезапустите телефон или попробуйте установить приложение QuickDrop для Android из Google Play."
"value" : "Если это происходит часто, перезагрузите ваше другое устройство или попробуйте скачать приложение QuickDrop для Android в Google Play."
}
},
"sv" : {
"stringUnit" : {
"state" : "translated",
"value" : "Om detta händer upprepade gånger, starta om din telefon eller ladda ner QuickDrop-appen för Android från Google Play."
"value" : "Om detta händer upprepade gånger, starta om din andra enhet eller ladda ner QuickDrop Android-appen från Google Play."
}
},
"th" : {
"stringUnit" : {
"state" : "translated",
"value" : "หากเกิดเหตุการณ์นี้ซ้ำ โปรดรีสตาร์ทโทรศัพท์หรือดาวน์โหลดแอป QuickDrop สำหรับ Android จาก Google Play"
"value" : "หากเกิดเหตุการณ์นี้บ่อยๆ กรุณารีสตาร์ทอุปกรณ์อีกเครื่องหรือดาวน์โหลดแอป QuickDrop สำหรับ Android จาก Google Play"
}
},
"tr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Bu tekrar ederse, lütfen telefonunuzu yeniden başlatın veya QuickDrop Android uygulamasını Google Play'den indirmeyi deneyin."
"value" : "Bu durum tekrar ederse, lütfen diğer cihazınızı yeniden başlatın veya Google Play'den QuickDrop Android uygulamasını indirmeyi deneyin."
}
},
"uk" : {
"stringUnit" : {
"state" : "translated",
"value" : "Якщо це трапляється повторно, перезавантажте телефон або спробуйте завантажити додаток QuickDrop для Android з Google Play."
"value" : "Якщо це трапляється часто, перезапустіть інший пристрій або спробуйте завантажити додаток QuickDrop для Android з Google Play."
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "Nếu điều này xảy ra liên tục, vui lòng khởi động lại điện thoại hoặc thử tải ứng dụng QuickDrop cho Android từ Google Play."
"value" : "Nếu điều này xảy ra nhiều lần, vui lòng khởi động lại thiết bị kia hoặc thử tải ứng dụng QuickDrop cho Android từ Google Play."
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "如果此问题反复出现,请重启手机或尝试从 Google Play 下载 QuickDrop 安卓应用。"
"value" : "如果这种情况反复发生,请重启你的另一台设备,或尝试从 Google Play 下载 QuickDrop 安卓应用。"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "如果這種情況重複發生,請重啟您的手機,或嘗試從 Google Play 下載 QuickDrop Android 應用程式。"
"value" : "如果這種情況反覆發生,請重新啟動您的其他裝置,或嘗試從 Google Play 下載 QuickDrop Android 應用程式。"
}
}
}
@@ -27246,229 +27246,229 @@
"ar" : {
"stringUnit" : {
"state" : "translated",
"value" : "فشل في استقبال الملفات من %@"
"value" : "فشل الاتصال مع %@"
}
},
"ca" : {
"stringUnit" : {
"state" : "translated",
"value" : "No s'han pogut rebre arxius de %@"
"value" : "No s'ha pogut connectar a %@"
}
},
"cs" : {
"stringUnit" : {
"state" : "translated",
"value" : "Nepodařilo se obdržet soubory od %@"
"value" : "Připojení k %@ selhalo"
}
},
"da" : {
"stringUnit" : {
"state" : "translated",
"value" : "Mislykkedes at modtage filer fra %@"
"value" : "Forbindelsen til %@ mislykkedes"
}
},
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Die Daten von %@ konnten nicht empfangen werden"
"value" : "Verbindung zu %@ fehlgeschlagen"
}
},
"el" : {
"stringUnit" : {
"state" : "translated",
"value" : "Αποτυχία λήψης αρχείων από %@"
"value" : "Η σύνδεση με το %@ απέτυχε"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Failed to receive files from %@"
"value" : "Connection to %@ failed"
}
},
"en-AU" : {
"stringUnit" : {
"state" : "translated",
"value" : "Failed to get files from %@"
"value" : "Connection to %@ failed"
}
},
"en-CA" : {
"stringUnit" : {
"state" : "translated",
"value" : "Failed to receive files from %@"
"value" : "Connection to %@ failed"
}
},
"en-GB" : {
"stringUnit" : {
"state" : "translated",
"value" : "Failed to receive files from %@"
"value" : "Connection to %@ failed"
}
},
"es" : {
"stringUnit" : {
"state" : "translated",
"value" : "Error al recibir archivos de %@"
"value" : "La conexión con %@ falló"
}
},
"es-419" : {
"stringUnit" : {
"state" : "translated",
"value" : "Fallo al recibir archivos de %@"
"value" : "La conexión a %@ falló"
}
},
"fi" : {
"stringUnit" : {
"state" : "translated",
"value" : "Virhe tiedostojen vastaanottamisessa: %@"
"value" : "Yhteys laitteeseen %@ epäonnistui."
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Échec de la réception des fichiers de %@"
"value" : "La connexion à %@ a échoué"
}
},
"fr-CA" : {
"stringUnit" : {
"state" : "translated",
"value" : "Échec de la réception des fichiers de %@"
"value" : "La connexion à %@ a échoué"
}
},
"he" : {
"stringUnit" : {
"state" : "translated",
"value" : "נכשל בקבלת קבצים מ-%@"
"value" : "החיבור אל %@ נכשל"
}
},
"hi" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ से फ़ाइलें प्राप्त करने में विफल"
"value" : "%@ से कनेक्शन विफल हुआ"
}
},
"hr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Neuspješno preuzimanje datoteka s %@"
"value" : "Veza s %@ nije uspjela"
}
},
"hu" : {
"stringUnit" : {
"state" : "translated",
"value" : "Nem sikerült %@-tól/től fájlokat fogadni"
"value" : "A(z) %@ kapcsolódás sikertelen"
}
},
"id" : {
"stringUnit" : {
"state" : "translated",
"value" : "Gagal menerima file dari %@"
"value" : "Koneksi ke %@ gagal"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "Impossibile ricevere i file da %@"
"value" : "Connessione a %@ non riuscita"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@からのファイル受信に失敗しました。"
"value" : "%@ への接続に失敗しました"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@에서 전송한 Nearby Share가 실패했습니다."
"value" : "%@에 연결 실패"
}
},
"ms" : {
"stringUnit" : {
"state" : "translated",
"value" : "Gagal menerima fail daripada %@"
"value" : "Sambungan ke %@ gagal"
}
},
"nb" : {
"stringUnit" : {
"state" : "translated",
"value" : "Kunne ikke motta filer fra %@"
"value" : "Tilkobling til %@ mislyktes"
}
},
"nl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Mislukt om bestanden te ontvangen van %@"
"value" : "Verbinding met %@ mislukt"
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Nie udało się odebrać plików od %@"
"value" : "Połączenie z %@ nie powiodło się"
}
},
"pt-BR" : {
"stringUnit" : {
"state" : "translated",
"value" : "Falha ao receber arquivos de %@"
"value" : "Conexão com %@ falhou"
}
},
"pt-PT" : {
"stringUnit" : {
"state" : "translated",
"value" : "Falha ao receber ficheiros de %@"
"value" : "A ligação a %@ falhou"
}
},
"ro" : {
"stringUnit" : {
"state" : "translated",
"value" : "Recepționarea fișierelor de la %@ a eșuat"
"value" : "Conectarea la %@ a eșuat"
}
},
"ru" : {
"stringUnit" : {
"state" : "translated",
"value" : "Не удалость принять файлы от %@"
"value" : "Не удалось подключиться к %@"
}
},
"sv" : {
"stringUnit" : {
"state" : "translated",
"value" : "Misslyckades att ta emot filer från %@"
"value" : "Anslutning till %@ misslyckades"
}
},
"th" : {
"stringUnit" : {
"state" : "translated",
"value" : "เกิดข้อผิดพลาดในการรับไฟล์จาก %@"
"value" : "การเชื่อมต่อกับ %@ ล้มเหลว"
}
},
"tr" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ dosyalarından dosyalar alınamadı."
"value" : "%@ ile bağlantı başarısız oldu"
}
},
"uk" : {
"stringUnit" : {
"state" : "translated",
"value" : "Не вдалося отримати файли від %@"
"value" : "Не вдалося підключитися до %@"
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "Không nhận được tệp từ %@"
"value" : "Kết nối với %@ thất bại"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "无法从 %@ 接收文件"
"value" : "连接到 %@ 失败"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "無法從 %@ 接收檔案"
"value" : "連接 %@ 失敗"
}
}
}
+3 -3
View File
@@ -49,7 +49,7 @@ class ReceiveModel: ObservableObject, InboundAppDelegate {
AudioManager.playIncomingFileSound()
#endif
let mainMessage = transfer.getDescription(deviceName: device.name ?? "Android", alreadyAccepted: false)
let mainMessage = transfer.getDescription(deviceName: device.name ?? "UnknownDevice".localized(), alreadyAccepted: false)
let pinCodeMessage = transfer.getPinCodeMessage()
let transferID = transfer.id
@@ -111,7 +111,7 @@ class ReceiveModel: ObservableObject, InboundAppDelegate {
func obtainedUserConsentAutomatically(transfer: TransferMetadata, device: RemoteDeviceInfo) {
let mainMessage = transfer.getDescription(deviceName: device.name ?? "Android", alreadyAccepted: true)
let mainMessage = transfer.getDescription(deviceName: device.name ?? "UnknownDevice".localized(), alreadyAccepted: true)
#if os(macOS)
@@ -203,7 +203,7 @@ class ReceiveModel: ObservableObject, InboundAppDelegate {
#endif
controlPlusScreen(false)
ErrorAlertHandler.shared.showErrorAlert(for: device.name ?? "Android", error: error)
ErrorAlertHandler.shared.showErrorAlert(for: device.name ?? "UnknownDevice".localized(), error: error)
} else {
#if os(iOS)
+10 -7
View File
@@ -61,11 +61,10 @@ class SendModel: ObservableObject, OutboundAppDelegate {
func connectionFailed(error: any Error) {
#if os(iOS)
errorVibration()
#endif
ErrorAlertHandler.shared.showErrorAlert(for: selectedDevice?.name ?? "UnknownDevice".localized(), error: error)
if let name = selectedDevice?.name {
errorVibration()
ErrorAlertHandler.shared.showErrorAlert(for: name, error: error)
}
progressValue = nil
selectedDevice = nil
@@ -126,9 +125,13 @@ class SendModel: ObservableObject, OutboundAppDelegate {
else {
progressValue = 0
progressState = "Connecting".localized()
progressState = "Preparing".localized()
selectedDevice = device
NearbyConnectionManager.shared.startOutgoingTransfer(deviceID: device.id!, delegate: self, urls: urls, textToSend: textToSend)
runAfter(seconds: 0.3) {
NearbyConnectionManager.shared.startOutgoingTransfer(deviceID: device.id!, delegate: self, urls: self.urls, textToSend: self.textToSend)
self.progressState = "Connecting".localized()
}
}
}
}
+1 -1
View File
@@ -284,7 +284,7 @@ struct DeviceButtonLabel: View {
var body: some View {
HStack(spacing: 12) {
let name = device.name ?? "Android"
let name = device.name ?? "UnknownDevice".localized()
ZStack {
Circle()
+25
View File
@@ -601,6 +601,31 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
ZIPFoundation
https://github.com/weichsel/ZIPFoundation
MIT License
Copyright (c) 2017-2025 Thomas Zoechling (https://www.peakstep.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SwiftECC
https://github.com/leif-ibsen/SwiftECC
Copyright (c) 2021 Leif Ibsen
+20 -15
View File
@@ -252,27 +252,32 @@ class ShareViewController: NSViewController, OutboundAppDelegate {
progressDeviceName?.stringValue = getDeviceName(device: device)
progressDeviceIcon?.image = imageForDeviceType(type: device.type)
progressProgressBar?.startAnimation(nil)
progressState?.stringValue = "Connecting".localized()
progressState?.stringValue = "Preparing".localized()
chosenDevice = device
NearbyConnectionManager.shared.stopDeviceDiscovery()
NearbyConnectionManager.shared.startOutgoingTransfer(deviceID: device.id!, delegate: self, urls: urls, textToSend: textToSend)
let timeoutAlert = DispatchWorkItem {
if !self.connectionEstablished {
AudioManager.playErrorSound()
let alert = NSAlert()
alert.alertStyle = .critical
runAfter(seconds: 0.3) {
NearbyConnectionManager.shared.startOutgoingTransfer(deviceID: device.id!, delegate: self, urls: self.urls, textToSend: self.textToSend)
alert.messageText = "TimeoutTitle".localized()
alert.informativeText = "TimeoutDescription".localized()
alert.addButton(withTitle: "TimeoutButton".localized())
self.progressState?.stringValue = "Connecting".localized()
alert.beginSheetModal(for: self.view.window!) { _ in }
let timeoutAlert = DispatchWorkItem {
if !self.connectionEstablished {
AudioManager.playErrorSound()
let alert = NSAlert()
alert.alertStyle = .critical
alert.messageText = "TimeoutTitle".localized()
alert.informativeText = "TimeoutDescription".localized()
alert.addButton(withTitle: "TimeoutButton".localized())
alert.beginSheetModal(for: self.view.window!) { _ in }
}
}
}
timeoutDispatchWorkItem = timeoutAlert
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0, execute: timeoutAlert)
self.timeoutDispatchWorkItem = timeoutAlert
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0, execute: timeoutAlert)
}
}
@@ -381,6 +386,6 @@ extension ShareViewController: NSCollectionViewDataSource {
return name
}
return "Android"
return "UnknownDevice".localized()
}
}