mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2024-12-24 16:51:19 +01:00
182 lines
4.7 KiB
Swift
182 lines
4.7 KiB
Swift
//
|
|
// DetailViewController.swift
|
|
// NetNewsWire
|
|
//
|
|
// Created by Brent Simmons on 7/26/15.
|
|
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import WebKit
|
|
import Articles
|
|
import RSWeb
|
|
|
|
enum DetailState: Equatable {
|
|
case noSelection
|
|
case multipleSelection
|
|
case loading
|
|
case article(Article, CGFloat?)
|
|
case extracted(Article, ExtractedArticle, CGFloat?)
|
|
}
|
|
|
|
final class DetailViewController: NSViewController, WKUIDelegate {
|
|
|
|
@IBOutlet var containerView: DetailContainerView!
|
|
@IBOutlet var statusBarView: DetailStatusBarView!
|
|
|
|
private lazy var regularWebViewController = createWebViewController()
|
|
private var searchWebViewController: DetailWebViewController?
|
|
|
|
private var currentWebViewController: DetailWebViewController! {
|
|
didSet {
|
|
let webview = currentWebViewController.view
|
|
if containerView.contentView === webview {
|
|
return
|
|
}
|
|
statusBarView.mouseoverLink = nil
|
|
containerView.contentView = webview
|
|
}
|
|
}
|
|
|
|
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
|
|
|
|
override func viewDidLoad() {
|
|
currentWebViewController = regularWebViewController
|
|
NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange(_:)), name: UserDefaults.didChangeNotification, object: nil)
|
|
}
|
|
|
|
// MARK: - API
|
|
|
|
func setState(_ state: DetailState, mode: TimelineSourceMode) {
|
|
switch mode {
|
|
case .regular:
|
|
detailStateForRegular = state
|
|
case .search:
|
|
detailStateForSearch = state
|
|
}
|
|
}
|
|
|
|
func showDetail(for mode: TimelineSourceMode) {
|
|
currentSourceMode = mode
|
|
}
|
|
|
|
func stopMediaPlayback() {
|
|
currentWebViewController.stopMediaPlayback()
|
|
}
|
|
|
|
func canScrollDown(_ callback: @escaping (Bool) -> Void) {
|
|
currentWebViewController.canScrollDown(callback)
|
|
}
|
|
|
|
func canScrollUp(_ callback: @escaping (Bool) -> Void) {
|
|
currentWebViewController.canScrollUp(callback)
|
|
}
|
|
|
|
override func scrollPageDown(_ sender: Any?) {
|
|
currentWebViewController.scrollPageDown(sender)
|
|
}
|
|
|
|
override func scrollPageUp(_ sender: Any?) {
|
|
currentWebViewController.scrollPageUp(sender)
|
|
}
|
|
|
|
// MARK: - Navigation
|
|
|
|
func focus() {
|
|
guard let window = currentWebViewController.webView.window else {
|
|
return
|
|
}
|
|
window.makeFirstResponderUnlessDescendantIsFirstResponder(currentWebViewController.webView)
|
|
}
|
|
|
|
// MARK: State Restoration
|
|
|
|
func saveState(to state: inout [AnyHashable : Any]) {
|
|
currentWebViewController.saveState(to: &state)
|
|
}
|
|
|
|
}
|
|
|
|
// MARK: - DetailWebViewControllerDelegate
|
|
|
|
extension DetailViewController: DetailWebViewControllerDelegate {
|
|
|
|
func mouseDidEnter(_ detailWebViewController: DetailWebViewController, link: String) {
|
|
guard !link.isEmpty, detailWebViewController === currentWebViewController else {
|
|
return
|
|
}
|
|
statusBarView.mouseoverLink = link
|
|
}
|
|
|
|
func mouseDidExit(_ detailWebViewController: DetailWebViewController) {
|
|
guard detailWebViewController === currentWebViewController else {
|
|
return
|
|
}
|
|
statusBarView.mouseoverLink = nil
|
|
}
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private extension DetailViewController {
|
|
|
|
func createWebViewController() -> DetailWebViewController {
|
|
let controller = DetailWebViewController()
|
|
controller.delegate = self
|
|
controller.state = .noSelection
|
|
return controller
|
|
}
|
|
|
|
func webViewController(for mode: TimelineSourceMode) -> DetailWebViewController {
|
|
switch mode {
|
|
case .regular:
|
|
return regularWebViewController
|
|
case .search:
|
|
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
|
|
}
|
|
}
|
|
}
|