Digital ACT192 story ONEAPP-8912- YIR | Year in review Prototype Updates
@ -293,6 +293,7 @@
|
|||||||
AF1C336F2885A16A006B1001 /* ActionCollapseNotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C336E2885A16A006B1001 /* ActionCollapseNotificationHandler.swift */; };
|
AF1C336F2885A16A006B1001 /* ActionCollapseNotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C336E2885A16A006B1001 /* ActionCollapseNotificationHandler.swift */; };
|
||||||
AF1C33712885AE76006B1001 /* MVMCoreUIActionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C33702885AE76006B1001 /* MVMCoreUIActionHandler.swift */; };
|
AF1C33712885AE76006B1001 /* MVMCoreUIActionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C33702885AE76006B1001 /* MVMCoreUIActionHandler.swift */; };
|
||||||
AF1C33732885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */; };
|
AF1C33732885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */; };
|
||||||
|
AF1CEFE82BEA73890001F9A5 /* VDSCoreTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF1CEFE72BEA73890001F9A5 /* VDSCoreTokens.xcframework */; };
|
||||||
AF60A7F62892D2E300919EEB /* ActionDismissNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F52892D2E300919EEB /* ActionDismissNotificationModel.swift */; };
|
AF60A7F62892D2E300919EEB /* ActionDismissNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F52892D2E300919EEB /* ActionDismissNotificationModel.swift */; };
|
||||||
AF60A7F82892D34D00919EEB /* ActionDismissNotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F72892D34D00919EEB /* ActionDismissNotificationHandler.swift */; };
|
AF60A7F82892D34D00919EEB /* ActionDismissNotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F72892D34D00919EEB /* ActionDismissNotificationHandler.swift */; };
|
||||||
AF766D262A3CD4C600749099 /* UIAccessibilityTraits+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF766D252A3CD4C600749099 /* UIAccessibilityTraits+Codable.swift */; };
|
AF766D262A3CD4C600749099 /* UIAccessibilityTraits+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF766D252A3CD4C600749099 /* UIAccessibilityTraits+Codable.swift */; };
|
||||||
@ -607,7 +608,6 @@
|
|||||||
EABFC1412763BB8D00E78B40 /* FormLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC1402763BB8D00E78B40 /* FormLabel.swift */; };
|
EABFC1412763BB8D00E78B40 /* FormLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC1402763BB8D00E78B40 /* FormLabel.swift */; };
|
||||||
EABFC152276913E800E78B40 /* FormLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC151276913E800E78B40 /* FormLabelModel.swift */; };
|
EABFC152276913E800E78B40 /* FormLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC151276913E800E78B40 /* FormLabelModel.swift */; };
|
||||||
EACCF38C2ABB346700E0F104 /* VDS-Interpreters.swift in Sources */ = {isa = PBXBuildFile; fileRef = EACCF38B2ABB346700E0F104 /* VDS-Interpreters.swift */; };
|
EACCF38C2ABB346700E0F104 /* VDS-Interpreters.swift in Sources */ = {isa = PBXBuildFile; fileRef = EACCF38B2ABB346700E0F104 /* VDS-Interpreters.swift */; };
|
||||||
EAD715AA2BBC8FAF00DEDA6A /* VDSTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAD715A92BBC8FAF00DEDA6A /* VDSTokens.xcframework */; };
|
|
||||||
FD99130028E21E4900542CC3 /* RuleNotEqualsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9912FF28E21E4900542CC3 /* RuleNotEqualsModel.swift */; };
|
FD99130028E21E4900542CC3 /* RuleNotEqualsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9912FF28E21E4900542CC3 /* RuleNotEqualsModel.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
@ -911,6 +911,7 @@
|
|||||||
AF1C336E2885A16A006B1001 /* ActionCollapseNotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCollapseNotificationHandler.swift; sourceTree = "<group>"; };
|
AF1C336E2885A16A006B1001 /* ActionCollapseNotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCollapseNotificationHandler.swift; sourceTree = "<group>"; };
|
||||||
AF1C33702885AE76006B1001 /* MVMCoreUIActionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIActionHandler.swift; sourceTree = "<group>"; };
|
AF1C33702885AE76006B1001 /* MVMCoreUIActionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIActionHandler.swift; sourceTree = "<group>"; };
|
||||||
AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIActionOpenPageHandler.swift; sourceTree = "<group>"; };
|
AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIActionOpenPageHandler.swift; sourceTree = "<group>"; };
|
||||||
|
AF1CEFE72BEA73890001F9A5 /* VDSCoreTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSCoreTokens.xcframework; path = ../SharedFrameworks/VDSCoreTokens.xcframework; sourceTree = "<group>"; };
|
||||||
AF60A7F52892D2E300919EEB /* ActionDismissNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionDismissNotificationModel.swift; sourceTree = "<group>"; };
|
AF60A7F52892D2E300919EEB /* ActionDismissNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionDismissNotificationModel.swift; sourceTree = "<group>"; };
|
||||||
AF60A7F72892D34D00919EEB /* ActionDismissNotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionDismissNotificationHandler.swift; sourceTree = "<group>"; };
|
AF60A7F72892D34D00919EEB /* ActionDismissNotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionDismissNotificationHandler.swift; sourceTree = "<group>"; };
|
||||||
AF766D252A3CD4C600749099 /* UIAccessibilityTraits+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAccessibilityTraits+Codable.swift"; sourceTree = "<group>"; };
|
AF766D252A3CD4C600749099 /* UIAccessibilityTraits+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAccessibilityTraits+Codable.swift"; sourceTree = "<group>"; };
|
||||||
@ -1244,9 +1245,9 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
AF1CEFE82BEA73890001F9A5 /* VDSCoreTokens.xcframework in Frameworks */,
|
||||||
D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */,
|
D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */,
|
||||||
EA985C602970A3F000F2FF2E /* VDS.framework in Frameworks */,
|
EA985C602970A3F000F2FF2E /* VDS.framework in Frameworks */,
|
||||||
EAD715AA2BBC8FAF00DEDA6A /* VDSTokens.xcframework in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -2138,6 +2139,7 @@
|
|||||||
D29DF0E421E4F3C7003B2FB9 /* Frameworks */ = {
|
D29DF0E421E4F3C7003B2FB9 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
AF1CEFE72BEA73890001F9A5 /* VDSCoreTokens.xcframework */,
|
||||||
EAD715A92BBC8FAF00DEDA6A /* VDSTokens.xcframework */,
|
EAD715A92BBC8FAF00DEDA6A /* VDSTokens.xcframework */,
|
||||||
EA985C5F2970A3F000F2FF2E /* VDS.framework */,
|
EA985C5F2970A3F000F2FF2E /* VDS.framework */,
|
||||||
D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */,
|
D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */,
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
import VDS
|
import VDS
|
||||||
import MVMCore
|
import MVMCore
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
import VDS
|
import VDS
|
||||||
|
|
||||||
open class Link: VDS.TextLink, VDSMoleculeViewProtocol {
|
open class Link: VDS.TextLink, VDSMoleculeViewProtocol {
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
import VDS
|
import VDS
|
||||||
import MVMCore
|
import MVMCore
|
||||||
import Combine
|
import Combine
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
@objcMembers open class RadioButton: Control, MFButtonProtocol {
|
@objcMembers open class RadioButton: Control, MFButtonProtocol {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -41,7 +41,9 @@ open class ButtonIcon: VDS.ButtonIcon, VDSMoleculeViewProtocol {
|
|||||||
iconName = viewModel.iconName
|
iconName = viewModel.iconName
|
||||||
selectedIconName = viewModel.selectedIconName
|
selectedIconName = viewModel.selectedIconName
|
||||||
size = viewModel.size
|
size = viewModel.size
|
||||||
customSize = viewModel.customSize
|
customContainerSize = viewModel.customContainerSize
|
||||||
|
customIconSize = viewModel.customIconSize
|
||||||
|
customBadgeIndicatorOffset = viewModel.customBadgeIndicatorOffSet
|
||||||
floating = viewModel.floating
|
floating = viewModel.floating
|
||||||
fitToIcon = viewModel.fitToIcon
|
fitToIcon = viewModel.fitToIcon
|
||||||
hideBorder = viewModel.hideBorder
|
hideBorder = viewModel.hideBorder
|
||||||
|
|||||||
@ -31,7 +31,9 @@ open class ButtonIconModel: ButtonModelProtocol, MoleculeModelProtocol {
|
|||||||
public var iconName: Icon.Name = .info
|
public var iconName: Icon.Name = .info
|
||||||
public var selectedIconName: Icon.Name?
|
public var selectedIconName: Icon.Name?
|
||||||
public var size = ButtonIcon.Size.large
|
public var size = ButtonIcon.Size.large
|
||||||
public var customSize : Int?
|
public var customContainerSize : Int?
|
||||||
|
public var customIconSize : Int?
|
||||||
|
public var customBadgeIndicatorOffSet : CGPoint?
|
||||||
public var floating: Bool = false
|
public var floating: Bool = false
|
||||||
public var fitToIcon: Bool = false
|
public var fitToIcon: Bool = false
|
||||||
public var hideBorder: Bool = true
|
public var hideBorder: Bool = true
|
||||||
@ -85,7 +87,9 @@ open class ButtonIconModel: ButtonModelProtocol, MoleculeModelProtocol {
|
|||||||
case iconName
|
case iconName
|
||||||
case selectedIconName
|
case selectedIconName
|
||||||
case size
|
case size
|
||||||
case customSize
|
case customContainerSize
|
||||||
|
case customIconSize
|
||||||
|
case customBadgeIndicatorOffSet
|
||||||
case floating
|
case floating
|
||||||
case fitToIcon
|
case fitToIcon
|
||||||
case hideBorder
|
case hideBorder
|
||||||
@ -110,7 +114,9 @@ open class ButtonIconModel: ButtonModelProtocol, MoleculeModelProtocol {
|
|||||||
iconName = try container.decode(Icon.Name.self, forKey: .iconName)
|
iconName = try container.decode(Icon.Name.self, forKey: .iconName)
|
||||||
selectedIconName = try container.decodeIfPresent(Icon.Name.self, forKey: .selectedIconName)
|
selectedIconName = try container.decodeIfPresent(Icon.Name.self, forKey: .selectedIconName)
|
||||||
size = try container.decodeIfPresent(ButtonIcon.Size.self, forKey: .size) ?? .large
|
size = try container.decodeIfPresent(ButtonIcon.Size.self, forKey: .size) ?? .large
|
||||||
customSize = try container.decodeIfPresent(Int.self, forKey: .customSize)
|
customContainerSize = try container.decodeIfPresent(Int.self, forKey: .customContainerSize)
|
||||||
|
customIconSize = try container.decodeIfPresent(Int.self, forKey: .customIconSize)
|
||||||
|
customBadgeIndicatorOffSet = try container.decodeIfPresent(CGPoint.self, forKey: .customBadgeIndicatorOffSet)
|
||||||
floating = try container.decodeIfPresent(Bool.self, forKey: .floating) ?? false
|
floating = try container.decodeIfPresent(Bool.self, forKey: .floating) ?? false
|
||||||
fitToIcon = try container.decodeIfPresent(Bool.self, forKey: .fitToIcon) ?? false
|
fitToIcon = try container.decodeIfPresent(Bool.self, forKey: .fitToIcon) ?? false
|
||||||
hideBorder = try container.decodeIfPresent(Bool.self, forKey: .hideBorder) ?? false
|
hideBorder = try container.decodeIfPresent(Bool.self, forKey: .hideBorder) ?? false
|
||||||
@ -131,7 +137,9 @@ open class ButtonIconModel: ButtonModelProtocol, MoleculeModelProtocol {
|
|||||||
try container.encode(iconName, forKey: .iconName)
|
try container.encode(iconName, forKey: .iconName)
|
||||||
try container.encodeIfPresent(selectedIconName, forKey: .selectedIconName)
|
try container.encodeIfPresent(selectedIconName, forKey: .selectedIconName)
|
||||||
try container.encodeIfPresent(size, forKey: .size)
|
try container.encodeIfPresent(size, forKey: .size)
|
||||||
try container.encodeIfPresent(customSize, forKey: .customSize)
|
try container.encodeIfPresent(customContainerSize, forKey: .customContainerSize)
|
||||||
|
try container.encodeIfPresent(customIconSize, forKey: .customIconSize)
|
||||||
|
try container.encodeIfPresent(customBadgeIndicatorOffSet, forKey: .customBadgeIndicatorOffSet)
|
||||||
try container.encodeIfPresent(floating, forKey: .floating)
|
try container.encodeIfPresent(floating, forKey: .floating)
|
||||||
try container.encodeIfPresent(fitToIcon, forKey: .fitToIcon)
|
try container.encodeIfPresent(fitToIcon, forKey: .fitToIcon)
|
||||||
try container.encodeIfPresent(hideBorder, forKey: .hideBorder)
|
try container.encodeIfPresent(hideBorder, forKey: .hideBorder)
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
// Created by Kevin Christiano on 1/30/20.
|
// Created by Kevin Christiano on 1/30/20.
|
||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
open class CarouselIndicator: Control, CarouselPageControlProtocol {
|
open class CarouselIndicator: Control, CarouselPageControlProtocol {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelProtocol, EnableableModelProtocol {
|
open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelProtocol, EnableableModelProtocol {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import VDS
|
import VDS
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
open class IconModel: MoleculeModelProtocol {
|
open class IconModel: MoleculeModelProtocol {
|
||||||
|
|
||||||
|
|||||||
@ -375,8 +375,8 @@ extension Label {
|
|||||||
public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect {
|
public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect {
|
||||||
|
|
||||||
guard let abstractContainer = label.abstractTextContainer() else { return CGRect() }
|
guard let abstractContainer = label.abstractTextContainer() else { return CGRect() }
|
||||||
let textContainer = abstractContainer.0
|
let textContainer = abstractContainer.textContainer
|
||||||
let layoutManager = abstractContainer.1
|
let layoutManager = abstractContainer.layoutManager
|
||||||
|
|
||||||
var glyphRange = NSRange()
|
var glyphRange = NSRange()
|
||||||
|
|
||||||
@ -385,36 +385,6 @@ extension Label {
|
|||||||
|
|
||||||
return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer)
|
return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a text container and layout manager of how the text would appear on screen.
|
|
||||||
They are used in tandem to derive low-level TextKit results of the label.
|
|
||||||
*/
|
|
||||||
public func abstractTextContainer() -> (NSTextContainer, NSLayoutManager, NSTextStorage)? {
|
|
||||||
|
|
||||||
// Must configure the attributed string to translate what would appear on screen to accurately analyze.
|
|
||||||
guard let attributedText = attributedText else { return nil }
|
|
||||||
|
|
||||||
let paragraph = NSMutableParagraphStyle()
|
|
||||||
paragraph.alignment = textAlignment
|
|
||||||
|
|
||||||
let stagedAttributedString = NSMutableAttributedString(attributedString: attributedText)
|
|
||||||
stagedAttributedString.addAttributes([NSAttributedString.Key.paragraphStyle: paragraph], range: NSRange(location: 0, length: attributedText.string.count))
|
|
||||||
|
|
||||||
let textStorage = NSTextStorage(attributedString: stagedAttributedString)
|
|
||||||
let layoutManager = NSLayoutManager()
|
|
||||||
let textContainer = NSTextContainer(size: .zero)
|
|
||||||
|
|
||||||
layoutManager.addTextContainer(textContainer)
|
|
||||||
textStorage.addLayoutManager(layoutManager)
|
|
||||||
|
|
||||||
textContainer.lineFragmentPadding = 0.0
|
|
||||||
textContainer.lineBreakMode = lineBreakMode
|
|
||||||
textContainer.maximumNumberOfLines = numberOfLines
|
|
||||||
textContainer.size = bounds.size
|
|
||||||
|
|
||||||
return (textContainer, layoutManager, textStorage)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Atomization
|
// MARK: - Atomization
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
import VDS
|
import VDS
|
||||||
|
|
||||||
public class LineModel: MoleculeModelProtocol, Invertable {
|
public class LineModel: MoleculeModelProtocol, Invertable {
|
||||||
|
|||||||
@ -34,6 +34,7 @@ open class TileContainerModel: TileContainerBaseModel<TileContainer.Padding, Til
|
|||||||
case moleculeName
|
case moleculeName
|
||||||
case molecule
|
case molecule
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
|
id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
|
||||||
@ -84,6 +85,7 @@ open class TileContainerBaseModel<PaddingType: DefaultValuing & Codable, TileCon
|
|||||||
case aspectRatio
|
case aspectRatio
|
||||||
case backgroundEffect
|
case backgroundEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
|
inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
|
||||||
@ -98,7 +100,6 @@ open class TileContainerBaseModel<PaddingType: DefaultValuing & Codable, TileCon
|
|||||||
color = try container.decodeIfPresent(TileContainerType.BackgroundColor.self, forKey: .color) ?? .black
|
color = try container.decodeIfPresent(TileContainerType.BackgroundColor.self, forKey: .color) ?? .black
|
||||||
aspectRatio = try container.decodeIfPresent(TileContainerType.AspectRatio.self, forKey: .aspectRatio) ?? .ratio1x1
|
aspectRatio = try container.decodeIfPresent(TileContainerType.AspectRatio.self, forKey: .aspectRatio) ?? .ratio1x1
|
||||||
backgroundEffect = try container.decodeIfPresent(TileContainerType.BackgroundEffect.self, forKey: .backgroundEffect) ?? .none
|
backgroundEffect = try container.decodeIfPresent(TileContainerType.BackgroundEffect.self, forKey: .backgroundEffect) ?? .none
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import VDS
|
import VDS
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
import MVMCore
|
import MVMCore
|
||||||
|
|
||||||
open class TooltipModel: MoleculeModelProtocol {
|
open class TooltipModel: MoleculeModelProtocol {
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import VDS
|
import VDS
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Codable Extensions
|
// MARK: - Codable Extensions
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
import VDS
|
import VDS
|
||||||
|
|
||||||
public class TitleLockupModel: ParentMoleculeModelProtocol {
|
public class TitleLockupModel: ParentMoleculeModelProtocol {
|
||||||
|
|||||||
@ -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 VDSTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
@objcMembers open class TabBar: UITabBar, MoleculeViewProtocol, TabBarProtocol, UITabBarDelegate {
|
@objcMembers open class TabBar: UITabBar, MoleculeViewProtocol, TabBarProtocol, UITabBarDelegate {
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
open class TabBarModel: MoleculeModelProtocol {
|
open class TabBarModel: MoleculeModelProtocol {
|
||||||
public static var identifier: String = "tabBar"
|
public static var identifier: String = "tabBar"
|
||||||
@ -34,7 +34,7 @@ open class TabBarModel: MoleculeModelProtocol {
|
|||||||
if let selectedColor = _selectedColor { return selectedColor }
|
if let selectedColor = _selectedColor { return selectedColor }
|
||||||
if let style = style,
|
if let style = style,
|
||||||
style == .dark { return Color(uiColor: VDSColor.elementsPrimaryOndark) }
|
style == .dark { return Color(uiColor: VDSColor.elementsPrimaryOndark) }
|
||||||
return Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
return Color(uiColor: UIColor.mvmRed)
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
_selectedColor = newValue
|
_selectedColor = newValue
|
||||||
@ -54,7 +54,7 @@ open class TabBarModel: MoleculeModelProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open var style: NavigationItemStyle? = .dark
|
open var style: NavigationItemStyle? = .light
|
||||||
|
|
||||||
// Must be capped to 0...(tabs.count - 1)
|
// Must be capped to 0...(tabs.count - 1)
|
||||||
open var selectedTab: Int = 0
|
open var selectedTab: Int = 0
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
import VDS
|
import VDS
|
||||||
|
|
||||||
@objc public protocol TabsDelegate {
|
@objc public protocol TabsDelegate {
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
import VDS
|
import VDS
|
||||||
open class TabsModel: MoleculeModelProtocol {
|
open class TabsModel: MoleculeModelProtocol {
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
public var fieldKey: String?
|
public var fieldKey: String?
|
||||||
public var groupName: String = FormValidator.defaultGroupName
|
public var groupName: String = FormValidator.defaultGroupName
|
||||||
public var baseValue: AnyHashable?
|
public var baseValue: AnyHashable?
|
||||||
|
public var gone: Bool = false
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Validation
|
// MARK: - Validation
|
||||||
@ -53,6 +54,7 @@
|
|||||||
case groupName
|
case groupName
|
||||||
case enabled
|
case enabled
|
||||||
case readOnly
|
case readOnly
|
||||||
|
case gone
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -76,6 +78,7 @@
|
|||||||
if let readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) {
|
if let readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) {
|
||||||
self.readOnly = readOnly
|
self.readOnly = readOnly
|
||||||
}
|
}
|
||||||
|
gone = try typeContainer.decodeIfPresent(Bool.self, forKey: .gone) ?? false
|
||||||
try super.init(from: decoder)
|
try super.init(from: decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,6 +102,7 @@
|
|||||||
&& fieldValue == model.fieldValue
|
&& fieldValue == model.fieldValue
|
||||||
&& enabled == model.enabled
|
&& enabled == model.enabled
|
||||||
&& readOnly == model.readOnly
|
&& readOnly == model.readOnly
|
||||||
|
&& gone == model.gone
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
public override func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||||
@ -107,5 +111,6 @@
|
|||||||
&& peakingArrowColor == model.peakingArrowColor
|
&& peakingArrowColor == model.peakingArrowColor
|
||||||
&& enabled == model.enabled
|
&& enabled == model.enabled
|
||||||
&& readOnly == model.readOnly
|
&& readOnly == model.readOnly
|
||||||
|
&& gone == model.gone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
public enum NavigationItemStyle: String, Codable {
|
public enum NavigationItemStyle: String, Codable {
|
||||||
case light
|
case light
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import Foundation
|
|||||||
import Combine
|
import Combine
|
||||||
import Dispatch
|
import Dispatch
|
||||||
import MVMCore
|
import MVMCore
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
@objcMembers open class CollapsableNotification: View {
|
@objcMembers open class CollapsableNotification: View {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -90,7 +90,7 @@ open class Carousel: View {
|
|||||||
showPeaking(false)
|
showPeaking(false)
|
||||||
|
|
||||||
// Go to current cell. layoutIfNeeded is needed otherwise cellForItem returns nil for peaking logic. The dispatch is a sad way to ensure the collection view is ready to be scrolled.
|
// Go to current cell. layoutIfNeeded is needed otherwise cellForItem returns nil for peaking logic. The dispatch is a sad way to ensure the collection view is ready to be scrolled.
|
||||||
guard let model = model as? CarouselModel, !model.molecules.isEmpty else { return }
|
guard let model = model as? CarouselModel, !model.visibleMolecules.isEmpty else { return }
|
||||||
guard (model.paging == true || loop == true) else {
|
guard (model.paging == true || loop == true) else {
|
||||||
DispatchQueue.main.async { [self] in
|
DispatchQueue.main.async { [self] in
|
||||||
updatePagerVisibility()
|
updatePagerVisibility()
|
||||||
@ -174,9 +174,12 @@ open class Carousel: View {
|
|||||||
MVMCoreLoggingHandler.shared()?.handleDebugMessage("[\(Self.self)] [\(ObjectIdentifier(self).hashValue)]\noriginal model: \(originalModel?.debugDescription ?? "none")\nnew model: \(model)")
|
MVMCoreLoggingHandler.shared()?.handleDebugMessage("[\(Self.self)] [\(ObjectIdentifier(self).hashValue)]\noriginal model: \(originalModel?.debugDescription ?? "none")\nnew model: \(model)")
|
||||||
|
|
||||||
if #available(iOS 15.0, *) {
|
if #available(iOS 15.0, *) {
|
||||||
if let originalModel, carouselModel.isDeeplyVisuallyEquivalent(to: originalModel) {
|
if let originalModel, carouselModel.isDeeplyVisuallyEquivalent(to: originalModel),
|
||||||
|
originalModel.visibleMolecules.isVisuallyEquivalent(to: molecules ?? []) // Since the carousel model's children are in place replaced and we do not have a deep copy of this model tree, add in this hack to check if the prior captured carousel items match the newly visible ones.
|
||||||
|
{
|
||||||
// Prevents a carousel reset while still updating the cell backing data through reconfigureItems.
|
// Prevents a carousel reset while still updating the cell backing data through reconfigureItems.
|
||||||
MVMCoreLoggingHandler.shared()?.handleDebugMessage("[\(Self.self)] Model is visually equivalent. Skipping rebuild...")
|
MVMCoreLoggingHandler.shared()?.handleDebugMessage("[\(Self.self)] Model is visually equivalent. Skipping rebuild...")
|
||||||
|
prepareMolecules(with: carouselModel)
|
||||||
FormValidator.setupValidation(for: carouselModel, delegate: delegateObject?.formHolderDelegate)
|
FormValidator.setupValidation(for: carouselModel, delegate: delegateObject?.formHolderDelegate)
|
||||||
updateModelIndex() // Ensure the new model indexing matches the old.
|
updateModelIndex() // Ensure the new model indexing matches the old.
|
||||||
pagingView?.currentIndex = pageIndex // Trigger a paging view render.
|
pagingView?.currentIndex = pageIndex // Trigger a paging view render.
|
||||||
@ -228,7 +231,7 @@ open class Carousel: View {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
func prepareMolecules(with carouselModel: CarouselModel?) {
|
func prepareMolecules(with carouselModel: CarouselModel?) {
|
||||||
guard let newMolecules = carouselModel?.molecules else {
|
guard let newMolecules = carouselModel?.visibleMolecules else {
|
||||||
numberOfPages = 0
|
numberOfPages = 0
|
||||||
molecules = nil
|
molecules = nil
|
||||||
return
|
return
|
||||||
@ -304,6 +307,7 @@ open class Carousel: View {
|
|||||||
|
|
||||||
pagingView?.removeFromSuperview()
|
pagingView?.removeFromSuperview()
|
||||||
bottomPin?.isActive = false
|
bottomPin?.isActive = false
|
||||||
|
pagingView = nil
|
||||||
|
|
||||||
guard var pagingView = view else {
|
guard var pagingView = view else {
|
||||||
bottomPin = bottomAnchor.constraint(equalTo: collectionView.bottomAnchor)
|
bottomPin = bottomAnchor.constraint(equalTo: collectionView.bottomAnchor)
|
||||||
|
|||||||
@ -44,6 +44,10 @@ import UIKit
|
|||||||
public var selectable = false
|
public var selectable = false
|
||||||
public var selectedIndex: Int?
|
public var selectedIndex: Int?
|
||||||
|
|
||||||
|
public var visibleMolecules: [MoleculeModelProtocol & CarouselItemModelProtocol] {
|
||||||
|
molecules.filter { !$0.gone }
|
||||||
|
}
|
||||||
|
|
||||||
public init(molecules: [MoleculeModelProtocol & CarouselItemModelProtocol]) {
|
public init(molecules: [MoleculeModelProtocol & CarouselItemModelProtocol]) {
|
||||||
self.molecules = molecules
|
self.molecules = molecules
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
public protocol CarouselItemModelProtocol: FormFieldProtocol, ContainerModelProtocol {
|
public protocol CarouselItemModelProtocol: FormFieldProtocol, ContainerModelProtocol {
|
||||||
var analyticsData: JSONValueDictionary? { get set }
|
var analyticsData: JSONValueDictionary? { get set }
|
||||||
|
var gone: Bool { get set }
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension CarouselItemModelProtocol {
|
public extension CarouselItemModelProtocol {
|
||||||
@ -16,4 +17,9 @@ public extension CarouselItemModelProtocol {
|
|||||||
get { nil }
|
get { nil }
|
||||||
set { analyticsData = newValue }
|
set { analyticsData = newValue }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var gone: Bool{
|
||||||
|
get { false }
|
||||||
|
set { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,7 @@ public extension ParentModelProtocol where Self: AnyObject {
|
|||||||
|
|
||||||
func replaceChildMolecule<T>(in molecules: inout [T], with replacementMolecule: MoleculeModelProtocol) throws -> MoleculeModelProtocol? {
|
func replaceChildMolecule<T>(in molecules: inout [T], with replacementMolecule: MoleculeModelProtocol) throws -> MoleculeModelProtocol? {
|
||||||
var replacedMolecule: MoleculeModelProtocol?
|
var replacedMolecule: MoleculeModelProtocol?
|
||||||
return try replaceChildMolecule(at: &molecules, with: replacementMolecule, replaced: &replacedMolecule) ? replacedMolecule : nil
|
return try replaceChildMolecule(in: &molecules, with: replacementMolecule, replaced: &replacedMolecule) ? replacedMolecule : nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper for replacing a molecule in place within an array. Note the "in".
|
/// Helper for replacing a molecule in place within an array. Note the "in".
|
||||||
@ -67,6 +67,26 @@ public protocol ParentMoleculeModelProtocol: ParentModelProtocol, MoleculeModelP
|
|||||||
|
|
||||||
public extension ParentMoleculeModelProtocol {
|
public extension ParentMoleculeModelProtocol {
|
||||||
|
|
||||||
|
/// Recursively finds and replaces the first child matching the replacement molecule id property.
|
||||||
|
mutating func deepReplaceMolecule(with replacementMolecule: MoleculeModelProtocol) throws -> MoleculeModelProtocol? {
|
||||||
|
var replacedMolecule: MoleculeModelProtocol?
|
||||||
|
var possibleError: Error?
|
||||||
|
// Dive into each root.
|
||||||
|
depthFirstTraverse(options: .parentFirst, depth: 0) { depth, molecule, stop in
|
||||||
|
guard var parentMolecule = molecule as? ParentMoleculeModelProtocol else { return }
|
||||||
|
do {
|
||||||
|
replacedMolecule = try parentMolecule.replaceChildMolecule(with: replacementMolecule)
|
||||||
|
} catch {
|
||||||
|
possibleError = error
|
||||||
|
}
|
||||||
|
stop = replacedMolecule != nil || possibleError != nil
|
||||||
|
}
|
||||||
|
if let error = possibleError {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
return replacedMolecule
|
||||||
|
}
|
||||||
|
|
||||||
func reduceDepthFirstTraverse<Result>(options: TreeTraversalOptions, depth: Int, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol, Int) -> Result) -> Result {
|
func reduceDepthFirstTraverse<Result>(options: TreeTraversalOptions, depth: Int, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol, Int) -> Result) -> Result {
|
||||||
var result = initialResult
|
var result = initialResult
|
||||||
if (options == .parentFirst) {
|
if (options == .parentFirst) {
|
||||||
|
|||||||
@ -40,31 +40,3 @@ public extension TemplateModelProtocol {
|
|||||||
return rootMolecules.depthFirstTraverse(options: options, depth: depth, onVisit: onVisit)
|
return rootMolecules.depthFirstTraverse(options: options, depth: depth, onVisit: onVisit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TemplateModelProtocol {
|
|
||||||
|
|
||||||
/// Recursively finds and replaces the first child matching the replacement molecule id property.
|
|
||||||
mutating func replaceMolecule(with replacementMolecule: MoleculeModelProtocol) throws -> MoleculeModelProtocol? {
|
|
||||||
// Attempt root level replacement on the template model first.
|
|
||||||
if let replacedMolecule = try replaceChildMolecule(with: replacementMolecule) {
|
|
||||||
return replacedMolecule
|
|
||||||
}
|
|
||||||
|
|
||||||
var replacedMolecule: MoleculeModelProtocol?
|
|
||||||
var possibleError: Error?
|
|
||||||
// Dive into each root thereafter.
|
|
||||||
depthFirstTraverse(options: .parentFirst, depth: 0) { depth, molecule, stop in
|
|
||||||
guard var parentMolecule = molecule as? ParentMoleculeModelProtocol else { return }
|
|
||||||
do {
|
|
||||||
replacedMolecule = try parentMolecule.replaceChildMolecule(with: replacementMolecule)
|
|
||||||
} catch {
|
|
||||||
possibleError = error
|
|
||||||
}
|
|
||||||
stop = replacedMolecule != nil || possibleError != nil
|
|
||||||
}
|
|
||||||
if let error = possibleError {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
return replacedMolecule
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -83,6 +83,9 @@ import Foundation
|
|||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
if let defaultPageType = Self.defaultPageType() {
|
if let defaultPageType = Self.defaultPageType() {
|
||||||
pageType = try typeContainer.decodeIfPresent(String.self, forKey: .pageType) ?? defaultPageType
|
pageType = try typeContainer.decodeIfPresent(String.self, forKey: .pageType) ?? defaultPageType
|
||||||
|
if pageType.isEmpty {
|
||||||
|
pageType = defaultPageType
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pageType = try typeContainer.decode(String.self, forKey: .pageType)
|
pageType = try typeContainer.decode(String.self, forKey: .pageType)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,10 +79,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open override func handleNewData(_ pageModel: PageModelProtocol? = nil) {
|
open override func handleNewData(_ pageModel: PageModelProtocol? = nil, shouldTriggerRender: Bool = true) {
|
||||||
setup()
|
setup()
|
||||||
registerCells()
|
registerCells()
|
||||||
super.handleNewData(pageModel)
|
super.handleNewData(pageModel, shouldTriggerRender: shouldTriggerRender)
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func updateUI(for molecules: [MoleculeModelProtocol]? = nil) {
|
open override func updateUI(for molecules: [MoleculeModelProtocol]? = nil) {
|
||||||
|
|||||||
@ -25,8 +25,8 @@ open class ModalMoleculeListTemplate: MoleculeListTemplate {
|
|||||||
try decoder.decode(ModalListPageTemplateModel.self, from: data)
|
try decoder.decode(ModalListPageTemplateModel.self, from: data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func handleNewData(_ pageModel: PageModelProtocol? = nil) {
|
override open func handleNewData(_ pageModel: PageModelProtocol? = nil, shouldTriggerRender: Bool = true) {
|
||||||
super.handleNewData(pageModel)
|
super.handleNewData(pageModel, shouldTriggerRender: shouldTriggerRender)
|
||||||
|
|
||||||
closeButton = MVMCoreUICommonViewsUtility.addCloseButton(to: view, tintColor: self.pageModel?.navigationBar?.tintColor.uiColor, action: { [weak self] _ in
|
closeButton = MVMCoreUICommonViewsUtility.addCloseButton(to: view, tintColor: self.pageModel?.navigationBar?.tintColor.uiColor, action: { [weak self] _ in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|||||||
@ -23,8 +23,8 @@ open class ModalMoleculeStackTemplate: MoleculeStackTemplate {
|
|||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
override open func handleNewData(_ pageModel: PageModelProtocol? = nil) {
|
override open func handleNewData(_ pageModel: PageModelProtocol? = nil, shouldTriggerRender: Bool = true) {
|
||||||
super.handleNewData(pageModel)
|
super.handleNewData(pageModel, shouldTriggerRender: shouldTriggerRender)
|
||||||
_ = MVMCoreUICommonViewsUtility.addCloseButton(to: view, tintColor: self.pageModel?.navigationBar?.tintColor.uiColor, action: { [weak self] _ in
|
_ = MVMCoreUICommonViewsUtility.addCloseButton(to: view, tintColor: self.pageModel?.navigationBar?.tintColor.uiColor, action: { [weak self] _ in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
let closeAction = (self.templateModel as? ModalStackPageTemplateModel)?.closeAction ??
|
let closeAction = (self.templateModel as? ModalStackPageTemplateModel)?.closeAction ??
|
||||||
|
|||||||
@ -85,8 +85,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
|||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func handleNewData(_ pageModel: PageModelProtocol? = nil) {
|
open override func handleNewData(_ pageModel: PageModelProtocol? = nil, shouldTriggerRender: Bool = true) {
|
||||||
super.handleNewData(pageModel)
|
super.handleNewData(pageModel, shouldTriggerRender: shouldTriggerRender)
|
||||||
|
|
||||||
if pageModel != nil {
|
if pageModel != nil {
|
||||||
setup()
|
setup()
|
||||||
|
|||||||
@ -20,10 +20,10 @@ open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
|
|||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override func handleNewData(_ pageModel: PageModelProtocol? = nil) {
|
open override func handleNewData(_ pageModel: PageModelProtocol? = nil, shouldTriggerRender: Bool = true) {
|
||||||
topViewOutsideOfScroll = templateModel?.anchorHeader ?? false
|
topViewOutsideOfScroll = templateModel?.anchorHeader ?? false
|
||||||
bottomViewOutsideOfScroll = templateModel?.anchorFooter ?? false
|
bottomViewOutsideOfScroll = templateModel?.anchorFooter ?? false
|
||||||
super.handleNewData(pageModel)
|
super.handleNewData(pageModel, shouldTriggerRender: shouldTriggerRender)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For subclassing the model.
|
// For subclassing the model.
|
||||||
|
|||||||
@ -52,17 +52,20 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController, Rotor
|
|||||||
bottomView.updateView(width)
|
bottomView.updateView(width)
|
||||||
showFooter(width)
|
showFooter(width)
|
||||||
}
|
}
|
||||||
tableView.reloadData()
|
tableView.visibleCells.forEach { cell in
|
||||||
|
(cell as? MVMCoreViewProtocol)?.updateView(width)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func updateUI(for molecules: [MoleculeModelProtocol]? = nil) {
|
open override func updateUI(for molecules: [MoleculeModelProtocol]? = nil) {
|
||||||
super.updateUI(for: molecules)
|
super.updateUI(for: molecules)
|
||||||
|
|
||||||
guard molecules == nil else { return }
|
guard molecules == nil else { return }
|
||||||
|
|
||||||
createViewForTableHeader()
|
createViewForTableHeader()
|
||||||
createViewForTableFooter()
|
createViewForTableFooter()
|
||||||
tableView?.reloadData()
|
// Reloading the table is handled in updateViews, however, update views is on a separate rendering task than the current thread. The table render needs to be bound and settled to the new model before others put in additional update requests.
|
||||||
|
tableView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func viewDidLoad() {
|
override open func viewDidLoad() {
|
||||||
|
|||||||
@ -146,6 +146,11 @@ import MVMCore
|
|||||||
do {
|
do {
|
||||||
let template = try parsePageJSON(loadObject: loadObject)
|
let template = try parsePageJSON(loadObject: loadObject)
|
||||||
pageModel = template // TODO: Eventually this page parsing should be done outside of this class and then set by the caller. For now, double duty.
|
pageModel = template // TODO: Eventually this page parsing should be done outside of this class and then set by the caller. For now, double duty.
|
||||||
|
// Needed for PageMoleculeTransformationBehavior + PageLocalDataShareBehavior behaviors.
|
||||||
|
if let behaviorContainer = template as? (PageBehaviorContainerModelProtocol & TemplateModelProtocol) {
|
||||||
|
var behaviorHandler = self
|
||||||
|
behaviorHandler.applyBehaviors(pageBehaviorModel: behaviorContainer)
|
||||||
|
}
|
||||||
isFirstRender = true // Assuming this is only on the first page load from the handler. Might need to revist later.
|
isFirstRender = true // Assuming this is only on the first page load from the handler. Might need to revist later.
|
||||||
if let backgroundRequest = loadObject.requestParameters?.backgroundRequest, !backgroundRequest, let pageType, let identifier = loadObject.identifier {
|
if let backgroundRequest = loadObject.requestParameters?.backgroundRequest, !backgroundRequest, let pageType, let identifier = loadObject.identifier {
|
||||||
MVMCoreLoggingHandler.shared()?.logCoreEvent(.pageProcessingComplete(pageType: pageType, requestUUID: identifier, webUrl: nil))
|
MVMCoreLoggingHandler.shared()?.logCoreEvent(.pageProcessingComplete(pageType: pageType, requestUUID: identifier, webUrl: nil))
|
||||||
@ -225,16 +230,16 @@ import MVMCore
|
|||||||
return navigationModel
|
return navigationModel
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Processes any new data. Called after the page is loaded the first time and on response updates for this page. Triggers a render refresh.
|
/// Processes any new data. Called after the page is loaded the first time and on response updates for this page. Triggers a render refresh unless specified otherwise.
|
||||||
@MainActor
|
@MainActor
|
||||||
open func handleNewData(_ pageModel: PageModelProtocol? = nil) {
|
open func handleNewData(_ pageModel: PageModelProtocol? = nil, shouldTriggerRender: Bool = true) {
|
||||||
|
|
||||||
guard var newPageModel = pageModel ?? self.pageModel else { return }
|
guard var newPageModel = pageModel ?? self.pageModel else { return }
|
||||||
let originalModel = isFirstRender ? nil : self.pageModel as? MVMControllerModelProtocol
|
let originalModel = self.pageModel as? MVMControllerModelProtocol
|
||||||
|
|
||||||
// Refresh our behaviors if there is a page change.
|
// Refresh our behaviors if there is a page change. Originally set up in shouldFinishProcessingLoad.
|
||||||
if let behaviorContainer = newPageModel as? (PageBehaviorContainerModelProtocol & TemplateModelProtocol),
|
if let behaviorContainer = newPageModel as? (PageBehaviorContainerModelProtocol & TemplateModelProtocol),
|
||||||
(originalModel == nil || originalModel!.id != behaviorContainer.id) {
|
(originalModel == nil || originalModel!.id != behaviorContainer.id) {
|
||||||
var behaviorHandler = self
|
var behaviorHandler = self
|
||||||
behaviorHandler.applyBehaviors(pageBehaviorModel: behaviorContainer)
|
behaviorHandler.applyBehaviors(pageBehaviorModel: behaviorContainer)
|
||||||
}
|
}
|
||||||
@ -277,15 +282,20 @@ import MVMCore
|
|||||||
let allUpdatedMolecules = behaviorUpdatedModels //+ pageUpdatedModels
|
let allUpdatedMolecules = behaviorUpdatedModels //+ pageUpdatedModels
|
||||||
|
|
||||||
// Notify the manager of new data.
|
// Notify the manager of new data.
|
||||||
// Warning: Some flows cause table reloads. Until the UI update is decoupled, should be after the updateUI.
|
|
||||||
manager?.newDataReceived?(in: self)
|
manager?.newDataReceived?(in: self)
|
||||||
|
|
||||||
if allUpdatedMolecules.isEmpty || isFirstRender {
|
guard shouldTriggerRender else { return }
|
||||||
debugLog("Performing full page render...")
|
|
||||||
updateUI()
|
// Dispatch to decouple execution. First massage data through template classes, then render.
|
||||||
} else {
|
Task { @MainActor in
|
||||||
debugLog("Performing partial render of \(allUpdatedMolecules) molecules...")
|
|
||||||
updateUI(for: allUpdatedMolecules)
|
if allUpdatedMolecules.isEmpty || isFirstRender {
|
||||||
|
debugLog("Performing full page render...")
|
||||||
|
updateUI()
|
||||||
|
} else {
|
||||||
|
debugLog("Performing partial render of \(allUpdatedMolecules) molecules...")
|
||||||
|
updateUI(for: allUpdatedMolecules)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +409,8 @@ import MVMCore
|
|||||||
initialLoad()
|
initialLoad()
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNewData(pageModel) // Set outside shouldFinishProcessingLoad.
|
handleNewData(pageModel, shouldTriggerRender: false) // Set outside shouldFinishProcessingLoad.
|
||||||
|
updateUI() // Force the rendering on the same main UI thread.
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func viewDidLayoutSubviews() {
|
open override func viewDidLayoutSubviews() {
|
||||||
|
|||||||
@ -41,7 +41,7 @@ public extension PageBehaviorHandlerProtocol {
|
|||||||
// Apply them to the page.
|
// Apply them to the page.
|
||||||
self.behaviors = behaviors.count > 0 ? behaviors : nil
|
self.behaviors = behaviors.count > 0 ? behaviors : nil
|
||||||
|
|
||||||
// Ask the session to apply any more. (Curently inverted contol due to Swift <--> Obj-C conflict.
|
// Ask the session to apply any more. (Currently inverted contol due to Swift <--> Obj-C conflict.)
|
||||||
if let viewController = self as? UIViewController {
|
if let viewController = self as? UIViewController {
|
||||||
MVMCoreUISession.sharedGlobal()?.applyGlobalBehaviors(to: viewController)
|
MVMCoreUISession.sharedGlobal()?.applyGlobalBehaviors(to: viewController)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ public class ReplaceableMoleculeBehaviorModel: PageBehaviorModelProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, CoreLogging {
|
public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, PageVisibilityBehavior, CoreLogging {
|
||||||
|
|
||||||
public var loggingPrefix: String {
|
public var loggingPrefix: String {
|
||||||
"\(self) \(ObjectIdentifier(self).hashValue) \(moleculeIds.prefix(3)) \(moleculeIds.count > 3 ? "+ \(moleculeIds.count - 3) more" : ""):\n"
|
"\(self) \(ObjectIdentifier(self).hashValue) \(moleculeIds.prefix(3)) \(moleculeIds.count > 3 ? "+ \(moleculeIds.count - 3) more" : ""):\n"
|
||||||
@ -30,6 +30,8 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co
|
|||||||
String(describing: Self.self)
|
String(describing: Self.self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isPageShowing = false
|
||||||
|
var previouslyReplacedIds = Set<String>()
|
||||||
var moleculeIds: [String]
|
var moleculeIds: [String]
|
||||||
public var modulesToListenFor: [String]
|
public var modulesToListenFor: [String]
|
||||||
private var observingForResponses: NSObjectProtocol?
|
private var observingForResponses: NSObjectProtocol?
|
||||||
@ -41,7 +43,7 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co
|
|||||||
self.delegateObject = delegateObject
|
self.delegateObject = delegateObject
|
||||||
guard let pageType = delegateObject?.moleculeDelegate?.getTemplateModel()?.pageType else { return }
|
guard let pageType = delegateObject?.moleculeDelegate?.getTemplateModel()?.pageType else { return }
|
||||||
MVMCoreViewControllerMappingObject.shared()?.addOptionalModules(toMapping: moleculeIds, forPageType: pageType)
|
MVMCoreViewControllerMappingObject.shared()?.addOptionalModules(toMapping: moleculeIds, forPageType: pageType)
|
||||||
Self.debugLog("Initializing for \((model as! ReplaceableMoleculeBehaviorModel).moleculeIds)")
|
Self.debugLog("Initializing for \(moleculeIds)")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?, changes: inout [MoleculeModelProtocol]) -> [MoleculeModelProtocol]? {
|
public func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?, changes: inout [MoleculeModelProtocol]) -> [MoleculeModelProtocol]? {
|
||||||
@ -75,7 +77,7 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co
|
|||||||
return rootMolecule
|
return rootMolecule
|
||||||
}
|
}
|
||||||
debugLog("top replacing \(rootMolecule) with \(updatedMolecule)")
|
debugLog("top replacing \(rootMolecule) with \(updatedMolecule)")
|
||||||
logUpdated(molecule: updatedMolecule)
|
logUpdated(moleculeId: updatedMolecule.id)
|
||||||
changeList.append(updatedMolecule)
|
changeList.append(updatedMolecule)
|
||||||
return updatedMolecule
|
return updatedMolecule
|
||||||
}
|
}
|
||||||
@ -85,14 +87,14 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co
|
|||||||
|
|
||||||
moleculeModels.forEach { newMolecule in
|
moleculeModels.forEach { newMolecule in
|
||||||
do {
|
do {
|
||||||
if let replacedMolecule = try parentMolecule.replaceChildMolecule(with: newMolecule) {
|
if let replacedMolecule = try parentMolecule.deepReplaceMolecule(with: newMolecule) {
|
||||||
guard !replacedMolecule.deepEquals(to: newMolecule) else {
|
guard !replacedMolecule.deepEquals(to: newMolecule) else {
|
||||||
// Note: Slight risk here of replacing the something in the original tree and misreporting that is it not replaced based on equality.
|
// Note: Slight risk here of replacing the something in the original tree and misreporting that is it not replaced based on equality.
|
||||||
debugLog("deep molecule \(newMolecule) is the same as \(replacedMolecule). skipping...")
|
debugLog("deep molecule \(newMolecule) is the same as \(replacedMolecule). skipping...")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
debugLog("deep replacing \(replacedMolecule) with \(newMolecule)")
|
debugLog("deep replacing \(replacedMolecule) with \(newMolecule)")
|
||||||
logUpdated(molecule: newMolecule)
|
logUpdated(moleculeId: newMolecule.id)
|
||||||
changeList.append(newMolecule)
|
changeList.append(newMolecule)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
@ -111,15 +113,29 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co
|
|||||||
return hasReplacement ? updatedRootMolecules : nil
|
return hasReplacement ? updatedRootMolecules : nil
|
||||||
}
|
}
|
||||||
|
|
||||||
private func logUpdated(molecule: MoleculeModelProtocol) {
|
private func logUpdated(moleculeId: String) {
|
||||||
guard let module: [AnyHashable: Any] = delegateObject?.moleculeDelegate?.getModuleWithName(molecule.id),
|
guard let module: [AnyHashable: Any] = delegateObject?.moleculeDelegate?.getModuleWithName(moleculeId),
|
||||||
let viewController = delegateObject?.moleculeDelegate as? MVMCoreViewControllerProtocol else {
|
let viewController = delegateObject?.moleculeDelegate as? MVMCoreViewControllerProtocol else {
|
||||||
debugLog("Missing the originating module \(molecule.id) creating this molecule!")
|
debugLog("Missing the originating module \(moleculeId) creating this molecule!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
previouslyReplacedIds.insert(moleculeId)
|
||||||
|
guard isPageShowing else { return } // Page has not been made visible yet. (Pulled and replaced from cache on load or background update.) Hold reporting until onPageShown.
|
||||||
MVMCoreUILoggingHandler.shared()?.defaultLogPageUpdate(forController: viewController, from: module)
|
MVMCoreUILoggingHandler.shared()?.defaultLogPageUpdate(forController: viewController, from: module)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) {
|
||||||
|
isPageShowing = true
|
||||||
|
debugLog("Page shown. Send molecule analytics for: \(previouslyReplacedIds)")
|
||||||
|
previouslyReplacedIds.forEach { id in
|
||||||
|
logUpdated(moleculeId: id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) {
|
||||||
|
isPageShowing = false
|
||||||
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
debugLog("deinit")
|
debugLog("deinit")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import VDSCoreTokens
|
||||||
|
|
||||||
public typealias ColorHexTuple = (uiColor: UIColor, hex: String)
|
public typealias ColorHexTuple = (uiColor: UIColor, hex: String)
|
||||||
|
|
||||||
@ -19,7 +20,8 @@ extension UIColor {
|
|||||||
/// Dictionary to access brand approved colors by name.
|
/// Dictionary to access brand approved colors by name.
|
||||||
public static let names: [String: ColorHexTuple] = ["black": (.mvmBlack, "#000000"),
|
public static let names: [String: ColorHexTuple] = ["black": (.mvmBlack, "#000000"),
|
||||||
"white": (.mvmWhite, "#FFFFFF"),
|
"white": (.mvmWhite, "#FFFFFF"),
|
||||||
"red": (.mvmRed, "#D52B1E"),
|
"red": (.mvmRed, "#EE0000"),
|
||||||
|
"monarchRed": (VDSCoreTokens.VDSColor.paletteMonarchred, "#f50a23"),
|
||||||
"pink": (.mvmPink, "#D90368"),
|
"pink": (.mvmPink, "#D90368"),
|
||||||
"pink33": (.mvmPink33, "#F2ABCD"),
|
"pink33": (.mvmPink33, "#F2ABCD"),
|
||||||
"pink66": (.mvmPink66, "#E6589B"),
|
"pink66": (.mvmPink66, "#E6589B"),
|
||||||
@ -48,13 +50,20 @@ extension UIColor {
|
|||||||
"blueShade2": (.mvmBlueShade2, "#0B4467"),
|
"blueShade2": (.mvmBlueShade2, "#0B4467"),
|
||||||
"blueInverted": (.mvmBlueInverted, "#0088CE"),
|
"blueInverted": (.mvmBlueInverted, "#0088CE"),
|
||||||
"yellow": (.mvmYellow, "#FFBC3D"),
|
"yellow": (.mvmYellow, "#FFBC3D"),
|
||||||
|
"neonYellow": (VDSCoreTokens.VDSColor.paletteNeonyellow, "#f5ff1e"),
|
||||||
"coolGray1": (.mvmCoolGray1, "#F6F6F6"),
|
"coolGray1": (.mvmCoolGray1, "#F6F6F6"),
|
||||||
"coolGray3": (.mvmCoolGray3, "#D8DADA"),
|
"coolGray3": (.mvmCoolGray3, "#D8DADA"),
|
||||||
"coolGray6": (.mvmCoolGray6, "#747676"),
|
"coolGray6": (.mvmCoolGray6, "#747676"),
|
||||||
"coolGray10": (.mvmCoolGray10, "#333333"),
|
"coolGray10": (.mvmCoolGray10, "#333333"),
|
||||||
"upGold1": (.vzupGold1, "#F9D542"),
|
"upGold1": (.vzupGold1, "#F9D542"),
|
||||||
"upGold2": (.vzupGold2, "#F4CA53"),
|
"upGold2": (.vzupGold2, "#F4CA53"),
|
||||||
"upGold3": (.vzupGold3, "#CC9B2D")]
|
"upGold3": (.vzupGold3, "#CC9B2D"),
|
||||||
|
"stone": (.stone, "#F3EDE0"),
|
||||||
|
"coral": (.coral, "#FF3C2D"),
|
||||||
|
"gray44": (.gray44, "#6F7171"),
|
||||||
|
"gray85": (.gray85, "#D8DADA"),
|
||||||
|
"gray95": (.gray95, "#F6F6F6")
|
||||||
|
]
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Helper
|
// MARK: - Helper
|
||||||
@ -82,9 +91,10 @@ extension UIColor {
|
|||||||
// MARK: - Red
|
// MARK: - Red
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
/// HEX: #D52B1E
|
/// HEX: #EE0000
|
||||||
|
@objc
|
||||||
public static let mvmRed = UIColor.assetColor(named: "red")
|
public static let mvmRed = UIColor.assetColor(named: "red")
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Pink
|
// MARK: - Pink
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -190,7 +200,7 @@ extension UIColor {
|
|||||||
// MARK: - Yellow
|
// MARK: - Yellow
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
/// HEX: #FFBC3D
|
/// HEX: ##F5FF1E
|
||||||
public static let mvmYellow = UIColor.assetColor(named: "yellow")
|
public static let mvmYellow = UIColor.assetColor(named: "yellow")
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -222,6 +232,25 @@ extension UIColor {
|
|||||||
/// HEX: #CC9B2D
|
/// HEX: #CC9B2D
|
||||||
public static let vzupGold3 = UIColor.assetColor(named: "upGold3")
|
public static let vzupGold3 = UIColor.assetColor(named: "upGold3")
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Monarch
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// HEX: #F3EDE0
|
||||||
|
@objc public static let stone = VDSCoreTokens.VDSColor.paletteStone
|
||||||
|
|
||||||
|
// HEX:#FF3C2D
|
||||||
|
@objc public static let coral = VDSCoreTokens.VDSColor.paletteCoral
|
||||||
|
|
||||||
|
// HEX:#6F7171
|
||||||
|
@objc public static let gray44 = VDSCoreTokens.VDSColor.paletteGray44
|
||||||
|
|
||||||
|
// HEX:#D8DADA
|
||||||
|
@objc public static let gray85 = VDSCoreTokens.VDSColor.paletteGray85
|
||||||
|
|
||||||
|
// HEX:#F6F6F6
|
||||||
|
@objc public static let gray95 = VDSCoreTokens.VDSColor.paletteGray95
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Functions
|
// MARK: - Functions
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -77,7 +77,7 @@
|
|||||||
#pragma mark - legacy
|
#pragma mark - legacy
|
||||||
|
|
||||||
+ (nonnull UIColor *)mfRedColor {
|
+ (nonnull UIColor *)mfRedColor {
|
||||||
return [UIColor colorWithRed:.804 green:.016 blue:.043 alpha:1.0];
|
return [UIColor mvmRed];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (nonnull UIColor *)mfDarkerRedColor {
|
+ (nonnull UIColor *)mfDarkerRedColor {
|
||||||
@ -307,8 +307,6 @@
|
|||||||
static dispatch_once_t once;
|
static dispatch_once_t once;
|
||||||
dispatch_once(&once, ^{
|
dispatch_once(&once, ^{
|
||||||
stringColorMapping = @{@"PrimaryRed":[UIColor mfRedColor],
|
stringColorMapping = @{@"PrimaryRed":[UIColor mfRedColor],
|
||||||
@"black":[UIColor blackColor],
|
|
||||||
@"red":[UIColor mfRedColor],
|
|
||||||
@"greyish":[UIColor mfLightGrayColor],
|
@"greyish":[UIColor mfLightGrayColor],
|
||||||
@"robinsEggBlue" : [UIColor mfRobinsEggBlue],
|
@"robinsEggBlue" : [UIColor mfRobinsEggBlue],
|
||||||
@"lightSalmon" : [UIColor mfLightSalmon],
|
@"lightSalmon" : [UIColor mfLightSalmon],
|
||||||
|
|||||||
@ -1,20 +1,20 @@
|
|||||||
{
|
{
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
},
|
|
||||||
"colors" : [
|
"colors" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
|
||||||
"color" : {
|
"color" : {
|
||||||
"color-space" : "srgb",
|
"color-space" : "srgb",
|
||||||
"components" : {
|
"components" : {
|
||||||
"red" : "0xD5",
|
|
||||||
"alpha" : "1.000",
|
"alpha" : "1.000",
|
||||||
"blue" : "0x1E",
|
"blue" : "0x00",
|
||||||
"green" : "0x2B"
|
"green" : "0x00",
|
||||||
|
"red" : "0xEE"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
}
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,20 +1,20 @@
|
|||||||
{
|
{
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
},
|
|
||||||
"colors" : [
|
"colors" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
|
||||||
"color" : {
|
"color" : {
|
||||||
"color-space" : "srgb",
|
"color-space" : "srgb",
|
||||||
"components" : {
|
"components" : {
|
||||||
"red" : "0xFF",
|
|
||||||
"alpha" : "1.000",
|
"alpha" : "1.000",
|
||||||
"blue" : "0x3D",
|
"blue" : "0x3D",
|
||||||
"green" : "0xBC"
|
"green" : "0xBC",
|
||||||
|
"red" : "0xFF"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
}
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import MVMCore
|
import MVMCore
|
||||||
import VDSTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol, TabsDelegate, MVMCorePresentationDelegateProtocol, SubNavSwipeNavigationProtocol {
|
open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol, TabsDelegate, MVMCorePresentationDelegateProtocol, SubNavSwipeNavigationProtocol {
|
||||||
/// The number of tabs count or less that will turn on the fillContainer
|
/// The number of tabs count or less that will turn on the fillContainer
|
||||||
|
|||||||
@ -1,23 +1,15 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"filename" : "Vector.svg",
|
||||||
"filename" : "exportBlack.png",
|
"idiom" : "universal"
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "exportBlack@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "exportBlack@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
"version" : 1,
|
"author" : "xcode",
|
||||||
"author" : "xcode"
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
MVMCoreUI/SupportingFiles/Media.xcassets/externalLink.imageset/Vector.svg
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20 -3.05176e-05V7.11108H18.7555V2.1333L11.9555 8.9333L11.0666 8.04441L17.8666 1.25553H12.8889V-3.05176e-05H20ZM15 18.7555H1.25553V4.99997H12.2222L13.3333 3.75552H-2.28882e-05V20H16.2555V6.66664L15 7.77775V18.7555Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 343 B |
|
Before Width: | Height: | Size: 345 B |
|
Before Width: | Height: | Size: 589 B |
|
Before Width: | Height: | Size: 869 B |
@ -1,23 +1,15 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"filename" : "nav_back.png",
|
"filename" : "Vector.svg",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal"
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "nav_back@2x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "nav_back@3x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
MVMCoreUI/SupportingFiles/Media.xcassets/nav_back.imageset/Vector.svg
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20 10.6361H2.46073L10.9975 19.1001L10.0897 20L0 10L10.0897 0L10.9974 0.899867L2.46077 9.36388H20V10.6361Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 235 B |
|
Before Width: | Height: | Size: 220 B |
|
Before Width: | Height: | Size: 302 B |
|
Before Width: | Height: | Size: 394 B |
|
Before Width: | Height: | Size: 435 B |
|
Before Width: | Height: | Size: 631 B |
|
Before Width: | Height: | Size: 257 B |
@ -1,23 +1,15 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"filename" : "Close.png",
|
"filename" : "Vector.svg",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal"
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Close-1.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Close-2.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
MVMCoreUI/SupportingFiles/Media.xcassets/nav_close.imageset/Vector.svg
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.87772 9.00001L17.7777 16.8889L16.8888 17.7778L8.99995 9.87778L1.11106 17.7778L0.222168 16.8889L8.11106 9.00001L0.222168 1.11112L1.11106 0.222229L8.99995 8.11112L16.8888 0.222229L17.7777 1.11112L9.87772 9.00001Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 342 B |
@ -22,6 +22,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
// The bundle for this framework
|
// The bundle for this framework
|
||||||
+ (nullable NSBundle *)bundleForMVMCoreUI;
|
+ (nullable NSBundle *)bundleForMVMCoreUI;
|
||||||
|
|
||||||
|
/// The bundle for the VDS frameowrk. Handy for accessing VDS resources such as fonts.
|
||||||
|
+ (nullable NSBundle *)bundleForFonts;
|
||||||
|
|
||||||
// Returns the hardcoded string from the string file.
|
// Returns the hardcoded string from the string file.
|
||||||
+ (nullable NSString *)hardcodedStringWithKey:(nonnull NSString *)key;
|
+ (nullable NSString *)hardcodedStringWithKey:(nonnull NSString *)key;
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,10 @@
|
|||||||
return [NSBundle bundleWithIdentifier:@"com.vzw.MVMCoreUI"];
|
return [NSBundle bundleWithIdentifier:@"com.vzw.MVMCoreUI"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (nullable NSBundle *)bundleForFonts {
|
||||||
|
return [NSBundle bundleWithIdentifier:@"com.vzw.vds"];
|
||||||
|
}
|
||||||
|
|
||||||
+ (nullable NSString *)hardcodedStringWithKey:(nonnull NSString *)key {
|
+ (nullable NSString *)hardcodedStringWithKey:(nonnull NSString *)key {
|
||||||
// Redirect key with relevant module.
|
// Redirect key with relevant module.
|
||||||
return [MVMCoreGetterUtility hardcodedStringWithKey:key bundle:[MVMCoreUIUtility bundleForMVMCoreUI]];
|
return [MVMCoreGetterUtility hardcodedStringWithKey:key bundle:[MVMCoreUIUtility bundleForMVMCoreUI]];
|
||||||
|
|||||||