mirror of
https://github.com/kiwix/kiwix-apple.git
synced 2025-09-24 04:03:03 -04:00
Cleaner logic in LibraryOnlineTBVC & LibRefreshOp
This commit is contained in:
parent
a6e03b6fec
commit
4fec367d75
@ -9,11 +9,11 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import CoreData
|
import CoreData
|
||||||
|
|
||||||
class LibraryOnlineTBVC: UITableViewController, NSFetchedResultsControllerDelegate, BookTableCellDelegate, LTBarButtonItemDelegate, RefreshLibraryOperationDelegate, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate {
|
class LibraryOnlineTBVC: UITableViewController, NSFetchedResultsControllerDelegate, BookTableCellDelegate, LTBarButtonItemDelegate, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate {
|
||||||
|
|
||||||
var booksShowingDetail = Set<Book>()
|
var booksShowingDetail = Set<Book>()
|
||||||
weak var refreshOperation: RefreshLibraryOperation?
|
|
||||||
var messsageLabelConfigTimer: NSTimer?
|
var messsageLabelConfigTimer: NSTimer?
|
||||||
|
var refreshing = false
|
||||||
|
|
||||||
// MARK: - Override
|
// MARK: - Override
|
||||||
|
|
||||||
@ -26,18 +26,20 @@ class LibraryOnlineTBVC: UITableViewController, NSFetchedResultsControllerDelega
|
|||||||
tableView.emptyDataSetSource = self
|
tableView.emptyDataSetSource = self
|
||||||
tableView.emptyDataSetDelegate = self
|
tableView.emptyDataSetDelegate = self
|
||||||
|
|
||||||
reconnectToExistingRefreshOperation()
|
|
||||||
refreshLibraryForTheFirstTime()
|
|
||||||
configureToolBar()
|
configureToolBar()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(animated: Bool) {
|
override func viewWillAppear(animated: Bool) {
|
||||||
super.viewWillAppear(animated)
|
super.viewWillAppear(animated)
|
||||||
segmentedControl.selectedSegmentIndex = 0
|
segmentedControl.selectedSegmentIndex = 0
|
||||||
configureRefreshStatus()
|
|
||||||
messsageLabelConfigTimer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: #selector(configureMessage), userInfo: nil, repeats: true)
|
messsageLabelConfigTimer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: #selector(configureMessage), userInfo: nil, repeats: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func viewDidAppear(animated: Bool) {
|
||||||
|
super.viewDidAppear(animated)
|
||||||
|
refreshLibraryForTheFirstTime()
|
||||||
|
}
|
||||||
|
|
||||||
override func viewWillDisappear(animated: Bool) {
|
override func viewWillDisappear(animated: Bool) {
|
||||||
super.viewWillDisappear(animated)
|
super.viewWillDisappear(animated)
|
||||||
messsageLabelConfigTimer?.invalidate()
|
messsageLabelConfigTimer?.invalidate()
|
||||||
@ -68,38 +70,40 @@ class LibraryOnlineTBVC: UITableViewController, NSFetchedResultsControllerDelega
|
|||||||
startRefresh(invokedAutomatically: false)
|
startRefresh(invokedAutomatically: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - RefreshLibraryOperationDelegate
|
|
||||||
|
|
||||||
func refreshDidStart() {
|
|
||||||
configureRefreshStatus()
|
|
||||||
configureToolBarVisibility(animated: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshDidFinish() {
|
|
||||||
configureRefreshStatus()
|
|
||||||
configureToolBarVisibility(animated: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Others
|
// MARK: - Others
|
||||||
|
|
||||||
func reconnectToExistingRefreshOperation() {
|
|
||||||
guard let operation = refreshOperation ??
|
|
||||||
UIApplication.globalOperationQueue.operation(String(RefreshLibraryOperation)) as? RefreshLibraryOperation
|
|
||||||
else {return}
|
|
||||||
refreshOperation = operation
|
|
||||||
operation.delegate = self
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshLibraryForTheFirstTime() {
|
func refreshLibraryForTheFirstTime() {
|
||||||
guard Preference.libraryLastRefreshTime == nil else {return}
|
guard Preference.libraryLastRefreshTime == nil else {return}
|
||||||
startRefresh(invokedAutomatically: true)
|
startRefresh(invokedAutomatically: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func startRefresh(invokedAutomatically invokedAutomatically: Bool) {
|
func startRefresh(invokedAutomatically invokedAutomatically: Bool) {
|
||||||
let refreshOperation = RefreshLibraryOperation(invokedAutomatically: invokedAutomatically)
|
let refreshOperation = RefreshLibraryOperation(invokedAutomatically: invokedAutomatically) { (errorCode) in
|
||||||
refreshOperation.delegate = self
|
defer {
|
||||||
|
NSOperationQueue.mainQueue().addOperationWithBlock({
|
||||||
|
self.refreshing = false
|
||||||
|
self.configureMessage()
|
||||||
|
self.configureRotatingStatus()
|
||||||
|
self.configureEmptyTableBackground()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if let errorCode = errorCode {
|
||||||
|
if errorCode == .NetworkError {
|
||||||
|
let alertOperation = RefreshLibraryInternetRequiredAlert(presentationContext: self)
|
||||||
|
UIApplication.appDelegate.globalOperationQueue.addOperation(alertOperation)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
guard !Preference.libraryHasShownPreferredLanguagePrompt else {return}
|
||||||
|
let operation = RefreshLibraryLanguageFilterAlert(libraryOnlineTBVC: self)
|
||||||
|
UIApplication.appDelegate.globalOperationQueue.addOperation(operation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshing = true
|
||||||
|
configureMessage()
|
||||||
|
configureRotatingStatus()
|
||||||
|
configureEmptyTableBackground()
|
||||||
UIApplication.globalOperationQueue.addOperation(refreshOperation)
|
UIApplication.globalOperationQueue.addOperation(refreshOperation)
|
||||||
self.refreshOperation = refreshOperation
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - ToolBar Button
|
// MARK: - ToolBar Button
|
||||||
@ -126,15 +130,13 @@ class LibraryOnlineTBVC: UITableViewController, NSFetchedResultsControllerDelega
|
|||||||
setToolbarItems(toolBarItems, animated: false)
|
setToolbarItems(toolBarItems, animated: false)
|
||||||
|
|
||||||
configureToolBarVisibility(animated: false)
|
configureToolBarVisibility(animated: false)
|
||||||
configureMessage(isRefreshing: false)
|
configureMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureToolBarVisibility(animated animated: Bool) {
|
func configureMessage() {
|
||||||
navigationController?.setToolbarHidden(fetchedResultController.fetchedObjects?.count == 0, animated: animated)
|
if refreshing {
|
||||||
}
|
messageButton.text = LocalizedStrings.refreshing
|
||||||
|
} else {
|
||||||
func configureMessage(isRefreshing isRefreshing: Bool = false) {
|
|
||||||
if !isRefreshing {
|
|
||||||
guard let sectionInfos = fetchedResultController.sections else {messageButton.text = nil; return}
|
guard let sectionInfos = fetchedResultController.sections else {messageButton.text = nil; return}
|
||||||
let count = sectionInfos.reduce(0) {$0 + $1.numberOfObjects}
|
let count = sectionInfos.reduce(0) {$0 + $1.numberOfObjects}
|
||||||
let localizedBookCountString = String.localizedStringWithFormat(NSLocalizedString("%d book(s) available for download", comment: "Book Library, online book catalogue message"), count)
|
let localizedBookCountString = String.localizedStringWithFormat(NSLocalizedString("%d book(s) available for download", comment: "Book Library, online book catalogue message"), count)
|
||||||
@ -150,15 +152,18 @@ class LibraryOnlineTBVC: UITableViewController, NSFetchedResultsControllerDelega
|
|||||||
return string
|
return string
|
||||||
}()
|
}()
|
||||||
messageButton.text = localizedBookCountString + "\n" + localizedRefreshTimeString
|
messageButton.text = localizedBookCountString + "\n" + localizedRefreshTimeString
|
||||||
} else {
|
|
||||||
messageButton.text = LocalizedStrings.refreshing
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureRefreshStatus() {
|
func configureToolBarVisibility(animated animated: Bool) {
|
||||||
let executing = refreshOperation?.executing ?? false
|
navigationController?.setToolbarHidden(fetchedResultController.fetchedObjects?.count == 0, animated: animated)
|
||||||
executing ? refreshLibButton.startRotating() : refreshLibButton.stopRotating()
|
}
|
||||||
configureMessage(isRefreshing: executing)
|
|
||||||
|
func configureRotatingStatus() {
|
||||||
|
refreshing ? refreshLibButton.startRotating() : refreshLibButton.stopRotating()
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureEmptyTableBackground() {
|
||||||
tableView.reloadEmptyDataSet()
|
tableView.reloadEmptyDataSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +192,7 @@ class LibraryOnlineTBVC: UITableViewController, NSFetchedResultsControllerDelega
|
|||||||
}
|
}
|
||||||
|
|
||||||
func buttonTitleForEmptyDataSet(scrollView: UIScrollView!, forState state: UIControlState) -> NSAttributedString! {
|
func buttonTitleForEmptyDataSet(scrollView: UIScrollView!, forState state: UIControlState) -> NSAttributedString! {
|
||||||
if let _ = refreshOperation {
|
if refreshing == true {
|
||||||
let text = NSLocalizedString("Refreshing...", comment: "Book Library, book downloader, refreshing button text")
|
let text = NSLocalizedString("Refreshing...", comment: "Book Library, book downloader, refreshing button text")
|
||||||
let attributes = [NSFontAttributeName: UIFont.boldSystemFontOfSize(17.0), NSForegroundColorAttributeName: UIColor.darkGrayColor()]
|
let attributes = [NSFontAttributeName: UIFont.boldSystemFontOfSize(17.0), NSForegroundColorAttributeName: UIColor.darkGrayColor()]
|
||||||
return NSAttributedString(string: text, attributes: attributes)
|
return NSAttributedString(string: text, attributes: attributes)
|
||||||
@ -207,7 +212,7 @@ class LibraryOnlineTBVC: UITableViewController, NSFetchedResultsControllerDelega
|
|||||||
}
|
}
|
||||||
|
|
||||||
func emptyDataSetDidTapButton(scrollView: UIScrollView!) {
|
func emptyDataSetDidTapButton(scrollView: UIScrollView!) {
|
||||||
guard self.refreshOperation == nil else {return}
|
guard !refreshing else {return}
|
||||||
startRefresh(invokedAutomatically: false)
|
startRefresh(invokedAutomatically: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +315,7 @@ class LibraryOnlineTBVC: UITableViewController, NSFetchedResultsControllerDelega
|
|||||||
fetchedResultController.fetchRequest.predicate = onlineCompoundPredicate
|
fetchedResultController.fetchRequest.predicate = onlineCompoundPredicate
|
||||||
fetchedResultController.performFetch(deleteCache: true)
|
fetchedResultController.performFetch(deleteCache: true)
|
||||||
tableView.reloadData()
|
tableView.reloadData()
|
||||||
configureMessage(isRefreshing: false)
|
configureMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var langPredicate: NSPredicate {
|
private var langPredicate: NSPredicate {
|
||||||
@ -360,5 +365,7 @@ class LibraryOnlineTBVC: UITableViewController, NSFetchedResultsControllerDelega
|
|||||||
|
|
||||||
func controllerDidChangeContent(controller: NSFetchedResultsController) {
|
func controllerDidChangeContent(controller: NSFetchedResultsController) {
|
||||||
tableView.endUpdates()
|
tableView.endUpdates()
|
||||||
|
configureToolBarVisibility(animated: true)
|
||||||
|
configureMessage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,21 +11,20 @@ import CoreData
|
|||||||
|
|
||||||
class RefreshLibraryOperation: GroupOperation {
|
class RefreshLibraryOperation: GroupOperation {
|
||||||
|
|
||||||
weak var delegate: RefreshLibraryOperationDelegate?
|
var completionHandler: ((errorCode: Int?) -> Void)?
|
||||||
weak var presentationContext: LibraryOnlineTBVC?
|
|
||||||
var completionHandler: (() -> Void)?
|
|
||||||
|
|
||||||
init(invokedAutomatically: Bool, presentationContext: LibraryOnlineTBVC? = nil, completionHandler: (() -> Void)? = nil) {
|
init(invokedAutomatically: Bool, completionHandler: ((errorCode: Int?) -> Void)?) {
|
||||||
super.init(operations: [])
|
super.init(operations: [])
|
||||||
|
|
||||||
name = String(RefreshLibraryOperation)
|
name = String(RefreshLibraryOperation)
|
||||||
|
self.completionHandler = completionHandler
|
||||||
|
|
||||||
// 1.Parse
|
// 1.Parse
|
||||||
let parseOperation = ParseLibraryOperation()
|
let parseOperation = ParseLibraryOperation()
|
||||||
|
|
||||||
// 0.Download library
|
// 0.Download library
|
||||||
let url = NSURL(string: "http://www.kiwix.org/library.xml")!
|
let url = NSURL(string: "http://www.kiwix.org/library.xml")!
|
||||||
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
|
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { [unowned parseOperation] (data, response, error) -> Void in
|
||||||
if let error = error {self.aggregateError(error)}
|
if let error = error {self.aggregateError(error)}
|
||||||
parseOperation.xmlData = data
|
parseOperation.xmlData = data
|
||||||
}
|
}
|
||||||
@ -33,24 +32,9 @@ class RefreshLibraryOperation: GroupOperation {
|
|||||||
fetchOperation.addObserver(NetworkObserver())
|
fetchOperation.addObserver(NetworkObserver())
|
||||||
fetchOperation.addCondition(ReachabilityCondition(host: url, allowCellular: Preference.libraryRefreshAllowCellularData))
|
fetchOperation.addCondition(ReachabilityCondition(host: url, allowCellular: Preference.libraryRefreshAllowCellularData))
|
||||||
|
|
||||||
let stateObserver = BlockObserver(
|
|
||||||
startHandler: { (operation) -> Void in
|
|
||||||
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
|
|
||||||
self.delegate?.refreshDidStart()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
produceHandler: nil) { (operation, errors) -> Void in
|
|
||||||
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
|
|
||||||
self.delegate?.refreshDidFinish()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
addObserver(stateObserver)
|
|
||||||
|
|
||||||
addCondition(MutuallyExclusive<RefreshLibraryOperation>())
|
|
||||||
if invokedAutomatically {
|
if invokedAutomatically {
|
||||||
addCondition(AllowAutoRefreshCondition())
|
addCondition(AllowAutoRefreshCondition())
|
||||||
addCondition(LibraryIsOldCondition())
|
addCondition(LibraryIsOldCondition())
|
||||||
addCondition(ReachabilityCondition(host: url, allowCellular: Preference.libraryRefreshAllowCellularData))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addOperation(fetchOperation)
|
addOperation(fetchOperation)
|
||||||
@ -59,22 +43,10 @@ class RefreshLibraryOperation: GroupOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func finished(errors: [NSError]) {
|
override func finished(errors: [NSError]) {
|
||||||
if let firstError = errors.first {
|
completionHandler?(errorCode: errors.first?.code)
|
||||||
if firstError.code == .NetworkError {
|
|
||||||
produceOperation(RefreshLibraryInternetRequiredAlert(presentationContext: presentationContext))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
guard !Preference.libraryHasShownPreferredLanguagePrompt else {return}
|
|
||||||
produceOperation(RefreshLibraryLanguageFilterAlert(libraryOnlineTBVC: presentationContext))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol RefreshLibraryOperationDelegate: class {
|
|
||||||
func refreshDidStart()
|
|
||||||
func refreshDidFinish()
|
|
||||||
}
|
|
||||||
|
|
||||||
class ParseLibraryOperation: Operation, NSXMLParserDelegate {
|
class ParseLibraryOperation: Operation, NSXMLParserDelegate {
|
||||||
var xmlData: NSData?
|
var xmlData: NSData?
|
||||||
let context: NSManagedObjectContext
|
let context: NSManagedObjectContext
|
||||||
@ -91,7 +63,7 @@ class ParseLibraryOperation: Operation, NSXMLParserDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func execute() {
|
override func execute() {
|
||||||
guard let data = xmlData else {return}
|
guard let data = xmlData else {finish(); return}
|
||||||
let xmlParser = NSXMLParser(data: data)
|
let xmlParser = NSXMLParser(data: data)
|
||||||
xmlParser.delegate = self
|
xmlParser.delegate = self
|
||||||
xmlParser.parse()
|
xmlParser.parse()
|
||||||
@ -106,7 +78,7 @@ class ParseLibraryOperation: Operation, NSXMLParserDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc internal func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, var attributes attributeDict: [String : String]) {
|
@objc internal func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
|
||||||
guard elementName == "book" else {return}
|
guard elementName == "book" else {return}
|
||||||
guard let id = attributeDict["id"] else {return}
|
guard let id = attributeDict["id"] else {return}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user