From 7b3f52fb93271bd73db068f2afdd3f746db9c2de Mon Sep 17 00:00:00 2001 From: Chris Li Date: Tue, 31 Jan 2017 15:25:13 -0500 Subject: [PATCH] Basic download finish notification --- Kiwix.xcodeproj/project.pbxproj | 2 - Kiwix/Network/Network-old.swift | 153 -------------------------------- Kiwix/Network/Network.swift | 17 +++- Kiwix/Tools/Preference.swift | 6 ++ 4 files changed, 22 insertions(+), 156 deletions(-) delete mode 100644 Kiwix/Network/Network-old.swift diff --git a/Kiwix.xcodeproj/project.pbxproj b/Kiwix.xcodeproj/project.pbxproj index 491a6ed2..8af1d075 100644 --- a/Kiwix.xcodeproj/project.pbxproj +++ b/Kiwix.xcodeproj/project.pbxproj @@ -289,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 = ""; }; - 97DF259F1D6F996B001648A3 /* Network-old.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Network-old.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 = ""; }; 97E850CA1D2DA5B300A9F688 /* About.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = About.html; path = Kiwix/HelpDocuments/About.html; sourceTree = SOURCE_ROOT; }; @@ -739,7 +738,6 @@ 97DF259E1D6F9942001648A3 /* Network */ = { isa = PBXGroup; children = ( - 97DF259F1D6F996B001648A3 /* Network-old.swift */, 97642B981E380CC0003E2D0B /* Network.swift */, 9726591A1D8DB91200D1DFFB /* DownloadProgress.swift */, ); diff --git a/Kiwix/Network/Network-old.swift b/Kiwix/Network/Network-old.swift deleted file mode 100644 index c4b0b9b4..00000000 --- a/Kiwix/Network/Network-old.swift +++ /dev/null @@ -1,153 +0,0 @@ -// -// Network.swift -// Kiwix -// -// Created by Chris Li on 8/25/16. -// Copyright © 2016 Chris Li. All rights reserved. -// - -import UIKit -import CoreData -import ProcedureKit -import UserNotifications - -class Network: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDownloadDelegate, ProcedureQueueDelegate { - static let shared = Network() - let queue = OperationQueue() - let context = NSManagedObjectContext.mainQueueContext - - fileprivate(set) var operations = [String: DownloadBookOperation]() - fileprivate var downloadedBookTitle = [String]() - fileprivate var completionHandler: (()-> Void)? - - fileprivate override init() { - super.init() - queue.delegate = self - session.getAllTasks { _ in } - } - - lazy var session: Foundation.URLSession = { - let configuration = URLSessionConfiguration.background(withIdentifier: "org.kiwix.www") - configuration.allowsCellularAccess = false - configuration.isDiscretionary = false - return Foundation.URLSession(configuration: configuration, delegate: self, delegateQueue: nil) - }() - - func rejoinSessionWithIdentifier(_ identifier: String, completionHandler: @escaping ()-> Void) { - guard identifier == session.configuration.identifier else {return} - self.completionHandler = completionHandler - } - - // MARK: - OperationQueueDelegate - - func operationQueue(_ queue: ProcedureQueue, willAddOperation operation: Procedure) { - guard let bookID = operation.name, - let operation = operation as? DownloadBookOperation else {return} - operations[bookID] = operation - } - - func operationQueue(_ queue: ProcedureQueue, didFinishOperation operation: Procedure, withErrors errors: [Error]) { - guard let bookID = operation.name else {return} - operations[bookID] = nil - } - - func operationQueue(_ queue: ProcedureQueue, willFinishOperation operation: Procedure, withErrors errors: [Error]) {} - - func operationQueue(_ queue: ProcedureQueue, willProduceOperation operation: Procedure) {} - - // MARK: - NSURLSessionDelegate - - func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { - OperationQueue.main.addOperation { - self.completionHandler?() - - let title = NSLocalizedString("Book download finished", comment: "Notification: Book download finished") - let body: String = { - switch self.downloadedBookTitle.count { - case 0: - return NSLocalizedString("All download tasks are finished.", comment: "Notification: Book download finished") - case 1: - return String(format: NSLocalizedString("%@ has been downloaded", comment: "Notification: Book download finished"), self.downloadedBookTitle[0]) - case 2: - return String(format: NSLocalizedString("%@ and %@ have been downloaded", comment: "Notification: Book download finished"), - self.downloadedBookTitle[0], self.downloadedBookTitle[1]) - default: - return String(format: NSLocalizedString("%@ and %d others have been downloaded", comment: "Notification: Book download finished"), - self.downloadedBookTitle[0], self.downloadedBookTitle.count - 1) - } - }() - - if #available(iOS 10, *) { - UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { (settings) in - guard settings.alertSetting == .enabled else {return} - let content = UNMutableNotificationContent() - content.title = title - content.body = body - let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false) - let request = UNNotificationRequest(identifier: "org.kiwix.downloadFinished", content: content, trigger: trigger) - UNUserNotificationCenter.current().add(request, withCompletionHandler: nil) - }) - } else { - let notification = UILocalNotification() - notification.alertTitle = title - notification.alertBody = body - notification.soundName = UILocalNotificationDefaultSoundName - UIApplication.shared.presentLocalNotificationNow(notification) - } - } - } - - // MARK: - NSURLSessionTaskDelegate - - func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { - if let error = error {print(error.localizedDescription)} - - 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? Data { - Preference.resumeData[bookID] = resumeData - downloadTask.state = .paused - downloadTask.totalBytesWritten = task.countOfBytesReceived - } else { - downloadTask.state = .error - } - } - - // MARK: - NSURLSessionDownloadDelegate - - func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { - guard let bookID = downloadTask.taskDescription, - let operation = operations[bookID] else {return} - operation.progress.addObservation(totalBytesWritten) - - context.perform { - guard let downloadTask = Book.fetch(bookID, context: self.context)?.downloadTask, downloadTask.state == .queued else {return} - downloadTask.state = .downloading - } - } - - func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { - guard let bookID = downloadTask.taskDescription else {return} - - // Save downloaded zim file - var fileName: String = downloadTask.response?.suggestedFilename ?? bookID - if !fileName.hasSuffix(".zim") {fileName += ".zim"} - guard let destination = FileManager.docDirURL.appendingPathComponent(fileName) else {return} - _ = try? FileManager.default.moveItem(at: location, to: destination) - - // Scanner Operation will updated Book object status - - // - Remove cache, if any - // - Delete Download task Object - context.performAndWait { - guard let book = Book.fetch(bookID, context: self.context) else {return} - if let title = book.title {self.downloadedBookTitle.append(title)} - book.removeResumeData() - guard let downloadTask = book.downloadTask else {return} - self.context.delete(downloadTask) - } - } -} diff --git a/Kiwix/Network/Network.swift b/Kiwix/Network/Network.swift index 09cedd9f..087dd662 100644 --- a/Kiwix/Network/Network.swift +++ b/Kiwix/Network/Network.swift @@ -6,7 +6,7 @@ // Copyright © 2017 Chris Li. All rights reserved. // -import UIKit +import UserNotifications class Network: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDownloadDelegate { static let shared = Network() @@ -141,6 +141,21 @@ class Network: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionD let handler = backgroundEventsCompleteProcessing[identifier] { handler() } + + if Preference.Notifications.bookDownloadFinish { + self.managedObjectContext.perform({ + guard let book = Book.fetch(bookID, context: self.managedObjectContext) else {return} + let content = UNMutableNotificationContent() + content.categoryIdentifier = "org.kiwix.download-finished" + content.title = { + if let title = book.title {return title + "is downloaded!"} + else {return "Download task is finished!"} + }() + content.body = book.fileSizeDescription + "has been downloaded." + let request = UNNotificationRequest(identifier: "org.kiwix.download-finished." + bookID, content: content, trigger: nil) + UNUserNotificationCenter.current().add(request, withCompletionHandler: nil) + }) + } } // MARK: - URLSessionDownloadDelegate diff --git a/Kiwix/Tools/Preference.swift b/Kiwix/Tools/Preference.swift index 76c210a0..1f87c418 100644 --- a/Kiwix/Tools/Preference.swift +++ b/Kiwix/Tools/Preference.swift @@ -132,10 +132,16 @@ extension Preference { get{return Defaults[.notificationBookUpdateAvailable] ?? true} set{Defaults[.notificationBookUpdateAvailable] = newValue} } + + class var bookDownloadFinish: Bool { + get{return Defaults[.notificationBookDownloadFinish] ?? true} + set{Defaults[.notificationBookDownloadFinish] = newValue} + } } } extension DefaultsKeys { static let notificationLibraryRefresh = DefaultsKey("notificationLibraryRefresh") static let notificationBookUpdateAvailable = DefaultsKey("notificationBookUpdateAvailable") + static let notificationBookDownloadFinish = DefaultsKey("notificationBookDownloadFinish") }