2017-05-27 19:43:27 +02:00
|
|
|
//
|
|
|
|
// DetailViewController.swift
|
2018-08-29 07:18:24 +02:00
|
|
|
// NetNewsWire
|
2017-05-27 19:43:27 +02:00
|
|
|
//
|
|
|
|
// Created by Brent Simmons on 7/26/15.
|
|
|
|
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import WebKit
|
|
|
|
import RSCore
|
2018-07-24 03:29:08 +02:00
|
|
|
import Articles
|
2017-12-03 21:13:44 +01:00
|
|
|
import RSWeb
|
2017-05-27 19:43:27 +02:00
|
|
|
|
2019-02-13 07:57:19 +01:00
|
|
|
enum DetailState: Equatable {
|
|
|
|
case noSelection
|
|
|
|
case multipleSelection
|
2019-09-21 22:03:42 +02:00
|
|
|
case loading
|
2021-09-14 03:42:58 +02:00
|
|
|
case article(Article, CGFloat?)
|
|
|
|
case extracted(Article, ExtractedArticle, CGFloat?)
|
2019-02-13 07:57:19 +01:00
|
|
|
}
|
|
|
|
|
2018-02-19 06:49:46 +01:00
|
|
|
final class DetailViewController: NSViewController, WKUIDelegate {
|
2017-11-06 05:31:50 +01:00
|
|
|
|
2017-12-16 19:18:02 +01:00
|
|
|
@IBOutlet var containerView: DetailContainerView!
|
2019-02-11 06:39:11 +01:00
|
|
|
@IBOutlet var statusBarView: DetailStatusBarView!
|
2017-12-03 21:38:44 +01:00
|
|
|
|
2023-11-29 06:37:38 +01:00
|
|
|
private lazy var regularWebViewController = createWebViewController()
|
|
|
|
private var searchWebViewController: DetailWebViewController?
|
2019-02-13 07:57:19 +01:00
|
|
|
|
2023-11-29 06:37:38 +01:00
|
|
|
private var currentWebViewController: DetailWebViewController! {
|
2018-02-19 06:49:46 +01:00
|
|
|
didSet {
|
2019-02-13 07:57:19 +01:00
|
|
|
let webview = currentWebViewController.view
|
|
|
|
if containerView.contentView === webview {
|
2018-02-19 06:49:46 +01:00
|
|
|
return
|
|
|
|
}
|
2019-02-11 06:39:11 +01:00
|
|
|
statusBarView.mouseoverLink = nil
|
2019-02-13 07:57:19 +01:00
|
|
|
containerView.contentView = webview
|
2018-02-19 06:49:46 +01:00
|
|
|
}
|
|
|
|
}
|
2019-02-11 06:46:53 +01:00
|
|
|
|
2023-11-29 06:37:38 +01:00
|
|
|
private var currentSourceMode: TimelineSourceMode = .regular {
|
|
|
|
didSet {
|
|
|
|
currentWebViewController = webViewController(for: currentSourceMode)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private var detailStateForRegular: DetailState = .noSelection {
|
|
|
|
didSet {
|
|
|
|
webViewController(for: .regular).state = detailStateForRegular
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private var detailStateForSearch: DetailState = .noSelection {
|
|
|
|
didSet {
|
|
|
|
webViewController(for: .search).state = detailStateForSearch
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private var isArticleContentJavascriptEnabled = AppDefaults.shared.isArticleContentJavascriptEnabled
|
|
|
|
|
2017-05-27 19:43:27 +02:00
|
|
|
override func viewDidLoad() {
|
2019-02-13 07:57:19 +01:00
|
|
|
currentWebViewController = regularWebViewController
|
2023-11-29 06:37:38 +01:00
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange(_:)), name: UserDefaults.didChangeNotification, object: nil)
|
2017-05-27 19:43:27 +02:00
|
|
|
}
|
|
|
|
|
2019-02-13 07:57:19 +01:00
|
|
|
// MARK: - API
|
2019-02-12 07:36:31 +01:00
|
|
|
|
2019-02-17 07:14:06 +01:00
|
|
|
func setState(_ state: DetailState, mode: TimelineSourceMode) {
|
2023-11-29 06:37:38 +01:00
|
|
|
switch mode {
|
|
|
|
case .regular:
|
|
|
|
detailStateForRegular = state
|
|
|
|
case .search:
|
|
|
|
detailStateForSearch = state
|
|
|
|
}
|
2019-02-13 07:57:19 +01:00
|
|
|
}
|
2017-12-20 22:39:31 +01:00
|
|
|
|
2019-02-25 07:39:57 +01:00
|
|
|
func showDetail(for mode: TimelineSourceMode) {
|
2023-11-29 06:37:38 +01:00
|
|
|
currentSourceMode = mode
|
2019-02-25 07:39:57 +01:00
|
|
|
}
|
|
|
|
|
2020-02-27 21:15:41 +01:00
|
|
|
func stopMediaPlayback() {
|
|
|
|
currentWebViewController.stopMediaPlayback()
|
|
|
|
}
|
|
|
|
|
2017-12-20 22:39:31 +01:00
|
|
|
func canScrollDown(_ callback: @escaping (Bool) -> Void) {
|
2019-02-13 07:57:19 +01:00
|
|
|
currentWebViewController.canScrollDown(callback)
|
2017-12-20 22:39:31 +01:00
|
|
|
}
|
|
|
|
|
2020-07-10 20:33:25 +02:00
|
|
|
func canScrollUp(_ callback: @escaping (Bool) -> Void) {
|
|
|
|
currentWebViewController.canScrollUp(callback)
|
|
|
|
}
|
|
|
|
|
2017-12-20 22:39:31 +01:00
|
|
|
override func scrollPageDown(_ sender: Any?) {
|
2019-02-13 07:57:19 +01:00
|
|
|
currentWebViewController.scrollPageDown(sender)
|
2017-05-27 19:43:27 +02:00
|
|
|
}
|
2020-07-10 20:33:25 +02:00
|
|
|
|
|
|
|
override func scrollPageUp(_ sender: Any?) {
|
|
|
|
currentWebViewController.scrollPageUp(sender)
|
|
|
|
}
|
2019-03-01 23:56:40 +01:00
|
|
|
|
|
|
|
// MARK: - Navigation
|
|
|
|
|
|
|
|
func focus() {
|
2019-09-04 10:12:50 +02:00
|
|
|
guard let window = currentWebViewController.webView.window else {
|
2019-03-01 23:56:40 +01:00
|
|
|
return
|
|
|
|
}
|
2019-09-04 10:12:50 +02:00
|
|
|
window.makeFirstResponderUnlessDescendantIsFirstResponder(currentWebViewController.webView)
|
2019-03-01 23:56:40 +01:00
|
|
|
}
|
|
|
|
|
2021-09-14 03:42:58 +02:00
|
|
|
// MARK: State Restoration
|
|
|
|
|
|
|
|
func saveState(to state: inout [AnyHashable : Any]) {
|
|
|
|
currentWebViewController.saveState(to: &state)
|
|
|
|
}
|
|
|
|
|
2017-05-27 19:43:27 +02:00
|
|
|
}
|
|
|
|
|
2019-02-13 07:57:19 +01:00
|
|
|
// MARK: - DetailWebViewControllerDelegate
|
2019-02-13 03:12:12 +01:00
|
|
|
|
|
|
|
extension DetailViewController: DetailWebViewControllerDelegate {
|
2017-11-06 05:31:50 +01:00
|
|
|
|
2019-02-18 06:43:51 +01:00
|
|
|
func mouseDidEnter(_ detailWebViewController: DetailWebViewController, link: String) {
|
|
|
|
guard !link.isEmpty, detailWebViewController === currentWebViewController else {
|
2017-11-06 05:31:50 +01:00
|
|
|
return
|
|
|
|
}
|
2019-02-11 06:39:11 +01:00
|
|
|
statusBarView.mouseoverLink = link
|
2017-11-06 05:31:50 +01:00
|
|
|
}
|
|
|
|
|
2021-03-16 02:10:42 +01:00
|
|
|
func mouseDidExit(_ detailWebViewController: DetailWebViewController) {
|
2019-02-18 06:43:51 +01:00
|
|
|
guard detailWebViewController === currentWebViewController else {
|
|
|
|
return
|
|
|
|
}
|
2019-02-11 06:39:11 +01:00
|
|
|
statusBarView.mouseoverLink = nil
|
2017-11-06 05:31:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-13 07:57:19 +01:00
|
|
|
// MARK: - Private
|
2018-02-19 06:49:46 +01:00
|
|
|
|
2017-12-20 22:39:31 +01:00
|
|
|
private extension DetailViewController {
|
|
|
|
|
2019-02-13 07:57:19 +01:00
|
|
|
func createWebViewController() -> DetailWebViewController {
|
|
|
|
let controller = DetailWebViewController()
|
|
|
|
controller.delegate = self
|
|
|
|
controller.state = .noSelection
|
|
|
|
return controller
|
2017-12-20 22:39:31 +01:00
|
|
|
}
|
2019-02-18 06:43:51 +01:00
|
|
|
|
|
|
|
func webViewController(for mode: TimelineSourceMode) -> DetailWebViewController {
|
|
|
|
switch mode {
|
|
|
|
case .regular:
|
|
|
|
return regularWebViewController
|
|
|
|
case .search:
|
2023-11-29 06:37:38 +01:00
|
|
|
if searchWebViewController == nil {
|
|
|
|
searchWebViewController = createWebViewController()
|
|
|
|
}
|
|
|
|
return searchWebViewController!
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@objc func userDefaultsDidChange(_ : Notification) {
|
|
|
|
if AppDefaults.shared.isArticleContentJavascriptEnabled != isArticleContentJavascriptEnabled {
|
|
|
|
isArticleContentJavascriptEnabled = AppDefaults.shared.isArticleContentJavascriptEnabled
|
|
|
|
createNewWebViewsAndRestoreState()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func createNewWebViewsAndRestoreState() {
|
|
|
|
|
|
|
|
regularWebViewController = createWebViewController()
|
|
|
|
currentWebViewController = regularWebViewController
|
|
|
|
regularWebViewController.state = detailStateForRegular
|
|
|
|
|
|
|
|
searchWebViewController = nil
|
|
|
|
|
|
|
|
if currentSourceMode == .search {
|
|
|
|
searchWebViewController = createWebViewController()
|
|
|
|
currentWebViewController = searchWebViewController
|
|
|
|
searchWebViewController!.state = detailStateForSearch
|
2019-02-18 06:43:51 +01:00
|
|
|
}
|
|
|
|
}
|
2017-12-20 22:39:31 +01:00
|
|
|
}
|