diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index 3f01be44..7b653611 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -186,6 +186,7 @@ D67895C0246870DE00D4CD9E /* LocalAccountAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67895BF246870DE00D4CD9E /* LocalAccountAvatarView.swift */; }; D679C09F215850EF00DA27FE /* XCBActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D679C09E215850EF00DA27FE /* XCBActions.swift */; }; D67B506D250B291200FAECFB /* BlurHashDecode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67B506C250B291200FAECFB /* BlurHashDecode.swift */; }; + D67C1795266D57D10070F250 /* FastAccountSwitcherIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67C1794266D57D10070F250 /* FastAccountSwitcherIndicatorView.swift */; }; D67C57AD21E265FC00C3118B /* LargeAccountDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67C57AC21E265FC00C3118B /* LargeAccountDetailView.swift */; }; D67C57AF21E28EAD00C3118B /* Array+Uniques.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */; }; D68015402401A6BA00D6103B /* ComposingPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D680153F2401A6BA00D6103B /* ComposingPrefsView.swift */; }; @@ -587,6 +588,7 @@ D67895BF246870DE00D4CD9E /* LocalAccountAvatarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAccountAvatarView.swift; sourceTree = ""; }; D679C09E215850EF00DA27FE /* XCBActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCBActions.swift; sourceTree = ""; }; D67B506C250B291200FAECFB /* BlurHashDecode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = ""; }; + D67C1794266D57D10070F250 /* FastAccountSwitcherIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FastAccountSwitcherIndicatorView.swift; sourceTree = ""; }; D67C57AC21E265FC00C3118B /* LargeAccountDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeAccountDetailView.swift; sourceTree = ""; }; D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Uniques.swift"; sourceTree = ""; }; D680153F2401A6BA00D6103B /* ComposingPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposingPrefsView.swift; sourceTree = ""; }; @@ -1449,6 +1451,7 @@ D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameLabel.swift */, D6E426B225337C7000C02E1C /* CustomEmojiImageView.swift */, D6EAE0DA2550CC8A002DB0AC /* FocusableTextField.swift */, + D67C1794266D57D10070F250 /* FastAccountSwitcherIndicatorView.swift */, D67C57A721E2649B00C3118B /* Account Detail */, D626494023C122C800612E6E /* Asset Picker */, D61959D0241E842400A37B8E /* Draft Cell */, @@ -2168,6 +2171,7 @@ D6AEBB432321685E00E5038B /* OpenInSafariActivity.swift in Sources */, D6C693FE2162FEEA007D6A6D /* UIViewController+Children.swift in Sources */, D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */, + D67C1795266D57D10070F250 /* FastAccountSwitcherIndicatorView.swift in Sources */, D627FF76217E923E00CC0648 /* DraftsManager.swift in Sources */, D64F80E2215875CC00BEF393 /* XCBActionType.swift in Sources */, 04586B4322B301470021BD04 /* AppearancePrefsView.swift in Sources */, diff --git a/Tusker/Screens/Main/MainTabBarViewController.swift b/Tusker/Screens/Main/MainTabBarViewController.swift index dead5878..b0e276b0 100644 --- a/Tusker/Screens/Main/MainTabBarViewController.swift +++ b/Tusker/Screens/Main/MainTabBarViewController.swift @@ -15,6 +15,9 @@ class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate { private var composePlaceholder: UIViewController! private var fastAccountSwitcher: FastAccountSwitcherViewController! + private var fastSwitcherIndicator: FastAccountSwitcherIndicatorView! + private var fastSwitcherConstraints: [NSLayoutConstraint] = [] + var selectedTab: Tab { return Tab(rawValue: selectedIndex)! } @@ -70,9 +73,62 @@ class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate { tapRecognizer.cancelsTouchesInView = false tabBar.addGestureRecognizer(tapRecognizer) + if findMyProfileTabBarButton() != nil { + fastSwitcherIndicator = FastAccountSwitcherIndicatorView() + fastSwitcherIndicator.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(fastSwitcherIndicator) + NSLayoutConstraint.activate([ + fastSwitcherIndicator.widthAnchor.constraint(equalToConstant: 10), + fastSwitcherIndicator.heightAnchor.constraint(equalToConstant: 12), + ]) + } + tabBar.isSpringLoaded = true } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + repositionFastSwitcherIndicator() + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + repositionFastSwitcherIndicator() + } + + private func repositionFastSwitcherIndicator() { + guard let myProfileButton = findMyProfileTabBarButton() else { + return + } + NSLayoutConstraint.deactivate(fastSwitcherConstraints) + // using interfaceOrientation isn't ideal, but UITabBar buttons may lay out horizontally even in the compact size class + if traitCollection.horizontalSizeClass == .compact && interfaceOrientation.isPortrait { + fastSwitcherConstraints = [ + fastSwitcherIndicator.centerYAnchor.constraint(equalTo: myProfileButton.centerYAnchor, constant: -4), + // tab bar button image width is 30 + fastSwitcherIndicator.leftAnchor.constraint(equalTo: myProfileButton.centerXAnchor, constant: 15 + 2), + ] + } else { + fastSwitcherConstraints = [ + fastSwitcherIndicator.centerYAnchor.constraint(equalTo: myProfileButton.centerYAnchor), + fastSwitcherIndicator.trailingAnchor.constraint(equalTo: myProfileButton.trailingAnchor), + ] + } + NSLayoutConstraint.activate(fastSwitcherConstraints) + } + + private func findMyProfileTabBarButton() -> UIView? { + 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 nil + } + return myProfileButton + } + @objc private func tabBarTapped(_ recognizer: UITapGestureRecognizer) { fastAccountSwitcher.hide() } @@ -146,13 +202,9 @@ extension MainTabBarViewController { 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 { + guard let myProfileButton = findMyProfileTabBarButton() else { return false } - let locationInButton = myProfileButton.convert(point, from: fastAccountSwitcher.view) return myProfileButton.bounds.contains(locationInButton) } diff --git a/Tusker/Views/FastAccountSwitcherIndicatorView.swift b/Tusker/Views/FastAccountSwitcherIndicatorView.swift new file mode 100644 index 00000000..e2100747 --- /dev/null +++ b/Tusker/Views/FastAccountSwitcherIndicatorView.swift @@ -0,0 +1,30 @@ +// +// FastAccountSwitchingIndicatorView.swift +// Tusker +// +// Created by Shadowfacts on 6/6/21. +// Copyright © 2021 Shadowfacts. All rights reserved. +// + +import UIKit + +class FastAccountSwitcherIndicatorView: UIView { + + override init(frame: CGRect) { + super.init(frame: frame) + + tintColor = .lightGray + + let up = UIImageView(image: UIImage(systemName: "arrowtriangle.up.fill")!) + up.frame = CGRect(x: 0, y: 0, width: 10, height: 5) + addSubview(up) + let down = UIImageView(image: UIImage(systemName: "arrowtriangle.down.fill")!) + down.frame = CGRect(x: 0, y: 7, width: 10, height: 5) + addSubview(down) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +}