mirror of
https://github.com/kiwix/kiwix-apple.git
synced 2025-09-26 13:29:31 -04:00
Operations
This commit is contained in:
parent
ec151e49f9
commit
bf3adbe58a
@ -27,7 +27,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
|
||||
NSURLProtocol.registerClass(KiwixURLProtocol)
|
||||
// Network.shared.restoreProgresses()
|
||||
//Network.shared.restoreProgresses()
|
||||
|
||||
// Register notification
|
||||
let settings = UIUserNotificationSettings(forTypes: [.Sound, .Alert, .Badge], categories: nil) // Here are the notification permission the app wants
|
||||
@ -64,7 +64,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Active
|
||||
|
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Operations
|
||||
|
||||
class SearchResultTBVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
|
||||
|
||||
@ -120,15 +121,19 @@ class SearchResultTBVC: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
tableView.reloadData()
|
||||
return
|
||||
}
|
||||
let operation = SearchOperation(searchTerm: searchText) { (results) in
|
||||
guard let results = results else {return}
|
||||
self.searchResults = results
|
||||
self.tableView.reloadData()
|
||||
if results.count > 0 {
|
||||
self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: .Top, animated: true)
|
||||
}
|
||||
}
|
||||
ZimMultiReader.sharedInstance.startSearch(operation)
|
||||
// let operation = SearchOperation(searchTerm: searchText) { [unowned self] (results) in
|
||||
// guard let results = results else {return}
|
||||
// self.searchResults = results
|
||||
// self.tableView.reloadData()
|
||||
// if results.count > 0 {
|
||||
// self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: .Top, animated: true)
|
||||
// }
|
||||
// }
|
||||
let operation = SearchOperation(searchTerm: searchText)
|
||||
operation.addObserver(DidFinishObserver {(operation, errors) in
|
||||
print("search op did finish, result injection")
|
||||
})
|
||||
GlobalQueue.shared.add(search: operation)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.8.229</string>
|
||||
<string>1.8.277</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.8.231</string>
|
||||
<string>1.8.280</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionMainStoryboard</key>
|
||||
|
@ -93,7 +93,7 @@
|
||||
97A127CB1D777CF100FB204D /* SearchController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A127C71D777CF100FB204D /* SearchController.swift */; };
|
||||
97A127CC1D777CF100FB204D /* SearchResultTBVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A127C81D777CF100FB204D /* SearchResultTBVC.swift */; };
|
||||
97A1FD161D6F71CE00A80EE2 /* DirectoryMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A1FD121D6F71CE00A80EE2 /* DirectoryMonitor.swift */; };
|
||||
97A1FD171D6F71CE00A80EE2 /* ExtensionAndTypealias.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A1FD131D6F71CE00A80EE2 /* ExtensionAndTypealias.swift */; };
|
||||
97A1FD171D6F71CE00A80EE2 /* Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A1FD131D6F71CE00A80EE2 /* Extension.swift */; };
|
||||
97A1FD181D6F71CE00A80EE2 /* SearchResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A1FD141D6F71CE00A80EE2 /* SearchResult.swift */; };
|
||||
97A1FD191D6F71CE00A80EE2 /* ZimMultiReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A1FD151D6F71CE00A80EE2 /* ZimMultiReader.swift */; };
|
||||
97A1FD1C1D6F71D800A80EE2 /* KiwixURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A1FD1A1D6F71D800A80EE2 /* KiwixURLProtocol.swift */; };
|
||||
@ -118,12 +118,12 @@
|
||||
97C601DC1D7F15C400362D4F /* Bookmark.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C601DB1D7F15C400362D4F /* Bookmark.storyboard */; };
|
||||
97C601DE1D7F342100362D4F /* HTMLHeading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97C601DD1D7F342100362D4F /* HTMLHeading.swift */; };
|
||||
97D452BE1D1723FF0033666F /* CollectionViewCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D452BD1D1723FF0033666F /* CollectionViewCells.swift */; };
|
||||
97D4D64F1D874E6E00C1B065 /* SearchOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D4D64E1D874E6E00C1B065 /* SearchOperation.swift */; };
|
||||
97D55EF61D2075180081B523 /* TableOfContentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D55EF51D2075180081B523 /* TableOfContentsController.swift */; };
|
||||
97D6811B1D6E2A7100E5FA99 /* DownloadTasksController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D6811A1D6E2A7100E5FA99 /* DownloadTasksController.swift */; };
|
||||
97D681231D6F70AC00E5FA99 /* GlobalQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D6811C1D6F70AC00E5FA99 /* GlobalQueue.swift */; };
|
||||
97D681241D6F70AC00E5FA99 /* RefreshLibraryOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D6811D1D6F70AC00E5FA99 /* RefreshLibraryOperation.swift */; };
|
||||
97D681251D6F70AC00E5FA99 /* ScanLocalBookOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D6811E1D6F70AC00E5FA99 /* ScanLocalBookOperation.swift */; };
|
||||
97D681261D6F70AC00E5FA99 /* SearchOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D6811F1D6F70AC00E5FA99 /* SearchOperation.swift */; };
|
||||
97D681271D6F70AC00E5FA99 /* UIOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D681201D6F70AC00E5FA99 /* UIOperations.swift */; };
|
||||
97D681281D6F70AC00E5FA99 /* UpdateWidgetDataSourceOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D681211D6F70AC00E5FA99 /* UpdateWidgetDataSourceOperation.swift */; };
|
||||
97D6812E1D6F70DE00E5FA99 /* Kiwix.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 97D6812A1D6F70DE00E5FA99 /* Kiwix.xcdatamodeld */; };
|
||||
@ -315,7 +315,7 @@
|
||||
97A127C71D777CF100FB204D /* SearchController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchController.swift; sourceTree = "<group>"; };
|
||||
97A127C81D777CF100FB204D /* SearchResultTBVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchResultTBVC.swift; sourceTree = "<group>"; };
|
||||
97A1FD121D6F71CE00A80EE2 /* DirectoryMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DirectoryMonitor.swift; sourceTree = "<group>"; };
|
||||
97A1FD131D6F71CE00A80EE2 /* ExtensionAndTypealias.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionAndTypealias.swift; sourceTree = "<group>"; };
|
||||
97A1FD131D6F71CE00A80EE2 /* Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extension.swift; sourceTree = "<group>"; };
|
||||
97A1FD141D6F71CE00A80EE2 /* SearchResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchResult.swift; sourceTree = "<group>"; };
|
||||
97A1FD151D6F71CE00A80EE2 /* ZimMultiReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZimMultiReader.swift; sourceTree = "<group>"; };
|
||||
97A1FD1A1D6F71D800A80EE2 /* KiwixURLProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KiwixURLProtocol.swift; sourceTree = "<group>"; };
|
||||
@ -349,12 +349,13 @@
|
||||
97C601DB1D7F15C400362D4F /* Bookmark.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Bookmark.storyboard; sourceTree = "<group>"; };
|
||||
97C601DD1D7F342100362D4F /* HTMLHeading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTMLHeading.swift; sourceTree = "<group>"; };
|
||||
97D452BD1D1723FF0033666F /* CollectionViewCells.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewCells.swift; sourceTree = "<group>"; };
|
||||
97D4D64E1D874E6E00C1B065 /* SearchOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchOperation.swift; sourceTree = "<group>"; };
|
||||
97D55EF51D2075180081B523 /* TableOfContentsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TableOfContentsController.swift; path = "Kiwix-iOS/Controller/TableOfContentsController.swift"; sourceTree = SOURCE_ROOT; };
|
||||
97D6811A1D6E2A7100E5FA99 /* DownloadTasksController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadTasksController.swift; sourceTree = "<group>"; };
|
||||
97D6811C1D6F70AC00E5FA99 /* GlobalQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlobalQueue.swift; sourceTree = "<group>"; };
|
||||
97D6811D1D6F70AC00E5FA99 /* RefreshLibraryOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshLibraryOperation.swift; sourceTree = "<group>"; };
|
||||
97D6811E1D6F70AC00E5FA99 /* ScanLocalBookOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScanLocalBookOperation.swift; sourceTree = "<group>"; };
|
||||
97D6811F1D6F70AC00E5FA99 /* SearchOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchOperation.swift; sourceTree = "<group>"; };
|
||||
97D6811F1D6F70AC00E5FA99 /* SearchOperation-old.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SearchOperation-old.swift"; sourceTree = "<group>"; };
|
||||
97D681201D6F70AC00E5FA99 /* UIOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIOperations.swift; sourceTree = "<group>"; };
|
||||
97D681211D6F70AC00E5FA99 /* UpdateWidgetDataSourceOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateWidgetDataSourceOperation.swift; sourceTree = "<group>"; };
|
||||
97D681221D6F70AC00E5FA99 /* URLSessionDownloadTaskOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSessionDownloadTaskOperation.swift; sourceTree = "<group>"; };
|
||||
@ -626,10 +627,10 @@
|
||||
97254FDD1C26442F0056950B /* ZimMultiReader */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97A1FD121D6F71CE00A80EE2 /* DirectoryMonitor.swift */,
|
||||
97A1FD131D6F71CE00A80EE2 /* ExtensionAndTypealias.swift */,
|
||||
97A1FD141D6F71CE00A80EE2 /* SearchResult.swift */,
|
||||
97A1FD151D6F71CE00A80EE2 /* ZimMultiReader.swift */,
|
||||
97A1FD121D6F71CE00A80EE2 /* DirectoryMonitor.swift */,
|
||||
97A1FD131D6F71CE00A80EE2 /* Extension.swift */,
|
||||
97A1FD141D6F71CE00A80EE2 /* SearchResult.swift */,
|
||||
);
|
||||
path = ZimMultiReader;
|
||||
sourceTree = "<group>";
|
||||
@ -988,7 +989,8 @@
|
||||
97D6811C1D6F70AC00E5FA99 /* GlobalQueue.swift */,
|
||||
97D6811D1D6F70AC00E5FA99 /* RefreshLibraryOperation.swift */,
|
||||
97D6811E1D6F70AC00E5FA99 /* ScanLocalBookOperation.swift */,
|
||||
97D6811F1D6F70AC00E5FA99 /* SearchOperation.swift */,
|
||||
97D4D64E1D874E6E00C1B065 /* SearchOperation.swift */,
|
||||
97D6811F1D6F70AC00E5FA99 /* SearchOperation-old.swift */,
|
||||
97D681201D6F70AC00E5FA99 /* UIOperations.swift */,
|
||||
97D681211D6F70AC00E5FA99 /* UpdateWidgetDataSourceOperation.swift */,
|
||||
97D681221D6F70AC00E5FA99 /* URLSessionDownloadTaskOperation.swift */,
|
||||
@ -1545,7 +1547,6 @@
|
||||
97A127C41D774C9900FB204D /* ControllerRetainer.swift in Sources */,
|
||||
97D681321D6F70EC00E5FA99 /* MigrationPolicy.swift in Sources */,
|
||||
97D6811B1D6E2A7100E5FA99 /* DownloadTasksController.swift in Sources */,
|
||||
97D681261D6F70AC00E5FA99 /* SearchOperation.swift in Sources */,
|
||||
9764CBD11D806AD800072D6A /* RefreshLibControl.swift in Sources */,
|
||||
971A10381D022C15007FC62C /* WebViewController.swift in Sources */,
|
||||
97C601DE1D7F342100362D4F /* HTMLHeading.swift in Sources */,
|
||||
@ -1555,6 +1556,7 @@
|
||||
9764F5991D833F2B00E0B1C4 /* KiwixURL.swift in Sources */,
|
||||
97A127CC1D777CF100FB204D /* SearchResultTBVC.swift in Sources */,
|
||||
97A8AD841D6C951A00584ED1 /* LocalBooksController.swift in Sources */,
|
||||
97D4D64F1D874E6E00C1B065 /* SearchOperation.swift in Sources */,
|
||||
97D452BE1D1723FF0033666F /* CollectionViewCells.swift in Sources */,
|
||||
971A102F1D022AD5007FC62C /* Logo.swift in Sources */,
|
||||
97D55EF61D2075180081B523 /* TableOfContentsController.swift in Sources */,
|
||||
@ -1565,7 +1567,7 @@
|
||||
97A1FD261D6F71E200A80EE2 /* ZimReader.mm in Sources */,
|
||||
97A1FD1C1D6F71D800A80EE2 /* KiwixURLProtocol.swift in Sources */,
|
||||
97D6813F1D6F712800E5FA99 /* Article+CoreDataProperties.swift in Sources */,
|
||||
97A1FD171D6F71CE00A80EE2 /* ExtensionAndTypealias.swift in Sources */,
|
||||
97A1FD171D6F71CE00A80EE2 /* Extension.swift in Sources */,
|
||||
971A103C1D022C2C007FC62C /* FontSizeTBVC.swift in Sources */,
|
||||
971A103B1D022C2C007FC62C /* AdjustLayoutTBVC.swift in Sources */,
|
||||
97219DBD1D383A00009FDFF1 /* BookmarkController.swift in Sources */,
|
||||
|
@ -10,6 +10,31 @@ import Operations
|
||||
|
||||
class GlobalQueue: OperationQueue {
|
||||
static let shared = GlobalQueue()
|
||||
|
||||
private weak var scanOperation: ScanLocalBookOperation?
|
||||
private weak var searchOperation: SearchOperation?
|
||||
|
||||
func add(scan operation: ScanLocalBookOperation) {
|
||||
addOperation(operation)
|
||||
scanOperation = operation
|
||||
}
|
||||
|
||||
func add(search operation: SearchOperation) {
|
||||
if let _ = searchOperation {
|
||||
print("search is not released")
|
||||
}
|
||||
|
||||
if let scanOperation = scanOperation {
|
||||
operation.addDependency(scanOperation)
|
||||
print("scan not finished")
|
||||
}
|
||||
|
||||
if let searchOperation = self.searchOperation {
|
||||
searchOperation.cancel()
|
||||
}
|
||||
addOperation(operation)
|
||||
searchOperation = operation
|
||||
}
|
||||
}
|
||||
|
||||
public enum OperationErrorCode: Int {
|
||||
|
@ -11,17 +11,14 @@ import Operations
|
||||
|
||||
class ScanLocalBookOperation: Operation {
|
||||
private let context: NSManagedObjectContext
|
||||
private var firstBookAdded = false
|
||||
private(set) var firstBookAdded = false
|
||||
|
||||
private var lastZimFileURLSnapshot: Set<NSURL>
|
||||
private var currentZimFileURLSnapshot = Set<NSURL>()
|
||||
private(set) var currentZimFileURLSnapshot = Set<NSURL>()
|
||||
private let lastIndexFolderURLSnapshot: Set<NSURL>
|
||||
private var currentIndexFolderURLSnapshot = Set<NSURL>()
|
||||
private(set) var currentIndexFolderURLSnapshot = Set<NSURL>()
|
||||
|
||||
private var completionHandler: ((currentZimFileURLSnapshot: Set<NSURL>, currentIndexFolderURLSnapshot: Set<NSURL>, firstBookAdded: Bool) -> Void)
|
||||
|
||||
init(lastZimFileURLSnapshot: Set<NSURL>, lastIndexFolderURLSnapshot: Set<NSURL>,
|
||||
completionHandler: ((currentZimFileURLSnapshot: Set<NSURL>, currentIndexFolderURLSnapshot: Set<NSURL>, firstBookAdded: Bool) -> Void)) {
|
||||
init(lastZimFileURLSnapshot: Set<NSURL>, lastIndexFolderURLSnapshot: Set<NSURL>) {
|
||||
self.context = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
|
||||
context.parentContext = NSManagedObjectContext.mainQueueContext
|
||||
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
||||
@ -29,7 +26,6 @@ class ScanLocalBookOperation: Operation {
|
||||
self.lastZimFileURLSnapshot = lastZimFileURLSnapshot
|
||||
self.lastIndexFolderURLSnapshot = lastIndexFolderURLSnapshot
|
||||
|
||||
self.completionHandler = completionHandler
|
||||
super.init()
|
||||
addCondition(MutuallyExclusive<ZimMultiReader>())
|
||||
name = String(self)
|
||||
@ -54,10 +50,6 @@ class ScanLocalBookOperation: Operation {
|
||||
override func operationDidFinish(errors: [ErrorType]) {
|
||||
context.performBlockAndWait {self.context.saveIfNeeded()}
|
||||
NSManagedObjectContext.mainQueueContext.performBlockAndWait {NSManagedObjectContext.mainQueueContext.saveIfNeeded()}
|
||||
NSOperationQueue.mainQueue().addOperationWithBlock {
|
||||
self.completionHandler(currentZimFileURLSnapshot: self.currentZimFileURLSnapshot,
|
||||
currentIndexFolderURLSnapshot: self.currentIndexFolderURLSnapshot, firstBookAdded: self.firstBookAdded)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateReaders() {
|
||||
|
110
Kiwix/Operations/SearchOperation-old.swift
Normal file
110
Kiwix/Operations/SearchOperation-old.swift
Normal file
@ -0,0 +1,110 @@
|
||||
//
|
||||
// SearchOperation.swift
|
||||
// Kiwix
|
||||
//
|
||||
// Created by Chris Li on 4/9/16.
|
||||
// Copyright © 2016 Chris. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Operations
|
||||
|
||||
class SearchOperation: GroupOperation {
|
||||
let completionHandler: ([SearchResult]?) -> Void
|
||||
private(set) var results = [SearchResult]()
|
||||
//private let startTime = NSDate()
|
||||
|
||||
init(searchTerm: String, completionHandler: ([SearchResult]?) -> Void) {
|
||||
self.completionHandler = completionHandler
|
||||
super.init(operations: [NSOperation]())
|
||||
|
||||
let sortOperation = SortSearchResultsOperation { (results) in
|
||||
self.results = results
|
||||
}
|
||||
|
||||
for (id, zimReader) in ZimMultiReader.sharedInstance.readers {
|
||||
let managedObjectContext = UIApplication.appDelegate.managedObjectContext
|
||||
guard let book = Book.fetch(id, context: managedObjectContext) else {continue}
|
||||
guard book.includeInSearch else {continue}
|
||||
let operation = SingleBookSearchOperation(zimReader: zimReader,
|
||||
lowerCaseSearchTerm: searchTerm.lowercaseString,
|
||||
completionHandler: { [unowned sortOperation] (results) in
|
||||
sortOperation.results += results
|
||||
})
|
||||
|
||||
addOperation(operation)
|
||||
sortOperation.addDependency(operation)
|
||||
}
|
||||
|
||||
addOperation(sortOperation)
|
||||
|
||||
addCondition(MutuallyExclusive<ZimMultiReader>())
|
||||
}
|
||||
|
||||
override func operationDidFinish(errors: [ErrorType]) {
|
||||
NSOperationQueue.mainQueue().addOperationWithBlock {
|
||||
self.completionHandler(self.cancelled ? nil : self.results)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SingleBookSearchOperation: Operation {
|
||||
let zimReader: ZimReader
|
||||
let lowerCaseSearchTerm: String
|
||||
let completionHandler: ([SearchResult]) -> Void
|
||||
|
||||
init(zimReader: ZimReader, lowerCaseSearchTerm: String, completionHandler: ([SearchResult]) -> Void) {
|
||||
self.zimReader = zimReader
|
||||
self.lowerCaseSearchTerm = lowerCaseSearchTerm
|
||||
self.completionHandler = completionHandler
|
||||
super.init()
|
||||
}
|
||||
|
||||
override private func execute() {
|
||||
var results = [String: SearchResult]()
|
||||
let indexedDics = zimReader.searchUsingIndex(lowerCaseSearchTerm) as? [[String: AnyObject]] ?? [[String: AnyObject]]()
|
||||
let titleDics = zimReader.searchSuggestionsSmart(lowerCaseSearchTerm) as? [[String: AnyObject]] ?? [[String: AnyObject]]()
|
||||
let mixedDics = titleDics + indexedDics // It is important we process the title search result first, so that we always keep the indexed search result
|
||||
for dic in mixedDics {
|
||||
guard let result = SearchResult (rawResult: dic, lowerCaseSearchTerm: lowerCaseSearchTerm) else {continue}
|
||||
results[result.path] = result
|
||||
}
|
||||
completionHandler(Array(results.values))
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
private class SortSearchResultsOperation: Operation {
|
||||
let completionHandler: ([SearchResult]) -> Void
|
||||
var results = [SearchResult]()
|
||||
|
||||
init(completionHandler: ([SearchResult]) -> Void) {
|
||||
self.completionHandler = completionHandler
|
||||
super.init()
|
||||
}
|
||||
|
||||
override private func execute() {
|
||||
sort()
|
||||
completionHandler(results)
|
||||
finish()
|
||||
}
|
||||
|
||||
private func sort() {
|
||||
results.sortInPlace { (result0, result1) -> Bool in
|
||||
if result0.score != result1.score {
|
||||
return result0.score < result1.score
|
||||
} else {
|
||||
if result0.snippet != nil {return true}
|
||||
if result1.snippet != nil {return false}
|
||||
return titleCaseInsensitiveCompare(result0, result1: result1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Utilities
|
||||
|
||||
private func titleCaseInsensitiveCompare(result0: SearchResult, result1: SearchResult) -> Bool {
|
||||
return result0.title.caseInsensitiveCompare(result1.title) == NSComparisonResult.OrderedAscending
|
||||
}
|
||||
}
|
||||
|
@ -2,109 +2,14 @@
|
||||
// SearchOperation.swift
|
||||
// Kiwix
|
||||
//
|
||||
// Created by Chris Li on 4/9/16.
|
||||
// Created by Chris Li on 9/12/16.
|
||||
// Copyright © 2016 Chris. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Operations
|
||||
|
||||
class SearchOperation: GroupOperation {
|
||||
let completionHandler: ([SearchResult]?) -> Void
|
||||
private(set) var results = [SearchResult]()
|
||||
//private let startTime = NSDate()
|
||||
|
||||
init(searchTerm: String, completionHandler: ([SearchResult]?) -> Void) {
|
||||
self.completionHandler = completionHandler
|
||||
super.init(operations: [NSOperation]())
|
||||
|
||||
let sortOperation = SortSearchResultsOperation { (results) in
|
||||
self.results = results
|
||||
}
|
||||
|
||||
for (id, zimReader) in ZimMultiReader.sharedInstance.readers {
|
||||
let managedObjectContext = UIApplication.appDelegate.managedObjectContext
|
||||
guard let book = Book.fetch(id, context: managedObjectContext) else {continue}
|
||||
guard book.includeInSearch else {continue}
|
||||
let operation = SingleBookSearchOperation(zimReader: zimReader,
|
||||
lowerCaseSearchTerm: searchTerm.lowercaseString,
|
||||
completionHandler: { [unowned sortOperation] (results) in
|
||||
sortOperation.results += results
|
||||
})
|
||||
|
||||
addOperation(operation)
|
||||
sortOperation.addDependency(operation)
|
||||
}
|
||||
|
||||
addOperation(sortOperation)
|
||||
|
||||
addCondition(MutuallyExclusive<ZimMultiReader>())
|
||||
}
|
||||
|
||||
override func operationDidFinish(errors: [ErrorType]) {
|
||||
NSOperationQueue.mainQueue().addOperationWithBlock {
|
||||
self.completionHandler(self.cancelled ? nil : self.results)
|
||||
}
|
||||
init(searchTerm: String) {
|
||||
super.init(operations: [])
|
||||
}
|
||||
}
|
||||
|
||||
private class SingleBookSearchOperation: Operation {
|
||||
let zimReader: ZimReader
|
||||
let lowerCaseSearchTerm: String
|
||||
let completionHandler: ([SearchResult]) -> Void
|
||||
|
||||
init(zimReader: ZimReader, lowerCaseSearchTerm: String, completionHandler: ([SearchResult]) -> Void) {
|
||||
self.zimReader = zimReader
|
||||
self.lowerCaseSearchTerm = lowerCaseSearchTerm
|
||||
self.completionHandler = completionHandler
|
||||
super.init()
|
||||
}
|
||||
|
||||
override private func execute() {
|
||||
var results = [String: SearchResult]()
|
||||
let indexedDics = zimReader.searchUsingIndex(lowerCaseSearchTerm) as? [[String: AnyObject]] ?? [[String: AnyObject]]()
|
||||
let titleDics = zimReader.searchSuggestionsSmart(lowerCaseSearchTerm) as? [[String: AnyObject]] ?? [[String: AnyObject]]()
|
||||
let mixedDics = titleDics + indexedDics // It is important we process the title search result first, so that we always keep the indexed search result
|
||||
for dic in mixedDics {
|
||||
guard let result = SearchResult (rawResult: dic, lowerCaseSearchTerm: lowerCaseSearchTerm) else {continue}
|
||||
results[result.path] = result
|
||||
}
|
||||
completionHandler(Array(results.values))
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
private class SortSearchResultsOperation: Operation {
|
||||
let completionHandler: ([SearchResult]) -> Void
|
||||
var results = [SearchResult]()
|
||||
|
||||
init(completionHandler: ([SearchResult]) -> Void) {
|
||||
self.completionHandler = completionHandler
|
||||
super.init()
|
||||
}
|
||||
|
||||
override private func execute() {
|
||||
sort()
|
||||
completionHandler(results)
|
||||
finish()
|
||||
}
|
||||
|
||||
private func sort() {
|
||||
results.sortInPlace { (result0, result1) -> Bool in
|
||||
if result0.score != result1.score {
|
||||
return result0.score < result1.score
|
||||
} else {
|
||||
if result0.snippet != nil {return true}
|
||||
if result1.snippet != nil {return false}
|
||||
return titleCaseInsensitiveCompare(result0, result1: result1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Utilities
|
||||
|
||||
private func titleCaseInsensitiveCompare(result0: SearchResult, result1: SearchResult) -> Bool {
|
||||
return result0.title.caseInsensitiveCompare(result1.title) == NSComparisonResult.OrderedAscending
|
||||
}
|
||||
}
|
||||
|
||||
|
32
Kiwix/ZimMultiReader/Extension.swift
Normal file
32
Kiwix/ZimMultiReader/Extension.swift
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// ExtensionAndTypealias.swift
|
||||
// Kiwix
|
||||
//
|
||||
// Created by Chris Li on 7/11/16.
|
||||
// Copyright © 2016 Chris. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
typealias ZimID = String
|
||||
typealias ArticlePath = String
|
||||
|
||||
extension ZimReader {
|
||||
var metaData: [String: AnyObject] {
|
||||
var metadata = [String: AnyObject]()
|
||||
|
||||
if let id = getID() {metadata["id"] = id}
|
||||
if let title = getTitle() {metadata["title"] = title}
|
||||
if let description = getDesc() {metadata["description"] = description}
|
||||
if let creator = getCreator() {metadata["creator"] = creator}
|
||||
if let publisher = getPublisher() {metadata["publisher"] = publisher}
|
||||
if let favicon = getFavicon() {metadata["favicon"] = favicon}
|
||||
if let date = getDate() {metadata["date"] = date}
|
||||
if let articleCount = getArticleCount() {metadata["articleCount"] = articleCount}
|
||||
if let mediaCount = getMediaCount() {metadata["mediaCount"] = mediaCount}
|
||||
if let fileSize = getFileSize() {metadata["size"] = fileSize}
|
||||
if let langCode = getLanguage() {metadata["language"] = langCode}
|
||||
|
||||
return metadata
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
//
|
||||
// ExtensionAndTypealias.swift
|
||||
// Kiwix
|
||||
//
|
||||
// Created by Chris Li on 7/11/16.
|
||||
// Copyright © 2016 Chris. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
typealias ZimID = String
|
||||
typealias ArticlePath = String
|
||||
|
||||
extension ZimReader {
|
||||
var metaData: [String: AnyObject] {
|
||||
var metadata = [String: AnyObject]()
|
||||
|
||||
if let id = getID() {metadata["id"] = id}
|
||||
if let title = getTitle() {metadata["title"] = title}
|
||||
if let description = getDesc() {metadata["description"] = description}
|
||||
if let creator = getCreator() {metadata["creator"] = creator}
|
||||
if let publisher = getPublisher() {metadata["publisher"] = publisher}
|
||||
if let favicon = getFavicon() {metadata["favicon"] = favicon}
|
||||
if let date = getDate() {metadata["date"] = date}
|
||||
if let articleCount = getArticleCount() {metadata["articleCount"] = articleCount}
|
||||
if let mediaCount = getMediaCount() {metadata["mediaCount"] = mediaCount}
|
||||
if let fileSize = getFileSize() {metadata["size"] = fileSize}
|
||||
if let langCode = getLanguage() {metadata["language"] = langCode}
|
||||
|
||||
return metadata
|
||||
}
|
||||
}
|
||||
|
||||
// https://gist.github.com/adamyanalunas/69f6601fad6040686d300a1cdc20f500
|
||||
private extension String {
|
||||
subscript(index: Int) -> Character {
|
||||
return self[startIndex.advancedBy(index)]
|
||||
}
|
||||
|
||||
subscript(range: Range<Int>) -> String {
|
||||
let start = startIndex.advancedBy(range.startIndex)
|
||||
let end = startIndex.advancedBy(range.endIndex)
|
||||
return self[start..<end]
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
func levenshtein(string cmpString: String) -> Int {
|
||||
let (length, cmpLength) = (characters.count, cmpString.characters.count)
|
||||
var matrix = Array(
|
||||
count: cmpLength + 1,
|
||||
repeatedValue: Array(
|
||||
count: length + 1,
|
||||
repeatedValue: 0
|
||||
)
|
||||
)
|
||||
|
||||
for m in 1..<cmpLength {
|
||||
matrix[m][0] = matrix[m - 1][0] + 1
|
||||
}
|
||||
|
||||
for n in 1..<length {
|
||||
matrix[0][n] = matrix[0][n - 1] + 1
|
||||
}
|
||||
|
||||
for m in 1..<(cmpLength + 1) {
|
||||
for n in 1..<(length + 1) {
|
||||
let penalty = self[n - 1] == cmpString[m - 1] ? 0 : 1
|
||||
let (horizontal, vertical, diagonal) = (matrix[m - 1][n] + 1, matrix[m][n - 1] + 1, matrix[m - 1][n - 1])
|
||||
matrix[m][n] = min(horizontal, vertical, diagonal + penalty)
|
||||
}
|
||||
}
|
||||
|
||||
return matrix[cmpLength][length]
|
||||
}
|
||||
}
|
@ -13,12 +13,9 @@ class ZimMultiReader: NSObject, DirectoryMonitorDelegate {
|
||||
static let sharedInstance = ZimMultiReader()
|
||||
|
||||
weak var delegate: ZimMultiReaderDelegate?
|
||||
private weak var scanOperation: ScanLocalBookOperation?
|
||||
private weak var searchOperation: SearchOperation?
|
||||
|
||||
private let searchQueue = OperationQueue()
|
||||
private(set) var readers = [ZimID: ZimReader]()
|
||||
private let monitor = DirectoryMonitor(URL: NSFileManager.docDirURL)
|
||||
|
||||
private(set) var readers = [ZimID: ZimReader]()
|
||||
private var lastZimFileURLSnapshot = Set<NSURL>()
|
||||
private var lastIndexFolderURLSnapshot = Set<NSURL>()
|
||||
|
||||
@ -35,15 +32,20 @@ class ZimMultiReader: NSObject, DirectoryMonitorDelegate {
|
||||
}
|
||||
|
||||
func startScan() {
|
||||
let scanOperation = ScanLocalBookOperation(lastZimFileURLSnapshot: lastZimFileURLSnapshot, lastIndexFolderURLSnapshot: lastIndexFolderURLSnapshot) { (currentZimFileURLSnapshot, currentIndexFolderURLSnapshot, firstBookAdded) in
|
||||
self.lastZimFileURLSnapshot = currentZimFileURLSnapshot
|
||||
self.lastIndexFolderURLSnapshot = currentIndexFolderURLSnapshot
|
||||
if firstBookAdded {
|
||||
let operation = ScanLocalBookOperation(lastZimFileURLSnapshot: lastZimFileURLSnapshot, lastIndexFolderURLSnapshot: lastIndexFolderURLSnapshot)
|
||||
operation.addObserver(DidFinishObserver { (operation, errors) in
|
||||
guard let operation = operation as? ScanLocalBookOperation else {return}
|
||||
NSOperationQueue.mainQueue().addOperationWithBlock({
|
||||
self.lastZimFileURLSnapshot = operation.currentZimFileURLSnapshot
|
||||
self.lastIndexFolderURLSnapshot = operation.currentIndexFolderURLSnapshot
|
||||
|
||||
guard operation.firstBookAdded else {return}
|
||||
self.delegate?.firstBookAdded()
|
||||
}
|
||||
}
|
||||
GlobalQueue.shared.addOperation(scanOperation)
|
||||
self.scanOperation = scanOperation
|
||||
})
|
||||
})
|
||||
operation.queuePriority = .VeryHigh
|
||||
if readers.count == 0 { operation.qualityOfService = .UserInitiated }
|
||||
GlobalQueue.shared.add(scan: operation)
|
||||
}
|
||||
|
||||
// MARK: - Reader Addition / Deletion
|
||||
@ -69,20 +71,6 @@ class ZimMultiReader: NSObject, DirectoryMonitorDelegate {
|
||||
startScan()
|
||||
}
|
||||
|
||||
// MARK: - Search
|
||||
|
||||
func startSearch(searchOperation: SearchOperation) {
|
||||
if let scanOperation = scanOperation {
|
||||
searchOperation.addDependency(scanOperation)
|
||||
}
|
||||
|
||||
if let searchOperation = self.searchOperation {
|
||||
searchOperation.cancel()
|
||||
}
|
||||
searchQueue.addOperation(searchOperation)
|
||||
self.searchOperation = searchOperation
|
||||
}
|
||||
|
||||
// MARK: - Loading System
|
||||
|
||||
func data(id: String, contentURLString: String) -> [String: AnyObject]? {
|
||||
|
Loading…
x
Reference in New Issue
Block a user