Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix controllers not popping when pressing a tab bar button #53

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions trySwift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
499CCFF21CC2E0F4007A5BBB /* UIViewControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 499CCFF11CC2E0F4007A5BBB /* UIViewControllerExtension.swift */; };
49F7B2811E8475F900F09768 /* SplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49F7B2801E8475F900F09768 /* SplitViewController.swift */; };
4D498DB1B98D4B496FDBB7AA /* Pods_try__Extension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD2E9D5733A6E1B6E10AFEEF /* Pods_try__Extension.framework */; };
5C7F82DB2048B01D009193B4 /* RootTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7F82DA2048B01D009193B4 /* RootTabBarController.swift */; };
5CDB20792048952A00C3E0D3 /* TwitterFollowDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDB20782048952A00C3E0D3 /* TwitterFollowDelegate.swift */; };
7AD1E19C80B78BB08E3DF079 /* Pods_trySwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 620220ABCCCDF47FDAF48B67 /* Pods_trySwift.framework */; };
EAFE1C26E49EFABF83487BDC /* Pods_try__Today.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24718BF11477753FCD47A7A8 /* Pods_try__Today.framework */; };
Expand Down Expand Up @@ -194,6 +195,7 @@
499CCFF11CC2E0F4007A5BBB /* UIViewControllerExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewControllerExtension.swift; sourceTree = "<group>"; };
49F7B2801E8475F900F09768 /* SplitViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplitViewController.swift; sourceTree = "<group>"; };
58F81AD508535BD405F98215 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
5C7F82DA2048B01D009193B4 /* RootTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootTabBarController.swift; sourceTree = "<group>"; };
5CDB20782048952A00C3E0D3 /* TwitterFollowDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwitterFollowDelegate.swift; sourceTree = "<group>"; };
5FA07FBC036240AEF8B7C739 /* Pods-trySwift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-trySwift.release.xcconfig"; path = "Pods/Target Support Files/Pods-trySwift/Pods-trySwift.release.xcconfig"; sourceTree = "<group>"; };
620220ABCCCDF47FDAF48B67 /* Pods_trySwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_trySwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -383,6 +385,14 @@
name = Frameworks;
sourceTree = "<group>";
};
5C7F82D92048B00B009193B4 /* RootTabBar */ = {
isa = PBXGroup;
children = (
5C7F82DA2048B01D009193B4 /* RootTabBarController.swift */,
);
path = RootTabBar;
sourceTree = "<group>";
};
5CDB20772048951F00C3E0D3 /* Twitter */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -425,6 +435,7 @@
FA39E8C51C6AB7310074B6BE /* ViewControllers */ = {
isa = PBXGroup;
children = (
5C7F82D92048B00B009193B4 /* RootTabBar */,
FA39E8FB1C6C26150074B6BE /* Schedule */,
FA39E9061C6C43480074B6BE /* Speakers */,
FABA73BF1D6D9ACE0081D887 /* OfficeHours */,
Expand Down Expand Up @@ -1138,6 +1149,7 @@
files = (
5CDB20792048952A00C3E0D3 /* TwitterFollowDelegate.swift in Sources */,
499BD62A1D05910200E74061 /* Twitter.swift in Sources */,
5C7F82DB2048B01D009193B4 /* RootTabBarController.swift in Sources */,
FA39E90F1C6C81870074B6BE /* SponsorsViewController.swift in Sources */,
FA36B7071E5DA3970022E6A9 /* DateFormatterExtension.swift in Sources */,
FAA54F141D9130F900EC9E80 /* UITableViewExtension.swift in Sources */,
Expand Down
4 changes: 2 additions & 2 deletions trySwift/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Tab Bar Controller-->
<!--Root Tab Bar Controller-->
<scene sceneID="mld-K4-cXp">
<objects>
<tabBarController id="Xe8-8h-xaI" sceneMemberID="viewController">
<tabBarController id="Xe8-8h-xaI" customClass="RootTabBarController" customModule="trySwift" customModuleProvider="target" sceneMemberID="viewController">
<tabBar key="tabBar" contentMode="scaleToFill" id="Iea-je-7kA">
<rect key="frame" x="0.0" y="0.0" width="320" height="49"/>
<autoresizingMask key="autoresizingMask"/>
Expand Down
61 changes: 61 additions & 0 deletions trySwift/RootTabBar/RootTabBarController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//
// RootTabBarController.swift
// trySwift
//
// Created by Sash Zats on 3/2/18.
// Copyright © 2018 NatashaTheRobot. All rights reserved.
//

import UIKit

class RootTabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}

func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
guard
let splitViewController = viewController as? UISplitViewController,
let navigationController = splitViewController.viewControllers.last as? UINavigationController
else {
return
}

// if several view controllers are in the stack, pop to the root
if navigationController.viewControllers.count > 1 {
navigationController.popToRootViewController(animated: true)
} else {
// if there's at least one view controller in the stack (which there always should be)
if let firstController = navigationController.viewControllers.first {
// we either delegate to the controller since it knows better how to scroll to the top
if let scrollableToTop = firstController as? ScrollableToTop {
scrollableToTop.scrollAfterTabTap()
// or we find the topmost scroll view and scroll it to the top
} else {
firstController.view.findScrollSubview()?.setContentOffset(.zero, animated: true)
}
}
}
}
}

protocol ScrollableToTop {
func scrollAfterTabTap()
}

private extension UIView {
func findScrollSubview() -> UIScrollView? {
if let scrollView = self as? UIScrollView,
scrollView.contentSize.width < scrollView.contentSize.height {
return scrollView
}
for subview in self.subviews {
if let scrollView = subview.findScrollSubview(),
scrollView.contentSize.width < scrollView.contentSize.height {
return scrollView
}
}
return nil
}
}
26 changes: 7 additions & 19 deletions trySwift/ScheduleViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ class ScheduleViewController: ButtonBarPagerTabStripViewController {
buttonBarView.backgroundColor = .white
settings.style.selectedBarBackgroundColor = .white
buttonBarView.selectedBar.backgroundColor = .trySwiftAccentColor()

tabBarController?.delegate = self
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this since it's handled at a higher level now (RootTabBarController delegates this functionality via protocol conformance now)

}

override func viewDidAppear(_ animated: Bool) {
Expand All @@ -47,7 +45,6 @@ class ScheduleViewController: ButtonBarPagerTabStripViewController {

override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
return days.map { SessionsTableViewController(conferenceDay: $0, scheduleViewController: self) }

}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
Expand All @@ -59,6 +56,13 @@ class ScheduleViewController: ButtonBarPagerTabStripViewController {
}
}

extension ScheduleViewController: ScrollableToTop {
func scrollAfterTabTap() {
let controller = viewControllers[currentIndex] as! SessionsTableViewController
controller.scrollAfterTabTap()
}
}

private extension ScheduleViewController {

@discardableResult
Expand All @@ -77,19 +81,3 @@ private extension ScheduleViewController {
}
}

extension ScheduleViewController: UITabBarControllerDelegate {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see the comment above, this functionality is handled in a RootTabBarController now

func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
guard
tabBarController.selectedViewController === viewController,
navigationController?.viewControllers.last === self
else { return true }

guard
let index = moveToCorrectDate(animated: true),
let controller = viewControllers[index] as? SessionsTableViewController
else { return true }
controller.scrollToCurrentSession(animated: true)

return true
}
}
55 changes: 31 additions & 24 deletions trySwift/SessionsTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import UIKit
import XLPagerTabStrip
import TrySwiftData


class SessionsTableViewController: UITableViewController {
private lazy var needsToScrollToCurrentSession = Calendar.current.isDateInToday(conferenceDay.date)

Expand All @@ -33,15 +34,15 @@ class SessionsTableViewController: UITableViewController {
super.viewDidLoad()

configureTableView()

if traitCollection.forceTouchCapability == .available {
registerForPreviewing(with: self, sourceView: tableView)
}
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

if needsToScrollToCurrentSession {
needsToScrollToCurrentSession = false
scrollToCurrentSession(animated: false)
Expand All @@ -55,32 +56,32 @@ class SessionsTableViewController: UITableViewController {
let isCollapsed = splitViewController?.isCollapsed,
!isCollapsed,
!didShowDetail else { return }

didShowDetail = true
scheduleViewController?.performSegue(withIdentifier: sessionDetailsSegue, sender: firstSelectableSessionVC)
}
}

// MARK: - Table view data source
extension SessionsTableViewController {

override func numberOfSections(in tableView: UITableView) -> Int {
return conferenceDay.sessionBlocks.count
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return conferenceDay.sessionBlocks[section].sessions.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(forIndexPath: indexPath) as SessionTableViewCell

let session = conferenceDay.sessionBlocks[indexPath.section].sessions[indexPath.row]
cell.configure(withSession: session)

return cell
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let session = conferenceDay.sessionBlocks[section]
let sessionDateFormatter = DateFormatter.sessionDateFormatter
Expand Down Expand Up @@ -108,33 +109,33 @@ extension SessionsTableViewController: IndicatorInfoProvider {
}

extension SessionsTableViewController: UIViewControllerPreviewingDelegate {

func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = tableView.indexPathForRow(at: location) else { return nil }
// This will show the cell clearly and blur the rest of the screen for our peek.
previewingContext.sourceRect = tableView.rectForRow(at: indexPath)
let session = conferenceDay.sessionBlocks[indexPath.section].sessions[indexPath.row]
return viewController(for: session)
}

func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
scheduleViewController?.performSegue(withIdentifier: sessionDetailsSegue, sender: viewControllerToCommit)
}
}

extension SessionsTableViewController {

func configureTableView() {

tableView.register(SessionTableViewCell.self)

tableView.estimatedRowHeight = 160
tableView.rowHeight = UITableViewAutomaticDimension
}
}

private extension SessionsTableViewController {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not to brag but phabricator has a feature of hiding whitespace changes in review - it's pretty cool because it minimizes noise like this in review. I remember there was some sort of secret url parameter when reviewing pull requests… but to be honest I don't even know when I would want to see whitespace changes 🙂

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


func viewController(for session: Session) -> UIViewController? {
switch session.type {
case .talk, .lightningTalk:
Expand Down Expand Up @@ -174,39 +175,39 @@ private extension SessionsTableViewController {
default:
return nil
}

return nil
}

func sessionDetails(_ presentation: Presentation, session: Session) -> UIViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let sessionDetailsVC = storyboard.instantiateViewController(withIdentifier: String(describing: SessionDetailsViewController.self)) as! SessionDetailsViewController
sessionDetailsVC.session = session
sessionDetailsVC.presentation = presentation
return sessionDetailsVC
}

func officeHourDetails(_ speaker: Speaker, session: Session) -> UIViewController {
let officeHoursVC = OfficeHoursDetailViewController()
officeHoursVC.speaker = speaker
officeHoursVC.session = session
return officeHoursVC
}

func webDisplay(_ event: Event) -> UIViewController {
let webViewController = WebDisplayViewController()
webViewController.url = URL(string: event.website!)
webViewController.displayTitle = event.title
return webViewController
}

func webDisplay(_ sponsor: Sponsor) -> UIViewController {
let webViewController = WebDisplayViewController()
webViewController.url = URL(string: sponsor.url!)
webViewController.displayTitle = sponsor.name
return webViewController
}

func venueDetails(_ venue: Venue) -> UIViewController {
let venueDetailsVC = VenueTableViewController(venue: venue)
venueDetailsVC.tableView.contentInset = UIEdgeInsets(top: 80,left: 0,bottom: 0,right: 0)
Expand All @@ -224,15 +225,21 @@ private extension SessionsTableViewController {
}

extension SessionsTableViewController {

func scrollToCurrentSession(animated: Bool) {
let secondsFromGMT = TimeZone.current.secondsFromGMT()
guard
let date = Date().changed(second: secondsFromGMT),
let section = conferenceDay.sessionBlocks.index(where: { date < $0.endTime }),
!conferenceDay.sessionBlocks[section].sessions.isEmpty
else { return }

tableView.scrollToRow(at: IndexPath(row: 0, section: section), at: .top, animated: animated)
}
}

extension SessionsTableViewController: ScrollableToTop {
func scrollAfterTabTap() {
scrollToCurrentSession(animated: true)
}
}