session-ios/SessionUIKit/Components/TabBar.swift
Morgan Pretty 823006a892 Updated the colours to source from direct theme values (instead of individual)
Removed an unused notification
Refactored the PrivacySettingsViewController
Refactored the ScreenLock code to Swift
Fixed an issue where the match dark/light setting wasn't getting applied on launch
Update the modal styling for the various settings modals
2022-08-24 17:33:10 +10:00

135 lines
4.8 KiB
Swift

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
public final class TabBar: UIView {
private let tabs: [Tab]
private var accentLineViewHorizontalCenteringConstraint: NSLayoutConstraint!
private var accentLineViewWidthConstraint: NSLayoutConstraint!
// MARK: - Components
private lazy var tabLabels: [UILabel] = tabs.map { tab in
let result = UILabel()
result.font = .boldSystemFont(ofSize: Values.mediumFontSize)
result.text = tab.title
result.themeTextColor = .textPrimary
result.textAlignment = .center
result.alpha = Values.mediumOpacity
result.set(.height, to: TabBar.snHeight - Values.separatorThickness - Values.accentLineThickness)
return result
}
private lazy var accentLineView: UIView = {
let result = UIView()
result.themeBackgroundColor = .primary
return result
}()
// MARK: - Types
public struct Tab {
let title: String
let onTap: () -> Void
public init(title: String, onTap: @escaping () -> Void) {
self.title = title
self.onTap = onTap
}
}
// MARK: - Settings
public static let snHeight = isIPhone5OrSmaller ? CGFloat(32) : CGFloat(48)
// MARK: - Lifecycle
public init(tabs: [Tab]) {
self.tabs = tabs
super.init(frame: CGRect.zero)
setUpViewHierarchy()
}
public override init(frame: CGRect) {
preconditionFailure("Use init(tabs:) instead.")
}
public required init?(coder: NSCoder) {
preconditionFailure("Use init(tabs:) instead.")
}
private func setUpViewHierarchy() {
set(.height, to: TabBar.snHeight)
tabLabels.forEach { tabLabel in
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTabLabelTapped(_:)))
tabLabel.addGestureRecognizer(tapGestureRecognizer)
}
let tabLabelStackView = UIStackView(arrangedSubviews: tabLabels)
tabLabelStackView.axis = .horizontal
tabLabelStackView.distribution = .fillEqually
tabLabelStackView.spacing = Values.mediumSpacing
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTabLabelTapped(_:)))
tabLabelStackView.addGestureRecognizer(tapGestureRecognizer)
tabLabelStackView.set(.height, to: TabBar.snHeight - Values.separatorThickness - Values.accentLineThickness)
addSubview(tabLabelStackView)
let separator = UIView()
separator.themeBackgroundColor = .borderSeparator
separator.set(.height, to: Values.separatorThickness)
addSubview(separator)
accentLineView.set(.height, to: Values.accentLineThickness)
addSubview(accentLineView)
tabLabelStackView.pin(.leading, to: .leading, of: self)
tabLabelStackView.pin(.top, to: .top, of: self)
pin(.trailing, to: .trailing, of: tabLabelStackView)
separator.pin(.leading, to: .leading, of: self)
separator.pin(.top, to: .bottom, of: tabLabelStackView)
pin(.trailing, to: .trailing, of: separator)
accentLineView.translatesAutoresizingMaskIntoConstraints = false
selectTab(at: 0, withAnimatedTransition: false)
accentLineView.pin(.top, to: .bottom, of: separator)
pin(.bottom, to: .bottom, of: accentLineView)
}
// MARK: - Updating
public func selectTab(at index: Int, withAnimatedTransition isAnimated: Bool = true) {
let tabLabel = tabLabels[index]
accentLineViewHorizontalCenteringConstraint?.isActive = false
accentLineViewHorizontalCenteringConstraint = accentLineView.centerXAnchor.constraint(equalTo: tabLabel.centerXAnchor)
accentLineViewHorizontalCenteringConstraint.isActive = true
accentLineViewWidthConstraint?.isActive = false
accentLineViewWidthConstraint = accentLineView.widthAnchor.constraint(equalTo: tabLabel.widthAnchor)
accentLineViewWidthConstraint.isActive = true
var tabLabelsCopy = tabLabels
tabLabelsCopy.remove(at: index)
UIView.animate(withDuration: isAnimated ? 0.25 : 0) {
tabLabel.alpha = 1
tabLabelsCopy.forEach { $0.alpha = Values.mediumOpacity }
self.layoutIfNeeded()
}
}
// MARK: - Interaction
@objc private func handleTabLabelTapped(_ sender: UITapGestureRecognizer) {
guard let tabLabel = tabLabels.first(where: { $0.bounds.contains(sender.location(in: $0)) }), let index = tabLabels.firstIndex(of: tabLabel) else { return }
selectTab(at: index)
let tab = tabs[index]
tab.onTap()
}
}