diff --git a/Kiwix-iOS/Controller/Bookmark/BookmarkBooksController.swift b/Kiwix-iOS/Controller/Bookmark/BookmarkBooksController.swift index 9568de7e..4ee31ecd 100644 --- a/Kiwix-iOS/Controller/Bookmark/BookmarkBooksController.swift +++ b/Kiwix-iOS/Controller/Bookmark/BookmarkBooksController.swift @@ -46,7 +46,7 @@ class BookmarkBooksController: CoreDataTableBaseController, UITableViewDelegate, return cell } - override func configureCell(_ cell: UITableViewCell, atIndexPath indexPath: IndexPath) { + override func configureCell(_ cell: UITableViewCell, atIndexPath indexPath: IndexPath, animated: Bool = false) { guard let cell = cell as? BasicBookCell else {return} let book = fetchedResultController.object(at: indexPath) diff --git a/Kiwix-iOS/Controller/Library/LibraryDownloadController.swift b/Kiwix-iOS/Controller/Library/LibraryDownloadController.swift index 7ba789e7..efdaf47f 100644 --- a/Kiwix-iOS/Controller/Library/LibraryDownloadController.swift +++ b/Kiwix-iOS/Controller/Library/LibraryDownloadController.swift @@ -21,6 +21,7 @@ class LibraryDownloadController: CoreDataTableBaseController, UITableViewDelegat @IBAction func dismissButtonTapped(_ sender: UIBarButtonItem) { dismiss(animated: true, completion: nil) } + // MARK: - Table view data source func numberOfSections(in tableView: UITableView) -> Int { @@ -33,11 +34,11 @@ class LibraryDownloadController: CoreDataTableBaseController, UITableViewDelegat func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) - configureCell(cell, atIndexPath: indexPath) + configureCell(cell, atIndexPath: indexPath, animated: false) return cell } - override func configureCell(_ cell: UITableViewCell, atIndexPath indexPath: IndexPath) { + override func configureCell(_ cell: UITableViewCell, atIndexPath indexPath: IndexPath, animated: Bool = false) { guard let cell = cell as? DownloadTaskCell else {return} let downloadTask = fetchedResultController.object(at: indexPath) @@ -49,7 +50,20 @@ class LibraryDownloadController: CoreDataTableBaseController, UITableViewDelegat if let data = book.favIcon {cell.thumbImageView.image = UIImage(data: data)} cell.titleLabel.text = book.title cell.subtitleLabel.text = progressFormatter.localizedAdditionalDescription - cell.progressView.setProgress(Float(downloadTask.totalBytesWritten) / Float(book.fileSize), animated: true) + cell.progressView.setProgress(Float(downloadTask.totalBytesWritten) / Float(book.fileSize), animated: animated) + } + + // MARK: - Table view delegate + + 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 + Network.shared.cancel(bookID: book.id) + } + return [ + cancel + ] } // MARK: - NSFetchedResultsController diff --git a/Kiwix-iOS/Controller/Others/CoreDataTableBaseController.swift b/Kiwix-iOS/Controller/Others/CoreDataTableBaseController.swift index cf36fb70..b8e2f027 100644 --- a/Kiwix-iOS/Controller/Others/CoreDataTableBaseController.swift +++ b/Kiwix-iOS/Controller/Others/CoreDataTableBaseController.swift @@ -20,7 +20,7 @@ import CoreData class CoreDataTableBaseController: UIViewController, NSFetchedResultsControllerDelegate { @IBOutlet weak var tableView: UITableView! - func configureCell(_ cell: UITableViewCell, atIndexPath indexPath: IndexPath) { + func configureCell(_ cell: UITableViewCell, atIndexPath indexPath: IndexPath, animated: Bool = false) { } @@ -49,7 +49,7 @@ class CoreDataTableBaseController: UIViewController, NSFetchedResultsControllerD tableView.deleteRows(at: [indexPath], with: .fade) case .update: guard let indexPath = indexPath, let cell = tableView.cellForRow(at: indexPath) else {return} - configureCell(cell, atIndexPath: indexPath) + configureCell(cell, atIndexPath: indexPath, animated: true) case .move: guard let indexPath = indexPath, let newIndexPath = newIndexPath else {return} tableView.deleteRows(at: [indexPath], with: .fade) diff --git a/Kiwix-iOS/Controller/Search/SearchScopeAndHistoryController.swift b/Kiwix-iOS/Controller/Search/SearchScopeAndHistoryController.swift index 70b0bf46..eb5f0149 100644 --- a/Kiwix-iOS/Controller/Search/SearchScopeAndHistoryController.swift +++ b/Kiwix-iOS/Controller/Search/SearchScopeAndHistoryController.swift @@ -64,7 +64,7 @@ class SearchScopeAndHistoryController: SearchBaseTableController, UITableViewDel return cell } - override func configureCell(_ cell: UITableViewCell, atIndexPath indexPath: IndexPath) { + override func configureCell(_ cell: UITableViewCell, atIndexPath indexPath: IndexPath, animated: Bool = false) { guard let cell = cell as? CheckMarkBookCell else {return} let book = fetchedResultController.object(at: indexPath) diff --git a/Kiwix-iOS/Storyboard/Library.storyboard b/Kiwix-iOS/Storyboard/Library.storyboard index 79aaa041..af9329b0 100644 --- a/Kiwix-iOS/Storyboard/Library.storyboard +++ b/Kiwix-iOS/Storyboard/Library.storyboard @@ -315,7 +315,7 @@ - + diff --git a/Kiwix/Network/Network.swift b/Kiwix/Network/Network.swift index debd8e03..c0d7814d 100644 --- a/Kiwix/Network/Network.swift +++ b/Kiwix/Network/Network.swift @@ -45,7 +45,53 @@ class Network: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionD if progresses.count == 1 { startTimer() } } - func startTimer() { + func pause(bookID: String) { + cancelTask(in: wifiSession, taskDescription: bookID, producingResumingData: true) + cancelTask(in: cellularSession, taskDescription: bookID, producingResumingData: true) + } + + func cancel(bookID: String) { + cancelTask(in: wifiSession, taskDescription: bookID, producingResumingData: false) + cancelTask(in: cellularSession, taskDescription: bookID, producingResumingData: false) + } + + 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) + } + } else { + updateCoreData(bookID: taskDescription) + } + } + } + + private func startTimer() { timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { (timer) in self.managedObjectContext.perform({ for (bookID, bytesWritten) in self.progresses { diff --git a/Kiwix/Operations/UIProcedure.swift b/Kiwix/Operations/UIProcedure.swift index 982127ba..6d68ee3a 100644 --- a/Kiwix/Operations/UIProcedure.swift +++ b/Kiwix/Operations/UIProcedure.swift @@ -49,7 +49,7 @@ extension AlertProcedure { let alert = AlertProcedure(presentAlertFrom: context) alert.title = Localized.Setting.Feedback.Success.title alert.message = Localized.Setting.Feedback.Success.message - alert.add(actionWithTitle: Localized.Alert.ok, style: .default) + alert.add(actionWithTitle: Localized.Common.ok, style: .default) return alert } @@ -57,7 +57,7 @@ extension AlertProcedure { let alert = AlertProcedure(presentAlertFrom: context) alert.title = Localized.Setting.Feedback.NotConfiguredError.title alert.message = Localized.Setting.Feedback.NotConfiguredError.message - alert.add(actionWithTitle: Localized.Alert.ok, style: .cancel) + alert.add(actionWithTitle: Localized.Common.ok, style: .cancel) return alert } @@ -65,7 +65,7 @@ extension AlertProcedure { let alert = AlertProcedure(presentAlertFrom: context) alert.title = Localized.Setting.Feedback.ComposerError.title alert.message = message - alert.add(actionWithTitle: Localized.Alert.ok, style: .cancel) + alert.add(actionWithTitle: Localized.Common.ok, style: .cancel) return alert } } @@ -83,7 +83,7 @@ extension AlertProcedure { // clear launch history }) } - alert.add(actionWithTitle: Localized.Alert.cancel, style: .cancel) + alert.add(actionWithTitle: Localized.Common.cancel, style: .cancel) return alert } @@ -99,7 +99,7 @@ extension AlertProcedure { UIPasteboard.general.string = url.absoluteString alert.finish() } - alert.add(actionWithTitle: Localized.Alert.cancel, style: .cancel) { _ in alert.finish() } + alert.add(actionWithTitle: Localized.Common.cancel, style: .cancel) { _ in alert.finish() } return alert } } diff --git a/Kiwix/Tools/StringTools.swift b/Kiwix/Tools/StringTools.swift index 559a917c..05bcedd3 100644 --- a/Kiwix/Tools/StringTools.swift +++ b/Kiwix/Tools/StringTools.swift @@ -70,7 +70,7 @@ class LocalizedStrings { } class Localized { - class Alert { + class Common { static let ok = NSLocalizedString("OK", comment: "Alert action") static let cancel = NSLocalizedString("Cancel", comment: "Alert action") }