Merge branch 'develop' into feature/models
This commit is contained in:
commit
727c02a966
@ -21,6 +21,7 @@
|
||||
01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; };
|
||||
01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; };
|
||||
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; };
|
||||
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; };
|
||||
B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* CornerLabels.swift */; };
|
||||
D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
@ -43,6 +44,8 @@
|
||||
D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */ = {isa = PBXBuildFile; fileRef = D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */; };
|
||||
D260D7B622D68514007E7233 /* MVMCoreUIPagingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D274CA332236A78900B01B62 /* StandardFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D274CA322236A78900B01B62 /* StandardFooterView.swift */; };
|
||||
D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */; };
|
||||
D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27CD40F2339057800C1DC07 /* EyebrowHeadlineBodyLink.swift */; };
|
||||
D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */; };
|
||||
D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB9224131D100C46919 /* MFTransparentGIFView.swift */; };
|
||||
D282AACB2243C61700C46919 /* ButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AACA2243C61700C46919 /* ButtonView.swift */; };
|
||||
@ -206,6 +209,7 @@
|
||||
01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = "<group>"; };
|
||||
01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = "<group>"; };
|
||||
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = "<group>"; };
|
||||
948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.swift; sourceTree = "<group>"; };
|
||||
B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = "<group>"; };
|
||||
B8200E182281DC1A007245F4 /* CornerLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = "<group>"; };
|
||||
D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = "<group>"; };
|
||||
@ -228,6 +232,8 @@
|
||||
D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIPageControl.m; sourceTree = "<group>"; };
|
||||
D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIPagingProtocol.h; sourceTree = "<group>"; };
|
||||
D274CA322236A78900B01B62 /* StandardFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardFooterView.swift; sourceTree = "<group>"; };
|
||||
D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsTableViewCell.swift; sourceTree = "<group>"; };
|
||||
D27CD40F2339057800C1DC07 /* EyebrowHeadlineBodyLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EyebrowHeadlineBodyLink.swift; sourceTree = "<group>"; };
|
||||
D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFLoadImageView.swift; sourceTree = "<group>"; };
|
||||
D282AAB9224131D100C46919 /* MFTransparentGIFView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFTransparentGIFView.swift; sourceTree = "<group>"; };
|
||||
D282AACA2243C61700C46919 /* ButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonView.swift; sourceTree = "<group>"; };
|
||||
@ -430,6 +436,7 @@
|
||||
children = (
|
||||
D2A638FC22CA98280052ED1F /* HeadlineBody.swift */,
|
||||
D22479952316AF6D003FCCF9 /* HeadlineBodyTextButton.swift */,
|
||||
D27CD40F2339057800C1DC07 /* EyebrowHeadlineBodyLink.swift */,
|
||||
);
|
||||
path = VerticalCombinationViews;
|
||||
sourceTree = "<group>";
|
||||
@ -467,6 +474,7 @@
|
||||
D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */,
|
||||
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */,
|
||||
D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */,
|
||||
D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */,
|
||||
);
|
||||
path = Items;
|
||||
sourceTree = "<group>";
|
||||
@ -698,6 +706,7 @@
|
||||
D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */,
|
||||
D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */,
|
||||
B8200E142280C4CF007245F4 /* ProgressBar.swift */,
|
||||
948DB67D2326DCD90011F916 /* MultiProgress.swift */,
|
||||
DBC4391622442196001AB423 /* CaretView.swift */,
|
||||
DBC4391722442197001AB423 /* DashLine.swift */,
|
||||
DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */,
|
||||
@ -1014,6 +1023,7 @@
|
||||
DBC4391922442197001AB423 /* DashLine.swift in Sources */,
|
||||
D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */,
|
||||
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */,
|
||||
D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */,
|
||||
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */,
|
||||
D22D1F1F220343560077CEC0 /* MVMCoreUICheckMarkView.m in Sources */,
|
||||
D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */,
|
||||
@ -1079,6 +1089,7 @@
|
||||
D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */,
|
||||
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
|
||||
D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */,
|
||||
D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */,
|
||||
D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */,
|
||||
0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */,
|
||||
D29DF29821E7ADB8003B2FB9 /* MFScrollingViewController.m in Sources */,
|
||||
@ -1087,6 +1098,7 @@
|
||||
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */,
|
||||
D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */,
|
||||
D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */,
|
||||
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */,
|
||||
D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */,
|
||||
D29DF11821E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m in Sources */,
|
||||
D29DF26C21E6AA0B003B2FB9 /* FLAnimatedImage.m in Sources */,
|
||||
|
||||
@ -174,7 +174,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
||||
super.init(frame: .zero)
|
||||
|
||||
setText(fullText, startTag: startTag, endTag: endTag)
|
||||
actionBlock = label?.createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
setActionMap(actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
@class Label;
|
||||
@class MFSizeObject;
|
||||
|
||||
@interface MVMCoreUICheckBox : UIControl <MVMCoreViewProtocol>
|
||||
@interface MVMCoreUICheckBox : UIControl <MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol>
|
||||
|
||||
@property (nullable, weak, nonatomic) MVMCoreUICheckMarkView *checkMark;
|
||||
@property (readonly, nonatomic) BOOL isSelected;
|
||||
|
||||
@ -9,10 +9,11 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <MVMCoreUI/MVMCoreUIMoleculeViewProtocol.h>
|
||||
#import <MVMCoreUI/MVMCoreUIViewConstrainingProtocol.h>
|
||||
@import MVMCore.MVMCoreViewProtocol;
|
||||
typedef void(^ValueChangeBlock)(void);
|
||||
|
||||
@interface MVMCoreUISwitch : UIControl <MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol>
|
||||
@interface MVMCoreUISwitch : UIControl <MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol>
|
||||
|
||||
@property (assign, nonatomic, getter=isOn) BOOL on;
|
||||
@property (nullable, strong, nonatomic) UIColor *onTintColor;
|
||||
|
||||
99
MVMCoreUI/Atoms/Views/MultiProgress.swift
Normal file
99
MVMCoreUI/Atoms/Views/MultiProgress.swift
Normal file
@ -0,0 +1,99 @@
|
||||
//
|
||||
// MultiProgress.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Ryan on 9/9/19.
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@objcMembers open class ProgressBarObject {
|
||||
///from 0.0 to 1.0. input progress should be [0 100]
|
||||
var progress: CGFloat = 0.0
|
||||
///default color is cerulean
|
||||
var color: UIColor = UIColor.mfCerulean()
|
||||
|
||||
init(_ module: [AnyHashable: Any]?) {
|
||||
progress = (module?.optionalCGFloatForKey("progress") ?? 0.0)/100
|
||||
if let colorString = module?.optionalStringForKey("progressColor") {
|
||||
color = UIColor.mfGet(forHex: colorString)
|
||||
}
|
||||
}
|
||||
|
||||
static func getProgressBarObjectList(_ list: [[AnyHashable: Any]]?) -> [ProgressBarObject]? {
|
||||
guard list?.count ?? 0 > 0 else {
|
||||
return nil
|
||||
}
|
||||
var progressList = [ProgressBarObject]()
|
||||
for module in list! {
|
||||
let progressObject = ProgressBarObject(module)
|
||||
progressList.append(progressObject)
|
||||
}
|
||||
return progressList
|
||||
}
|
||||
}
|
||||
|
||||
@objcMembers open class MultiProgress: MFView {
|
||||
///passing value to progressList creates corresponding progress bars
|
||||
var progressList: Array<ProgressBarObject>? {
|
||||
didSet {
|
||||
for subview in subviews {
|
||||
subview.removeFromSuperview()
|
||||
}
|
||||
guard (progressList?.count ?? 0) > 0 else {
|
||||
return
|
||||
}
|
||||
var previous: UIView?
|
||||
for progressObject in progressList! {
|
||||
guard progressObject.progress > 0.0 else {
|
||||
continue
|
||||
}
|
||||
let view = MFView(frame: .zero)
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(view)
|
||||
view.backgroundColor = progressObject.color
|
||||
view.widthAnchor.constraint(equalTo: widthAnchor, multiplier: progressObject.progress).isActive = true
|
||||
view.leadingAnchor.constraint(equalTo: previous?.trailingAnchor ?? leadingAnchor).isActive = true
|
||||
previous = view
|
||||
NSLayoutConstraint.constraintPinSubview(view, pinTop: true, pinBottom: true, pinLeft: false, pinRight: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var roundedRect: Bool = false {
|
||||
didSet {
|
||||
if roundedRect {
|
||||
layer.cornerRadius = (thicknessConstraint?.constant ?? defaultHeight)/2
|
||||
} else {
|
||||
layer.cornerRadius = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
var thicknessConstraint: NSLayoutConstraint?
|
||||
let defaultHeight: CGFloat = 8
|
||||
|
||||
override open func setupView() {
|
||||
super.setupView()
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
backgroundColor = .mfLightSilver()
|
||||
clipsToBounds = true
|
||||
if thicknessConstraint == nil {
|
||||
thicknessConstraint = heightAnchor.constraint(equalToConstant: defaultHeight)
|
||||
thicknessConstraint?.isActive = true
|
||||
}
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
backgroundColor = .mfLightSilver()
|
||||
progressList = nil
|
||||
}
|
||||
|
||||
override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
thicknessConstraint?.constant = json?.optionalCGFloatForKey("thickness") ?? defaultHeight
|
||||
roundedRect = json?.optionalBoolForKey("roundedRect") ?? false
|
||||
progressList = ProgressBarObject.getProgressBarObjectList(json?.optionalArrayForKey("progressList") as? [[AnyHashable: Any]])
|
||||
}
|
||||
}
|
||||
@ -70,7 +70,7 @@ import Foundation
|
||||
thickness = 8
|
||||
progress = 0
|
||||
progressTintColor = UIColor.mfCerulean()
|
||||
trackTintColor = UIColor.mfSilver()
|
||||
trackTintColor = UIColor.mfLightSilver()
|
||||
}
|
||||
|
||||
public static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
|
||||
@ -34,6 +34,9 @@
|
||||
@property (nonatomic) BOOL updateViewHorizontalDefaults;
|
||||
@property (nonatomic) BOOL updateViewVerticalDefaults;
|
||||
|
||||
@property (nonatomic) CGFloat topMarginPadding;
|
||||
@property (nonatomic) CGFloat bottomMarginPadding;
|
||||
|
||||
/// A molecule if we constrain one.
|
||||
@property (weak, nullable, nonatomic) UIView <MVMCoreUIMoleculeViewProtocol>*molecule;
|
||||
|
||||
|
||||
@ -304,18 +304,15 @@
|
||||
[super setupView];
|
||||
self.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.topMarginPadding = PaddingDefaultVerticalSpacing3;
|
||||
self.bottomMarginPadding = PaddingDefaultVerticalSpacing3;
|
||||
[MVMCoreUIUtility setMarginsForView:self leading:0 top:0 trailing:0 bottom:0];
|
||||
}
|
||||
|
||||
- (void)updateView:(CGFloat)size {
|
||||
[super updateView:size];
|
||||
if ([self.constrainedView respondsToSelector:@selector(updateView:)]) {
|
||||
[((id<MVMCoreViewProtocol>)self.constrainedView) updateView:size];
|
||||
}
|
||||
if (self.molecule != self.constrainedView) {
|
||||
[self.molecule updateView:size];
|
||||
}
|
||||
[MFStyler setDefaultMarginsForView:self size:size horizontal:self.updateViewHorizontalDefaults vertical:self.updateViewVerticalDefaults];
|
||||
[self.molecule updateView:size];
|
||||
[MFStyler setMarginsForView:self size:size defaultHorizontal:self.updateViewHorizontalDefaults top:(self.updateViewVerticalDefaults ? self.topMarginPadding : 0) bottom:(self.updateViewVerticalDefaults ? self.bottomMarginPadding : 0)];
|
||||
UIEdgeInsets margins = [MVMCoreUIUtility getMarginsForView:self];
|
||||
if (self.updateViewHorizontalDefaults) {
|
||||
[self setLeftPinConstant:margins.left];
|
||||
@ -344,6 +341,8 @@
|
||||
[super reset];
|
||||
self.updateViewHorizontalDefaults = NO;
|
||||
self.updateViewVerticalDefaults = NO;
|
||||
self.topMarginPadding = PaddingDefaultVerticalSpacing3;
|
||||
self.bottomMarginPadding = PaddingDefaultVerticalSpacing3;
|
||||
if ([self.molecule respondsToSelector:@selector(alignment)]) {
|
||||
[self alignHorizontal:[(UIView <MVMCoreUIViewConstrainingProtocol> *)self.molecule alignment]];
|
||||
}
|
||||
@ -354,8 +353,10 @@
|
||||
}
|
||||
|
||||
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
|
||||
[super setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
|
||||
|
||||
// Only treated as a container if we are constraining a molecule.
|
||||
if (!self.constrainedView) {
|
||||
[super setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
|
||||
}
|
||||
[self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
|
||||
if (self.shouldSetupMoleculeFromJSON) {
|
||||
NSDictionary *moleculeJSON = [json dict:KeyMolecule];
|
||||
|
||||
@ -30,6 +30,9 @@
|
||||
|
||||
@property (nonatomic, readonly) NSInteger selectedIndex;
|
||||
|
||||
/// A flag for if there should be padding before the first item.
|
||||
@property (nonatomic) BOOL paddingBeforeFirstTab;
|
||||
|
||||
//method to set the height
|
||||
- (void)pinHeight:(CGFloat)height;
|
||||
|
||||
|
||||
@ -75,6 +75,7 @@ static NSString * const COLLECTION_CELL_ID = @"cell";
|
||||
}
|
||||
|
||||
- (void)setupView {
|
||||
self.paddingBeforeFirstTab = YES;
|
||||
self.maxHeight = BAR_HEIGHT;
|
||||
self.selectedIndex = 0;
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
@ -229,6 +230,9 @@ static NSString * const COLLECTION_CELL_ID = @"cell";
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
|
||||
if (!self.paddingBeforeFirstTab && section == 0) {
|
||||
return UIEdgeInsetsMake(SECTION_TOPPIN, 0,SECTION_BOTPIN, 0);
|
||||
}
|
||||
return UIEdgeInsetsMake(SECTION_TOPPIN, SECTION_PADDING,SECTION_BOTPIN, 0);
|
||||
}
|
||||
|
||||
@ -341,7 +345,7 @@ static NSString * const COLLECTION_CELL_ID = @"cell";
|
||||
}
|
||||
|
||||
- (void)selectIndex:(NSInteger)index animated:(BOOL)animated {
|
||||
if (self.collectionView) {
|
||||
if (self.collectionView && [self.datasource numberOfTopTabbarItems:self] > 0) {
|
||||
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
||||
NSInteger currentIndex = self.selectedIndex;
|
||||
self.selectedIndex = index;
|
||||
|
||||
@ -20,27 +20,30 @@ import UIKit
|
||||
guard subviews.count == 0 else {
|
||||
return
|
||||
}
|
||||
MVMCoreUIUtility.setMarginsFor(self, leading: 0, top: 0, trailing: 0, bottom: 0)
|
||||
headlineBody.headlineLabel.styleB1(true)
|
||||
headlineBody.spaceBetweenLabelsConstant = 0
|
||||
addSubview(headlineBody)
|
||||
addSubview(imageView)
|
||||
|
||||
NSLayoutConstraint.pinViewTop(toSuperview: headlineBody, useMargins: true, constant: 0).isActive = true
|
||||
NSLayoutConstraint.pinViewRight(toSuperview: headlineBody, useMargins: true, constant: 0).isActive = true
|
||||
layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: headlineBody.bottomAnchor).isActive = true
|
||||
var constraint = NSLayoutConstraint.pinViewBottom(toSuperview: headlineBody, useMargins: true, constant: 0)
|
||||
let view = MVMCoreUICommonViewsUtility.commonView()
|
||||
addSubview(view)
|
||||
pinView(toSuperView: view)
|
||||
view.addSubview(headlineBody)
|
||||
view.addSubview(imageView)
|
||||
|
||||
headlineBody.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
|
||||
view.rightAnchor.constraint(equalTo: headlineBody.rightAnchor).isActive = true
|
||||
view.bottomAnchor.constraint(greaterThanOrEqualTo: headlineBody.bottomAnchor).isActive = true
|
||||
var constraint = view.bottomAnchor.constraint(equalTo: headlineBody.bottomAnchor)
|
||||
constraint.priority = .defaultLow
|
||||
constraint.isActive = true
|
||||
|
||||
imageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
|
||||
NSLayoutConstraint.pinViewLeft(toSuperview: imageView, useMargins: true, constant: 0).isActive = true
|
||||
imageView.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true
|
||||
layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: imageView.bottomAnchor).isActive = true
|
||||
constraint = NSLayoutConstraint.pinViewBottom(toSuperview: imageView, useMargins: true, constant: 0)
|
||||
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
|
||||
imageView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
|
||||
imageView.topAnchor.constraint(greaterThanOrEqualTo: view.topAnchor).isActive = true
|
||||
view.bottomAnchor.constraint(greaterThanOrEqualTo: imageView.bottomAnchor).isActive = true
|
||||
constraint = view.bottomAnchor.constraint(equalTo: imageView.bottomAnchor)
|
||||
constraint.priority = UILayoutPriority(rawValue: 200)
|
||||
constraint.isActive = true
|
||||
constraint = NSLayoutConstraint.pinViewTop(toSuperview: imageView, useMargins: true, constant: 0)
|
||||
constraint = imageView.topAnchor.constraint(equalTo: view.topAnchor)
|
||||
constraint.priority = UILayoutPriority(rawValue: 200)
|
||||
constraint.isActive = true
|
||||
|
||||
|
||||
@ -34,9 +34,9 @@ import UIKit
|
||||
}
|
||||
|
||||
if accordionButton.isSelected {
|
||||
delegateObject?.moleculeDelegate?.addMolecules?(molecules, senderIndexPath: indexPath)
|
||||
delegateObject?.moleculeDelegate?.addMolecules?(molecules, sender: self, animation: .automatic)
|
||||
} else {
|
||||
delegateObject?.moleculeDelegate?.removeMolecules?(molecules, senderIndexPath: indexPath)
|
||||
delegateObject?.moleculeDelegate?.removeMolecules?(molecules, sender: self, animation: .automatic)
|
||||
}
|
||||
|
||||
if (json?.boolForKey("hideSeparatorWhenExpanded") ?? false) && (self.bottomSeparatorView?.shouldBeVisible() ?? false) {
|
||||
|
||||
@ -137,7 +137,7 @@ import UIKit
|
||||
if let useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") {
|
||||
updateViewHorizontalDefaults = useHorizontalMargins
|
||||
}
|
||||
if json?.optionalBoolForKey("useVerticalMargins") ?? false {
|
||||
if (json?.optionalBoolForKey("useVerticalMargins") ?? true) == false {
|
||||
topMarginPadding = 0
|
||||
bottomMarginPadding = 0
|
||||
}
|
||||
|
||||
81
MVMCoreUI/Molecules/Items/TabsTableViewCell.swift
Normal file
81
MVMCoreUI/Molecules/Items/TabsTableViewCell.swift
Normal file
@ -0,0 +1,81 @@
|
||||
//
|
||||
// TabsTableViewCell.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 9/6/19.
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@objcMembers public class TabsTableViewCell: MoleculeTableViewCell {
|
||||
let tabs = TopTabbar(frame: .zero)
|
||||
var delegateObject: MVMCoreUIDelegateObject?
|
||||
var previousTabIndex = 0
|
||||
|
||||
// MARK: - MFViewProtocol
|
||||
override public func setupView() {
|
||||
super.setupView()
|
||||
guard tabs.superview == nil else {
|
||||
return
|
||||
}
|
||||
tabs.paddingBeforeFirstTab = false
|
||||
topMarginPadding = 8
|
||||
bottomMarginPadding = 0
|
||||
|
||||
tabs.translatesAutoresizingMaskIntoConstraints = false
|
||||
tabs.delegate = self
|
||||
tabs.datasource = self
|
||||
contentView.addSubview(tabs)
|
||||
|
||||
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: tabs, useMargins: true).values))
|
||||
tabs.reloadData()
|
||||
}
|
||||
|
||||
public override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
tabs.updateView(size)
|
||||
}
|
||||
|
||||
// MARK: - MoleculeDelegateProtocol
|
||||
public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
|
||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
self.delegateObject = delegateObject
|
||||
tabs.reloadData()
|
||||
}
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
topMarginPadding = 8
|
||||
bottomMarginPadding = 0
|
||||
}
|
||||
}
|
||||
|
||||
extension TabsTableViewCell: TopTabbarDelegate {
|
||||
public func shouldSelectItem(at index: Int, topTabbar: TopTabbar) -> Bool {
|
||||
if let moleculesArrays = json?.arrayForKey(KeyMolecules), let molecules = moleculesArrays[topTabbar.selectedIndex] as? [[AnyHashable: Any]] {
|
||||
delegateObject?.moleculeDelegate?.removeMolecules?(molecules, sender: self, animation: index < tabs.selectedIndex ? .right : .left)
|
||||
}
|
||||
previousTabIndex = tabs.selectedIndex
|
||||
return true
|
||||
}
|
||||
|
||||
public func topTabbar(_ topTabbar: TopTabbar, didSelectItemAt index: Int) {
|
||||
if let moleculesArrays = json?.arrayForKey(KeyMolecules), let molecules = moleculesArrays[index] as? [[AnyHashable: Any]] {
|
||||
delegateObject?.moleculeDelegate?.addMolecules?(molecules, sender: self, animation: index < previousTabIndex ? .left : .right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension TabsTableViewCell: TopTabbarDataSource {
|
||||
public func number(ofTopTabbarItems topTabbar: TopTabbar) -> Int {
|
||||
return json?.optionalDictionaryForKey("tabs")?.optionalArrayForKey("tabs")?.count ?? 0
|
||||
}
|
||||
|
||||
public func topTabbar(_ topTabbar: TopTabbar, titleForItemAt index: Int) -> String? {
|
||||
guard let tabs = json?.optionalDictionaryForKey("tabs")?.arrayForKey("tabs"), let label = tabs[index] as? [AnyHashable: Any], let title = label.optionalStringForKey(KeyText) else {
|
||||
return "Select"
|
||||
}
|
||||
return title
|
||||
}
|
||||
}
|
||||
@ -25,8 +25,12 @@ import UIKit
|
||||
return
|
||||
}
|
||||
headlineBody.styleListItem()
|
||||
addSubview(headlineBody)
|
||||
addSubview(mvmSwitch)
|
||||
let view = MVMCoreUICommonViewsUtility.commonView()
|
||||
addSubview(view)
|
||||
pinView(toSuperView: view)
|
||||
|
||||
view.addSubview(headlineBody)
|
||||
view.addSubview(mvmSwitch)
|
||||
NSLayoutConstraint.pinSubviewsCenter(leftView: headlineBody, rightView: mvmSwitch)
|
||||
}
|
||||
|
||||
|
||||
@ -24,9 +24,13 @@ import UIKit
|
||||
guard mvmSwitch.superview == nil else {
|
||||
return
|
||||
}
|
||||
let view = MVMCoreUICommonViewsUtility.commonView()
|
||||
addSubview(view)
|
||||
pinView(toSuperView: view)
|
||||
|
||||
headlineBodyTextButton.headlineBody.styleListItem()
|
||||
addSubview(headlineBodyTextButton)
|
||||
addSubview(mvmSwitch)
|
||||
view.addSubview(headlineBodyTextButton)
|
||||
view.addSubview(mvmSwitch)
|
||||
NSLayoutConstraint.pinSubviewsCenter(leftView: headlineBodyTextButton, rightView: mvmSwitch)
|
||||
}
|
||||
|
||||
|
||||
@ -24,8 +24,12 @@ import UIKit
|
||||
guard mvmSwitch.superview == nil else {
|
||||
return
|
||||
}
|
||||
addSubview(label)
|
||||
addSubview(mvmSwitch)
|
||||
let view = MVMCoreUICommonViewsUtility.commonView()
|
||||
addSubview(view)
|
||||
pinView(toSuperView: view)
|
||||
|
||||
view.addSubview(label)
|
||||
view.addSubview(mvmSwitch)
|
||||
label.setContentHuggingPriority(UILayoutPriority.required, for: NSLayoutConstraint.Axis.vertical)
|
||||
NSLayoutConstraint.pinSubviewsCenter(leftView: label, rightView: mvmSwitch)
|
||||
}
|
||||
|
||||
@ -19,7 +19,8 @@ import UIKit
|
||||
}
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
scrollView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addConstrainedView(scrollView)
|
||||
addSubview(scrollView)
|
||||
pinView(toSuperView: scrollView)
|
||||
scrollView.addSubview(contentView)
|
||||
NSLayoutConstraint.constraintPinSubview(toSuperview: contentView)
|
||||
let constraint = contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: 1.0)
|
||||
|
||||
@ -11,6 +11,8 @@ import UIKit
|
||||
open class StandardFooterView: ViewConstrainingView {
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
topMarginPadding = PaddingDefaultVerticalSpacing
|
||||
bottomMarginPadding = PaddingDefaultVerticalSpacing
|
||||
shouldSetupMoleculeFromJSON = true
|
||||
updateViewVerticalDefaults = true
|
||||
updateViewHorizontalDefaults = true
|
||||
|
||||
@ -22,6 +22,8 @@ public class StandardHeaderView: ViewConstrainingView {
|
||||
shouldSetupMoleculeFromJSON = true
|
||||
updateViewVerticalDefaults = true
|
||||
updateViewHorizontalDefaults = true
|
||||
topMarginPadding = PaddingDefaultVerticalSpacing
|
||||
bottomMarginPadding = PaddingDefaultVerticalSpacing
|
||||
if separatorView == nil, let separatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionBot, withHorizontalPadding: 0) {
|
||||
separatorView.setAsHeavy()
|
||||
addSubview(separatorView)
|
||||
@ -54,6 +56,8 @@ public class StandardHeaderView: ViewConstrainingView {
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
topMarginPadding = PaddingDefaultVerticalSpacing
|
||||
bottomMarginPadding = PaddingDefaultVerticalSpacing
|
||||
separatorView?.setAsHeavy()
|
||||
separatorView?.show()
|
||||
}
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
//
|
||||
// EyebrowHeadlineBodyLink.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 9/23/19.
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@objcMembers open class EyebrowHeadlineBodyLink: ViewConstrainingView {
|
||||
let stack = MoleculeStackView(frame: .zero)
|
||||
let eyebrow = Label.commonLabelB3(true)
|
||||
let headline = Label.commonLabelB1(true)
|
||||
let body = Label.commonLabelB2(true)
|
||||
let link = MFTextButton(nil, constrainHeight: false, forWidth: MVMCoreUIUtility.getWidth())
|
||||
|
||||
// MARK: - MFViewProtocol
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
guard stack.superview == nil else {
|
||||
return
|
||||
}
|
||||
stack.spacing = 0
|
||||
stack.updateViewHorizontalDefaults = false
|
||||
addSubview(stack)
|
||||
pinView(toSuperView: stack)
|
||||
stack.addStackItem(StackItem(with: eyebrow), lastItem: false)
|
||||
stack.addStackItem(StackItem(with: headline), lastItem: false)
|
||||
stack.addStackItem(StackItem(with: body), lastItem: false)
|
||||
|
||||
// To visually take into account the extra padding in the intrinsic content of a button.
|
||||
let stackItem = StackItem(with: link)
|
||||
stackItem.spacing = -6
|
||||
stack.addStackItem(stackItem, lastItem: true)
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
stack.updateView(size)
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||
open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
|
||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
eyebrow.setWithJSON(json?.optionalDictionaryForKey("eyebrow"), delegateObject: delegateObject, additionalData: additionalData)
|
||||
stack.items[0].gone = !eyebrow.hasText
|
||||
headline.setWithJSON(json?.optionalDictionaryForKey("headline"), delegateObject: delegateObject, additionalData: additionalData)
|
||||
stack.items[1].gone = !headline.hasText
|
||||
body.setWithJSON(json?.optionalDictionaryForKey("body"), delegateObject: delegateObject, additionalData: additionalData)
|
||||
stack.items[2].gone = !body.hasText
|
||||
link.setWithJSON(json?.optionalDictionaryForKey("link"), delegateObject: delegateObject, additionalData: additionalData)
|
||||
stack.items[3].gone = link.titleLabel?.text?.count ?? 0 == 0
|
||||
stack.restack()
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
stack.reset()
|
||||
stack.spacing = 0
|
||||
stack.updateViewHorizontalDefaults = false
|
||||
eyebrow.styleB3(true)
|
||||
headline.styleB1(true)
|
||||
body.styleB2(true)
|
||||
}
|
||||
|
||||
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
return 65
|
||||
}
|
||||
}
|
||||
@ -32,6 +32,8 @@ open class HeadlineBody: ViewConstrainingView {
|
||||
stylePageHeader()
|
||||
case "item":
|
||||
styleListItem()
|
||||
case "itemHeader":
|
||||
styleListItemDivider()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
@ -53,6 +55,12 @@ open class HeadlineBody: ViewConstrainingView {
|
||||
messageLabel.styleB2(true)
|
||||
spaceBetweenLabelsConstant = 0
|
||||
}
|
||||
|
||||
func styleListItemDivider() {
|
||||
headlineLabel.styleH3(true)
|
||||
messageLabel.styleB2(true)
|
||||
spaceBetweenLabelsConstant = 0
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreViewProtocol
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
@ -70,34 +78,36 @@ open class HeadlineBody: ViewConstrainingView {
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
backgroundColor = .clear
|
||||
clipsToBounds = true
|
||||
|
||||
addSubview(headlineLabel)
|
||||
addSubview(messageLabel)
|
||||
|
||||
let view = MVMCoreUICommonViewsUtility.commonView()
|
||||
addSubview(view)
|
||||
pinView(toSuperView: view)
|
||||
|
||||
view.addSubview(headlineLabel)
|
||||
view.addSubview(messageLabel)
|
||||
|
||||
headlineLabel.setContentHuggingPriority(UILayoutPriority.required, for: NSLayoutConstraint.Axis.vertical)
|
||||
messageLabel.setContentHuggingPriority(UILayoutPriority.required, for: NSLayoutConstraint.Axis.vertical)
|
||||
setContentHuggingPriority(UILayoutPriority.required, for: NSLayoutConstraint.Axis.vertical)
|
||||
view.setContentHuggingPriority(UILayoutPriority.required, for: NSLayoutConstraint.Axis.vertical)
|
||||
|
||||
topPin = headlineLabel.topAnchor.constraint(equalTo: topAnchor, constant: 0)
|
||||
topPin?.isActive = true
|
||||
headlineLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
|
||||
|
||||
spaceBetweenLabels = messageLabel.topAnchor.constraint(equalTo: headlineLabel.bottomAnchor, constant: spaceBetweenLabelsConstant)
|
||||
spaceBetweenLabels?.isActive = true
|
||||
|
||||
leftConstraintTitle = headlineLabel.leftAnchor.constraint(equalTo: leftAnchor)
|
||||
leftConstraintTitle = headlineLabel.leftAnchor.constraint(equalTo: view.leftAnchor)
|
||||
leftConstraintTitle?.isActive = true
|
||||
|
||||
rightConstraintTitle = rightAnchor.constraint(equalTo: headlineLabel.rightAnchor)
|
||||
rightConstraintTitle = view.rightAnchor.constraint(equalTo: headlineLabel.rightAnchor)
|
||||
rightConstraintTitle?.isActive = true
|
||||
|
||||
leftConstraintMessage = messageLabel.leftAnchor.constraint(equalTo: leftAnchor)
|
||||
leftConstraintMessage = messageLabel.leftAnchor.constraint(equalTo: view.leftAnchor)
|
||||
leftConstraintMessage?.isActive = true
|
||||
|
||||
rightConstraintMessage = rightAnchor.constraint(equalTo: messageLabel.rightAnchor)
|
||||
rightConstraintMessage = view.rightAnchor.constraint(equalTo: messageLabel.rightAnchor)
|
||||
rightConstraintMessage?.isActive = true
|
||||
|
||||
bottomPin = bottomAnchor.constraint(equalTo: messageLabel.bottomAnchor, constant: 0)
|
||||
bottomPin?.isActive = true
|
||||
view.bottomAnchor.constraint(equalTo: messageLabel.bottomAnchor, constant: 0).isActive = true
|
||||
}
|
||||
|
||||
// MARK: - Constraining
|
||||
@ -109,16 +119,6 @@ open class HeadlineBody: ViewConstrainingView {
|
||||
}
|
||||
}
|
||||
|
||||
open override func setLeftPinConstant(_ constant: CGFloat) {
|
||||
leftConstraintTitle?.constant = constant
|
||||
leftConstraintMessage?.constant = constant
|
||||
}
|
||||
|
||||
open override func setRightPinConstant(_ constant: CGFloat) {
|
||||
rightConstraintTitle?.constant = constant
|
||||
rightConstraintMessage?.constant = constant
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
|
||||
@ -28,23 +28,27 @@ import UIKit
|
||||
guard subviews.count == 0 else {
|
||||
return
|
||||
}
|
||||
addSubview(headlineBody)
|
||||
addSubview(textButton)
|
||||
let view = MVMCoreUICommonViewsUtility.commonView()
|
||||
addSubview(view)
|
||||
pinView(toSuperView: view)
|
||||
|
||||
view.addSubview(headlineBody)
|
||||
view.addSubview(textButton)
|
||||
headlineBody.styleListItem()
|
||||
|
||||
headlineBody.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor, constant: 0).isActive = true
|
||||
headlineBody.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true
|
||||
var constraint = layoutMarginsGuide.rightAnchor.constraint(equalTo: headlineBody.rightAnchor)
|
||||
headlineBody.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
|
||||
headlineBody.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
|
||||
var constraint = view.rightAnchor.constraint(equalTo: headlineBody.rightAnchor)
|
||||
constraint.priority = .defaultHigh
|
||||
constraint.isActive = true
|
||||
|
||||
spaceBetween = textButton.topAnchor.constraint(equalTo: headlineBody.bottomAnchor, constant: spaceBetweenConstant)
|
||||
spaceBetween?.isActive = true
|
||||
|
||||
textButton.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true
|
||||
layoutMarginsGuide.bottomAnchor.constraint(equalTo: textButton.bottomAnchor).isActive = true
|
||||
layoutMarginsGuide.rightAnchor.constraint(greaterThanOrEqualTo: textButton.rightAnchor).isActive = true
|
||||
constraint = layoutMarginsGuide.rightAnchor.constraint(equalTo: textButton.rightAnchor)
|
||||
textButton.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
|
||||
view.bottomAnchor.constraint(equalTo: textButton.bottomAnchor).isActive = true
|
||||
view.rightAnchor.constraint(greaterThanOrEqualTo: textButton.rightAnchor).isActive = true
|
||||
constraint = view.rightAnchor.constraint(equalTo: textButton.rightAnchor)
|
||||
constraint.priority = .defaultHigh
|
||||
constraint.isActive = true
|
||||
}
|
||||
|
||||
@ -14,24 +14,30 @@ public class StackItem {
|
||||
var percentage: Int?
|
||||
var verticalAlignment: UIStackView.Alignment?
|
||||
var horizontalAlignment: UIStackView.Alignment?
|
||||
var gone = false
|
||||
|
||||
init(with view: UIView) {
|
||||
self.view = view
|
||||
}
|
||||
|
||||
init(with view: UIView, json: [AnyHashable: Any]) {
|
||||
init(with view: UIView, json: [AnyHashable: Any]?) {
|
||||
self.view = view
|
||||
update(with: json)
|
||||
}
|
||||
|
||||
func update(with json: [AnyHashable: Any]) {
|
||||
spacing = json.optionalCGFloatForKey("spacing")
|
||||
percentage = json["percent"] as? Int
|
||||
if let alignment = json.optionalStringForKey("verticalAlignment") {
|
||||
func update(with json: [AnyHashable: Any]?) {
|
||||
gone = json?.boolForKey("gone") ?? (json == nil)
|
||||
spacing = json?.optionalCGFloatForKey("spacing")
|
||||
percentage = json?["percent"] as? Int
|
||||
if let alignment = json?.stringOptionalWithChainOfKeysOrIndexes([KeyMolecule,"verticalAlignment"]) {
|
||||
verticalAlignment = ViewConstrainingView.getAlignmentFor(alignment, defaultAlignment: .fill)
|
||||
} else {
|
||||
verticalAlignment = nil
|
||||
}
|
||||
if let alignment = json.optionalStringForKey("horizontalAlignment") {
|
||||
if let alignment = json?.stringOptionalWithChainOfKeysOrIndexes([KeyMolecule,"horizontalAlignment"]) {
|
||||
horizontalAlignment = ViewConstrainingView.getAlignmentFor(alignment, defaultAlignment: .fill)
|
||||
} else {
|
||||
horizontalAlignment = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -80,11 +86,13 @@ public class MoleculeStackView: ViewConstrainingView {
|
||||
|
||||
/// Restacks the existing items.
|
||||
func restack() {
|
||||
MVMCoreUIStackableViewController.remove(contentView.subviews)
|
||||
let stackItems = items
|
||||
items.removeAll()
|
||||
for (index, item) in stackItems.enumerated() {
|
||||
addStackItem(item, lastItem: index == stackItems.count - 1)
|
||||
setWithStackItems(items)
|
||||
}
|
||||
|
||||
/// Removes all stack items views from the view.
|
||||
func removeAllItemViews() {
|
||||
for item in items {
|
||||
item.view.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,7 +148,7 @@ public class MoleculeStackView: ViewConstrainingView {
|
||||
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
let previousJSON = self.json
|
||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
MVMCoreUIStackableViewController.remove(contentView.subviews)
|
||||
removeAllItemViews()
|
||||
|
||||
// If the items in the stack are the same, just update previous items instead of re-allocating.
|
||||
var items: [StackItem]?
|
||||
@ -234,6 +242,10 @@ public class MoleculeStackView: ViewConstrainingView {
|
||||
|
||||
/// Adds the stack item to the stack.
|
||||
func addStackItem(_ stackItem: StackItem, lastItem: Bool) {
|
||||
guard !stackItem.gone else {
|
||||
items.append(stackItem)
|
||||
return
|
||||
}
|
||||
let view = stackItem.view
|
||||
contentView.addSubview(view)
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
@ -245,10 +257,13 @@ public class MoleculeStackView: ViewConstrainingView {
|
||||
view.alignHorizontal?(horizontalAlignment)
|
||||
view.alignVertical?(verticalAlignment)
|
||||
}
|
||||
let first = items.first { !$0.gone } == nil
|
||||
if axis == .vertical {
|
||||
if items.count == 0 {
|
||||
if first {
|
||||
pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: useStackSpacingBeforeFirstItem ? spacing : stackItem.spacing ?? 0)
|
||||
} else if let previousView = items.last?.view {
|
||||
} else if let previousView = items.last(where: { stackItem in
|
||||
return !stackItem.gone
|
||||
})?.view {
|
||||
_ = NSLayoutConstraint(pinFirstView: previousView, toSecondView: view, withConstant: spacing, directionVertical: true)
|
||||
}
|
||||
pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: 0)
|
||||
@ -260,10 +275,12 @@ public class MoleculeStackView: ViewConstrainingView {
|
||||
pinView(contentView, toView: view, attribute: .bottom, relation: .equal, priority: .required, constant: 0)
|
||||
}
|
||||
} else {
|
||||
if items.count == 0 {
|
||||
if first {
|
||||
// First horizontal item has no spacing by default unless told otherwise.
|
||||
pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: useStackSpacingBeforeFirstItem ? spacing : stackItem.spacing ?? 0)
|
||||
} else if let previousView = items.last?.view {
|
||||
} else if let previousView = items.last(where: { stackItem in
|
||||
return !stackItem.gone
|
||||
})?.view {
|
||||
_ = NSLayoutConstraint(pinFirstView: previousView, toSecondView: view, withConstant: spacing, directionVertical: false)
|
||||
}
|
||||
pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: 0)
|
||||
@ -277,4 +294,20 @@ public class MoleculeStackView: ViewConstrainingView {
|
||||
}
|
||||
items.append(stackItem)
|
||||
}
|
||||
|
||||
func setWithStackItems(_ items: [StackItem]) {
|
||||
removeAllItemViews()
|
||||
self.items.removeAll()
|
||||
var previousPresentItem: StackItem? = nil
|
||||
for item in items {
|
||||
if !item.gone {
|
||||
previousPresentItem = item
|
||||
}
|
||||
addStackItem(item, lastItem: false)
|
||||
}
|
||||
if let lastView = previousPresentItem?.view {
|
||||
let attribute: NSLayoutConstraint.Attribute = axis == .vertical ? .bottom : .right
|
||||
pinView(contentView, toView: lastView, attribute: attribute, relation: .equal, priority: .required, constant: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
@"checkbox" : MVMCoreUICheckBox.class,
|
||||
@"cornerLabels" : CornerLabels.class,
|
||||
@"progressBar": ProgressBar.class,
|
||||
@"multiProgressBar": MultiProgress.class,
|
||||
@"checkbox": MVMCoreUICheckBox.class,
|
||||
@"listItem": MoleculeTableViewCell.class,
|
||||
@"accordionListItem": AccordionMoleculeTableViewCell.class,
|
||||
@ -58,7 +59,9 @@
|
||||
@"labelSwitch": LabelSwitch.class,
|
||||
@"headlineBodySwitch": HeadlineBodySwitch.class,
|
||||
@"headlineBodyTextButton": HeadlineBodyTextButton.class,
|
||||
@"headlineBodyTextButtonSwitch": HeadlineBodyTextButtonSwitch.class
|
||||
@"headlineBodyTextButtonSwitch": HeadlineBodyTextButtonSwitch.class,
|
||||
@"tabsListItem": TabsTableViewCell.class,
|
||||
@"eyebrowHeadlineBodyLink": EyebrowHeadlineBodyLink.class
|
||||
} mutableCopy];
|
||||
});
|
||||
return mapping;
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
- (void)moleculeLayoutUpdated:(nonnull UIView <MVMCoreUIMoleculeViewProtocol>*)molecule;
|
||||
|
||||
/// Asks the delegate to add or remove molecules.
|
||||
- (void)addMolecules:(nonnull NSArray <NSDictionary *>*)molecules senderIndexPath:(nonnull NSIndexPath *)indexPath;
|
||||
- (void)removeMolecules:(nonnull NSArray <NSDictionary *>*)molecules senderIndexPath:(nonnull NSIndexPath *)indexPath;
|
||||
- (void)addMolecules:(nonnull NSArray <NSDictionary *>*)molecules sender:(nonnull UITableViewCell *)sender animation:(UITableViewRowAnimation)animation;
|
||||
- (void)removeMolecules:(nonnull NSArray <NSDictionary *>*)molecules sender:(nonnull UITableViewCell *)sender animation:(UITableViewRowAnimation)animation;
|
||||
|
||||
@end
|
||||
|
||||
@ -117,34 +117,40 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
|
||||
}
|
||||
}
|
||||
|
||||
open override func addMolecules(_ molecules: [[AnyHashable: Any]], senderIndexPath indexPath: IndexPath) {
|
||||
var indexPaths: [IndexPath] = []
|
||||
var moleculeList: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])] = []
|
||||
for (index, molecule) in molecules.enumerated() {
|
||||
if let info = getMoleculeInfo(with: molecule) {
|
||||
moleculeList.append(info)
|
||||
indexPaths.append(IndexPath(row: indexPath.row + 1 + index, section: 0))
|
||||
tableView?.register(info.class, forCellReuseIdentifier: info.identifier)
|
||||
open override func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) {
|
||||
// This dispatch is needed to fix a race condition that can occur if this function is called during the table setup.
|
||||
DispatchQueue.main.async {
|
||||
guard let cell = sender as? MoleculeTableViewCell, let indexPath = self.tableView?.indexPath(for: cell) else {
|
||||
return
|
||||
}
|
||||
var indexPaths: [IndexPath] = []
|
||||
for molecule in molecules {
|
||||
if let info = self.getMoleculeInfo(with: molecule) {
|
||||
self.tableView?.register(info.class, forCellReuseIdentifier: info.identifier)
|
||||
let index = indexPath.row + 1 + indexPaths.count
|
||||
self.moleculesInfo?.insert(info, at: index)
|
||||
indexPaths.append(IndexPath(row: index, section: 0))
|
||||
}
|
||||
}
|
||||
self.tableView?.insertRows(at: indexPaths, with: animation)
|
||||
self.updateViewConstraints()
|
||||
self.view.layoutIfNeeded()
|
||||
}
|
||||
moleculesInfo?.insert(contentsOf: moleculeList, at: indexPath.row + 1)
|
||||
tableView?.insertRows(at: indexPaths, with: .automatic)
|
||||
}
|
||||
|
||||
open override func removeMolecules(_ molecules: [[AnyHashable: Any]], senderIndexPath indexPath: IndexPath) {
|
||||
guard let moleculesList = moleculesInfo else {
|
||||
return
|
||||
}
|
||||
open override func removeMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) {
|
||||
var indexPaths: [IndexPath] = []
|
||||
for (index, moleculeInfo) in moleculesList.enumerated() {
|
||||
if molecules.contains(where: { (molecule) -> Bool in
|
||||
for molecule in molecules {
|
||||
if let removeIndex = moleculesInfo?.firstIndex(where: { (moleculeInfo) -> Bool in
|
||||
return NSDictionary(dictionary: molecule).isEqual(to: moleculeInfo.molecule)
|
||||
}) {
|
||||
indexPaths.append(IndexPath(row: index, section: 0))
|
||||
moleculesInfo?.remove(at: index)
|
||||
moleculesInfo?.remove(at: removeIndex)
|
||||
indexPaths.append(IndexPath(row: removeIndex + indexPaths.count, section: 0))
|
||||
}
|
||||
}
|
||||
tableView?.deleteRows(at: indexPaths, with: .automatic)
|
||||
self.tableView?.deleteRows(at: indexPaths, with: animation)
|
||||
self.updateViewConstraints()
|
||||
self.view.layoutIfNeeded()
|
||||
}
|
||||
|
||||
// MARK: - Convenience
|
||||
|
||||
Loading…
Reference in New Issue
Block a user