This commit is contained in:
Scott Pfeil 2022-03-15 16:36:06 -04:00
parent 41031856e5
commit 9ce71945ae
9 changed files with 635 additions and 74 deletions

View File

@ -7,7 +7,7 @@
// //
import UIKit import UIKit
import VDSColorTokens
@objcMembers public class LineModel: MoleculeModelProtocol { @objcMembers public class LineModel: MoleculeModelProtocol {
//-------------------------------------------------- //--------------------------------------------------
@ -54,8 +54,42 @@ 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_inverted: Color = Color(uiColor: .mvmWhite) public var backgroundColor: Color? {
get {
if let backgroundColor = _backgroundColor { return backgroundColor }
if inverted {
if type == .standard { return Color(uiColor: VDSColor.interactiveDisabledOndark) }
return Color(uiColor: VDSColor.elementsPrimaryOndark)
}
if type == .standard { return Color(uiColor: VDSColor.interactiveDisabledOnlight) }
return Color(uiColor: VDSColor.elementsPrimaryOnlight)
}
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 inverted: Bool = false public var inverted: Bool = false
// Use this to show vertical line // Use this to show vertical line
@ -90,6 +124,7 @@ import UIKit
case frequency case frequency
case inverted case inverted
case useVerticalLine case useVerticalLine
case thickness
} }
//-------------------------------------------------- //--------------------------------------------------
@ -111,12 +146,9 @@ import UIKit
self.inverted = inverted self.inverted = inverted
} }
if let backgroundColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor_inverted) {
self.backgroundColor_inverted = backgroundColor_inverted
}
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 +157,8 @@ 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(useVerticalLine, forKey: .useVerticalLine) try container.encodeIfPresent(useVerticalLine, forKey: .useVerticalLine)
try container.encodeIfPresent(_thickness, forKey: .thickness)
} }
} }

View File

@ -5,7 +5,7 @@
// Created by Scott Pfeil on 5/28/20. // Created by Scott Pfeil on 5/28/20.
// Copyright © 2020 Verizon Wireless. All rights reserved. // Copyright © 2020 Verizon Wireless. All rights reserved.
// //
import VDSColorTokens
@objcMembers open class TabBar: UITabBar, MoleculeViewProtocol, TabBarProtocol, UITabBarDelegate { @objcMembers open class TabBar: UITabBar, MoleculeViewProtocol, TabBarProtocol, UITabBarDelegate {
@ -21,7 +21,6 @@
delegate = self delegate = self
translatesAutoresizingMaskIntoConstraints = false translatesAutoresizingMaskIntoConstraints = false
line.addLine(to: self, edge: .top, useMargin: false) line.addLine(to: self, edge: .top, useMargin: false)
line.backgroundColor = .mvmCoolGray3
set(with: model, delegateObject, additionalData) set(with: model, delegateObject, additionalData)
} }
@ -50,6 +49,10 @@
} }
setItems(tabs, animated: false) setItems(tabs, animated: false)
selectedItem = tabs[model.selectedTab] selectedItem = tabs[model.selectedTab]
guard let lineModel = line.lineModel else { return }
lineModel.inverted = model.style == .dark
line.set(with: lineModel, delegateObject, additionalData)
} }
/// Sets the item colors. /// Sets the item colors.

View File

@ -7,16 +7,55 @@
// //
import Foundation import Foundation
import VDSColorTokens
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: VDSColor.backgroundPrimaryDark) }
return Color(uiColor: VDSColor.backgroundPrimaryLight)
}
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: VDSColor.elementsPrimaryOndark) }
return Color(uiColor: VDSColor.elementsPrimaryOnlight)
}
set {
_selectedColor = newValue
}
}
private var _unSelectedColor: Color?
open var unSelectedColor: Color {
get {
if let unSelectedColor = _unSelectedColor { return unSelectedColor }
if let style = style,
style == .dark { return Color(uiColor: VDSColor.elementsSecondaryOndark) }
return Color(uiColor: VDSColor.elementsSecondaryOnlight)
}
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 +64,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 +86,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) ?? .dark
} }
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 +128,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

@ -7,6 +7,7 @@
// //
import UIKit import UIKit
import VDSColorTokens
@objc public protocol TabsDelegate { @objc public protocol TabsDelegate {
func shouldSelectItem(_ indexPath: IndexPath, tabs: Tabs) -> Bool func shouldSelectItem(_ indexPath: IndexPath, tabs: Tabs) -> Bool
@ -66,7 +67,7 @@ import UIKit
open override func setupView() { open override func setupView() {
super.setupView() super.setupView()
backgroundColor = .white backgroundColor = VDSColor.backgroundPrimaryLight
addSubview(bottomLine) addSubview(bottomLine)
setupCollectionView() setupCollectionView()
setupSelectionLine() setupSelectionLine()
@ -94,7 +95,7 @@ import UIKit
bottomScrollView.delegate = self bottomScrollView.delegate = self
addSubview(bottomScrollView) addSubview(bottomScrollView)
bottomScrollView.addSubview(bottomContentView) bottomScrollView.addSubview(bottomContentView)
selectionLine.backgroundColor = .mvmRed selectionLine.backgroundColor = VDSColor.paletteRed
bottomContentView.addSubview(selectionLine) bottomContentView.addSubview(selectionLine)
bringSubviewToFront(bottomScrollView) bringSubviewToFront(bottomScrollView)
} }
@ -153,8 +154,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()
} }
} }
@ -169,10 +169,10 @@ extension Tabs: UICollectionViewDataSource {
} }
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let labelModel = tabsModel?.tabs[indexPath.row].label, let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TabCellId, for: indexPath) as? TabItemCell else { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TabCellId, for: indexPath) as? TabItemCell else {
return UICollectionViewCell() return UICollectionViewCell()
} }
cell.updateCell(labelModel: labelModel, indexPath: indexPath, delegateObject: delegateObject, additionalData: additionalData, selected: indexPath.row == selectedIndex, tabsModel: tabsModel) cell.updateCell(indexPath: indexPath, delegateObject: delegateObject, additionalData: additionalData, selected: indexPath.row == selectedIndex, tabsModel: tabsModel)
updateView(collectionView.bounds.width) updateView(collectionView.bounds.width)
return cell return cell
} }
@ -332,13 +332,14 @@ extension Tabs {
label.updateView(size) label.updateView(size)
} }
public func updateCell(labelModel: LabelModel, indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, selected: Bool, tabsModel: TabsModel?) { public func updateCell(indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, selected: Bool, tabsModel: TabsModel?) {
guard let tabsModel = tabsModel else { return }
label.reset() label.reset()
label.set(with: labelModel, delegateObject, additionalData) label.set(with: tabsModel.tabs[indexPath.row].label, delegateObject, additionalData)
if selected { if selected {
label.textColor = tabsModel?.selectedColor.uiColor ?? .black label.textColor = tabsModel.selectedColor.uiColor
} else { } else {
label.textColor = .mvmCoolGray6 label.textColor = tabsModel.unselectedColor.uiColor
} }
updateAccessibility(indexPath: indexPath, selected: selected, tabsModel: tabsModel) updateAccessibility(indexPath: indexPath, selected: selected, tabsModel: tabsModel)
} }

View File

@ -7,22 +7,78 @@
// //
import UIKit import UIKit
import VDSColorTokens
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: VDSColor.backgroundPrimaryDark) }
return Color(uiColor: VDSColor.backgroundPrimaryLight)
}
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: VDSColor.elementsPrimaryOndark) }
return Color(uiColor: VDSColor.elementsPrimaryOnlight)
}
set {
_selectedColor = newValue
}
}
private var _unselectedColor: Color?
open var unselectedColor: Color {
get {
if let unselectedColor = _unselectedColor { return unselectedColor }
if let style = style,
style == .dark { return Color(uiColor: VDSColor.elementsSecondaryOndark) }
return Color(uiColor: VDSColor.elementsSecondaryOnlight)
}
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: VDSColor.elementsPrimaryOndark) }
return Color(uiColor: VDSColor.paletteRed)
}
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 +89,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 +126,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 +145,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,12 @@
// Copyright © 2020 Verizon Wireless. All rights reserved. // Copyright © 2020 Verizon Wireless. All rights reserved.
// //
import VDSColorTokens
public enum NavigationItemStyle: String, Codable {
case light
case dark
}
open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol { open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol {
//-------------------------------------------------- //--------------------------------------------------
@ -14,12 +20,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: VDSColor.backgroundPrimaryDark) }
return Color(uiColor: VDSColor.backgroundPrimaryLight)
}
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: VDSColor.elementsPrimaryOndark) }
return Color(uiColor: VDSColor.elementsPrimaryOnlight)
}
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?
@ -28,17 +61,13 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
open var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]? open var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
open var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]? open var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
open var titleView: MoleculeModelProtocol? open var titleView: MoleculeModelProtocol?
open var titleOffset: UIOffset?
//-------------------------------------------------- //--------------------------------------------------
// 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 +86,8 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
case additionalLeftButtons case additionalLeftButtons
case additionalRightButtons case additionalRightButtons
case titleView case titleView
case style
case titleOffset
} }
//-------------------------------------------------- //--------------------------------------------------
@ -66,16 +97,25 @@ 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)
titleOffset = try typeContainer.decodeIfPresent(UIOffset.self, forKey: .titleOffset) ?? UIOffset(horizontal: -CGFloat.greatestFiniteMagnitude, vertical: 0)
line?.inverted = style == .dark
} }
open func encode(to encoder: Encoder) throws { open func encode(to encoder: Encoder) throws {
@ -83,8 +123,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 +132,8 @@ 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)
try container.encodeIfPresent(titleOffset, forKey: .titleOffset)
} }
} }

View File

@ -0,0 +1,213 @@
//
// 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
}
<<<<<<< HEAD:MVMCoreUI/Containers/NavigationController.swift
/// 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
}
static 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, except for the buttons.
public static func setNavigationBarUI(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
let navigationBar = navigationController.navigationBar
let font = MFStyler.fontBoldBodySmall(false)
let backgroundColor = navigationItemModel.backgroundColor?.uiColor
let tint = navigationItemModel.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.titlePositionAdjustment = navigationItemModel.titleOffset ?? .zero
appearance.shadowColor = navigationItemModel.line?.backgroundColor?.uiColor ?? .clear
appearance.shadowImage = getNavigationBarShadowImage(for: navigationItemModel)?.withRenderingMode(.alwaysTemplate)
navigationBar.standardAppearance = appearance
navigationBar.scrollEdgeAppearance = appearance
navigationController.setNavigationBarHidden(navigationItemModel.hidden, animated: true)
}
/// 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
}
}
=======
>>>>>>> feature/develop_mvp_3:MVMCoreUI/Containers/NavigationController/NavigationController.swift
/// 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,168 @@
//
// MVMCoreUISplitViewController+Extension.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 6/18/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
import UIKit
// Navigation bar update functions
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.
func setNavigationBar(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
guard navigationController == self.navigationController,
viewController == getCurrentDetailViewController() else {
/// Not the split view navigation controller, skip split functions.
return
}
setLeftPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isLeftPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false)
setRightPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isRightPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false)
setLeftNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
setRightNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
setNavigationIconColor(navigationItemModel.tintColor.uiColor)
}
/// Sets the left navigation items for the view controller based on model and splitview.
func setLeftNavigationButtons(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) {
guard let topViewController = navigationController.topViewController else { return }
var leftItems: [UIBarButtonItem] = []
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
// Add back button first.
if navigationItemModel?.hidesSystemBackButton == true {
var showBackButton: Bool
if let forceBackButton = navigationItemModel?.alwaysShowBackButton {
showBackButton = forceBackButton
} else {
showBackButton = MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 0 > 1
}
if showBackButton {
if let backButtonModel = navigationItemModel?.backButton {
leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
} else if let backButton = backButton {
// Default to legacy if we have default back button.
leftItems.append(backButton)
}
}
}
// Add the panel button after the back button.
if let panelButton = leftPanelButton,
leftPanelIsAccessible,
!leftPanelStaysExtended() {
leftItems.append(panelButton)
}
// Add other model buttons
if let leftItemModels = navigationItemModel?.additionalLeftButtons {
for item in leftItemModels {
leftItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
}
}
// Add any buttons added by the splitview.
if let additionalLeftButtons = additionalLeftButtons(for: viewController) {
leftItems.append(contentsOf: additionalLeftButtons)
}
topViewController.navigationItem.setLeftBarButtonItems(leftItems.count > 0 ? leftItems : nil, animated: !DisableAnimations.boolValue)
}
/// Sets the right navigation items for the view controller based on model and splitview.
func setRightNavigationButtons(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) {
guard let topViewController = navigationController.topViewController else { return }
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
var rightItems: [UIBarButtonItem] = []
// Add the panel button first.
if let panelButton = rightPanelButton,
rightPanelIsAccessible,
!rightPanelStaysExtended() {
rightItems.append(panelButton)
}
// Add other model buttons
if let rightItemModels = navigationItemModel?.additionalRightButtons {
for item in rightItemModels {
rightItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
}
}
// Add any buttons added by the splitview.
if let additionalRightButtons = additionalRightButtons(for: viewController) {
rightItems.append(contentsOf: additionalRightButtons)
}
topViewController.navigationItem.setRightBarButtonItems(rightItems.count > 0 ? rightItems : nil, animated: !DisableAnimations.boolValue)
}
@objc func navigationBarModelExists() -> Bool {
// Legacy Navigation
guard let currentViewController = getCurrentDetailViewController(),
let _ = navigationController?.getNavigationModel(from: currentViewController) else { return false }
return true
}
/// Convenience function to update the navigation bar if the controller is the current lowest controller.
@objc func updateNavigationBarFor(viewController: UIViewController) {
guard let navigationController = navigationController,
navigationController.isDisplayed(viewController: viewController),
let model = navigationController.getNavigationModel(from: viewController) else { return }
<<<<<<< HEAD
set(for: viewController, navigationController: navigationController, navigationItemModel: model)
guard !(topAlertView?.overridingStatusBar() ?? false) else { return }
setStatusBarForCurrentViewController()
}
/// Returns the bar style for the background color. Light if on a dark background, otherwise default.
func getStatusBarStyle(for backgroundColor: UIColor?) -> UIStatusBarStyle {
var greyScale: CGFloat = 0
if backgroundColor?.getWhite(&greyScale, alpha: nil) == true,
greyScale < 0.5 { return .lightContent }
return .default
}
/// Updates the status bar background color and style.
@objc func setStatusBarForCurrentViewController() {
let viewController = getCurrentViewController() as? MVMCoreUIDetailViewProtocol
let backgroundColor = viewController?.defaultStatusBarBackgroundColor?() ??
navigationController?.navigationBar.standardAppearance.backgroundColor ??
statusBarView?.backgroundColor
let style = viewController?.defaultStatusBarStyle?() ??
getStatusBarStyle(for: backgroundColor)
setStatusBarBackgroundColor(backgroundColor, style: style)
=======
setNavigationBar(for: viewController, navigationController: navigationController, navigationItemModel: model)
>>>>>>> feature/develop_mvp_3
}
}
extension MVMCoreUISplitViewController: MVMCoreViewManagerProtocol {
public func getCurrentViewController() -> UIViewController? {
navigationController?.getCurrentViewController()
}
public func containsPage(withPageType pageType: String?) -> Bool {
navigationController?.containsPage(withPageType: pageType) ?? false
}
public func displayedViewController(_ viewController: UIViewController) {
setupPanels()
updateNavigationBarFor(viewController: viewController)
}
public func newDataReceived(in viewController: UIViewController) {
updateNavigationBarFor(viewController: viewController)
}
}

View File

@ -156,10 +156,10 @@ open class Styler {
} }
} else { } else {
if isBold() { if isBold() {
return size >= 15 ? MFFonts.mfFontDSBold(size) : MFFonts.mfFontTXBold(size) return size >= 13 ? MFFonts.mfFontDSBold(size) : MFFonts.mfFontTXBold(size)
} else { } else {
return size >= 15 ? MFFonts.mfFontDSRegular(size) : MFFonts.mfFontTXRegular(size) return size >= 13 ? MFFonts.mfFontDSRegular(size) : MFFonts.mfFontTXRegular(size)
} }
} }
} }