Pause / Resume

This commit is contained in:
Chris Li 2016-09-19 14:02:47 -04:00
parent f22415e3c9
commit 043ad93fcd
6 changed files with 64 additions and 41 deletions

View File

@ -18,7 +18,7 @@ class DownloadTasksController: UITableViewController, NSFetchedResultsController
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
tabBarItem.title = LocalizedStrings.LibraryTabTitle.download
tabBarItem.title = LocalizedStrings.download
tabBarItem.image = UIImage(named: "Download")
tabBarItem.selectedImage = UIImage(named: "DownloadFilled")
}
@ -188,29 +188,29 @@ class DownloadTasksController: UITableViewController, NSFetchedResultsController
case .Downloading:
let pause = UITableViewRowAction(style: .Normal, title: "Pause") { (action, indexPath) in
let operation = PauseBookDwonloadOperation(bookID: bookID)
GlobalQueue.shared.addOperation(operation)
Network.shared.queue.addOperation(operation)
tableView.setEditing(false, animated: true)
}
actions.insert(pause, atIndex: 0)
case .Paused:
let resume = UITableViewRowAction(style: .Normal, title: "Resume") { (action, indexPath) in
let operation = ResumeBookDwonloadOperation(bookID: bookID)
GlobalQueue.shared.addOperation(operation)
Network.shared.queue.addOperation(operation)
tableView.setEditing(false, animated: true)
}
actions.insert(resume, atIndex: 0)
case .Error:
let retry = UITableViewRowAction(style: .Normal, title: "Restart") { (action, indexPath) in
let restart = UITableViewRowAction(style: .Normal, title: "Restart") { (action, indexPath) in
let operation = ResumeBookDwonloadOperation(bookID: bookID)
GlobalQueue.shared.addOperation(operation)
Network.shared.queue.addOperation(operation)
tableView.setEditing(false, animated: true)
}
actions.insert(retry, atIndex: 0)
actions.insert(restart, atIndex: 0)
default:
break
}
let cancel = UITableViewRowAction(style: .Destructive, title: LocalizedStrings.Common.cancel) { (action, indexPath) -> Void in
let cancel = UITableViewRowAction(style: .Destructive, title: LocalizedStrings.cancel) { (action, indexPath) -> Void in
if let bookID = downloadTask.book?.id {
if let operation = Network.shared.operations[bookID] {
// When download is ongoing
@ -289,4 +289,12 @@ class DownloadTasksController: UITableViewController, NSFetchedResultsController
tableView.endUpdates()
//refreshTabBarBadgeCount()
}
// MARK: - LocalizedStrings
class LocalizedStrings {
static let download = NSLocalizedString("Download", comment: "Library, download tab")
}
}

View File

@ -49,7 +49,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.8.777</string>
<string>1.8.827</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>

View File

@ -21,7 +21,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.8.780</string>
<string>1.8.830</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionMainStoryboard</key>

View File

@ -50,21 +50,18 @@ class Network: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSe
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if let error = error {print(error.localizedDescription)}
guard let error = error, let bookID = task.taskDescription else {return}
self.context.performBlockAndWait {
guard let book = Book.fetch(bookID, context: self.context),
let downloadTask = book.downloadTask else {return}
if let resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData] as? NSData {
// If download task doesnt exist, it must mean download is cancelled by user
// DownloadTask object will have been deleted when user tap Cancel button / table row action
downloadTask.totalBytesWritten = task.countOfBytesReceived
downloadTask.state = .Paused
// Save resume data to disk
Preference.resumeData[bookID] = resumeData
} else {
downloadTask.state = .Error
}
let context = NSManagedObjectContext.mainQueueContext
guard let error = error,
let bookID = task.taskDescription,
let downloadTask = Book.fetch(bookID, context: context)?.downloadTask else {return}
if let resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData] as? NSData {
Preference.resumeData[bookID] = resumeData
downloadTask.state = .Paused
downloadTask.totalBytesWritten = task.countOfBytesReceived
} else {
downloadTask.state = .Error
}
}

View File

@ -64,20 +64,32 @@ class DownloadBookOperation: URLSessionDownloadTaskOperation {
}
override func operationDidCancel() {
// Update CoreData
let context = NSManagedObjectContext.mainQueueContext
context.performBlockAndWait {
guard let bookID = self.bookID,
let book = Book.fetch(bookID, context: context) else {return}
if !self.produceResumeData {book.isLocal = false}
guard let downloadTask = book.downloadTask else {return}
if self.produceResumeData {
downloadTask.state = .Paused
} else {
context.deleteObject(downloadTask)
}
// Not Reachable
if let error = errors.first as? Operations.ReachabilityCondition.Error where error == .NotReachable {
return
}
// Update Core Data
if produceResumeData {
let context = NSManagedObjectContext.mainQueueContext
context.performBlockAndWait({
guard let bookID = self.bookID,
let book = Book.fetch(bookID, context: context) else {return}
book.isLocal = nil
})
} else {
let context = NSManagedObjectContext.mainQueueContext
context.performBlockAndWait({
guard let bookID = self.bookID,
let book = Book.fetch(bookID, context: context) else {return}
book.isLocal = false
guard let downloadTask = book.downloadTask else {return}
context.deleteObject(downloadTask)
})
}
// URLSessionDelegate save resume data and update downloadTask
}
// MARK: - Helper
@ -192,7 +204,14 @@ class ResumeBookDwonloadOperation: Operation {
override func execute() {
guard let data: NSData = Preference.resumeData[bookID],
let operation = DownloadBookOperation(bookID: bookID, resumeData: data) else {return}
let operation = DownloadBookOperation(bookID: bookID, resumeData: data) else {
if let operation = DownloadBookOperation(bookID: bookID) {
produceOperation(operation)
}
finish()
return
}
Network.shared.queue.addOperation(operation)
finish()
}

View File

@ -27,12 +27,11 @@ class URLSessionDownloadTaskOperation: Operation {
addObserver(NetworkObserver())
addObserver(DidCancelObserver { _ in
if self.produceResumeData {
downloadTask.cancelByProducingResumeData({ (data) in })
downloadTask.cancelByProducingResumeData({ _ in })
} else {
downloadTask.cancel()
}
}
)
})
}
func cancel(produceResumeData produceResumeData: Bool) {