2019-04-15 22:03:05 +02:00
|
|
|
//
|
2019-09-24 11:29:15 +02:00
|
|
|
// ArticleViewController.swift
|
2019-04-15 22:03:05 +02:00
|
|
|
// NetNewsWire
|
|
|
|
//
|
|
|
|
// Created by Maurice Parker on 4/8/19.
|
|
|
|
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
import WebKit
|
|
|
|
import Account
|
|
|
|
import Articles
|
2019-04-21 13:41:59 +02:00
|
|
|
import SafariServices
|
2024-04-08 00:05:38 +02:00
|
|
|
import ArticleExtractor
|
2019-04-15 22:03:05 +02:00
|
|
|
|
2019-09-24 11:29:15 +02:00
|
|
|
class ArticleViewController: UIViewController {
|
2019-10-12 21:45:44 +02:00
|
|
|
|
2020-01-29 19:30:52 +01:00
|
|
|
typealias State = (extractedArticle: ExtractedArticle?,
|
|
|
|
isShowingExtractedArticle: Bool,
|
|
|
|
articleExtractorButtonState: ArticleExtractorButtonState,
|
|
|
|
windowScrollY: Int)
|
|
|
|
|
2019-08-31 21:30:01 +02:00
|
|
|
@IBOutlet private weak var nextUnreadBarButtonItem: UIBarButtonItem!
|
|
|
|
@IBOutlet private weak var prevArticleBarButtonItem: UIBarButtonItem!
|
|
|
|
@IBOutlet private weak var nextArticleBarButtonItem: UIBarButtonItem!
|
|
|
|
@IBOutlet private weak var readBarButtonItem: UIBarButtonItem!
|
|
|
|
@IBOutlet private weak var starBarButtonItem: UIBarButtonItem!
|
|
|
|
@IBOutlet private weak var actionBarButtonItem: UIBarButtonItem!
|
2020-01-01 00:55:39 +01:00
|
|
|
|
2020-05-11 22:08:01 +02:00
|
|
|
@IBOutlet private var searchBar: ArticleSearchBar!
|
2020-05-15 23:56:14 +02:00
|
|
|
@IBOutlet private var searchBarBottomConstraint: NSLayoutConstraint!
|
2020-05-11 22:08:01 +02:00
|
|
|
private var defaultControls: [UIBarButtonItem]?
|
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
private var pageViewController: UIPageViewController!
|
|
|
|
|
|
|
|
private var currentWebViewController: WebViewController? {
|
|
|
|
return pageViewController?.viewControllers?.first as? WebViewController
|
|
|
|
}
|
2019-11-18 03:20:50 +01:00
|
|
|
|
2019-09-27 21:09:28 +02:00
|
|
|
private var articleExtractorButton: ArticleExtractorButton = {
|
|
|
|
let button = ArticleExtractorButton(type: .system)
|
2019-09-28 00:32:13 +02:00
|
|
|
button.frame = CGRect(x: 0, y: 0, width: 44.0, height: 44.0)
|
2019-09-27 21:09:28 +02:00
|
|
|
button.setImage(AppAssets.articleExtractorOff, for: .normal)
|
|
|
|
return button
|
|
|
|
}()
|
|
|
|
|
2019-09-01 19:43:07 +02:00
|
|
|
weak var coordinator: SceneCoordinator!
|
2019-04-15 22:03:05 +02:00
|
|
|
|
2024-03-04 07:51:53 +01:00
|
|
|
private let poppableDelegate = PoppableGestureRecognizerDelegate()
|
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
var article: Article? {
|
2019-09-24 02:23:23 +02:00
|
|
|
didSet {
|
2020-01-01 00:55:39 +01:00
|
|
|
if let controller = currentWebViewController, controller.article != article {
|
2020-03-14 12:31:14 +01:00
|
|
|
controller.setArticle(article)
|
2020-01-01 00:55:39 +01:00
|
|
|
DispatchQueue.main.async {
|
|
|
|
// You have to set the view controller to clear out the UIPageViewController child controller cache.
|
|
|
|
// You also have to do it in an async call or you will get a strange assertion error.
|
|
|
|
self.pageViewController.setViewControllers([controller], direction: .forward, animated: false, completion: nil)
|
|
|
|
}
|
2019-09-24 02:23:23 +02:00
|
|
|
}
|
2020-01-01 00:55:39 +01:00
|
|
|
updateUI()
|
2019-09-24 23:34:11 +02:00
|
|
|
}
|
|
|
|
}
|
2020-01-29 19:30:52 +01:00
|
|
|
|
2021-09-13 09:22:15 +02:00
|
|
|
var restoreScrollPosition: (isShowingExtractedArticle: Bool, articleWindowScrollY: Int)? {
|
|
|
|
didSet {
|
|
|
|
if let rsp = restoreScrollPosition {
|
|
|
|
currentWebViewController?.setScrollPosition(isShowingExtractedArticle: rsp.isShowingExtractedArticle, articleWindowScrollY: rsp.articleWindowScrollY)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-29 19:30:52 +01:00
|
|
|
var currentState: State? {
|
|
|
|
guard let controller = currentWebViewController else { return nil}
|
|
|
|
return State(extractedArticle: controller.extractedArticle,
|
|
|
|
isShowingExtractedArticle: controller.isShowingExtractedArticle,
|
|
|
|
articleExtractorButtonState: controller.articleExtractorButtonState,
|
|
|
|
windowScrollY: controller.windowScrollY)
|
|
|
|
}
|
|
|
|
|
|
|
|
var restoreState: State?
|
2019-09-24 23:34:11 +02:00
|
|
|
|
2019-09-05 21:37:07 +02:00
|
|
|
private let keyboardManager = KeyboardManager(type: .detail)
|
2019-09-05 04:06:29 +02:00
|
|
|
override var keyCommands: [UIKeyCommand]? {
|
|
|
|
return keyboardManager.keyCommands
|
|
|
|
}
|
|
|
|
|
2024-03-04 07:51:53 +01:00
|
|
|
private var lastKnownDisplayMode : UISplitViewController.DisplayMode?
|
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
override func viewDidLoad() {
|
|
|
|
super.viewDidLoad()
|
2019-08-31 21:30:01 +02:00
|
|
|
|
2019-04-23 11:35:48 +02:00
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
|
2019-04-15 22:03:05 +02:00
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
|
2020-02-05 01:00:26 +01:00
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil)
|
2019-11-19 02:12:24 +01:00
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
|
2019-09-21 17:37:21 +02:00
|
|
|
|
2019-12-26 20:21:56 +01:00
|
|
|
let fullScreenTapZone = UIView()
|
|
|
|
NSLayoutConstraint.activate([
|
|
|
|
fullScreenTapZone.widthAnchor.constraint(equalToConstant: 150),
|
|
|
|
fullScreenTapZone.heightAnchor.constraint(equalToConstant: 44)
|
|
|
|
])
|
|
|
|
fullScreenTapZone.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(didTapNavigationBar)))
|
|
|
|
navigationItem.titleView = fullScreenTapZone
|
|
|
|
|
2019-09-24 23:34:11 +02:00
|
|
|
articleExtractorButton.addTarget(self, action: #selector(toggleArticleExtractor(_:)), for: .touchUpInside)
|
2019-11-06 15:08:08 +01:00
|
|
|
toolbarItems?.insert(UIBarButtonItem(customView: articleExtractorButton), at: 6)
|
2024-03-04 07:51:53 +01:00
|
|
|
|
|
|
|
if let parentNavController = navigationController?.parent as? UINavigationController {
|
|
|
|
poppableDelegate.navigationController = parentNavController
|
|
|
|
parentNavController.interactivePopGestureRecognizer?.delegate = poppableDelegate
|
|
|
|
}
|
|
|
|
|
|
|
|
navigationItem.leftItemsSupplementBackButton = true
|
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: [:])
|
|
|
|
pageViewController.delegate = self
|
|
|
|
pageViewController.dataSource = self
|
2020-04-12 18:48:14 +02:00
|
|
|
|
|
|
|
// This code is to disallow paging if we scroll from the left edge. If this code is removed
|
|
|
|
// PoppableGestureRecognizerDelegate will allow us to both navigate back and page back at the
|
|
|
|
// same time. That is really weird when it happens.
|
|
|
|
let panGestureRecognizer = UIPanGestureRecognizer()
|
|
|
|
panGestureRecognizer.delegate = self
|
|
|
|
pageViewController.scrollViewInsidePageControl?.addGestureRecognizer(panGestureRecognizer)
|
|
|
|
|
2020-01-17 05:29:10 +01:00
|
|
|
pageViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
2020-01-01 00:55:39 +01:00
|
|
|
view.addSubview(pageViewController.view)
|
|
|
|
addChild(pageViewController!)
|
|
|
|
NSLayoutConstraint.activate([
|
|
|
|
view.leadingAnchor.constraint(equalTo: pageViewController.view.leadingAnchor),
|
|
|
|
view.trailingAnchor.constraint(equalTo: pageViewController.view.trailingAnchor),
|
|
|
|
view.topAnchor.constraint(equalTo: pageViewController.view.topAnchor),
|
|
|
|
view.bottomAnchor.constraint(equalTo: pageViewController.view.bottomAnchor)
|
|
|
|
])
|
|
|
|
|
2020-03-16 13:58:51 +01:00
|
|
|
let controller: WebViewController
|
2020-01-29 19:30:52 +01:00
|
|
|
if let state = restoreState {
|
2020-03-16 13:58:51 +01:00
|
|
|
controller = createWebViewController(article, updateView: false)
|
2020-01-29 19:30:52 +01:00
|
|
|
controller.extractedArticle = state.extractedArticle
|
|
|
|
controller.isShowingExtractedArticle = state.isShowingExtractedArticle
|
|
|
|
controller.articleExtractorButtonState = state.articleExtractorButtonState
|
|
|
|
controller.windowScrollY = state.windowScrollY
|
2020-03-16 13:58:51 +01:00
|
|
|
} else {
|
|
|
|
controller = createWebViewController(article, updateView: true)
|
2020-01-29 19:30:52 +01:00
|
|
|
}
|
2020-03-16 13:58:51 +01:00
|
|
|
|
2021-09-13 09:22:15 +02:00
|
|
|
if let rsp = restoreScrollPosition {
|
|
|
|
controller.setScrollPosition(isShowingExtractedArticle: rsp.isShowingExtractedArticle, articleWindowScrollY: rsp.articleWindowScrollY)
|
|
|
|
}
|
|
|
|
|
2020-01-16 01:28:37 +01:00
|
|
|
articleExtractorButton.buttonState = controller.articleExtractorButtonState
|
2020-02-26 03:06:02 +01:00
|
|
|
|
2020-03-12 01:17:09 +01:00
|
|
|
self.pageViewController.setViewControllers([controller], direction: .forward, animated: false, completion: nil)
|
2020-07-02 04:47:45 +02:00
|
|
|
if AppDefaults.shared.articleFullscreenEnabled {
|
2020-03-12 01:17:09 +01:00
|
|
|
controller.hideBars()
|
2020-02-26 03:06:02 +01:00
|
|
|
}
|
2020-05-11 22:08:01 +02:00
|
|
|
|
|
|
|
// Search bar
|
2020-05-15 23:56:14 +02:00
|
|
|
searchBar.translatesAutoresizingMaskIntoConstraints = false
|
2020-05-11 22:08:01 +02:00
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(beginFind(_:)), name: .FindInArticle, object: nil)
|
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(endFind(_:)), name: .EndFindInArticle, object: nil)
|
2020-05-15 23:56:14 +02:00
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChangeFrame(_:)), name: UIWindow.keyboardWillChangeFrameNotification, object: nil)
|
|
|
|
searchBar.delegate = self
|
2020-05-11 22:08:01 +02:00
|
|
|
view.bringSubviewToFront(searchBar)
|
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
updateUI()
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
2024-03-04 07:51:53 +01:00
|
|
|
override func viewWillAppear(_ animated: Bool) {
|
|
|
|
navigationController?.isToolbarHidden = false
|
|
|
|
if AppDefaults.shared.articleFullscreenEnabled {
|
|
|
|
currentWebViewController?.hideBars()
|
|
|
|
}
|
|
|
|
|
|
|
|
super.viewWillAppear(animated)
|
2019-11-19 02:12:24 +01:00
|
|
|
}
|
2024-03-04 07:51:53 +01:00
|
|
|
|
2020-05-11 22:08:01 +02:00
|
|
|
override func viewWillDisappear(_ animated: Bool) {
|
2024-03-04 07:51:53 +01:00
|
|
|
super.viewWillDisappear(animated)
|
2020-05-15 23:56:14 +02:00
|
|
|
if searchBar != nil && !searchBar.isHidden {
|
|
|
|
endFind()
|
|
|
|
}
|
2020-05-11 22:08:01 +02:00
|
|
|
}
|
|
|
|
|
2019-11-24 10:42:38 +01:00
|
|
|
override func viewSafeAreaInsetsDidChange() {
|
2019-11-24 20:41:32 +01:00
|
|
|
// This will animate if the show/hide bars animation is happening.
|
|
|
|
view.layoutIfNeeded()
|
2019-11-24 10:42:38 +01:00
|
|
|
}
|
|
|
|
|
2019-04-23 11:35:48 +02:00
|
|
|
func updateUI() {
|
2019-04-15 22:03:05 +02:00
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
guard let article = article else {
|
2019-09-24 23:34:11 +02:00
|
|
|
articleExtractorButton.isEnabled = false
|
2019-04-22 00:42:26 +02:00
|
|
|
nextUnreadBarButtonItem.isEnabled = false
|
|
|
|
prevArticleBarButtonItem.isEnabled = false
|
|
|
|
nextArticleBarButtonItem.isEnabled = false
|
2019-04-15 22:03:05 +02:00
|
|
|
readBarButtonItem.isEnabled = false
|
|
|
|
starBarButtonItem.isEnabled = false
|
|
|
|
actionBarButtonItem.isEnabled = false
|
|
|
|
return
|
|
|
|
}
|
2020-03-13 20:21:18 +01:00
|
|
|
|
2019-07-06 00:45:39 +02:00
|
|
|
nextUnreadBarButtonItem.isEnabled = coordinator.isAnyUnreadAvailable
|
|
|
|
prevArticleBarButtonItem.isEnabled = coordinator.isPrevArticleAvailable
|
|
|
|
nextArticleBarButtonItem.isEnabled = coordinator.isNextArticleAvailable
|
2019-04-15 22:03:05 +02:00
|
|
|
readBarButtonItem.isEnabled = true
|
|
|
|
starBarButtonItem.isEnabled = true
|
2020-03-13 20:21:18 +01:00
|
|
|
|
|
|
|
let permalinkPresent = article.preferredLink != nil
|
2023-06-26 01:19:20 +02:00
|
|
|
articleExtractorButton.isEnabled = permalinkPresent && !AppDefaults.shared.isDeveloperBuild
|
2020-03-13 20:21:18 +01:00
|
|
|
actionBarButtonItem.isEnabled = permalinkPresent
|
|
|
|
|
2020-01-09 22:38:25 +01:00
|
|
|
if article.status.read {
|
|
|
|
readBarButtonItem.image = AppAssets.circleOpenImage
|
2020-02-18 22:49:29 +01:00
|
|
|
readBarButtonItem.isEnabled = article.isAvailableToMarkUnread
|
2020-01-09 22:38:25 +01:00
|
|
|
readBarButtonItem.accLabelText = NSLocalizedString("Mark Article Unread", comment: "Mark Article Unread")
|
|
|
|
} else {
|
|
|
|
readBarButtonItem.image = AppAssets.circleClosedImage
|
2020-02-18 22:49:29 +01:00
|
|
|
readBarButtonItem.isEnabled = true
|
2020-01-09 22:38:25 +01:00
|
|
|
readBarButtonItem.accLabelText = NSLocalizedString("Selected - Mark Article Unread", comment: "Selected - Mark Article Unread")
|
|
|
|
}
|
2019-04-15 22:03:05 +02:00
|
|
|
|
2020-01-09 22:38:25 +01:00
|
|
|
if article.status.starred {
|
|
|
|
starBarButtonItem.image = AppAssets.starClosedImage
|
|
|
|
starBarButtonItem.accLabelText = NSLocalizedString("Selected - Star Article", comment: "Selected - Star Article")
|
|
|
|
} else {
|
|
|
|
starBarButtonItem.image = AppAssets.starOpenImage
|
|
|
|
starBarButtonItem.accLabelText = NSLocalizedString("Star Article", comment: "Star Article")
|
|
|
|
}
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
2024-03-04 07:51:53 +01:00
|
|
|
|
|
|
|
override func contentScrollView(for edge: NSDirectionalRectEdge) -> UIScrollView? {
|
|
|
|
return currentWebViewController?.webView?.scrollView
|
|
|
|
}
|
|
|
|
|
2019-04-23 11:35:48 +02:00
|
|
|
// MARK: Notifications
|
|
|
|
|
|
|
|
@objc dynamic func unreadCountDidChange(_ notification: Notification) {
|
|
|
|
updateUI()
|
|
|
|
}
|
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
@objc func statusesDidChange(_ note: Notification) {
|
2019-12-17 07:45:59 +01:00
|
|
|
guard let articleIDs = note.userInfo?[Account.UserInfoKey.articleIDs] as? Set<String> else {
|
2019-04-15 22:03:05 +02:00
|
|
|
return
|
|
|
|
}
|
2020-01-01 00:55:39 +01:00
|
|
|
guard let article = article else {
|
2019-12-17 07:45:59 +01:00
|
|
|
return
|
|
|
|
}
|
2020-01-01 00:55:39 +01:00
|
|
|
if articleIDs.contains(article.articleID) {
|
2019-04-23 11:35:48 +02:00
|
|
|
updateUI()
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-05 01:00:26 +01:00
|
|
|
@objc func contentSizeCategoryDidChange(_ note: Notification) {
|
2020-07-16 20:56:07 +02:00
|
|
|
currentWebViewController?.fullReload()
|
2020-02-05 01:00:26 +01:00
|
|
|
}
|
|
|
|
|
2019-11-19 02:12:24 +01:00
|
|
|
@objc func willEnterForeground(_ note: Notification) {
|
2019-11-24 21:49:44 +01:00
|
|
|
// The toolbar will come back on you if you don't hide it again
|
2020-07-02 04:47:45 +02:00
|
|
|
if AppDefaults.shared.articleFullscreenEnabled {
|
2020-01-01 00:55:39 +01:00
|
|
|
currentWebViewController?.hideBars()
|
2019-11-24 21:49:44 +01:00
|
|
|
}
|
2019-11-19 02:12:24 +01:00
|
|
|
}
|
|
|
|
|
2019-04-22 00:42:26 +02:00
|
|
|
// MARK: Actions
|
2019-11-18 03:20:50 +01:00
|
|
|
|
2019-12-26 20:21:56 +01:00
|
|
|
@objc func didTapNavigationBar() {
|
2020-01-01 00:55:39 +01:00
|
|
|
currentWebViewController?.hideBars()
|
2019-12-26 20:21:56 +01:00
|
|
|
}
|
|
|
|
|
2019-11-19 02:12:24 +01:00
|
|
|
@objc func showBars(_ sender: Any) {
|
2020-01-01 00:55:39 +01:00
|
|
|
currentWebViewController?.showBars()
|
2019-11-18 03:20:50 +01:00
|
|
|
}
|
|
|
|
|
2019-09-24 23:34:11 +02:00
|
|
|
@IBAction func toggleArticleExtractor(_ sender: Any) {
|
2020-01-01 00:55:39 +01:00
|
|
|
currentWebViewController?.toggleArticleExtractor()
|
2019-09-24 13:46:53 +02:00
|
|
|
}
|
|
|
|
|
2019-04-22 00:42:26 +02:00
|
|
|
@IBAction func nextUnread(_ sender: Any) {
|
2019-07-06 00:45:39 +02:00
|
|
|
coordinator.selectNextUnread()
|
2019-04-22 00:42:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@IBAction func prevArticle(_ sender: Any) {
|
2019-07-06 18:32:19 +02:00
|
|
|
coordinator.selectPrevArticle()
|
2019-04-22 00:42:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@IBAction func nextArticle(_ sender: Any) {
|
2019-07-06 18:32:19 +02:00
|
|
|
coordinator.selectNextArticle()
|
2019-04-22 00:42:26 +02:00
|
|
|
}
|
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
@IBAction func toggleRead(_ sender: Any) {
|
2019-07-06 18:49:53 +02:00
|
|
|
coordinator.toggleReadForCurrentArticle()
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@IBAction func toggleStar(_ sender: Any) {
|
2019-09-05 22:43:01 +02:00
|
|
|
coordinator.toggleStarredForCurrentArticle()
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@IBAction func showActivityDialog(_ sender: Any) {
|
2020-01-01 00:55:39 +01:00
|
|
|
currentWebViewController?.showActivityDialog(popOverBarButtonItem: actionBarButtonItem)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
2020-05-13 13:59:59 +02:00
|
|
|
|
|
|
|
@objc func toggleReaderView(_ sender: Any?) {
|
|
|
|
currentWebViewController?.toggleArticleExtractor()
|
|
|
|
}
|
2019-08-25 18:38:04 +02:00
|
|
|
|
2019-09-05 04:06:29 +02:00
|
|
|
// MARK: Keyboard Shortcuts
|
2020-05-15 09:09:33 +02:00
|
|
|
|
2019-09-05 04:06:29 +02:00
|
|
|
@objc func navigateToTimeline(_ sender: Any?) {
|
|
|
|
coordinator.navigateToTimeline()
|
|
|
|
}
|
|
|
|
|
2019-08-25 18:38:04 +02:00
|
|
|
// MARK: API
|
|
|
|
|
2019-09-05 04:06:29 +02:00
|
|
|
func focus() {
|
2020-01-01 00:55:39 +01:00
|
|
|
currentWebViewController?.focus()
|
2019-09-05 04:06:29 +02:00
|
|
|
}
|
2019-08-25 18:38:04 +02:00
|
|
|
|
2019-09-06 04:14:19 +02:00
|
|
|
func canScrollDown() -> Bool {
|
2020-01-01 00:55:39 +01:00
|
|
|
return currentWebViewController?.canScrollDown() ?? false
|
2019-09-06 04:14:19 +02:00
|
|
|
}
|
|
|
|
|
2020-07-10 20:51:41 +02:00
|
|
|
func canScrollUp() -> Bool {
|
|
|
|
return currentWebViewController?.canScrollUp() ?? false
|
|
|
|
}
|
|
|
|
|
2019-09-06 04:14:19 +02:00
|
|
|
func scrollPageDown() {
|
2020-01-01 00:55:39 +01:00
|
|
|
currentWebViewController?.scrollPageDown()
|
2019-10-16 23:40:49 +02:00
|
|
|
}
|
2020-07-10 20:51:41 +02:00
|
|
|
|
|
|
|
func scrollPageUp() {
|
|
|
|
currentWebViewController?.scrollPageUp()
|
|
|
|
}
|
2019-10-16 23:40:49 +02:00
|
|
|
|
2020-01-29 19:30:52 +01:00
|
|
|
func stopArticleExtractorIfProcessing() {
|
|
|
|
currentWebViewController?.stopArticleExtractorIfProcessing()
|
|
|
|
}
|
2020-05-15 09:09:33 +02:00
|
|
|
|
|
|
|
func openInAppBrowser() {
|
|
|
|
currentWebViewController?.openInAppBrowser()
|
2021-09-13 08:11:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func setScrollPosition(isShowingExtractedArticle: Bool, articleWindowScrollY: Int) {
|
|
|
|
currentWebViewController?.setScrollPosition(isShowingExtractedArticle: isShowingExtractedArticle, articleWindowScrollY: articleWindowScrollY)
|
|
|
|
}
|
2024-03-04 07:51:53 +01:00
|
|
|
|
|
|
|
public func splitViewControllerWillChangeTo(displayMode: UISplitViewController.DisplayMode) {
|
|
|
|
lastKnownDisplayMode = displayMode
|
|
|
|
}
|
2019-11-26 02:43:43 +01:00
|
|
|
}
|
|
|
|
|
2020-05-11 22:08:01 +02:00
|
|
|
// MARK: Find in Article
|
|
|
|
public extension Notification.Name {
|
|
|
|
static let FindInArticle = Notification.Name("FindInArticle")
|
|
|
|
static let EndFindInArticle = Notification.Name("EndFindInArticle")
|
|
|
|
}
|
|
|
|
|
|
|
|
extension ArticleViewController: SearchBarDelegate {
|
|
|
|
|
|
|
|
func searchBar(_ searchBar: ArticleSearchBar, textDidChange searchText: String) {
|
|
|
|
currentWebViewController?.searchText(searchText) {
|
|
|
|
found in
|
|
|
|
searchBar.resultsCount = found.count
|
|
|
|
|
|
|
|
if let index = found.index {
|
|
|
|
searchBar.selectedResult = index + 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func doneWasPressed(_ searchBar: ArticleSearchBar) {
|
|
|
|
NotificationCenter.default.post(name: .EndFindInArticle, object: nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func nextWasPressed(_ searchBar: ArticleSearchBar) {
|
|
|
|
if searchBar.selectedResult < searchBar.resultsCount {
|
|
|
|
currentWebViewController?.selectNextSearchResult()
|
|
|
|
searchBar.selectedResult += 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func previousWasPressed(_ searchBar: ArticleSearchBar) {
|
|
|
|
if searchBar.selectedResult > 1 {
|
|
|
|
currentWebViewController?.selectPreviousSearchResult()
|
|
|
|
searchBar.selectedResult -= 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension ArticleViewController {
|
|
|
|
|
2020-05-13 12:13:31 +02:00
|
|
|
@objc func beginFind(_ _: Any? = nil) {
|
2020-05-11 22:08:01 +02:00
|
|
|
searchBar.isHidden = false
|
|
|
|
navigationController?.setToolbarHidden(true, animated: true)
|
|
|
|
currentWebViewController?.additionalSafeAreaInsets.bottom = searchBar.frame.height
|
|
|
|
searchBar.becomeFirstResponder()
|
|
|
|
}
|
|
|
|
|
2020-05-15 23:56:14 +02:00
|
|
|
@objc func endFind(_ _: Any? = nil) {
|
2020-05-11 22:08:01 +02:00
|
|
|
searchBar.resignFirstResponder()
|
|
|
|
searchBar.isHidden = true
|
|
|
|
navigationController?.setToolbarHidden(false, animated: true)
|
|
|
|
currentWebViewController?.additionalSafeAreaInsets.bottom = 0
|
|
|
|
currentWebViewController?.endSearch()
|
|
|
|
}
|
|
|
|
|
2020-05-15 23:56:14 +02:00
|
|
|
@objc func keyboardWillChangeFrame(_ notification: Notification) {
|
|
|
|
if !searchBar.isHidden,
|
|
|
|
let duration = notification.userInfo?[UIWindow.keyboardAnimationDurationUserInfoKey] as? Double,
|
|
|
|
let curveRaw = notification.userInfo?[UIWindow.keyboardAnimationCurveUserInfoKey] as? UInt,
|
|
|
|
let frame = notification.userInfo?[UIWindow.keyboardFrameEndUserInfoKey] as? CGRect {
|
|
|
|
|
|
|
|
let curve = UIView.AnimationOptions(rawValue: curveRaw)
|
|
|
|
let newHeight = view.safeAreaLayoutGuide.layoutFrame.maxY - frame.minY
|
|
|
|
currentWebViewController?.additionalSafeAreaInsets.bottom = newHeight + searchBar.frame.height + 10
|
|
|
|
self.searchBarBottomConstraint.constant = newHeight
|
|
|
|
UIView.animate(withDuration: duration, delay: 0, options: curve, animations: {
|
|
|
|
self.view.layoutIfNeeded()
|
|
|
|
})
|
2020-05-11 22:08:01 +02:00
|
|
|
}
|
|
|
|
}
|
2020-05-15 23:56:14 +02:00
|
|
|
|
2020-05-11 22:08:01 +02:00
|
|
|
}
|
|
|
|
|
2020-05-15 23:56:14 +02:00
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
// MARK: WebViewControllerDelegate
|
2019-04-15 22:03:05 +02:00
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
extension ArticleViewController: WebViewControllerDelegate {
|
2020-01-21 19:05:47 +01:00
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
func webViewController(_ webViewController: WebViewController, articleExtractorButtonStateDidUpdate buttonState: ArticleExtractorButtonState) {
|
|
|
|
if webViewController === currentWebViewController {
|
|
|
|
articleExtractorButton.buttonState = buttonState
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
2019-09-21 19:43:15 +02:00
|
|
|
}
|
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
2019-04-23 14:26:35 +02:00
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
// MARK: UIPageViewControllerDataSource
|
2019-10-12 21:45:44 +02:00
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
extension ArticleViewController: UIPageViewControllerDataSource {
|
2019-10-14 02:41:34 +02:00
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
|
2020-01-26 22:21:04 +01:00
|
|
|
guard let webViewController = viewController as? WebViewController,
|
|
|
|
let currentArticle = webViewController.article,
|
|
|
|
let article = coordinator.findPrevArticle(currentArticle) else {
|
2020-01-01 00:55:39 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return createWebViewController(article)
|
2019-10-16 18:31:20 +02:00
|
|
|
}
|
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
|
2020-01-26 22:21:04 +01:00
|
|
|
guard let webViewController = viewController as? WebViewController,
|
|
|
|
let currentArticle = webViewController.article,
|
|
|
|
let article = coordinator.findNextArticle(currentArticle) else {
|
2020-01-01 00:55:39 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return createWebViewController(article)
|
2019-10-16 18:31:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
// MARK: UIPageViewControllerDelegate
|
2019-10-16 01:08:13 +02:00
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
extension ArticleViewController: UIPageViewControllerDelegate {
|
2019-10-16 01:08:13 +02:00
|
|
|
|
2020-01-01 00:55:39 +01:00
|
|
|
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
|
|
|
|
guard finished, completed else { return }
|
|
|
|
guard let article = currentWebViewController?.article else { return }
|
2020-02-18 20:08:38 +01:00
|
|
|
|
2020-01-30 00:31:50 +01:00
|
|
|
coordinator.selectArticle(article, animations: [.select, .scroll, .navigation])
|
2020-01-01 00:55:39 +01:00
|
|
|
articleExtractorButton.buttonState = currentWebViewController?.articleExtractorButtonState ?? .off
|
2020-02-18 20:08:38 +01:00
|
|
|
|
2024-03-04 07:51:53 +01:00
|
|
|
let webViewControllers = previousViewControllers.compactMap{ $0 as? WebViewController }
|
|
|
|
for webViewController in webViewControllers {
|
|
|
|
webViewController.stopWebViewActivity()
|
|
|
|
}
|
2019-10-16 01:08:13 +02:00
|
|
|
}
|
2019-10-12 21:45:44 +02:00
|
|
|
}
|
|
|
|
|
2020-04-12 18:48:14 +02:00
|
|
|
// MARK: UIGestureRecognizerDelegate
|
|
|
|
|
|
|
|
extension ArticleViewController: UIGestureRecognizerDelegate {
|
|
|
|
|
|
|
|
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
|
|
|
let point = gestureRecognizer.location(in: nil)
|
|
|
|
if point.x > 40 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-09-21 03:33:28 +02:00
|
|
|
// MARK: Private
|
|
|
|
|
2019-09-24 11:29:15 +02:00
|
|
|
private extension ArticleViewController {
|
2019-04-23 14:26:35 +02:00
|
|
|
|
2020-03-14 12:31:14 +01:00
|
|
|
func createWebViewController(_ article: Article?, updateView: Bool = true) -> WebViewController {
|
2020-01-01 00:55:39 +01:00
|
|
|
let controller = WebViewController()
|
|
|
|
controller.coordinator = coordinator
|
|
|
|
controller.delegate = self
|
2020-03-14 12:31:14 +01:00
|
|
|
controller.setArticle(article, updateView: updateView)
|
2020-01-01 00:55:39 +01:00
|
|
|
return controller
|
2019-11-18 03:20:50 +01:00
|
|
|
}
|
|
|
|
|
2019-04-23 14:26:35 +02:00
|
|
|
}
|