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