This commit is contained in:
Chris Li 2017-01-17 13:27:05 -05:00
parent c0443cd506
commit f3d16e7add
6 changed files with 352 additions and 374 deletions

View File

@ -12,7 +12,7 @@ import JavaScriptCore
class JS {
class func inject(webView: UIWebView) {
guard let url = Bundle.main.url(forResource: "injection", withExtension: "js"),
guard let url = Bundle.main.url(forResource: "JSInject", withExtension: "js"),
let jString = try? String(contentsOf: url) else {return}
webView.stringByEvaluatingJavaScript(from: jString)
}

View File

@ -7,7 +7,9 @@
//
import UIKit
import WebKit
import SafariServices
import CoreSpotlight
import CloudKit
class MainController: UIViewController {
@ -70,5 +72,347 @@ class MainController: UIViewController {
tableOfContentsController?.delegate = self
}
}
}
// MARK: - Web
extension MainController: UIWebViewDelegate, SFSafariViewControllerDelegate {
func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
guard let url = request.url else {return false}
if url.isKiwixURL {
return true
} else if url.scheme == "pagescroll" {
let components = URLComponents(string: url.absoluteString)
guard let query = components?.queryItems,
let startStr = query[0].value, let start = Int(startStr),
let lengthStr = query[1].value, let length = Int(lengthStr) else {
return false
}
tableOfContentsController?.visibleRange = (start, length)
return false
} else {
let controller = SFSafariViewController(url: url)
controller.delegate = self
present(controller, animated: true, completion: nil)
return false
}
}
func webViewDidStartLoad(_ webView: UIWebView) {
URLResponseCache.shared.start()
}
func webViewDidFinishLoad(_ webView: UIWebView) {
JS.inject(webView: webView)
JS.preventDefaultLongTap(webView: webView)
tableOfContentsController?.headings = JS.getTableOfContents(webView: webView)
JS.startTOCCallBack(webView: webView)
URLResponseCache.shared.stop()
guard let url = webView.request?.url,
let article = Article.fetch(url: url, context: AppDelegate.persistentContainer.viewContext) else {return}
buttons.back.tintColor = webView.canGoBack ? nil : UIColor.gray
buttons.forward.tintColor = webView.canGoForward ? nil : UIColor.gray
buttons.bookmark.isHighlighted = article.isBookmarked
guard let title = JS.getTitle(from: webView) else {return}
searchBar.title = title
article.title = title
article.snippet = JS.getSnippet(from: webView)
article.bookmarkDate = Date()
article.thumbImagePath = URLResponseCache.shared.firstImage()?.path
}
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
}
}
// MARK: - Search
extension MainController: SearchBarDelegate, SearchContainerDelegate {
func didBecomeFirstResponder(searchBar: SearchBar) {
showSearch(animated: true)
}
func didResignFirstResponder(searchBar: SearchBar) {
hideSearch(animated: true)
}
func textDidChange(text: String, searchBar: SearchBar) {
controllers.search.searchText = text
}
func shouldReturn(searchBar: SearchBar) -> Bool {
let controller = controllers.search.resultController!
controller.selectFirstResult()
return controller.searchResults.count > 0
}
private func showSearch(animated: Bool) {
let controller = controllers.search
controller.delegate = self
guard !childViewControllers.contains(controller) else {return}
// hide toolbar
// add cancel button
if traitCollection.horizontalSizeClass == .compact {
navigationController?.setToolbarHidden(true, animated: animated)
navigationItem.setRightBarButton(buttons.cancel, animated: animated)
}
// manage view hierarchy
addChildViewController(controller)
controller.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(controller.view)
let views = ["view": controller.view]
view.addConstraints(NSLayoutConstraint.constraints(
withVisualFormat: "H:|[view]|", options: .alignAllCenterY, metrics: nil, views: views))
view.addConstraint(controller.view.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor))
view.addConstraint(controller.view.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor))
if animated {
controller.view.alpha = 0.5
UIView.animate(withDuration: 0.15, delay: 0.0, options: .curveEaseOut, animations: { () -> Void in
controller.view.alpha = 1.0
}, completion: nil)
} else {
controller.view.alpha = 1.0
}
controller.didMove(toParentViewController: self)
}
private func hideSearch(animated: Bool) {
guard let searchController = childViewControllers.flatMap({$0 as? SearchContainer}).first else {return}
// show toolbar
// remove cancel button
if traitCollection.horizontalSizeClass == .compact {
navigationController?.setToolbarHidden(false, animated: animated)
navigationItem.setRightBarButton(nil, animated: animated)
}
let completion = { (complete: Bool) -> Void in
guard complete else {return}
searchController.view.removeFromSuperview()
searchController.removeFromParentViewController()
guard self.traitCollection.horizontalSizeClass == .compact else {return}
self.navigationController?.setToolbarHidden(false, animated: animated)
}
searchController.willMove(toParentViewController: nil)
if animated {
UIView.animate(withDuration: 0.15, delay: 0.0, options: .beginFromCurrentState, animations: {
searchController.view.alpha = 0.0
}, completion: completion)
} else {
completion(true)
}
}
func didTapSearchDimView() {
_ = searchBar.resignFirstResponder()
}
}
// MARK: - Button Delegates
extension MainController: ButtonDelegates {
func didTapBackButton() {
webView.goBack()
}
func didTapForwardButton() {
webView.goForward()
}
func didTapTOCButton() {
isShowingTableOfContents ? hideTableOfContents(animated: true) : showTableOfContents(animated: true)
}
func didTapBookmarkButton() {
showBookmarkController()
}
func didTapLibraryButton() {
present(controllers.library, animated: true, completion: nil)
}
func didTapCancelButton() {
_ = searchBar.resignFirstResponder()
}
func didLongPressBackButton() {
}
func didLongPressForwardButton() {
}
func didLongPressBookmarkButton() {
func indexCoreSpotlight(article: Article) {
if article.isBookmarked {
CSSearchableIndex.default().indexSearchableItems([article.searchableItem], completionHandler: nil)
} else {
guard let url = article.url else {return}
CSSearchableIndex.default().deleteSearchableItems(withIdentifiers: [url.absoluteString], completionHandler: nil)
}
}
let context = AppDelegate.persistentContainer.viewContext
guard let url = webView.request?.url,
let article = Article.fetch(url: url, context: context) else {return}
article.isBookmarked = !article.isBookmarked
if article.isBookmarked {article.bookmarkDate = Date()}
if context.hasChanges {try? context.save()}
showBookmarkHUD()
controllers.bookmarkHUD.bookmarkAdded = article.isBookmarked
buttons.bookmark.isHighlighted = article.isBookmarked
indexCoreSpotlight(article: article)
// let operation = BookmarkSyncOperation(articleURL: url)
// GlobalQueue.shared.add(operation: operation)
}
}
// MARK: - Table Of Content
extension MainController: TableOfContentsDelegate {
func showTableOfContents(animated: Bool) {
guard welcomeController == nil else {return}
isShowingTableOfContents = true
tocVisiualEffectView.isHidden = false
dimView.isHidden = false
dimView.alpha = 0.0
view.layoutIfNeeded()
//configureTableOfContents()
configureTOCConstraints()
if animated {
UIView.animate(withDuration: 0.3, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
self.dimView.alpha = 0.5
}) { (completed) in }
} else {
view.layoutIfNeeded()
dimView.alpha = 0.5
}
}
func hideTableOfContents(animated: Bool) {
isShowingTableOfContents = false
view.layoutIfNeeded()
configureTOCConstraints()
if animated {
UIView.animate(withDuration: 0.2, delay: 0.0, options: .curveEaseIn, animations: {
self.view.layoutIfNeeded()
self.dimView.alpha = 0.0
}) { (completed) in
self.dimView.isHidden = true
self.tocVisiualEffectView.isHidden = true
}
} else {
view.layoutIfNeeded()
dimView.alpha = 0.0
dimView.isHidden = true
tocVisiualEffectView.isHidden = true
}
}
func configureTOCConstraints() {
switch traitCollection.horizontalSizeClass {
case .compact:
let toolBarHeight: CGFloat = traitCollection.horizontalSizeClass == .regular ? 0.0 : (traitCollection.verticalSizeClass == .compact ? 32.0 : 44.0)
let tocHeight: CGFloat = {
guard let controller = tableOfContentsController else {return floor(view.frame.height * 0.4)}
let tocContentHeight = controller.tableView.contentSize.height
guard controller.headings.count != 0 else {return floor(view.frame.height * 0.4)}
return min(tocContentHeight, floor(view.frame.height * 0.65))
}()
tocHeightConstraint.constant = tocHeight
tocTopToSuperViewBottomSpacing.constant = isShowingTableOfContents ? tocHeight + toolBarHeight + 10 : 0.0
case .regular:
tocLeadSpacing.constant = isShowingTableOfContents ? 0.0 : 270
default:
break
}
}
func didSelectHeading(index: Int) {
JS.scrollToHeading(webView: webView, index: index)
if traitCollection.horizontalSizeClass == .compact {
hideTableOfContents(animated: true)
}
}
@IBAction func didTapTOCDimView(_ sender: UITapGestureRecognizer) {
hideTableOfContents(animated: true)
}
}
// MARK: - Welcome
extension MainController {
func showWelcome() {
let controller = controllers.welcome
controller.view.translatesAutoresizingMaskIntoConstraints = false
addChildViewController(controller)
view.insertSubview(controller.view, aboveSubview: webView)
let views = ["view": controller.view]
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[view]|", options: .alignAllTop, metrics: nil, views: views))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[view]|", options: .alignAllLeft, metrics: nil, views: views))
controller.didMove(toParentViewController: self)
}
func hideWelcome() {
guard let controller = welcomeController else {return}
controller.removeFromParentViewController()
controller.view.removeFromSuperview()
}
var welcomeController: WelcomeController? {
return childViewControllers.flatMap({$0 as? WelcomeController}).first
}
}
// MARK: - Bookmark
extension MainController: UIViewControllerTransitioningDelegate {
func showBookmarkController() {
let controller = controllers.bookmark
controller.modalPresentationStyle = .fullScreen
present(controller, animated: true, completion: nil)
}
func showBookmarkHUD() {
let controller = controllers.bookmarkHUD
controller.bookmarkAdded = !controller.bookmarkAdded
controller.transitioningDelegate = self
controller.modalPresentationStyle = .overFullScreen
present(controller, animated: true, completion: nil)
}
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return BookmarkHUDAnimator(animateIn: true)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return BookmarkHUDAnimator(animateIn: false)
}
}
// MARK: - SFSafariViewControllerDelegate
extension MainController {
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
controller.dismiss(animated: true, completion: nil)
}
}

View File

@ -1,354 +0,0 @@
//
// MainControllerDelegates.swift
// Kiwix
//
// Created by Chris Li on 11/14/16.
// Copyright © 2016 Chris Li. All rights reserved.
//
import UIKit
import SafariServices
import CoreSpotlight
import CloudKit
// MARK: - Web
extension MainController: UIWebViewDelegate, SFSafariViewControllerDelegate {
func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
guard let url = request.url else {return false}
if url.isKiwixURL {
return true
} else if url.scheme == "pagescroll" {
let components = URLComponents(string: url.absoluteString)
guard let query = components?.queryItems,
let startStr = query[0].value, let start = Int(startStr),
let lengthStr = query[1].value, let length = Int(lengthStr) else {
return false
}
tableOfContentsController?.visibleRange = (start, length)
return false
} else {
let controller = SFSafariViewController(url: url)
controller.delegate = self
present(controller, animated: true, completion: nil)
return false
}
}
func webViewDidStartLoad(_ webView: UIWebView) {
URLResponseCache.shared.start()
}
func webViewDidFinishLoad(_ webView: UIWebView) {
JS.inject(webView: webView)
JS.preventDefaultLongTap(webView: webView)
tableOfContentsController?.headings = JS.getTableOfContents(webView: webView)
JS.startTOCCallBack(webView: webView)
URLResponseCache.shared.stop()
guard let url = webView.request?.url,
let article = Article.fetch(url: url, context: AppDelegate.persistentContainer.viewContext) else {return}
buttons.back.tintColor = webView.canGoBack ? nil : UIColor.gray
buttons.forward.tintColor = webView.canGoForward ? nil : UIColor.gray
buttons.bookmark.isHighlighted = article.isBookmarked
guard let title = JS.getTitle(from: webView) else {return}
searchBar.title = title
article.title = title
article.snippet = JS.getSnippet(from: webView)
article.bookmarkDate = Date()
article.thumbImagePath = URLResponseCache.shared.firstImage()?.path
}
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
}
}
// MARK: - Search
extension MainController: SearchBarDelegate, SearchContainerDelegate {
func didBecomeFirstResponder(searchBar: SearchBar) {
showSearch(animated: true)
}
func didResignFirstResponder(searchBar: SearchBar) {
hideSearch(animated: true)
}
func textDidChange(text: String, searchBar: SearchBar) {
controllers.search.searchText = text
}
func shouldReturn(searchBar: SearchBar) -> Bool {
let controller = controllers.search.resultController!
controller.selectFirstResult()
return controller.searchResults.count > 0
}
private func showSearch(animated: Bool) {
let controller = controllers.search
controller.delegate = self
guard !childViewControllers.contains(controller) else {return}
// hide toolbar
// add cancel button
if traitCollection.horizontalSizeClass == .compact {
navigationController?.setToolbarHidden(true, animated: animated)
navigationItem.setRightBarButton(buttons.cancel, animated: animated)
}
// manage view hierarchy
addChildViewController(controller)
controller.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(controller.view)
let views = ["view": controller.view]
view.addConstraints(NSLayoutConstraint.constraints(
withVisualFormat: "H:|[view]|", options: .alignAllCenterY, metrics: nil, views: views))
view.addConstraint(controller.view.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor))
view.addConstraint(controller.view.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor))
if animated {
controller.view.alpha = 0.5
UIView.animate(withDuration: 0.15, delay: 0.0, options: .curveEaseOut, animations: { () -> Void in
controller.view.alpha = 1.0
}, completion: nil)
} else {
controller.view.alpha = 1.0
}
controller.didMove(toParentViewController: self)
}
private func hideSearch(animated: Bool) {
guard let searchController = childViewControllers.flatMap({$0 as? SearchContainer}).first else {return}
// show toolbar
// remove cancel button
if traitCollection.horizontalSizeClass == .compact {
navigationController?.setToolbarHidden(false, animated: animated)
navigationItem.setRightBarButton(nil, animated: animated)
}
let completion = { (complete: Bool) -> Void in
guard complete else {return}
searchController.view.removeFromSuperview()
searchController.removeFromParentViewController()
guard self.traitCollection.horizontalSizeClass == .compact else {return}
self.navigationController?.setToolbarHidden(false, animated: animated)
}
searchController.willMove(toParentViewController: nil)
if animated {
UIView.animate(withDuration: 0.15, delay: 0.0, options: .beginFromCurrentState, animations: {
searchController.view.alpha = 0.0
}, completion: completion)
} else {
completion(true)
}
}
func didTapSearchDimView() {
_ = searchBar.resignFirstResponder()
}
}
// MARK: - Button Delegates
extension MainController: ButtonDelegates {
func didTapBackButton() {
webView.goBack()
}
func didTapForwardButton() {
webView.goForward()
}
func didTapTOCButton() {
isShowingTableOfContents ? hideTableOfContents(animated: true) : showTableOfContents(animated: true)
}
func didTapBookmarkButton() {
showBookmarkController()
}
func didTapLibraryButton() {
present(controllers.library, animated: true, completion: nil)
}
func didTapCancelButton() {
_ = searchBar.resignFirstResponder()
}
func didLongPressBackButton() {
}
func didLongPressForwardButton() {
}
func didLongPressBookmarkButton() {
func indexCoreSpotlight(article: Article) {
if article.isBookmarked {
CSSearchableIndex.default().indexSearchableItems([article.searchableItem], completionHandler: nil)
} else {
guard let url = article.url else {return}
CSSearchableIndex.default().deleteSearchableItems(withIdentifiers: [url.absoluteString], completionHandler: nil)
}
}
let context = AppDelegate.persistentContainer.viewContext
guard let url = webView.request?.url,
let article = Article.fetch(url: url, context: context) else {return}
article.isBookmarked = !article.isBookmarked
if article.isBookmarked {article.bookmarkDate = Date()}
if context.hasChanges {try? context.save()}
showBookmarkHUD()
controllers.bookmarkHUD.bookmarkAdded = article.isBookmarked
buttons.bookmark.isHighlighted = article.isBookmarked
indexCoreSpotlight(article: article)
// let operation = BookmarkSyncOperation(articleURL: url)
// GlobalQueue.shared.add(operation: operation)
}
}
// MARK: - Table Of Content
extension MainController: TableOfContentsDelegate {
func showTableOfContents(animated: Bool) {
guard welcomeController == nil else {return}
isShowingTableOfContents = true
tocVisiualEffectView.isHidden = false
dimView.isHidden = false
dimView.alpha = 0.0
view.layoutIfNeeded()
//configureTableOfContents()
configureTOCConstraints()
if animated {
UIView.animate(withDuration: 0.3, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
self.dimView.alpha = 0.5
}) { (completed) in }
} else {
view.layoutIfNeeded()
dimView.alpha = 0.5
}
}
func hideTableOfContents(animated: Bool) {
isShowingTableOfContents = false
view.layoutIfNeeded()
configureTOCConstraints()
if animated {
UIView.animate(withDuration: 0.2, delay: 0.0, options: .curveEaseIn, animations: {
self.view.layoutIfNeeded()
self.dimView.alpha = 0.0
}) { (completed) in
self.dimView.isHidden = true
self.tocVisiualEffectView.isHidden = true
}
} else {
view.layoutIfNeeded()
dimView.alpha = 0.0
dimView.isHidden = true
tocVisiualEffectView.isHidden = true
}
}
func configureTOCConstraints() {
switch traitCollection.horizontalSizeClass {
case .compact:
let toolBarHeight: CGFloat = traitCollection.horizontalSizeClass == .regular ? 0.0 : (traitCollection.verticalSizeClass == .compact ? 32.0 : 44.0)
let tocHeight: CGFloat = {
guard let controller = tableOfContentsController else {return floor(view.frame.height * 0.4)}
let tocContentHeight = controller.tableView.contentSize.height
guard controller.headings.count != 0 else {return floor(view.frame.height * 0.4)}
return min(tocContentHeight, floor(view.frame.height * 0.65))
}()
tocHeightConstraint.constant = tocHeight
tocTopToSuperViewBottomSpacing.constant = isShowingTableOfContents ? tocHeight + toolBarHeight + 10 : 0.0
case .regular:
tocLeadSpacing.constant = isShowingTableOfContents ? 0.0 : 270
default:
break
}
}
func didSelectHeading(index: Int) {
JS.scrollToHeading(webView: webView, index: index)
if traitCollection.horizontalSizeClass == .compact {
hideTableOfContents(animated: true)
}
}
@IBAction func didTapTOCDimView(_ sender: UITapGestureRecognizer) {
hideTableOfContents(animated: true)
}
}
// MARK: - Welcome
extension MainController {
func showWelcome() {
let controller = controllers.welcome
controller.view.translatesAutoresizingMaskIntoConstraints = false
addChildViewController(controller)
view.insertSubview(controller.view, aboveSubview: webView)
let views = ["view": controller.view]
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[view]|", options: .alignAllTop, metrics: nil, views: views))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[view]|", options: .alignAllLeft, metrics: nil, views: views))
controller.didMove(toParentViewController: self)
}
func hideWelcome() {
guard let controller = welcomeController else {return}
controller.removeFromParentViewController()
controller.view.removeFromSuperview()
}
var welcomeController: WelcomeController? {
return childViewControllers.flatMap({$0 as? WelcomeController}).first
}
}
// MARK: - Bookmark
extension MainController: UIViewControllerTransitioningDelegate {
func showBookmarkController() {
let controller = controllers.bookmark
controller.modalPresentationStyle = .fullScreen
present(controller, animated: true, completion: nil)
}
func showBookmarkHUD() {
let controller = controllers.bookmarkHUD
controller.bookmarkAdded = !controller.bookmarkAdded
controller.transitioningDelegate = self
controller.modalPresentationStyle = .overFullScreen
present(controller, animated: true, completion: nil)
}
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return BookmarkHUDAnimator(animateIn: true)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return BookmarkHUDAnimator(animateIn: false)
}
}
// MARK: - SFSafariViewControllerDelegate
extension MainController {
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
controller.dismiss(animated: true, completion: nil)
}
}

View File

@ -48,7 +48,7 @@
<constraint firstAttribute="width" constant="32" id="aFo-L8-O71"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="justified" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LK0-aY-C9L">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="justified" lineBreakMode="clip" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LK0-aY-C9L">
<rect key="frame" x="8" y="31" width="191" height="17"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<nil key="textColor"/>

View File

@ -58,7 +58,6 @@
973DD4191D343F2F009D45DB /* libzim.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 973DD40E1D343F2F009D45DB /* libzim.a */; };
973DD4281D36E3E4009D45DB /* SettingDetailController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 973DD4271D36E3E4009D45DB /* SettingDetailController.swift */; };
974000151DB008C6009A740D /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9788419C1DA2FF2A00D22D3C /* MainInterface.storyboard */; };
974C49661DA307FF00E276E1 /* injection.js in Resources */ = {isa = PBXBuildFile; fileRef = 974C49621DA307FF00E276E1 /* injection.js */; };
974C49681DA4266200E276E1 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 974C49671DA4266200E276E1 /* CloudKit.framework */; };
975227CD1D0227E8001D1DDE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 975227CA1D0227E8001D1DDE /* Main.storyboard */; };
975227CE1D0227E8001D1DDE /* Setting.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 975227CB1D0227E8001D1DDE /* Setting.storyboard */; };
@ -95,6 +94,7 @@
97A1FD421D6F728200A80EE2 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A1FD3D1D6F728200A80EE2 /* Extensions.swift */; };
97A1FD441D6F728200A80EE2 /* Preference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A1FD401D6F728200A80EE2 /* Preference.swift */; };
97A1FD451D6F728200A80EE2 /* StringTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A1FD411D6F728200A80EE2 /* StringTools.swift */; };
97A9F6F51E2E990500F423AA /* JSInject.js in Resources */ = {isa = PBXBuildFile; fileRef = 97A9F6F41E2E990500F423AA /* JSInject.js */; };
97BC0FBF1DD90A65004BBAD1 /* JSInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97BC0FBD1DD90A65004BBAD1 /* JSInjection.swift */; };
97BC0FC01DD90A65004BBAD1 /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97BC0FBE1DD90A65004BBAD1 /* MainController.swift */; };
97BC0FC21DD92B62004BBAD1 /* Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97BC0FC11DD92B62004BBAD1 /* Buttons.swift */; };
@ -102,7 +102,6 @@
97C2C26A1DDCC58500A9CC64 /* ArticleOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9764CBD21D8083AA00072D6A /* ArticleOperation.swift */; };
97C601DC1D7F15C400362D4F /* Bookmark.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C601DB1D7F15C400362D4F /* Bookmark.storyboard */; };
97C601DE1D7F342100362D4F /* HTMLHeading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97C601DD1D7F342100362D4F /* HTMLHeading.swift */; };
97D0E98F1DDA12B30029530E /* MainDelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D0E98E1DDA12B30029530E /* MainDelegates.swift */; };
97D0E9931DDA487E0029530E /* SearchBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D0E9921DDA487E0029530E /* SearchBaseController.swift */; };
97D681311D6F70EC00E5FA99 /* 1.5.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = 97D6812F1D6F70EC00E5FA99 /* 1.5.xcmappingmodel */; };
97D681321D6F70EC00E5FA99 /* MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D681301D6F70EC00E5FA99 /* MigrationPolicy.swift */; };
@ -218,7 +217,6 @@
973DD40D1D343F2F009D45DB /* libxapian.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libxapian.a; path = Kiwix/libkiwix/iOS/libxapian.a; sourceTree = "<group>"; };
973DD40E1D343F2F009D45DB /* libzim.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libzim.a; path = Kiwix/libkiwix/iOS/libzim.a; sourceTree = "<group>"; };
973DD4271D36E3E4009D45DB /* SettingDetailController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SettingDetailController.swift; path = "Kiwix-iOS/Controller/Setting/SettingDetailController.swift"; sourceTree = SOURCE_ROOT; };
974C49621DA307FF00E276E1 /* injection.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = injection.js; sourceTree = "<group>"; };
974C49671DA4266200E276E1 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; };
975227CA1D0227E8001D1DDE /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = "Kiwix-iOS/Storyboard/Main.storyboard"; sourceTree = SOURCE_ROOT; };
975227CB1D0227E8001D1DDE /* Setting.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Setting.storyboard; path = "Kiwix-iOS/Storyboard/Setting.storyboard"; sourceTree = SOURCE_ROOT; };
@ -267,6 +265,7 @@
97A2ABAA1C1B810000052E74 /* Kiwix-iOSUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Kiwix-iOSUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
97A8AD831D6C951A00584ED1 /* LocalBooksController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalBooksController.swift; sourceTree = "<group>"; };
97A8AD861D6CF38000584ED1 /* EmptyTableConfigExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyTableConfigExtension.swift; sourceTree = "<group>"; };
97A9F6F41E2E990500F423AA /* JSInject.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = JSInject.js; sourceTree = "<group>"; };
97BC0FBD1DD90A65004BBAD1 /* JSInjection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSInjection.swift; sourceTree = "<group>"; };
97BC0FBE1DD90A65004BBAD1 /* MainController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainController.swift; sourceTree = "<group>"; };
97BC0FC11DD92B62004BBAD1 /* Buttons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Buttons.swift; sourceTree = "<group>"; };
@ -276,7 +275,6 @@
97C5BD4A1D9AF4B5009692CF /* BookmarkController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkController.swift; sourceTree = "<group>"; };
97C601DB1D7F15C400362D4F /* Bookmark.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Bookmark.storyboard; sourceTree = "<group>"; };
97C601DD1D7F342100362D4F /* HTMLHeading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTMLHeading.swift; sourceTree = "<group>"; };
97D0E98E1DDA12B30029530E /* MainDelegates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainDelegates.swift; sourceTree = "<group>"; };
97D0E9921DDA487E0029530E /* SearchBaseController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchBaseController.swift; sourceTree = "<group>"; };
97D4D64E1D874E6E00C1B065 /* SearchOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchOperation.swift; sourceTree = "<group>"; };
97D6811A1D6E2A7100E5FA99 /* DownloadTasksController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadTasksController.swift; sourceTree = "<group>"; };
@ -474,7 +472,6 @@
isa = PBXGroup;
children = (
97BC0FBE1DD90A65004BBAD1 /* MainController.swift */,
97D0E98E1DDA12B30029530E /* MainDelegates.swift */,
97BC0FC11DD92B62004BBAD1 /* Buttons.swift */,
97BC0FBD1DD90A65004BBAD1 /* JSInjection.swift */,
972F81581DDC1B71008D7289 /* Controllers.swift */,
@ -522,7 +519,6 @@
977A458A1E14E98F0089C596 /* Cloud */,
9711872D1CEB507600B9909D /* CoreData */,
97163D321CD7E79F008BE2D6 /* Help Docs */,
974C495E1DA307FF00E276E1 /* JavaScripts */,
971187051CEB426E00B9909D /* libkiwix */,
97DF259E1D6F9942001648A3 /* Network */,
97E5712A1CA0525300FF4F1D /* Operation */,
@ -558,14 +554,6 @@
path = Kiwix;
sourceTree = "<group>";
};
974C495E1DA307FF00E276E1 /* JavaScripts */ = {
isa = PBXGroup;
children = (
974C49621DA307FF00E276E1 /* injection.js */,
);
path = JavaScripts;
sourceTree = "<group>";
};
975227A41D020C0F001D1DDE /* indexer */ = {
isa = PBXGroup;
children = (
@ -684,6 +672,7 @@
children = (
97A1FD3D1D6F728200A80EE2 /* Extensions.swift */,
97C601DD1D7F342100362D4F /* HTMLHeading.swift */,
97A9F6F41E2E990500F423AA /* JSInject.js */,
97A1FD401D6F728200A80EE2 /* Preference.swift */,
97A1FD411D6F728200A80EE2 /* StringTools.swift */,
);
@ -1000,6 +989,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97A9F6F51E2E990500F423AA /* JSInject.js in Resources */,
971A10811D022F74007FC62C /* Pic_P.png in Resources */,
975227D01D022814001D1DDE /* LaunchScreen.storyboard in Resources */,
97F03CE21D2440470040D26E /* Search.storyboard in Resources */,
@ -1007,7 +997,6 @@
971A10161D022872007FC62C /* Assets.xcassets in Resources */,
97E850CB1D2DA5B300A9F688 /* About.html in Resources */,
97C601DC1D7F15C400362D4F /* Bookmark.storyboard in Resources */,
974C49661DA307FF00E276E1 /* injection.js in Resources */,
975227CD1D0227E8001D1DDE /* Main.storyboard in Resources */,
975227CE1D0227E8001D1DDE /* Setting.storyboard in Resources */,
971A10801D022F74007FC62C /* Pic_I.png in Resources */,
@ -1104,7 +1093,6 @@
97A1FD161D6F71CE00A80EE2 /* DirectoryMonitor.swift in Sources */,
9726591D1D90A64600D1DFFB /* Notifications.swift in Sources */,
971A102C1D022AD5007FC62C /* BarButtonItems.swift in Sources */,
97D0E98F1DDA12B30029530E /* MainDelegates.swift in Sources */,
970A2A221DD562CB0078BB7C /* BookOperations.swift in Sources */,
97A1FD391D6F724E00A80EE2 /* pathTools.cpp in Sources */,
972F81591DDC1B71008D7289 /* Controllers.swift in Sources */,