Merge branch 'develop' into bugfix/detail_view_controller

This commit is contained in:
panxi 2019-05-08 12:45:42 -04:00
commit 2dde640793
52 changed files with 1495 additions and 705 deletions

View File

@ -96,8 +96,6 @@
D29DF28021E7AA51003B2FB9 /* MVMCoreUIDetailViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF27F21E7AA50003B2FB9 /* MVMCoreUIDetailViewProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF28121E7AB23003B2FB9 /* MVMCoreUICommonViewsUtility.m */; };
D29DF28421E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF28221E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29DF28921E7AC2B003B2FB9 /* MFLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF28521E7AC2B003B2FB9 /* MFLabel.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29DF28A21E7AC2B003B2FB9 /* MFLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF28621E7AC2B003B2FB9 /* MFLabel.m */; };
D29DF28B21E7AC2B003B2FB9 /* ViewConstrainingView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF28721E7AC2B003B2FB9 /* ViewConstrainingView.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF28821E7AC2B003B2FB9 /* ViewConstrainingView.m */; };
D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF28D21E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m */; };
@ -158,10 +156,14 @@
D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; };
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */; };
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */; };
D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */; };
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */; };
DBC4391822442197001AB423 /* CaretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391622442196001AB423 /* CaretView.swift */; };
DBC4391922442197001AB423 /* DashLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391722442197001AB423 /* DashLine.swift */; };
DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391A224421A0001AB423 /* CaretButton.swift */; };
DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391C2245232D001AB423 /* LabelWithInternalButton.swift */; };
DBEFFA04225A829700230692 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB891E822253FA8500022516 /* Label.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -263,8 +265,6 @@
D29DF27F21E7AA50003B2FB9 /* MVMCoreUIDetailViewProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIDetailViewProtocol.h; sourceTree = "<group>"; };
D29DF28121E7AB23003B2FB9 /* MVMCoreUICommonViewsUtility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUICommonViewsUtility.m; sourceTree = "<group>"; };
D29DF28221E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUICommonViewsUtility.h; sourceTree = "<group>"; };
D29DF28521E7AC2B003B2FB9 /* MFLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFLabel.h; sourceTree = "<group>"; };
D29DF28621E7AC2B003B2FB9 /* MFLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFLabel.m; sourceTree = "<group>"; };
D29DF28721E7AC2B003B2FB9 /* ViewConstrainingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewConstrainingView.h; sourceTree = "<group>"; };
D29DF28821E7AC2B003B2FB9 /* ViewConstrainingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewConstrainingView.m; sourceTree = "<group>"; };
D29DF28D21E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProgrammaticScrollViewController.m; sourceTree = "<group>"; };
@ -319,6 +319,10 @@
D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = "<group>"; };
D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = "<group>"; };
D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIDelegateObject.swift; sourceTree = "<group>"; };
DB891E822253FA8500022516 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; };
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeTableViewCell.swift; sourceTree = "<group>"; };
D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTableViewController.swift; sourceTree = "<group>"; };
D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeListTemplate.swift; sourceTree = "<group>"; };
DBC4391622442196001AB423 /* CaretView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretView.swift; sourceTree = "<group>"; };
DBC4391722442197001AB423 /* DashLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashLine.swift; sourceTree = "<group>"; };
DBC4391A224421A0001AB423 /* CaretButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretButton.swift; sourceTree = "<group>"; };
@ -407,6 +411,7 @@
01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */,
D2A5146022121FBF00345BFB /* MoleculeStackTemplate.swift */,
D2A514622213643100345BFB /* MoleculeStackCenteredTemplate.swift */,
D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */,
);
path = Templates;
sourceTree = "<group>";
@ -442,6 +447,7 @@
D2A5145C2211D22A00345BFB /* MVMCoreUIMoleculeViewProtocol.h */,
D2A5145E2211DDC100345BFB /* MoleculeStackView.swift */,
D274CA322236A78900B01B62 /* StandardFooterView.swift */,
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */,
);
path = Molecules;
sourceTree = "<group>";
@ -462,6 +468,7 @@
D29DF2CC21E7C104003B2FB9 /* MFLoadingViewController.h */,
D29DF2CD21E7C104003B2FB9 /* MFLoadingViewController.m */,
D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */,
D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */,
);
path = BaseControllers;
sourceTree = "<group>";
@ -564,8 +571,6 @@
DBC4391722442197001AB423 /* DashLine.swift */,
D29DF17E21E69E2E003B2FB9 /* MFView.h */,
D29DF17F21E69E2E003B2FB9 /* MFView.m */,
D29DF28521E7AC2B003B2FB9 /* MFLabel.h */,
D29DF28621E7AC2B003B2FB9 /* MFLabel.m */,
D29DF31E21ED0CBA003B2FB9 /* LabelView.h */,
D29DF31F21ED0CBA003B2FB9 /* LabelView.m */,
D29DF28721E7AC2B003B2FB9 /* ViewConstrainingView.h */,
@ -590,6 +595,7 @@
D22D1F44220496A30077CEC0 /* MVMCoreUISwitch.h */,
D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */,
DBC4391C2245232D001AB423 /* LabelWithInternalButton.swift */,
DB891E822253FA8500022516 /* Label.swift */,
0198F7A02256A80A0066C936 /* MFRadioButton.h */,
0198F7A22256A80A0066C936 /* MFRadioButton.m */,
);
@ -745,7 +751,6 @@
D29DF27521E79E81003B2FB9 /* MVMCoreUILoggingHandler.h in Headers */,
D29DF28B21E7AC2B003B2FB9 /* ViewConstrainingView.h in Headers */,
D29DF2B321E7B76D003B2FB9 /* MFLoadingSpinner.h in Headers */,
D29DF28921E7AC2B003B2FB9 /* MFLabel.h in Headers */,
D29DF32521ED0DA2003B2FB9 /* TextButtonView.h in Headers */,
D29DF25021E6A177003B2FB9 /* MFDigitTextBox.h in Headers */,
D29DF2C621E7BF57003B2FB9 /* MFTabBarInteractor.h in Headers */,
@ -891,12 +896,14 @@
D29DF25421E6A177003B2FB9 /* MFMdnTextField.m in Sources */,
D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */,
D2A514672213885800345BFB /* StandardHeaderView.swift in Sources */,
DBEFFA04225A829700230692 /* Label.swift in Sources */,
D29DF13021E6851E003B2FB9 /* MVMCoreUITopAlertShortView.m in Sources */,
D28B4F8B21FF967C00712C7A /* MVMCoreUIObject.m in Sources */,
D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */,
D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */,
D282AACB2243C61700C46919 /* ButtonView.swift in Sources */,
0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */,
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */,
D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */,
D29DF18121E69E50003B2FB9 /* MFView.m in Sources */,
D29DF18321E69E54003B2FB9 /* SeparatorView.m in Sources */,
@ -904,7 +911,6 @@
D274CA332236A78900B01B62 /* StandardFooterView.swift in Sources */,
D29DF2BF21E7BEA4003B2FB9 /* MVMCoreUITabBarPageControlViewController.m in Sources */,
D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */,
D29DF28A21E7AC2B003B2FB9 /* MFLabel.m in Sources */,
D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */,
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */,
@ -913,6 +919,7 @@
D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */,
D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */,
D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */,
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */,
D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */,
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */,
@ -920,6 +927,7 @@
0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */,
D29DF29821E7ADB8003B2FB9 /* MFScrollingViewController.m in Sources */,
D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */,
D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */,
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */,
D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */,
D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */,

View File

@ -8,13 +8,14 @@
//
open class CaretButton: MFCustomButton {
open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol {
//------------------------------------------------------
// MARK: - Constants
//------------------------------------------------------
private let CaretViewHeight: Float = 10.8
private let CaretViewWidth: Float = 6.6
private let CARET_VIEW_HEIGHT: Float = 10.5
private let CARET_VIEW_WIDTH: Float = 6.5
//------------------------------------------------------
// MARK: - Properties
@ -25,17 +26,11 @@ open class CaretButton: MFCustomButton {
@objc public var rightViewWidth: NSNumber?
@objc public var enabledColor: UIColor = .black {
didSet {
setTitleColor(enabledColor, for: .normal)
changeCaretColor()
}
didSet { changeCaretColor() }
}
@objc public var disabledColor: UIColor = .mfSilver() {
didSet {
setTitleColor(disabledColor, for: .disabled)
changeCaretColor()
}
didSet { changeCaretColor() }
}
private var caretSpacingConstraint: NSLayoutConstraint?
@ -61,9 +56,11 @@ open class CaretButton: MFCustomButton {
//------------------------------------------------------
private func changeCaretColor() {
setTitleColor(enabledColor, for: .normal)
setTitleColor(disabledColor, for: .disabled)
if let rightCaretView = rightView as? CaretView {
rightCaretView.tintColor = isEnabled ? enabledColor : disabledColor
rightCaretView.setLineColor(isEnabled ? enabledColor : disabledColor)
}
}
@ -71,8 +68,8 @@ open class CaretButton: MFCustomButton {
rightView?.removeFromSuperview()
let width = CGFloat(rightViewWidth?.floatValue ?? CaretViewWidth)
let height = CGFloat(rightViewHeight?.floatValue ?? CaretViewHeight)
let width = CGFloat(rightViewWidth?.floatValue ?? CARET_VIEW_WIDTH)
let height = CGFloat(rightViewHeight?.floatValue ?? CARET_VIEW_HEIGHT)
let edgeInsets: UIEdgeInsets = contentEdgeInsets
contentEdgeInsets = UIEdgeInsets(top: edgeInsets.top, left: edgeInsets.left, bottom: edgeInsets.bottom, right: 4 + width)
@ -113,7 +110,7 @@ open class CaretButton: MFCustomButton {
setTitleColor(disabledColor, for: .disabled)
}
open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) {
@objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) {
setWithActionMap(json, delegateObject: delegateObject, additionalData: additionalData)
guard let dictionary = json else { return }
@ -130,4 +127,12 @@ open class CaretButton: MFCustomButton {
disabledColor = UIColor.mfGet(forHex: disabledColorHex)
}
}
public func needsToBeConstrained() -> Bool {
return true
}
open func moleculeAlignment() -> UIStackView.Alignment {
return UIStackView.Alignment.leading;
}
}

View File

@ -141,4 +141,12 @@
}
}
- (BOOL)needsToBeConstrained {
return YES;
}
- (UIStackViewAlignment)moleculeAlignment {
return UIStackViewAlignmentLeading;
}
@end

View File

@ -11,7 +11,7 @@
@class PrimaryButton;
@class MFTextField;
@class MFLabel;
@class Label;
@protocol MFTextFieldDelegate <NSObject>
@ -34,7 +34,7 @@
@property (nullable, weak, nonatomic) IBOutlet UIView *textFieldContainerView;
@property (nullable, weak, nonatomic) IBOutlet UITextField *textField;
@property (nullable, weak, nonatomic) IBOutlet MFLabel *formLabel;
@property (nullable, weak, nonatomic) IBOutlet Label *formLabel;
@property (nullable, weak, nonatomic) IBOutlet UIView *separatorView;//make it public so outsider class can know the posistion of it.
@property (nullable, weak, nonatomic) IBOutlet NSLayoutConstraint *heightConstraint;

View File

@ -7,12 +7,10 @@
//
#import "MFTextField.h"
#import <MVMCoreUI/MVMCoreUI-Swift.h>
#import "MFTextFieldSubclassExtension.h"
#import "MFStyler.h"
#import "UIColor+MFConvenience.h"
#import "MVMCoreUICommonViewsUtility.h"
#import "MFLabel.h"
#import "MVMCoreUIUtility.h"
#import "MVMCoreUIConstants.h"
#import <MVMCoreUI/MVMCoreUI-Swift.h>
@ -300,14 +298,11 @@
self.uiTextFieldDelegate = delegate;
}
- (void)setWithMap:(nullable NSDictionary *)map bothDelegates:(nullable id<UITextFieldDelegate, MFTextFieldDelegate>)delegate {
- (void)setWithMap:(nullable NSDictionary *)map {
if (map.count == 0) {
return;
}
[MVMCoreUICommonViewsUtility addDismissToolbar:self.textField delegate:delegate];
[self setBothTextFieldDelegates:delegate];
NSString *string = [map string:KeyLabel];
if (string.length > 0) {
self.formText = string;
@ -326,7 +321,7 @@
}
// key used to send text value to server
string = [map string:@"fieldKey"];
string = [map string:KeyFieldKey];
if (string.length > 0) {
self.fieldKey = string;
}
@ -353,6 +348,12 @@
}
}
- (void)setWithMap:(nullable NSDictionary *)map bothDelegates:(nullable id<UITextFieldDelegate, MFTextFieldDelegate>)delegate {
[MVMCoreUICommonViewsUtility addDismissToolbar:self.textField delegate:delegate];
[self setBothTextFieldDelegates:delegate];
[self setWithMap:map];
}
- (void)setValidationBlock:(BOOL (^)(NSString * _Nullable))validationBlock {
_validationBlock = validationBlock;
[self valueChanged];
@ -562,7 +563,11 @@
if ([delegateObject isKindOfClass:[MVMCoreUIDelegateObject class]]) {
[FormValidator setupValidationWithMolecule:self delegate:((MVMCoreUIDelegateObject *)delegateObject).formValidationProtocol];
FormValidator *formValidator = [FormValidator getFormValidatorForDelegate:((MVMCoreUIDelegateObject *)delegateObject).formValidationProtocol];
[self setWithMap:json bothDelegates:formValidator];
[self setWithMap:json];
self.mfTextFieldDelegate = formValidator;
self.uiTextFieldDelegate = ((MVMCoreUIDelegateObject *)delegateObject).uiTextFieldDelegate;
[MVMCoreUICommonViewsUtility addDismissToolbar:self.textField delegate:self.uiTextFieldDelegate];
}
}

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -98,7 +98,7 @@
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8zH-YN-qag" customClass="MFLabel">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8zH-YN-qag" customClass="Label" customModule="MVMCoreUI" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="36"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>

View File

@ -13,15 +13,21 @@ open class CaretView: MFView {
// MARK: - Properties
//------------------------------------------------------
// Objc can't use float enum.
@objc public static let thin: CGFloat = 6.0
@objc public static let standard: CGFloat = 2.6
@objc public static let thick: CGFloat = 1.5
private(set) var strokeColor: UIColor?
private var lineWidth: CGFloat?
private var lineThickness: CGFloat?
//------------------------------------------------------
// MARK: - Initialization
//------------------------------------------------------
@objc public init() {
super.init(frame: CGRect.zero)
super.init(frame: .zero)
}
@objc public override init(frame: CGRect) {
@ -32,14 +38,19 @@ open class CaretView: MFView {
super.init(coder: aDecoder)
}
/// Can init with a specific line width.
@objc public init(lineWidth: CGFloat) {
super.init(frame: CGRect())
self.lineWidth = lineWidth
}
/// Can init with a specific line thickness, scales based on width and height.
@objc public init(lineThickness: CGFloat) {
super.init(frame: CGRect())
self.lineThickness = lineThickness
}
@objc override open func setupView() {
defaultState()
}
@ -48,7 +59,6 @@ open class CaretView: MFView {
//------------------------------------------------------
private func defaultState() {
isOpaque = false
isHidden = false
backgroundColor = .clear
@ -64,7 +74,7 @@ open class CaretView: MFView {
let context = UIGraphicsGetCurrentContext()
context?.clear(rect)
let lineWidthToDraw: CGFloat = lineWidth ?? frame.size.width / 2.6
let lineWidthToDraw: CGFloat = lineWidth ?? frame.size.width / (lineThickness ?? 2.6)
let path = UIBezierPath()
path.move(to: CGPoint(x: lineWidthToDraw / 2.0, y: 0.0))
@ -80,7 +90,6 @@ open class CaretView: MFView {
}
@objc public func setLineColor(_ color: UIColor?) {
strokeColor = color
setNeedsDisplay()
}
@ -91,33 +100,40 @@ open class CaretView: MFView {
// Default values for view.
@objc open override func setAsMolecule() {
defaultState()
}
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
// Configure class properties with JSON values
guard let jsonDictionary = json else { return }
guard let dictionary = json else { return }
if let backgroundColorHex = jsonDictionary[KeyBackgroundColor] as? String {
if let backgroundColorHex = dictionary[KeyBackgroundColor] as? String {
backgroundColor = UIColor.mfGet(forHex: backgroundColorHex)
}
if let strokeColorHex = jsonDictionary["strokeColor"] as? String {
if let strokeColorHex = dictionary["strokeColor"] as? String {
strokeColor = UIColor.mfGet(forHex: strokeColorHex)
}
if let isHiddenValue = jsonDictionary[KeyIsHidden] as? Bool {
if let isHiddenValue = dictionary[KeyIsHidden] as? Bool {
isHidden = isHiddenValue
}
if let isOpaqueValue = jsonDictionary[KeyIsOpaque] as? Bool {
if let isOpaqueValue = dictionary[KeyIsOpaque] as? Bool {
isOpaque = isOpaqueValue
}
if let lineWidthValue = jsonDictionary["lineWidth"] as? CGFloat {
if let lineWidthValue = dictionary["lineWidth"] as? CGFloat {
lineWidth = lineWidthValue
}
}
open override func needsToBeConstrained() -> Bool {
return true
}
open override func moleculeAlignment() -> UIStackView.Alignment {
return UIStackView.Alignment.leading;
}
}

View File

@ -0,0 +1,310 @@
//
// Label.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 3/22/17.
// Converted by Christiano, Kevin on 4/2/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import MVMCore
@objc open class Label: UILabel, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol {
//------------------------------------------------------
// MARK: - Properties
//------------------------------------------------------
// Set this property if you want updateView to update the font based on this standard and the size passed in.
@objc public var standardFontSize: CGFloat = 0.0
// Set this to use a custom sizing object during updateView instead of the standard.
@objc public var sizeObject: MFSizeObject?
@objc public var scaleSize: NSNumber?
// Used for scaling the font in updateView.
private var originalAttributedString: NSAttributedString?
@objc public var hasText: Bool {
guard let text = text, let attributedText = attributedText else { return false }
return !text.isEmpty || !attributedText.string.isEmpty
}
//------------------------------------------------------
// MARK: - Initialization
//------------------------------------------------------
@objc public func setupView() {
backgroundColor = .clear
numberOfLines = 0
lineBreakMode = .byWordWrapping
translatesAutoresizingMaskIntoConstraints = false
}
@objc public init() {
super.init(frame: .zero)
setupView()
}
@objc required public init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
@objc override public init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
@objc convenience public init(standardFontSize size: CGFloat) {
self.init()
standardFontSize = size
}
//------------------------------------------------------
// MARK: - Functions
//------------------------------------------------------
@objc public static func commonLabelH1(_ scale: Bool) -> Label {
let label = Label.label()
label.styleH1(scale)
return label
}
@objc public static func commonLabelH2(_ scale: Bool) -> Label {
let label = Label.label()
label.styleH2(scale)
return label
}
@objc public static func commonLabelH3(_ scale: Bool) -> Label {
let label = Label.label()
label.styleH3(scale)
return label
}
@objc public static func commonLabelH32(_ scale: Bool) -> Label {
let label = Label.label()
label.styleH32(scale)
return label
}
@objc public static func commonLabelB1(_ scale: Bool) -> Label {
let label = Label.label()
label.styleB1(scale)
return label
}
@objc public static func commonLabelB2(_ scale: Bool) -> Label {
let label = Label.label()
label.styleB2(scale)
return label
}
@objc public static func commonLabelB3(_ scale: Bool) -> Label {
let label = Label.label()
label.styleB3(scale)
return label
}
@objc public static func commonLabelB20(_ scale: Bool) -> Label {
let label = Label.label()
label.styleB20(scale)
return label
}
@objc open class func label() -> Label {
return Label(frame: .zero)
}
//------------------------------------------------------
// MARK: - Functions
//------------------------------------------------------
@objc public static func setLabel(_ label: UILabel?, withHTML html: String?) {
guard let data = html?.data(using: .utf8) else { return }
do {
label?.attributedText = try NSAttributedString(data: data,
options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html,
NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue],
documentAttributes: nil)
} catch {
if let coreErrorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "LabelHTMLParse") {
MVMCoreUILoggingHandler.shared()?.addError(toLog: coreErrorObject)
}
}
}
@objc public static func setUILabel(_ label: UILabel?, withJSON json: [AnyHashable: Any]?, delegate: DelegateObject?, additionalData: [AnyHashable: Any]?) {
guard let label = label else { return }
label.text = json?.optionalStringForKey(KeyText)
setLabel(label, withHTML: json?.optionalStringForKey("html"))
if let textColorHex = json?.optionalStringForKey(KeyTextColor), !textColorHex.isEmpty {
label.textColor = UIColor.mfGet(forHex: textColorHex)
}
if let backgroundColorHex = json?.optionalStringForKey(KeyBackgroundColor), !backgroundColorHex.isEmpty {
label.backgroundColor = UIColor.mfGet(forHex: backgroundColorHex)
}
label.accessibilityLabel = json?.optionalStringForKey("accessibilityText")
let fontSize = json?["fontSize"] as? CGFloat
if let fontName = json?.optionalStringForKey("fontName") {
label.font = MFFonts.mfFont(withName: fontName, size: fontSize ?? label.font.pointSize)
} else if let fontSize = fontSize {
label.font = label.font.withSize(fontSize)
}
if let attributes = json?.arrayForKey("attributes"), let labelText = label.text {
let attributedString = NSMutableAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: label.font as UIFont,
NSAttributedString.Key.foregroundColor: label.textColor as UIColor])
for case let attribute as [String: Any] in attributes {
guard let attributeType = attribute.optionalStringForKey(KeyType),
let location = attribute["location"] as? Int,
let length = attribute["length"] as? Int
else { continue }
let range = NSRange(location: location, length: length)
switch attributeType {
case "underline":
attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range)
case "strikethrough":
attributedString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.thick.rawValue, range: range)
case "color":
if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty {
attributedString.removeAttribute(.foregroundColor, range: range)
attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range)
}
case "font":
let fontSize = attribute["size"] as? CGFloat
var font: UIFont?
if let fontName = attribute.optionalStringForKey("name") {
font = MFFonts.mfFont(withName: fontName, size: fontSize ?? label.font.pointSize)
} else if let fontSize = fontSize {
font = label.font.withSize(fontSize)
}
if let font = font {
attributedString.removeAttribute(.font, range: range)
attributedString.addAttribute(.font, value: font, range: range)
}
default:
continue
}
}
label.attributedText = attributedString
}
}
//------------------------------------------------------
// MARK: - Methods
//------------------------------------------------------
@objc public func styleH1(_ scale: Bool) {
MFStyler.styleLabelH1(self, genericScaling: false)
setScale(scale)
}
@objc public func styleH2(_ scale: Bool) {
MFStyler.styleLabelH2(self, genericScaling: false)
setScale(scale)
}
@objc public func styleH3(_ scale: Bool) {
MFStyler.styleLabelH3(self, genericScaling: false)
setScale(scale)
}
@objc public func styleH32(_ scale: Bool) {
MFStyler.styleLabelH32(self, genericScaling: false)
setScale(scale)
}
@objc public func styleB1(_ scale: Bool) {
MFStyler.styleLabelB1(self, genericScaling: false)
setScale(scale)
}
@objc public func styleB2(_ scale: Bool) {
MFStyler.styleLabelB2(self, genericScaling: false)
setScale(scale)
}
@objc public func styleB3(_ scale: Bool) {
MFStyler.styleLabelB3(self, genericScaling: false)
setScale(scale)
}
@objc public func styleB20(_ scale: Bool) {
MFStyler.styleLabelB20(self, genericScaling: false)
setScale(scale)
}
@objc public func updateView(_ size: CGFloat) {
scaleSize = size as NSNumber
if let originalAttributedString = originalAttributedString {
let attributedString = NSMutableAttributedString(attributedString: originalAttributedString)
attributedString.removeAttribute(.font, range: NSRange(location: 0, length: attributedString.length))
originalAttributedString.enumerateAttribute(.font, in: NSRange(location: 0, length: originalAttributedString.length), options: [], using: { value, range, stop in
// Loop the original attributed string, resize the fonts.
if let fontObj = value as? UIFont, let stylerSize = MFStyler.sizeObjectGeneric(forCurrentDevice: fontObj.pointSize)?.getValueBased(onSize: size) {
attributedString.addAttribute(.font, value: fontObj.withSize(stylerSize) as Any, range: range)
}
})
attributedText = attributedString
} else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject: MFSizeObject = self.sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) {
self.font = self.font.withSize(sizeObject.getValueBased(onSize: size))
}
}
@objc public func setFont(_ font: UIFont, scale: Bool) {
self.font = font
setScale(scale)
}
@objc public func setScale(_ scale: Bool) {
if scale {
standardFontSize = font.pointSize
if let floatScale = scaleSize?.floatValue {
updateView(CGFloat(floatScale))
} else {
updateView(MVMCoreUISplitViewController.getApplicationViewWidth())
}
} else {
standardFontSize = 0
}
}
//------------------------------------------------------
// MARK: - Atomization
//------------------------------------------------------
@objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) {
Label.setUILabel(self, withJSON: json, delegate: delegateObject, additionalData: additionalData)
originalAttributedString = attributedText
}
public func needsToBeConstrained() -> Bool {
return true;
}
}
extension Label {
}

View File

@ -8,12 +8,12 @@
#import <UIKit/UIKit.h>
#import <MVMCoreUI/ViewConstrainingView.h>
#import <MVMCoreUI/MFLabel.h>
@class Label;
@interface LabelView : ViewConstrainingView
// Customize the label.
@property (nullable, weak, nonatomic) MFLabel *label;
@property (nullable, weak, nonatomic) Label *label;
// Change the alignment of the label
- (void)alignLeft;

View File

@ -8,6 +8,7 @@
#import <MVMCoreUI/LabelView.h>
#import "MFStyler.h"
#import <MVMCoreUI/MVMCoreUI-Swift.h>
@interface LabelView ()
// Change to customize.
@ -32,7 +33,7 @@
if (!self.label) {
self.backgroundColor = [UIColor clearColor];
MFLabel *label = [MFLabel commonLabelB2:YES];
Label *label = [Label commonLabelB2:YES];
[self addSubview:label];
self.label = label;

View File

@ -10,9 +10,9 @@
import MVMCore
public typealias ActionBlock = () -> Void
private typealias ActionableStringTuple = (front: String?, middle: String?, end: String?)
public typealias ActionObjectDelegate = (NSObjectProtocol & MVMCoreActionDelegateProtocol)
public typealias ButtonObjectDelegate = (NSObjectProtocol & ButtonDelegateProtocol)
private typealias ActionableStringTuple = (front: String?, action: String?, end: String?)
public typealias ActionObjectDelegate = NSObjectProtocol & MVMCoreActionDelegateProtocol
public typealias ButtonObjectDelegate = NSObjectProtocol & ButtonDelegateProtocol
public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProtocol & MVMCoreLoadDelegateProtocol & MVMCorePresentationDelegateProtocol & NSObjectProtocol
@ -22,11 +22,11 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
//------------------------------------------------------
public var actionBlock: ActionBlock?
public weak var label: MFLabel?
public weak var label: Label?
public var attributedText: NSAttributedString? {
willSet(newAttributedText) {
if let newAttribText = newAttributedText, !newAttribText.string.isEmpty {
if let newAttribText = newAttributedText {
let mutableAttributedText = NSMutableAttributedString(attributedString: newAttribText)
let paragraphStyle = NSMutableParagraphStyle()
@ -62,6 +62,10 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
}
}
private var actionRange: NSRange {
return NSRange(location: frontText?.count ?? 0, length: actionText?.count ?? 0)
}
public var makeWholeViewClickable = false
override open var isEnabled: Bool {
@ -74,9 +78,16 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
public var actionText: String?
public var backText: String?
private var text: String? {
willSet(newText) {
attributedText = NSAttributedString(string: newText ?? "")
private var internalText: String = ""
public var text: String? {
get {
return internalText
}
set {
guard let text = newValue else { return }
internalText = text
attributedText = NSAttributedString(string: text)
setAlternateNormalTextAttributes([NSAttributedString.Key.font: normalTextFont as Any])
setAlternateActionTextAttributes([NSAttributedString.Key.font: actionTextFont as Any])
setAlternateNormalTextAttributes([NSAttributedString.Key.foregroundColor: normalTextColor as Any])
@ -89,7 +100,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
//------------------------------------------------------
public init() {
super.init(frame: CGRect.zero)
super.init(frame: .zero)
setup()
}
@ -103,15 +114,9 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
setup()
}
public init(frontText: String?, actionText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
super.init(frame: CGRect.zero)
setFrontText(frontText, actionText: actionText, actionMap: actionMap, backText: backText, additionalData: additionalData, delegate: delegate, buttonDelegate: buttonDelegate)
}
// MARK: - legacy
public init(frontText: String?, actionText: String?, backText: String?, actionBlock block: ActionBlock?) {
super.init(frame: CGRect.zero)
super.init(frame: .zero)
self.frontText = frontText
self.actionText = actionText
@ -121,42 +126,46 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
setup()
}
public convenience init(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
public convenience init(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
self.init(frontText: actionMap?.optionalStringForKey(KeyTitlePrefix),
actionText: actionMap?.optionalStringForKey(KeyTitle),
backText: actionMap?.optionalStringForKey(KeyTitlePostfix),
actionMap: actionMap, additionalData: additionalData,
delegateObject: delegateObject)
}
public convenience init(frontText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
self.init(frontText: frontText,
actionText: actionMap?.optionalStringForKey(KeyTitle),
backText: backText,
actionMap: actionMap,
additionalData: additionalData,
delegateObject: delegateObject)
}
public init(frontText: String?, actionText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
super.init(frame: CGRect.zero)
self.init(frontText: actionMap?.optionalStringForKey(KeyTitlePrefix), actionText: actionMap?.optionalStringForKey(KeyTitle), backText: actionMap?.optionalStringForKey(KeyTitlePostfix), actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
}
public convenience init(frontText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
self.init(frontText: frontText, actionText: actionMap?.optionalStringForKey(KeyTitle), backText: backText, actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
}
public convenience init(frontText: String?, actionText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
self.init(frontText: frontText, actionText: actionText, backText: backText, actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: nil)
}
public convenience init(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
self.init(frontText: actionMap?.optionalStringForKey(KeyTitlePrefix), actionText: actionMap?.optionalStringForKey(KeyTitle), backText: actionMap?.optionalStringForKey(KeyTitlePostfix), actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate)
}
public convenience init(frontText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
self.init(frontText: frontText, actionText: actionMap?.optionalStringForKey(KeyTitle), backText: backText, actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate)
setFrontText(frontText, actionText: actionText, actionMap: actionMap, backText: backText, additionalData: additionalData, delegateObject: delegateObject)
}
// Convenience Initializer which assumes that the clickable text will be embedded in curly braces {}.
public convenience init(clickableTextEmbeddedInCurlyBraces fullText: String?, actionMapForClickableText actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
self.init(text: fullText, startTag: "{", endTag: "}", actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate)
public convenience init(clickableTextEmbeddedInCurlyBraces fullText: String?, actionMapForClickableText actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
self.init(text: fullText,
startTag: "{",
endTag: "}",
actionMap: actionMap,
additionalData: additionalData,
delegateObject: delegateObject)
}
public init(text fullText: String?, startTag: String?, endTag: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
public init(text fullText: String?, startTag: String?, endTag: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
super.init(frame: CGRect.zero)
setText(fullText, startTag: startTag, endTag: endTag)
weak var weakDelegate: ActionObjectDelegate? = delegate
actionBlock = {
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: weakDelegate as? CoreObjectActionLoadPresentDelegate)
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
}
}
@ -167,7 +176,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
private func setup() {
if self.label == nil {
let label = MFLabel(frame: CGRect.zero)
let label = Label(frame: CGRect.zero)
backgroundColor = .clear
label.isUserInteractionEnabled = false
@ -186,13 +195,11 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
self.label?.attributedText = attributedText
self.label?.accessibilityTraits = .button
}
private func
setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
@objc public func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
weak var weakSelf: LabelWithInternalButton? = self
weak var weakDelegate: ActionObjectDelegate? = delegate
weak var weakButtonDelegate: ButtonObjectDelegate? = buttonDelegate
weak var weakButtonDelegate: ButtonDelegateProtocol? = (delegateObject as? MVMCoreUIDelegateObject)?.buttonDelegate
actionBlock = {
var performAction = true
@ -201,8 +208,8 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
performAction = wButtonDelegate.button?(wSelf, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? false
}
if let wDelegate = weakDelegate as? CoreObjectActionLoadPresentDelegate, performAction {
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: wDelegate)
if performAction {
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
}
}
}
@ -211,26 +218,22 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
// MARK: - Methods
//------------------------------------------------------
@objc public func setFrontText(_ frontText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
setFrontText(frontText, actionText: actionMap?.optionalStringForKey(KeyTitle), actionMap: actionMap, backText: backText, additionalData: additionalData, delegate: delegate, buttonDelegate: buttonDelegate)
}
@objc public func setFrontText(_ frontText: String?, actionText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
@objc public func setFrontText(_ frontText: String?, actionText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
self.frontText = frontText
setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
setActionMap(actionMap, additionalData: additionalData, delegateObject: delegateObject)
self.actionText = actionText
self.backText = backText
text = getTextFromStringComponents()
setup()
}
@objc public func setFrontAttributedText(_ frontAttributedText: NSAttributedString?, actionMap: [AnyHashable: Any]?, backAttributedText backText: NSAttributedString?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
@objc public func setFrontText(_ frontText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
setFrontAttributedText(frontAttributedText, actionMap: actionMap, backAttributedText: backText, addNewLine: false, additionalData: additionalData, delegate: delegate, buttonDelegate: buttonDelegate)
setFrontText(frontText, actionText: actionMap?.optionalStringForKey(KeyTitle), actionMap: actionMap, backText: backText, additionalData: additionalData, delegateObject: delegateObject)
}
private func setFrontAttributedText(_ frontAttributedText: NSAttributedString?, actionMap: [AnyHashable: Any]?, backAttributedText: NSAttributedString?, addNewLine: Bool, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
@objc public func setFrontAttributedText(_ frontAttributedText: NSAttributedString?, actionMap: [AnyHashable: Any]?, backAttributedText: NSAttributedString?, addNewLine: Bool, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
let mutableAttributedString = NSMutableAttributedString()
@ -248,7 +251,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
let actionStringOnLine = actionString + (addNewLine ? "\n" : " ")
actionText = actionStringOnLine
setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
setActionMap(actionMap, additionalData: additionalData, delegateObject: delegateObject)
mutableAttributedString.append(MFStyler.styleGetAttributedString(actionStringOnLine, font: b2Font, color: .black))
} else {
@ -297,7 +300,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
let location: CGPoint? = touches?.first?.location(in: label)
let actionString = actionText
let index: Int = getActionRange().location
let index: Int = actionRange.location
let rangeArray = getRangeArrayOfWords(in: actionString, withInitalIndex: index)
let rectArray = getRectArray(fromRangeArray: rangeArray)
var result = false
@ -335,11 +338,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
return "\(frontText ?? "")\(actionText ?? "")\(backText ?? "")"
}
private func getActionRange() -> NSRange {
return NSRange(location: frontText?.count ?? 0, length: actionText?.count ?? 0)
}
private func getRangeArrayOfWords(in string: String?, withInitalIndex index: Int) -> [Any]? {
var index = index
@ -383,22 +381,29 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
let actionableTuple: ActionableStringTuple = rangeOfText(text, startTag: startTag, endTag: endTag)
if let front = actionableTuple.front, let middle = actionableTuple.middle, let end = actionableTuple.end {
if let text = text,
let leftTag = startTag,
text.contains(leftTag),
let rightTag = endTag,
text.contains(rightTag),
let front = actionableTuple.front,
let middle = actionableTuple.action,
let end = actionableTuple.end {
frontText = front.trimmingCharacters(in: .whitespaces)
actionText = middle.trimmingCharacters(in: .whitespaces)
backText = end.trimmingCharacters(in: .whitespaces)
self.text = getTextFromStringComponents()
} else {
frontText = text
self.text = text
}
self.text = getTextFromStringComponents()
setup()
}
private func rangeOfText(_ text: String?, startTag: String?, endTag: String?) -> ActionableStringTuple {
var actionableTuple: ActionableStringTuple = (front: nil, middle: nil, end: nil)
var actionableTuple: ActionableStringTuple = (front: nil, action: nil, end: nil)
guard let text = text else { return actionableTuple }
@ -409,46 +414,31 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
if let rightTag = endTag, text.contains(rightTag) {
let secondHalf = firstHalf[1].components(separatedBy: rightTag)
actionableTuple.middle = secondHalf[0]
actionableTuple.action = secondHalf[0]
actionableTuple.end = secondHalf[1]
}
}
return actionableTuple
}
@objc public func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: nil)
}
// Reset the text and action map
@objc public func setTextWithClickableTextEmbeddedInCurlyBraces(_ text: String?, textAttributes attributes: [AnyHashable: Any]?, actionMapForClickableText actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
@objc public func setTextWithClickableTextEmbeddedInCurlyBraces(_ text: String?, textAttributes attributes: [AnyHashable: Any]?, actionMapForClickableText actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
attributedText = NSAttributedString(string: text ?? "", attributes: attributes as? [NSAttributedString.Key: Any])
setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate)
setActionMap(actionMap, additionalData: additionalData, delegateObject: delegateObject)
}
@objc public func setWithText(_ fullText: String?, startTag: String?, endTag: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
@objc public func setWithText(_ fullText: String?, startTag: String?, endTag: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
setText(fullText, startTag: startTag, endTag: endTag)
setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate)
}
@objc public func setFrontText(_ frontText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?) {
setFrontText(frontText, actionMap: actionMap, backText: backText, additionalData: additionalData, delegate: delegate, buttonDelegate: nil)
setActionMap(actionMap, additionalData: additionalData, delegateObject: delegateObject)
}
// Reset the front text, back text, action map
@objc public func setFrontAttributedText(_ frontAttributedText: NSAttributedString?, actionMap: [AnyHashable: Any]?, backAttributedText: NSAttributedString?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?) {
@objc public func setFrontAttributedText(_ frontAttributedText: NSAttributedString?, actionMap: [AnyHashable: Any]?, backAttributedText: NSAttributedString?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
setFrontAttributedText(frontAttributedText, actionMap: actionMap, backAttributedText: backAttributedText, addNewLine: false, additionalData: additionalData, delegate: delegate)
}
@objc public func setFrontAttributedText(_ frontAttributedText: NSAttributedString?, actionMap: [AnyHashable: Any]?, backAttributedText: NSAttributedString?, addNewLine: Bool, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?) {
setFrontAttributedText(frontAttributedText, actionMap: actionMap, backAttributedText: backAttributedText, addNewLine: addNewLine, additionalData: additionalData, delegate: delegate, buttonDelegate: nil)
setFrontAttributedText(frontAttributedText, actionMap: actionMap, backAttributedText: backAttributedText, addNewLine: false, additionalData: additionalData, delegateObject: delegateObject)
}
@objc public func setAlignment(_ textAlignment: NSTextAlignment) {
@ -462,7 +452,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
let attributedString = NSMutableAttributedString(attributedString: thisAttributedText)
if !attributedString.string.isEmpty {
attributedString.addAttributes(theseAttributes, range: getActionRange())
attributedString.addAttributes(theseAttributes, range: actionRange)
}
attributedText = attributedString
}
@ -500,16 +490,14 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
}
/// Used to just reset the texts and actions if already initialized
@objc public func reset(withActionMap actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?) {
@objc public func reset(withActionMap actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
frontText = actionMap?.optionalStringForKey(KeyTitlePrefix)
actionText = actionMap?.optionalStringForKey(KeyTitle)
backText = actionMap?.optionalStringForKey(KeyTitlePostfix)
weak var weakDelegate: ActionObjectDelegate? = delegate
actionBlock = {
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: weakDelegate as? CoreObjectActionLoadPresentDelegate)
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
}
text = getTextFromStringComponents()
@ -544,13 +532,203 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
return UIAccessibilityCustomAction()
}
}
extension LabelWithInternalButton: MVMCoreUIMoleculeViewProtocol {
//------------------------------------------------------
// MARK: - Atomization
// MARK: - Legacy for Delegate Change
//------------------------------------------------------
@available(*, deprecated)
public init(frontText: String?, actionText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
super.init(frame: CGRect.zero)
setFrontText(frontText, actionText: actionText, actionMap: actionMap, backText: backText, additionalData: additionalData, delegate: delegate, buttonDelegate: buttonDelegate)
}
@available(*, deprecated)
public convenience init(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
self.init(frontText: actionMap?.optionalStringForKey(KeyTitlePrefix), actionText: actionMap?.optionalStringForKey(KeyTitle), backText: actionMap?.optionalStringForKey(KeyTitlePostfix), actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
}
@available(*, deprecated)
public convenience init(frontText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
self.init(frontText: frontText, actionText: actionMap?.optionalStringForKey(KeyTitle), backText: backText, actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
}
@available(*, deprecated)
public convenience init(frontText: String?, actionText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
self.init(frontText: frontText, actionText: actionText, backText: backText, actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: nil)
}
@available(*, deprecated)
public convenience init(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
self.init(frontText: actionMap?.optionalStringForKey(KeyTitlePrefix), actionText: actionMap?.optionalStringForKey(KeyTitle), backText: actionMap?.optionalStringForKey(KeyTitlePostfix), actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate)
}
@available(*, deprecated)
public convenience init(frontText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
self.init(frontText: frontText, actionText: actionMap?.optionalStringForKey(KeyTitle), backText: backText, actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate)
}
// Convenience Initializer which assumes that the clickable text will be embedded in curly braces {}.
@available(*, deprecated)
public convenience init(clickableTextEmbeddedInCurlyBraces fullText: String?, actionMapForClickableText actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
self.init(text: fullText, startTag: "{", endTag: "}", actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate)
}
@available(*, deprecated)
public init(text fullText: String?, startTag: String?, endTag: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
super.init(frame: CGRect.zero)
setText(fullText, startTag: startTag, endTag: endTag)
weak var weakDelegate: ActionObjectDelegate? = delegate
actionBlock = {
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: weakDelegate as? CoreObjectActionLoadPresentDelegate)
}
}
@available(*, deprecated)
private func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
weak var weakSelf: LabelWithInternalButton? = self
weak var weakDelegate: ActionObjectDelegate? = delegate
weak var weakButtonDelegate: ButtonObjectDelegate? = buttonDelegate
actionBlock = {
var performAction = true
if let wSelf = weakSelf, let wButtonDelegate = weakButtonDelegate, wButtonDelegate.responds(to: #selector(ButtonObjectDelegate.button(_:shouldPerformActionWithMap:additionalData:))) {
performAction = wButtonDelegate.button?(wSelf, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? false
}
if performAction {
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: weakDelegate as? CoreObjectActionLoadPresentDelegate)
}
}
}
@available(*, deprecated)
@objc public func setFrontText(_ frontText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
setFrontText(frontText, actionText: actionMap?.optionalStringForKey(KeyTitle), actionMap: actionMap, backText: backText, additionalData: additionalData, delegate: delegate, buttonDelegate: buttonDelegate)
}
@available(*, deprecated)
@objc public func setFrontText(_ frontText: String?, actionText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
self.frontText = frontText
setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
self.actionText = actionText
self.backText = backText
text = getTextFromStringComponents()
setup()
}
@available(*, deprecated)
@objc public func setFrontAttributedText(_ frontAttributedText: NSAttributedString?, actionMap: [AnyHashable: Any]?, backAttributedText backText: NSAttributedString?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
setFrontAttributedText(frontAttributedText, actionMap: actionMap, backAttributedText: backText, addNewLine: false, additionalData: additionalData, delegate: delegate, buttonDelegate: buttonDelegate)
}
@available(*, deprecated)
private func setFrontAttributedText(_ frontAttributedText: NSAttributedString?, actionMap: [AnyHashable: Any]?, backAttributedText: NSAttributedString?, addNewLine: Bool, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
let mutableAttributedString = NSMutableAttributedString()
if let frontAttributedText = frontAttributedText {
mutableAttributedString.append(frontAttributedText)
// Need to do this to fix the range issue
frontText = frontAttributedText.string
}
if let b2Font = MFStyler.fontB2(),
let actions = actionMap,
actions.keys.count > 0,
let actionString = actions.optionalStringForKey(KeyTitle),
!actionString.isEmpty {
let actionStringOnLine = actionString + (addNewLine ? "\n" : " ")
actionText = actionStringOnLine
setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
mutableAttributedString.append(MFStyler.styleGetAttributedString(actionStringOnLine, font: b2Font, color: .black))
} else {
actionText = nil
actionBlock = nil
}
if let backAttributedText = backAttributedText {
mutableAttributedString.append(backAttributedText)
}
attributedText = mutableAttributedString
// Added this line for underlining
setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)])
}
@available(*, deprecated)
@objc public func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: nil)
}
// Reset the text and action map
@available(*, deprecated)
@objc public func setTextWithClickableTextEmbeddedInCurlyBraces(_ text: String?, textAttributes attributes: [AnyHashable: Any]?, actionMapForClickableText actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
attributedText = NSAttributedString(string: text ?? "", attributes: attributes as? [NSAttributedString.Key: Any])
setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate)
}
@available(*, deprecated)
@objc public func setWithText(_ fullText: String?, startTag: String?, endTag: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) {
setText(fullText, startTag: startTag, endTag: endTag)
setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate)
}
@available(*, deprecated)
@objc public func setFrontText(_ frontText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?) {
setFrontText(frontText, actionMap: actionMap, backText: backText, additionalData: additionalData, delegate: delegate, buttonDelegate: nil)
}
// Reset the front text, back text, action map
@available(*, deprecated)
@objc public func setFrontAttributedText(_ frontAttributedText: NSAttributedString?, actionMap: [AnyHashable: Any]?, backAttributedText: NSAttributedString?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?) {
setFrontAttributedText(frontAttributedText, actionMap: actionMap, backAttributedText: backAttributedText, addNewLine: false, additionalData: additionalData, delegate: delegate)
}
@available(*, deprecated)
@objc public func setFrontAttributedText(_ frontAttributedText: NSAttributedString?, actionMap: [AnyHashable: Any]?, backAttributedText: NSAttributedString?, addNewLine: Bool, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?) {
setFrontAttributedText(frontAttributedText, actionMap: actionMap, backAttributedText: backAttributedText, addNewLine: addNewLine, additionalData: additionalData, delegate: delegate, buttonDelegate: nil)
}
/// Used to just reset the texts and actions if already initialized
@available(*, deprecated)
@objc public func reset(withActionMap actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?) {
frontText = actionMap?.optionalStringForKey(KeyTitlePrefix)
actionText = actionMap?.optionalStringForKey(KeyTitle)
backText = actionMap?.optionalStringForKey(KeyTitlePostfix)
weak var weakDelegate: ActionObjectDelegate? = delegate
actionBlock = {
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: weakDelegate as? CoreObjectActionLoadPresentDelegate)
}
text = getTextFromStringComponents()
setup()
}
}
// MARK: - Atomization
extension LabelWithInternalButton: MVMCoreUIMoleculeViewProtocol {
// Default values for view.
@objc open func setAsMolecule() {

View File

@ -1,64 +0,0 @@
//
// MFLabel.h
// mobilefirst
//
// Created by Scott Pfeil on 3/22/17.
// Copyright © 2017 Verizon Wireless. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <MVMCoreUI/MFView.h>
@class MFSizeObject;
@class DelegateObject;
@interface MFLabel : UILabel <MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol>
- (nullable instancetype)initWithStandardFontSize:(CGFloat)size;
// Set this property if you want updateView to update the font based on this standard and the size passed in.
@property (nonatomic) CGFloat standardFontSize;
// Set this to use a custom sizing object during updateView instead of the standard.
@property (nonatomic, strong, nullable) MFSizeObject *sizeObject;
// Set the font and set to scale
- (void)setFont:(nonnull UIFont *)font scale:(BOOL)scale;
// Convenience checker for text or attributed text.
- (BOOL)hasText;
#pragma mark - 2.0
//75Bd 40pt
+ (nonnull MFLabel *)commonLabelH1:(BOOL)scale;
//75Bd 25pt
+ (nonnull MFLabel *)commonLabelH2:(BOOL)scale;
//75Bd 18pt
+ (nonnull MFLabel *)commonLabelH3:(BOOL)scale;
//75Bd 32pt
+ (nonnull MFLabel *)commonLabelH32:(BOOL)scale;
//75Bd 13pt
+ (nonnull MFLabel *)commonLabelB1:(BOOL)scale;
//55Rg 13pt
+ (nonnull MFLabel *)commonLabelB2:(BOOL)scale;
//55Rg 11pt gray
+ (nonnull MFLabel *)commonLabelB3:(BOOL)scale;
//55Rg 20pt
+ (nonnull MFLabel *)commonLabelB20:(BOOL)scale;
// Getters
+ (nonnull MFLabel *)label NS_SWIFT_NAME(commonLabel());
// Setters
+ (void)setLabel:(nullable UILabel *)label withHTML:(nullable NSString *)html;
+ (void)setUILabel:(nullable UILabel *)label withJSON:(nullable NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData;
- (void)styleH1:(BOOL)scale;
- (void)styleH2:(BOOL)scale;
- (void)styleH3:(BOOL)scale;
- (void)styleH32:(BOOL)scale;
- (void)styleB1:(BOOL)scale;
- (void)styleB2:(BOOL)scale;
- (void)styleB3:(BOOL)scale;
- (void)styleB20:(BOOL)scale;
@end

View File

@ -1,291 +0,0 @@
//
// MFLabel.m
// mobilefirst
//
// Created by Scott Pfeil on 3/22/17.
// Copyright © 2017 Verizon Wireless. All rights reserved.
//
#import "MFLabel.h"
#import <MVMCoreUI/MFStyler.h>
#import <MVMCoreUI/MFSizeObject.h>
#import <MVMCoreUI/MVMCoreUIConstants.h>
#import "UIColor+MFConvenience.h"
#import "MFFonts.h"
#import "MVMCoreUISplitViewController.h"
#import "MVMCoreUILoggingHandler.h"
@import MVMCore.MVMCoreGetterUtility;
@import MVMCore.NSDictionary_MFConvenience;
@import MVMCore.MVMCoreJSONConstants;
@interface MFLabel ()
@property (strong, nonatomic) NSNumber *scaleSize;
// Used for scaling the font in updateView.
@property (strong, nonatomic) NSAttributedString *originalAttributedString;
@end
@implementation MFLabel
- (void)setupView {
self.backgroundColor = [UIColor clearColor];
self.numberOfLines = 0;
self.lineBreakMode = NSLineBreakByWordWrapping;
self.translatesAutoresizingMaskIntoConstraints = NO;
}
- (instancetype)init {
if (self = [super init]) {
[self setupView];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if (self) {
[self setupView];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setupView];
}
return self;
}
- (instancetype)initWithStandardFontSize:(CGFloat)size {
if ([self init]) {
self.standardFontSize = size;
}
return self;
}
- (void)updateView:(CGFloat)size {
self.scaleSize = @(size);
if (self.originalAttributedString) {
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.originalAttributedString];
[attributedString removeAttribute:NSFontAttributeName range:NSMakeRange(0, attributedString.length)];
[self.originalAttributedString enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, self.originalAttributedString.length) options:0 usingBlock:^(UIFont *value, NSRange range, BOOL * _Nonnull stop) {
// Loop the original attributed string, resize the fonts.
UIFont *font = [value fontWithSize:[[MFStyler sizeObjectGenericForCurrentDevice:value.pointSize] getValueBasedOnSize:size]];
[attributedString addAttribute:NSFontAttributeName value:font range:range];
}];
self.attributedText = attributedString;
} else if (!fequal(self.standardFontSize, 0)) {
MFSizeObject *sizeObject = self.sizeObject;
if (!sizeObject) {
sizeObject = [MFStyler sizeObjectGenericForCurrentDevice:self.standardFontSize];
}
self.font = [self.font fontWithSize:[sizeObject getValueBasedOnSize:size]];
}
}
- (void)setFont:(nonnull UIFont *)font scale:(BOOL)scale {
self.font = font;
[self setScale:scale];
}
- (void)setScale:(BOOL)scale {
if (scale) {
self.standardFontSize = self.font.pointSize;
[self updateView:(self.scaleSize ? self.scaleSize.floatValue : [MVMCoreUISplitViewController getApplicationViewWidth])];
} else {
self.standardFontSize = 0;
}
}
- (BOOL)hasText {
return self.text.length > 0 || self.attributedText.length > 0;
}
#pragma mark - 2.0
+ (nonnull MFLabel *)commonLabelH1:(BOOL)scale {
MFLabel *label = [MFLabel label];
[label styleH1:scale];
return label;
}
+ (nonnull MFLabel *)commonLabelH2:(BOOL)scale {
MFLabel *label = [MFLabel label];
[label styleH2:scale];
return label;
}
+ (nonnull MFLabel *)commonLabelH3:(BOOL)scale {
MFLabel *label = [MFLabel label];
[label styleH3:scale];
return label;
}
+ (nonnull MFLabel *)commonLabelH32:(BOOL)scale {
MFLabel *label = [MFLabel label];
[label styleH32:scale];
return label;
}
+ (nonnull MFLabel *)commonLabelB1:(BOOL)scale {
MFLabel *label = [MFLabel label];
[label styleB1:scale];
return label;
}
+ (nonnull MFLabel *)commonLabelB2:(BOOL)scale {
MFLabel *label = [MFLabel label];
[label styleB2:scale];
return label;
}
+ (nonnull MFLabel *)commonLabelB3:(BOOL)scale {
MFLabel *label = [MFLabel label];
[label styleB3:scale];
return label;
}
+ (nonnull MFLabel *)commonLabelB20:(BOOL)scale {
MFLabel *label = [MFLabel label];
[label styleB20:scale];
return label;
}
+ (nonnull MFLabel *)label {
return [[MFLabel alloc] initWithFrame:CGRectZero];
}
#pragma mark - Setters
+ (void)setLabel:(nullable UILabel *)label withHTML:(nullable NSString *)html {
NSData *data = [html dataUsingEncoding:kCFStringEncodingUTF8];
if (data) {
NSError *error = nil;
label.attributedText = [[NSAttributedString alloc] initWithData:data options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType} documentAttributes:nil error:&error];
if (error) {
[[MVMCoreUILoggingHandler sharedLoggingHandler] addErrorToLog:[MVMCoreErrorObject createErrorObjectForNSError:error location:@"LabelHTMLParse"]];
}
}
}
+ (void)setUILabel:(nullable UILabel *)label withJSON:(nullable NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData {
if (label) {
label.text = [json string:KeyText];
[self setLabel:label withHTML:[json string:@"html"]];
NSString *textColor = [json string:KeyTextColor];
if (textColor) {
label.textColor = [UIColor mfGetColorForHex:textColor];
}
NSString *backgroundColor = [json string:KeyBackgroundColor];
if (backgroundColor) {
label.backgroundColor = [UIColor mfGetColorForHex:backgroundColor];
}
NSString *accessibilityText = [json string:@"accessibilityText"];
if (accessibilityText) {
label.accessibilityLabel = accessibilityText;
}
NSString *fontName = [json string:@"fontName"];
NSNumber *fontSize = [json optionalNumberForKey:@"fontSize"];
if (fontName) {
label.font = [MFFonts mfFontWithName:fontName size:fontSize ? fontSize.doubleValue : label.font.pointSize];
} else if (fontSize) {
label.font = [label.font fontWithSize:fontSize.doubleValue];
}
NSArray *attributes = [json array:@"attributes"];
if (attributes) {
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:label.text attributes:@{NSFontAttributeName:label.font,NSForegroundColorAttributeName:label.textColor}];
for (NSDictionary *attribute in attributes) {
NSNumber *location = [attribute optionalNumberForKey:@"location"];
NSNumber *length = [attribute optionalNumberForKey:@"length"];
if (location && length) {
NSRange range = NSMakeRange(location.unsignedIntegerValue, length.unsignedIntegerValue);
NSString *type = [attribute string:KeyType];
if ([type isEqualToString:@"underline"]) {
[attributedString addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:range];
} else if ([type isEqualToString:@"strikethrough"]) {
[attributedString addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlineStyleThick) range:range];
} else if ([type isEqualToString:@"color"]) {
NSString *color = [attribute string:KeyTextColor];
if (color) {
[attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor mfGetColorForHex:color] range:range];
}
} else if ([type isEqualToString:@"font"]) {
NSString *fontName = [attribute string:@"name"];
NSNumber *fontSize = [attribute optionalNumberForKey:@"size"];
UIFont *font = nil;
if (fontName) {
font = [MFFonts mfFontWithName:fontName size:fontSize ? fontSize.doubleValue : label.font.pointSize];
} else if (fontSize) {
font = [label.font fontWithSize:fontSize.doubleValue];
}
if (font) {
[attributedString addAttribute:NSFontAttributeName value:font range:range];
}
}
}
}
label.attributedText = attributedString;
}
}
}
- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
[MFLabel setUILabel:self withJSON:json delegateObject:delegateObject additionalData:additionalData];
self.originalAttributedString = self.attributedText;
}
- (void)styleH1:(BOOL)scale {
[MFStyler styleLabelH1:self genericScaling:NO];
[self setScale:scale];
}
- (void)styleH2:(BOOL)scale {
[MFStyler styleLabelH2:self genericScaling:NO];
[self setScale:scale];
}
- (void)styleH3:(BOOL)scale {
[MFStyler styleLabelH3:self genericScaling:NO];
[self setScale:scale];
}
- (void)styleH32:(BOOL)scale {
[MFStyler styleLabelH32:self genericScaling:NO];
[self setScale:scale];
}
- (void)styleB1:(BOOL)scale {
[MFStyler styleLabelB1:self genericScaling:NO];
[self setScale:scale];
}
- (void)styleB2:(BOOL)scale {
[MFStyler styleLabelB2:self genericScaling:NO];
[self setScale:scale];
}
- (void)styleB3:(BOOL)scale {
[MFStyler styleLabelB3:self genericScaling:NO];
[self setScale:scale];
}
- (void)styleB20:(BOOL)scale {
[MFStyler styleLabelB20:self genericScaling:NO];
[self setScale:scale];
}
- (void)setAccessibilityTraits:(UIAccessibilityTraits)accessibilityTraits {
if (accessibilityTraits& UIAccessibilityTraitHeader) {
UIAccessibilityTraits noHeaderTraits = accessibilityTraits - UIAccessibilityTraitHeader;
[super setAccessibilityTraits:noHeaderTraits];
} else {
[super setAccessibilityTraits:accessibilityTraits];
}
}
@end

View File

@ -243,7 +243,7 @@ import UIKit
// Gifs aren't supported by default and need special handling
MVMCoreCache.shared()?.getGif(imageName, useWidth: width != nil, widthForS7: width?.intValue ?? 0, useHeight: height != nil, heightForS7: height?.intValue ?? 0, format: format, localFallbackImageName: fallbackImageName, completionHandler: finishedLoadingBlock)
} else {
MVMCoreCache.shared()?.getImage(imageName, useWidth: width != nil, widthForS7: width?.intValue ?? 0, useHeight: height != nil, heightForS7: height?.intValue ?? 0, localFallbackImageName: fallbackImageName, completionHandler: finishedLoadingBlock)
MVMCoreCache.shared()?.getImage(imageName, useWidth: width != nil, widthForS7: width?.intValue ?? 0, useHeight: height != nil, heightForS7: height?.intValue ?? 0, format: format, localFallbackImageName: fallbackImageName, completionHandler: finishedLoadingBlock)
}
})
}

View File

@ -36,7 +36,7 @@
}
- (void)setupView {
self.preservesSuperviewLayoutMargins = YES;
}
- (void)updateView:(CGFloat)size {

View File

@ -9,7 +9,7 @@
#import <UIKit/UIKit.h>
#import <MVMCoreUI/MFView.h>
#import <MVMCoreUI/MVMCoreUICheckMarkView.h>
#import <MVMCoreUI/MFLabel.h>
@class Label;
@class MFSizeObject;
@interface MVMCoreUICheckBox : UIControl <MVMCoreViewProtocol>
@ -23,7 +23,7 @@
@property (nullable, strong, nonatomic) UIColor *unCheckedColor;
// Label to the right of the check box.
@property (nullable, weak, nonatomic) MFLabel *descriptionLabel;
@property (nullable, weak, nonatomic) Label *descriptionLabel;
// Setter for the descriptionLabel.text. Also sets the accessibility text.
@property (nullable, strong, nonatomic) NSString *descriptionText;

View File

@ -16,10 +16,12 @@
#import "UIColor+MFConvenience.h"
#import "MVMCoreUIUtility.h"
#import "MFStyler.h"
#import <MVMCoreUI/MVMCoreUI-Swift.h>
static const CGFloat FaultTolerance = 20.f;
static const CGFloat CheckBoxHeightWidth = 18.0;
@interface MVMCoreUICheckBox ()
@interface MVMCoreUICheckBox () <FormValidationProtocol, MVMCoreUIMoleculeViewProtocol>
@property (nonatomic, readwrite) BOOL isSelected;
@property (weak, nonatomic) UIView *checkedSquare;
@ -38,10 +40,45 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
@property (nullable, strong, nonatomic) NSLayoutConstraint *checkboxWidth;
@property (nullable, strong, nonatomic) NSLayoutConstraint *checkboxHeight;
@property (nonatomic) BOOL isRequired;
@property (nullable, strong, nonatomic) NSString *fieldKey;
@property (nullable, strong, nonatomic) DelegateObject *delegate;
@end
@implementation MVMCoreUICheckBox
#pragma mark - MVMCoreUIMoleculeViewProtocol
- (BOOL)needsToBeConstrained {
return YES;
}
- (UIStackViewAlignment)moleculeAlignment {
return UIStackViewAlignmentLeading;
}
- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
[FormValidator setupValidationWithMolecule:self delegate:((MVMCoreUIDelegateObject *)delegateObject).formValidationProtocol];
self.delegate = delegateObject;
self.fieldKey = [json stringForKey:KeyFieldKey];
self.isRequired = [json boolForKey:KeyRequired];
NSString *checkedColorHex = [json string:@"checkedColor"];
NSString *unCheckedColorHex = [json string:@"unCheckedColor"];
UIColor *checkedColor = checkedColorHex ? [UIColor mfGetColorForHex:checkedColorHex]: [UIColor clearColor];
UIColor *unCheckedColor = unCheckedColorHex ? [UIColor mfGetColorForHex:unCheckedColorHex]: [UIColor clearColor];
[self setupWithCheckedColor:checkedColor
unCheckColor:unCheckedColor
label:[json dict:KeyLabel]
delegateObject:delegateObject
additionalData: additionalData];
}
#pragma mark - convenient class methods
+ (instancetype)mfCheckBox {
@ -68,8 +105,33 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
return checkBox;
}
#pragma mark - FormValidationProtocol
- (BOOL)isValidField {
if (self.isRequired) {
return self.isSelected;
}
return true;
}
- (nullable NSString *)formFieldName {
return self.fieldKey;
}
- (nullable id)formFieldValue {
return @(self.isSelected);
}
#pragma mark - inits
- (instancetype)init {
self = [super init];
if (self) {
[self setupView];
}
return self;
}
- (instancetype)initWithCheckedColor:(UIColor *)checkedColor unCheckColor:(UIColor *)unCheckedColor text:(NSString *)text {
if (self = [super init]) {
[self setupWithCheckedColor:checkedColor unCheckColor:unCheckedColor text:text];
@ -121,6 +183,7 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
- (instancetype)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if (self) {
[self setupView];
[self setupWithCheckedColor:[UIColor whiteColor] unCheckColor:[UIColor whiteColor] text:nil];
[self addAccessibleProperties];
}
@ -130,6 +193,7 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setupView];
[self setupWithCheckedColor:[UIColor whiteColor] unCheckColor:[UIColor whiteColor] text:nil];
[self addAccessibleProperties];
}
@ -179,14 +243,12 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
[self.checkMark.widthAnchor constraintEqualToAnchor:self.checkedSquare.widthAnchor multiplier:.4].active = YES;
[self.checkMark.heightAnchor constraintEqualToAnchor:self.checkedSquare.heightAnchor multiplier:.4].active = YES;
[self.checkMark.centerXAnchor constraintEqualToAnchor:self.checkedSquare.centerXAnchor].active = YES;
[self.checkMark.centerYAnchor constraintEqualToAnchor:self.checkedSquare.centerYAnchor].active = YES;
} else {
[self.checkedSquare addSubview:self.checkMark];
[self.checkMark.centerYAnchor constraintEqualToAnchor:self.checkedSquare.centerYAnchor].active = YES;
}
//label
if (!self.descriptionLabel) {
MFLabel *descriptionLabel = [MFLabel commonLabelB2:YES];
Label *descriptionLabel = [Label commonLabelB2:YES];
[containterView addSubview:descriptionLabel];
[NSLayoutConstraint constraintPinSubview:descriptionLabel pinCenterX:NO pinCenterY:YES];
[NSLayoutConstraint constraintPinSubview:descriptionLabel pinTop:NO pinBottom:NO pinLeft:NO pinRight:YES];
@ -206,17 +268,25 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
}
}
- (void)setupWithCheckedColor:(UIColor *)checkedColor unCheckColor:(UIColor *)unCheckedColor {
if (checkedColor) {
self.checkedColor = checkedColor;
}
if (unCheckedColor) {
self.unCheckedColor = unCheckedColor;
}
}
- (void)setupWithCheckedColor:(UIColor *)checkedColor unCheckColor:(UIColor *)unCheckedColor text:(NSString *)text {
[self setupView];
if (checkedColor) {
self.checkedColor = checkedColor;
}
if (unCheckedColor) {
self.unCheckedColor = unCheckedColor;
}
[self setupWithCheckedColor:checkedColor unCheckColor:unCheckedColor];
[self setDescriptionText:text];
}
- (void)setupWithCheckedColor:(UIColor *)checkedColor unCheckColor:(UIColor *)unCheckedColor label:(NSDictionary *)labelJson delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
[self setupWithCheckedColor:checkedColor unCheckColor:unCheckedColor];
[self.descriptionLabel setWithJSON:labelJson delegateObject:delegateObject additionalData:additionalData];
}
- (void)updateView:(CGFloat)size {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
[self.descriptionLabel updateView:size];
@ -253,7 +323,7 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
[self setSelected:selected animated:animated runBlock:YES];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated runBlock:(BOOL)runBlock{
- (void)setSelected:(BOOL)selected animated:(BOOL)animated runBlock:(BOOL)runBlock {
[self addAccessibilityLabel:selected];
self.isSelected = selected;
@ -271,6 +341,9 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
} completion:nil];
[self.checkMark updateCheckSelected:NO animated:animated];
}
FormValidator *formValidator = ((MVMCoreUIDelegateObject *)self.delegate).formValidationProtocol.formValidatorModel;
[formValidator enableByValidation];
}
- (void)setColor:(nullable UIColor *)color forState:(UIControlState)state {

View File

@ -26,6 +26,9 @@
// Returns a view with the provided view as a subview, pinned.
+ (nonnull ViewConstrainingView *)viewConstrainingView:(nonnull UIView *)view;
// Can be initialized with a molecule to constrain
- (nullable instancetype)initWithMolecule:(nonnull UIView <MVMCoreUIMoleculeViewProtocol>*)molecule alignment:(UIStackViewAlignment)alignment;
// Use these to sets the constants, because subclasses may align differently.
- (void)setPinConstantsWithInsets:(UIEdgeInsets)insets;
- (void)setTopPinConstant:(CGFloat)top left:(CGFloat)left bottom:(CGFloat)bottom right:(CGFloat)right;
@ -47,4 +50,7 @@
// For setting up the view.
- (void)setupView;
// Add a view to be constrained in this view.
- (void)addConstrainedView:(nonnull UIView *)view;
@end

View File

@ -9,69 +9,50 @@
#import "ViewConstrainingView.h"
@import MVMCore.MVMCoreConstants;
@import MVMCore.MVMCoreDispatchUtility;
#import "NSLayoutConstraint+MFConvenience.h"
#import "MFStyler.h"
@interface ViewConstrainingView ()
@property (weak, nullable, nonatomic) UIView *constrainedView;
@property (weak, nullable, nonatomic) UIView <MVMCoreUIMoleculeViewProtocol>*molecule;
@end
@implementation ViewConstrainingView
- (nullable instancetype)initWithMolecule:(nonnull UIView <MVMCoreUIMoleculeViewProtocol>*)molecule alignment:(UIStackViewAlignment)alignment {
if (self = [super init]) {
if (!molecule.superview) {
[self addConstrainedView:molecule alignment:alignment];
[self setAsMolecule];
}
self.molecule = molecule;
}
return self;
}
+ (nonnull ViewConstrainingView *)emptyView {
ViewConstrainingView *view = [[ViewConstrainingView alloc] initWithFrame:CGRectZero];
view.translatesAutoresizingMaskIntoConstraints = NO;
view.backgroundColor = [UIColor clearColor];
return view;
}
+ (nonnull ViewConstrainingView *)viewConstrainingView:(UIView *)view {
ViewConstrainingView *constrainingView = [[ViewConstrainingView alloc] initWithFrame:CGRectZero];
constrainingView.translatesAutoresizingMaskIntoConstraints = NO;
constrainingView.backgroundColor = [UIColor clearColor];
view.translatesAutoresizingMaskIntoConstraints = NO;
[constrainingView addSubview:view];
constrainingView.constrainedView = view;
NSLayoutConstraint *leftPin = [view.leftAnchor constraintEqualToAnchor:constrainingView.leftAnchor];
constrainingView.leftPin = leftPin;
leftPin.active = YES;
NSLayoutConstraint *topPin = [view.topAnchor constraintEqualToAnchor:constrainingView.topAnchor];
constrainingView.topPin = topPin;
topPin.active = YES;
NSLayoutConstraint *bottomPin = [constrainingView.bottomAnchor constraintEqualToAnchor:view.bottomAnchor];
constrainingView.bottomPin = bottomPin;
bottomPin.active = YES;
NSLayoutConstraint *rightPin = [constrainingView.rightAnchor constraintEqualToAnchor:view.rightAnchor];
constrainingView.rightPin = rightPin;
rightPin.active = YES;
[constrainingView addConstrainedView:view];
return constrainingView;
}
- (void)pinToSuperView {
// Align left and right constants.
NSLayoutConstraint *leftPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
self.leftPin = leftPin;
leftPin.active = YES;
NSLayoutConstraint *topPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
self.topPin = topPin;
topPin.active = YES;
NSLayoutConstraint *bottomPin = [NSLayoutConstraint constraintWithItem:self.superview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
self.bottomPin = bottomPin;
bottomPin.active = YES;
NSLayoutConstraint *rightPin = [NSLayoutConstraint constraintWithItem:self.superview attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
self.rightPin = rightPin;
rightPin.active = YES;
NSDictionary *dictionary = [NSLayoutConstraint constraintPinSubviewToSuperview:self];
self.leftPin = dictionary[ConstraintLeading];
self.topPin = dictionary[ConstraintTop];
self.bottomPin = dictionary[ConstraintBot];
self.rightPin = dictionary[ConstraintTrailing];
}
- (void)setPinConstantsWithInsets:(UIEdgeInsets)insets {
[self setTopPinConstant:insets.top left:insets.left bottom:insets.bottom right:insets.right];
}
@ -115,6 +96,34 @@
self.backgroundColor = [UIColor clearColor];
}
- (void)addConstrainedView:(nonnull UIView *)view alignment:(UIStackViewAlignment)alignment {
view.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:view];
self.constrainedView = view;
NSLayoutRelation leftRelation;
if (alignment == UIStackViewAlignmentFill || alignment == UIStackViewAlignmentLeading || alignment == UIStackViewAlignmentFirstBaseline) {
leftRelation = NSLayoutRelationEqual;
} else {
leftRelation = NSLayoutRelationGreaterThanOrEqual;
}
NSLayoutRelation rightRelation;
if (alignment == UIStackViewAlignmentFill || alignment == UIStackViewAlignmentTrailing || alignment == UIStackViewAlignmentLastBaseline) {
rightRelation = NSLayoutRelationEqual;
} else {
rightRelation = NSLayoutRelationGreaterThanOrEqual;
}
NSDictionary *dictionary = [NSLayoutConstraint constraintPinSubview:view topRelation:NSLayoutRelationEqual bottomRelation:NSLayoutRelationEqual leftRelation:leftRelation rightRelation:rightRelation];
self.leftPin = dictionary[ConstraintLeading];
self.topPin = dictionary[ConstraintTop];
self.bottomPin = dictionary[ConstraintBot];
self.rightPin = dictionary[ConstraintTrailing];
}
- (void)addConstrainedView:(nonnull UIView *)view {
[self addConstrainedView:view alignment:UIStackViewAlignmentFill];
}
- (void)setupView {
[super setupView];
self.translatesAutoresizingMaskIntoConstraints = NO;
@ -131,6 +140,7 @@
CGFloat padding = [MFStyler defaultHorizontalPaddingForSize:size];
[self setLeftPinConstant:padding];
[self setRightPinConstant:padding];
[MFStyler setDefaultMarginsForView:self size:size];
}];
}
}
@ -138,6 +148,15 @@
#pragma mark - MVMCoreUIMoleculeViewProtocol
- (void)setAsMolecule {
self.updateViewHorizontalDefaults = YES;
}
- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
[super setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
if (self.molecule) {
[self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
self.backgroundColor = self.molecule.backgroundColor;
}
}
@end

View File

@ -530,6 +530,10 @@
} completion:completion];
}
- (BOOL)viewRespectsSystemMinimumLayoutMargins {
return NO;
}
#pragma mark - UITextField Functions
// To Remove TextFields Bug: Keyboard is not dismissing after reaching textfield max length limit

View File

@ -0,0 +1,255 @@
//
// ThreeLayerTableViewController.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 4/18/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
import MVMAnimationFramework
open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
// The three main views
private var topView: UIView?
private var bottomView: UIView?
private var headerView: UIView?
private var footerView: UIView?
private var safeAreaView: UIView?
var useMargins: Bool = true
var bottomViewOutsideOfScrollArea: Bool = false
private var topViewBottomConstraint: NSLayoutConstraint?
private var bottomViewTopConstraint: NSLayoutConstraint?
//MARK: - MVMCoreViewProtocol
open override func updateViews() {
super.updateViews()
let width = view.bounds.width
MFStyler.setDefaultMarginsFor(contentView, size: width)
if let topView = topView as? MVMCoreViewProtocol {
topView.updateView(width)
showHeader()
}
if let bottomView = bottomView as? MVMCoreViewProtocol {
bottomView.updateView(width)
showFooter()
}
self.tableView?.reloadData()
}
//MARK: - MFViewController
open override func newDataBuildScreen() {
super.newDataBuildScreen()
createViewForTableHeader()
createViewForTableFooter()
tableView?.reloadData()
}
override open func viewDidLoad() {
super.viewDidLoad()
setToHaveNoSectionHeadersFooters()
// Do any additional setup after loading the view.
}
//MARK: - Spacing
// If both are subclassed to return a value, then the buttons will not be pinned towards the bottom because neither spacing would try to fill the screen.
/// Space between the top view and the table sections, nil to fill. 0 default
open func spaceBelowTopView() -> CGFloat? {
return 0
}
/// Space between the bottom view and the table sections, nil to fill. nil default
open func spaceAboveBottomView() -> CGFloat? {
return nil
}
/// can override to return a minimum fill space.
open func minimumFillSpace() -> CGFloat {
return 0
}
open override func updateViewConstraints() {
super.updateViewConstraints()
guard let tableView = tableView else {
return
}
let minimumSpace: CGFloat = minimumFillSpace()
var currentSpace: CGFloat = 0
var totalMinimumSpace: CGFloat = 0
var fillTop = false
if spaceBelowTopView() == nil, self.tableView?.tableHeaderView != nil {
fillTop = true
currentSpace += topViewBottomConstraint?.constant ?? 0
totalMinimumSpace += minimumSpace
}
var fillBottom = false
if spaceAboveBottomView() == nil, !bottomViewOutsideOfScrollArea, self.tableView?.tableFooterView != nil {
fillBottom = true
currentSpace += bottomViewTopConstraint?.constant ?? 0
totalMinimumSpace += minimumSpace
}
guard fillTop || fillBottom else {
return
}
let newSpace = MVMCoreUIUtility.getVariableConstraintHeight(currentSpace, in: tableView, minimumHeight: totalMinimumSpace)
// If the bottom view is outside of the scroll, then only the top view constraint is being used, so we have to double it to account for the bottom constraint not being there when we compare to the new value.
var currentSpaceForCompare: CGFloat = currentSpace
if fillTop && bottomViewOutsideOfScrollArea {
currentSpaceForCompare = currentSpace * 2;
}
if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 0.1) {
if fillTop && fillBottom {
// space both
let half = newSpace / 2
topViewBottomConstraint?.constant = half
bottomViewTopConstraint?.constant = half
showHeader()
showFooter()
} else if fillTop {
// Only top is spaced (half the size if the bottom view is out of the scroll because it needs to be sized as if there are two spacers but there is only one.
if bottomViewOutsideOfScrollArea {
topViewBottomConstraint?.constant = newSpace / 2
} else {
topViewBottomConstraint?.constant = newSpace
}
showHeader()
} else if fillBottom {
// Only bottom is spaced.
bottomViewTopConstraint?.constant = newSpace
showFooter()
}
}
}
//MARK: - Header Footer
/// Gets the top view and adds it to a spacing view, headerView, and then calls showHeader.
open func createViewForTableHeader() {
let topView = viewForTop()
self.topView = topView
let headerView = MVMCoreUICommonViewsUtility.commonView()
headerView.addSubview(topView)
topView.topAnchor.constraint(equalTo: headerView.topAnchor).isActive = true
topView.leftAnchor.constraint(equalTo: headerView.leftAnchor).isActive = true
headerView.rightAnchor.constraint(equalTo: topView.rightAnchor).isActive = true
topViewBottomConstraint = headerView.bottomAnchor.constraint(equalTo: topView.bottomAnchor, constant: spaceBelowTopView() ?? 0)
topViewBottomConstraint?.isActive = true
self.headerView = headerView
showHeader()
}
/// Gets the bottom view and adds it to a spacing view, footerView, and then calls showFooter.
open func createViewForTableFooter() {
let bottomView = viewForBottom()
self.bottomView = bottomView
let footerView = MVMCoreUICommonViewsUtility.commonView()
footerView.addSubview(bottomView)
bottomViewTopConstraint = bottomView.topAnchor.constraint(equalTo: footerView.topAnchor, constant: spaceAboveBottomView() ?? 0)
bottomViewTopConstraint?.isActive = true
bottomView.leftAnchor.constraint(equalTo: footerView.leftAnchor).isActive = true
footerView.rightAnchor.constraint(equalTo: bottomView.rightAnchor).isActive = true
footerView.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor).isActive = true
self.footerView = footerView
showFooter()
}
/// Takes the current headerView and adds it to the tableHeaderView
func showHeader() {
headerView?.removeFromSuperview()
tableView?.tableHeaderView = nil
guard let headerView = headerView else {
return
}
// This extra view is needed because of the wonkiness of apple's table header. Things breaks if using autolayout.
MVMCoreUIUtility.sizeView(toFit: headerView)
let tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: MVMCoreUIUtility.getWidth(), height: headerView.frame.height))
tableHeaderView.addSubview(headerView)
NSLayoutConstraint.constraintPinSubview(toSuperview: headerView)
tableView?.tableHeaderView = tableHeaderView
}
/// Takes the current footerView and adds it to the tableFooterView
func showFooter() {
footerView?.removeFromSuperview()
safeAreaView?.removeFromSuperview()
guard let footerView = footerView, let tableView = tableView else {
return
}
if bottomViewOutsideOfScrollArea {
// put bottom view outside of scrolling area.
bottomConstraint?.isActive = false
view.addSubview(footerView)
footerView.topAnchor.constraint(equalTo: tableView.bottomAnchor).isActive = true
footerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
view.rightAnchor.constraint(equalTo: footerView.rightAnchor).isActive = true
if #available(iOS 11.0, *) {
view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: footerView.bottomAnchor).isActive = true
safeAreaView = MVMCoreUICommonViewsUtility.getAndSetupSafeAreaView(on: view)
safeAreaView?.backgroundColor = bottomView?.backgroundColor
} else {
view.bottomAnchor.constraint(equalTo: footerView.bottomAnchor).isActive = true
}
} else {
bottomConstraint?.isActive = true
var y: CGFloat?
if let tableFooterView = tableView.tableFooterView {
// if footer already exists, use the same y location to avoid strange moving animation
y = tableFooterView.frame.minY
}
// This extra view is needed because of the wonkiness of apple's table footer. Things breaks if using autolayout.
MVMCoreUIUtility.sizeView(toFit: footerView)
let tableFooterView = UIView(frame: CGRect(x: 0, y: y ?? 0, width: MVMCoreUIUtility.getWidth(), height: footerView.frame.height))
tableFooterView.addSubview(footerView)
NSLayoutConstraint.constraintPinSubview(toSuperview: footerView)
tableView.tableFooterView = tableFooterView
}
}
//MARK: - Functions to subclass
/// Subclass for a top view.
open func viewForTop() -> UIView {
let view = MVMCoreUICommonViewsUtility.commonView()
view.heightAnchor.constraint(equalToConstant: 0).isActive = true
return view
}
/// Subclass for a bottom view.
open func viewForBottom() -> UIView {
let view = MVMCoreUICommonViewsUtility.commonView()
view.heightAnchor.constraint(equalToConstant: 0).isActive = true
return view
}
//MARK: - Scrollview
open override func scrollViewDidScroll(_ scrollView: UIScrollView) {
// To stop handscroll animation if animating after scroll
stopHandScrollAnimation(true)
}
deinit {
tableView?.delegate = nil
}
//MARK: - Animation
open override func setupIntroAnimations() {
if let topView = topView, topView.subviews.count > 0 {
introAnimationManager?.addAnimation(animation: MVMAnimations.fadeUpAnimation(view: topView))
}
if let tableView = tableView {
introAnimationManager?.addAnimation(animation: MVMAnimations.animateTableViewFadeInCells(tableView: tableView))
}
if let bottomView = bottomView, bottomView.subviews.count > 0 {
introAnimationManager?.addAnimation(animation: MVMAnimations.fadeUpAnimation(view: bottomView))
}
}
}

View File

@ -16,7 +16,7 @@ open class ThreeLayerViewController: ProgrammaticScrollViewController {
var topView: UIView?
var middleView: UIView?
var bottomView: UIView?
var useMargins: Bool = true
var useMargins: Bool = false
// The bottom view can be put outside of the scrolling area.
var bottomViewOutsideOfScroll = false

View File

@ -31,8 +31,12 @@ extern NSString * _Nonnull const ConstraintWidth;
+ (nullable NSDictionary *)constraintPinSubview:(nullable UIView *)subview pinTop:(BOOL)pinTop pinBottom:(BOOL)pinBottom pinLeft:(BOOL)pinLeft pinRight:(BOOL)pinRight;
+ (nullable NSDictionary *)constraintPinSubview:(nullable UIView *)subview topRelation:(NSLayoutRelation)topRelation bottomRelation:(NSLayoutRelation)bottomRelation leftRelation:(NSLayoutRelation)leftRelation rightRelation:(NSLayoutRelation)rightRelation;
+ (nullable NSDictionary *)constraintPinSubview:(nullable UIView *)subview pinTop:(BOOL)pinTop topConstant:(CGFloat)topConstant pinBottom:(BOOL)pinBottom bottomConstant:(CGFloat)bottomConstant pinLeft:(BOOL)pinLeft leftConstant:(CGFloat)leftConstant pinRight:(BOOL)pinRight rightConstant:(CGFloat)rightConstant;
+ (nullable NSDictionary *)constraintPinSubview:(nullable UIView *)subview pinTop:(BOOL)pinTop topConstant:(CGFloat)topConstant topRelation:(NSLayoutRelation)topRelation pinBottom:(BOOL)pinBottom bottomConstant:(CGFloat)bottomConstant bottomRelation:(NSLayoutRelation)bottomRelation pinLeft:(BOOL)pinLeft leftConstant:(CGFloat)leftConstant leftRelation:(NSLayoutRelation)leftRelation pinRight:(BOOL)pinRight rightConstant:(CGFloat)rightConstant rightRelation:(NSLayoutRelation)rightRelation;
// Pin subview with 1 side
+ (nullable NSDictionary *)constraintPinTopSubview:(nonnull UIView *)subview topConstant:(CGFloat)topConstant;
+ (nullable NSDictionary *)constraintPinBottomSubview:(nonnull UIView *)subview bottomConstant:(CGFloat)bottomConstant;
@ -57,6 +61,7 @@ extern NSString * _Nonnull const ConstraintWidth;
#pragma mark - With Margins
+ (nonnull NSDictionary <NSString *, NSLayoutConstraint *>*)pinViewToSuperview:(nonnull UIView *)subview useMargins:(BOOL)useMargins;
+ (nonnull NSLayoutConstraint *)pinViewTopToSuperview:(nonnull UIView *)view useMargins:(BOOL)useMargins constant:(CGFloat)constant;
+ (nonnull NSLayoutConstraint *)pinViewLeftToSuperview:(nonnull UIView *)view useMargins:(BOOL)useMargins constant:(CGFloat)constant;
+ (nonnull NSLayoutConstraint *)pinViewRightToSuperview:(nonnull UIView *)view useMargins:(BOOL)useMargins constant:(CGFloat)constant;

View File

@ -44,29 +44,37 @@ NSString *const ConstraintWidth = @"width";
return [NSLayoutConstraint constraintPinSubview:subview pinTop:pinTop topConstant:0 pinBottom:pinBottom bottomConstant:0 pinLeft:pinLeft leftConstant:0 pinRight:pinRight rightConstant:0];
}
+ (nullable NSDictionary *)constraintPinSubview:(nullable UIView *)subview topRelation:(NSLayoutRelation)topRelation bottomRelation:(NSLayoutRelation)bottomRelation leftRelation:(NSLayoutRelation)leftRelation rightRelation:(NSLayoutRelation)rightRelation {
return [self constraintPinSubview:subview pinTop:YES topConstant:0 topRelation:topRelation pinBottom:YES bottomConstant:0 bottomRelation:bottomRelation pinLeft:YES leftConstant:0 leftRelation:leftRelation pinRight:YES rightConstant:0 rightRelation:rightRelation];
}
+ (NSDictionary *)constraintPinSubview:(UIView *)subview pinTop:(BOOL)pinTop topConstant:(CGFloat)topConstant pinBottom:(BOOL)pinBottom bottomConstant:(CGFloat)bottomConstant pinLeft:(BOOL)pinLeft leftConstant:(CGFloat)leftConstant pinRight:(BOOL)pinRight rightConstant:(CGFloat)rightConstant {
return [self constraintPinSubview:subview pinTop:pinTop topConstant:topConstant topRelation:NSLayoutRelationEqual pinBottom:pinBottom bottomConstant:bottomConstant bottomRelation:NSLayoutRelationEqual pinLeft:pinLeft leftConstant:leftConstant leftRelation:NSLayoutRelationEqual pinRight:pinRight rightConstant:rightConstant rightRelation:NSLayoutRelationEqual];
}
+ (NSDictionary *)constraintPinSubview:(UIView *)subview pinTop:(BOOL)pinTop topConstant:(CGFloat)topConstant topRelation:(NSLayoutRelation)topRelation pinBottom:(BOOL)pinBottom bottomConstant:(CGFloat)bottomConstant bottomRelation:(NSLayoutRelation)bottomRelation pinLeft:(BOOL)pinLeft leftConstant:(CGFloat)leftConstant leftRelation:(NSLayoutRelation)leftRelation pinRight:(BOOL)pinRight rightConstant:(CGFloat)rightConstant rightRelation:(NSLayoutRelation)rightRelation {
UIView *superview = subview.superview;
NSMutableDictionary *constraintDic = [[NSMutableDictionary alloc] init];
if (pinTop) {
NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1 constant:topConstant];
NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:topRelation toItem:superview attribute:NSLayoutAttributeTop multiplier:1 constant:topConstant];
top.priority = 999;
top.active = YES;
[constraintDic setObject:top forKey:ConstraintTop];
}
if (pinBottom) {
NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:subview attribute:NSLayoutAttributeBottom multiplier:1 constant:bottomConstant];
NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeBottom relatedBy:bottomRelation toItem:subview attribute:NSLayoutAttributeBottom multiplier:1 constant:bottomConstant];
bottom.priority = 999;
bottom.active = YES;
[constraintDic setObject:bottom forKey:ConstraintBot];
}
if (pinLeft) {
NSLayoutConstraint *leading = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeading multiplier:1 constant:leftConstant];
NSLayoutConstraint *leading = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeLeading relatedBy:leftRelation toItem:superview attribute:NSLayoutAttributeLeading multiplier:1 constant:leftConstant];
leading.priority = 999;
leading.active = YES;
[constraintDic setObject:leading forKey:ConstraintLeading];
}
if (pinRight) {
NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:subview attribute:NSLayoutAttributeTrailing multiplier:1 constant:rightConstant];
NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeTrailing relatedBy:rightRelation toItem:subview attribute:NSLayoutAttributeTrailing multiplier:1 constant:rightConstant];
trailing.priority = 999;
trailing.active = YES;
[constraintDic setObject:trailing forKey:ConstraintTrailing];
@ -152,6 +160,14 @@ NSString *const ConstraintWidth = @"width";
#pragma mark - With Margins
+ (nonnull NSDictionary *)pinViewToSuperview:(nonnull UIView *)subview useMargins:(BOOL)useMargins {
return @{ConstraintTop:[self pinViewTopToSuperview:subview useMargins:useMargins constant:0],
ConstraintLeading:[self pinViewLeftToSuperview:subview useMargins:useMargins constant:0],
ConstraintTrailing:[self pinViewRightToSuperview:subview useMargins:useMargins constant:0],
ConstraintBot:[self pinViewBottomToSuperview:subview useMargins:useMargins constant:0],
};
}
+ (NSLayoutConstraint *)pinViewTopToSuperview:(UIView *)view useMargins:(BOOL)useMargins constant:(CGFloat)constant {
return [view.topAnchor constraintEqualToAnchor:(useMargins ? view.superview.layoutMarginsGuide.topAnchor : view.superview.topAnchor) constant:constant];
}

View File

@ -25,6 +25,9 @@
// true while panning
@property (nonatomic) BOOL panning;
//set pannable percentage 0 to 1
@property (nonatomic) CGFloat pannablePercentage;
// can be used to keep track of if we are ..
@property (nonatomic) BOOL interactive;

View File

@ -8,8 +8,6 @@
#import "MFTabBarInteractor.h"
static CGFloat pannablePercentage = 0.15;
typedef NS_ENUM(NSUInteger, MFTabBarPanningDirection) {
MFTabBarPanningDirectionLeft,
MFTabBarPanningDirectionRight
@ -33,6 +31,7 @@ typedef NS_ENUM(NSUInteger, MFTabBarPanningDirection) {
- (nullable instancetype)initWithViewController:(nullable UIViewController *)viewController delegate:(nullable id<MFSwipeNavigationProtocol>)delegate {
if (self = [super init]) {
self.pannablePercentage = 0.15;
self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
[viewController.view addGestureRecognizer:self.panGesture];
self.delegate = delegate;
@ -48,8 +47,8 @@ typedef NS_ENUM(NSUInteger, MFTabBarPanningDirection) {
// Simulates an edge gesture by only accepting pans at the edge of the screen. Needed because edge gesture doesn't work nicely with extended menus such as on ipad.
CGRect frame = pan.view.frame;
CGRect pannableFrameLeft = CGRectMake(frame.origin.x, frame.origin.y, frame.size.width*pannablePercentage, frame.size.height);
CGRect pannableFrameRight = CGRectMake(frame.origin.x + frame.size.width*(1-pannablePercentage), frame.origin.y, frame.size.width*pannablePercentage, frame.size.height);
CGRect pannableFrameLeft = CGRectMake(frame.origin.x, frame.origin.y, frame.size.width*self.pannablePercentage, frame.size.height);
CGRect pannableFrameRight = CGRectMake(frame.origin.x + frame.size.width*(1-self.pannablePercentage), frame.origin.y, frame.size.width*self.pannablePercentage, frame.size.height);
switch (pan.state) {
case UIGestureRecognizerStateBegan:

View File

@ -193,13 +193,7 @@ static NSString * const COLLECTION_CELL_ID = @"cell";
[label layoutIfNeeded];
label.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
//set up cell acceessibility label
cell.isAccessibilityElement = NO;
cell.contentView.isAccessibilityElement = YES;
NSString *accLabel = [title stringByAppendingString:[MVMCoreUIUtility hardcodedStringWithKey:@"AccTab"]];
cell.contentView.accessibilityLabel = accLabel;
[cell.contentView setAccessibilityHint:[MVMCoreUIUtility hardcodedStringWithKey:@"AccTabHint"]];
[self setCellAccessibility:cell title:label.text isSelected:NO indexPath:indexPath];
if (indexPath.row == self.selectedIndex) {
label.textColor = [UIColor mfTomatoRed];
@ -404,20 +398,27 @@ static NSString * const COLLECTION_CELL_ID = @"cell";
[cell layoutIfNeeded];
}
//setup selected tab accessibility
NSString *string = label.text;
NSString *accLabel = [string stringByAppendingString:[MVMCoreUIUtility hardcodedStringWithKey:@"toptabbar_tab_selected"]];
cell.contentView.accessibilityLabel = accLabel;
[cell.contentView setAccessibilityHint:nil];
self.selectedIndex = indexPath.row;
if ([self.delegate respondsToSelector:@selector(topTabbar:titleForItemAtIndex:)]){
[self.delegate topTabbar:self didSelectItemAtIndex:indexPath.row];
}
[self setCellAccessibility:cell title:label.text isSelected:YES indexPath:indexPath];
}
- (void)reloadData {
[self.collectionView reloadData];
}
- (void)setCellAccessibility:(UICollectionViewCell *)cell title:(NSString *)title isSelected:(BOOL)isSelected indexPath:(NSIndexPath *)indexPath {
cell.isAccessibilityElement = NO;
cell.contentView.isAccessibilityElement = YES;
NSString *accKey = isSelected ? @"toptabbar_tab_selected" : @"AccTab";
NSString *accLabel = [title stringByAppendingString:[MVMCoreUIUtility hardcodedStringWithKey:accKey]];
NSString *accString = [accLabel stringByAppendingString:[NSString stringWithFormat:[MVMCoreUIUtility hardcodedStringWithKey:@"AccTabIndex"], indexPath.row + 1, [self.datasource numberOfTopTabbarItems:self]]];
cell.contentView.accessibilityLabel = accString;
NSString *accHint = isSelected ? nil : [MVMCoreUIUtility hardcodedStringWithKey:@"AccTabHint"];
[cell.contentView setAccessibilityHint:accHint];
}
@end

View File

@ -22,6 +22,6 @@ import Foundation
// The Field name key value pair for sending to server
@objc optional func formFieldName() -> String?
// The Feild value key value paid for sending to server
@objc optional func formFieldValue() -> String?
// The Field value key value pair for sending to server
@objc optional func formFieldValue() -> Any?
}

View File

@ -8,63 +8,6 @@
import Foundation
@objc extension FormValidator: UITextFieldDelegate {
public func textFieldDidEndEditing(_ textField: UITextField) {
enableByValidation()
if let delegate = delegate as? UITextFieldDelegate {
delegate.textFieldDidEndEditing?(textField)
}
}
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
if let delegate = delegate as? UITextFieldDelegate {
return delegate.textFieldShouldReturn?(textField) ?? true
}
return true
}
public func textFieldDidBeginEditing(_ textField: UITextField) {
if let delegate = delegate as? UITextFieldDelegate {
delegate.textFieldDidBeginEditing?(textField)
}
}
public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if let delegate = delegate as? UITextFieldDelegate {
return delegate.textFieldShouldBeginEditing?(textField) ?? true
}
return true
}
public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
if let delegate = delegate as? UITextFieldDelegate {
return delegate.textFieldShouldEndEditing?(textField) ?? true
}
return true
}
public func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) {
if let delegate = delegate as? UITextFieldDelegate {
delegate.textFieldDidEndEditing?(textField, reason: reason)
}
}
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let delegate = delegate as? UITextFieldDelegate {
return delegate.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) ?? true
}
return true
}
public func textFieldShouldClear(_ textField: UITextField) -> Bool {
if let delegate = delegate as? UITextFieldDelegate {
return delegate.textFieldShouldClear?(textField) ?? true
}
return true
}
}
@objc extension FormValidator: MFTextFieldDelegate {
public func dismissFieldInput(_ sender: Any?) {
if let delegate = delegate as? MFTextFieldDelegate {

View File

@ -10,7 +10,6 @@
#import <MVMCoreUI/StackableViewController.h>
#import <MVMCoreUI/ViewConstrainingView.h>
#import <MVMCoreUI/TopLabelsView.h>
@class LabelView;
@class PrimaryButton;

View File

@ -72,8 +72,6 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[];
#pragma mark - Atoms
#pragma mark Views
#import <MVMCoreUI/MFView.h>
#import <MVMCoreUI/MFLabel.h>
#import <MVMCoreUI/ViewConstrainingView.h>
#import <MVMCoreUI/MFLoadingSpinner.h>
#import <MVMCoreUI/MFTextView.h>

View File

@ -110,6 +110,14 @@ import UIKit
rightPin?.isActive = true
}
open func alignFill() {
alignCenterPin?.isActive = false
alignCenterLeftPin?.isActive = false
alignCenterRightPin?.isActive = false
leftPin?.isActive = true
rightPin?.isActive = true
}
open override func setLeftPinConstant(_ constant: CGFloat) {
super.setLeftPinConstant(constant)
alignCenterLeftPin?.constant = constant

View File

@ -19,6 +19,15 @@
// Called after init to provide an early setter for any molecule specific logic
- (void)setAsMolecule;
// Notifies the creator that the view needs to be constrained in a view.
- (BOOL)needsToBeConstrained;
// The alignment for the molecule if constrained.
- (UIStackViewAlignment)moleculeAlignment;
// For the molecule list to load more efficiently.
+ (CGFloat)estimatedHeightForRow;
@end

View File

@ -13,6 +13,7 @@ public class MoleculeStackView: MFView {
var moleculesArray: [UIView]?
var useMargins: Bool = false
// MARK: - Inits
public override init(frame: CGRect) {
super.init(frame: frame)
}
@ -31,6 +32,7 @@ public class MoleculeStackView: MFView {
fatalError("init(coder:) has not been implemented")
}
// MARK: - MFViewProtocol
public override func setupView() {
super.setupView()
translatesAutoresizingMaskIntoConstraints = false
@ -48,17 +50,17 @@ public class MoleculeStackView: MFView {
}
}
// MARK: - MVMCoreUIMoleculeViewProtocol
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
guard let molecules = json?.arrayForKey("molecules") as? [[String: Any]] else {
guard let molecules = json?.arrayForKey(KeyMolecules) as? [[String: Any]] else {
return
}
// Create the molecules and set the json.
var moleculesArray = [] as [UIView]
for moleculeJSON in molecules {
if let name = moleculeJSON.optionalStringForKey("moleculeName"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForName(name) {
molecule.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject) {
moleculesArray.append(molecule)
}
}
@ -70,12 +72,9 @@ public class MoleculeStackView: MFView {
if let spacingBlock = spacingBlock {
MVMCoreUIStackableViewController.populateView(self, withUIArray: moleculesArray, useMargins: useMargins, withSpacingBlock: spacingBlock)
} else {
let separation = json?.optionalCGFloatForKey("separation") ?? PaddingDefault
MVMCoreUIStackableViewController.populateView(self, withUIArray: moleculesArray, useMargins: useMargins) { (object) -> UIEdgeInsets in
if object as AnyObject? === moleculesArray.first {
return UIEdgeInsets.zero
} else {
return UIEdgeInsets.init(top: PaddingTwo, left: 0, bottom: 0, right: 0)
}
return UIEdgeInsets.init(top: separation, left: 0, bottom: 0, right: 0)
}
}
}

View File

@ -0,0 +1,152 @@
//
// MoleculeTableViewCell.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 4/18/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class MoleculeTableViewCell: UITableViewCell, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol {
open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)?
// For the accessory view convenience.
public var caretView: CaretView?
private var caretViewWidthSizeObject: MFSizeObject?
private var caretViewHeightSizeObject: MFSizeObject?
// For separation between cells.
public var topSeparatorView: SeparatorView?
public var bottomSeparatorView: SeparatorView?
public enum SeparatorFrequency: String {
case All = "all"
case AllExceptTop = "allExceptTop"
case AllExceptBottom = "allExceptBottom"
case Between = "between"
}
// MARK: - Inits
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupView()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
// MARK: - MFViewProtocol
public func updateView(_ size: CGFloat) {
MFStyler.setDefaultMarginsFor(self, size: size)
if #available(iOS 11.0, *) {
contentView.directionalLayoutMargins = directionalLayoutMargins
topSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading)
bottomSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading)
} else {
contentView.layoutMargins = layoutMargins
topSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left)
bottomSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left)
}
if let molecule = molecule as? MVMCoreViewProtocol {
molecule.updateView(size)
}
if let _ = accessoryView, let caretView = caretView, let widthObject = caretViewWidthSizeObject, let heightObject = caretViewHeightSizeObject {
caretView.frame = CGRect(x: 0, y: 0, width: widthObject.getValueBased(onSize: size), height: heightObject.getValueBased(onSize: size))
}
topSeparatorView?.updateView(size)
bottomSeparatorView?.updateView(size)
}
public func setupView() {
preservesSuperviewLayoutMargins = false
contentView.preservesSuperviewLayoutMargins = false
selectionStyle = .none
}
// MARK: - MVMCoreUIMoleculeViewProtocol
public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) {
guard let json = json else {
return
}
if molecule == nil {
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: json, delegateObject: delegateObject) {
contentView.addSubview(moleculeView)
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: moleculeView.needsToBeConstrained?() ?? false).values))
molecule = moleculeView
}
} else {
molecule?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
}
backgroundColor = molecule?.backgroundColor
}
// MARK: - Convenience
/// Adds the standard mvm style caret to the accessory view
public func addCaretViewAccessory() {
guard accessoryView == nil else {
return
}
let width: CGFloat = 6
let height: CGFloat = 10
caretView = CaretView(lineThickness: CaretView.thin)
caretView?.frame = CGRect(x: 0, y: 0, width: width, height: height)
caretViewWidthSizeObject = MFSizeObject(scalingStandardSize: width)
caretViewHeightSizeObject = MFSizeObject(scalingStandardSize: height)
accessoryView = caretView
}
func addSeparatorsIfNeeded() {
if topSeparatorView == nil {
topSeparatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionTop)
topSeparatorView?.hide()
}
if bottomSeparatorView == nil {
bottomSeparatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionBot)
bottomSeparatorView?.hide()
}
}
/// For when the separator between cells shows using json and frequency.
public func setSeparatorWithJSON(_ json: [AnyHashable : Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?, indexPath: IndexPath) {
guard let json = json else {
return
}
addSeparatorsIfNeeded()
topSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
bottomSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
if let separatorFrequencyString = json.optionalStringForKey("frequency"), let separatorFrequency = SeparatorFrequency(rawValue: separatorFrequencyString) {
setSeparatorFrequency(separatorFrequency, indexPath: indexPath)
}
}
/// For when the separator between cells shows.
public func setSeparatorFrequency(_ separatorFrequency: SeparatorFrequency, indexPath: IndexPath) {
switch separatorFrequency {
case .All:
if indexPath.row == 0 {
topSeparatorView?.show()
} else {
topSeparatorView?.hide()
}
bottomSeparatorView?.show()
case .AllExceptBottom:
topSeparatorView?.show()
bottomSeparatorView?.hide()
case .Between:
if indexPath.row == 0 {
topSeparatorView?.hide()
} else {
topSeparatorView?.show()
}
bottomSeparatorView?.hide()
case .AllExceptTop:
fallthrough
default:
topSeparatorView?.hide()
bottomSeparatorView?.show()
}
}
}

View File

@ -46,16 +46,16 @@ public class StandardFooterView: ViewConstrainingView {
spaceBetweenButtons = textButton.topAnchor.constraint(equalTo: twoButtonView.bottomAnchor, constant: PaddingTwo)
spaceBetweenButtons?.isActive = true
leftConstraintTwoButton = twoButtonView.leftAnchor.constraint(equalTo: leftAnchor)
leftConstraintTwoButton = twoButtonView.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor)
leftConstraintTwoButton?.isActive = true
rightConstraintTwoButton = rightAnchor.constraint(equalTo: twoButtonView.rightAnchor)
rightConstraintTwoButton = layoutMarginsGuide.rightAnchor.constraint(equalTo: twoButtonView.rightAnchor)
rightConstraintTwoButton?.isActive = true
leftConstraintTextButton = textButton.leftAnchor.constraint(greaterThanOrEqualTo: leftAnchor)
leftConstraintTextButton = textButton.leftAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.leftAnchor)
leftConstraintTextButton?.isActive = true
rightConstraintTextButton = rightAnchor.constraint(greaterThanOrEqualTo: textButton.rightAnchor)
rightConstraintTextButton = layoutMarginsGuide.rightAnchor.constraint(greaterThanOrEqualTo: textButton.rightAnchor)
rightConstraintTextButton?.isActive = true
centerAlignTextButton = textButton.centerXAnchor.constraint(equalTo: centerXAnchor)
@ -93,16 +93,6 @@ public class StandardFooterView: ViewConstrainingView {
layoutIfNeeded()
}
public override func setLeftPinConstant(_ constant: CGFloat) {
leftConstraintTwoButton?.constant = constant
leftConstraintTextButton?.constant = constant
}
public override func setRightPinConstant(_ constant: CGFloat) {
rightConstraintTwoButton?.constant = constant
rightConstraintTextButton?.constant = constant
}
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
if let colorString = json?.optionalStringForKey(KeyBackgroundColor) {

View File

@ -9,8 +9,8 @@
import UIKit
public class StandardHeaderView: ViewConstrainingView {
let headlineLabel = MFLabel.commonLabelH2(true)
let messageLabel = MFLabel.commonLabelB2(true)
let headlineLabel = Label.commonLabelH2(true)
let messageLabel = Label.commonLabelB2(true)
var separatorView: SeparatorView?
var spaceBetweenLabels: NSLayoutConstraint?
var leftConstraintTitle: NSLayoutConstraint?
@ -75,10 +75,10 @@ public class StandardHeaderView: ViewConstrainingView {
}
public func setSpacing() {
if headlineLabel.hasText() && messageLabel.hasText() {
if headlineLabel.hasText && messageLabel.hasText {
spaceBetweenLabels?.constant = PaddingTwo
show()
} else if headlineLabel.hasText() || messageLabel.hasText() {
} else if headlineLabel.hasText || messageLabel.hasText {
spaceBetweenLabels?.constant = 0
show()
} else {

View File

@ -7,17 +7,16 @@
//
#import <UIKit/UIKit.h>
#import <MVMCoreUI/MFView.h>
#import <MVMCoreUI/MFLabel.h>
@class Label;
#import <MVMCoreUI/SeparatorView.h>
@class TopLabelsAndBottomButtonsTableViewController;
@interface TopLabelsView : MFView
@property (nullable, weak, nonatomic) MFLabel *headlineLabel;
@property (nullable, weak, nonatomic) MFLabel *messageLabel;
@property (nullable, weak, nonatomic) Label *headlineLabel;
@property (nullable, weak, nonatomic) Label *messageLabel;
@property (nullable, strong, nonatomic) NSLayoutConstraint *topLabelConstraint;
@property (nullable, weak, nonatomic) NSLayoutConstraint *spaceBetweenLabels;

View File

@ -14,6 +14,7 @@
#import <MVMCoreUI/MFStyler.h>
#import <MVMCore/MVMCoreConstants.h>
#import <MVMCoreUI/NSLayoutConstraint+MFConvenience.h>
#import <MVMCoreUI/MVMCoreUI-Swift.h>
@interface TopLabelsView ()
@ -54,12 +55,12 @@
self.clipsToBounds = YES;
[self.headlineLabel removeFromSuperview];
MFLabel *headlineLabel = [MFLabel commonLabelH2:YES];
Label *headlineLabel = [Label commonLabelH2:YES];
[self addSubview:headlineLabel];
self.headlineLabel = headlineLabel;
[self.messageLabel removeFromSuperview];
MFLabel *messageLabel = [MFLabel commonLabelB2:YES];
Label *messageLabel = [Label commonLabelB2:YES];
[self addSubview:messageLabel];
self.messageLabel = messageLabel;

View File

@ -11,10 +11,12 @@ import UIKit
open class MVMCoreUIDelegateObject: DelegateObject {
public weak var formValidationProtocol: FormValidationProtocol?
public weak var buttonDelegate: ButtonDelegateProtocol?
public weak var uiTextFieldDelegate: UITextFieldDelegate?
open override func setAll(withDelegate delegate: Any) {
super.setAll(withDelegate: delegate)
formValidationProtocol = delegate as? FormValidationProtocol
buttonDelegate = delegate as? ButtonDelegateProtocol
uiTextFieldDelegate = delegate as? UITextFieldDelegate
}
}

View File

@ -22,4 +22,7 @@
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForName:(nonnull NSString *)name;
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject;
// Similar to above but also checks if the molecule needs to be constrained for a stack.
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForStackWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject;
@end

View File

@ -22,7 +22,7 @@
static NSMutableDictionary <NSString *, Class>*mapping;
dispatch_once(&onceToken, ^{
mapping = [@{
@"label": LabelView.class,
@"label": Label.class,
@"separator": SeparatorView.class,
@"button": ButtonView.class,
@"textButton": MFTextButton.class,
@ -32,7 +32,8 @@
@"standardFooter": StandardFooterView.class,
@"caretView": CaretView.class,
@"caretButton": CaretButton.class,
@"textField" : MFTextField.class
@"textField" : MFTextField.class,
@"checkbox" : MVMCoreUICheckBox.class
} mutableCopy];
});
return mapping;
@ -45,18 +46,18 @@
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForName:(nonnull NSString *)name {
Class class = [self.moleculeMapping objectForKey:name];
if (class) {
UIView <MVMCoreUIMoleculeViewProtocol>*view = [[class alloc] init];
if ([view respondsToSelector:@selector(setAsMolecule)]) {
[view setAsMolecule];
}
return view;
if (!class) {
return nil;
}
return nil;
UIView <MVMCoreUIMoleculeViewProtocol>*molecule = [[class alloc] init];
if ([molecule respondsToSelector:@selector(setAsMolecule)]) {
[molecule setAsMolecule];
}
return molecule;
}
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject {
NSString *moleculeName = [json string:@"moleculeName"];
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject {
NSString *moleculeName = [json string:KeyMoleculeName];
if (!moleculeName) {
return nil;
}
@ -66,4 +67,17 @@
}
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForStackWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject {
NSString *moleculeName = [json string:KeyMoleculeName];
if (!moleculeName) {
return nil;
}
UIView <MVMCoreUIMoleculeViewProtocol>*molecule = [self getMoleculeForName:moleculeName];
if ([molecule respondsToSelector:@selector(needsToBeConstrained)] && [molecule needsToBeConstrained]) {
molecule = [[ViewConstrainingView alloc] initWithMolecule:molecule alignment:[molecule respondsToSelector:@selector(moleculeAlignment)] ? [molecule moleculeAlignment] : UIStackViewAlignmentFill];
}
[molecule setWithJSON:json delegateObject:delegateObject additionalData:nil];
return molecule;
}
@end

View File

@ -21,7 +21,8 @@
viewControllerMapping = [@{
@"textFieldListForm" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[TextFieldListFormViewController class]],
@"moleculeStack" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeStackTemplate class]],
@"centerMoleculeStack" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeStackCenteredTemplate class]]
@"centerMoleculeStack" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeStackCenteredTemplate class]],
@"moleculeList" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeListTemplate class]]
} mutableCopy];
});
return viewControllerMapping;

View File

@ -13,6 +13,7 @@
#import "NSLayoutConstraint+MFConvenience.h"
#import "MVMCoreUISplitViewController.h"
@import MVMCore.MVMCoreDispatchUtility;
#import <MVMCoreUI/MVMCoreUIUtility.h>
CGFloat const PaddingDefault = 24;
CGFloat const PaddingDefaultHorizontalSpacing = 32;
@ -947,7 +948,8 @@ CGFloat const LabelWithInternalButtonLineSpace = 2;
if ([times containsObject:@"DD"]) {
[timeString appendString:[NSString stringWithFormat:@"%02ld",days]];
if (timeUnit == MFTimeFormatNormal) {
NSString *dayUnit = (days <= 1) ? @" day": @" days";
NSString *dayKey = (days <= 1) ? @"CountDownDay": @"CountDownDays";
NSString *dayUnit = [MVMCoreUIUtility hardcodedStringWithKey:dayKey];
[timeString appendString:dayUnit];
} else if (timeUnit == MFTimeFormatColon && ![[times lastObject] isEqualToString:@"DD"]) {
[timeString appendString:@" : "];
@ -962,7 +964,8 @@ CGFloat const LabelWithInternalButtonLineSpace = 2;
}
[timeString appendString:[NSString stringWithFormat:@"%02d",hours]];
if (timeUnit == MFTimeFormatNormal) {
NSString *hourUnit = (hours <= 1) ? @" hour": @" hours";
NSString *hourKey = (hours <= 1) ? @"CountDownHour": @"CountDownHours";
NSString *hourUnit = [MVMCoreUIUtility hardcodedStringWithKey:hourKey];
[timeString appendString:hourUnit];
} else if (timeUnit == MFTimeFormatColon && ![[times lastObject] isEqualToString:@"HH"]) {
[timeString appendString:@" : "];
@ -981,7 +984,8 @@ CGFloat const LabelWithInternalButtonLineSpace = 2;
}
[timeString appendString:[NSString stringWithFormat:@"%02d",minutes]];
if (timeUnit == MFTimeFormatNormal) {
NSString *minuteUnit = (minutes <= 1) ? @" min": @" mins";
NSString *minKey = (minutes <= 1) ? @"CountDownMin": @"CountDownMins";
NSString *minuteUnit = [MVMCoreUIUtility hardcodedStringWithKey:minKey];
[timeString appendString:minuteUnit];
} else if (timeUnit == MFTimeFormatColon && ![[times lastObject] isEqualToString:@"MM"]) {
[timeString appendString:@" : "];
@ -1005,7 +1009,8 @@ CGFloat const LabelWithInternalButtonLineSpace = 2;
}
[timeString appendString:[NSString stringWithFormat:@"%02d",seconds]];
if (timeUnit == MFTimeFormatNormal) {
NSString *secondUnit = (seconds <= 1) ? @" sec": @" secs";
NSString *secondKey = (seconds <= 1) ? @"CountDownSec": @"CountDownSecs";
NSString *secondUnit = [MVMCoreUIUtility hardcodedStringWithKey:secondKey];
[timeString appendString:secondUnit];
}
}

View File

@ -11,6 +11,7 @@
// Tab
"AccTab" = ", tab";
"AccTabHint" = "Double tap to select.";
"AccTabIndex" = ", %ld of %ld";
// top alert
"toptabbar_tab_selected" = ", tab, Selected";
"AccTopAlertClosed" = "Top alert notification is closed.";
@ -39,3 +40,12 @@
"AccOn" = "on";
"AccOff" = "off";
"AccToggleHint" = "double tap to toggle";
//Styler
"CountDownDay" = " day";
"CountDownHour" = " hour";
"CountDownMin" = " min";
"CountDownSec" = " sec";
"CountDownDays" = " days";
"CountDownHours" = " hours";
"CountDownMins" = " mins";
"CountDownSecs" = " secs";

View File

@ -10,6 +10,7 @@
// Tab
"AccTab" = ", pestaña";
"AccTabHint" = "Toca dos veces para seleccionar.";
"AccTabIndex" = ", %ld de %ld";
// top alert
"toptabbar_tab_selected" = ", pestaña, Seleccionado";
"AccTopAlertClosed" = "La notificación de alerta máxima está desactivada.";
@ -38,3 +39,12 @@
"AccOn" = "encendido";
"AccOff" = "apagado";
"AccToggleHint" = "toca dos veces para alternar";
//Styler
"CountDownDay" = " día";
"CountDownHour" = " hora";
"CountDownMin" = " min";
"CountDownSec" = " seg";
"CountDownDays" = " días";
"CountDownHours" = " horas";
"CountDownMins" = " min";
"CountDownSecs" = " seg";

View File

@ -10,6 +10,7 @@
// Tab
"AccTab" = ", pestaña";
"AccTabHint" = "Toca dos veces para seleccionar.";
"AccTabIndex" = ", %ld de %ld";
// top alert
"toptabbar_tab_selected" = ", pestaña, Seleccionado";
"AccTopAlertClosed" = "La notificación de alerta máxima está desactivada.";
@ -38,3 +39,12 @@
"AccOn" = "encendido";
"AccOff" = "apagado";
"AccToggleHint" = "toca dos veces para alternar";
//Styler
"CountDownDay" = " día";
"CountDownHour" = " hora";
"CountDownMin" = " min";
"CountDownSec" = " seg";
"CountDownDays" = " días";
"CountDownHours" = " horas";
"CountDownMins" = " min";
"CountDownSecs" = " seg";

View File

@ -0,0 +1,68 @@
//
// MoleculeListTemplate.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 4/18/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
open class MoleculeListTemplate: ThreeLayerTableViewController {
open override func registerWithTable() {
super.registerWithTable()
guard let molecules = loadObject?.pageJSON?.arrayForKey(KeyMolecules) else {
return
}
for case let molecule as Dictionary<AnyHashable, Any> in molecules {
if let moleculeName = molecule.optionalStringForKey(KeyMoleculeName) {
tableView?.register(MoleculeTableViewCell.self, forCellReuseIdentifier: moleculeName)
}
}
}
open override func viewForTop() -> UIView {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else {
return super.viewForTop()
}
return molecule
}
override open func viewForBottom() -> UIView {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else {
return viewForBottom()
}
return molecule
}
open override func newDataBuildScreen() {
super.newDataBuildScreen()
registerWithTable()
}
open override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if let moleculeName = loadObject?.pageJSON?.stringOptionalWithChainOfKeysOrIndexes([KeyMolecules,indexPath.row,KeyMoleculeName]), let theClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping?[moleculeName] as? MVMCoreUIMoleculeViewProtocol.Type,
let estimatedHeightForRow = theClass.estimatedHeightForRow {
return estimatedHeightForRow()
}
return 0
}
open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return loadObject?.pageJSON?.arrayForKey(KeyMolecules).count ?? 0
}
open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let molecule = loadObject?.pageJSON?.optionalDictionaryWithChainOfKeysOrIndexes([KeyMolecules,indexPath.row]),
let moleculeName = molecule.optionalStringForKey(KeyMoleculeName),
let cell = tableView.dequeueReusableCell(withIdentifier: moleculeName) as? MoleculeTableViewCell else {
return UITableViewCell()
}
let delegate = delegateObject()
cell.setWithJSON(molecule, delegateObject: delegate, additionalData: nil)
cell.setSeparatorWithJSON(loadObject?.pageJSON?.optionalDictionaryForKey("separator"), delegateObject: delegate, additionalData: nil, indexPath: indexPath)
cell.updateView(tableView.bounds.width)
return cell
}
}

View File

@ -18,7 +18,7 @@ public class MoleculeStackCenteredTemplate: ThreeLayerViewController {
public override func viewForTop() -> UIView? {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"),
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForJSON(moleculeJSON, delegateObject: delegateObject()) else {
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else {
return nil
}
return molecule
@ -26,7 +26,7 @@ public class MoleculeStackCenteredTemplate: ThreeLayerViewController {
override public func viewForBottom() -> UIView? {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"),
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForJSON(moleculeJSON, delegateObject: delegateObject()) else {
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else {
return nil
}
return molecule

View File

@ -12,11 +12,11 @@ public class MoleculeStackTemplate: ThreeLayerViewController {
public override func spaceBetweenTopAndMiddle() -> CGFloat? {
return PaddingTwo
return 0
}
public override func viewForTop() -> UIView? {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForJSON(moleculeJSON, delegateObject: delegateObject()) else {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else {
return nil
}
return molecule
@ -30,7 +30,7 @@ public class MoleculeStackTemplate: ThreeLayerViewController {
}
override public func viewForBottom() -> UIView? {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForJSON(moleculeJSON, delegateObject: delegateObject()) else {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else {
return nil
}
return molecule

View File

@ -13,6 +13,9 @@
extern NSString * const KeyScreenHeading;
extern NSString * const KeyMolecules;
extern NSString * const KeyMoleculeName;
extern NSString * const KeyDisableButton;
extern NSString * const KeyValue;
@ -35,6 +38,9 @@ extern NSString * const KeyTextColor;
extern NSString * const KeyIsHidden;
extern NSString * const KeyIsOpaque;
extern NSString * const KeyFieldKey;
extern NSString * const KeyRequired;
#pragma mark - Values
extern NSString * const StringY;

View File

@ -12,12 +12,17 @@
NSString * const KeyScreenHeading = @"screenHeading";
NSString * const KeyMolecules = @"molecules";
NSString * const KeyMoleculeName = @"moleculeName";
NSString * const KeyDisableButton = @"disableAction";
NSString * const KeyValue = @"value";
NSString * const KeyLabel = @"label";
NSString * const KeyDisable = @"disable";
NSString * const KeyFieldName = @"fieldName";
NSString * const KeyFieldKey = @"fieldKey";
NSString * const KeyRequired = @"required";
NSString * const KeyHideMainMenu = @"hideMainMenu";
NSString * const KeyProgressPercent = @"progressPercent";
@ -34,6 +39,7 @@ NSString * const KeyTextColor = @"textColor";
NSString * const KeyIsHidden = @"isHidden";
NSString * const KeyIsOpaque = @"isOpaque";
#pragma mark - Values
NSString * const StringY = @"Y";