Merge branch 'develop' into feature/star

# Conflicts:
#	MVMCoreUI.xcodeproj/project.pbxproj
#	MVMCoreUI/Atomic/MoleculeObjectMapping.swift
This commit is contained in:
Lekshmi S 2020-10-12 09:56:50 +05:30
commit 37f8f2ac25
20 changed files with 464 additions and 141 deletions

View File

@ -240,6 +240,8 @@
AA997252247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */; };
AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */; };
AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */; };
AAA7CD69250641F90045B959 /* HeartModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA7CD68250641F90045B959 /* HeartModel.swift */; };
AAA7CD6B250642080045B959 /* Heart.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA7CD6A250642080045B959 /* Heart.swift */; };
AAA905DF24D1758700D1EFAB /* ListThreeColumnBillHistoryModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA905DE24D1758700D1EFAB /* ListThreeColumnBillHistoryModel.swift */; };
AAA905E124D1759A00D1EFAB /* ListThreeColumnBillHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA905E024D1759A00D1EFAB /* ListThreeColumnBillHistory.swift */; };
AAB7EDEF246ADA1600E54929 /* ListProgressBarThinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB7EDEE246ADA1600E54929 /* ListProgressBarThinModel.swift */; };
@ -307,6 +309,8 @@
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; };
D20C7009250BF99B0095B21C /* TopNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C7008250BF99B0095B21C /* TopNotificationModel.swift */; };
D20C700B250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */; };
D20F3B44252E00E4004B3F56 /* PageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20F3B43252E00E4004B3F56 /* PageProtocol.swift */; };
D20F3B5E252F9B5E004B3F56 /* NavigationBarRefreshProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20F3B5D252F9B5D004B3F56 /* NavigationBarRefreshProtocol.swift */; };
D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */; };
D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; };
D2169301251E51E7002A6324 /* SectionListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2169300251E51E7002A6324 /* SectionListTemplate.swift */; };
@ -473,6 +477,8 @@
D2CAC7D3251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7D2251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift */; };
D2D2FCF0252B72AF0033EAAA /* MoleculeSectionFooterModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D2FCEF252B72AF0033EAAA /* MoleculeSectionFooterModel.swift */; };
D2D2FCF3252B72CF0033EAAA /* MoleculeSectionFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D2FCF2252B72CF0033EAAA /* MoleculeSectionFooter.swift */; };
D2D3957A252FDBB300047B11 /* ModalSectionListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D39579252FDBB300047B11 /* ModalSectionListTemplate.swift */; };
D2D3957D252FDBCD00047B11 /* ModalSectionListTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D3957C252FDBCD00047B11 /* ModalSectionListTemplateModel.swift */; };
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; };
D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */; };
D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */; };
@ -490,12 +496,12 @@
D2E2A99F23E07F8A000B42E6 /* PillButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A99E23E07F8A000B42E6 /* PillButton.swift */; };
D2E2A9A123E095AB000B42E6 /* ButtonModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A9A023E095AB000B42E6 /* ButtonModelProtocol.swift */; };
D2E2A9A323E096B1000B42E6 /* DisableableModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A9A223E096B1000B42E6 /* DisableableModelProtocol.swift */; };
D2FA83D22513EA6900564112 /* NotificationXButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D12513EA6900564112 /* NotificationXButton.swift */; };
D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D32514F80C00564112 /* CollapsableNotification.swift */; };
D2FA83D62515021F00564112 /* CollapsableNotificationTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */; };
D2EC7BD52527B7A600F540AF /* MoleculeSectionHeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BD42527B7A600F540AF /* MoleculeSectionHeaderModel.swift */; };
D2EC7BD92527B7CF00F540AF /* MoleculeSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BD82527B7CF00F540AF /* MoleculeSectionHeader.swift */; };
D2EC7BDD2527B83700F540AF /* SectionHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */; };
D2FA83D22513EA6900564112 /* NotificationXButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D12513EA6900564112 /* NotificationXButton.swift */; };
D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D32514F80C00564112 /* CollapsableNotification.swift */; };
D2FA83D62515021F00564112 /* CollapsableNotificationTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */; };
D2FB151B23A2B65B00C20E10 /* MoleculeContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */; };
D2FB151D23A40F1500C20E10 /* MoleculeStackItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FB151C23A40F1500C20E10 /* MoleculeStackItem.swift */; };
D2FD4A4925199BD9000C28A9 /* AccessibilityProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FD4A4825199BD9000C28A9 /* AccessibilityProtocol.swift */; };
@ -744,6 +750,8 @@
AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconAllTextLinks.swift; sourceTree = "<group>"; };
AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyText.swift; sourceTree = "<group>"; };
AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyTextModel.swift; sourceTree = "<group>"; };
AAA7CD68250641F90045B959 /* HeartModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartModel.swift; sourceTree = "<group>"; };
AAA7CD6A250642080045B959 /* Heart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Heart.swift; sourceTree = "<group>"; };
AAA905DE24D1758700D1EFAB /* ListThreeColumnBillHistoryModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnBillHistoryModel.swift; sourceTree = "<group>"; };
AAA905E024D1759A00D1EFAB /* ListThreeColumnBillHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnBillHistory.swift; sourceTree = "<group>"; };
AAB7EDEE246ADA1600E54929 /* ListProgressBarThinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListProgressBarThinModel.swift; sourceTree = "<group>"; };
@ -811,6 +819,8 @@
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
D20C7008250BF99B0095B21C /* TopNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopNotificationModel.swift; sourceTree = "<group>"; };
D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUITopAlertView+Extension.swift"; sourceTree = "<group>"; };
D20F3B43252E00E4004B3F56 /* PageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageProtocol.swift; sourceTree = "<group>"; };
D20F3B5D252F9B5D004B3F56 /* NavigationBarRefreshProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarRefreshProtocol.swift; sourceTree = "<group>"; };
D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModel.swift; sourceTree = "<group>"; };
D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
D2169300251E51E7002A6324 /* SectionListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionListTemplate.swift; sourceTree = "<group>"; };
@ -979,6 +989,8 @@
D2CAC7D2251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUITopAlertExpandableView+Extension.swift"; sourceTree = "<group>"; };
D2D2FCEF252B72AF0033EAAA /* MoleculeSectionFooterModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionFooterModel.swift; sourceTree = "<group>"; };
D2D2FCF2252B72CF0033EAAA /* MoleculeSectionFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionFooter.swift; sourceTree = "<group>"; };
D2D39579252FDBB300047B11 /* ModalSectionListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalSectionListTemplate.swift; sourceTree = "<group>"; };
D2D3957C252FDBCD00047B11 /* ModalSectionListTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalSectionListTemplateModel.swift; sourceTree = "<group>"; };
D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scroller.swift; sourceTree = "<group>"; };
D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTemplate.swift; sourceTree = "<group>"; };
D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeHeaderModel.swift; sourceTree = "<group>"; };
@ -995,12 +1007,12 @@
D2E2A99E23E07F8A000B42E6 /* PillButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillButton.swift; sourceTree = "<group>"; };
D2E2A9A023E095AB000B42E6 /* ButtonModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonModelProtocol.swift; sourceTree = "<group>"; };
D2E2A9A223E096B1000B42E6 /* DisableableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableableModelProtocol.swift; sourceTree = "<group>"; };
D2FA83D12513EA6900564112 /* NotificationXButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButton.swift; sourceTree = "<group>"; };
D2FA83D32514F80C00564112 /* CollapsableNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotification.swift; sourceTree = "<group>"; };
D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationTopView.swift; sourceTree = "<group>"; };
D2EC7BD42527B7A600F540AF /* MoleculeSectionHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionHeaderModel.swift; sourceTree = "<group>"; };
D2EC7BD82527B7CF00F540AF /* MoleculeSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionHeader.swift; sourceTree = "<group>"; };
D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeaderFooterView.swift; sourceTree = "<group>"; };
D2FA83D12513EA6900564112 /* NotificationXButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButton.swift; sourceTree = "<group>"; };
D2FA83D32514F80C00564112 /* CollapsableNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotification.swift; sourceTree = "<group>"; };
D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationTopView.swift; sourceTree = "<group>"; };
D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeContainer.swift; sourceTree = "<group>"; };
D2FB151C23A40F1500C20E10 /* MoleculeStackItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeStackItem.swift; sourceTree = "<group>"; };
D2FD4A4825199BD9000C28A9 /* AccessibilityProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityProtocol.swift; sourceTree = "<group>"; };
@ -1611,6 +1623,8 @@
D2092348244A51D40044AD09 /* RadioSwatchModel.swift */,
AAB9C109243496DD00151545 /* RadioSwatch.swift */,
AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */,
AAA7CD68250641F90045B959 /* HeartModel.swift */,
AAA7CD6A250642080045B959 /* Heart.swift */,
);
path = Selectors;
sourceTree = "<group>";
@ -1715,6 +1729,8 @@
D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */,
D2169302251E53D9002A6324 /* SectionListTemplateModel.swift */,
D2169300251E51E7002A6324 /* SectionListTemplate.swift */,
D2D3957C252FDBCD00047B11 /* ModalSectionListTemplateModel.swift */,
D2D39579252FDBB300047B11 /* ModalSectionListTemplate.swift */,
);
path = Templates;
sourceTree = "<group>";
@ -2101,8 +2117,10 @@
children = (
012A88C7238DB02000FE3DA1 /* MoleculeDelegateProtocol.swift */,
017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */,
D20F3B43252E00E4004B3F56 /* PageProtocol.swift */,
012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */,
D28BA7442481652D00B75CB8 /* TabBarProtocol.swift */,
D20F3B5D252F9B5D004B3F56 /* NavigationBarRefreshProtocol.swift */,
011B58EE23A2AA850085F53C /* ModelProtocols */,
);
path = Protocols;
@ -2272,6 +2290,7 @@
943784F5236B77BB006A1E82 /* Wheel.swift in Sources */,
31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */,
8D3BA9BF2433789900D341BA /* ListThreeColumnInternationalDataDivider.swift in Sources */,
AAA7CD6B250642080045B959 /* Heart.swift in Sources */,
94C661DA23CCF4FB00D9FE5B /* UIColor+Extension.swift in Sources */,
D28A838123CCB0D800DFE4FC /* AccordionListItemModel.swift in Sources */,
D2509ED62472EE2F001BFB9D /* NavigationImageButtonModel.swift in Sources */,
@ -2291,6 +2310,7 @@
BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */,
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */,
3265B30424BCA749000D154B /* HeadersH1NoButtonsBodyText.swift in Sources */,
AAA7CD69250641F90045B959 /* HeartModel.swift in Sources */,
D2FB151D23A40F1500C20E10 /* MoleculeStackItem.swift in Sources */,
D28BA7452481652D00B75CB8 /* TabBarProtocol.swift in Sources */,
AA11A41F23F15D3100D7962F /* ListRightVariablePayments.swift in Sources */,
@ -2389,6 +2409,7 @@
525239C02407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift in Sources */,
D2E2A99A23D8D6B4000B42E6 /* HeadlineBodyButtonModel.swift in Sources */,
D202AFE6242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift in Sources */,
D20F3B44252E00E4004B3F56 /* PageProtocol.swift in Sources */,
AA37CBD3251907200027344C /* StarsModel.swift in Sources */,
8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */,
94C0150C2421564A005811A9 /* ActionCollapseNotificationModel.swift in Sources */,
@ -2473,6 +2494,7 @@
D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */,
D2B18B94236214AD00A9AEDC /* NavigationController.swift in Sources */,
0A9D09222433796500D2E6C0 /* CarouselIndicator.swift in Sources */,
D20F3B5E252F9B5E004B3F56 /* NavigationBarRefreshProtocol.swift in Sources */,
D29E28DA23D21AFA00ACEA85 /* StringAndMoleculeModel.swift in Sources */,
D260105D23D0BCD400764D80 /* Stack.swift in Sources */,
0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */,
@ -2574,6 +2596,7 @@
0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */,
D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */,
AA2AD118244EE48C00BBFFE3 /* ListDeviceComplexLinkMediumModel.swift in Sources */,
D2D3957A252FDBB300047B11 /* ModalSectionListTemplate.swift in Sources */,
DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */,
D28BA741248025A300B75CB8 /* TabBarModel.swift in Sources */,
D224798A2314445E003FCCF9 /* LabelToggle.swift in Sources */,
@ -2687,6 +2710,7 @@
D260105923D0A92900764D80 /* ContainerProtocol.swift in Sources */,
BB6C6AC924225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift in Sources */,
C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */,
D2D3957D252FDBCD00047B11 /* ModalSectionListTemplateModel.swift in Sources */,
8D4687E2242E2DE400802879 /* ListFourColumnDataUsageListItemModel.swift in Sources */,
D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */,
012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */,

View File

@ -0,0 +1,114 @@
//
// Heart.swift
// MVMCoreUI
//
// Created by Lekshmi S on 07/09/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class Heart: Control, MFButtonProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
private var heartLayer: CAShapeLayer?
@objc public override var isSelected: Bool {
didSet {
heartModel?.isActive = isSelected
updateAccessibilityLabel()
}
}
public var delegateObject: MVMCoreUIDelegateObject?
public var heartModel: HeartModel? {
return model as? HeartModel
}
var additionalData: [AnyHashable: Any]?
//--------------------------------------------------
// MARK: - Constraints
//--------------------------------------------------
public var widthConstraint: NSLayoutConstraint?
public var heightConstraint: NSLayoutConstraint?
//------------------------------------------------------
// MARK: - State Handling
//------------------------------------------------------
open override func draw(_ rect: CGRect) {
//Draw the heart
heartLayer?.removeFromSuperlayer()
let heart = drawHeart()
layer.addSublayer(heart)
heartLayer = heart
}
func drawHeart() -> CAShapeLayer {
let heart = CAShapeLayer()
let rect = bounds
let leftArc = rect.width * 0.4
let rightArc = rect.height * 0.3
let arcRadius = sqrt(leftArc*leftArc + rightArc*rightArc)/2
let heartPath = UIBezierPath()
//Left Hand Curve
heartPath.addArc(withCenter: CGPoint(x: rect.width * 0.3, y: rect.height * 0.35), radius: arcRadius, startAngle: 135.degreesToRadians, endAngle: 315.degreesToRadians, clockwise: true)
//Top Centre Dip
heartPath.addLine(to: CGPoint(x: rect.width/2, y: rect.height * 0.2))
//Right Hand Curve
heartPath.addArc(withCenter: CGPoint(x: rect.width * 0.7, y: rect.height * 0.35), radius: arcRadius, startAngle: 225.degreesToRadians, endAngle: 45.degreesToRadians, clockwise: true)
//Right Bottom Line
heartPath.addLine(to: CGPoint(x: rect.width * 0.5, y: rect.height * 0.95))
//Left Bottom Line
heartPath.close()
heart.path = heartPath.cgPath
heart.fillColor = isSelected ? heartModel?.activeColor.cgColor : heartModel?.inActiveColor.cgColor
heart.opacity = 1.0
heart.lineWidth = 1
heart.strokeColor = isSelected ? UIColor.clear.cgColor : UIColor.mvmBlack.cgColor
return heart
}
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func setupView() {
super.setupView()
addTarget(self, action: #selector(tapAction), for: .touchUpInside)
widthConstraint = widthAnchor.constraint(equalToConstant: 22)
widthConstraint?.isActive = true
heightConstraint = heightAnchor.constraint(equalTo: widthAnchor, multiplier: 1)
heightConstraint?.isActive = true
isAccessibilityElement = true
accessibilityTraits = .button
updateAccessibilityLabel()
}
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
self.delegateObject = delegateObject
self.additionalData = additionalData
guard let model = model as? HeartModel else { return }
isSelected = model.isActive
}
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
/// Adjust accessibility label based on selection of Heart.
func updateAccessibilityLabel() {
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_unfavorite_action_hint" : "heart_favorite_action_hint")
accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_selected_state" : "heart_not_selected_state")
}
func tapAction() {
isSelected = !isSelected
if let heartModel = heartModel {
Button.performButtonAction(with: heartModel.action, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: heartModel)
}
setNeedsDisplay()
}
}
extension Int {
var degreesToRadians: CGFloat { return CGFloat(self) * .pi / 180 }
}

View File

@ -0,0 +1,65 @@
//
// HeartModel.swift
// MVMCoreUI
//
// Created by Lekshmi S on 07/09/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
open class HeartModel: MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "heart"
public var backgroundColor: Color?
public var isActive: Bool = false
public var activeColor: Color = Color(uiColor: .mvmRed)
public var inActiveColor: Color = Color(uiColor: .clear)
public var action: ActionModelProtocol = ActionNoopModel()
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case moleculeName
case backgroundColor
case isActive
case activeColor
case inActiveColor
case action
}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
if let isActive = try typeContainer.decodeIfPresent(Bool.self, forKey: .isActive) {
self.isActive = isActive
}
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
if let activeColor = try typeContainer.decodeIfPresent(Color.self, forKey: .activeColor) {
self.activeColor = activeColor
}
if let inActiveColor = try typeContainer.decodeIfPresent(Color.self, forKey: .inActiveColor) {
self.inActiveColor = inActiveColor
}
if let action: ActionModelProtocol = try typeContainer.decodeModelIfPresent(codingKey: .action) {
self.action = action
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(isActive, forKey: .isActive)
try container.encode(activeColor, forKey: .activeColor)
try container.encode(inActiveColor, forKey: .inActiveColor)
try container.encodeModel(action, forKey: .action)
}
}

View File

@ -35,12 +35,12 @@ import Foundation
}
/// Convenience function for legacy classes
public func getMoleculeModelForJSON(_ json: [String: Any]) throws -> MoleculeModelProtocol? {
public func getMoleculeModelForJSON(_ json: [String: Any], delegateObject: DelegateObject? = nil) throws -> MoleculeModelProtocol? {
guard let moleculeName = json.optionalStringForKey(KeyMoleculeName),
let type = ModelRegistry.getType(for: moleculeName, with: MoleculeModelProtocol.self) else {
throw ModelRegistry.Error.decoderErrorModelNotMapped()
}
guard let model = try type.decode(jsonDict: json) as? MoleculeModelProtocol else {
guard let model = try type.decode(jsonDict: json, delegateObject: delegateObject) as? MoleculeModelProtocol else {
throw ModelRegistry.Error.decoderError
}
return model
@ -87,6 +87,7 @@ import Foundation
MoleculeObjectMapping.shared()?.register(viewClass: RadioSwatches.self, viewModelClass: RadioSwatchesModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: Tags.self, viewModelClass: TagsModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: Tag.self, viewModelClass: TagModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: Heart.self, viewModelClass: HeartModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: Stars.self, viewModelClass: StarsModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: Star.self, viewModelClass: StarModel.self)

View File

@ -8,25 +8,25 @@
import Foundation
public class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol {
public class var identifier: String {
open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol {
open class var identifier: String {
return "navigationBar"
}
public var title: String?
public var hidden: Bool
public var backgroundColor: Color?
public var tintColor: Color
public var line: LineModel?
public var hidesSystemBackButton = true
open var title: String?
open var hidden: Bool
open var backgroundColor: Color?
open var tintColor: Color
open var line: LineModel?
open var hidesSystemBackButton = true
/// 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
public var alwaysShowBackButton: Bool?
public var backButton: (NavigationButtonModelProtocol & MoleculeModelProtocol)?
open var alwaysShowBackButton: Bool?
open var backButton: (NavigationButtonModelProtocol & MoleculeModelProtocol)?
public var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
public var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
public var titleView: MoleculeModelProtocol?
open var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
open var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
open var titleView: MoleculeModelProtocol?
public init() {
hidden = false
@ -44,8 +44,6 @@ public class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProt
case line
case alwaysShowBackButton
case backButton
case showLeftPanelButton
case showRightPanelButton
case additionalLeftButtons
case additionalRightButtons
case titleView

View File

@ -0,0 +1,34 @@
//
// NavigationBarRefreshProtocol.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 10/8/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
/// A protocol to inform that we should refresh the navigation bar ui.
@objc public protocol NavigationBarRefreshProtocol {
@objc func refreshNavigationUI()
}
extension UIViewController: NavigationBarRefreshProtocol {
/// Convenience function to refresh the navigation bar ui. A separate function for others to use.
@objc public static func refreshNavigationUI(for viewController: UIViewController) {
guard let model = (viewController as? PageProtocol)?.pageModel?.navigationBar else { return }
if let navigationController = viewController.navigationController {
NavigationController.setNavigationItem(navigationController: navigationController, navigationItemModel: model, viewController: viewController)
MVMCoreUISplitViewController.setNavigationBarUI(for: viewController, navigationController: navigationController, navigationItemModel: model)
}
if let manager = ((viewController as? MVMCoreViewManagerViewControllerProtocol)?.manager as? NavigationBarRefreshProtocol) {
// Refresh the manager if possible.
manager.refreshNavigationUI()
}
}
public func refreshNavigationUI() {
UIViewController.refreshNavigationUI(for: self)
}
}

View File

@ -0,0 +1,13 @@
//
// PageProtocol.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 10/7/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public protocol PageProtocol {
var pageModel: PageModelProtocol? { get set }
}

View File

@ -23,7 +23,7 @@ public extension TemplateProtocol where Self: ViewController {
let decoder = JSONDecoder()
try decoder.add(delegateObject: delegateObjectIVar)
self.templateModel = try decodeTemplate(using: decoder, from: data)
self.pageModel = templateModel as? MVMControllerModelProtocol
self.model = templateModel as? MVMControllerModelProtocol
}
func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> TemplateModel {

View File

@ -0,0 +1,30 @@
//
// ModalSectionListTemplate.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 10/8/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
open class ModalSectionListTemplate: SectionListTemplate {
// For subclassing the model.
open override func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> ModalSectionListTemplateModel {
return try decoder.decode(ModalSectionListTemplateModel.self, from: data)
}
override open func handleNewData() {
super.handleNewData()
_ = MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: {[weak self] _ in
guard let self = self else { return }
guard let model = self.templateModel as? ModalSectionListTemplateModel,
let actionMap = model.closeAction else {
MVMCoreActionHandler.shared()?.handleAction(with: ActionBackModel().toJSON(), additionalData: nil, delegateObject: self.delegateObjectIVar)
return
}
MVMCoreActionHandler.shared()?.handleAction(with: actionMap.toJSON(), additionalData: nil, delegateObject: self.delegateObjectIVar)
})
}
}

View File

@ -0,0 +1,32 @@
//
// ModalSectionListTemplateModel.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 10/8/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
@objcMembers public class ModalSectionListTemplateModel: SectionListTemplateModel {
public override class var identifier: String {
return "modalSectionList"
}
public var closeAction: ActionModelProtocol?
private enum CodingKeys: String, CodingKey {
case closeAction
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
closeAction = try typeContainer.decodeModelIfPresent(codingKey: .closeAction)
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeModelIfPresent(closeAction, forKey: .closeAction)
}
}

View File

@ -63,6 +63,16 @@ open class ScrollingViewController: ViewController {
registerForKeyboardNotifications()
}
open override func handleNewData() {
super.handleNewData()
// will change scrollView indicatorStyle automatically on the basis of backgroundColor
var greyScale: CGFloat = 0
if view.backgroundColor?.getWhite(&greyScale, alpha: nil) ?? false {
scrollView.indicatorStyle = greyScale > 0.5 ? .black : .white
}
scrollView.flashScrollIndicators()
}
//--------------------------------------------------
// MARK: - Keyboard Handling
//--------------------------------------------------

View File

@ -8,15 +8,23 @@
import UIKit
@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, MVMCoreLoadDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate, MVMCoreUIDetailViewProtocol {
@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, MVMCoreLoadDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate, MVMCoreUIDetailViewProtocol, PageProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@objc public var pageType: String?
@objc public var loadObject: MVMCoreLoadObject?
public var pageModel: MVMControllerModelProtocol?
public var model: MVMControllerModelProtocol?
public var pageModel: PageModelProtocol? {
get {
return model
}
set {
model = newValue as? MVMControllerModelProtocol
}
}
/// Set if this page is containted in a manager.
public var manager: (UIViewController & MVMCoreViewManagerProtocol)?
@ -111,9 +119,15 @@ import UIKit
MVMCoreDispatchUtility.performBlock(onMainThread: {
self.handleNewDataAndUpdateUI()
// Update navigation bar if showing.
if MVMCoreUIUtility.getCurrentVisibleController() == self {
// Update navigation bar if showing.
self.setNavigationBar()
self.manager?.refreshNavigationUI()
}
// Update splitview properties
if self == MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() {
MVMCoreUISplitViewController.main()?.setBottomProgressBarProgress(self.bottomProgress() ?? 0)
self.updateTabBar()
}
})
} catch {
@ -127,7 +141,7 @@ import UIKit
pageType = loadObject.pageType
self.loadObject = loadObject
// Verifies all modules needed are loaded. TODO: change to ViewController
// Verifies all modules needed are loaded.
guard ViewController.verifyRequiredModulesLoaded(for: loadObject, error: error) else { return false }
// Parse the model for the page.
@ -214,18 +228,18 @@ import UIKit
/// Creates a legacy navigation model.
open func createDefaultLegacyNavigationModel() -> NavigationItemModel {
let navigationModel = NavigationItemModel()
navigationModel.title = pageModel?.screenHeading
navigationModel.title = model?.screenHeading
return navigationModel
}
/// Processes any new data. Called after the page is loaded the first time and on response updates for this page,
open func handleNewData() {
if formValidator == nil {
let rules = pageModel?.formRules
let rules = model?.formRules
formValidator = FormValidator(rules)
}
if let backgroundColor = pageModel?.backgroundColor {
if let backgroundColor = model?.backgroundColor {
view.backgroundColor = backgroundColor.uiColor
}
@ -234,16 +248,16 @@ import UIKit
}
//--------------------------------------------------
// MARK: - Navigation Item (Move to model base)
// MARK: - Navigation Item
//--------------------------------------------------
open func getNavigationModel() -> NavigationItemModelProtocol? {
// TODO: remove legacy. Temporary, convert legacy to navigation model.
if pageModel?.navigationBar == nil {
if model?.navigationBar == nil {
let navigationItem = createDefaultLegacyNavigationModel()
pageModel?.navigationBar = navigationItem
model?.navigationBar = navigationItem
}
return pageModel?.navigationBar
return model?.navigationBar
}
/// Sets the navigation item for this view controller.
@ -252,70 +266,22 @@ import UIKit
let navigationController = navigationController
else { return }
// We additionally want our left items
navigationItem.leftItemsSupplementBackButton = true
// Utilize helper function to set the navigation item state.
NavigationController.setNavigationItem(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: self)
}
/// Sets the appearance of the navigation bar based on the model.
open func setNavigationBar() {
let viewController = manager ?? self
guard let navigationItemModel = getNavigationModel(),
let navigationController = viewController.navigationController else {
let navigationController = navigationController else {
MVMCoreUISession.sharedGlobal()?.splitViewController?.parent?.setNeedsStatusBarAppearanceUpdate()
return
}
// Utilize helper function to set the split view and navigation item state.
MVMCoreUISplitViewController.setNavigationBarUI(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel, leftPanelAccessible: isMasterInitiallyAccessible(), rightPanelAccessible: isSupportInitiallyAccessible(), progress: bottomProgress() ?? 0)
MVMCoreUISplitViewController.setNavigationBarUI(for: self, navigationController: navigationController, navigationItemModel: navigationItemModel)
}
// Eventually will be moved to server
open func isMasterInitiallyAccessible() -> Bool {
if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false {
return false
}
return MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false
}
// Eventually will be moved to server
open func isSupportInitiallyAccessible() -> Bool {
if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false {
return false
}
return (MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false) || showRightPanelForScreenBeforeLaunchApp()
}
open func showRightPanelForScreenBeforeLaunchApp() -> Bool {
return loadObject?.pageJSON?.lenientBoolForKey("showRightPanel") ?? false
}
// Eventually will be moved to separate button in navigation item model
open func isOverridingRightButton() -> Bool {
guard let rightPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("rightPanelButtonLink")
else { return false }
MVMCoreActionHandler.shared()?.handleAction(with: rightPanelLink, additionalData: nil, delegateObject: delegateObject())
return true
}
// Eventually will be moved to separate button in navigation item model
open func isOverridingLeftButton() -> Bool {
guard let leftPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("leftPanelButtonLink")
else { return false }
MVMCoreActionHandler.shared()?.handleAction(with: leftPanelLink, additionalData: nil, delegateObject: delegateObject())
return true
}
// Eventually will be moved to Model
open func bottomProgress() -> Float? {
guard let progressString = loadObject?.pageJSON?.optionalStringForKey(KeyProgressPercent),
let progress = Float(progressString)
else { return nil }
return progress / Float(100)
}
//--------------------------------------------------
// MARK: - TabBar
//--------------------------------------------------
@ -324,7 +290,7 @@ import UIKit
guard MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() == self else { return }
MVMCoreUISplitViewController.main()?.tabBar?.delegateObject = delegateObjectIVar
if let index = (pageModel as? TabPageModelProtocol)?.tabBarIndex {
if let index = (model as? TabPageModelProtocol)?.tabBarIndex {
MVMCoreUISplitViewController.main()?.tabBar?.highlightTab(at: index)
} else if let index = loadObject?.requestParameters?.actionMap?["tabBarIndex"] as? Int {
MVMCoreUISplitViewController.main()?.tabBar?.highlightTab(at: index)
@ -335,7 +301,7 @@ import UIKit
self.tabBarIndex = index
}
if let hidden = (pageModel as? TabPageModelProtocol)?.tabBarHidden {
if let hidden = (model as? TabPageModelProtocol)?.tabBarHidden {
MVMCoreUISplitViewController.main()?.updateTabBarShowing(!hidden)
} else if let hidden = loadObject?.requestParameters?.actionMap?["tabBarHidden"] as? Bool {
MVMCoreUISplitViewController.main()?.updateTabBarShowing(!hidden)
@ -398,14 +364,15 @@ import UIKit
}
open func pageShown() {
// Update the navigation bar ui when view is appearing.
// Update split view properties if this is the current detail controller.
if self == MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() {
MVMCoreUISplitViewController.main()?.setupPanels()
MVMCoreUISplitViewController.main()?.setBottomProgressBarProgress(bottomProgress() ?? 0)
updateTabBar()
}
setNavigationBar()
// Update tab if needed.
updateTabBar()
// Update the navigation bar ui when view is appearing.
setNavigationBar()
// Track.
MVMCoreUISession.sharedGlobal()?.currentPageType = pageType
@ -526,6 +493,51 @@ import UIKit
setNavigationBar()
}
public func isLeftPanelAccessible() -> Bool {
// TODO: Remove when hamburger menu is fully phased out.
if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false {
return false
}
return MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false
}
public func isRightPanelAccessible() -> Bool {
// TODO: Remove when FAB is 100%.
if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false {
return false
}
return (MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false) || showRightPanelForScreenBeforeLaunchApp()
}
open func showRightPanelForScreenBeforeLaunchApp() -> Bool {
return loadObject?.pageJSON?.lenientBoolForKey("showRightPanel") ?? false
}
// TODO: make molecular
open func isOverridingRightButton() -> Bool {
guard let rightPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("rightPanelButtonLink")
else { return false }
MVMCoreActionHandler.shared()?.handleAction(with: rightPanelLink, additionalData: nil, delegateObject: delegateObject())
return true
}
// TODO: make molecular
open func isOverridingLeftButton() -> Bool {
guard let leftPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("leftPanelButtonLink")
else { return false }
MVMCoreActionHandler.shared()?.handleAction(with: leftPanelLink, additionalData: nil, delegateObject: delegateObject())
return true
}
// Eventually will be moved to Model
open func bottomProgress() -> Float? {
guard let progressString = loadObject?.pageJSON?.optionalStringForKey(KeyProgressPercent),
let progress = Float(progressString)
else { return nil }
return progress / Float(100)
}
//--------------------------------------------------
// MARK: - UITextFieldDelegate
//--------------------------------------------------
@ -594,6 +606,6 @@ import UIKit
//--------------------------------------------------
func executeBehaviors<T>(_ behaviorBlock:(_ behavior:T)->Void) {
pageModel?.behaviors?.compactMap({ $0 as? T }).forEach { behaviorBlock($0) }
model?.behaviors?.compactMap({ $0 as? T }).forEach { behaviorBlock($0) }
}
}

View File

@ -48,6 +48,7 @@ import UIKit
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)
}
@ -58,7 +59,7 @@ import UIKit
var leftItems: [UIBarButtonItem] = []
if navigationItemModel.alwaysShowBackButton != false {
if let backButtonModel = navigationItemModel.backButton,
navigationController.viewControllers.count > 1 || navigationItemModel.alwaysShowBackButton ?? false {
MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 0 > 1 || navigationItemModel.alwaysShowBackButton ?? false {
leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
}
if let leftItemModels = navigationItemModel.additionalLeftButtons {
@ -94,23 +95,7 @@ import UIKit
navigationController.separatorView?.isHidden = navigationItemModel.line?.type ?? .standard == .none
}
}
/// Convenience setter for legacy files
public static func setNavigationItem(navigationController: UINavigationController, navigationJSON: [String: Any], viewController: UIViewController) throws {
guard let barModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else {
throw ModelRegistry.Error.decoderOther(message: "Model not a bar model")
}
setNavigationItem(navigationController: navigationController, navigationItemModel: barModel, viewController: viewController)
}
/// Convenience setter for legacy files
public static func setNavigationBarUI(navigationController: UINavigationController, navigationJSON: [String: Any], viewController: UIViewController) throws {
guard let barModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else {
throw ModelRegistry.Error.decoderOther(message: "Model not a bar model")
}
setNavigationBarUI(navigationController: navigationController, navigationItemModel: barModel, viewController: viewController)
}
/// 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

View File

@ -15,6 +15,12 @@ NS_ASSUME_NONNULL_BEGIN
@optional
/// Returns if the left panel should be accessible.
- (BOOL)isLeftPanelAccessible;
/// Returns if the right panel should be accessible.
- (BOOL)isRightPanelAccessible;
- (void)panelWillAppear:(nonnull NSObject <MVMCoreUIPanelProtocol>*)panel;
- (void)panelWillAppear:(nonnull NSObject <MVMCoreUIPanelProtocol>*)panel overtakingDetail:(BOOL)willOvertake;
- (void)panelDidAppear:(nonnull NSObject <MVMCoreUIPanelProtocol>*)panel;

View File

@ -10,32 +10,29 @@ import Foundation
public extension MVMCoreUISplitViewController {
/// Convenience function. Sets the navigation and split view properties for the view controller. Optional parameters use current value if not set.
static func setNavigationBarUI(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, leftPanelAccessible: Bool? = nil, rightPanelAccessible: Bool? = nil, progress: Float? = nil) {
/// 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) {
guard let splitView = MVMCoreUISplitViewController.main(),
navigationController == splitView.navigationController,
navigationController.topViewController == viewController else {
NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
return
/// Not the split view navigation controller, skip split functions.
NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
return
}
splitView.set(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel, leftPanelAccessible: leftPanelAccessible, rightPanelAccessible: rightPanelAccessible, progress: progress)
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, leftPanelAccessible: Bool? = nil, rightPanelAccessible: Bool? = nil, progress: Float? = nil) {
private func set(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
setLeftPanelIsAccessible(leftPanelAccessible ?? leftPanelIsAccessible, for: viewController, updateNavigationButtons: false)
setRightPanelIsAccessible(rightPanelAccessible ?? rightPanelIsAccessible, for: viewController, updateNavigationButtons: false)
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)
if let progress = progress {
setBottomProgressBarProgress(progress)
}
}
/// Sets the left navigation items for the view controller based on model and splitview.
@ -48,7 +45,7 @@ public extension MVMCoreUISplitViewController {
if let forceBackButton = navigationItemModel?.alwaysShowBackButton {
showBackButton = forceBackButton
} else {
showBackButton = navigationController.viewControllers.count > 1
showBackButton = MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 0 > 1
}
if showBackButton {
if let backButtonModel = navigationItemModel?.backButton {
@ -107,20 +104,4 @@ public extension MVMCoreUISplitViewController {
viewController.navigationItem.setRightBarButtonItems(rightItems.count > 0 ? rightItems : nil, animated: !DisableAnimations.boolValue)
}
// MARK: - Legacy Functions
/// Convenience setter for legacy files. Sets the navigation item for the view controller based on the json and splitview controller
@objc static func setNavigationBarUI(for viewController: UIViewController, navigationController: UINavigationController, navigationJSON: [String: Any], leftPanelAccessible: Bool, rightPanelAccessible: Bool, progress: NSNumber?) throws {
guard let navigationItemModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else {
throw ModelRegistry.Error.decoderOther(message: "Model not a bar model")
}
guard let splitView = MVMCoreUISplitViewController.main(),
navigationController == splitView.navigationController,
navigationController.topViewController == viewController else {
NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
return
}
let progress = progress?.floatValue
splitView.set(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel, leftPanelAccessible: leftPanelAccessible, rightPanelAccessible: rightPanelAccessible, progress: progress)
}
}

View File

@ -241,7 +241,7 @@ CGFloat const PanelAnimationDuration = 0.2;
- (void)setLeftNavigationItemForViewController:(UIViewController * _Nonnull)viewController accessible:(BOOL)accessible extended:(BOOL)extended {
NSMutableArray *leftBarButtonItems = [NSMutableArray array];
if ([viewController.navigationController.viewControllers count] > 1) {
if (viewController.navigationController && [MVMCoreNavigationHandler.sharedNavigationHandler getViewControllersForNavigationController:viewController.navigationController].count > 1) {
[leftBarButtonItems addObject:self.backButton];
}
if ((accessible && !extended) && self.leftPanelButton) {

View File

@ -21,6 +21,7 @@ public extension MVMCoreUIViewControllerMappingObject {
register(template: MoleculeListTemplate.self)
add(toTemplateViewControllerMapping: ["modalList": MVMCoreViewControllerProgrammaticMappingObject(with: ModalMoleculeListTemplate.self)!])
add(toTemplateViewControllerMapping: [SectionListTemplateModel.identifier: MVMCoreViewControllerProgrammaticMappingObject(with: SectionListTemplate.self)!])
add(toTemplateViewControllerMapping: [ModalSectionListTemplateModel.identifier: MVMCoreViewControllerProgrammaticMappingObject(with: ModalSectionListTemplate.self)!])
register(template: ThreeLayerTemplate.self)
register(template: ThreeLayerCenterTemplate.self)

View File

@ -67,6 +67,11 @@
"AccOff" = "off";
"AccToggleHint" = "double tap to toggle";
// MARK: Heart
"heart_favorite_action_hint" = "Double tap to favorite";
"heart_unfavorite_action_hint" = "Double tap to unfavorite";
"heart_selected_state" = "Favorited";
"heart_not_selected_state" = "Un-favorited";
// MARK: Carousel
"MVMCoreUIPageControl_currentpage_index" = "page %@ of %d";

View File

@ -49,6 +49,11 @@
"AccOn" = "encendido";
"AccOff" = "apagado";
"AccToggleHint" = "toca dos veces para alternar";
// Heart
"heart_favorite_action_hint" = "Toca dos veces en favorito";
"heart_unfavorite_action_hint" = "Toca dos veces para dejar de marcar como favorito";
"heart_selected_state" = "Favoritos";
"heart_not_selected_state" = "No favorito";
// Carousel
"MVMCoreUIPageControl_currentpage_index" = "página %@ de %d";
"MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %@ of %d";

View File

@ -51,6 +51,13 @@
"AccOn" = "encendido";
"AccOff" = "apagado";
"AccToggleHint" = "toca dos veces para alternar";
// Heart
"heart_favorite_action_hint" = "Toca dos veces en favorito";
"heart_unfavorite_action_hint" = "Toca dos veces para dejar de marcar como favorito";
"heart_selected_state" = "Favoritos";
"heart_not_selected_state" = "No favorito";
// Carousel
"MVMCoreUIPageControl_currentpage_index" = "página %@ de %d";
"MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %@ of %d";