diff --git a/Kiwix-iOS/AppDelegate.swift b/Kiwix-iOS/AppDelegate.swift
index da915ac1..c0db8be7 100644
--- a/Kiwix-iOS/AppDelegate.swift
+++ b/Kiwix-iOS/AppDelegate.swift
@@ -34,7 +34,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
application.registerUserNotificationSettings(settings)
// Set background refresh interval
- application.setMinimumBackgroundFetchInterval(60 * 60 * 24)
+ application.setMinimumBackgroundFetchInterval(86400)
return true
}
@@ -150,7 +150,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
let notification = UILocalNotification()
- notification.alertTitle = "[debug] Library was refreshed"
+ notification.alertTitle = "[DEBUG] Library was refreshed"
notification.alertBody = NSDate().description
notification.soundName = UILocalNotificationDefaultSoundName
UIApplication.sharedApplication().presentLocalNotificationNow(notification)
diff --git a/Kiwix-iOS/Controller/Library/DownloadTasksController.swift b/Kiwix-iOS/Controller/Library/DownloadTasksController.swift
index 566ec20e..e1c8d463 100644
--- a/Kiwix-iOS/Controller/Library/DownloadTasksController.swift
+++ b/Kiwix-iOS/Controller/Library/DownloadTasksController.swift
@@ -12,6 +12,8 @@ import DZNEmptyDataSet
class DownloadTasksController: UITableViewController, NSFetchedResultsControllerDelegate, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate {
+ var timer: NSTimer?
+
// MARK: - Override
required init?(coder aDecoder: NSCoder) {
@@ -33,6 +35,29 @@ class DownloadTasksController: UITableViewController, NSFetchedResultsController
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
tabBarController?.navigationItem.rightBarButtonItem = nil
+ timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(DownloadTasksController.refreshProgress), userInfo: nil, repeats: true)
+ }
+
+ override func viewWillDisappear(animated: Bool) {
+ super.viewWillDisappear(animated)
+ timer?.invalidate()
+ timer = nil
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ guard let identifier = segue.identifier else {return}
+ switch identifier {
+ case "ShowBookDetail":
+ guard let navController = segue.destinationViewController as? UINavigationController,
+ let bookDetailController = navController.topViewController as? BookDetailController,
+ let cell = sender as? UITableViewCell,
+ let indexPath = tableView.indexPathForCell(cell),
+ let downloadTask = fetchedResultController.objectAtIndexPath(indexPath) as? DownloadTask,
+ let book = downloadTask.book else {return}
+ bookDetailController.book = book
+ default:
+ break
+ }
}
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
@@ -43,6 +68,15 @@ class DownloadTasksController: UITableViewController, NSFetchedResultsController
tableView.scrollIndicatorInsets = inset
}
+ // MARK: - Methods
+
+ func refreshProgress() {
+ tableView.visibleCells.forEach { (cell) in
+ guard let indexPath = tableView.indexPathForCell(cell) else {return}
+ configureCell(cell, atIndexPath: indexPath)
+ }
+ }
+
// MARK: - TableView Data Source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
@@ -67,19 +101,10 @@ class DownloadTasksController: UITableViewController, NSFetchedResultsController
cell.titleLabel.text = book.title
cell.favIcon.image = UIImage(data: book.favIcon ?? NSData())
-//
-// guard let progress = Network.shared.progresses[id] else {return}
-// cell.progressView.progress = Float(progress.fractionCompleted)
-// switch downloadTask.state {
-// case .Queued, .Downloading:
-// cell.accessoryImageView.highlighted = false
-// cell.accessoryImageTintColor = UIColor.orangeColor().colorWithAlphaComponent(0.75)
-// case .Paused, .Error:
-// cell.accessoryImageView.highlighted = true
-// cell.accessoryHighlightedImageTintColor = UIColor.greenColor().colorWithAlphaComponent(0.75)
-// }
-// cell.subtitleLabel.text = progress.description
+ guard let progress = Network.shared.operations[id]?.progress else {return}
+ cell.progressView.progress = Float(progress.fractionCompleted)
+ cell.detailLabel.text = progress.localizedAdditionalDescription.stringByReplacingOccurrencesOfString(" – ", withString: "\n")
}
// MARK: Other Data Source
@@ -114,27 +139,21 @@ class DownloadTasksController: UITableViewController, NSFetchedResultsController
// header.textLabel?.font = UIFont.boldSystemFontOfSize(14)
// }
//
-// override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
-// return true
-// }
-//
-// override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {}
-//
-// override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
-// let remove = UITableViewRowAction(style: .Destructive, title: LocalizedStrings.remove) { (action, indexPath) -> Void in
-// guard let downloadTask = self.fetchedResultController.objectAtIndexPath(indexPath) as? DownloadTask else {return}
-// let context = UIApplication.appDelegate.managedObjectContext
-// if let book = downloadTask.book {
-// Network.sharedInstance.cancel(book)
-// FileManager.removeResumeData(book)
-// }
-// context.performBlockAndWait({ () -> Void in
-// downloadTask.book?.isLocal = false
-// context.deleteObject(downloadTask)
-// })
-// }
-// return [remove]
-// }
+ override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
+ return true
+ }
+
+ override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {}
+
+ override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
+ let remove = UITableViewRowAction(style: .Destructive, title: LocalizedStrings.remove) { (action, indexPath) -> Void in
+ guard let downloadTask = self.fetchedResultController.objectAtIndexPath(indexPath) as? DownloadTask,
+ let bookID = downloadTask.book?.id else {return}
+ let operation = CancelBookDownloadOperation(bookID: bookID)
+ GlobalOperationQueue.sharedInstance.addOperation(operation)
+ }
+ return [remove]
+ }
// MARK: - Fetched Results Controller
diff --git a/Kiwix-iOS/Info.plist b/Kiwix-iOS/Info.plist
index 7ca73986..da824076 100644
--- a/Kiwix-iOS/Info.plist
+++ b/Kiwix-iOS/Info.plist
@@ -49,7 +49,7 @@
CFBundleVersion
- 1.7.1386
+ 1.7.1423
ITSAppUsesNonExemptEncryption
LSRequiresIPhoneOS
diff --git a/Kiwix-iOS/Storyboard/Library.storyboard b/Kiwix-iOS/Storyboard/Library.storyboard
index 18623880..8db82d1c 100644
--- a/Kiwix-iOS/Storyboard/Library.storyboard
+++ b/Kiwix-iOS/Storyboard/Library.storyboard
@@ -469,7 +469,7 @@
-
+
@@ -515,6 +515,7 @@
+
@@ -686,6 +687,6 @@
-
+
diff --git a/Kiwix-iOSWidgets/Bookmarks/Info.plist b/Kiwix-iOSWidgets/Bookmarks/Info.plist
index e0819875..4e6c67cd 100644
--- a/Kiwix-iOSWidgets/Bookmarks/Info.plist
+++ b/Kiwix-iOSWidgets/Bookmarks/Info.plist
@@ -21,7 +21,7 @@
CFBundleSignature
????
CFBundleVersion
- 1.7.1673
+ 1.7.1742
NSExtension
NSExtensionMainStoryboard
diff --git a/Kiwix.xcodeproj/project.pbxproj b/Kiwix.xcodeproj/project.pbxproj
index 2854f846..11ed82d3 100644
--- a/Kiwix.xcodeproj/project.pbxproj
+++ b/Kiwix.xcodeproj/project.pbxproj
@@ -38,7 +38,6 @@
971A104A1D022CBE007FC62C /* SearchResultTBVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971A10471D022CBE007FC62C /* SearchResultTBVC.swift */; };
971A104B1D022CBE007FC62C /* SearchBooksVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971A10481D022CBE007FC62C /* SearchBooksVC.swift */; };
971A10521D022D9D007FC62C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971A10511D022D9D007FC62C /* AppDelegate.swift */; };
- 971A106F1D022E62007FC62C /* DownloadProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971A106D1D022E62007FC62C /* DownloadProgress.swift */; };
971A10771D022F05007FC62C /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 971A10791D022F05007FC62C /* Localizable.stringsdict */; };
971A107E1D022F74007FC62C /* DownloaderLearnMore.html in Resources */ = {isa = PBXBuildFile; fileRef = 971A107A1D022F74007FC62C /* DownloaderLearnMore.html */; };
971A107F1D022F74007FC62C /* ImportBookLearnMore.html in Resources */ = {isa = PBXBuildFile; fileRef = 971A107B1D022F74007FC62C /* ImportBookLearnMore.html */; };
@@ -131,7 +130,7 @@
97D681421D6F712800E5FA99 /* Language+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D6813E1D6F712800E5FA99 /* Language+CoreDataProperties.swift */; };
97D681441D6F713200E5FA99 /* CoreDataExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D681431D6F713200E5FA99 /* CoreDataExtension.swift */; };
97DB65DA1D4576B600A2CC42 /* BookmarkWidgetCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97DB65D91D4576B600A2CC42 /* BookmarkWidgetCell.swift */; };
- 97DF259C1D6F7613001648A3 /* DownloadBookOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97DF259B1D6F7612001648A3 /* DownloadBookOperation.swift */; };
+ 97DF259C1D6F7613001648A3 /* BookOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97DF259B1D6F7612001648A3 /* BookOperation.swift */; };
97DF259D1D6F9053001648A3 /* URLSessionDownloadTaskOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D681221D6F70AC00E5FA99 /* URLSessionDownloadTaskOperation.swift */; };
97DF25A01D6F996B001648A3 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97DF259F1D6F996B001648A3 /* Network.swift */; };
97E60A021D10423A00EBCB9D /* ShadowViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97E60A011D10423A00EBCB9D /* ShadowViews.swift */; };
@@ -357,7 +356,7 @@
97D6813E1D6F712800E5FA99 /* Language+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Language+CoreDataProperties.swift"; path = "Classes/Language+CoreDataProperties.swift"; sourceTree = ""; };
97D681431D6F713200E5FA99 /* CoreDataExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CoreDataExtension.swift; path = Classes/CoreDataExtension.swift; sourceTree = ""; };
97DB65D91D4576B600A2CC42 /* BookmarkWidgetCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkWidgetCell.swift; sourceTree = ""; };
- 97DF259B1D6F7612001648A3 /* DownloadBookOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadBookOperation.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 /* ShadowViews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShadowViews.swift; sourceTree = ""; };
@@ -969,7 +968,7 @@
97E5712A1CA0525300FF4F1D /* Operation */ = {
isa = PBXGroup;
children = (
- 97DF259B1D6F7612001648A3 /* DownloadBookOperation.swift */,
+ 97DF259B1D6F7612001648A3 /* BookOperation.swift */,
97D6811C1D6F70AC00E5FA99 /* GlobalOperationQueue.swift */,
97D6811D1D6F70AC00E5FA99 /* RefreshLibraryOperation.swift */,
97D6811E1D6F70AC00E5FA99 /* ScanLocalBookOperation.swift */,
@@ -1499,7 +1498,6 @@
97A7017F1D2C59CA00AAE2D8 /* GetStartedController.swift in Sources */,
97A8AD871D6CF38000584ED1 /* EmptyTableConfigExtension.swift in Sources */,
97D452BC1D16FF010033666F /* RecentSearchCVC.swift in Sources */,
- 971A106F1D022E62007FC62C /* DownloadProgress.swift in Sources */,
971A102E1D022AD5007FC62C /* TableViewCells.swift in Sources */,
97DF259D1D6F9053001648A3 /* URLSessionDownloadTaskOperation.swift in Sources */,
97E60A021D10423A00EBCB9D /* ShadowViews.swift in Sources */,
@@ -1555,7 +1553,7 @@
97A1FD441D6F728200A80EE2 /* Preference.swift in Sources */,
97D681311D6F70EC00E5FA99 /* 1.5.xcmappingmodel in Sources */,
97D681441D6F713200E5FA99 /* CoreDataExtension.swift in Sources */,
- 97DF259C1D6F7613001648A3 /* DownloadBookOperation.swift in Sources */,
+ 97DF259C1D6F7613001648A3 /* BookOperation.swift in Sources */,
97A1FD181D6F71CE00A80EE2 /* SearchResult.swift in Sources */,
9763275E1D64FE0F0034F120 /* BookDetailController.swift in Sources */,
973DD4281D36E3E4009D45DB /* SettingSingleSwitchTBVC.swift in Sources */,
diff --git a/Kiwix/Network/Network.swift b/Kiwix/Network/Network.swift
index 7c89b098..f5953c7e 100644
--- a/Kiwix/Network/Network.swift
+++ b/Kiwix/Network/Network.swift
@@ -9,10 +9,11 @@
import UIKit
import Operations
-// , NSURLSessionDownloadDelegate, NSURLSessionTaskDelegate
-class Network: NSObject, NSURLSessionDelegate, OperationQueueDelegate {
+// , NSURLSessionTaskDelegate
+class Network: NSObject, NSURLSessionDelegate, NSURLSessionDownloadDelegate, OperationQueueDelegate {
static let shared = Network()
let queue = OperationQueue()
+ private(set) var operations = [String: DownloadBookOperation]()
private override init() {
super.init()
@@ -26,15 +27,34 @@ class Network: NSObject, NSURLSessionDelegate, OperationQueueDelegate {
return NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
}()
+ // MARK: - OperationQueueDelegate
+
func operationQueue(queue: OperationQueue, willAddOperation operation: NSOperation) {
- print(queue.operationCount)
+ print("DEBUG: Network Queue will add" + (operation.name ?? "Unknown OP"))
+ guard let bookID = operation.name,
+ let operation = operation as? DownloadBookOperation else {return}
+ operations[bookID] = operation
}
func operationQueue(queue: OperationQueue, willFinishOperation operation: NSOperation, withErrors errors: [ErrorType]) {}
func operationQueue(queue: OperationQueue, didFinishOperation operation: NSOperation, withErrors errors: [ErrorType]) {
- print(queue.operationCount)
+ print("DEBUG: Network Queue did finish" + (operation.name ?? "Unknown OP"))
+ guard let bookID = operation.name else {return}
+ operations[bookID] = nil
}
func operationQueue(queue: OperationQueue, willProduceOperation operation: NSOperation) {}
+
+ // MARK: - NSURLSessionDownloadDelegate
+
+ func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
+ guard let bookID = downloadTask.taskDescription,
+ let operation = operations[bookID] else {return}
+ operation.progress.completedUnitCount = totalBytesWritten
+ }
+
+ func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
+
+ }
}
diff --git a/Kiwix/Operations/BookOperation.swift b/Kiwix/Operations/BookOperation.swift
new file mode 100644
index 00000000..16f31f9d
--- /dev/null
+++ b/Kiwix/Operations/BookOperation.swift
@@ -0,0 +1,76 @@
+//
+// DownloadBookOperation.swift
+// Kiwix
+//
+// Created by Chris Li on 8/25/16.
+// Copyright © 2016 Chris. All rights reserved.
+//
+
+import UIKit
+import CoreData
+import Operations
+
+class DownloadBookOperation: URLSessionDownloadTaskOperation {
+
+ let progress: DownloadProgress
+
+ override init(downloadTask: NSURLSessionDownloadTask) {
+ progress = DownloadProgress(completedUnitCount: downloadTask.countOfBytesReceived, totalUnitCount: downloadTask.countOfBytesExpectedToReceive)
+ super.init(downloadTask: downloadTask)
+ name = downloadTask.taskDescription
+ }
+
+ 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.downloadTaskWithURL(url)
+ task.taskDescription = bookID
+ self.init(downloadTask: task)
+
+ let downloadTask = DownloadTask.addOrUpdate(book, context: context)
+ downloadTask?.state = .Queued
+
+ progress.completedUnitCount = book.downloadTask?.totalBytesWritten ?? 0
+ progress.totalUnitCount = book.fileSize
+ }
+
+}
+
+class CancelBookDownloadOperation: Operation {
+
+ let bookID: String
+
+ init(bookID: String) {
+ self.bookID = bookID
+ super.init()
+ }
+
+ override func execute() {
+ Network.shared.operations[bookID]?.cancel(produceResumeData: false)
+
+ let context = NSManagedObjectContext.mainQueueContext
+ context.performBlockAndWait {
+ guard let book = Book.fetch(self.bookID, context: context) else {return}
+ if let _ = book.meta4URL {
+ book.isLocal = false
+ } else{
+ context.deleteObject(book)
+ }
+
+ guard let downloadTask = book.downloadTask else {return}
+ context.deleteObject(downloadTask)
+ }
+ finish()
+ }
+}
+
+class DownloadProgress: NSProgress {
+ init(completedUnitCount: Int64, totalUnitCount: Int64) {
+ super.init(parent: nil, userInfo: [NSProgressFileOperationKindKey: NSProgressFileOperationKindDownloading])
+ self.kind = NSProgressKindFile
+ self.totalUnitCount = totalUnitCount
+ self.completedUnitCount = completedUnitCount
+ }
+}
diff --git a/Kiwix/Operations/DownloadBookOperation.swift b/Kiwix/Operations/DownloadBookOperation.swift
deleted file mode 100644
index 50ef78fd..00000000
--- a/Kiwix/Operations/DownloadBookOperation.swift
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// DownloadBookOperation.swift
-// Kiwix
-//
-// Created by Chris Li on 8/25/16.
-// Copyright © 2016 Chris. All rights reserved.
-//
-
-import UIKit
-import CoreData
-import Operations
-
-class DownloadBookOperation: URLSessionDownloadTaskOperation {
-
- convenience init?(bookID: String) {
- let context = NSManagedObjectContext.mainQueueContext
- guard let book = Book.fetch(bookID, context: context),
- let url = book.url else { return nil }
-
-// book
- let task = Network.shared.session.downloadTaskWithURL(url)
-
- let downloadTask = DownloadTask.addOrUpdate(book, context: context)
- downloadTask?.state = .Queued
-
- task.taskDescription = bookID
- self.init(downloadTask: task)
- }
-
- override func operationDidFinish(errors: [ErrorType]) {
- guard let bookID = task.taskDescription else {return}
- print("Book download op finished")
- }
-}
-
diff --git a/Kiwix/Operations/URLSessionDownloadTaskOperation.swift b/Kiwix/Operations/URLSessionDownloadTaskOperation.swift
index 8f219c5f..b75cbcd9 100644
--- a/Kiwix/Operations/URLSessionDownloadTaskOperation.swift
+++ b/Kiwix/Operations/URLSessionDownloadTaskOperation.swift
@@ -16,7 +16,7 @@ class URLSessionDownloadTaskOperation: Operation {
let task: NSURLSessionTask
- private var produceResumeData = false
+ private(set) var produceResumeData = false
private var removedObserved = false
private let lock = NSLock()