merging
This commit is contained in:
commit
ebd15c45e3
@ -334,6 +334,10 @@
|
||||
D28A839123CD4FD400DFE4FC /* CornerLabelsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A839023CD4FD400DFE4FC /* CornerLabelsModel.swift */; };
|
||||
D28A839323CE828900DFE4FC /* HeadlineBodyCaretLinkImageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A839223CE828900DFE4FC /* HeadlineBodyCaretLinkImageModel.swift */; };
|
||||
D28BA730247EC2EB00B75CB8 /* NavigationButtomModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28BA72F247EC2EB00B75CB8 /* NavigationButtomModelProtocol.swift */; };
|
||||
D28BA741248025A300B75CB8 /* TabBarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28BA740248025A300B75CB8 /* TabBarModel.swift */; };
|
||||
D28BA7432480284E00B75CB8 /* TabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28BA7422480284E00B75CB8 /* TabBar.swift */; };
|
||||
D28BA7452481652D00B75CB8 /* TabBarProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28BA7442481652D00B75CB8 /* TabBarProtocol.swift */; };
|
||||
D28BA74D248589C800B75CB8 /* TabPageModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28BA74C248589C800B75CB8 /* TabPageModelProtocol.swift */; };
|
||||
D296E14722A5984C0051EBE7 /* MVMCoreUIViewConstrainingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */; };
|
||||
D29C94D5242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29C94D4242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift */; };
|
||||
@ -768,6 +772,10 @@
|
||||
D28A839023CD4FD400DFE4FC /* CornerLabelsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabelsModel.swift; sourceTree = "<group>"; };
|
||||
D28A839223CE828900DFE4FC /* HeadlineBodyCaretLinkImageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyCaretLinkImageModel.swift; sourceTree = "<group>"; };
|
||||
D28BA72F247EC2EB00B75CB8 /* NavigationButtomModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationButtomModelProtocol.swift; sourceTree = "<group>"; };
|
||||
D28BA740248025A300B75CB8 /* TabBarModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarModel.swift; sourceTree = "<group>"; };
|
||||
D28BA7422480284E00B75CB8 /* TabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBar.swift; sourceTree = "<group>"; };
|
||||
D28BA7442481652D00B75CB8 /* TabBarProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarProtocol.swift; sourceTree = "<group>"; };
|
||||
D28BA74C248589C800B75CB8 /* TabPageModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabPageModelProtocol.swift; sourceTree = "<group>"; };
|
||||
D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewConstrainingProtocol.h; sourceTree = "<group>"; };
|
||||
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleMolecule.swift; sourceTree = "<group>"; };
|
||||
D29C94D4242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUICommonViewsUtility+Extension.swift"; sourceTree = "<group>"; };
|
||||
@ -904,6 +912,7 @@
|
||||
D2E2A9A223E096B1000B42E6 /* DisableableModelProtocol.swift */,
|
||||
D2092354244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift */,
|
||||
D2509ED02472ED9B001BFB9D /* NavigationItemModelProtocol.swift */,
|
||||
D28BA74C248589C800B75CB8 /* TabPageModelProtocol.swift */,
|
||||
);
|
||||
path = ModelProtocols;
|
||||
sourceTree = "<group>";
|
||||
@ -1232,6 +1241,8 @@
|
||||
017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */,
|
||||
D28764FA245A33A500CB882D /* TwoLinkViewModel.swift */,
|
||||
D28764F8245A327200CB882D /* TwoLinkView.swift */,
|
||||
D28BA740248025A300B75CB8 /* TabBarModel.swift */,
|
||||
D28BA7422480284E00B75CB8 /* TabBar.swift */,
|
||||
);
|
||||
path = HorizontalCombinationViews;
|
||||
sourceTree = "<group>";
|
||||
@ -1883,6 +1894,7 @@
|
||||
012A88C7238DB02000FE3DA1 /* MoleculeDelegateProtocol.swift */,
|
||||
017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */,
|
||||
012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */,
|
||||
D28BA7442481652D00B75CB8 /* TabBarProtocol.swift */,
|
||||
011B58EE23A2AA850085F53C /* ModelProtocols */,
|
||||
);
|
||||
path = Protocols;
|
||||
@ -2033,6 +2045,7 @@
|
||||
D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */,
|
||||
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */,
|
||||
D2FB151D23A40F1500C20E10 /* MoleculeStackItem.swift in Sources */,
|
||||
D28BA7452481652D00B75CB8 /* TabBarProtocol.swift in Sources */,
|
||||
AA11A41F23F15D3100D7962F /* ListRightVariablePayments.swift in Sources */,
|
||||
D28764AA2458980300CB882D /* ThreeLayerFillMiddleTemplate.swift in Sources */,
|
||||
0116A4E5228B19640094F3ED /* RadioButtonSelectionHelper.swift in Sources */,
|
||||
@ -2100,6 +2113,7 @@
|
||||
BB1D17E0244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift in Sources */,
|
||||
D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */,
|
||||
D28A837B23C928DA00DFE4FC /* MoleculeListCellProtocol.swift in Sources */,
|
||||
D28BA74D248589C800B75CB8 /* TabPageModelProtocol.swift in Sources */,
|
||||
014AA72F23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift in Sources */,
|
||||
0A21DB91235E0EDB00C160A2 /* DigitBox.swift in Sources */,
|
||||
BBAA4F04243D8E3B005AAD5F /* RadioBoxModel.swift in Sources */,
|
||||
@ -2276,6 +2290,7 @@
|
||||
D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */,
|
||||
AA2AD118244EE48C00BBFFE3 /* ListDeviceComplexLinkMediumModel.swift in Sources */,
|
||||
DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */,
|
||||
D28BA741248025A300B75CB8 /* TabBarModel.swift in Sources */,
|
||||
D224798A2314445E003FCCF9 /* LabelToggle.swift in Sources */,
|
||||
D2A92882241AAB67004E01C6 /* ScrollingViewController.swift in Sources */,
|
||||
C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */,
|
||||
@ -2375,6 +2390,7 @@
|
||||
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
|
||||
0A98D1722485842200FAD895 /* AccessibilityProtocol.swift in Sources */,
|
||||
94C661D923CCF4B400D9FE5B /* LeftRightLabelModel.swift in Sources */,
|
||||
D28BA7432480284E00B75CB8 /* TabBar.swift in Sources */,
|
||||
AA26850C244840AE00CE34CC /* HeadersH2TinyButton.swift in Sources */,
|
||||
011D95AB2405C553000E3791 /* FormItemProtocol.swift in Sources */,
|
||||
D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */,
|
||||
|
||||
@ -17,6 +17,7 @@ import Foundation
|
||||
public let leftImage = LoadImageView()
|
||||
public let headlineBody = HeadlineBody()
|
||||
public let rightLabel = Label.createLabelRegularBodySmall(true)
|
||||
public let rightLabelStackItem: StackItem
|
||||
public var stack: Stack<StackModel>
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -24,9 +25,10 @@ import Foundation
|
||||
//--------------------------------------------------
|
||||
|
||||
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
stack = Stack<StackModel>.createStack(with: [(view: leftImage, model: StackItemModel(horizontalAlignment: .fill)),
|
||||
(view: headlineBody, model: StackItemModel(horizontalAlignment: .leading)),
|
||||
(view: rightLabel, model: StackItemModel(horizontalAlignment: .fill, verticalAlignment: .leading))], axis: .horizontal)
|
||||
rightLabelStackItem = StackItem(andContain: rightLabel)
|
||||
let stackItems = [StackItem(andContain: leftImage), StackItem(andContain: headlineBody), rightLabelStackItem]
|
||||
let stackModel = StackModel(molecules: [StackItemModel(horizontalAlignment: .fill), StackItemModel(horizontalAlignment: .fill), StackItemModel(horizontalAlignment: .fill)], axis: .horizontal)
|
||||
stack = Stack<StackModel>(with: stackModel, stackItems: stackItems)
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
}
|
||||
|
||||
@ -34,7 +36,17 @@ import Foundation
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
open override func alignAccessoryToHero() -> CGPoint? {
|
||||
// Ensures that the right label is centered vertically with headline.
|
||||
let heroCenter = super.alignAccessoryToHero()
|
||||
if let heroCenter = heroCenter {
|
||||
let convertedPoint = stack.convert(heroCenter, from: self)
|
||||
rightLabelStackItem.containerHelper.alignCenterVerticalConstraint?.constant = convertedPoint.y - stack.bounds.midY
|
||||
}
|
||||
return heroCenter
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// MARK: - View Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
|
||||
@ -0,0 +1,101 @@
|
||||
//
|
||||
// TabBar.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 5/28/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class TabBar: UITabBar, MoleculeViewProtocol, TabBarProtocol, UITabBarDelegate {
|
||||
|
||||
public var model: TabBarModel
|
||||
public var delegateObject: MVMCoreUIDelegateObject?
|
||||
public let line = Line()
|
||||
|
||||
required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
guard let model = model as? TabBarModel else {
|
||||
fatalError("model is not TabBarModel")
|
||||
}
|
||||
self.model = model
|
||||
super.init(frame: .zero)
|
||||
|
||||
delegate = self
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
line.addLine(to: self, edge: .top, useMargin: false)
|
||||
line.backgroundColor = .mvmCoolGray3
|
||||
set(with: model, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
||||
guard let model = model as? TabBarModel else { return }
|
||||
self.model = model
|
||||
|
||||
// Set appearance
|
||||
if #available(iOS 13.0, *) {
|
||||
let appearance = UITabBarAppearance()
|
||||
appearance.backgroundColor = model.backgroundColor?.uiColor
|
||||
setTabBarItemColors(appearance.stackedLayoutAppearance, model: model)
|
||||
setTabBarItemColors(appearance.inlineLayoutAppearance, model: model)
|
||||
setTabBarItemColors(appearance.compactInlineLayoutAppearance, model: model)
|
||||
standardAppearance = appearance
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
backgroundColor = model.backgroundColor?.uiColor
|
||||
tintColor = model.selectedColor.uiColor
|
||||
unselectedItemTintColor = model.unSelectedColor.uiColor
|
||||
barTintColor = model.backgroundColor?.uiColor
|
||||
isTranslucent = false
|
||||
}
|
||||
|
||||
// Add buttons
|
||||
var tabs: [UITabBarItem] = []
|
||||
for (index, tab) in model.tabs.enumerated() {
|
||||
let tabBarItem = UITabBarItem(title: tab.title, image: UIImage(named: tab.image, in: MVMCoreCache.shared()?.bundleToUseForImages(), compatibleWith: nil), tag: index)
|
||||
tabs.append(tabBarItem)
|
||||
}
|
||||
setItems(tabs, animated: false)
|
||||
selectedItem = tabs[model.selectedTab]
|
||||
}
|
||||
|
||||
/// Sets the item colors.
|
||||
@available(iOS 13.0, *)
|
||||
private func setTabBarItemColors(_ itemAppearance: UITabBarItemAppearance, model: TabBarModel) {
|
||||
itemAppearance.normal.iconColor = model.unSelectedColor.uiColor
|
||||
itemAppearance.normal.titleTextAttributes = [NSAttributedString.Key.foregroundColor: model.unSelectedColor.uiColor]
|
||||
|
||||
itemAppearance.selected.iconColor = model.selectedColor.uiColor
|
||||
itemAppearance.selected.titleTextAttributes = [NSAttributedString.Key.foregroundColor: model.selectedColor.uiColor]
|
||||
}
|
||||
|
||||
// MARK: - UITabBarDelegate
|
||||
public func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
|
||||
self.model.selectedTab = item.tag
|
||||
Button.performButtonAction(with: model.tabs[item.tag].action, button: item, delegateObject: delegateObject, additionalData: nil)
|
||||
}
|
||||
|
||||
// MARK: - TabBarProtocol
|
||||
public func highlightTab(at index: Int) {
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
guard let newSelectedItem = self.items?[index] else { return }
|
||||
self.model.selectedTab = index
|
||||
self.selectedItem = newSelectedItem
|
||||
})
|
||||
}
|
||||
|
||||
public func selectTab(at index: Int) {
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
guard let newSelectedItem = self.items?[index] else { return }
|
||||
self.selectedItem = newSelectedItem
|
||||
self.tabBar(self, didSelect: newSelectedItem)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
extension UITabBarItem: MFButtonProtocol {
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
//
|
||||
// TabBarModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 5/28/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class TabBarModel: MoleculeModelProtocol {
|
||||
public static var identifier: String = "tabBar"
|
||||
public var backgroundColor: Color? = Color(uiColor: .white)
|
||||
public var tabs: [TabBarItemModel]
|
||||
public var selectedColor = Color(uiColor: .mvmBlack)
|
||||
public var unSelectedColor = Color(uiColor: .mvmCoolGray3)
|
||||
|
||||
// Must be capped to 0...(tabs.count - 1)
|
||||
public var selectedTab: Int = 0
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case tabs
|
||||
case selectedColor
|
||||
case unSelectedColor
|
||||
case selectedTab
|
||||
}
|
||||
|
||||
public init(with tabs: [TabBarItemModel]) {
|
||||
self.tabs = tabs
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
tabs = try typeContainer.decode([TabBarItemModel].self, forKey: .tabs)
|
||||
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) {
|
||||
backgroundColor = color
|
||||
}
|
||||
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .unSelectedColor) {
|
||||
unSelectedColor = color
|
||||
}
|
||||
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedColor) {
|
||||
selectedColor = color
|
||||
}
|
||||
if let index = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedTab) {
|
||||
selectedTab = index
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(tabs, forKey: .tabs)
|
||||
try container.encode(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encode(selectedColor, forKey: .selectedColor)
|
||||
try container.encode(unSelectedColor, forKey: .unSelectedColor)
|
||||
try container.encode(selectedTab, forKey: .selectedTab)
|
||||
}
|
||||
}
|
||||
|
||||
public class TabBarItemModel: Codable {
|
||||
var title: String
|
||||
var image: String
|
||||
var action: ActionModelProtocol
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case title
|
||||
case image
|
||||
case action
|
||||
}
|
||||
|
||||
public init(with title: String, image: String, action: ActionModelProtocol) {
|
||||
self.title = title
|
||||
self.image = image
|
||||
self.action = action
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
title = try typeContainer.decode(String.self, forKey: .title)
|
||||
image = try typeContainer.decode(String.self, forKey: .image)
|
||||
action = try typeContainer.decodeModel(codingKey: .action)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(title, forKey: .title)
|
||||
try container.encode(image, forKey: .image)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
}
|
||||
}
|
||||
@ -78,5 +78,4 @@ public class TabItemModel: Codable {
|
||||
try container.encodeModel(label, forKey: .label)
|
||||
try container.encodeModelIfPresent(action, forKey: .action)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
//
|
||||
// TabPageModelProtocol.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 6/1/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol TabPageModelProtocol {
|
||||
var tabBarHidden: Bool { get set }
|
||||
var tabBarIndex: Int? { get set }
|
||||
}
|
||||
17
MVMCoreUI/Atomic/Protocols/TabBarProtocol.swift
Normal file
17
MVMCoreUI/Atomic/Protocols/TabBarProtocol.swift
Normal file
@ -0,0 +1,17 @@
|
||||
//
|
||||
// TabBarProtocol.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 5/29/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc public protocol TabBarProtocol {
|
||||
/// Should visually select the given tab index.
|
||||
@objc func highlightTab(at index: Int)
|
||||
|
||||
/// Should select the tab index. As if the user selected it.
|
||||
@objc func selectTab(at index: Int)
|
||||
}
|
||||
@ -57,7 +57,9 @@ open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
|
||||
|
||||
let stack = MoleculeStackView(frame: .zero)
|
||||
moleculeStackModel.useStackSpacingBeforeFirstItem = true
|
||||
moleculeStackModel.useHorizontalMargins = true
|
||||
if moleculeStackModel.useHorizontalMargins == nil {
|
||||
moleculeStackModel.useHorizontalMargins = true
|
||||
}
|
||||
stack.set(with: moleculeStackModel, delegateObject() as? MVMCoreUIDelegateObject, nil)
|
||||
return stack
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
|
||||
|
||||
@objcMembers public class TemplateModel: MVMControllerModelProtocol {
|
||||
@objcMembers public class TemplateModel: MVMControllerModelProtocol, TabPageModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -29,6 +29,9 @@ import Foundation
|
||||
public var navigationBar: (NavigationItemModelProtocol & MoleculeModelProtocol)?
|
||||
public var formRules: [FormGroupRule]?
|
||||
public var behaviors: [PageBehaviorProtocol]?
|
||||
|
||||
public var tabBarHidden: Bool = false
|
||||
public var tabBarIndex: Int?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
@ -50,6 +53,8 @@ import Foundation
|
||||
case formRules
|
||||
case behaviors
|
||||
case navigationBar
|
||||
case tabBarHidden
|
||||
case tabBarIndex
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -64,6 +69,10 @@ import Foundation
|
||||
formRules = try typeContainer.decodeIfPresent([FormGroupRule].self, forKey: .formRules)
|
||||
behaviors = try typeContainer.decodeModelsIfPresent(codingKey: .behaviors)
|
||||
navigationBar = try typeContainer.decodeModelIfPresent(codingKey: .navigationBar)
|
||||
if let tabBarHidden = try typeContainer.decodeIfPresent(Bool.self, forKey: .tabBarHidden) {
|
||||
self.tabBarHidden = tabBarHidden
|
||||
}
|
||||
tabBarIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .tabBarIndex)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -74,5 +83,7 @@ import Foundation
|
||||
try container.encodeIfPresent(screenHeading, forKey: .screenHeading)
|
||||
try container.encodeIfPresent(formRules, forKey: .formRules)
|
||||
try container.encodeModelIfPresent(navigationBar, forKey: .navigationBar)
|
||||
try container.encode(tabBarHidden, forKey: .tabBarHidden)
|
||||
try container.encodeIfPresent(tabBarIndex, forKey: .tabBarIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,11 +31,7 @@ public typealias BarButtonAction = (BarButtonItem) -> ()
|
||||
open func set(with actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
buttonDelegate = delegateObject?.buttonDelegate
|
||||
actionDelegate?.buttonAction = { sender in
|
||||
if let data = try? actionModel.encode(using: JSONEncoder()),
|
||||
let actionMap = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.init()) as? [AnyHashable: Any],
|
||||
delegateObject?.buttonDelegate?.button?(sender, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
}
|
||||
Button.performButtonAction(with: actionModel, button: sender, delegateObject: delegateObject, additionalData: additionalData)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -78,11 +78,15 @@ public typealias ButtonAction = (Button) -> ()
|
||||
|
||||
addActionBlock(event: .touchUpInside) { [weak self] sender in
|
||||
guard let self = self else { return }
|
||||
if let data = try? actionModel.encode(using: JSONEncoder()),
|
||||
let actionMap = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.init()) as? [AnyHashable: Any],
|
||||
delegateObject?.buttonDelegate?.button?(self, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
}
|
||||
Self.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData)
|
||||
}
|
||||
}
|
||||
|
||||
open class func performButtonAction(with model: ActionModelProtocol, button: MFButtonProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
if let data = try? model.encode(using: JSONEncoder()),
|
||||
let actionMap = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.init()) as? [AnyHashable: Any],
|
||||
delegateObject?.buttonDelegate?.button?(button, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate {
|
||||
@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, MVMCoreLoadDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate {
|
||||
@objc public var pageType: String?
|
||||
@objc public var loadObject: MVMCoreLoadObject?
|
||||
public var pageModel: MVMControllerModelProtocol?
|
||||
@ -259,6 +259,16 @@ import UIKit
|
||||
MVMCoreUISplitViewController.main()?.setBottomProgressBarProgress(progress / Float(100))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - TabBar
|
||||
open func updateTabBar() {
|
||||
guard MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() == self,
|
||||
var tabModel = pageModel as? TabPageModelProtocol else { return }
|
||||
if let index = tabModel.tabBarIndex {
|
||||
MVMCoreUISplitViewController.main()?.tabBar?.highlightTab(at: index)
|
||||
}
|
||||
MVMCoreUISplitViewController.main()?.updateTabBarShowing(!tabModel.tabBarHidden)
|
||||
}
|
||||
|
||||
// MARK: - View lifecycle
|
||||
|
||||
@ -323,6 +333,9 @@ import UIKit
|
||||
open override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
// Update tab if needed.
|
||||
updateTabBar()
|
||||
|
||||
if manager == nil {
|
||||
MVMCoreUISession.sharedGlobal()?.currentPageType = pageType
|
||||
MVMCoreUILoggingHandler.shared()?.defaultLogPageState(forController: self)
|
||||
@ -371,6 +384,28 @@ import UIKit
|
||||
MVMCoreUILoggingHandler.shared()?.defaultLogPageState(forController: self)
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreLoadDelegateProtocol
|
||||
// TODO: Move this function out of here after architecture cleanup.
|
||||
open func loadFinished(_ loadObject: MVMCoreLoadObject?, loadedViewController: (UIViewController & MVMCoreViewControllerProtocol)?, error: MVMCoreErrorObject?) {
|
||||
|
||||
MVMCoreUILoggingHandler.log(withDelegateLoadFinished: loadObject, loadedViewController: loadedViewController, error: error)
|
||||
|
||||
// Open the support panel
|
||||
if error == nil,
|
||||
loadObject?.requestParameters?.openSupportPanel ?? (loadObject?.systemParametersJSON?.boolForKey(KeyOpenSupport) ?? false) == true {
|
||||
MVMCoreUISession.sharedGlobal()?.splitViewController?.showRightPanel(animated: true)
|
||||
}
|
||||
|
||||
// Selects the tab if needed. Page driven takes priority over action driven (see viewWillAppear)
|
||||
if let tab: Int = loadObject?.requestParameters?.actionMap?["tabBarIndex"] as? Int,
|
||||
error == nil,
|
||||
loadObject?.pageJSON?["tabBarIndex"] == nil {
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
MVMCoreUISplitViewController.main()?.tabBar?.highlightTab(at: tab)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreActionDelegateProtocol
|
||||
open func handleOpenPage(for requestParameters: MVMCoreRequestParameters, actionInformation: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) {
|
||||
formValidator?.addFormParams(requestParameters: requestParameters)
|
||||
|
||||
@ -11,9 +11,11 @@
|
||||
@import MVMCore.MVMCoreActionDelegateProtocol;
|
||||
#import <MVMCoreUI/MVMCoreUIPanelProtocol.h>
|
||||
#import <MVMCoreUI/MVMCoreUIPanelButtonProtocol.h>
|
||||
|
||||
@class MVMCoreUITopAlertView;
|
||||
@class MFViewController;
|
||||
@class NavigationController;
|
||||
@protocol TabBarProtocol;
|
||||
|
||||
typedef NS_ENUM(NSInteger, MFNumberOfDrawers) {
|
||||
MFNoDrawer = 0,
|
||||
@ -47,6 +49,9 @@ typedef NS_ENUM(NSInteger, MFNumberOfDrawers) {
|
||||
@property (nonatomic, readonly) BOOL rightPanelIsAccessible;
|
||||
@property (nullable, weak, nonatomic, readonly) UIViewController *navigationItemViewController;
|
||||
|
||||
/// Reference to the tabbar.
|
||||
@property (nullable, weak, nonatomic) UIView <TabBarProtocol>*tabBar;
|
||||
|
||||
// Convenience getter
|
||||
+ (nullable instancetype)mainSplitViewController;
|
||||
|
||||
@ -141,4 +146,15 @@ typedef NS_ENUM(NSInteger, MFNumberOfDrawers) {
|
||||
- (IBAction)backButtonPressed:(nullable id)sender;
|
||||
- (IBAction)rightPanelButtonPressed:(nullable id)sender;
|
||||
|
||||
#pragma mark - TabBar
|
||||
|
||||
/// Called when split view is loaded to create the initial tabbar. Default is nil.
|
||||
- (nullable UIView <TabBarProtocol>*)createTabBar;
|
||||
|
||||
/// Adds any tabbar at the bottom of the split view.
|
||||
- (void)addTabBar:(nonnull UIView <TabBarProtocol>*)tabBar;
|
||||
|
||||
/// Updates if the tab bar is showing or not.
|
||||
- (void)updateTabBarShowing:(BOOL)showing;
|
||||
|
||||
@end
|
||||
|
||||
@ -43,6 +43,8 @@ typedef NS_OPTIONS(NSInteger, MFExtendedDrawer) {
|
||||
@property (weak, nonatomic) UIView *leftPanelSeparator;
|
||||
@property (weak, nonatomic) UIView *rightPanelSeparator;
|
||||
|
||||
@property (weak, nonatomic) NSLayoutConstraint *bottomConstraint;
|
||||
|
||||
@property (weak, nonatomic, readwrite) NavigationController *navigationController;
|
||||
|
||||
// A view that covers the detail view when the master is out.
|
||||
@ -716,7 +718,7 @@ CGFloat const PanelAnimationDuration = 0.2;
|
||||
self.leftPanelWidth = leftPanelWidth;
|
||||
[NSLayoutConstraint constraintWithItem:self.mainView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.leftView attribute:NSLayoutAttributeRight multiplier:1.0 constant:0].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:self.leftView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.mainView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:self.leftView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.mainView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.leftView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
|
||||
|
||||
if ([panel respondsToSelector:@selector(buttonForPanel)]) {
|
||||
self.leftPanelButton = [panel buttonForPanel];
|
||||
@ -751,7 +753,7 @@ CGFloat const PanelAnimationDuration = 0.2;
|
||||
self.rightPanelWidth = rightPanelWidth;
|
||||
[NSLayoutConstraint constraintWithItem:self.rightView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.mainView attribute:NSLayoutAttributeRight multiplier:1.0 constant:0].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:self.rightView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.mainView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:self.rightView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.mainView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.rightView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
|
||||
|
||||
if ([panel respondsToSelector:@selector(buttonForPanel)]) {
|
||||
self.rightPanelButton = [panel buttonForPanel];
|
||||
@ -771,6 +773,36 @@ CGFloat const PanelAnimationDuration = 0.2;
|
||||
[self.view layoutIfNeeded];
|
||||
}
|
||||
|
||||
#pragma mark - TabBar
|
||||
|
||||
- (nullable UIView <TabBarProtocol>*)createTabBar {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)addTabBar:(nonnull UIView <TabBarProtocol>*)tabBar {
|
||||
[self.view insertSubview:tabBar atIndex:0];
|
||||
self.tabBar = tabBar;
|
||||
[tabBar.topAnchor constraintEqualToAnchor:self.bottomProgressBar.bottomAnchor].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:tabBar attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.mainView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:tabBar attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.mainView attribute:NSLayoutAttributeRight multiplier:1.0 constant:0].active = YES;
|
||||
[self updateTabBarShowing:YES];
|
||||
}
|
||||
|
||||
- (void)updateTabBarShowing:(BOOL)showing {
|
||||
self.tabBar.hidden = !showing;
|
||||
self.bottomConstraint.active = NO;
|
||||
if (showing && self.tabBar) {
|
||||
NSLayoutConstraint *bottom = [self.view.safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:self.tabBar.bottomAnchor];
|
||||
bottom.active = YES;
|
||||
self.bottomConstraint = bottom;
|
||||
} else {
|
||||
NSLayoutConstraint *bottom = [self.view.bottomAnchor constraintEqualToAnchor:self.bottomProgressBar.bottomAnchor];
|
||||
bottom.active = YES;
|
||||
self.bottomConstraint = bottom;
|
||||
}
|
||||
[self.view layoutIfNeeded];
|
||||
}
|
||||
|
||||
#pragma mark - Bottom Progress Bar
|
||||
|
||||
- (void)setBottomProgressBarProgress:(float)progress {
|
||||
@ -841,9 +873,17 @@ CGFloat const PanelAnimationDuration = 0.2;
|
||||
self.bottomProgressBarHeightConstraint = bottomProgressHeight;
|
||||
|
||||
if (topAlertView) {
|
||||
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[topAlertView]-0-[mainView]-0-[progressView]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(topAlertView, mainView, progressView)]];
|
||||
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[topAlertView]-0-[mainView]-0-[progressView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(topAlertView, mainView, progressView)]];
|
||||
} else {
|
||||
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[mainView]-0-[progressView]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(mainView, progressView)]];
|
||||
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[mainView]-0-[progressView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(mainView, progressView)]];
|
||||
}
|
||||
|
||||
// Add tabbar if we have it.
|
||||
UIView <TabBarProtocol>*tabs = [self createTabBar];
|
||||
if (tabs) {
|
||||
[self addTabBar:tabs];
|
||||
} else {
|
||||
[self updateTabBarShowing:NO];
|
||||
}
|
||||
|
||||
// Cover View
|
||||
@ -855,8 +895,8 @@ CGFloat const PanelAnimationDuration = 0.2;
|
||||
self.mainViewCoverView = coverView;
|
||||
[NSLayoutConstraint constraintWithItem:coverView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:mainView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:coverView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:mainView attribute:NSLayoutAttributeRight multiplier:1.0 constant:0].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:coverView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:mainView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:coverView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:mainView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:coverView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0].active = YES;
|
||||
[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:coverView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
|
||||
|
||||
[self setupPanels];
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user