mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-08-05 16:58:59 +00:00
197 lines
8 KiB
Swift
197 lines
8 KiB
Swift
//
|
|
// DetailViewController.swift
|
|
// NewsBlur
|
|
//
|
|
// Created by David Sinclair on 2020-08-27.
|
|
// Copyright © 2020 NewsBlur. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
/// Manages the detail column of the split view, with the feed detail and/or the story pages.
|
|
class DetailViewController: DetailObjCViewController {
|
|
/// How the feed detail and story pages are laid out.
|
|
enum Layout {
|
|
/// The feed detail is to the left of the story pages (and managed by the split view, not here).
|
|
case left
|
|
|
|
/// The feed detail is at the top, the story pages at the bottom.
|
|
case top
|
|
|
|
/// The story pages are at the top, the feed detail at the bottom.
|
|
case bottom
|
|
}
|
|
|
|
/// How the feed detail and story pages are laid out.
|
|
var layout: Layout = .left { //TODO: set this based on prefs, either here or in the initializer
|
|
didSet {
|
|
updateLayout()
|
|
}
|
|
}
|
|
|
|
/// Position of the divider between the views.
|
|
var splitPosition: CGFloat = 200 //TODO: set this based on prefs
|
|
|
|
/// The feed detail view controller, if using `top` or `bottom` layout. `nil` if using `left` layout.
|
|
var feedDetailViewController: FeedDetailViewController?
|
|
|
|
/// The horizontal page view controller.
|
|
var horizontalPageViewController: HorizontalPageViewController?
|
|
|
|
/// Returns the currently displayed story view controller, or `nil` if none.
|
|
@objc var currentStoryController: StoryDetailViewController? {
|
|
return horizontalPageViewController?.currentController?.currentController
|
|
}
|
|
|
|
/// Returns an array of all existing story view controllers.
|
|
@objc var storyControllers: [StoryDetailViewController] {
|
|
var controllers = [StoryDetailViewController]()
|
|
|
|
guard let pageViewController = horizontalPageViewController else {
|
|
return controllers
|
|
}
|
|
|
|
addStories(from: pageViewController.previousController, to: &controllers)
|
|
addStories(from: pageViewController.currentController, to: &controllers)
|
|
addStories(from: pageViewController.nextController, to: &controllers)
|
|
|
|
return controllers
|
|
}
|
|
|
|
/// Returns an array of the previous, current, and next vertical page view controllers, each with the previous, current, and next story view controllers. Note that the top-level array will always have three values, but the inner arrays may have 0-3, depending on usage. This is mainly for debugging use.
|
|
@objc var storyControllersMatrix: [[StoryDetailViewController]] {
|
|
guard let pageViewController = horizontalPageViewController else {
|
|
return [[]]
|
|
}
|
|
|
|
var previousVerticalControllers = [StoryDetailViewController]()
|
|
var currentVerticalControllers = [StoryDetailViewController]()
|
|
var nextVerticalControllers = [StoryDetailViewController]()
|
|
|
|
addStories(from: pageViewController.previousController, to: &previousVerticalControllers)
|
|
addStories(from: pageViewController.currentController, to: ¤tVerticalControllers)
|
|
addStories(from: pageViewController.nextController, to: &nextVerticalControllers)
|
|
|
|
return [previousVerticalControllers, currentVerticalControllers, nextVerticalControllers]
|
|
}
|
|
|
|
/// Calls a closure for each story view controller.
|
|
///
|
|
/// - Parameter handler: The closure to call; it takes a story controller as a parameter.
|
|
@objc(updateStoryControllers:) func updateStoryControllers(handler:(StoryDetailViewController) -> Void) {
|
|
for controller in storyControllers {
|
|
handler(controller)
|
|
}
|
|
}
|
|
|
|
/// Resets all of the other story controllers from the current one.
|
|
@objc func resetOtherStoryControllers() {
|
|
horizontalPageViewController?.currentController = horizontalPageViewController?.currentController
|
|
|
|
navigationItem.titleView = nil
|
|
}
|
|
|
|
/// Resets the page controllers to a blank state.
|
|
@objc func resetPageControllers() {
|
|
if let viewController = Storyboards.shared.controller(withIdentifier: .verticalPages) as? VerticalPageViewController {
|
|
viewController.horizontalPageViewController = horizontalPageViewController
|
|
viewController.currentController = makeStoryController(for: -2)
|
|
|
|
horizontalPageViewController?.setViewControllers([viewController], direction: .forward, animated: false, completion: nil)
|
|
}
|
|
}
|
|
|
|
/// Creates a new story view controller for the specified page index, and starts loading the content.
|
|
///
|
|
/// - Parameter pageIndex: The index of the story page.
|
|
/// - Returns: A new `StoryDetailViewController` instance.
|
|
func makeStoryController(for pageIndex: Int) -> StoryDetailViewController? {
|
|
let storyController = StoryDetailViewController(pageIndex: pageIndex)
|
|
|
|
applyNewIndex(pageIndex, pageController: storyController)
|
|
|
|
return storyController
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
updateLayout()
|
|
resetPageControllers()
|
|
}
|
|
}
|
|
|
|
private extension DetailViewController {
|
|
func updateLayout() {
|
|
checkViewControllers()
|
|
|
|
//TODO: *** TO BE IMPLEMENTED ***: update the layout
|
|
}
|
|
|
|
func checkViewControllers() {
|
|
if layout == .left {
|
|
remove(viewController: feedDetailViewController)
|
|
|
|
feedDetailViewController = nil
|
|
} else {
|
|
if feedDetailViewController == nil {
|
|
feedDetailViewController = Storyboards.shared.controller(withIdentifier: .feedDetail) as? FeedDetailViewController
|
|
|
|
add(viewController: feedDetailViewController)
|
|
}
|
|
}
|
|
|
|
if horizontalPageViewController == nil {
|
|
horizontalPageViewController = Storyboards.shared.controller(withIdentifier: .horizontalPages) as? HorizontalPageViewController
|
|
|
|
horizontalPageViewController?.detailViewController = self
|
|
|
|
add(viewController: horizontalPageViewController)
|
|
}
|
|
}
|
|
|
|
func add(viewController: UIViewController?) {
|
|
guard let viewController = viewController else {
|
|
return
|
|
}
|
|
|
|
addChild(viewController)
|
|
// view.addSubview(viewController.view)
|
|
view.insertSubview(viewController.view, at: 0)
|
|
|
|
//TODO: *** TO BE IMPLEMENTED ***: will want to use slightly different constraints for top & bottom layouts
|
|
viewController.view.translatesAutoresizingMaskIntoConstraints = false
|
|
viewController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
|
|
viewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
|
|
viewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
|
|
viewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
|
|
|
|
viewController.didMove(toParent: self)
|
|
}
|
|
|
|
func remove(viewController: UIViewController?) {
|
|
guard let viewController = viewController else {
|
|
return
|
|
}
|
|
|
|
viewController.willMove(toParent: nil)
|
|
viewController.removeFromParent()
|
|
viewController.view.removeFromSuperview()
|
|
}
|
|
|
|
func addStories(from verticalPageController: VerticalPageViewController?, to controllers: inout [StoryDetailViewController]) {
|
|
guard let verticalPageController = verticalPageController else {
|
|
return
|
|
}
|
|
|
|
addStory(verticalPageController.previousController, to: &controllers)
|
|
addStory(verticalPageController.currentController, to: &controllers)
|
|
addStory(verticalPageController.nextController, to: &controllers)
|
|
}
|
|
|
|
func addStory(_ story: StoryDetailViewController?, to controllers: inout [StoryDetailViewController]) {
|
|
if let story = story {
|
|
controllers.append(story)
|
|
}
|
|
}
|
|
}
|