// // MainTabBarViewController.swift // Tusker // // Created by Shadowfacts on 8/21/18. // Copyright © 2018 Shadowfacts. All rights reserved. // import UIKit import SwiftUI class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate { weak var mastodonController: MastodonController! private var composePlaceholder: UIViewController! private var fastAccountSwitcher: FastAccountSwitcherViewController! var selectedTab: Tab { return Tab(rawValue: selectedIndex)! } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { if UIDevice.current.userInterfaceIdiom == .phone { return .portrait } else { return .all } } init(mastodonController: MastodonController) { self.mastodonController = mastodonController super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() self.delegate = self composePlaceholder = UIViewController() composePlaceholder.title = "Compose" composePlaceholder.tabBarItem.image = UIImage(systemName: "pencil") viewControllers = [ embedInNavigationController(Tab.timelines.createViewController(mastodonController)), embedInNavigationController(Tab.notifications.createViewController(mastodonController)), composePlaceholder, embedInNavigationController(Tab.explore.createViewController(mastodonController)), embedInNavigationController(Tab.myProfile.createViewController(mastodonController)), ] fastAccountSwitcher = FastAccountSwitcherViewController() fastAccountSwitcher.delegate = self fastAccountSwitcher.view.translatesAutoresizingMaskIntoConstraints = false view.addSubview(fastAccountSwitcher.view) NSLayoutConstraint.activate([ fastAccountSwitcher.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), fastAccountSwitcher.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), fastAccountSwitcher.view.topAnchor.constraint(equalTo: view.topAnchor), fastAccountSwitcher.view.bottomAnchor.constraint(equalTo: tabBar.topAnchor), ]) tabBar.addGestureRecognizer(fastAccountSwitcher.createSwitcherGesture()) let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(tabBarTapped)) tapRecognizer.cancelsTouchesInView = false tabBar.addGestureRecognizer(tapRecognizer) } @objc private func tabBarTapped(_ recognizer: UITapGestureRecognizer) { fastAccountSwitcher.hide() } func embedInNavigationController(_ vc: UIViewController) -> UINavigationController { if let vc = vc as? UINavigationController { return vc } else { return EnhancedNavigationViewController(rootViewController: vc) } } func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool { if viewController == composePlaceholder { presentCompose() return false } if viewController == viewControllers![selectedIndex], let nav = viewController as? UINavigationController, nav.viewControllers.count == 1, let scrollableVC = nav.viewControllers.first as? TabBarScrollableViewController { scrollableVC.tabBarScrollToTop() return false } return true } func setViewController(_ viewController: UIViewController, forTab tab: Tab) { viewControllers![tab.rawValue] = viewController } func viewController(for tab: Tab) -> UIViewController { return viewControllers![tab.rawValue] } } extension MainTabBarViewController { enum Tab: Int, Hashable, CaseIterable { case timelines case notifications case compose case explore case myProfile func createViewController(_ mastodonController: MastodonController) -> UIViewController { switch self { case .timelines: return TimelinesPageViewController(mastodonController: mastodonController) case .notifications: return NotificationsPageViewController(mastodonController: mastodonController) case .compose: return ComposeHostingController(mastodonController: mastodonController) case .explore: return ExploreViewController(mastodonController: mastodonController) case .myProfile: return MyProfileViewController(mastodonController: mastodonController) } } } func getTabController(tab: Tab) -> UIViewController? { if tab == .compose { return nil } else { return viewControllers![tab.rawValue] } } } extension MainTabBarViewController: FastAccountSwitcherViewControllerDelegate { func fastAccountSwitcher(_ fastAccountSwitcher: FastAccountSwitcherViewController, triggerZoneContains point: CGPoint) -> Bool { let tabBarButtons = tabBar.subviews.filter { String(describing: type(of: $0)).lowercased().contains("button") } // sanity check that there is 1 button per VC guard tabBarButtons.count == viewControllers!.count, let myProfileButton = tabBarButtons.last else { return false } let locationInButton = myProfileButton.convert(point, from: fastAccountSwitcher.view) return myProfileButton.bounds.contains(locationInButton) } } extension MainTabBarViewController: TuskerRootViewController { func presentCompose() { let vc = ComposeHostingController(mastodonController: mastodonController) let nav = EnhancedNavigationViewController(rootViewController: vc) nav.presentationController?.delegate = vc present(nav, animated: true) } func select(tab: Tab) { if tab == .compose { presentCompose() } else { selectedIndex = tab.rawValue } } } extension MainTabBarViewController: BackgroundableViewController { func sceneDidEnterBackground() { if let selectedVC = selectedViewController as? BackgroundableViewController { selectedVC.sceneDidEnterBackground() } } }