Cancel Download OP & other changes

This commit is contained in:
Chris Li 2016-08-27 17:25:35 -04:00
parent 11d442789e
commit b3ae1c6a02
10 changed files with 164 additions and 85 deletions

View File

@ -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)

View File

@ -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

View File

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

View File

@ -469,7 +469,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="Cell" rowHeight="100" id="ekT-ed-PU9" customClass="DownloadBookCell" customModule="Kiwix" customModuleProvider="target">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" rowHeight="100" id="ekT-ed-PU9" customClass="DownloadBookCell" customModule="Kiwix" customModuleProvider="target">
<rect key="frame" x="0.0" y="92" width="375" height="100"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ekT-ed-PU9" id="oM4-Hy-Mkf">
@ -515,6 +515,7 @@
<outlet property="favIcon" destination="Too-68-SzG" id="nfU-AD-1Ji"/>
<outlet property="progressView" destination="g0o-rT-qxm" id="Jaw-Zr-uJY"/>
<outlet property="titleLabel" destination="Hji-3G-yaJ" id="mZ2-S6-XEO"/>
<segue destination="5Sz-gR-dgz" kind="showDetail" identifier="ShowBookDetail" id="eUy-Zq-fkw"/>
</connections>
</tableViewCell>
</prototypes>
@ -686,6 +687,6 @@
</scene>
</scenes>
<inferredMetricsTieBreakers>
<segue reference="N3M-rH-rAM"/>
<segue reference="eUy-Zq-fkw"/>
</inferredMetricsTieBreakers>
</document>

View File

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

View File

@ -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 = "<group>"; };
97D681431D6F713200E5FA99 /* CoreDataExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CoreDataExtension.swift; path = Classes/CoreDataExtension.swift; sourceTree = "<group>"; };
97DB65D91D4576B600A2CC42 /* BookmarkWidgetCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkWidgetCell.swift; sourceTree = "<group>"; };
97DF259B1D6F7612001648A3 /* DownloadBookOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadBookOperation.swift; sourceTree = "<group>"; };
97DF259B1D6F7612001648A3 /* BookOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookOperation.swift; sourceTree = "<group>"; };
97DF259F1D6F996B001648A3 /* Network.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = "<group>"; };
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 = "<group>"; };
@ -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 */,

View File

@ -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) {
}
}

View File

@ -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
}
}

View File

@ -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")
}
}

View File

@ -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()