Compare commits

..

No commits in common. "473ef018c9a815c5de1ddfc1bcadbf6002f47cee" and "203c1852d4d0bce087358626b1c5b2b8efd498f7" have entirely different histories.

5 changed files with 27 additions and 29 deletions

View File

@ -8,6 +8,8 @@
import UIKit import UIKit
public protocol DuckableViewController: UIViewController { public protocol DuckableViewController: UIViewController {
var duckableDelegate: DuckableViewControllerDelegate? { get set }
func duckableViewControllerShouldDuck() -> DuckAttemptAction func duckableViewControllerShouldDuck() -> DuckAttemptAction
func duckableViewControllerMayAttemptToDuck() func duckableViewControllerMayAttemptToDuck()
@ -24,6 +26,10 @@ extension DuckableViewController {
public func duckableViewControllerDidFinishAnimatingDuck() {} public func duckableViewControllerDidFinishAnimatingDuck() {}
} }
public protocol DuckableViewControllerDelegate: AnyObject {
func duckableViewControllerWillDismiss(animated: Bool)
}
public enum DuckAttemptAction { public enum DuckAttemptAction {
case duck case duck
case dismiss case dismiss

View File

@ -11,7 +11,7 @@ let duckedCornerRadius: CGFloat = 10
let detentHeight: CGFloat = 44 let detentHeight: CGFloat = 44
@available(iOS 16.0, *) @available(iOS 16.0, *)
public class DuckableContainerViewController: UIViewController { public class DuckableContainerViewController: UIViewController, DuckableViewControllerDelegate {
public let child: UIViewController public let child: UIViewController
private var bottomConstraint: NSLayoutConstraint! private var bottomConstraint: NSLayoutConstraint!
@ -87,6 +87,7 @@ public class DuckableContainerViewController: UIViewController {
} }
private func doPresentDuckable(_ viewController: DuckableViewController, animated: Bool, completion: (() -> Void)?) { private func doPresentDuckable(_ viewController: DuckableViewController, animated: Bool, completion: (() -> Void)?) {
viewController.duckableDelegate = self
viewController.modalPresentationStyle = .custom viewController.modalPresentationStyle = .custom
viewController.transitioningDelegate = self viewController.transitioningDelegate = self
present(viewController, animated: animated) { present(viewController, animated: animated) {
@ -95,10 +96,7 @@ public class DuckableContainerViewController: UIViewController {
} }
} }
func dismissalTransitionWillBegin() { public func duckableViewControllerWillDismiss(animated: Bool) {
guard case .presentingDucked(_, _) = state else {
return
}
state = .idle state = .idle
bottomConstraint.isActive = false bottomConstraint.isActive = false
bottomConstraint = child.view.bottomAnchor.constraint(equalTo: view.bottomAnchor) bottomConstraint = child.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
@ -146,7 +144,7 @@ public class DuckableContainerViewController: UIViewController {
case .block: case .block:
viewController.sheetPresentationController!.selectedDetentIdentifier = .large viewController.sheetPresentationController!.selectedDetentIdentifier = .large
case .dismiss: case .dismiss:
// duckableViewControllerWillDismiss() duckableViewControllerWillDismiss(animated: true)
dismiss(animated: true) dismiss(animated: true)
} }
} }
@ -191,7 +189,7 @@ public class DuckableContainerViewController: UIViewController {
@available(iOS 16.0, *) @available(iOS 16.0, *)
extension DuckableContainerViewController: UIViewControllerTransitioningDelegate { extension DuckableContainerViewController: UIViewControllerTransitioningDelegate {
public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
let controller = DuckableSheetPresentationController(presentedViewController: presented, presenting: presenting) let controller = UISheetPresentationController(presentedViewController: presented, presenting: presenting)
controller.delegate = self controller.delegate = self
controller.prefersGrabberVisible = true controller.prefersGrabberVisible = true
controller.selectedDetentIdentifier = .large controller.selectedDetentIdentifier = .large
@ -217,14 +215,6 @@ extension DuckableContainerViewController: UIViewControllerTransitioningDelegate
} }
} }
@available(iOS 16.0, *)
class DuckableSheetPresentationController: UISheetPresentationController {
override func dismissalTransitionWillBegin() {
super.dismissalTransitionWillBegin()
(self.delegate as! DuckableContainerViewController).dismissalTransitionWillBegin()
}
}
@available(iOS 16.0, *) @available(iOS 16.0, *)
extension DuckableContainerViewController: UISheetPresentationControllerDelegate { extension DuckableContainerViewController: UISheetPresentationControllerDelegate {
public func presentationController(_ presentationController: UIPresentationController, willPresentWithAdaptiveStyle style: UIModalPresentationStyle, transitionCoordinator: UIViewControllerTransitionCoordinator?) { public func presentationController(_ presentationController: UIPresentationController, willPresentWithAdaptiveStyle style: UIModalPresentationStyle, transitionCoordinator: UIViewControllerTransitionCoordinator?) {

View File

@ -23,6 +23,7 @@ protocol ComposeHostingControllerDelegate: AnyObject {
class ComposeHostingController: UIHostingController<ComposeHostingController.View>, DuckableViewController { class ComposeHostingController: UIHostingController<ComposeHostingController.View>, DuckableViewController {
weak var delegate: ComposeHostingControllerDelegate? weak var delegate: ComposeHostingControllerDelegate?
weak var duckableDelegate: DuckableViewControllerDelegate?
let controller: ComposeController let controller: ComposeController
let mastodonController: MastodonController let mastodonController: MastodonController
@ -106,6 +107,7 @@ class ComposeHostingController: UIHostingController<ComposeHostingController.Vie
return return
} else { } else {
dismiss(animated: true) dismiss(animated: true)
duckableDelegate?.duckableViewControllerWillDismiss(animated: true)
} }
} }

View File

@ -225,7 +225,7 @@ extension MainSplitViewController: UISplitViewControllerDelegate {
case let .tab(tab): case let .tab(tab):
// sidebar items that map 1 <-> 1 can be transferred directly // sidebar items that map 1 <-> 1 can be transferred directly
tabBarViewController.select(tab: tab, dismissPresented: false) tabBarViewController.select(tab: tab)
case .explore: case .explore:
// Search sidebar item maps to the Explore tab with the search controller/results visible // Search sidebar item maps to the Explore tab with the search controller/results visible
@ -268,10 +268,10 @@ extension MainSplitViewController: UISplitViewControllerDelegate {
// Transfer the navigation stack, dropping the search VC, to keep anything the user has opened // Transfer the navigation stack, dropping the search VC, to keep anything the user has opened
transferNavigationStack(from: .explore, to: exploreNav, dropFirst: true, append: true) transferNavigationStack(from: .explore, to: exploreNav, dropFirst: true, append: true)
tabBarViewController.select(tab: .explore, dismissPresented: false) tabBarViewController.select(tab: .explore)
case .bookmarks, .favorites, .list(_), .savedHashtag(_), .savedInstance(_): case .bookmarks, .favorites, .list(_), .savedHashtag(_), .savedInstance(_):
tabBarViewController.select(tab: .explore, dismissPresented: false) tabBarViewController.select(tab: .explore)
// Make sure the Explore VC doesn't show its search bar when it appears, in case the user was previously // Make sure the Explore VC doesn't show its search bar when it appears, in case the user was previously
// in compact mode and performing a search. // in compact mode and performing a search.
let exploreNav = tabBarViewController.viewController(for: .explore) as! UINavigationController let exploreNav = tabBarViewController.viewController(for: .explore) as! UINavigationController

View File

@ -111,13 +111,13 @@ class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate {
repositionFastSwitcherIndicator() repositionFastSwitcherIndicator()
} }
func select(tab: Tab, dismissPresented: Bool) { func select(tab: Tab) {
if tab == .compose { if tab == .compose {
compose(editing: nil) compose(editing: nil)
} else { } else {
// when switching tabs, dismiss the currently presented VC // when switching tabs, dismiss the currently presented VC
// otherwise the selected tab changes behind the presented VC // otherwise the selected tab changes behind the presented VC
if presentedViewController != nil && dismissPresented { if presentedViewController != nil {
dismiss(animated: true) { dismiss(animated: true) {
self.selectedIndex = tab.rawValue self.selectedIndex = tab.rawValue
} }
@ -141,8 +141,8 @@ class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate {
return return
} }
NSLayoutConstraint.deactivate(fastSwitcherConstraints) NSLayoutConstraint.deactivate(fastSwitcherConstraints)
let isPortrait = view.bounds.width < view.bounds.height // using interfaceOrientation isn't ideal, but UITabBar buttons may lay out horizontally even in the compact size class
if traitCollection.horizontalSizeClass == .compact && isPortrait { if traitCollection.horizontalSizeClass == .compact && interfaceOrientation.isPortrait {
fastSwitcherConstraints = [ fastSwitcherConstraints = [
fastSwitcherIndicator.centerYAnchor.constraint(equalTo: myProfileButton.centerYAnchor, constant: -4), fastSwitcherIndicator.centerYAnchor.constraint(equalTo: myProfileButton.centerYAnchor, constant: -4),
// tab bar button image width is 30 // tab bar button image width is 30
@ -291,18 +291,18 @@ extension MainTabBarViewController: TuskerRootViewController {
func select(route: TuskerRoute, animated: Bool) { func select(route: TuskerRoute, animated: Bool) {
switch route { switch route {
case .timelines: case .timelines:
select(tab: .timelines, dismissPresented: true) select(tab: .timelines)
case .notifications: case .notifications:
select(tab: .notifications, dismissPresented: true) select(tab: .notifications)
case .myProfile: case .myProfile:
select(tab: .myProfile, dismissPresented: true) select(tab: .myProfile)
case .explore: case .explore:
select(tab: .explore, dismissPresented: true) select(tab: .explore)
case .bookmarks: case .bookmarks:
select(tab: .explore, dismissPresented: true) select(tab: .explore)
getNavigationController().pushViewController(BookmarksViewController(mastodonController: mastodonController), animated: animated) getNavigationController().pushViewController(BookmarksViewController(mastodonController: mastodonController), animated: animated)
case .list(id: let id): case .list(id: let id):
select(tab: .explore, dismissPresented: true) select(tab: .explore)
if let list = mastodonController.getCachedList(id: id) { if let list = mastodonController.getCachedList(id: id) {
let nav = getNavigationController() let nav = getNavigationController()
_ = nav.popToRootViewController(animated: animated) _ = nav.popToRootViewController(animated: animated)
@ -325,7 +325,7 @@ extension MainTabBarViewController: TuskerRootViewController {
return return
} }
select(tab: .explore, dismissPresented: true) select(tab: .explore)
exploreNavController.popToRootViewController(animated: false) exploreNavController.popToRootViewController(animated: false)
// setting searchController.isActive directly doesn't work until the view has loaded/appeared for the first time // setting searchController.isActive directly doesn't work until the view has loaded/appeared for the first time