2020-08-27 21:26:12 -07:00
|
|
|
//
|
|
|
|
// 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.
|
2021-01-29 20:10:53 -08:00
|
|
|
class DetailViewController: BaseViewController {
|
|
|
|
/// Returns the shared app delegate.
|
|
|
|
var appDelegate: NewsBlurAppDelegate {
|
|
|
|
return NewsBlurAppDelegate.shared()
|
|
|
|
}
|
|
|
|
|
2020-11-28 21:28:19 -08:00
|
|
|
/// Preference keys.
|
|
|
|
enum Key {
|
|
|
|
/// Layout of the story titles and story pages.
|
|
|
|
static let layout = "story_titles_position"
|
|
|
|
|
2022-04-01 17:54:01 -07:00
|
|
|
/// Behavior of the split controller.
|
|
|
|
static let behavior = "split_behavior"
|
|
|
|
|
2020-11-28 21:28:19 -08:00
|
|
|
/// Position of the divider between the views when in horizontal orientation. Only used for `.top` and `.bottom` layouts.
|
|
|
|
static let horizontalPosition = "story_titles_divider_horizontal"
|
|
|
|
|
|
|
|
/// Position of the divider between the views when in vertical orientation. Only used for `.top` and `.bottom` layouts.
|
|
|
|
static let verticalPosition = "story_titles_divider_vertical"
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Preference values.
|
2022-04-01 17:54:01 -07:00
|
|
|
enum LayoutValue {
|
2020-11-28 21:28:19 -08:00
|
|
|
static let left = "titles_on_left"
|
|
|
|
static let top = "titles_on_top"
|
|
|
|
static let bottom = "titles_on_bottom"
|
|
|
|
}
|
|
|
|
|
2020-09-25 20:31:01 -07:00
|
|
|
/// 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
|
|
|
|
}
|
2020-08-27 21:26:12 -07:00
|
|
|
|
2020-09-25 20:31:01 -07:00
|
|
|
/// How the feed detail and story pages are laid out.
|
2020-11-28 21:28:19 -08:00
|
|
|
var layout: Layout {
|
|
|
|
get {
|
|
|
|
switch UserDefaults.standard.string(forKey: Key.layout) {
|
2022-04-01 17:54:01 -07:00
|
|
|
case LayoutValue.top:
|
2020-11-28 21:28:19 -08:00
|
|
|
return .top
|
2022-04-01 17:54:01 -07:00
|
|
|
case LayoutValue.bottom:
|
2020-11-28 21:28:19 -08:00
|
|
|
return .bottom
|
|
|
|
default:
|
|
|
|
return .left
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
guard newValue != layout else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch newValue {
|
|
|
|
case .top:
|
2022-04-01 17:54:01 -07:00
|
|
|
UserDefaults.standard.set(LayoutValue.top, forKey: Key.layout)
|
2020-11-28 21:28:19 -08:00
|
|
|
case .bottom:
|
2022-04-01 17:54:01 -07:00
|
|
|
UserDefaults.standard.set(LayoutValue.bottom, forKey: Key.layout)
|
2020-11-28 21:28:19 -08:00
|
|
|
default:
|
2022-04-01 17:54:01 -07:00
|
|
|
UserDefaults.standard.set(LayoutValue.left, forKey: Key.layout)
|
2020-11-28 21:28:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
updateLayout(reload: true)
|
2020-09-25 20:31:01 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-24 21:34:45 -08:00
|
|
|
/// Whether or not the feed detail is on the left; see also the following property.
|
|
|
|
@objc var storyTitlesOnLeft: Bool {
|
|
|
|
return layout == .left
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Whether or not the feed detail is on the top; see also the previous property.
|
|
|
|
@objc var storyTitlesOnTop: Bool {
|
|
|
|
return layout == .top
|
|
|
|
}
|
|
|
|
|
2022-04-01 17:54:01 -07:00
|
|
|
/// Preference values.
|
|
|
|
enum BehaviorValue {
|
|
|
|
static let auto = "auto"
|
|
|
|
static let tile = "tile"
|
|
|
|
static let displace = "displace"
|
|
|
|
static let overlay = "overlay"
|
|
|
|
}
|
|
|
|
|
|
|
|
/// How the split controller behaves.
|
|
|
|
enum Behavior {
|
|
|
|
/// The split controller figures out the best behavior.
|
|
|
|
case auto
|
|
|
|
|
|
|
|
/// The split controller arranges the views side-by-side.
|
|
|
|
case tile
|
|
|
|
|
|
|
|
/// The split controller pushes the detail view aside.
|
|
|
|
case displace
|
|
|
|
|
|
|
|
/// The split controller puts the left columns over the detail view.
|
|
|
|
case overlay
|
|
|
|
}
|
|
|
|
|
|
|
|
/// How the split controller behaves.
|
|
|
|
var behavior: Behavior {
|
|
|
|
switch UserDefaults.standard.string(forKey: Key.behavior) {
|
|
|
|
case BehaviorValue.tile:
|
|
|
|
return .tile
|
|
|
|
case BehaviorValue.displace:
|
|
|
|
return .displace
|
|
|
|
case BehaviorValue.overlay:
|
|
|
|
return .overlay
|
|
|
|
default:
|
|
|
|
return .auto
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-29 20:10:53 -08:00
|
|
|
/// Returns `true` if the window is in portrait orientation, otherwise `false`.
|
|
|
|
@objc var isPortraitOrientation: Bool {
|
|
|
|
return view.window?.windowScene?.interfaceOrientation.isPortrait ?? false
|
|
|
|
}
|
|
|
|
|
2020-09-25 20:31:01 -07:00
|
|
|
/// Position of the divider between the views.
|
2020-11-28 21:28:19 -08:00
|
|
|
var dividerPosition: CGFloat {
|
|
|
|
get {
|
|
|
|
let key = isPortraitOrientation ? Key.verticalPosition : Key.horizontalPosition
|
|
|
|
let value = CGFloat(UserDefaults.standard.float(forKey: key))
|
|
|
|
|
|
|
|
if value == 0 {
|
|
|
|
return 200
|
|
|
|
} else {
|
|
|
|
return value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
guard newValue != dividerPosition else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let key = isPortraitOrientation ? Key.verticalPosition : Key.horizontalPosition
|
|
|
|
|
|
|
|
UserDefaults.standard.set(Float(newValue), forKey: key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Top container view.
|
|
|
|
@IBOutlet weak var topContainerView: UIView!
|
|
|
|
|
|
|
|
/// Bottom container view.
|
|
|
|
@IBOutlet weak var bottomContainerView: UIView!
|
|
|
|
|
2021-01-29 20:10:53 -08:00
|
|
|
/// Draggable divider view.
|
|
|
|
@IBOutlet weak var dividerView: UIView!
|
|
|
|
|
2021-01-29 21:28:34 -08:00
|
|
|
/// Indicator image in the divider view.
|
|
|
|
@IBOutlet weak var dividerImageView: UIImageView!
|
|
|
|
|
2020-12-24 16:20:22 -08:00
|
|
|
/// Top container view top constraint. May need to adjust this for fullscreen on iPhone.
|
|
|
|
@IBOutlet weak var topContainerTopConstraint: NSLayoutConstraint!
|
|
|
|
|
2020-11-28 21:28:19 -08:00
|
|
|
/// Bottom constraint of the divider view.
|
|
|
|
@IBOutlet weak var dividerViewBottomConstraint: NSLayoutConstraint!
|
|
|
|
|
2021-02-27 20:29:58 -08:00
|
|
|
/// The navigation controller managed by the split view controller, that encloses the immediate navigation controller of the detail view when in compact layout.
|
|
|
|
@objc var parentNavigationController: UINavigationController? {
|
|
|
|
return navigationController?.parent as? UINavigationController
|
|
|
|
}
|
|
|
|
|
2020-11-28 21:28:19 -08:00
|
|
|
/// The feed detail navigation controller in the supplementary pane, loaded from the storyboard.
|
|
|
|
var supplementaryFeedDetailNavigationController: UINavigationController?
|
|
|
|
|
|
|
|
/// The feed detail view controller in the supplementary pane, loaded from the storyboard.
|
|
|
|
var supplementaryFeedDetailViewController: FeedDetailViewController?
|
2020-09-25 20:31:01 -07:00
|
|
|
|
|
|
|
/// The feed detail view controller, if using `top` or `bottom` layout. `nil` if using `left` layout.
|
|
|
|
var feedDetailViewController: FeedDetailViewController?
|
|
|
|
|
2021-01-29 20:10:53 -08:00
|
|
|
/// The horizontal page view controller. [Not currently used; might be used for #1351 (gestures in vertical scrolling).]
|
|
|
|
// var horizontalPageViewController: HorizontalPageViewController?
|
2020-09-25 20:31:01 -07:00
|
|
|
|
2021-01-29 20:10:53 -08:00
|
|
|
/// The story pages view controller, that manages the previous, current, and next story view controllers.
|
|
|
|
var storyPagesViewController: StoryPagesViewController? {
|
|
|
|
return appDelegate.storyPagesViewController
|
2021-01-15 21:26:53 -08:00
|
|
|
}
|
|
|
|
|
2020-10-30 20:58:27 -07:00
|
|
|
/// Returns the currently displayed story view controller, or `nil` if none.
|
|
|
|
@objc var currentStoryController: StoryDetailViewController? {
|
2021-01-29 20:10:53 -08:00
|
|
|
return storyPagesViewController?.currentPage
|
2020-10-30 20:58:27 -07:00
|
|
|
}
|
|
|
|
|
2020-11-28 21:28:19 -08:00
|
|
|
/// Updates the layout; call this when the layout is changed in the preferences.
|
|
|
|
@objc(updateLayoutWithReload:) func updateLayout(reload: Bool) {
|
|
|
|
checkViewControllers()
|
|
|
|
|
|
|
|
appDelegate.feedsViewController.loadOfflineFeeds(false)
|
2021-04-24 20:46:54 -07:00
|
|
|
|
|
|
|
if layout != .left, let controller = feedDetailViewController {
|
2022-04-01 17:54:01 -07:00
|
|
|
if behavior == .overlay {
|
|
|
|
navigationItem.leftBarButtonItems = [controller.feedsBarButton, controller.settingsBarButton]
|
|
|
|
} else {
|
|
|
|
navigationItem.leftBarButtonItems = [controller.settingsBarButton]
|
|
|
|
}
|
2021-04-24 20:46:54 -07:00
|
|
|
} else {
|
|
|
|
navigationItem.leftBarButtonItems = []
|
|
|
|
}
|
2020-11-28 21:28:19 -08:00
|
|
|
}
|
|
|
|
|
2021-01-30 20:33:29 -08:00
|
|
|
/// Update the theme.
|
2021-01-29 21:28:34 -08:00
|
|
|
@objc override func updateTheme() {
|
|
|
|
super.updateTheme()
|
|
|
|
|
|
|
|
guard let manager = ThemeManager.shared else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
manager.update(navigationController)
|
|
|
|
manager.updateBackground(of: view)
|
|
|
|
|
|
|
|
dividerImageView.image = manager.themedImage(UIImage(named: "drag_icon.png"))
|
2021-03-28 16:03:59 -07:00
|
|
|
view.backgroundColor = navigationController?.navigationBar.barTintColor
|
|
|
|
navigationController?.navigationBar.barStyle = manager.isDarkTheme ? .black : .default
|
2021-05-28 20:34:28 -07:00
|
|
|
|
2022-01-28 21:19:00 -08:00
|
|
|
tidyNavigationController()
|
|
|
|
|
2021-05-28 20:34:28 -07:00
|
|
|
// DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
|
|
|
|
// self.findSplitBackButton()
|
|
|
|
// }
|
2021-01-29 21:28:34 -08:00
|
|
|
}
|
|
|
|
|
2021-01-30 20:33:29 -08:00
|
|
|
/// Adjusts the container when autoscrolling. Only applies to iPhone.
|
2020-12-24 16:20:22 -08:00
|
|
|
@objc func adjustForAutoscroll() {
|
2021-01-29 20:10:53 -08:00
|
|
|
if UIDevice.current.userInterfaceIdiom == .phone, let controller = storyPagesViewController, !controller.isNavigationBarHidden {
|
2020-12-24 16:20:22 -08:00
|
|
|
topContainerTopConstraint.constant = -44
|
|
|
|
} else {
|
|
|
|
topContainerTopConstraint.constant = 0
|
|
|
|
}
|
2021-01-30 20:33:29 -08:00
|
|
|
|
|
|
|
updateTheme()
|
2020-12-24 16:20:22 -08:00
|
|
|
}
|
|
|
|
|
2021-05-28 20:34:28 -07:00
|
|
|
// @objc func findSplitBackButton() {
|
|
|
|
// guard let navBar = navigationController?.navigationBar else {
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// let imageViews = recursiveImageSubviews(of: navBar)
|
|
|
|
//
|
|
|
|
// for view in imageViews {
|
|
|
|
// if let imageView = view as? UIImageView, let image = imageView.image, image.description.contains("BackIndicator"), let button = recursiveButtonSuperview(of: imageView) {
|
|
|
|
// print("image view: \(imageView), image: \(String(describing: imageView.image)), button: \(button)")
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// func recursiveImageSubviews(of view: UIView) -> [UIView] {
|
|
|
|
// var subviews = [UIView]()
|
|
|
|
//
|
|
|
|
// for subview in view.subviews {
|
|
|
|
// if subview is UIImageView {
|
|
|
|
// subviews.append(subview)
|
|
|
|
// } else {
|
|
|
|
// subviews.append(contentsOf: recursiveImageSubviews(of: subview))
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// return subviews
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// func recursiveButtonSuperview(of view: UIView) -> UIButton? {
|
|
|
|
// guard let superview = view.superview else {
|
|
|
|
// return nil
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if let button = superview as? UIButton {
|
|
|
|
// return button
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// return recursiveButtonSuperview(of: superview)
|
|
|
|
// }
|
|
|
|
|
2020-10-30 20:58:27 -07:00
|
|
|
override func viewDidLoad() {
|
|
|
|
super.viewDidLoad()
|
|
|
|
|
2020-11-28 21:28:19 -08:00
|
|
|
updateLayout(reload: false)
|
2020-10-30 20:58:27 -07:00
|
|
|
}
|
2020-11-28 21:28:19 -08:00
|
|
|
|
|
|
|
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
|
|
|
super.viewWillTransition(to: size, with: coordinator)
|
2020-09-25 20:31:01 -07:00
|
|
|
|
2020-11-28 21:28:19 -08:00
|
|
|
if layout != .left {
|
|
|
|
coordinator.animate { context in
|
|
|
|
self.dividerViewBottomConstraint.constant = self.dividerPosition
|
|
|
|
}
|
|
|
|
}
|
2020-09-25 20:31:01 -07:00
|
|
|
}
|
|
|
|
|
2020-11-28 21:28:19 -08:00
|
|
|
private var isDraggingDivider = false
|
|
|
|
|
|
|
|
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
|
|
let touch = touches.first
|
|
|
|
|
|
|
|
guard let point = touch?.location(in: view) else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let isInside = dividerView.frame.contains(point)
|
|
|
|
|
|
|
|
guard touch?.view == dividerView || isInside || isDraggingDivider else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
isDraggingDivider = true
|
|
|
|
|
|
|
|
let position = view.frame.height - point.y - 6
|
|
|
|
|
|
|
|
guard position > 150, position < view.frame.height - 200 else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
dividerPosition = position
|
|
|
|
dividerViewBottomConstraint.constant = position
|
|
|
|
view.setNeedsLayout()
|
|
|
|
}
|
|
|
|
|
|
|
|
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
|
|
isDraggingDivider = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private extension DetailViewController {
|
2020-09-25 20:31:01 -07:00
|
|
|
func checkViewControllers() {
|
2020-12-21 20:53:08 -08:00
|
|
|
let isTop = layout == .top
|
|
|
|
|
2020-09-25 20:31:01 -07:00
|
|
|
if layout == .left {
|
2020-11-28 21:28:19 -08:00
|
|
|
if feedDetailViewController != nil {
|
|
|
|
remove(viewController: feedDetailViewController)
|
|
|
|
|
|
|
|
feedDetailViewController = nil
|
2021-04-24 20:46:54 -07:00
|
|
|
appDelegate.feedDetailNavigationController = supplementaryFeedDetailNavigationController
|
2020-11-28 21:28:19 -08:00
|
|
|
appDelegate.feedDetailViewController = supplementaryFeedDetailViewController
|
|
|
|
appDelegate.splitViewController.setViewController(supplementaryFeedDetailNavigationController, for: .supplementary)
|
|
|
|
supplementaryFeedDetailNavigationController = nil
|
|
|
|
supplementaryFeedDetailViewController = nil
|
|
|
|
}
|
2020-09-25 20:31:01 -07:00
|
|
|
|
2020-11-28 21:28:19 -08:00
|
|
|
dividerViewBottomConstraint.constant = -13
|
2020-09-25 20:31:01 -07:00
|
|
|
} else {
|
|
|
|
if feedDetailViewController == nil {
|
|
|
|
feedDetailViewController = Storyboards.shared.controller(withIdentifier: .feedDetail) as? FeedDetailViewController
|
|
|
|
|
2020-12-21 20:53:08 -08:00
|
|
|
add(viewController: feedDetailViewController, top: isTop)
|
2020-11-28 21:28:19 -08:00
|
|
|
|
|
|
|
supplementaryFeedDetailNavigationController = appDelegate.feedDetailNavigationController
|
|
|
|
supplementaryFeedDetailViewController = appDelegate.feedDetailViewController
|
2021-04-24 20:46:54 -07:00
|
|
|
appDelegate.feedDetailNavigationController = nil
|
2020-11-28 21:28:19 -08:00
|
|
|
appDelegate.feedDetailViewController = feedDetailViewController
|
|
|
|
appDelegate.splitViewController.setViewController(nil, for: .supplementary)
|
2020-12-21 20:53:08 -08:00
|
|
|
} else {
|
|
|
|
let appropriateSuperview = isTop ? topContainerView : bottomContainerView
|
|
|
|
|
|
|
|
if feedDetailViewController?.view.superview != appropriateSuperview {
|
|
|
|
add(viewController: feedDetailViewController, top: isTop)
|
|
|
|
}
|
2020-09-25 20:31:01 -07:00
|
|
|
}
|
2020-11-28 21:28:19 -08:00
|
|
|
|
|
|
|
dividerViewBottomConstraint.constant = dividerPosition
|
2022-04-01 17:54:01 -07:00
|
|
|
|
|
|
|
appDelegate.updateSplitBehavior()
|
2020-09-25 20:31:01 -07:00
|
|
|
}
|
|
|
|
|
2021-01-29 20:10:53 -08:00
|
|
|
guard let storyPagesViewController = storyPagesViewController else {
|
|
|
|
return
|
2020-12-21 20:53:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
let appropriateSuperview = isTop ? bottomContainerView : topContainerView
|
|
|
|
|
2021-01-29 20:10:53 -08:00
|
|
|
if storyPagesViewController.view.superview != appropriateSuperview {
|
|
|
|
add(viewController: storyPagesViewController, top: !isTop)
|
2020-09-26 20:30:35 -07:00
|
|
|
|
2020-12-24 16:20:22 -08:00
|
|
|
adjustForAutoscroll()
|
|
|
|
|
2021-01-29 20:10:53 -08:00
|
|
|
// if isTop {
|
|
|
|
// bottomContainerView.addSubview(traverseView)
|
|
|
|
// bottomContainerView.addSubview(autoscrollView)
|
|
|
|
// } else {
|
|
|
|
// topContainerView.addSubview(traverseView)
|
|
|
|
// topContainerView.addSubview(autoscrollView)
|
|
|
|
// }
|
2020-11-28 21:28:19 -08:00
|
|
|
}
|
2021-01-29 20:10:53 -08:00
|
|
|
//
|
|
|
|
// traverseTopContainerBottomConstraint.isActive = !isTop
|
|
|
|
// traverseBottomContainerBottomConstraint.isActive = isTop
|
|
|
|
// autoscrollTopContainerBottomConstraint.isActive = !isTop
|
|
|
|
// autoscrollBottomContainerBottomConstraint.isActive = isTop
|
2020-11-28 21:28:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func add(viewController: UIViewController?, top: Bool) {
|
|
|
|
if top {
|
|
|
|
add(viewController: viewController, to: topContainerView)
|
|
|
|
} else {
|
|
|
|
add(viewController: viewController, to: bottomContainerView)
|
2020-09-25 20:31:01 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-28 21:28:19 -08:00
|
|
|
func add(viewController: UIViewController?, to containerView: UIView) {
|
2020-09-25 20:31:01 -07:00
|
|
|
guard let viewController = viewController else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
addChild(viewController)
|
2020-10-30 20:58:27 -07:00
|
|
|
|
2020-11-28 21:28:19 -08:00
|
|
|
containerView.addSubview(viewController.view)
|
|
|
|
|
2020-10-30 20:58:27 -07:00
|
|
|
viewController.view.translatesAutoresizingMaskIntoConstraints = false
|
2020-11-28 21:28:19 -08:00
|
|
|
viewController.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
|
|
|
|
viewController.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
|
|
|
|
viewController.view.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
|
|
|
|
viewController.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
|
2020-10-30 20:58:27 -07:00
|
|
|
|
2020-09-25 20:31:01 -07:00
|
|
|
viewController.didMove(toParent: self)
|
|
|
|
}
|
|
|
|
|
|
|
|
func remove(viewController: UIViewController?) {
|
|
|
|
guard let viewController = viewController else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
viewController.willMove(toParent: nil)
|
|
|
|
viewController.removeFromParent()
|
|
|
|
viewController.view.removeFromSuperview()
|
|
|
|
}
|
2022-01-28 21:19:00 -08:00
|
|
|
|
|
|
|
/// The status bar portion of the navigation controller isn't the right color, due to a white subview bleeding through the visual effect view. This somewhat hacky function will correct that.
|
|
|
|
func tidyNavigationController() {
|
|
|
|
guard let visualEffectSubviews = navigationController?.navigationBar.subviews.first?.subviews.first?.subviews, visualEffectSubviews.count == 3, visualEffectSubviews[1].alpha == 1 else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
navigationController?.navigationBar.subviews.first?.backgroundColor = UINavigationBar.appearance().backgroundColor
|
|
|
|
}
|
2020-08-27 21:26:12 -07:00
|
|
|
}
|