From 253e1e7d257d1435780fea71cd3363a8dbe3eb8b Mon Sep 17 00:00:00 2001 From: Aquarius Xiong Date: Sun, 27 Dec 2020 14:46:07 +0800 Subject: [PATCH 1/5] 1. Fix core data merge conflict in FileCache, context.save() 2. Fix task synchronization in getting folder uuid in WebDAVStorage 3. Replace some prints with os_log. --- RemoteCloud/RemoteCloud/FileCache.swift | 4 + RemoteCloud/RemoteCloud/Info.plist | 5 + .../RemoteCloud/Storages/Cryptomator.swift | 166 +++++++++++++----- .../RemoteCloud/Storages/WebDAVStorage.swift | 8 +- 4 files changed, 137 insertions(+), 46 deletions(-) diff --git a/RemoteCloud/RemoteCloud/FileCache.swift b/RemoteCloud/RemoteCloud/FileCache.swift index b67689c..1687b46 100644 --- a/RemoteCloud/RemoteCloud/FileCache.swift +++ b/RemoteCloud/RemoteCloud/FileCache.swift @@ -124,6 +124,10 @@ public class FileCache { defer { group.leave() } + + // Fix CoreData merge conflict shows managed object version change not data + context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy + let fetchrequest = NSFetchRequest(entityName: "FileCacheItem") fetchrequest.predicate = NSPredicate(format: "storage == %@ && id == %@ && chunkOffset == %lld", storage, id, offset) do{ diff --git a/RemoteCloud/RemoteCloud/Info.plist b/RemoteCloud/RemoteCloud/Info.plist index e1fe4cf..783773a 100644 --- a/RemoteCloud/RemoteCloud/Info.plist +++ b/RemoteCloud/RemoteCloud/Info.plist @@ -2,6 +2,11 @@ + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable diff --git a/RemoteCloud/RemoteCloud/Storages/Cryptomator.swift b/RemoteCloud/RemoteCloud/Storages/Cryptomator.swift index 6fed04e..6fe758a 100644 --- a/RemoteCloud/RemoteCloud/Storages/Cryptomator.swift +++ b/RemoteCloud/RemoteCloud/Storages/Cryptomator.swift @@ -818,10 +818,15 @@ public class Cryptomator: ChildStorage { (t, encryptedName) = self.decodeFilename(encodedName: encodedName, t: t) guard t != .broken else { return} guard let decryptedName = self.decryptFilename(ciphertextName: encryptedName, dirId: dirId) else { return} + + // Skip files started with "." + if ( decryptedName.hasPrefix(".")) {continue} + if t == .directory { self.storeItem(parentId: fileId, item: item, name: decryptedName, isFolder: true, dirId: dirId, deflatedName: item.name, path: path, context: backgroundContext) } else if t == .regular { + self.storeItem(parentId: fileId,item: item, name: decryptedName, isFolder: false, dirId: dirId, deflatedName: item.name, path: path, context: backgroundContext) } group.enter() @@ -1011,8 +1016,79 @@ public class Cryptomator: ChildStorage { return CryptomatorRemoteItem(path: path) } - var pDirIdCache = [String: (Date, String)]() + func resolveDirUUIDFile(dirIdHash: String, deflateDirId: String, onFinish: @escaping (String?)->Void) { + findParentStorage(path: [self.DATA_DIR_NAME, String(dirIdHash.prefix(2)), String(dirIdHash.suffix(30)), deflateDirId]) { items in + for item in items { + if item.name != self.V7_DIR {continue} + item.read() { data in + guard let data = data else { + onFinish(nil) + return + } + onFinish(String(bytes: data, encoding: .utf8)) + return + } + } + onFinish(nil) + } + } + + func resolveUUIDFromItem( item: RemoteItem, onFinish: @escaping (String?)->Void) { + var id: String? = nil + var uuidItem: RemoteItem = item + let uuidGroup = DispatchGroup() + let uuidSem = DispatchSemaphore(value: 0) + + if ( self.version == 7) { + let deflateDirID = item.name + let array = item.id.components(separatedBy: "/") + uuidGroup.enter() + findParentStorage(path: [array[1], array[2], array[3], deflateDirID]) { items in + defer { + uuidGroup.leave() + uuidSem.signal() + } + for item in items { + if item.name != self.V7_DIR {continue} + uuidItem = item + return + } + } + } else { + uuidSem.signal() + } + + uuidGroup.enter() + uuidSem.wait() + uuidItem.read() { data in + defer { + uuidGroup.leave() + + } + guard let data = data else {return} + guard let tempid = String(bytes: data, encoding: .utf8) else { return} + id = tempid + } + + uuidGroup.notify(queue: .global()) { + onFinish(id) + } + } + + var pDirIdCache = [String: (Date, String)]() + /* + Use parent folder's HASH to access/traverse storage, match file name specificied by folder's name in BASE32/64, and then read this folder's UUID in the matching file. + In V6, the folder UUID is stored in item.id; in V7, the folder UUID is stored in item.id/dir.c9r. https://github.com/cryptomator/cryptofs/issues/64 + + Example below - + fileId = "bb26ccca-3726-4c1c-b4eb-d58802d03d66/0ALUAELRDZQI3W3UWPE5JOWMJJQ6PRLEHRAJJDDU56M======" + Parent folder UUID - bb26ccca-3726-4c1c-b4eb-d58802d03d66 + File containing this folder's UUID - 0ALUAELRDZQI3W3UWPE5JOWMJJQ6PRLEHRAJJDDU56M====== + + item.id = "/d/S7/3BUXDLCW4X4IOZBQ4X4BNOLJ273A4T/0ALUAELRDZQI3W3UWPE5JOWMJJQ6PRLEHRAJJDDU56M======" + item.path = "rclone:/d/S7/3BUXDLCW4X4IOZBQ4X4BNOLJ273A4T/0ALUAELRDZQI3W3UWPE5JOWMJJQ6PRLEHRAJJDDU56M======" + */ func resolveDirId(fileId: String, onFinish: ((String?)->Void)?) { os_log("%{public}@", log: log, type: .debug, "resolveFileId(cryptomator:\(storageName ?? "")) \(fileId)") let fixFileId = (fileId == "") ? "/" : fileId @@ -1024,7 +1100,7 @@ public class Cryptomator: ChildStorage { onFinish?("") return } - + if let (d, id) = pDirIdCache[fileId] { if Date(timeIntervalSinceNow: -5*60) > d { pDirIdCache[fileId] = nil @@ -1041,61 +1117,67 @@ public class Cryptomator: ChildStorage { return } - /* - Use parent folder's HASH to access/traverse storage, match file name specificied by folder's name in BASE32/64, and then read this folder's UUID in the matching file. - In V6, the folder UUID is stored in item.id; in V7, the folder UUID is stored in item.id/dir.c9r. https://github.com/cryptomator/cryptofs/issues/64 - - Example below - - fileId = "bb26ccca-3726-4c1c-b4eb-d58802d03d66/0ALUAELRDZQI3W3UWPE5JOWMJJQ6PRLEHRAJJDDU56M======" - Parent folder UUID - bb26ccca-3726-4c1c-b4eb-d58802d03d66 - File containing this folder's UUID - 0ALUAELRDZQI3W3UWPE5JOWMJJQ6PRLEHRAJJDDU56M====== - - item.id = "/d/S7/3BUXDLCW4X4IOZBQ4X4BNOLJ273A4T/0ALUAELRDZQI3W3UWPE5JOWMJJQ6PRLEHRAJJDDU56M======" - item.path = "rclone:/d/S7/3BUXDLCW4X4IOZBQ4X4BNOLJ273A4T/0ALUAELRDZQI3W3UWPE5JOWMJJQ6PRLEHRAJJDDU56M======" - */ + var id: String? = nil + var uuidItem: RemoteItem? = nil + let group = DispatchGroup() + let sem = DispatchSemaphore.init(value: 0) group.enter() findParentStorage(path: [DATA_DIR_NAME, String(dirIdHash.prefix(2)), String(dirIdHash.suffix(30))]) { items in - - defer { - group.leave() - } - + + /* This for loop runs as a concurrent task in global queue */ for item in items { if item.name != deflateDirId { continue } + /* + if (self.version == 6) { + uuidItem = item + sem.signal() + } else { + let deflateDirID = item.name + let array = item.id.components(separatedBy: "/") - var tempItem: RemoteItem = item - if self.version == 7 { group.enter() - - guard let uuidItem = CloudFactory.shared[self.baseRootStorage]?.get(fileId: (item.id + self.V7_DIR)), self.version == 7 else { defer { + self.findParentStorage(path: [array[1], array[2], array[3], deflateDirID]) { items in + for item in items { + if item.name != self.V7_DIR {continue} + uuidItem = item + + sem.signal() group.leave() + return } - - onFinish?(nil) - return } - tempItem = uuidItem - } + }*/ - tempItem.read() { data in - var id: String? = nil - defer { - onFinish?(id) - } - guard let data = data else {return} - guard let tempid = String(bytes: data, encoding: .utf8) else { return} - id = tempid - - os_log("%{public}@", log: self.log, type: .debug, "resolveFileId(cryptomator:\(self.storageName ?? "")) \(fileId)->\(String(describing: id))") - self.pDirIdCache[fileId] = (Date(), id) as? (Date, String) + + group.enter() + self.resolveUUIDFromItem(item: item) { dirUUID in + id = dirUUID + group.leave() } + break } // end item in items loop - group.notify( queue: .global()) { - onFinish?(nil) - } + group.leave() } //End of findParentStorage + + /* + group.enter() + sem.wait() // Wait till matching item is found. + uuidItem!.read() { data in + guard let data = data else { return} + guard let tempid = String(bytes: data, encoding: .utf8) else { return} + id = tempid + group.leave() + }*/ + + group.notify( queue: .global()) { + defer { onFinish?(id)} + + guard let id = id else { return} + os_log("%{public}@", log: self.log, type: .debug, "resolveFileId(cryptomator:\(self.storageName ?? "")) \(fileId)->\(String(describing: id))") + self.pDirIdCache[fileId] = (Date(), id) + } } diff --git a/RemoteCloud/RemoteCloud/Storages/WebDAVStorage.swift b/RemoteCloud/RemoteCloud/Storages/WebDAVStorage.swift index 24beef5..0e54f52 100644 --- a/RemoteCloud/RemoteCloud/Storages/WebDAVStorage.swift +++ b/RemoteCloud/RemoteCloud/Storages/WebDAVStorage.swift @@ -625,13 +625,13 @@ public class WebDAVStorage: NetworkStorage, URLSessionTaskDelegate, URLSessionDa var prop: [String: String] = [:] func parserDidStartDocument(_ parser: XMLParser) { - print("parser Start") + os_log("%{public}@", log: OSLog.default, type: .debug, "parser Start") } func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { switch elementName { case let str where str.hasSuffix(":multistatus"): - print("start") + os_log("%{public}@", log: OSLog.default, type: .debug, "start") case let str where str.hasSuffix(":response"): response.append([:]) case let str where str.hasSuffix(":propstat"): @@ -677,7 +677,7 @@ public class WebDAVStorage: NetworkStorage, URLSessionTaskDelegate, URLSessionDa func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { switch elementName { case let str where str.hasSuffix(":multistatus"): - print("end") + os_log("%{public}@", log: OSLog.default, type: .debug, "end") case let str where str.hasSuffix(":propstat"): response[response.count-1]["propstat"] = curProp case let str where str.hasSuffix(":prop"): @@ -689,7 +689,7 @@ public class WebDAVStorage: NetworkStorage, URLSessionTaskDelegate, URLSessionDa } func parserDidEndDocument(_ parser: XMLParser) { - print("parser End") + os_log("%{public}@", log: OSLog.default, type: .debug, "parser End") onFinish?(response) } From 9d2278feeec58637c6138bfb0669b18a04e2ffad Mon Sep 17 00:00:00 2001 From: Aquarius Xiong Date: Fri, 1 Jan 2021 19:40:06 +0800 Subject: [PATCH 2/5] Replace simple Request with RequestFromTemplate. Note Xcode's weird support for FromTemplate in editor. --- .../RemoteCloud/Storages/Cryptomator.swift | 116 ++++++++++++++++-- .../RemoteCloud/Storages/WebDAVStorage.swift | 16 ++- .../cloud.xcdatamodel/contents | 57 +++++---- 3 files changed, 146 insertions(+), 43 deletions(-) diff --git a/RemoteCloud/RemoteCloud/Storages/Cryptomator.swift b/RemoteCloud/RemoteCloud/Storages/Cryptomator.swift index 6fe758a..880b8d9 100644 --- a/RemoteCloud/RemoteCloud/Storages/Cryptomator.swift +++ b/RemoteCloud/RemoteCloud/Storages/Cryptomator.swift @@ -142,6 +142,10 @@ public class Cryptomator: ChildStorage { let LONG_NAME_FILE_EXT = ".lng" let masterkey_filename = "masterkey.cryptomator" let V7_DIR = "dir.c9r" + let V7_SYMLINK = "symlink.c9r" + let V7_SHORT_SUFFIX = "c9s" + let V7_SHORT_FILE = "contents.c9r" + let V7_SHORT_NAME = "name.c9s" enum ItemType { case regular @@ -728,8 +732,8 @@ public class Cryptomator: ChildStorage { } func storeItem(parentId: String, item: RemoteItem, name: String, isFolder: Bool, dirId: String, deflatedName: String, path: String, context: NSManagedObjectContext) { - os_log("%{public}@", log: log, type: .debug, "storeItem(cryptomator:\(storageName ?? "")) \(name)") - + os_log("%{public}@", log: log, type: .debug, "storeItem(cryptomator:\(storageName ?? "")) \(name); \(dirId)/\(deflatedName)") + context.perform { let newid = "\(dirId)/\(deflatedName)" let newname = name @@ -740,10 +744,20 @@ public class Cryptomator: ChildStorage { let fetchRequest = NSFetchRequest(entityName: "RemoteData") fetchRequest.predicate = NSPredicate(format: "id == %@ && storage == %@", newid, self.storageName ?? "") - if let result = try? context.fetch(fetchRequest) { + + // Will this be faster than simple fetchRequest? + // XCode 12.3. Must use custom predicate in data model editor instead of picking fields directly. + let fetchRequestTemplate = CloudFactory.shared.data.persistentContainer.managedObjectModel.fetchRequestFromTemplate(withName: "fetchByIDAndStorage", substitutionVariables: ["STORAGE" : self.storageName ?? "", "ID" : newid]) as! NSFetchRequest + + if let result = try? context.fetch(fetchRequestTemplate) { +// if let result = try? context.fetch(fetchRequest) { + let itemcount = result.count + os_log("%{public}@", log: self.log, type: .debug, "Delete \(itemcount) old items (cryptomator:\(self.storageName ?? "")) \(name); \(newid)") for object in result { - context.delete(object as! NSManagedObject) + context.delete(object as NSManagedObject) } + } else { + os_log("%{public}@", log: self.log, type: .debug, "FAILED fetch before deleting (cryptomator:\(self.storageName ?? "")) \(name); \(newid)") } let newitem = RemoteData(context: context) @@ -803,15 +817,25 @@ public class Cryptomator: ChildStorage { } } else { // self.version == 7 // This only indicates parent folder is actually a folder - // TODO - Add shortened name support + // TODO - verify shortened name support // TODO - Add symlink support if ( encodedName == "dir.c9r" || - encodedName.hasSuffix(".c9s") || encodedName == "symlink.c9r" ) { continue } - - t = item.isFolder ? .directory : .regular + if item.name.hasSuffix(self.V7_SHORT_SUFFIX) { + group.enter() + self.resolveMetadataFile(item: item) { (type, orgname) in + defer { + group.leave() + } + guard let orgname = orgname else {return} + encodedName = orgname + t = type + } + } else { + t = item.isFolder ? .directory : .regular + } } // end self.version check @@ -855,11 +879,16 @@ public class Cryptomator: ChildStorage { func decodeFilename(encodedName: String, t: ItemType) -> (ItemType, String) { if ( self.version == 7) { - if encodedName.hasSuffix(".c9r") { + if encodedName.hasSuffix(".c9r") { return (t, String(encodedName.dropLast(4))) - } else { - return (.broken, encodedName) } + + // Should not run into this case. + if encodedName.hasSuffix(self.V7_SHORT_SUFFIX) { + + } + return (.broken, encodedName) + } else { return decodeFilename(encryptedName: encodedName) } @@ -894,6 +923,71 @@ public class Cryptomator: ChildStorage { return (.broken, encryptedName) } + func resolveMetadataFile(item: RemoteItem, onFinish: @escaping (ItemType, String?)->Void) { + var inflatedName: String? = nil + var itemType: ItemType = .broken + + var nameItem: RemoteItem = item + let nameGroup = DispatchGroup() + let nameSem = DispatchSemaphore(value: 0) + + if ( self.version == 7) { + let array = item.id.components(separatedBy: "/") + nameGroup.enter() + findParentStorage(path: [array[1], array[2], array[3], item.name]) { items in + defer { + nameGroup.leave() + nameSem.signal() + } + for item in items { + if item.name == self.V7_DIR { + itemType = .directory + continue + } + if item.name == self.V7_SYMLINK { + itemType = .symlink + continue + } + + if item.name == self.V7_SHORT_FILE { + itemType = .regular + continue + } + + if item.name == self.V7_SHORT_NAME { + nameItem = item + } + } + } + } else { // self.version = 6 + nameGroup.enter() + findParentStorage(path: [METADATA_DIR_NAME, String(item.name.prefix(2)), String(item.name.dropFirst(2).prefix(2))]) { items in + defer { + nameGroup.leave() + nameSem.signal() + } + guard items.count > 0 else { return} + nameItem = items[0] + } + } + + nameGroup.enter() + nameSem.wait() + nameItem.read() { data in + defer { + nameGroup.leave() + } + guard let data = data else {return} + guard let tempInflatedName = String(bytes: data, encoding: .utf8) else { return} + inflatedName = tempInflatedName + } + + nameGroup.notify(queue: .global()) { + onFinish(itemType, inflatedName) + } + + } + func resolveMetadataFile(shortName: String, onFinish: @escaping (String?)->Void) { findParentStorage(path: [METADATA_DIR_NAME, String(shortName.prefix(2)), String(shortName.dropFirst(2).prefix(2))]) { items in guard items.count > 0 else { diff --git a/RemoteCloud/RemoteCloud/Storages/WebDAVStorage.swift b/RemoteCloud/RemoteCloud/Storages/WebDAVStorage.swift index 0e54f52..6504de5 100644 --- a/RemoteCloud/RemoteCloud/Storages/WebDAVStorage.swift +++ b/RemoteCloud/RemoteCloud/Storages/WebDAVStorage.swift @@ -534,6 +534,7 @@ public class WebDAVStorage: NetworkStorage, URLSessionTaskDelegate, URLSessionDa super.logout() } + /* Generate RemoteData item from WebDAV records */ func storeItem(item: [String: Any], parentFileId: String? = nil, parentPath: String? = nil, context: NSManagedObjectContext) { let formatter = DateFormatter() formatter.locale = Locale(identifier: "en_US_POSIX") @@ -579,6 +580,7 @@ public class WebDAVStorage: NetworkStorage, URLSessionTaskDelegate, URLSessionDa let fetchRequest = NSFetchRequest(entityName: "RemoteData") fetchRequest.predicate = NSPredicate(format: "id == %@ && storage == %@", id, self.storageName ?? "") + if let result = try? context.fetch(fetchRequest) { for object in result { if let item = object as? RemoteData { @@ -625,13 +627,13 @@ public class WebDAVStorage: NetworkStorage, URLSessionTaskDelegate, URLSessionDa var prop: [String: String] = [:] func parserDidStartDocument(_ parser: XMLParser) { - os_log("%{public}@", log: OSLog.default, type: .debug, "parser Start") + //os_log("%{public}@", log: OSLog.default, type: .debug, "parser Start") } func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { switch elementName { - case let str where str.hasSuffix(":multistatus"): - os_log("%{public}@", log: OSLog.default, type: .debug, "start") +// case let str where str.hasSuffix(":multistatus"): + //os_log("%{public}@", log: OSLog.default, type: .debug, "start") case let str where str.hasSuffix(":response"): response.append([:]) case let str where str.hasSuffix(":propstat"): @@ -676,8 +678,8 @@ public class WebDAVStorage: NetworkStorage, URLSessionTaskDelegate, URLSessionDa func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { switch elementName { - case let str where str.hasSuffix(":multistatus"): - os_log("%{public}@", log: OSLog.default, type: .debug, "end") +// case let str where str.hasSuffix(":multistatus"): + // os_log("%{public}@", log: OSLog.default, type: .debug, "end") case let str where str.hasSuffix(":propstat"): response[response.count-1]["propstat"] = curProp case let str where str.hasSuffix(":prop"): @@ -689,7 +691,7 @@ public class WebDAVStorage: NetworkStorage, URLSessionTaskDelegate, URLSessionDa } func parserDidEndDocument(_ parser: XMLParser) { - os_log("%{public}@", log: OSLog.default, type: .debug, "parser End") + //os_log("%{public}@", log: OSLog.default, type: .debug, "parser End") onFinish?(response) } @@ -794,6 +796,8 @@ public class WebDAVStorage: NetworkStorage, URLSessionTaskDelegate, URLSessionDa listFolder(path: fileId) { result in if let items = result { let backgroundContext = CloudFactory.shared.data.persistentContainer.newBackgroundContext() + let itemcount = items.count + os_log("%{public}@", log: self.log, type: .debug, "store \(itemcount) items(WebDAV:\(self.storageName ?? "") \(fileId)") for item in items { self.storeItem(item: item, parentFileId: fileId, parentPath: path, context: backgroundContext) } diff --git a/RemoteCloud/RemoteCloud/cloud.xcdatamodeld/cloud.xcdatamodel/contents b/RemoteCloud/RemoteCloud/cloud.xcdatamodeld/cloud.xcdatamodel/contents index 43f7053..762afad 100644 --- a/RemoteCloud/RemoteCloud/cloud.xcdatamodeld/cloud.xcdatamodel/contents +++ b/RemoteCloud/RemoteCloud/cloud.xcdatamodeld/cloud.xcdatamodel/contents @@ -1,38 +1,43 @@ - + - - - - + + + + - - - - - + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file From 4ed2ac85270ece6f5d46fa0ad272f871d66c2b83 Mon Sep 17 00:00:00 2001 From: Aquarius Xiong Date: Sat, 2 Jan 2021 22:41:35 +0800 Subject: [PATCH 3/5] Initial snippets reading Digitalized date, GPS coordinates, and show annotation in ViewControllerImage. --- .../project.pbxproj | 107 ++++--- ccViewer/ccViewer/AppDelegate.swift | 16 +- ccViewer/ccViewer/Base.lproj/Main.storyboard | 281 ++++++++++-------- ccViewer/ccViewer/Info.plist | 2 + ccViewer/ccViewer/ViewControllerImage.swift | 48 ++- ccViewer/ccViewer/ccViewer.entitlements | 16 +- 6 files changed, 273 insertions(+), 197 deletions(-) diff --git a/ccViewer/CryptCloudViewer.xcodeproj/project.pbxproj b/ccViewer/CryptCloudViewer.xcodeproj/project.pbxproj index 312952e..f78219b 100644 --- a/ccViewer/CryptCloudViewer.xcodeproj/project.pbxproj +++ b/ccViewer/CryptCloudViewer.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -14,7 +14,6 @@ 3C06934A2253DBD50040DC0B /* ProductManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0693472253DBD40040DC0B /* ProductManager.swift */; }; 3C06934B2253DBD50040DC0B /* PurchaceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0693482253DBD50040DC0B /* PurchaceManager.swift */; }; 3C06934C2253DBD50040DC0B /* PurchaceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0693492253DBD50040DC0B /* PurchaceViewController.swift */; }; - 3C06934E2253E2610040DC0B /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C06934D2253E2610040DC0B /* StoreKit.framework */; }; 3C0D4419224B106C001FCAAC /* TableViewControllerItemsEdit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D4418224B106C001FCAAC /* TableViewControllerItemsEdit.swift */; }; 3C0D441D224C4949001FCAAC /* AuthenticationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C0D441C224C4949001FCAAC /* AuthenticationServices.framework */; }; 3C40091222401D020028A45A /* CustomPlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C40091122401D020028A45A /* CustomPlayerViewController.swift */; }; @@ -53,21 +52,18 @@ 3F19BBD82324203C0040ED19 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F19BBD72324203C0040ED19 /* SystemConfiguration.framework */; }; 3F19BBDA232420450040ED19 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F19BBD9232420450040ED19 /* UIKit.framework */; }; 3F19BBDC232420670040ED19 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F19BBDB232420670040ED19 /* libc++.tbd */; }; - 3F19BC1C232455C80040ED19 /* ffconverter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F19BC1B232455C80040ED19 /* ffconverter.framework */; }; - 3F19BC1D232455C80040ED19 /* ffconverter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3F19BC1B232455C80040ED19 /* ffconverter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3F19BC1F232455C80040ED19 /* ffplayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F19BC1E232455C80040ED19 /* ffplayer.framework */; }; - 3F19BC20232455C80040ED19 /* ffplayer.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3F19BC1E232455C80040ED19 /* ffplayer.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 3F19BC22232455C80040ED19 /* RemoteCloud.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F19BC21232455C80040ED19 /* RemoteCloud.framework */; }; 3F19BC23232455C80040ED19 /* RemoteCloud.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3F19BC21232455C80040ED19 /* RemoteCloud.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 3F3D274423743B00009A4C52 /* TimePickerKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F3D274323743B00009A4C52 /* TimePickerKeyboard.swift */; }; - 3F754D5424C6174A00BF2636 /* GoogleCast.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F754D5224C6164D00BF2636 /* GoogleCast.framework */; platformFilter = ios; }; - 3F754D5524C6174A00BF2636 /* GoogleCast.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3F754D5224C6164D00BF2636 /* GoogleCast.framework */; platformFilter = ios; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 3F84578A238E5039004E78EC /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F845789238E5039004E78EC /* SceneDelegate.swift */; }; 3F84578C238E622C004E78EC /* About.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3F84578B238E622C004E78EC /* About.storyboard */; }; 3F84578E238E6896004E78EC /* ViewControllerAbout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F84578D238E6896004E78EC /* ViewControllerAbout.swift */; }; 3F92E7032336B1F700D1FF9B /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3F92E7022336B1F700D1FF9B /* Media.xcassets */; }; 3FA954D62322EC22005B086A /* ViewControllerConvert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FA954D52322EC22005B086A /* ViewControllerConvert.swift */; }; 3FC2F2392381355800EB747C /* ccViewer.help in Resources */ = {isa = PBXBuildFile; fileRef = 3FC2F2382381355800EB747C /* ccViewer.help */; }; + 8F8DFF2025A03469001033CA /* GoogleCast.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F754D5224C6164D00BF2636 /* GoogleCast.framework */; platformFilter = ios; }; + 8F8DFF2125A0346A001033CA /* GoogleCast.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3F754D5224C6164D00BF2636 /* GoogleCast.framework */; platformFilter = ios; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 8F8DFF2925A0A874001033CA /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8F8DFF2825A0A874001033CA /* MapKit.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -94,10 +90,8 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3F754D5524C6174A00BF2636 /* GoogleCast.framework in Embed Frameworks */, + 8F8DFF2125A0346A001033CA /* GoogleCast.framework in Embed Frameworks */, 3F19BC23232455C80040ED19 /* RemoteCloud.framework in Embed Frameworks */, - 3F19BC20232455C80040ED19 /* ffplayer.framework in Embed Frameworks */, - 3F19BC1D232455C80040ED19 /* ffconverter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -114,7 +108,6 @@ 3C0693472253DBD40040DC0B /* ProductManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductManager.swift; sourceTree = ""; }; 3C0693482253DBD50040DC0B /* PurchaceManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PurchaceManager.swift; sourceTree = ""; }; 3C0693492253DBD50040DC0B /* PurchaceViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PurchaceViewController.swift; sourceTree = ""; }; - 3C06934D2253E2610040DC0B /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; 3C0D4418224B106C001FCAAC /* TableViewControllerItemsEdit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewControllerItemsEdit.swift; sourceTree = ""; }; 3C0D441C224C4949001FCAAC /* AuthenticationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AuthenticationServices.framework; path = System/Library/Frameworks/AuthenticationServices.framework; sourceTree = SDKROOT; }; 3C40091122401D020028A45A /* CustomPlayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPlayerViewController.swift; sourceTree = ""; }; @@ -174,6 +167,13 @@ 3F92E7022336B1F700D1FF9B /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = ""; }; 3FA954D52322EC22005B086A /* ViewControllerConvert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerConvert.swift; sourceTree = ""; }; 3FC2F2382381355800EB747C /* ccViewer.help */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ccViewer.help; sourceTree = ""; }; + 8F26615F258A1656008297AA /* CryptCloudViewerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CryptCloudViewerDebug.entitlements; sourceTree = ""; }; + 8F266162258A16F8008297AA /* ffconverter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ffconverter.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8F266165258A170F008297AA /* ffconverter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ffconverter.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8F26616E258A28AE008297AA /* GoogleCast.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GoogleCast.framework; path = "../GoogleCastSDK-ios-4.4.7_dynamic/GoogleCast.framework"; sourceTree = ""; }; + 8F60E4E6258AE18700A8EB54 /* GoogleCast.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GoogleCast.framework; path = "../GoogleCastSDK-ios-4.5.3_dynamic/GoogleCast.framework"; sourceTree = ""; }; + 8F60E4EC258AE7FE00A8EB54 /* GoogleCastSDK */ = {isa = PBXFileReference; lastKnownFileType = folder; name = GoogleCastSDK; path = ../GoogleCastSDK; sourceTree = ""; }; + 8F8DFF2825A0A874001033CA /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -182,28 +182,26 @@ buildActionMask = 2147483647; files = ( 3F19BBDC232420670040ED19 /* libc++.tbd in Frameworks */, - 3F19BC1C232455C80040ED19 /* ffconverter.framework in Frameworks */, 3F19BBDA232420450040ED19 /* UIKit.framework in Frameworks */, 3F19BBD82324203C0040ED19 /* SystemConfiguration.framework in Frameworks */, 3F19BC22232455C80040ED19 /* RemoteCloud.framework in Frameworks */, + 8F8DFF2925A0A874001033CA /* MapKit.framework in Frameworks */, 3F19BBD62324202F0040ED19 /* Security.framework in Frameworks */, 3F19BBD4232420280040ED19 /* QuartzCore.framework in Frameworks */, - 3F19BC1F232455C80040ED19 /* ffplayer.framework in Frameworks */, 3F19BBD2232420200040ED19 /* MediaPlayer.framework in Frameworks */, 3F19BBD0232420180040ED19 /* MediaAccessibility.framework in Frameworks */, + 8F8DFF2025A03469001033CA /* GoogleCast.framework in Frameworks */, 3F19BBCC23241FF20040ED19 /* Foundation.framework in Frameworks */, 3F19BBCA23241FE90040ED19 /* CoreText.framework in Frameworks */, 3F19BBC823241FE10040ED19 /* CoreMedia.framework in Frameworks */, 3F19BBC623241FD90040ED19 /* CoreGraphics.framework in Frameworks */, 3F19BBC423241FCF0040ED19 /* CoreData.framework in Frameworks */, 3F19BBC023241FBE0040ED19 /* CFNetwork.framework in Frameworks */, - 3F754D5424C6174A00BF2636 /* GoogleCast.framework in Frameworks */, 3F19BBBE23241FB60040ED19 /* AVFoundation.framework in Frameworks */, 3F19BBBC23241FAC0040ED19 /* AudioToolbox.framework in Frameworks */, 3F19BBBA23241FA30040ED19 /* Accelerate.framework in Frameworks */, 3CC48515225719160003C44A /* CloudKit.framework in Frameworks */, 3C0D441D224C4949001FCAAC /* AuthenticationServices.framework in Frameworks */, - 3C06934E2253E2610040DC0B /* StoreKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -227,6 +225,12 @@ 3CA2C9482234956100481DB5 /* Frameworks */ = { isa = PBXGroup; children = ( + 8F8DFF2825A0A874001033CA /* MapKit.framework */, + 8F60E4EC258AE7FE00A8EB54 /* GoogleCastSDK */, + 8F26616E258A28AE008297AA /* GoogleCast.framework */, + 8F60E4E6258AE18700A8EB54 /* GoogleCast.framework */, + 8F266165258A170F008297AA /* ffconverter.framework */, + 8F266162258A16F8008297AA /* ffconverter.framework */, 3F754D5224C6164D00BF2636 /* GoogleCast.framework */, 3F19BBDB232420670040ED19 /* libc++.tbd */, 3F19BBD9232420450040ED19 /* UIKit.framework */, @@ -246,7 +250,6 @@ 3F19BBBB23241FAC0040ED19 /* AudioToolbox.framework */, 3F19BBB923241FA30040ED19 /* Accelerate.framework */, 3CC48514225719160003C44A /* CloudKit.framework */, - 3C06934D2253E2610040DC0B /* StoreKit.framework */, 3C0D441C224C4949001FCAAC /* AuthenticationServices.framework */, ); name = Frameworks; @@ -255,6 +258,7 @@ 3CFCF68C222F347900843054 = { isa = PBXGroup; children = ( + 8F26615F258A1656008297AA /* CryptCloudViewerDebug.entitlements */, 3F19BC21232455C80040ED19 /* RemoteCloud.framework */, 3F19BC1E232455C80040ED19 /* ffplayer.framework */, 3F19BC1B232455C80040ED19 /* ffconverter.framework */, @@ -345,8 +349,8 @@ 3CFCF691222F347A00843054 /* Sources */, 3CFCF692222F347A00843054 /* Frameworks */, 3CFCF693222F347A00843054 /* Resources */, - 3CA2C9552234980C00481DB5 /* Embed Frameworks */, 3F9151E5236C463100E5EF65 /* ShellScript */, + 3CA2C9552234980C00481DB5 /* Embed Frameworks */, ); buildRules = ( ); @@ -400,8 +404,8 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1010; - LastUpgradeCheck = 1100; - ORGANIZATIONNAME = lithium03; + LastUpgradeCheck = 1230; + ORGANIZATIONNAME = apogeios; TargetAttributes = { 3CFCF694222F347A00843054 = { CreatedOnToolsVersion = 10.1; @@ -504,7 +508,8 @@ /* Begin PBXShellScriptBuildPhase section */ 3F9151E5236C463100E5EF65 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; + alwaysOutOfDate = 1; + buildActionMask = 12; files = ( ); inputFileListPaths = ( @@ -517,7 +522,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nif [ \"${PLATFORM_NAME}\" = \"iphoneos\" ]; then\n ${SRCROOT}/../GoogleCastSDK/Tools/strip_unused_archs.sh\nfi\n"; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nset -x\n\n${SRCROOT}/../GoogleCastSDK/Tools/strip_unused_archs.sh\n\necho \"Print log here\"\n\n#${PROJECT_DIR}/GoogleCastSDK/Tools/strip_unused_archs.sh\n\n#if [ \"${PLATFORM_NAME}\" = \"iphoneos\" ]; then\n# ${SRCROOT}/../GoogleCastSDK/Tools/strip_unused_archs.sh\n#fi\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -651,6 +656,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -660,6 +666,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = RBCU3NX86X; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -676,7 +683,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -713,6 +720,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -722,6 +730,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = RBCU3NX86X; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -732,7 +741,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -746,19 +755,19 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = ccViewer/ccViewer.entitlements; + CODE_SIGN_ENTITLEMENTS = CryptCloudViewerDebug.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 70; - DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; - DEVELOPMENT_TEAM = 7A9X38B4YU; + DEVELOPMENT_TEAM = RBCU3NX86X; "ENABLE_HARDENED_RUNTIME[sdk=macosx*]" = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", ); - GCC_OPTIMIZATION_LEVEL = fast; + GCC_OPTIMIZATION_LEVEL = 0; INFOPLIST_FILE = ccViewer/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -768,12 +777,14 @@ "-ObjC", "-lc++", ); - PRODUCT_BUNDLE_IDENTIFIER = info.lithium03.ccViewer; + PRODUCT_BUNDLE_IDENTIFIER = apogeios.ccviewer; PRODUCT_NAME = "$(TARGET_NAME)"; - SUPPORTS_MACCATALYST = YES; + PROVISIONING_PROFILE_SPECIFIER = ""; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; + VALIDATE_WORKSPACE = YES; }; name = Debug; }; @@ -782,18 +793,18 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = ccViewer/ccViewer.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 70; - DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; - DEVELOPMENT_TEAM = 7A9X38B4YU; + DEVELOPMENT_TEAM = RBCU3NX86X; "ENABLE_HARDENED_RUNTIME[sdk=macosx*]" = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", ); - GCC_OPTIMIZATION_LEVEL = fast; + GCC_OPTIMIZATION_LEVEL = 0; INFOPLIST_FILE = ccViewer/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -803,12 +814,14 @@ "-ObjC", "-lc++", ); - PRODUCT_BUNDLE_IDENTIFIER = info.lithium03.ccViewer; + PRODUCT_BUNDLE_IDENTIFIER = apogeios.ccviewer; PRODUCT_NAME = "$(TARGET_NAME)"; - SUPPORTS_MACCATALYST = YES; + PROVISIONING_PROFILE_SPECIFIER = ""; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; + VALIDATE_WORKSPACE = YES; }; name = Release; }; @@ -818,7 +831,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7A9X38B4YU; + DEVELOPMENT_TEAM = RBCU3NX86X; INFOPLIST_FILE = ccViewerTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -828,7 +841,7 @@ PRODUCT_BUNDLE_IDENTIFIER = info.lithium03.ccViewerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CryptCloudViewer.app/CryptCloudViewer"; }; name = Debug; @@ -839,7 +852,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7A9X38B4YU; + DEVELOPMENT_TEAM = RBCU3NX86X; INFOPLIST_FILE = ccViewerTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -849,7 +862,7 @@ PRODUCT_BUNDLE_IDENTIFIER = info.lithium03.ccViewerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CryptCloudViewer.app/CryptCloudViewer"; }; name = Release; @@ -859,7 +872,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7A9X38B4YU; + DEVELOPMENT_TEAM = RBCU3NX86X; INFOPLIST_FILE = ccViewerUITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -869,7 +882,7 @@ PRODUCT_BUNDLE_IDENTIFIER = info.lithium03.ccViewerUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; TEST_TARGET_NAME = ccViewer; }; name = Debug; @@ -879,7 +892,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7A9X38B4YU; + DEVELOPMENT_TEAM = RBCU3NX86X; INFOPLIST_FILE = ccViewerUITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -889,7 +902,7 @@ PRODUCT_BUNDLE_IDENTIFIER = info.lithium03.ccViewerUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; TEST_TARGET_NAME = ccViewer; }; name = Release; diff --git a/ccViewer/ccViewer/AppDelegate.swift b/ccViewer/ccViewer/AppDelegate.swift index 8d421ed..6778091 100644 --- a/ccViewer/ccViewer/AppDelegate.swift +++ b/ccViewer/ccViewer/AppDelegate.swift @@ -12,7 +12,7 @@ import UserNotifications import AVFoundation import RemoteCloud -import ffplayer +//import ffplayer #if !targetEnvironment(macCatalyst) import GoogleCast @@ -38,6 +38,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate { try FileManager.default.removeItem(at: fileURL) } } catch { print(error) } + + // TODO - Set user defaults + UserDefaults.standard.register( + defaults: [ + "FFplayer" : false, + "savePlaypos" : false, + "resumePlaypos" : false, + "cloudPlaypos" : false, + "cloudPlaylist" : false + ]) // MARK: google chromecast #if !targetEnvironment(macCatalyst) @@ -130,12 +140,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. - FFPlayerViewController.inFocus = false +//Andy FFPlayerViewController.inFocus = false } func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - FFPlayerViewController.inFocus = true +//Andy FFPlayerViewController.inFocus = true } func applicationWillTerminate(_ application: UIApplication) { diff --git a/ccViewer/ccViewer/Base.lproj/Main.storyboard b/ccViewer/ccViewer/Base.lproj/Main.storyboard index d12a4df..5e724ef 100644 --- a/ccViewer/ccViewer/Base.lproj/Main.storyboard +++ b/ccViewer/ccViewer/Base.lproj/Main.storyboard @@ -1,12 +1,12 @@ - - + + - - + + @@ -15,15 +15,15 @@ - + - + - + - + @@ -44,26 +44,26 @@ - + - + - + - + diff --git a/ccViewer/ccViewer/Info.plist b/ccViewer/ccViewer/Info.plist index 9e29f59..ba4639d 100644 --- a/ccViewer/ccViewer/Info.plist +++ b/ccViewer/ccViewer/Info.plist @@ -43,6 +43,8 @@ LSSupportsOpeningDocumentsInPlace + MKDirectionsApplicationSupportedModes + NSAppTransportSecurity NSAllowsArbitraryLoads diff --git a/ccViewer/ccViewer/ViewControllerImage.swift b/ccViewer/ccViewer/ViewControllerImage.swift index 6a195bc..5a65be3 100644 --- a/ccViewer/ccViewer/ViewControllerImage.swift +++ b/ccViewer/ccViewer/ViewControllerImage.swift @@ -8,11 +8,32 @@ import UIKit import RemoteCloud +import MapKit + +/* Placeholder - this one does not work as UIImage strips most meta data. */ +extension UIImage { + + func getExifData() -> CFDictionary? { + var exifData: CFDictionary? = nil + if let data = self.jpegData(compressionQuality: 1.0) { + data.withUnsafeBytes { + let bytes = $0.baseAddress?.assumingMemoryBound(to: UInt8.self) + if let cfData = CFDataCreate(kCFAllocatorDefault, bytes, data.count), + let source = CGImageSourceCreateWithData(cfData, nil) { + exifData = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) + } + } + } + return exifData + } +} class ViewControllerImage: UIViewController, UIScrollViewDelegate, UIDocumentInteractionControllerDelegate { @IBOutlet weak var scrollView: UIScrollView! - + @IBOutlet weak var tableView: UITableView! + @IBOutlet weak var mapView: MKMapView! + @IBOutlet weak var doubleTapGesture: UITapGestureRecognizer! @IBOutlet weak var singleTapGesture: UITapGestureRecognizer! @@ -40,6 +61,19 @@ class ViewControllerImage: UIViewController, UIScrollViewDelegate, UIDocumentInt d.transitioningDelegate = self return d }() + + func getExifData() -> [CFString : Any]? { + // let data :Data = imagedata.jpegData(compressionQuality: 1.0)! + // Apple strips most of metadata from UImage for security concern, so raw data it is. + let data = self.data[itemIdx]! + let options = [kCGImageSourceShouldCache as String: kCFBooleanFalse] + if let source = CGImageSourceCreateWithData(data as CFData, options as CFDictionary) { + let exifData = CGImageSourceCopyPropertiesAtIndex(source, 0, options as CFDictionary) as? [CFString : Any] +// debugPrint(exifData ?? nil) + return exifData + } + return nil + } override func viewDidLoad() { super.viewDidLoad() @@ -55,6 +89,18 @@ class ViewControllerImage: UIViewController, UIScrollViewDelegate, UIDocumentInt imageView.contentMode = .scaleAspectFit scrollView.addSubview(imageView) + let exifData = getExifData() + let exifDict = exifData?[kCGImagePropertyExifDictionary] as? [CFString : Any] + let exifGPS = exifData?[kCGImagePropertyGPSDictionary] as? [CFString : Any] + print( "Name = \(self.items[itemIdx].name), Create date = \(exifDict?[kCGImagePropertyExifDateTimeDigitized]), GPS = \(exifGPS?[kCGImagePropertyGPSAltitude]), \(exifGPS?[kCGImagePropertyGPSLatitude]), \(exifGPS?[kCGImagePropertyGPSLongitude])") + + let annotation = MKPointAnnotation() + annotation.coordinate = CLLocationCoordinate2DMake(exifGPS?[kCGImagePropertyGPSLatitude] as! CLLocationDegrees, exifGPS?[kCGImagePropertyGPSLongitude] as! CLLocationDegrees) + let region = MKCoordinateRegion(center: annotation.coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000) + + mapView.addAnnotation(annotation) + mapView.setRegion(region, animated: false) + activityIndicator.center = view.center if #available(iOS 13.0, *) { activityIndicator.style = .large diff --git a/ccViewer/ccViewer/ccViewer.entitlements b/ccViewer/ccViewer/ccViewer.entitlements index 456616d..c07c7b3 100644 --- a/ccViewer/ccViewer/ccViewer.entitlements +++ b/ccViewer/ccViewer/ccViewer.entitlements @@ -2,22 +2,10 @@ - com.apple.developer.authentication-services.autofill-credential-provider - - com.apple.developer.icloud-container-identifiers - - iCloud.info.lithium03.ccViewer - - com.apple.developer.icloud-services - - CloudKit - - com.apple.developer.networking.wifi-info - - com.apple.developer.ubiquity-kvstore-identifier - $(TeamIdentifierPrefix)$(CFBundleIdentifier) com.apple.security.app-sandbox + com.apple.security.files.downloads.read-write + com.apple.security.files.user-selected.read-write com.apple.security.network.client From b45cb9b142ed77c61ba450139feea8e9fc5e8f60 Mon Sep 17 00:00:00 2001 From: Aquarius Xiong Date: Sun, 3 Jan 2021 16:41:29 +0800 Subject: [PATCH 4/5] First working EXIF. Map on the top, digitized date and place in the middle, and then the picture. --- ccViewer/ccViewer/Base.lproj/Main.storyboard | 24 +++++---- ccViewer/ccViewer/ViewControllerImage.swift | 55 +++++++++++++++----- 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/ccViewer/ccViewer/Base.lproj/Main.storyboard b/ccViewer/ccViewer/Base.lproj/Main.storyboard index 5e724ef..c6241ed 100644 --- a/ccViewer/ccViewer/Base.lproj/Main.storyboard +++ b/ccViewer/ccViewer/Base.lproj/Main.storyboard @@ -422,8 +422,9 @@ - - + + + @@ -434,30 +435,33 @@ - + - - + + + + + + - + - + + - diff --git a/ccViewer/ccViewer/ViewControllerImage.swift b/ccViewer/ccViewer/ViewControllerImage.swift index 5a65be3..7268c05 100644 --- a/ccViewer/ccViewer/ViewControllerImage.swift +++ b/ccViewer/ccViewer/ViewControllerImage.swift @@ -31,7 +31,8 @@ extension UIImage { class ViewControllerImage: UIViewController, UIScrollViewDelegate, UIDocumentInteractionControllerDelegate { @IBOutlet weak var scrollView: UIScrollView! - @IBOutlet weak var tableView: UITableView! + + @IBOutlet weak var exifDigitalizedDate: UILabel! @IBOutlet weak var mapView: MKMapView! @IBOutlet weak var doubleTapGesture: UITapGestureRecognizer! @@ -74,12 +75,50 @@ class ViewControllerImage: UIViewController, UIScrollViewDelegate, UIDocumentInt } return nil } + + func updateViewFromEXIF() { + var errormsg : String = "Reverse Geo Code..." + defer { + self.exifDigitalizedDate.attributedText = NSAttributedString(string: errormsg) + } + + guard let exifData = getExifData() else { errormsg = "No EXIF data"; return} + guard let exifDict = exifData[kCGImagePropertyExifDictionary] as? [CFString : Any] else { errormsg = "Corrupted EXIF data"; return} + guard let digitizedDate = exifDict[kCGImagePropertyExifDateTimeDigitized] as? String else { errormsg = "No digitized date"; return} + guard let exifGPS = exifData[kCGImagePropertyGPSDictionary] as? [CFString : Any] else { errormsg = "No GPS info, \(digitizedDate)"; return} + guard let longitude = exifGPS[kCGImagePropertyGPSLongitude] as? CLLocationDegrees else { errormsg = "No GPS Longitude, \(digitizedDate)"; return} + guard let latitude = exifGPS[kCGImagePropertyGPSLatitude] as? CLLocationDegrees else { errormsg = "No GPS Latitude, \(digitizedDate)"; return} + + let geocoder = CLGeocoder() + let location = CLLocation(latitude: latitude, longitude: longitude) + geocoder.reverseGeocodeLocation(location) { (placemarks, error) -> Void in + defer { + let annotation = MKPointAnnotation() + annotation.coordinate = location.coordinate + let region = MKCoordinateRegion(center: annotation.coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000) + + self.mapView.addAnnotation(annotation) + self.mapView.setRegion(region, animated: false) + + self.exifDigitalizedDate.attributedText = NSAttributedString(string: "\(place ?? "") + \(digitizedDate)" ) + } + + var place : String? = "" + if (error != nil) {return} + + let pm = placemarks! as [CLPlacemark] + if (pm.count > 0){ + place = pm[0].name + } + } + } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. singleTapGesture.require(toFail: doubleTapGesture) + scrollView.delegate = self scrollView.minimumZoomScale = 0.0 @@ -89,17 +128,7 @@ class ViewControllerImage: UIViewController, UIScrollViewDelegate, UIDocumentInt imageView.contentMode = .scaleAspectFit scrollView.addSubview(imageView) - let exifData = getExifData() - let exifDict = exifData?[kCGImagePropertyExifDictionary] as? [CFString : Any] - let exifGPS = exifData?[kCGImagePropertyGPSDictionary] as? [CFString : Any] - print( "Name = \(self.items[itemIdx].name), Create date = \(exifDict?[kCGImagePropertyExifDateTimeDigitized]), GPS = \(exifGPS?[kCGImagePropertyGPSAltitude]), \(exifGPS?[kCGImagePropertyGPSLatitude]), \(exifGPS?[kCGImagePropertyGPSLongitude])") - - let annotation = MKPointAnnotation() - annotation.coordinate = CLLocationCoordinate2DMake(exifGPS?[kCGImagePropertyGPSLatitude] as! CLLocationDegrees, exifGPS?[kCGImagePropertyGPSLongitude] as! CLLocationDegrees) - let region = MKCoordinateRegion(center: annotation.coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000) - - mapView.addAnnotation(annotation) - mapView.setRegion(region, animated: false) + updateViewFromEXIF() activityIndicator.center = view.center if #available(iOS 13.0, *) { @@ -236,6 +265,8 @@ class ViewControllerImage: UIViewController, UIScrollViewDelegate, UIDocumentInt let scale = min(w_scale, h_scale) scrollView.setZoomScale(scale, animated: false) } + + updateViewFromEXIF() } else { transrateData(toLeft: toLeft) From 551adca2e54426343b1b66f57c33677f411a132a Mon Sep 17 00:00:00 2001 From: Aquarius Xiong Date: Tue, 5 Jan 2021 21:11:45 +0800 Subject: [PATCH 5/5] 1. SWIFT_ACTIVE_COMPILATION_CONDITIONS = "FFCONVERTER FFPLAYER CLOUDMARK", as FFMPEG does not build and also enable real device debugging w/o Apple developer account. 2. GPS view changed to hybrid. --- .../project.pbxproj | 9 +++ ccViewer/ccViewer/AppDelegate.swift | 4 +- ccViewer/ccViewer/Base.lproj/Main.storyboard | 2 +- ccViewer/ccViewer/SceneDelegate.swift | 6 ++ .../ccViewer/TableViewControllerItems.swift | 58 +++++++++++++++++-- .../TableViewControllerItemsEdit.swift | 6 ++ .../TableViewControllerPlaylist.swift | 8 ++- ccViewer/ccViewer/ViewControllerConvert.swift | 4 +- ccViewer/ccViewer/ViewControllerFirst.swift | 10 ++-- chromecast.sh | 8 +-- 10 files changed, 98 insertions(+), 17 deletions(-) diff --git a/ccViewer/CryptCloudViewer.xcodeproj/project.pbxproj b/ccViewer/CryptCloudViewer.xcodeproj/project.pbxproj index f78219b..a321592 100644 --- a/ccViewer/CryptCloudViewer.xcodeproj/project.pbxproj +++ b/ccViewer/CryptCloudViewer.xcodeproj/project.pbxproj @@ -766,6 +766,10 @@ "$(PROJECT_DIR)", ); GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); INFOPLIST_FILE = ccViewer/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.3; LD_RUNPATH_SEARCH_PATHS = ( @@ -777,10 +781,12 @@ "-ObjC", "-lc++", ); + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = apogeios.ccviewer; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTS_MACCATALYST = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; @@ -803,6 +809,7 @@ "$(PROJECT_DIR)", ); GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ""; INFOPLIST_FILE = ccViewer/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.3; LD_RUNPATH_SEARCH_PATHS = ( @@ -814,10 +821,12 @@ "-ObjC", "-lc++", ); + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = apogeios.ccviewer; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTS_MACCATALYST = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "FFCONVERTER FFPLAYER CLOUDMARK"; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; diff --git a/ccViewer/ccViewer/AppDelegate.swift b/ccViewer/ccViewer/AppDelegate.swift index 6778091..383073d 100644 --- a/ccViewer/ccViewer/AppDelegate.swift +++ b/ccViewer/ccViewer/AppDelegate.swift @@ -12,7 +12,9 @@ import UserNotifications import AVFoundation import RemoteCloud -//import ffplayer +#if FFPLAYER +import ffplayer +#endif #if !targetEnvironment(macCatalyst) import GoogleCast diff --git a/ccViewer/ccViewer/Base.lproj/Main.storyboard b/ccViewer/ccViewer/Base.lproj/Main.storyboard index c6241ed..166378e 100644 --- a/ccViewer/ccViewer/Base.lproj/Main.storyboard +++ b/ccViewer/ccViewer/Base.lproj/Main.storyboard @@ -434,7 +434,7 @@ - + diff --git a/ccViewer/ccViewer/SceneDelegate.swift b/ccViewer/ccViewer/SceneDelegate.swift index ff92489..28d9922 100644 --- a/ccViewer/ccViewer/SceneDelegate.swift +++ b/ccViewer/ccViewer/SceneDelegate.swift @@ -8,7 +8,9 @@ import UIKit +#if FFPLAYER import ffplayer +#endif import RemoteCloud @available(iOS 13.0, *) @@ -43,13 +45,17 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func sceneDidBecomeActive(_ scene: UIScene) { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + #if FFPLAYER FFPlayerViewController.inFocus = true + #endif } func sceneWillResignActive(_ scene: UIScene) { // Called when the scene will move from an active state to an inactive state. // This may occur due to temporary interruptions (ex. an incoming phone call). + #if FFPLAYER FFPlayerViewController.inFocus = false + #endif } func sceneWillEnterForeground(_ scene: UIScene) { diff --git a/ccViewer/ccViewer/TableViewControllerItems.swift b/ccViewer/ccViewer/TableViewControllerItems.swift index 0dc52ff..1152084 100644 --- a/ccViewer/ccViewer/TableViewControllerItems.swift +++ b/ccViewer/ccViewer/TableViewControllerItems.swift @@ -10,8 +10,13 @@ import UIKit import PDFKit import RemoteCloud +#if FFPLAYER import ffplayer +#endif + +#if FFCONVERTER import ffconverter +#endif #if !targetEnvironment(macCatalyst) import GoogleCast @@ -241,6 +246,7 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, func restoreToolbarButton() { #if !targetEnvironment(macCatalyst) + #if FFCONVERTER let castContext = GCKCastContext.sharedInstance() if Converter.IsCasting() && (castContext.castState == .connected || castContext.castState == .connecting) { if let castButton = castButton { @@ -253,6 +259,7 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, else { toolbarItems = [playlistItem, flexible, playloopItem, flexible, playallItem, flexible, playshuffleItem, flexible, editlistItem, flexible, playCastItem] } + #endif #else toolbarItems = [playlistItem, flexible, playloopItem, flexible, playallItem, flexible, playshuffleItem, flexible, editlistItem, flexible, playCastItem] #endif @@ -276,12 +283,16 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, else { playshuffleItem.image = UIImage(named: "shuffle") } + #if FFCONVERTER if Converter.IsCasting() { playCastItem.image = UIImage(named: "cast_on") } else { playCastItem.image = UIImage(named: "cast") } + #else + playCastItem.image = UIImage(named: "cast") + #endif restoreToolbarButton() @@ -334,6 +345,7 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, } @objc func barButtonPlayCastTapped(_ sender: UIBarButtonItem) { + #if FFCONVERTER if Converter.IsCasting() { Converter.Stop() activityIndicator.stopAnimating() @@ -383,6 +395,7 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, else { playCastItem.image = UIImage(named: "cast") } + #endif } @objc func barButtonPlayListTapped(_ sender: UIBarButtonItem) { @@ -491,11 +504,13 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, } if playItems.count > 0 { + #if FFPLAYER Player.play(parent: self, items: playItems, shuffle: UserDefaults.standard.bool(forKey: "playshuffle"), loop: UserDefaults.standard.bool(forKey: "playloop")) { finish in DispatchQueue.main.async { self.tableView.reloadData() } } + #endif } } } @@ -897,7 +912,11 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, cell.detailTextLabel?.lineBreakMode = .byWordWrapping cell.detailTextLabel?.text = "\(tStr) \t\(sStr2) (\(sStr) bytes) \t\(result[indexPath.row].subinfo ?? "")" if let storage = result[indexPath.row].storage, let id = result[indexPath.row].id { + #if CLOUDMARK let localpos = CloudFactory.shared.data.getMark(storage: storage, targetID: id) + #else + var localpos: Double? = nil + #endif if localpos != nil { cell.backgroundColor = UIColor(named: "DidPlayColor") } @@ -1012,17 +1031,25 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, if UserDefaults.standard.bool(forKey: "ImageViewer") && pict_exts.contains(item.ext) { displayImageViewer(item: item) + return } else if UserDefaults.standard.bool(forKey: "PDFViewer") && (item.ext == "pdf") { displayPDFViewer(item: item) + return } - else if Converter.IsCasting() { + #if FFCONVERTER + if Converter.IsCasting() { semaphore.signal() playConverter(item: item) { fin in } + return } - else if UserDefaults.standard.bool(forKey: "FFplayer") && UserDefaults.standard.bool(forKey: "firstFFplayer") && + #endif + + #if FFPLAYER + if UserDefaults.standard.bool(forKey: "FFplayer") && UserDefaults.standard.bool(forKey: "firstFFplayer") && !Converter.IsCasting() { + semaphore.signal() playFFmpeg(item: item) { finish in if finish { @@ -1036,10 +1063,14 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, self.autoDetectRun(item: item) } } + return } - else if UserDefaults.standard.bool(forKey: "MediaViewer") && media_exts.contains(item.ext) { + #endif + + if UserDefaults.standard.bool(forKey: "MediaViewer") && media_exts.contains(item.ext) { displayMediaViewer(item: item, fallback: true) + return } else { DispatchQueue.main.async { @@ -1062,11 +1093,13 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, return } } + #if FFCONVERTER if Converter.IsCasting() { DispatchQueue.global().asyncAfter(deadline: .now()+1) { self.waitToPlay(target: target, onFind: onFind) } } + #endif return } @@ -1082,6 +1115,7 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, DispatchQueue.global().async { let skip = UserDefaults.standard.integer(forKey: "playStartSkipSec") let stop = UserDefaults.standard.integer(forKey: "playStopAfterSec") + #if FFCONVERTER let info = ConvertIteminfo(item: item) if skip > 0 { info.startpos = Double(skip) @@ -1146,6 +1180,7 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, } } + #endif if(url == nil) { DispatchQueue.main.async { self.activityIndicator.stopAnimating() @@ -1161,6 +1196,7 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, DispatchQueue.global().async { let skip = UserDefaults.standard.integer(forKey: "playStartSkipSec") let stop = UserDefaults.standard.integer(forKey: "playStopAfterSec") + #if FFCONVERTER let info = ConvertIteminfo(item: item) if skip > 0 { info.startpos = Double(skip) @@ -1213,6 +1249,7 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, self.convertPlayer?.play(parent: self) } } + #endif if(url == nil) { DispatchQueue.main.async { self.activityIndicator.stopAnimating() @@ -1223,6 +1260,7 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, } func playFFmpeg(item: RemoteItem, onFinish: @escaping (Bool)->Void) { + #if FFPLAYER let localpos = UserDefaults.standard.bool(forKey: "resumePlaypos") ? CloudFactory.shared.data.getMark(storage: item.storage, targetID: item.id) : nil Player.play(parent: self, item: item, start: localpos) { position in if let pos = position { @@ -1250,6 +1288,7 @@ class TableViewControllerItems: UITableViewController, UISearchResultsUpdating, } } } + #endif } func fallbackView(item: RemoteItem) { @@ -1887,7 +1926,9 @@ class DownloadProgressViewController: UIViewController, DownloadManagerDelegate class SelectStreamViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate { var onDone: ((Int, Int)->Void)? + #if FFPLAYER var info: PlayItemInfo? + #endif var picker1: UIPickerView! var picker2: UIPickerView! @@ -1904,8 +1945,10 @@ class SelectStreamViewController: UIViewController, UIPickerViewDataSource, UIPi view.backgroundColor = .white } + #if FFPLAYER videoIdx = info?.mainVideo ?? -1 subtitleIdx = info?.mainSubtitle ?? -1 + #endif let stackView = UIStackView() stackView.axis = .vertical @@ -1948,13 +1991,14 @@ class SelectStreamViewController: UIViewController, UIPickerViewDataSource, UIPi buttonOK.setTitle("OK", for: .normal) buttonOK.addTarget(self, action: #selector(buttonEvent), for: .touchUpInside) stackView.addArrangedSubview(buttonOK) - + #if FFPLAYER if let key = info?.videos.keys.sorted(), let ind = key.firstIndex(of: videoIdx) { picker1.selectRow(ind, inComponent: 0, animated: false) } if let key = info?.subtitle.keys.sorted(), let ind = key.firstIndex(of: subtitleIdx) { picker2.selectRow(ind, inComponent: 0, animated: false) } + #endif } @objc func buttonEvent(_ sender: UIButton) { @@ -1968,31 +2012,37 @@ class SelectStreamViewController: UIViewController, UIPickerViewDataSource, UIPi } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + #if FFPLAYER if pickerView == picker1 { return info?.videos.count ?? 0 } else if pickerView == picker2 { return info?.subtitle.count ?? 0 } + #endif return 0 } func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { + #if FFPLAYER if pickerView == picker1, let key = info?.videos.keys.sorted() { return "\(key[row]) : \(info?.videos[key[row]] ?? "")" } if pickerView == picker2, let key = info?.subtitle.keys.sorted() { return "\(key[row]) : \(info?.subtitle[key[row]] ?? "")" } + #endif return nil } func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + #if FFPLAYER if pickerView == picker1, let key = info?.videos.keys.sorted() { videoIdx = key[row] } if pickerView == picker2, let key = info?.subtitle.keys.sorted() { subtitleIdx = key[row] } + #endif } } diff --git a/ccViewer/ccViewer/TableViewControllerItemsEdit.swift b/ccViewer/ccViewer/TableViewControllerItemsEdit.swift index df9d9ff..e8b58ac 100644 --- a/ccViewer/ccViewer/TableViewControllerItemsEdit.swift +++ b/ccViewer/ccViewer/TableViewControllerItemsEdit.swift @@ -949,7 +949,13 @@ class TableViewControllerItemsEdit: UITableViewController, UISearchResultsUpdati cell.detailTextLabel?.lineBreakMode = .byWordWrapping cell.detailTextLabel?.text = "\(tStr) \t\(sStr2) (\(sStr) bytes)" if let storage = result[indexPath.row].storage, let id = result[indexPath.row].id { + #if CLOUDMARK let localpos = CloudFactory.shared.data.getMark(storage: storage, targetID: id) + #else + //TODO - skip it + var localpos : Double? = nil + #endif + if localpos != nil { cell.backgroundColor = UIColor(named: "DidPlayColor") } diff --git a/ccViewer/ccViewer/TableViewControllerPlaylist.swift b/ccViewer/ccViewer/TableViewControllerPlaylist.swift index c5dd366..c806fa9 100644 --- a/ccViewer/ccViewer/TableViewControllerPlaylist.swift +++ b/ccViewer/ccViewer/TableViewControllerPlaylist.swift @@ -9,7 +9,9 @@ import UIKit import RemoteCloud -import ffplayer +#if FFPLAYER +//import ffplayer +#endif class TableViewControllerPlaylist: UITableViewController, UISearchResultsUpdating { @@ -232,11 +234,13 @@ class TableViewControllerPlaylist: UITableViewController, UISearchResultsUpdatin } if playItems.count > 0 { + #if FFPLAYER Player.play(parent: self, items: playItems, shuffle: UserDefaults.standard.bool(forKey: "playshuffle"), loop: UserDefaults.standard.bool(forKey: "playloop")) { finish in DispatchQueue.main.async { self.tableView.reloadData() } } + #endif } } } @@ -682,6 +686,7 @@ class TableViewControllerPlaylist: UITableViewController, UISearchResultsUpdatin } func playFFmpeg(item: RemoteItem, onFinish: @escaping (Bool)->Void) { + #if FFPLAYER Player.play(parent: self, item: item, start: nil) { position in DispatchQueue.main.async { self.navigationController?.popToViewController(self, animated: true) @@ -689,6 +694,7 @@ class TableViewControllerPlaylist: UITableViewController, UISearchResultsUpdatin self.tableView.reloadData() } } + #endif } func fallbackView(item: RemoteItem) { diff --git a/ccViewer/ccViewer/ViewControllerConvert.swift b/ccViewer/ccViewer/ViewControllerConvert.swift index fe8ac45..4511449 100644 --- a/ccViewer/ccViewer/ViewControllerConvert.swift +++ b/ccViewer/ccViewer/ViewControllerConvert.swift @@ -10,7 +10,9 @@ import UIKit import AVFoundation import AVKit -import ffconverter +#if FFCONVERTER +//import ffconverter +#endif import RemoteCloud class ConvertPlayerView: NSObject, AVPlayerViewControllerDelegate { diff --git a/ccViewer/ccViewer/ViewControllerFirst.swift b/ccViewer/ccViewer/ViewControllerFirst.swift index f40b32f..fb03607 100644 --- a/ccViewer/ccViewer/ViewControllerFirst.swift +++ b/ccViewer/ccViewer/ViewControllerFirst.swift @@ -46,11 +46,11 @@ class ViewControllerFirst: UIViewController { UserDefaults.standard.set(true, forKey: "ImageViewer") UserDefaults.standard.set(true, forKey: "PDFViewer") UserDefaults.standard.set(true, forKey: "MediaViewer") - UserDefaults.standard.set(true, forKey: "FFplayer") - UserDefaults.standard.set(true, forKey: "savePlaypos") - UserDefaults.standard.set(true, forKey: "resumePlaypos") - UserDefaults.standard.set(true, forKey: "cloudPlaypos") - UserDefaults.standard.set(true, forKey: "cloudPlaylist") + UserDefaults.standard.set(false, forKey: "FFplayer") + UserDefaults.standard.set(false, forKey: "savePlaypos") + UserDefaults.standard.set(false, forKey: "resumePlaypos") + UserDefaults.standard.set(false, forKey: "cloudPlaypos") + UserDefaults.standard.set(false, forKey: "cloudPlaylist") UserDefaults.standard.set(true, forKey: "PDF_continuous") UserDefaults.standard.set(true, forKey: "tutorial") diff --git a/chromecast.sh b/chromecast.sh index 88974b3..f30d18c 100755 --- a/chromecast.sh +++ b/chromecast.sh @@ -1,6 +1,6 @@ #!/bin/bash -curl -OL https://dl.google.com/dl/chromecast/sdk/ios/GoogleCastSDK-ios-no-bluetooth-4.4.7_dynamic.zip -unzip GoogleCastSDK-ios-no-bluetooth-4.4.7_dynamic.zip -ln -s GoogleCastSDK-ios-4.4.7_dynamic GoogleCastSDK -patch -p0