diff --git a/Kiwix-iOS/Controller/Main/Buttons.swift b/Kiwix-iOS/Controller/Main/Buttons.swift index 4dae6b86..eed1ea90 100644 --- a/Kiwix-iOS/Controller/Main/Buttons.swift +++ b/Kiwix-iOS/Controller/Main/Buttons.swift @@ -34,6 +34,8 @@ class Buttons: LPTBarButtonItemDelegate { delegate?.didTapForwardButton() case toc: delegate?.didTapTOCButton() + case library: + delegate?.didTapLibraryButton() default: return } diff --git a/Kiwix-iOS/Info.plist b/Kiwix-iOS/Info.plist index bcc68d8b..6a58f533 100644 --- a/Kiwix-iOS/Info.plist +++ b/Kiwix-iOS/Info.plist @@ -49,7 +49,7 @@ CFBundleVersion - 1.8.3669 + 1.8.3683 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/Kiwix-iOSWidgets/Bookmarks/Info.plist b/Kiwix-iOSWidgets/Bookmarks/Info.plist index df45585e..7296d298 100644 --- a/Kiwix-iOSWidgets/Bookmarks/Info.plist +++ b/Kiwix-iOSWidgets/Bookmarks/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 1.8.3687 + 1.8.3701 NSExtension NSExtensionMainStoryboard diff --git a/Kiwix.xcodeproj/project.pbxproj b/Kiwix.xcodeproj/project.pbxproj index 47cc847f..ddcfa388 100644 --- a/Kiwix.xcodeproj/project.pbxproj +++ b/Kiwix.xcodeproj/project.pbxproj @@ -214,7 +214,6 @@ 973DD4271D36E3E4009D45DB /* SettingDetailController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SettingDetailController.swift; path = "Kiwix-iOS/Controller/Setting/SettingDetailController.swift"; sourceTree = SOURCE_ROOT; }; 974C49621DA307FF00E276E1 /* injection.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = injection.js; sourceTree = ""; }; 974C49671DA4266200E276E1 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; }; - 974F33C51D99CAD700879D35 /* BookmarkOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkOperation.swift; sourceTree = ""; }; 975227CA1D0227E8001D1DDE /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = "Kiwix-iOS/Storyboard/Main.storyboard"; sourceTree = SOURCE_ROOT; }; 975227CB1D0227E8001D1DDE /* Setting.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Setting.storyboard; path = "Kiwix-iOS/Storyboard/Setting.storyboard"; sourceTree = SOURCE_ROOT; }; 975227CF1D022814001D1DDE /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = "Kiwix-iOS/Storyboard/LaunchScreen.storyboard"; sourceTree = SOURCE_ROOT; }; @@ -273,7 +272,6 @@ 97D4D64E1D874E6E00C1B065 /* SearchOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchOperation.swift; sourceTree = ""; }; 97D6811A1D6E2A7100E5FA99 /* DownloadTasksController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadTasksController.swift; sourceTree = ""; }; 97D6811C1D6F70AC00E5FA99 /* GlobalQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlobalQueue.swift; sourceTree = ""; }; - 97D6811D1D6F70AC00E5FA99 /* RefreshLibraryOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshLibraryOperation.swift; sourceTree = ""; }; 97D6811E1D6F70AC00E5FA99 /* ScanLocalBook.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScanLocalBook.swift; sourceTree = ""; }; 97D681211D6F70AC00E5FA99 /* UpdateWidgetDataSourceOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateWidgetDataSourceOperation.swift; sourceTree = ""; }; 97D681221D6F70AC00E5FA99 /* URLSessionDownloadTaskOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSessionDownloadTaskOperation.swift; sourceTree = ""; }; @@ -291,7 +289,6 @@ 97D6813D1D6F712800E5FA99 /* DownloadTask+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "DownloadTask+CoreDataProperties.swift"; path = "Classes/DownloadTask+CoreDataProperties.swift"; sourceTree = ""; }; 97D6813E1D6F712800E5FA99 /* Language+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Language+CoreDataProperties.swift"; path = "Classes/Language+CoreDataProperties.swift"; sourceTree = ""; }; 97DB65D91D4576B600A2CC42 /* BookmarkWidgetCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkWidgetCell.swift; sourceTree = ""; }; - 97DF259B1D6F7612001648A3 /* BookOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookOperation.swift; sourceTree = ""; }; 97DF259F1D6F996B001648A3 /* Network.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; 97E609F01D103DED00EBCB9D /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; }; 97E60A011D10423A00EBCB9D /* Others.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Others.swift; sourceTree = ""; }; @@ -372,16 +369,6 @@ name = Frameworks; sourceTree = ""; }; - 970A2A201DD562B60078BB7C /* old */ = { - isa = PBXGroup; - children = ( - 974F33C51D99CAD700879D35 /* BookmarkOperation.swift */, - 97DF259B1D6F7612001648A3 /* BookOperation.swift */, - 97D6811D1D6F70AC00E5FA99 /* RefreshLibraryOperation.swift */, - ); - name = old; - sourceTree = ""; - }; 971187051CEB426E00B9909D /* libkiwix */ = { isa = PBXGroup; children = ( @@ -784,7 +771,6 @@ 97E5712A1CA0525300FF4F1D /* Operation */ = { isa = PBXGroup; children = ( - 970A2A201DD562B60078BB7C /* old */, 97D6811C1D6F70AC00E5FA99 /* GlobalQueue.swift */, 9764CBD21D8083AA00072D6A /* ArticleOperation.swift */, 970A2A211DD562CB0078BB7C /* BookOperations.swift */, diff --git a/Kiwix.xcworkspace/xcuserdata/chrisli.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Kiwix.xcworkspace/xcuserdata/chrisli.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index e2573a59..ed9a9b4d 100644 --- a/Kiwix.xcworkspace/xcuserdata/chrisli.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/Kiwix.xcworkspace/xcuserdata/chrisli.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -2,16 +2,4 @@ - - - - - - diff --git a/Kiwix/Operations/BookOperation.swift b/Kiwix/Operations/BookOperation.swift deleted file mode 100644 index 2e95fbf2..00000000 --- a/Kiwix/Operations/BookOperation.swift +++ /dev/null @@ -1,218 +0,0 @@ -// -// DownloadBookOperation.swift -// Kiwix -// -// Created by Chris Li on 8/25/16. -// Copyright © 2016 Chris Li. All rights reserved. -// - -import UIKit -import CoreData -import ProcedureKit - -class DownloadBookOperation: URLSessionDownloadTaskOperation { - let bookID: String? - let progress: DownloadProgress - - override init(downloadTask: URLSessionDownloadTask) { - progress = DownloadProgress(completedUnitCount: downloadTask.countOfBytesReceived, totalUnitCount: downloadTask.countOfBytesExpectedToReceive) - bookID = downloadTask.taskDescription - super.init(downloadTask: downloadTask) - name = downloadTask.taskDescription - - if UIApplication.shared.applicationState == .active, - let url = downloadTask.originalRequest?.url { - add(ReachabilityCondition(url: url, connectivity: .ViaWiFi)) - } - - // Update Coredata - let context = NSManagedObjectContext.mainQueueContext - context.performAndWait { - guard let bookID = self.bookID, - let book = Book.fetch(bookID, context: context), - let downloadTask = DownloadTask.fetch(book, context: context) else {return} - book.state = .downloading - downloadTask.state = .queued - - // Overwrite progress - self.progress.completedUnitCount = book.downloadTask?.totalBytesWritten ?? 0 - self.progress.totalUnitCount = book.fileSize - } - } - - convenience init?(bookID: String, resumeData: Data) { - if #available(iOS 10.0, *) { - guard let data = DownloadBookOperation.correctFuckingResumeData(resumeData) else {return nil} - let downloadTask = Network.shared.session.downloadTask(withResumeData: data) - downloadTask.taskDescription = bookID - self.init(downloadTask: downloadTask) - } else { - let downloadTask = Network.shared.session.downloadTask(withResumeData: resumeData) - downloadTask.taskDescription = bookID - self.init(downloadTask: downloadTask) - } - } - - convenience init?(bookID: String) { - let context = NSManagedObjectContext.mainQueueContext - guard let book = Book.fetch(bookID, context: context), - let url = book.url else { return nil } - - let task = Network.shared.session.downloadTask(with: url) - task.taskDescription = bookID - self.init(downloadTask: task) - } - - override func operationDidCancel() { - // Not Reachable - if let error = errors.first as? Operations.ReachabilityCondition.Error, error == .NotReachable { - return - } - - // Update Core Data - if produceResumeData { - let context = NSManagedObjectContext.mainQueueContext - context.performAndWait({ - guard let bookID = self.bookID, - let book = Book.fetch(bookID, context: context) else {return} - book.state = .downloading - }) - } else { - let context = NSManagedObjectContext.mainQueueContext - context.performAndWait({ - guard let bookID = self.bookID, - let book = Book.fetch(bookID, context: context) else {return} - book.state = .cloud - - guard let downloadTask = book.downloadTask else {return} - context.delete(downloadTask) - }) - } - - // URLSessionDelegate save resume data and update downloadTask - } - - // MARK: - Helper - - fileprivate class func correctFuckingResumeData(_ data: Data?) -> Data? { - let kResumeCurrentRequest = "NSURLSessionResumeCurrentRequest" - let kResumeOriginalRequest = "NSURLSessionResumeOriginalRequest" - - guard let data = data, let resumeDictionary = (try? PropertyListSerialization.propertyList(from: data, options: [.mutableContainersAndLeaves], format: nil)) as? NSMutableDictionary else { - return nil - } - - resumeDictionary[kResumeCurrentRequest] = correctFuckingRequestData(resumeDictionary[kResumeCurrentRequest] as? Data) - resumeDictionary[kResumeOriginalRequest] = correctFuckingRequestData(resumeDictionary[kResumeOriginalRequest] as? Data) - - let result = try? PropertyListSerialization.data(fromPropertyList: resumeDictionary, format: PropertyListSerialization.PropertyListFormat.xml, options: PropertyListSerialization.WriteOptions()) - return result - } - - fileprivate class func correctFuckingRequestData(_ data: Data?) -> Data? { - guard let data = data else { - return nil - } - if NSKeyedUnarchiver.unarchiveObject(with: data) != nil { - return data - } - guard let archive = (try? PropertyListSerialization.propertyList(from: data, options: [.mutableContainersAndLeaves], format: nil)) as? NSMutableDictionary else { - return nil - } - // Rectify weird __nsurlrequest_proto_props objects to $number pattern - var k = 0 - while archive["$objects"]?[1].object(forKey: "$\(k)") != nil { - k += 1 - } - var i = 0 - while archive["$objects"]?[1].object(forKey: "__nsurlrequest_proto_prop_obj_\(i)") != nil { - let arr = archive["$objects"] as? NSMutableArray - if let dic = arr?[1] as? NSMutableDictionary, let obj = dic["__nsurlrequest_proto_prop_obj_\(i)"] { - dic.setObject(obj, forKey: "$\(i + k)" as NSCopying) - dic.removeObject(forKey: "__nsurlrequest_proto_prop_obj_\(i)") - arr?[1] = dic - archive["$objects"] = arr - } - i += 1 - } - if archive["$objects"]?[1]["__nsurlrequest_proto_props"] != nil { - let arr = archive["$objects"] as? NSMutableArray - if let dic = arr?[1] as? NSMutableDictionary, let obj = dic["__nsurlrequest_proto_props"] { - dic.setObject(obj, forKey: "$\(i + k)" as NSCopying) - dic.removeObject(forKey: "__nsurlrequest_proto_props") - arr?[1] = dic - archive["$objects"] = arr - } - } - // Rectify weird "NSKeyedArchiveRootObjectKey" top key to NSKeyedArchiveRootObjectKey = "root" - if archive["$top"]?["NSKeyedArchiveRootObjectKey"] != nil { - (archive["$top"]? as AnyObject).set(archive["$top"]?["NSKeyedArchiveRootObjectKey"], forKey: NSKeyedArchiveRootObjectKey) - (archive["$top"]? as AnyObject).removeObject(forKey: "NSKeyedArchiveRootObjectKey") - } - // Re-encode archived object - let result = try? PropertyListSerialization.data(fromPropertyList: archive, format: PropertyListSerialization.PropertyListFormat.binary, options: PropertyListSerialization.WriteOptions()) - return result - } -} - -class RemoveBookOperation: Procedure { - let bookID: String - - init(bookID: String) { - self.bookID = bookID - super.init() - } - - override func execute() { - let context = NSManagedObjectContext.mainQueueContext - context.performAndWait { - guard let zimFileURL = ZimMultiReader.shared.readers[self.bookID]?.fileURL else {return} - _ = try? FileManager.default.removeItem(at: zimFileURL) - - // Core data is updated by scan book operation - // Article removal is handled by cascade relationship - - guard let idxFolderURL = ZimMultiReader.shared.readers[self.bookID]?.idxFolderURL else {return} - _ = try? FileManager.default.removeItem(at: idxFolderURL) - } - finish() - } -} - -class PauseBookDwonloadOperation: Procedure { - let bookID: String - - init(bookID: String) { - self.bookID = bookID - super.init() - } - - override func execute() { - Network.shared.operations[bookID]?.cancel(produceResumeData: true) - finish() - } -} - -class ResumeBookDwonloadOperation: Procedure { - let bookID: String - - init(bookID: String) { - self.bookID = bookID - super.init() - name = "Resume Book Dwonload Operation, bookID = \(bookID)" - } - - override func execute() { - guard let data: Data = Preference.resumeData[bookID] as Data?, - let operation = DownloadBookOperation(bookID: bookID, resumeData: data) else { - if let operation = DownloadBookOperation(bookID: bookID) { - produce(operation) - } - - finish() - return - } - Network.shared.queue.addOperation(operation) - finish() - } -} diff --git a/Kiwix/Operations/BookmarkOperation.swift b/Kiwix/Operations/BookmarkOperation.swift deleted file mode 100644 index a8b931e0..00000000 --- a/Kiwix/Operations/BookmarkOperation.swift +++ /dev/null @@ -1,150 +0,0 @@ -// -// BookmarkMigrationOperation.swift -// Kiwix -// -// Created by Chris Li on 9/26/16. -// Copyright © 2016 Chris Li. All rights reserved. -// - -import CoreData -import CloudKit -import ProcedureKit - -class BookmarkMigrationOperation: Procedure { - private let context: NSManagedObjectContext - - override init() { - self.context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) - context.parent = NSManagedObjectContext.mainQueueContext - context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy - - super.init() - add(condition: MutuallyExclusive()) - name = String(describing: self) - } - - override func execute() { - context.performAndWait { - let pids = Book.fetchLocal(self.context).flatMap({$1.pid}) - for pid in pids { - var books = Book.fetch(pid: pid, context: self.context) - let latestBook = books.removeFirst() - for book in books { - book.articles.forEach({$0.book = latestBook}) - } - } - if self.context.hasChanges {_ = try? self.context.save()} - } - finish() - } -} - -class BookmarkTrashOperation: Procedure { - private let context: NSManagedObjectContext - private let articles: [Article] - - init(articles: [Article]) { - self.context = NSManagedObjectContext.mainQueueContext - self.articles = articles - - super.init() -// add(condition: MutuallyExclusive()) - name = String(describing: self) - } - - override func execute() { - context.perform { - self.articles.forEach() { - $0.isBookmarked = false - $0.bookmarkDate = nil - } - - // Get books whose zim file removed, but are retain by bookmarks, and whose bookmarks are all removed - let books = Set(self.articles.flatMap({$0.book})) - .filter({Article.fetchBookmarked(in: $0, with: self.context).count == 0 && $0.state == .retained}) - books.forEach({ (book) in - if let _ = book.meta4URL { - book.state = .cloud - } else { - self.context.delete(book) - } - }) - - if self.context.hasChanges {_ = try? self.context.save()} - } - - if articles.count > 0 { -// produce(UpdateWidgetDataSourceOperation()) - } - - finish() - } -} - -class BookmarkCloudKitOperation: Procedure { - let article: Article - - init(article: Article) { - self.article = article - super.init() - name = String(describing: self) - } - - override func execute() { -// guard let bookID = article.book?.id else {finish(); return} -// let container = CKContainer(identifier: "iCloud.org.kiwix") -// container.accountStatusWithCompletionHandler { (status, error) in -// guard status == .Available else {self.finish(); return} -// -// container.fetchUserRecordIDWithCompletionHandler({ (recordID, error) in -// guard let ownerName = recordID?.recordName else {self.finish(); return} -// let database = container.privateCloudDatabase -// let zoneID = CKRecordZoneID(zoneName: bookID, ownerName: ownerName) -// database.fetchRecordZoneWithID(zoneID, completionHandler: { (zone, error) in -// if let zone = zone { -// -// } else { -// database. -// } -// }) -// }) -// } -// -// -// -// guard let bookID = article.book?.id else {finish(); return} -// -// let recordID = CKRecordID(recordName: bookID + "|" + article.path) -// let database = CKContainer(identifier: "iCloud.org.kiwix").privateCloudDatabase -// -// database.fetchRecordWithID(recordID) { (record, error) in -// if let record = record { -// if self.article.isBookmarked { -// self.populate(record, with: self.article) -// database.saveRecord(record, completionHandler: { (record, error) in -// self.finish() -// }) -// } else { -// database.deleteRecordWithID(recordID, completionHandler: { (recordID, error) in -// self.finish() -// }) -// } -// } else { -// guard self.article.isBookmarked else {self.finish(); return} -// let record = CKRecord(recordType: "Article", recordID: recordID) -// self.populate(record, with: self.article) -// database.saveRecord(record, completionHandler: { (record, error) in -// self.finish() -// }) -// } -// } - } - - func populate(_ record: CKRecord, with article: Article) { - record["path"] = self.article.path as CKRecordValue? - record["title"] = self.article.title as CKRecordValue? - record["snippet"] = self.article.snippet as CKRecordValue? - } -} - - diff --git a/Kiwix/Operations/RefreshLibrary.swift b/Kiwix/Operations/RefreshLibrary.swift index 942f18ff..2533f989 100644 --- a/Kiwix/Operations/RefreshLibrary.swift +++ b/Kiwix/Operations/RefreshLibrary.swift @@ -67,9 +67,10 @@ fileprivate class Process: Procedure, InputProcedure, XMLParserDelegate { let toBeDeleted = storeBookIDs.subtracting(memoryBookIDs) hasUpdate = toBeDeleted.count > 0 context.performAndWait { - toBeDeleted.forEach({ (id) in - - }) + for id in toBeDeleted { + guard let book = Book.fetch(id, context: self.context) else {continue} + self.context.delete(book) + } } if context.hasChanges { try? context.save() } diff --git a/Kiwix/Operations/RefreshLibraryOperation.swift b/Kiwix/Operations/RefreshLibraryOperation.swift deleted file mode 100644 index b95662d7..00000000 --- a/Kiwix/Operations/RefreshLibraryOperation.swift +++ /dev/null @@ -1,131 +0,0 @@ -// -// RefreshLibraryOperation.swift -// Kiwix -// -// Created by Chris Li on 2/7/16. -// Copyright © 2016 Chris Li. All rights reserved. -// - -import CoreData -import ProcedureKit - -class RefreshLibraryOperation: GroupProcedure { - - private(set) var hasUpdate = false - private(set) var firstTime = Preference.libraryLastRefreshTime == nil - - init(invokedByUser: Bool = false) { - let retrieve = Retrieve() - let process = Process() - process.injectResultFromDependency(retrieve) - super.init(operations: [retrieve, process]) - - addObserver(NetworkObserver()) - if UIApplication.sharedApplication().applicationState == .Active { - add(ReachabilityCondition(url: Retrieve.url)) - } - - addObserver(WillExecuteObserver { _ in - (UIApplication.sharedApplication().delegate as! AppDelegate).registerNotification() - }) - - process.addObserver(DidFinishObserver { [unowned self] (operation, errors) in - guard let operation = operation as? Process else {return} - self.hasUpdate = operation.hasUpdate - self.firstTime = operation.firstTime - }) - } -} - -private class Retrieve: Procedure, ResultInjection { - private static let url = URL(string: "https://download.kiwix.org/library/library.xml")! - private var result: Data? - - override init() { - super.init() - name = "Library Retrieve" - } - - fileprivate override func execute() { - guard !isCancelled else {return} - let task = URLSession.shared.dataTask(with: Retrieve.url, completionHandler: { (data, response, error) in - self.result = data - self.finish() - }) - task.resume() - } -} - -private class Process: Procedure, XMLParserDelegate, AutomaticInjectionOperationType { - var requirement: Data? - fileprivate(set) var hasUpdate = false - fileprivate(set) var firstTime = false - private let context: NSManagedObjectContext - private var oldBookIDs = Set() - private var newBookIDs = Set() - - override init() { - self.context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) - context.parent = NSManagedObjectContext.mainQueueContext - context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy - super.init() - name = "Library Process" - } - - override fileprivate func execute() { - guard let data = requirement else {finish(); return} - let xmlParser = XMLParser(data: data) - xmlParser.delegate = self - xmlParser.parse() - finish() - } - - fileprivate func saveManagedObjectContexts() { - context.performAndWait { self.context.saveIfNeeded() } - context.parent?.performAndWait { self.context.parent?.saveIfNeeded() } - } - - // MARK: NSXMLParser Delegate - - @objc fileprivate func parserDidStartDocument(_ parser: XMLParser) { - context.performAndWait { () -> Void in - self.oldBookIDs = Set(Book.fetchAll(self.context).map({ $0.id })) - } - } - - @objc fileprivate func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { - guard elementName == "book", - let id = attributeDict["id"] else {return} - - if !oldBookIDs.contains(id) { - hasUpdate = true - context.performAndWait({ () -> Void in - Book.add(attributeDict, context: self.context) - }) - } - newBookIDs.insert(id) - } - - @objc fileprivate func parserDidEndDocument(_ parser: XMLParser) { - let idsToDelete = oldBookIDs.subtracting(newBookIDs) - - context.performAndWait({ () -> Void in - idsToDelete.forEach({ (id) in - guard let book = Book.fetch(id, context: self.context) else {return} - - // Delete Book object only if book is online, i.e., is not associated with a download task or is not local - guard book.state == .cloud else {return} - self.context.delete(book) - self.hasUpdate = true - }) - }) - - saveManagedObjectContexts() - firstTime = Preference.libraryLastRefreshTime == nil - Preference.libraryLastRefreshTime = Date() - } - - @objc fileprivate func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) { - saveManagedObjectContexts() - } -} diff --git a/Kiwix/libkiwix/ZimReader.mm b/Kiwix/libkiwix/ZimReader.mm index 31dd549a..dcbcc012 100755 --- a/Kiwix/libkiwix/ZimReader.mm +++ b/Kiwix/libkiwix/ZimReader.mm @@ -1,4 +1,3 @@ - // // ZimReader.m // KiwixTest