mirror of
https://github.com/kiwix/kiwix-apple.git
synced 2025-09-27 13:59:04 -04:00
Refactor
This commit is contained in:
parent
c0443cd506
commit
f3d16e7add
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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"/>
|
||||
|
@ -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 */,
|
||||
|
Loading…
x
Reference in New Issue
Block a user