Merge branch 'feature/navigation_bar_style' into 'feature/develop_mvp_3'

Feature/navigation bar style

See merge request BPHV_MIPS/mvm_core_ui!808
This commit is contained in:
Pfeil, Scott Robert 2022-03-14 19:04:50 +00:00
commit 290d19b661
12 changed files with 504 additions and 314 deletions

View File

@ -272,6 +272,7 @@
AAE7270E24AC8B9300A3ED0E /* HeadersH2CaretLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE7270D24AC8B9300A3ED0E /* HeadersH2CaretLink.swift */; }; AAE7270E24AC8B9300A3ED0E /* HeadersH2CaretLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE7270D24AC8B9300A3ED0E /* HeadersH2CaretLink.swift */; };
AAE96FA225341F6A0037A989 /* ListStoreLocatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */; }; AAE96FA225341F6A0037A989 /* ListStoreLocatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */; };
AAE96FA525341F7D0037A989 /* ListStoreLocator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */; }; AAE96FA525341F7D0037A989 /* ListStoreLocator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */; };
AFE4A1D627DFBB6F00C458D0 /* UINavigationController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */; };
BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */; }; BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */; };
BB1D17E0244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1D17DF244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift */; }; BB1D17E0244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1D17DF244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift */; };
BB1D17E2244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1D17E1244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift */; }; BB1D17E2244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1D17E1244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift */; };
@ -857,6 +858,7 @@
AAE7270D24AC8B9300A3ED0E /* HeadersH2CaretLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2CaretLink.swift; sourceTree = "<group>"; }; AAE7270D24AC8B9300A3ED0E /* HeadersH2CaretLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2CaretLink.swift; sourceTree = "<group>"; };
AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStoreLocatorModel.swift; sourceTree = "<group>"; }; AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStoreLocatorModel.swift; sourceTree = "<group>"; };
AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStoreLocator.swift; sourceTree = "<group>"; }; AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStoreLocator.swift; sourceTree = "<group>"; };
AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Extension.swift"; sourceTree = "<group>"; };
BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UICollectionViewLeftAlignedLayout.swift; sourceTree = "<group>"; }; BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UICollectionViewLeftAlignedLayout.swift; sourceTree = "<group>"; };
BB1D17DF244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListDeviceComplexButtonMediumModel.swift; sourceTree = "<group>"; }; BB1D17DF244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListDeviceComplexButtonMediumModel.swift; sourceTree = "<group>"; };
BB1D17E1244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListDeviceComplexButtonMedium.swift; sourceTree = "<group>"; }; BB1D17E1244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListDeviceComplexButtonMedium.swift; sourceTree = "<group>"; };
@ -1535,6 +1537,15 @@
path = Miscellaneous; path = Miscellaneous;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
AFE4A1D427DFBB2700C458D0 /* NavigationController */ = {
isa = PBXGroup;
children = (
D2B18B93236214AD00A9AEDC /* NavigationController.swift */,
AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */,
);
path = NavigationController;
sourceTree = "<group>";
};
D202AFE2242A5F1400E5BEDF /* Extensions */ = { D202AFE2242A5F1400E5BEDF /* Extensions */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -2072,9 +2083,9 @@
D29DF11921E68467003B2FB9 /* Containers */ = { D29DF11921E68467003B2FB9 /* Containers */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
AFE4A1D427DFBB2700C458D0 /* NavigationController */,
0ABD1369237B18EE0081388D /* Views */, 0ABD1369237B18EE0081388D /* Views */,
D29DF2B621E7BE66003B2FB9 /* SplitViewController */, D29DF2B621E7BE66003B2FB9 /* SplitViewController */,
D2B18B93236214AD00A9AEDC /* NavigationController.swift */,
); );
path = Containers; path = Containers;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2637,6 +2648,7 @@
DBC4391922442197001AB423 /* DashLine.swift in Sources */, DBC4391922442197001AB423 /* DashLine.swift in Sources */,
D2ED27FC254B0E0300A1C293 /* MVMCoreAlertObject+Swift.swift in Sources */, D2ED27FC254B0E0300A1C293 /* MVMCoreAlertObject+Swift.swift in Sources */,
D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */, D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */,
AFE4A1D627DFBB6F00C458D0 /* UINavigationController+Extension.swift in Sources */,
AAC23FAD24D92A0D009208DF /* ListThreeColumnSpeedTestModel.swift in Sources */, AAC23FAD24D92A0D009208DF /* ListThreeColumnSpeedTestModel.swift in Sources */,
BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */, BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */,
01F2C20527C81F9700DC3D36 /* SubNavSwipeAnimator.swift in Sources */, 01F2C20527C81F9700DC3D36 /* SubNavSwipeAnimator.swift in Sources */,

View File

@ -18,10 +18,6 @@ import UIKit
get { return model as? LineModel } get { return model as? LineModel }
} }
var lineBackgroundColor: Color? {
return (lineModel?.inverted ?? false) ? lineModel?.backgroundColor_inverted : lineModel?.backgroundColor
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Constraints // MARK: - Constraints
//-------------------------------------------------- //--------------------------------------------------
@ -50,28 +46,33 @@ import UIKit
addLine(to: view, edge: edge, useMargin: useMargin) addLine(to: view, edge: edge, useMargin: useMargin)
} }
public init() {
super.init(frame: .zero)
model = LineModel(type: .standard)
}
public override init(frame: CGRect) {
super.init(frame: frame)
model = LineModel(type: .standard)
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
model = LineModel(type: .standard)
}
public required init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
super.init(model: model, delegateObject, additionalData)
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Methods // MARK: - Methods
//-------------------------------------------------- //--------------------------------------------------
open func setStyle(_ style: LineModel.Style) { open func setStyle(_ style: LineModel.Style) {
lineModel?.type = style
switch style { backgroundColor = lineModel?.backgroundColor?.uiColor
case .standard: updateLineConstraints(constant: lineModel?.thickness ?? 1)
updateLineConstraints(constant: 1)
backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mvmCoolGray3
case .thin:
updateLineConstraints(constant: 1)
backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mvmBlack
case .medium:
updateLineConstraints(constant: 2)
backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mvmBlack
case .heavy:
updateLineConstraints(constant: 4)
backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mvmBlack
case .none:
updateLineConstraints(constant: 0)
}
} }
open func shouldBeVisible() -> Bool { open func shouldBeVisible() -> Bool {
@ -90,12 +91,10 @@ import UIKit
open override func setupView() { open override func setupView() {
super.setupView() super.setupView()
heightConstraint = heightAnchor.constraint(equalToConstant: 1) heightConstraint = heightAnchor.constraint(equalToConstant: 1)
heightConstraint?.isActive = true heightConstraint?.isActive = true
widthConstraint = widthAnchor.constraint(equalToConstant: 1) widthConstraint = widthAnchor.constraint(equalToConstant: 1)
widthConstraint?.isActive = false widthConstraint?.isActive = false
setStyle(.standard)
} }
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
@ -111,19 +110,7 @@ import UIKit
} }
public override static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { public override static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return (model as? LineModel)?.thickness ?? 1
guard let type = (model as? LineModel)?.type else { return 1 }
switch type {
case .none:
return 0
case .medium:
return 2
case .heavy:
return 4
default:
return 1
}
} }
} }

View File

@ -54,7 +54,39 @@ import UIKit
//TODO: use color insted of backgroundColor. Needs server changes //TODO: use color insted of backgroundColor. Needs server changes
// public var color: Color? // public var color: Color?
public var backgroundColor: Color? private var _backgroundColor: Color?
public var backgroundColor: Color? {
get {
if inverted { return backgroundColor_inverted }
if let backgroundColor = _backgroundColor { return backgroundColor }
if type == .standard { return Color(uiColor: .mvmCoolGray3) }
return Color(uiColor: .mvmBlack)
}
set {
_backgroundColor = newValue
}
}
private var _thickness: CGFloat?
public var thickness: CGFloat {
get {
if let thickness = _thickness { return thickness }
switch type {
case .heavy:
return 4
case .medium:
return 2
case .none:
return 0
default:
return 1
}
}
set {
_thickness = newValue
}
}
public var backgroundColor_inverted: Color = Color(uiColor: .mvmWhite) public var backgroundColor_inverted: Color = Color(uiColor: .mvmWhite)
public var inverted: Bool = false public var inverted: Bool = false
@ -90,6 +122,7 @@ import UIKit
case frequency case frequency
case inverted case inverted
case useVerticalLine case useVerticalLine
case thickness
} }
//-------------------------------------------------- //--------------------------------------------------
@ -117,6 +150,7 @@ import UIKit
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
useVerticalLine = try typeContainer.decodeIfPresent(Bool.self, forKey: .useVerticalLine) useVerticalLine = try typeContainer.decodeIfPresent(Bool.self, forKey: .useVerticalLine)
_thickness = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .thickness)
} }
public func encode(to encoder: Encoder) throws { public func encode(to encoder: Encoder) throws {
@ -125,8 +159,9 @@ import UIKit
try container.encode(type, forKey: .type) try container.encode(type, forKey: .type)
try container.encode(inverted, forKey: .inverted) try container.encode(inverted, forKey: .inverted)
try container.encodeIfPresent(frequency, forKey: .frequency) try container.encodeIfPresent(frequency, forKey: .frequency)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(backgroundColor_inverted, forKey: .backgroundColor_inverted) try container.encodeIfPresent(backgroundColor_inverted, forKey: .backgroundColor_inverted)
try container.encodeIfPresent(useVerticalLine, forKey: .useVerticalLine) try container.encodeIfPresent(useVerticalLine, forKey: .useVerticalLine)
try container.encodeIfPresent(_thickness, forKey: .thickness)
} }
} }

View File

@ -8,15 +8,51 @@
import Foundation import Foundation
public class TabBarModel: MoleculeModelProtocol { open class TabBarModel: MoleculeModelProtocol {
public static var identifier: String = "tabBar" public static var identifier: String = "tabBar"
public var backgroundColor: Color? = Color(uiColor: .white) open var tabs: [TabBarItemModel]
public var tabs: [TabBarItemModel]
public var selectedColor = Color(uiColor: .mvmBlack) private var _backgroundColor: Color?
public var unSelectedColor = Color(uiColor: .mvmCoolGray6) open var backgroundColor: Color? {
get {
if let backgroundColor = _backgroundColor { return backgroundColor }
if let style = style,
style == .dark { return Color(uiColor: .mvmBlack) }
return Color(uiColor: .mvmWhite)
}
set {
_backgroundColor = newValue
}
}
private var _selectedColor: Color?
open var selectedColor: Color {
get {
if let selectedColor = _selectedColor { return selectedColor }
if let style = style,
style == .dark { return Color(uiColor: .mvmWhite) }
return Color(uiColor: .mvmBlack)
}
set {
_selectedColor = newValue
}
}
private var _unSelectedColor: Color?
open var unSelectedColor: Color {
get {
if let unselectedColor = _unSelectedColor { return unselectedColor }
return Color(uiColor: .mvmCoolGray6)
}
set {
_unSelectedColor = newValue
}
}
open var style: NavigationItemStyle?
// Must be capped to 0...(tabs.count - 1) // Must be capped to 0...(tabs.count - 1)
public var selectedTab: Int = 0 open var selectedTab: Int = 0
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case moleculeName case moleculeName
@ -25,6 +61,7 @@ public class TabBarModel: MoleculeModelProtocol {
case selectedColor case selectedColor
case unSelectedColor case unSelectedColor
case selectedTab case selectedTab
case style
} }
public init(with tabs: [TabBarItemModel]) { public init(with tabs: [TabBarItemModel]) {
@ -46,24 +83,26 @@ public class TabBarModel: MoleculeModelProtocol {
if let index = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedTab) { if let index = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedTab) {
selectedTab = index selectedTab = index
} }
style = try typeContainer.decodeIfPresent(NavigationItemStyle.self, forKey: .style)
} }
public func encode(to encoder: Encoder) throws { open func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName) try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(tabs, forKey: .tabs) try container.encode(tabs, forKey: .tabs)
try container.encode(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
try container.encode(selectedColor, forKey: .selectedColor) try container.encodeIfPresent(_selectedColor, forKey: .selectedColor)
try container.encode(unSelectedColor, forKey: .unSelectedColor) try container.encodeIfPresent(_unSelectedColor, forKey: .unSelectedColor)
try container.encode(selectedTab, forKey: .selectedTab) try container.encode(selectedTab, forKey: .selectedTab)
try container.encodeIfPresent(style, forKey: .style)
} }
} }
public class TabBarItemModel: Codable { open class TabBarItemModel: Codable {
var title: String? open var title: String?
var image: String open var image: String
var action: ActionModelProtocol open var action: ActionModelProtocol
var accessibilityText: String? open var accessibilityText: String?
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case title case title
@ -86,7 +125,7 @@ public class TabBarItemModel: Codable {
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText) accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
} }
public func encode(to encoder: Encoder) throws { open func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(title, forKey: .title) try container.encodeIfPresent(title, forKey: .title)
try container.encode(image, forKey: .image) try container.encode(image, forKey: .image)

View File

@ -153,8 +153,7 @@ import UIKit
self.delegateObject = delegateObject self.delegateObject = delegateObject
self.additionalData = additionalData self.additionalData = additionalData
selectedIndex = tabsModel?.selectedIndex ?? 0 selectedIndex = tabsModel?.selectedIndex ?? 0
// TODO: Commented out until we have model support for bar color. Should also do unselected color. selectionLine.backgroundColor = tabsModel?.selectedBarColor.uiColor
//selectionLine.backgroundColor = tabsModel?.selectedColor.uiColor
reloadData() reloadData()
} }
} }
@ -338,7 +337,7 @@ extension Tabs {
if selected { if selected {
label.textColor = tabsModel?.selectedColor.uiColor ?? .black label.textColor = tabsModel?.selectedColor.uiColor ?? .black
} else { } else {
label.textColor = .mvmCoolGray6 label.textColor = tabsModel?.unselectedColor.uiColor ?? .mvmCoolGray6
} }
updateAccessibility(indexPath: indexPath, selected: selected, tabsModel: tabsModel) updateAccessibility(indexPath: indexPath, selected: selected, tabsModel: tabsModel)
} }

View File

@ -8,21 +8,74 @@
import UIKit import UIKit
public class TabsModel: MoleculeModelProtocol { open class TabsModel: MoleculeModelProtocol {
public static var identifier: String = "tabs" public static var identifier: String = "tabs"
public var backgroundColor: Color? open var tabs: [TabItemModel]
public var tabs: [TabItemModel]
public var selectedColor = Color(uiColor: .black) open var style: NavigationItemStyle?
private var _backgroundColor: Color?
open var backgroundColor: Color? {
get {
if let backgroundColor = _backgroundColor { return backgroundColor }
if let style = style,
style == .dark { return Color(uiColor: .mvmBlack) }
return Color(uiColor: .mvmWhite)
}
set {
_backgroundColor = newValue
}
}
private var _selectedColor: Color?
open var selectedColor: Color {
get {
if let selectedColor = _selectedColor { return selectedColor }
if let style = style,
style == .dark { return Color(uiColor: .mvmWhite) }
return Color(uiColor: .mvmBlack)
}
set {
_selectedColor = newValue
}
}
private var _unselectedColor: Color?
open var unselectedColor: Color {
get {
if let unselectedColor = _unselectedColor { return unselectedColor }
return Color(uiColor: .mvmCoolGray6)
}
set {
_unselectedColor = newValue
}
}
private var _selectedBarColor: Color?
open var selectedBarColor: Color {
get {
if let selectedBarColor = _selectedBarColor { return selectedBarColor }
if let style = style,
style == .dark { return Color(uiColor: .mvmWhite) }
return Color(uiColor: .mvmRed)
}
set {
_selectedBarColor = newValue
}
}
// Must be capped to 0...(tabs.count - 1) // Must be capped to 0...(tabs.count - 1)
public var selectedIndex: Int = 0 open var selectedIndex: Int = 0
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case moleculeName
case tabs case tabs
case backgroundColor case backgroundColor
case selectedColor case selectedColor
case unselectedColor
case selectedBarColor
case selectedIndex case selectedIndex
case moleculeName case style
} }
public init(with tabs: [TabItemModel]) { public init(with tabs: [TabItemModel]) {
@ -33,31 +86,35 @@ public class TabsModel: MoleculeModelProtocol {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
tabs = try typeContainer.decode([TabItemModel].self, forKey: .tabs) tabs = try typeContainer.decode([TabItemModel].self, forKey: .tabs)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedColor) { _selectedColor = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedColor)
selectedColor = color _unselectedColor = try typeContainer.decodeIfPresent(Color.self, forKey: .unselectedColor)
} _selectedBarColor = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedBarColor)
style = try typeContainer.decodeIfPresent(NavigationItemStyle.self, forKey: .style)
if let index = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedIndex) { if let index = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedIndex) {
selectedIndex = index selectedIndex = index
} }
} }
public func encode(to encoder: Encoder) throws { open func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName) try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(tabs, forKey: .tabs) try container.encode(tabs, forKey: .tabs)
try container.encode(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
try container.encode(selectedColor, forKey: .selectedColor) try container.encodeIfPresent(_selectedColor, forKey: .selectedColor)
try container.encodeIfPresent(_unselectedColor, forKey: .unselectedColor)
try container.encodeIfPresent(_selectedBarColor, forKey: .selectedBarColor)
try container.encode(selectedIndex, forKey: .selectedIndex) try container.encode(selectedIndex, forKey: .selectedIndex)
try container.encodeIfPresent(style, forKey: .style)
} }
} }
public class TabItemModel: Codable { open class TabItemModel: Codable {
public var label: LabelModel open var label: LabelModel
public var action: ActionModelProtocol? open var action: ActionModelProtocol?
init(label: LabelModel) { public init(label: LabelModel) {
self.label = label self.label = label
} }
@ -66,7 +123,7 @@ public class TabItemModel: Codable {
case action case action
} }
func setDefaults() { open func setDefaults() {
if label.textAlignment == nil { if label.textAlignment == nil {
label.textAlignment = .center label.textAlignment = .center
} }
@ -85,7 +142,7 @@ public class TabItemModel: Codable {
setDefaults() setDefaults()
} }
public func encode(to encoder: Encoder) throws { open func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeModel(label, forKey: .label) try container.encodeModel(label, forKey: .label)
try container.encodeModelIfPresent(action, forKey: .action) try container.encodeModelIfPresent(action, forKey: .action)

View File

@ -6,6 +6,10 @@
// Copyright © 2020 Verizon Wireless. All rights reserved. // Copyright © 2020 Verizon Wireless. All rights reserved.
// //
public enum NavigationItemStyle: String, Codable {
case light
case dark
}
open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol { open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol {
//-------------------------------------------------- //--------------------------------------------------
@ -14,12 +18,39 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
open class var identifier: String { "navigationBar" } open class var identifier: String { "navigationBar" }
private let defaultHidesSystemBackButton = true
open var title: String? open var title: String?
open var hidden: Bool open var hidden = false
open var backgroundColor: Color? open var line: LineModel? = LineModel(type: .standard)
open var tintColor: Color
open var line: LineModel?
open var hidesSystemBackButton = true open var hidesSystemBackButton = true
open var style: NavigationItemStyle?
private var _backgroundColor: Color?
open var backgroundColor: Color? {
get {
if let backgroundColor = _backgroundColor { return backgroundColor }
if let style = style,
style == .dark { return Color(uiColor: .mvmBlack) }
return Color(uiColor: .mvmWhite)
}
set {
_backgroundColor = newValue
}
}
private var _tintColor: Color?
open var tintColor: Color {
get {
if let tintColor = _tintColor { return tintColor }
if let style = style,
style == .dark { return Color(uiColor: .mvmWhite) }
return Color(uiColor: .mvmBlack)
}
set {
_tintColor = newValue
}
}
/// If true, we add the button in the backButton property. If false we do not add the button. If nil, we add the button if the controller is not the bottom of the stack /// If true, we add the button in the backButton property. If false we do not add the button. If nil, we add the button if the controller is not the bottom of the stack
open var alwaysShowBackButton: Bool? open var alwaysShowBackButton: Bool?
@ -33,12 +64,7 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
// MARK: - Initializer // MARK: - Initializer
//-------------------------------------------------- //--------------------------------------------------
public init() { public init() {}
hidden = false
backgroundColor = Color(uiColor: .mvmWhite)
tintColor = Color(uiColor: .mvmBlack)
line = LineModel(type: .standard)
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Keys // MARK: - Keys
@ -57,6 +83,7 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
case additionalLeftButtons case additionalLeftButtons
case additionalRightButtons case additionalRightButtons
case titleView case titleView
case style
} }
//-------------------------------------------------- //--------------------------------------------------
@ -66,16 +93,23 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
title = try typeContainer.decodeIfPresent(String.self, forKey: .title) title = try typeContainer.decodeIfPresent(String.self, forKey: .title)
hidden = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidden) ?? false if let hidden = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidden) {
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) ?? Color(uiColor: .mvmWhite) self.hidden = hidden
tintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .tintColor) ?? Color(uiColor: .mvmBlack) }
line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) ?? LineModel(type: .standard) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
hidesSystemBackButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidesSystemBackButton) ?? true _tintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .tintColor)
if let line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) {
self.line = line
}
if let hidesSystemBackButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidesSystemBackButton) {
self.hidesSystemBackButton = hidesSystemBackButton
}
alwaysShowBackButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysShowBackButton) alwaysShowBackButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysShowBackButton)
backButton = try typeContainer.decodeModelIfPresent(codingKey: .backButton) backButton = try typeContainer.decodeModelIfPresent(codingKey: .backButton)
additionalLeftButtons = try typeContainer.decodeModelsIfPresent(codingKey: .additionalLeftButtons) additionalLeftButtons = try typeContainer.decodeModelsIfPresent(codingKey: .additionalLeftButtons)
additionalRightButtons = try typeContainer.decodeModelsIfPresent(codingKey: .additionalRightButtons) additionalRightButtons = try typeContainer.decodeModelsIfPresent(codingKey: .additionalRightButtons)
titleView = try typeContainer.decodeModelIfPresent(codingKey: .titleView) titleView = try typeContainer.decodeModelIfPresent(codingKey: .titleView)
style = try typeContainer.decodeIfPresent(NavigationItemStyle.self, forKey: .style)
} }
open func encode(to encoder: Encoder) throws { open func encode(to encoder: Encoder) throws {
@ -83,8 +117,8 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
try container.encode(moleculeName, forKey: .moleculeName) try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(title, forKey: .title) try container.encodeIfPresent(title, forKey: .title)
try container.encode(hidden, forKey: .hidden) try container.encode(hidden, forKey: .hidden)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
try container.encode(tintColor, forKey: .tintColor) try container.encodeIfPresent(_tintColor, forKey: .tintColor)
try container.encodeIfPresent(line, forKey: .line) try container.encodeIfPresent(line, forKey: .line)
try container.encode(hidesSystemBackButton, forKey: .hidesSystemBackButton) try container.encode(hidesSystemBackButton, forKey: .hidesSystemBackButton)
try container.encodeIfPresent(alwaysShowBackButton, forKey: .alwaysShowBackButton) try container.encodeIfPresent(alwaysShowBackButton, forKey: .alwaysShowBackButton)
@ -92,6 +126,7 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
try container.encodeModelsIfPresent(additionalLeftButtons, forKey: .additionalLeftButtons) try container.encodeModelsIfPresent(additionalLeftButtons, forKey: .additionalLeftButtons)
try container.encodeModelsIfPresent(additionalRightButtons, forKey: .additionalRightButtons) try container.encodeModelsIfPresent(additionalRightButtons, forKey: .additionalRightButtons)
try container.encodeModelIfPresent(titleView, forKey: .titleView) try container.encodeModelIfPresent(titleView, forKey: .titleView)
try container.encodeIfPresent(style, forKey: .style)
} }
} }

View File

@ -1,201 +0,0 @@
//
// NavigationController.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 10/24/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class NavigationController: UINavigationController, MVMCoreViewManagerViewControllerProtocol {
public var separatorView: Line?
public weak var manager: (UIViewController & MVMCoreViewManagerProtocol)?
/// Getter for the main navigation controller
public static func navigationController() -> Self? {
return MVMCoreActionUtility.initializerClassCheck(MVMCoreUISession.sharedGlobal()?.navigationController, classToVerify: self) as? Self
}
/// Provides MVM styling to the navigation bar. Returns a reference to the line.
public static func style(_ navigationBar: UINavigationBar) -> Line {
navigationBar.backgroundColor = .white
navigationBar.shadowImage = UIImage()
navigationBar.isOpaque = true
navigationBar.tintColor = .black
navigationBar.titleTextAttributes = [NSAttributedString.Key.font: MFStyler.fontBoldBodySmall(false)];
return Line(pinTo: navigationBar, edge: .bottom, useMargin: false)
}
/// Sets up the application with a navigation controller
public static func setupNavigationController() -> Self? {
let navigationController = self.init()
navigationController.separatorView = style(navigationController.navigationBar)
MVMCoreUISession.sharedGlobal()?.navigationController = navigationController
MVMCoreNavigationHandler.shared()?.viewControllerToPresentOn = navigationController
MVMCoreNavigationHandler.shared()?.navigationController = navigationController
MVMCoreNavigationHandler.shared()?.addDelegate(navigationController)
return navigationController
}
/// Sets up the application with a navigation controller as the main container.
public static func setupNavigationControllerAsMainController() -> Self? {
guard let navigationController = setupNavigationController() else { return nil }
MVMCoreUISession.sharedGlobal()?.setup(asStandardLoadViewDelegate: navigationController)
return navigationController
}
/// Convenience function for setting the navigation item.
public static func setNavigationItem(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, viewController: UIViewController) {
viewController.navigationItem.title = navigationItemModel.title
viewController.navigationItem.accessibilityLabel = navigationItemModel.title
viewController.navigationItem.hidesBackButton = navigationItemModel.hidesSystemBackButton
viewController.navigationItem.leftItemsSupplementBackButton = !navigationItemModel.hidesSystemBackButton
setNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
setNavigationTitleView(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
}
/// Convenience function for setting the navigation buttons.
public static func setNavigationButtons(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, viewController: UIViewController) {
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
var leftItems: [UIBarButtonItem] = []
if navigationItemModel.hidesSystemBackButton,
navigationItemModel.alwaysShowBackButton != false {
if let backButtonModel = navigationItemModel.backButton,
MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 0 > 1 || navigationItemModel.alwaysShowBackButton ?? false {
leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
}
if let leftItemModels = navigationItemModel.additionalLeftButtons {
for item in leftItemModels {
leftItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
}
}
}
viewController.navigationItem.leftBarButtonItems = leftItems.count > 0 ? leftItems : nil
var rightItems: [UIBarButtonItem] = []
if let rightItemModels = navigationItemModel.additionalRightButtons {
for item in rightItemModels {
rightItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
}
}
viewController.navigationItem.rightBarButtonItems = rightItems.count > 0 ? rightItems : nil
}
/// Convenience function for setting the navigation bar ui, except for the buttons.
public static func setNavigationBarUI(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, viewController: UIViewController) {
navigationController.setNavigationBarHidden(navigationItemModel.hidden, animated: true)
navigationController.navigationBar.barTintColor = navigationItemModel.backgroundColor?.uiColor ?? .white
let tint = navigationItemModel.tintColor.uiColor
navigationController.navigationBar.tintColor = tint
// Have the navigation title match the tint color
navigationController.navigationBar.titleTextAttributes?.updateValue(tint, forKey: .foregroundColor)
// Update line.
if let navigationController = navigationController as? NavigationController {
navigationController.separatorView?.isHidden = navigationItemModel.line?.type ?? .standard == .none
}
}
/// Convenience function for setting the navigation titleView.
public static func setNavigationTitleView(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) {
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
if let titleViewModel = navigationItemModel?.titleView, let molecule = ModelRegistry.createMolecule(titleViewModel, delegateObject: delegate, additionalData: nil) {
viewController.navigationItem.titleView = molecule
}
}
/// Convenience function to return the navigation model of the lowest controller traversing managers if applicable.
public func getNavigationModel(from viewController: UIViewController) -> NavigationItemModelProtocol? {
return (viewController as? PageProtocol)?.pageModel?.navigationBar
}
/// Verifies the controller is the currently displayed controller.
public func isDisplayed(viewController: UIViewController) -> Bool {
guard let topViewController = topViewController,
viewController == MVMCoreUIUtility.getViewControllerTraversingManagers(topViewController) else {
return false
}
return true
}
}
extension NavigationController: MVMCoreViewManagerProtocol {
public func getCurrentViewController() -> UIViewController? {
guard let topViewController = topViewController else { return nil }
return MVMCoreUIUtility.getViewControllerTraversingManagers(topViewController)
}
public func containsPage(withPageType pageType: String?) -> Bool {
for controller in viewControllers {
if let manager = controller as? MVMCoreViewManagerProtocol,
manager.containsPage(withPageType: pageType) {
return true
} else if let controller = controller as? MVMCoreViewControllerProtocol,
controller.pageType == pageType {
return true
}
}
return false
}
public func newDataReceived(in viewController: UIViewController) {
if isDisplayed(viewController: viewController),
let topViewController = topViewController,
let model = getNavigationModel(from: viewController) {
Self.setNavigationItem(navigationController: self, navigationItemModel: model, viewController: topViewController)
Self.setNavigationBarUI(navigationController: self, navigationItemModel: model, viewController: topViewController)
}
manager?.newDataReceived?(in: viewController)
}
public func willDisplay(_ viewController: UIViewController) {
if let topViewController = topViewController,
let model = getNavigationModel(from: viewController) {
Self.setNavigationItem(navigationController: self, navigationItemModel: model, viewController: topViewController)
}
manager?.willDisplay?(viewController)
}
public func displayedViewController(_ viewController: UIViewController) {
if isDisplayed(viewController: viewController),
let topViewController = topViewController,
let model = getNavigationModel(from: viewController) {
Self.setNavigationBarUI(navigationController: self, navigationItemModel: model, viewController: topViewController)
}
manager?.displayedViewController?(viewController)
}
}
extension NavigationController: MVMCorePresentationDelegateProtocol {
public func navigationController(_ navigationController: UINavigationController, prepareDisplayFor viewController: UIViewController) {
guard self == navigationController,
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController),
let model = getNavigationModel(from: newViewController) else { return }
Self.setNavigationItem(navigationController: self, navigationItemModel: model, viewController: viewController)
}
public func navigationController(_ navigationController: UINavigationController, willDisplay viewController: UIViewController) {
guard self == navigationController,
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController) else { return }
if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
MVMCoreViewManagerViewControllerProtocolHelper.helpSetManager(self, viewController: controller)
}
manager?.willDisplay?(newViewController)
}
public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) {
guard self == navigationController,
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController) else { return }
if let model = getNavigationModel(from: newViewController) {
Self.setNavigationBarUI(navigationController: self, navigationItemModel: model, viewController: viewController)
}
manager?.displayedViewController?(newViewController)
if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
controller.viewControllerReady?(inManager: self)
}
}
}

View File

@ -0,0 +1,136 @@
//
// NavigationController.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 10/24/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class NavigationController: UINavigationController, MVMCoreViewManagerViewControllerProtocol {
public weak var manager: (UIViewController & MVMCoreViewManagerProtocol)?
/// Getter for the main navigation controller
public static func navigationController() -> Self? {
return MVMCoreActionUtility.initializerClassCheck(MVMCoreUISession.sharedGlobal()?.navigationController, classToVerify: self) as? Self
}
/// Sets up the application with a navigation controller
public static func setupNavigationController() -> Self? {
let navigationController = self.init()
MVMCoreUISession.sharedGlobal()?.navigationController = navigationController
MVMCoreNavigationHandler.shared()?.viewControllerToPresentOn = navigationController
MVMCoreNavigationHandler.shared()?.navigationController = navigationController
MVMCoreNavigationHandler.shared()?.addDelegate(navigationController)
navigationController.setNavigationBarUI(with: NavigationItemModel())
return navigationController
}
/// Sets up the application with a navigation controller as the main container.
public static func setupNavigationControllerAsMainController() -> Self? {
guard let navigationController = setupNavigationController() else { return nil }
MVMCoreUISession.sharedGlobal()?.setup(asStandardLoadViewDelegate: navigationController)
return navigationController
}
/// Convenience function to return the navigation model of the lowest controller traversing managers if applicable.
public func getNavigationModel(from viewController: UIViewController) -> NavigationItemModelProtocol? {
return (viewController as? PageProtocol)?.pageModel?.navigationBar
}
/// Verifies the controller is the currently displayed controller.
public func isDisplayed(viewController: UIViewController) -> Bool {
guard let topViewController = topViewController,
viewController == MVMCoreUIUtility.getViewControllerTraversingManagers(topViewController) else {
return false
}
return true
}
}
extension NavigationController: MVMCoreViewManagerProtocol {
public func getCurrentViewController() -> UIViewController? {
guard let topViewController = topViewController else { return nil }
return MVMCoreUIUtility.getViewControllerTraversingManagers(topViewController)
}
public func containsPage(withPageType pageType: String?) -> Bool {
for controller in viewControllers {
if let manager = controller as? MVMCoreViewManagerProtocol,
manager.containsPage(withPageType: pageType) {
return true
} else if let controller = controller as? MVMCoreViewControllerProtocol,
controller.pageType == pageType {
return true
}
}
return false
}
public func newDataReceived(in viewController: UIViewController) {
if isDisplayed(viewController: viewController),
let topViewController = topViewController,
let model = getNavigationModel(from: viewController) {
setNavigationItem(with: model, for: topViewController)
setNavigationBarUI(with: model)
}
manager?.newDataReceived?(in: viewController)
}
public func willDisplay(_ viewController: UIViewController) {
if let topViewController = topViewController,
let model = getNavigationModel(from: viewController) {
setNavigationItem(with: model, for: topViewController)
}
manager?.willDisplay?(viewController)
}
public func displayedViewController(_ viewController: UIViewController) {
if isDisplayed(viewController: viewController),
let model = getNavigationModel(from: viewController) {
setNavigationBarUI(with: model)
}
manager?.displayedViewController?(viewController)
}
}
extension NavigationController: MVMCorePresentationDelegateProtocol {
public func navigationController(_ navigationController: UINavigationController, prepareDisplayFor viewController: UIViewController) {
guard self == navigationController,
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController),
let model = getNavigationModel(from: newViewController) else { return }
setNavigationItem(with: model, for: viewController)
}
public func navigationController(_ navigationController: UINavigationController, willDisplay viewController: UIViewController) {
guard self == navigationController,
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController) else { return }
if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
MVMCoreViewManagerViewControllerProtocolHelper.helpSetManager(self, viewController: controller)
}
manager?.willDisplay?(newViewController)
}
public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) {
guard self == navigationController,
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController) else { return }
if let model = getNavigationModel(from: newViewController) {
setNavigationBarUI(with: model)
}
manager?.displayedViewController?(newViewController)
if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
controller.viewControllerReady?(inManager: self)
}
}
}
extension UIColor {
func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
return UIGraphicsImageRenderer(size: size).image { rendererContext in
self.setFill()
rendererContext.fill(CGRect(origin: .zero, size: size))
}
}
}

View File

@ -0,0 +1,87 @@
//
// UINavigationController+Extension.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 3/14/22.
// Copyright © 2022 Verizon Wireless. All rights reserved.
//
import Foundation
public extension UINavigationController {
/// Convenience function for setting the navigation item.
func setNavigationItem(with model: NavigationItemModelProtocol, for viewController: UIViewController) {
viewController.navigationItem.title = model.title
viewController.navigationItem.accessibilityLabel = model.title
viewController.navigationItem.hidesBackButton = model.hidesSystemBackButton
viewController.navigationItem.leftItemsSupplementBackButton = !model.hidesSystemBackButton
setNavigationButtons(with: model, for: viewController)
setNavigationTitleView(with: model, for: viewController)
}
/// Convenience function for setting the navigation buttons.
func setNavigationButtons(with model: NavigationItemModelProtocol, for viewController: UIViewController) {
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
var leftItems: [UIBarButtonItem] = []
if model.hidesSystemBackButton,
model.alwaysShowBackButton != false {
if let backButtonModel = model.backButton,
MVMCoreNavigationHandler.shared()?.getViewControllers(for: self)?.count ?? 0 > 1 || model.alwaysShowBackButton ?? false {
leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
}
if let leftItemModels = model.additionalLeftButtons {
for item in leftItemModels {
leftItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
}
}
}
viewController.navigationItem.leftBarButtonItems = leftItems.count > 0 ? leftItems : nil
var rightItems: [UIBarButtonItem] = []
if let rightItemModels = model.additionalRightButtons {
for item in rightItemModels {
rightItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
}
}
viewController.navigationItem.rightBarButtonItems = rightItems.count > 0 ? rightItems : nil
}
/// Convenience function for setting the navigation titleView.
func setNavigationTitleView(with model: NavigationItemModelProtocol, for viewController: UIViewController) {
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
if let titleViewModel = model.titleView,
let molecule = ModelRegistry.createMolecule(titleViewModel, delegateObject: delegate, additionalData: nil) {
viewController.navigationItem.titleView = molecule
}
}
/// Returns a ShadowImage based on the line property of NavigationItemModelProtocol
func getNavigationBarShadowImage(for navigationItemModel: NavigationItemModelProtocol) -> UIImage? {
guard let thickness = navigationItemModel.line?.thickness,
let backgroundColor = navigationItemModel.line?.backgroundColor else { return nil }
return backgroundColor.uiColor.image(CGSize(width: thickness, height: thickness))
}
/// Convenience function for setting the navigation bar ui
func setNavigationBarUI(with model: NavigationItemModelProtocol) {
let navigationBar = navigationBar
let font = MFStyler.fontBoldBodySmall(false)
let backgroundColor = model.backgroundColor?.uiColor
let tint = model.tintColor.uiColor
navigationBar.tintColor = tint
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.titleTextAttributes = [NSAttributedString.Key.font: font,
NSAttributedString.Key.foregroundColor: tint];
appearance.backgroundColor = backgroundColor
appearance.titleTextAttributes.updateValue(tint, forKey: .foregroundColor)
appearance.shadowColor = model.line?.backgroundColor?.uiColor ?? .clear
appearance.shadowImage = getNavigationBarShadowImage(for: model)?.withRenderingMode(.alwaysTemplate)
navigationBar.standardAppearance = appearance
navigationBar.scrollEdgeAppearance = appearance
setNavigationBarHidden(model.hidden, animated: true)
}
}

View File

@ -12,18 +12,13 @@ import Foundation
public extension MVMCoreUISplitViewController { public extension MVMCoreUISplitViewController {
/// Convenience function. Sets the navigation and split view properties for the view controller. Panel access is determined if view controller is a detail view protocol. /// Convenience function. Sets the navigation and split view properties for the view controller. Panel access is determined if view controller is a detail view protocol.
static func setNavigationBarUI(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) { func setNavigationBar(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
guard let splitView = MVMCoreUISplitViewController.main(), guard navigationController == self.navigationController,
navigationController == splitView.navigationController, viewController == getCurrentDetailViewController() else {
viewController == MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() else {
/// Not the split view navigation controller, skip split functions. /// Not the split view navigation controller, skip split functions.
return return
} }
splitView.set(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel)
}
/// Sets the navigation item for the view controller based on the model and splitview controller
private func set(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
setLeftPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isLeftPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false) setLeftPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isLeftPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false)
setRightPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isRightPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false) setRightPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isRightPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false)
@ -121,7 +116,7 @@ public extension MVMCoreUISplitViewController {
guard let navigationController = navigationController, guard let navigationController = navigationController,
navigationController.isDisplayed(viewController: viewController), navigationController.isDisplayed(viewController: viewController),
let model = navigationController.getNavigationModel(from: viewController) else { return } let model = navigationController.getNavigationModel(from: viewController) else { return }
set(for: viewController, navigationController: navigationController, navigationItemModel: model) setNavigationBar(for: viewController, navigationController: navigationController, navigationItemModel: model)
} }
} }

View File

@ -78,7 +78,6 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) { if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
MVMCoreViewManagerViewControllerProtocolHelper.helpSetManager(self, viewController: controller) MVMCoreViewManagerViewControllerProtocolHelper.helpSetManager(self, viewController: controller)
} }
hideNavigationBarLine(for: viewController)
} }
required public init?(coder: NSCoder) { required public init?(coder: NSCoder) {
@ -111,16 +110,27 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
} }
} }
open override func pageShown() {
// Currently not calling super until we can decouple page shown logics for managers.
hideNavigationBarLine(true)
}
open override func viewWillDisappear(_ animated: Bool) { open override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated) super.viewWillDisappear(animated)
// Notify showing view we will disappear. // Notify showing view we will disappear.
(viewController as? MVMCoreViewManagerViewControllerProtocol)?.managerWillDisappear?(self) (viewController as? MVMCoreViewManagerViewControllerProtocol)?.managerWillDisappear?(self)
} }
/// Hides the navigation bar for the page. /// Hides/Shows the navigation bar for the page.
open func hideNavigationBarLine(for viewController: UIViewController) { open func hideNavigationBarLine(_ isHidden: Bool) {
(viewController as? PageProtocol)?.pageModel?.navigationBar?.line?.type = .none guard self == navigationController?.topViewController else { return }
var color = UIColor.clear
if !isHidden,
let backgroundColor = (getCurrentViewController() as? PageProtocol)?.pageModel?.navigationBar?.line?.backgroundColor?.uiColor {
color = backgroundColor
}
navigationController?.navigationBar.standardAppearance.shadowColor = color
navigationController?.navigationBar.scrollEdgeAppearance?.shadowColor = color
} }
open override func updateViews() { open override func updateViews() {
@ -213,7 +223,6 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
index != tabs.selectedIndex else { return } index != tabs.selectedIndex else { return }
viewController = controller viewController = controller
pageType = (viewController as? MVMCoreViewControllerProtocol)?.pageType pageType = (viewController as? MVMCoreViewControllerProtocol)?.pageType
hideNavigationBarLine(for: controller)
if let viewController = getCurrentViewController() { if let viewController = getCurrentViewController() {
manager?.willDisplay?(viewController) manager?.willDisplay?(viewController)
} }
@ -253,6 +262,7 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
if let viewController = getCurrentViewController() { if let viewController = getCurrentViewController() {
manager?.displayedViewController?(viewController) manager?.displayedViewController?(viewController)
} }
hideNavigationBarLine(true)
} }
// MARK: - TabsDelegate // MARK: - TabsDelegate
@ -279,6 +289,7 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
// MARK: - MVMCoreViewManagerViewControllerProtocol // MARK: - MVMCoreViewManagerViewControllerProtocol
open override func viewControllerReady(inManager manager: UIViewController & MVMCoreViewManagerProtocol) { open override func viewControllerReady(inManager manager: UIViewController & MVMCoreViewManagerProtocol) {
super.viewControllerReady(inManager: manager)
// Pass on down // Pass on down
(viewController as? MVMCoreViewManagerViewControllerProtocol)?.viewControllerReady?(inManager: self) (viewController as? MVMCoreViewManagerViewControllerProtocol)?.viewControllerReady?(inManager: self)
} }
@ -297,19 +308,17 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
} }
open func newDataReceived(in viewController: UIViewController) { open func newDataReceived(in viewController: UIViewController) {
if viewController == self.viewController {
hideNavigationBarLine(for: viewController)
}
manager?.newDataReceived?(in: viewController) manager?.newDataReceived?(in: viewController)
hideNavigationBarLine(true)
} }
public func willDisplay(_ viewController: UIViewController) { public func willDisplay(_ viewController: UIViewController) {
hideNavigationBarLine(for: viewController)
manager?.willDisplay?(viewController) manager?.willDisplay?(viewController)
} }
public func displayedViewController(_ viewController: UIViewController) { public func displayedViewController(_ viewController: UIViewController) {
manager?.displayedViewController?(viewController) manager?.displayedViewController?(viewController)
hideNavigationBarLine(true)
} }
// MARK: - MVMCoreUISwipeNavigationProtocol // MARK: - MVMCoreUISwipeNavigationProtocol