From aa60ae8919d303ba38b0e12064f25d266bb8197c Mon Sep 17 00:00:00 2001 From: Chris Li Date: Tue, 31 Jan 2017 11:24:09 -0500 Subject: [PATCH] Pausing task when app quits --- Kiwix-iOS/AppDelegate.swift | 2 +- .../Library/LibraryDownloadController.swift | 20 ++++- Kiwix/Network/Network.swift | 73 ++++++++++--------- 3 files changed, 57 insertions(+), 38 deletions(-) diff --git a/Kiwix-iOS/AppDelegate.swift b/Kiwix-iOS/AppDelegate.swift index abecf36d..69e4d1d0 100644 --- a/Kiwix-iOS/AppDelegate.swift +++ b/Kiwix-iOS/AppDelegate.swift @@ -89,7 +89,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { URLProtocol.registerClass(KiwixURLProtocol.self) -// Network.shared + Network.shared // Register notification if let _ = Preference.libraryLastRefreshTime { registerNotification() } diff --git a/Kiwix-iOS/Controller/Library/LibraryDownloadController.swift b/Kiwix-iOS/Controller/Library/LibraryDownloadController.swift index 4efa9697..5f5a8618 100644 --- a/Kiwix-iOS/Controller/Library/LibraryDownloadController.swift +++ b/Kiwix-iOS/Controller/Library/LibraryDownloadController.swift @@ -59,10 +59,26 @@ class LibraryDownloadController: CoreDataTableBaseController, UITableViewDelegat func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { let downloadTask = fetchedResultController.object(at: indexPath) guard let book = downloadTask.book else {return []} - let cancel = UITableViewRowAction(style: .destructive, title: Localized.Common.cancel) { (action, indexPath) in + var actions = [UITableViewRowAction(style: .destructive, title: Localized.Common.cancel) { (action, indexPath) in Network.shared.cancel(bookID: book.id) + }] + if downloadTask.state == .downloading { + let pause = UITableViewRowAction(style: .normal, title: "Pause", handler: { _ in + tableView.setEditing(false, animated: true) + Network.shared.pause(bookID: book.id) + }) + pause.backgroundColor = UIColor.orange + actions.append(pause) + } else if downloadTask.state == .paused { + let resume = UITableViewRowAction(style: .normal, title: "Resume", handler: { (action, indexPath) in + tableView.setEditing(false, animated: true) + Network.shared.resume(bookID: book.id) + }) + resume.backgroundColor = view.tintColor + actions.append(resume) } - return [cancel] + + return actions } // MARK: - NSFetchedResultsController diff --git a/Kiwix/Network/Network.swift b/Kiwix/Network/Network.swift index bcfc27ce..3437d0af 100644 --- a/Kiwix/Network/Network.swift +++ b/Kiwix/Network/Network.swift @@ -10,7 +10,11 @@ import UIKit class Network: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDownloadDelegate { static let shared = Network() - private override init() {} + private override init() { + super.init() + _ = wifiSession + _ = cellularSession + } var progresses = [String: Int64]() let managedObjectContext = AppDelegate.persistentContainer.viewContext var timer: Timer? @@ -48,45 +52,38 @@ class Network: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionD func pause(bookID: String) { cancelTask(in: wifiSession, taskDescription: bookID, producingResumingData: true) cancelTask(in: cellularSession, taskDescription: bookID, producingResumingData: true) + + self.managedObjectContext.perform({ + guard let book = Book.fetch(bookID, context: self.managedObjectContext) else {return} + if book.state != .downloading {book.state = .downloading} + book.downloadTask?.state = .paused + if self.managedObjectContext.hasChanges { try? self.managedObjectContext.save() } + }) } func cancel(bookID: String) { cancelTask(in: wifiSession, taskDescription: bookID, producingResumingData: false) cancelTask(in: cellularSession, taskDescription: bookID, producingResumingData: false) + + self.managedObjectContext.perform({ + guard let book = Book.fetch(bookID, context: self.managedObjectContext) else {return} + book.meta4URL != nil ? book.state = .cloud : self.managedObjectContext.delete(book) + if let downloadTask = book.downloadTask {self.managedObjectContext.delete(downloadTask)} + if self.managedObjectContext.hasChanges { try? self.managedObjectContext.save() } + }) + } + + func resume(bookID: String) { + } private func cancelTask(in session: URLSession, taskDescription: String, producingResumingData: Bool) { session.getTasksWithCompletionHandler { (_, _, downloadTasks) in - func updateCoreData(bookID: String) { - self.managedObjectContext.perform({ - guard let book = Book.fetch(taskDescription, context: self.managedObjectContext) else {return} - if let _ = book.url { - book.state = .cloud - } else { - self.managedObjectContext.delete(book) - } - - guard let downloadTask = book.downloadTask else {return} - if producingResumingData { - downloadTask.state = .paused - } else { - self.managedObjectContext.delete(downloadTask) - } - }) - } - - if let task = downloadTasks.filter({$0.taskDescription == taskDescription}).first { - if producingResumingData { - task.cancel(byProducingResumeData: { (data) in - // save data - updateCoreData(bookID: taskDescription) - }) - } else { - task.cancel() - updateCoreData(bookID: taskDescription) - } + guard let task = downloadTasks.filter({$0.taskDescription == taskDescription}).first else {return} + if producingResumingData { + task.cancel(byProducingResumeData: {data in Preference.resumeData[taskDescription] = data }) } else { - updateCoreData(bookID: taskDescription) + task.cancel() } } } @@ -106,11 +103,19 @@ class Network: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionD func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { guard let bookID = task.taskDescription else {return} - if let data = (error as NSError?)?.userInfo[NSURLSessionDownloadTaskResumeData] as? Data { - Preference.resumeData[bookID] = data + progresses[bookID] = nil + if progresses.count == 0 { timer?.invalidate() } + + if let error = error as NSError?, error.code == URLError.cancelled.rawValue { self.managedObjectContext.perform({ guard let book = Book.fetch(bookID, context: self.managedObjectContext) else {return} + guard book.downloadTask?.state != .paused else {return} + if let data = error.userInfo[NSURLSessionDownloadTaskResumeData] as? Data { + Preference.resumeData[bookID] = data + } + if book.state != .downloading {book.state = .downloading} book.downloadTask?.state = .paused + if self.managedObjectContext.hasChanges { try? self.managedObjectContext.save() } }) } } @@ -122,6 +127,7 @@ class Network: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionD guard let bookID = downloadTask.taskDescription, let book = Book.fetch(bookID, context: self.managedObjectContext) else {return} if book.state != .downloading {book.state = .downloading} + if book.downloadTask?.state != .downloading {book.downloadTask?.state = .downloading} self.progresses[bookID] = totalBytesWritten } } @@ -129,9 +135,6 @@ class Network: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionD func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { guard let bookID = downloadTask.taskDescription else {return} - progresses[bookID] = nil - if progresses.count == 0 { timer?.invalidate() } - if let docDirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first { let fileName = { return downloadTask.response?.suggestedFilename