From abe80a1ce31f4d61cbd9a8c354d41fbd03d0799c Mon Sep 17 00:00:00 2001 From: "Christiano, Kevin" Date: Fri, 29 Mar 2019 10:00:35 -0400 Subject: [PATCH 01/13] Converted LabelWithInternalButton.h/m to LabelWithInternalButton.swift. Removed LabelWithInternalButton.h/m. Changes reflected in project file. --- MVMCoreUI.xcodeproj/project.pbxproj | 12 +- .../Atoms/Views/LabelWithInternalButton.h | 94 --- .../Atoms/Views/LabelWithInternalButton.m | 557 --------------- .../Atoms/Views/LabelWithInternalButton.swift | 647 ++++++++++++++++++ MVMCoreUI/MVMCoreUI.h | 1 - 5 files changed, 651 insertions(+), 660 deletions(-) delete mode 100644 MVMCoreUI/Atoms/Views/LabelWithInternalButton.h delete mode 100644 MVMCoreUI/Atoms/Views/LabelWithInternalButton.m create mode 100644 MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 40733e65..2cd04862 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -150,11 +150,10 @@ D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; }; 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 */; }; - D2C5001D21F8EE67001DA659 /* LabelWithInternalButton.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001B21F8EE66001DA659 /* LabelWithInternalButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D2C5001E21F8EE67001DA659 /* LabelWithInternalButton.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001C21F8EE66001DA659 /* LabelWithInternalButton.m */; }; 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 */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -305,11 +304,10 @@ D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerViewController.swift; sourceTree = ""; }; D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = ""; }; D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = ""; }; - D2C5001B21F8EE66001DA659 /* LabelWithInternalButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LabelWithInternalButton.h; sourceTree = ""; }; - D2C5001C21F8EE66001DA659 /* LabelWithInternalButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LabelWithInternalButton.m; sourceTree = ""; }; DBC4391622442196001AB423 /* CaretView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretView.swift; sourceTree = ""; }; DBC4391722442197001AB423 /* DashLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashLine.swift; sourceTree = ""; }; DBC4391A224421A0001AB423 /* CaretButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretButton.swift; sourceTree = ""; }; + DBC4391C2245232D001AB423 /* LabelWithInternalButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelWithInternalButton.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -543,8 +541,6 @@ D29DF28621E7AC2B003B2FB9 /* MFLabel.m */, D29DF31E21ED0CBA003B2FB9 /* LabelView.h */, D29DF31F21ED0CBA003B2FB9 /* LabelView.m */, - D2C5001B21F8EE66001DA659 /* LabelWithInternalButton.h */, - D2C5001C21F8EE66001DA659 /* LabelWithInternalButton.m */, D29DF28721E7AC2B003B2FB9 /* ViewConstrainingView.h */, D29DF28821E7AC2B003B2FB9 /* ViewConstrainingView.m */, D282AAB9224131D100C46919 /* MFTransparentGIFView.swift */, @@ -566,6 +562,7 @@ D22D1F19220341F50077CEC0 /* MVMCoreUICheckBox.m */, D22D1F44220496A30077CEC0 /* MVMCoreUISwitch.h */, D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */, + DBC4391C2245232D001AB423 /* LabelWithInternalButton.swift */, ); path = Views; sourceTree = ""; @@ -725,7 +722,6 @@ D29DF17521E69E1F003B2FB9 /* ButtonDelegateProtocol.h in Headers */, D29DF18221E69E54003B2FB9 /* SeparatorView.h in Headers */, D29DF26E21E6AA0B003B2FB9 /* FLAnimatedImage.h in Headers */, - D2C5001D21F8EE67001DA659 /* LabelWithInternalButton.h in Headers */, D29DF11621E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.h in Headers */, D29DF17721E69E1F003B2FB9 /* MFTextButton.h in Headers */, D29DF16221E69996003B2FB9 /* MFViewController.h in Headers */, @@ -845,6 +841,7 @@ D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */, D29DF25321E6A177003B2FB9 /* MFDigitTextField.m in Sources */, D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */, + DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */, D29DF17C21E69E1F003B2FB9 /* MFTextButton.m in Sources */, D29DF2C521E7BF57003B2FB9 /* MFTabBarSwipeAnimator.m in Sources */, D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */, @@ -897,7 +894,6 @@ D29DF25121E6A177003B2FB9 /* MFDigitTextBox.m in Sources */, DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */, D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, - D2C5001E21F8EE67001DA659 /* LabelWithInternalButton.m in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */, D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.h b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.h deleted file mode 100644 index 10c0bfdd..00000000 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.h +++ /dev/null @@ -1,94 +0,0 @@ -// -// TextMixedWithButtonView.h -// mobilefirst -// -// Created by Chris Yang on 2/25/16. -// Copyright © 2016 Verizon Wireless. All rights reserved. -// - -#import -#import -#import -#import -#import -#import - -typedef void (^ActionBlock)(void); - -@interface LabelWithInternalButton : UIControl - -@property (nullable, copy, nonatomic) ActionBlock actionBlock; -@property (nullable, weak, nonatomic) MFLabel *label; - -@property (nullable, strong, nonatomic) NSString *frontText; -@property (nullable, strong, nonatomic) NSString *actionText; -@property (nullable, strong, nonatomic) NSString *backText; -@property (nullable, strong, nonatomic) NSAttributedString *attributedText; - -//by default, it will follow most of the font standard in zepplin, and should need to be changed -@property (nullable, strong, nonatomic) UIFont *normalTextFont; -@property (nullable, strong, nonatomic) UIFont *actionTextFont; -@property (nullable, strong, nonatomic) UIColor *normalTextColor; -@property (nullable, strong, nonatomic) UIColor *actionTextColor; - -@property (nullable, strong, nonatomic) NSString *alternateAttributeForActionText; - -@property (assign, nonatomic) BOOL makeWholeViewClickable; - -// with button delegate -- (nullable instancetype)initWithActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate; -- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate; -- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText actionText:(nullable NSString *)actionText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate; -// set with button delegate -- (void)setActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate; -- (void)setFrontText:(nullable NSString *)frontText actionMap:(nullable NSDictionary *)actionMap backText:(nullable NSString *)backText additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate; -- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backText additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate; -- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backAttributedText addNewLine:(BOOL) addNewLine additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate; - - -// legacy -- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText actionText:(nullable NSString *)actionText backText:(nullable NSString *)backText actionBlock:(nullable ActionBlock)block; -- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText actionText:(nullable NSString *)actionText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate; - -- (nullable instancetype)initWithActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate; - -//this assume that the action text is the "title" key in action map -- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate; - -// Convenience Initializer which assumes that the clickable text will be embedded in curly braces {}. -- (nullable instancetype)initWithClickableTextEmbeddedInCurlyBraces:(nullable NSString *)fullText actionMapForClickableText:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate; -// Convenience Initializer which assumes that the clickable text will be embedded in any tag. -- (nullable instancetype)initWithText:(nullable NSString *)fullText startTag:(nullable NSString *)startTag endTag:(nullable NSString *)endTag actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate; - - -//set action map -- (void)setActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate; - -//set text with curly braces -- (void)setCurlyBracedText:(nonnull NSString *)text; -// set text with any tags -- (void)setWithText:(nullable NSString *)fullText startTag:(nullable NSString *)startTag endTag:(nullable NSString *)endTag actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate; - -// Reset the text, action map and delegate -- (void)setTextWithClickableTextEmbeddedInCurlyBraces:(nullable NSString *)text textAttributes:(nullable NSDictionary *)attributes actionMapForClickableText:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate; - -// Reset the front text, back text, action map -- (void)setFrontText:(nullable NSString *)frontText actionMap:(nullable NSDictionary *)actionMap backText:(nullable NSString *)backText additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate; - -// Reset the front text, back text, action map -- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backText additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate; -- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backAttributedText addNewLine:(BOOL) addNewLine additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate; - -- (void)resetWithActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary * )additionalData delegate:(nullable NSObject *)delegate; - -- (void)setAlignment:(NSTextAlignment)textAlignment; - -- (void)setEnabled:(BOOL)enabled; - -- (void)setAlternateActionTextAttributes:(nullable NSDictionary *)attributes; - -- (void)setActionTextString:(nullable NSString *)actionText; - -- (nonnull UIAccessibilityCustomAction *)accessibilityCustomAction; - -@end diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.m b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.m deleted file mode 100644 index c4c509c5..00000000 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.m +++ /dev/null @@ -1,557 +0,0 @@ -// -// TextMixedWithButtonView.m -// mobilefirst -// -// Created by Chris Yang on 2/25/16. -// Copyright © 2016 Verizon Wireless. All rights reserved. -// - -#import "LabelWithInternalButton.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import - -@interface LabelWithInternalButton () - -@property (nullable, strong, nonatomic) NSString *text; - -@end - -@implementation LabelWithInternalButton - - - -- (nullable instancetype)initWithActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate { - return [self initWithFrontText:[actionMap stringForKey:KeyTitlePrefix] actionText:[actionMap stringForKey:KeyTitle] backText:[actionMap stringForKey:KeyTitlePostfix] actionMap:actionMap additionalData:additionalData actionDelegate:delegate buttonDelegate:buttonDelegate]; -} - -- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate { - return [self initWithFrontText:frontText actionText:[actionMap stringForKey:KeyTitle] backText:backText actionMap:actionMap additionalData:additionalData actionDelegate:delegate buttonDelegate:buttonDelegate]; -} - -- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText actionText:(nullable NSString *)actionText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate { - if (self = [super init]) { - [self setFrontText:frontText actionText:actionText actionMap:actionMap backText:backText additionalData:additionalData delegate:delegate buttonDelegate:buttonDelegate]; - } - return self; -} - -- (void)setActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate { - __weak typeof(self) weakSelf = self; - __weak typeof(delegate) weakDelegate = delegate; - __weak typeof(buttonDelegate) weakButtonDelegate = buttonDelegate; - self.actionBlock = ^{ - BOOL performAction = YES; - if (weakButtonDelegate && [weakButtonDelegate respondsToSelector:@selector(button:shouldPerformActionWithMap:additionalData:)]) { - performAction = [weakButtonDelegate button:weakSelf shouldPerformActionWithMap:actionMap additionalData:additionalData]; - } - - if (performAction) { - [[MVMCoreActionHandler sharedActionHandler] handleActionWithDictionary:actionMap additionalData:additionalData delegate:weakDelegate]; - } - }; -} - -- (void)setFrontText:(NSString *)frontText actionMap:(NSDictionary *)actionMap backText:(NSString *)backText additionalData:(NSDictionary *)additionalData delegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate { - [self setFrontText:frontText actionText:[actionMap stringForKey:KeyTitle] actionMap:actionMap backText:backText additionalData:additionalData delegate:delegate buttonDelegate:buttonDelegate]; -} - -- (void)setFrontText:(NSString *)frontText actionText:(NSString *)actionText actionMap:(NSDictionary *)actionMap backText:(NSString *)backText additionalData:(NSDictionary *)additionalData delegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate { - self.frontText = frontText; - [self setActionMap:actionMap additionalData:additionalData actionDelegate:delegate buttonDelegate:buttonDelegate]; - self.actionText = actionText; - self.backText = backText; - self.text = [self getTextFromStringComponents]; - [self setup]; -} - -- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backText additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate { - [self setFrontAttributedText:frontAttributedText actionMap:actionMap backAttributedText:backText addNewLine:NO additionalData:additionalData delegate:delegate buttonDelegate:buttonDelegate]; -} - -- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backAttributedText addNewLine:(BOOL) addNewLine additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate buttonDelegate:(nullable NSObject *)buttonDelegate { - NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init]; - if (frontAttributedText) { - [attributedString appendAttributedString:frontAttributedText]; - // need to do this to fix the range issue - self.frontText = frontAttributedText.string; - } - - NSString *newLineAttributed = [[NSString alloc] initWithString:addNewLine?@"\n":@" "]; - - if (actionMap.allKeys.count > 0) { - - NSMutableString *actionString = [[actionMap stringForKey:KeyTitle] mutableCopy]; - - if (actionString.length > 0) { - - [actionString appendString:newLineAttributed]; - - NSAttributedString *actionAttributedString = [MFStyler styleGetAttributedString:actionString font:[MFStyler fontB2] color:[UIColor blackColor]]; - - self.actionText = actionString; - [self setActionMap:actionMap additionalData:additionalData actionDelegate:delegate buttonDelegate:buttonDelegate]; - - [attributedString appendAttributedString:actionAttributedString]; - } - } else { - self.actionText = nil; - self.actionBlock = nil; - } - - if (backAttributedText) { - [attributedString appendAttributedString:backAttributedText]; - } - self.attributedText = attributedString; - - //added this line for underlining - [self setAlternateActionTextAttributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)}]; -} - -#pragma mark - legacy - -- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText actionText:(nullable NSString *)actionText backText:(nullable NSString *)backText actionBlock:(nullable ActionBlock)block { - if (self = [super init]) { - self.frontText = frontText; - self.actionText = actionText; - self.backText = backText; - self.actionBlock = block; - self.text = [self getTextFromStringComponents]; - [self setup]; - } - return self; -} -- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText actionText:(nullable NSString *)actionText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate { - return [self initWithFrontText:frontText actionText:actionText backText:backText actionMap:actionMap additionalData:additionalData actionDelegate:delegate buttonDelegate:nil]; -} - -- (nullable instancetype)initWithActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate { - return [self initWithFrontText:[actionMap stringForKey:KeyTitlePrefix] actionText:[actionMap stringForKey:KeyTitle] backText:[actionMap stringForKey:KeyTitlePostfix] actionMap:actionMap additionalData:additionalData actionDelegate:delegate]; -} - -- (instancetype)init -{ - self = [super init]; - if (self) { - [self setup]; - } - return self; -} - - -- (instancetype)initWithCoder:(NSCoder *)coder -{ - self = [super initWithCoder:coder]; - if (self) { - [self setup]; - } - return self; -} - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self) { - [self setup]; - } - return self; -} - -- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate { - return [self initWithFrontText:frontText actionText:[actionMap stringForKey:KeyTitle] backText:backText actionMap:actionMap additionalData:additionalData actionDelegate:delegate]; -} - -// Convenience Initializer which assumes that the clickable text will be embedded in curly braces {}. -- (nullable instancetype)initWithClickableTextEmbeddedInCurlyBraces:(nullable NSString *)fullText actionMapForClickableText:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate { - return [self initWithText:fullText startTag:@"{" endTag:@"}" actionMap:actionMap additionalData:additionalData actionDelegate:delegate]; -} - -- (instancetype)initWithText:(nullable NSString *)fullText startTag:(nullable NSString *)startTag endTag:(nullable NSString *)endTag actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate -{ - self = [super init]; - if (self) { - [self setText:fullText startTag:startTag endTag:endTag]; - __weak typeof(delegate) weakDelegate = delegate; - self.actionBlock = ^{ - [[MVMCoreActionHandler sharedActionHandler] handleActionWithDictionary:actionMap additionalData:additionalData delegate:weakDelegate]; - }; - } - return self; -} - -- (void)setup { - if (!self.label) { - MFLabel *label = [[MFLabel alloc] initWithFrame:CGRectZero]; - - self.backgroundColor = [UIColor clearColor]; - label.translatesAutoresizingMaskIntoConstraints = NO; - label.userInteractionEnabled = NO; - label.numberOfLines = 0; - label.lineBreakMode = NSLineBreakByWordWrapping; - [label setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; - [self addSubview:label]; - [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[label]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(label)]]; - [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[label]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(label)]]; - - - self.label = label; - [label sizeToFit]; - } - - if (!self.normalTextColor) { - self.normalTextColor = [UIColor blackColor]; - } - if (!self.actionTextColor) { - self.actionTextColor = [UIColor blackColor]; - } - if (!self.normalTextFont) { - self.normalTextFont = [MFStyler fontB2]; - } - if (!self.actionTextFont) { - self.actionTextFont = [MFStyler fontB2]; - } - - //adding the underline - [self setAlternateActionTextAttributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)}]; - - self.label.attributedText = self.attributedText; - [self.label setAccessibilityTraits:UIAccessibilityTraitButton]; -} - -- (void)updateView:(CGFloat)size { - //reset font for app size change - self.normalTextFont = [MFStyler fontB2]; - self.actionTextFont = [MFStyler fontB2]; - self.label.attributedText = self.attributedText; -} - -#pragma mark - UIControl overide - -- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - if ([self areTouchesInActionString:touches]) { - [self sendActionsForControlEvents:UIControlEventTouchUpInside]; - [self performAction]; - } else { - [self sendActionsForControlEvents:UIControlEventTouchUpOutside]; - } -} - -#pragma mark - helper - -- (NSString *)getTextFromStringComponents { - if (self.frontText.length == 0) { - self.frontText = @""; - } else { - self.frontText = [self.frontText stringByAppendingString:[self spaceBetweenPartOne:self.frontText andPartTwo:self.actionText]]; - } - if (self.actionText.length == 0) { - self.actionText = @""; - } else { - self.actionText = [self.actionText stringByAppendingString:[self spaceBetweenPartOne:self.actionText andPartTwo:self.backText]]; - } - if (self.backText.length == 0) { - self.backText = @""; - } - return [[NSString alloc] initWithFormat:@"%@%@%@",self.frontText, self.actionText, self.backText]; -} - -- (NSString *)spaceBetweenPartOne:(NSString *)partOne andPartTwo:(NSString *)partTwo { - /*if (!partTwo || partTwo.length == 0 || [MFUtility validateString:partTwo withRegularExpression:@"[.,?!;:]"] || [partOne hasSuffix:@" "]) { - return @""; - }*/ - return @" "; -} - -- (NSRange)getActionRange { - return NSMakeRange(self.frontText.length, self.actionText.length); -} - -- (NSRange)getFrontRange { - return NSMakeRange(0, self.frontText.length); -} - -- (NSRange)getBackRange { - return NSMakeRange(self.frontText.length + self.actionText.length, self.backText.length);} - -- (void)performAction { - if (self.actionBlock) { - self.actionBlock(); - } -} - -- (NSArray *)getRangeArrayOfWordsInString:(NSString *)string withInitalIndex:(NSInteger)index { - NSArray *words = [string componentsSeparatedByString:@" "]; - NSMutableArray *rangeArray = [[NSMutableArray alloc] init]; - for (NSString *subString in words) { - NSString *finalSubString = [subString stringByAppendingString:@" "]; - NSInteger wordIndex = index; - NSInteger length = finalSubString.length; - NSRange subStringRange = NSMakeRange(wordIndex, length); - NSValue *rangeValue = [NSValue valueWithRange:subStringRange]; - [rangeArray addObject:rangeValue]; - index += length; - } - return rangeArray; -} - -- (NSArray *)getRectArrayFromRangeArray:(NSArray *)rangeArray { - NSMutableArray *rectArray = [[NSMutableArray alloc] init]; - for (NSValue *aValueOfRange in rangeArray) { - NSRange wordRange = [aValueOfRange rangeValue]; - CGRect rect = [self.label boundingRectForCharacterRange:wordRange]; - NSValue *rectValue = [NSValue valueWithCGRect:rect]; - [rectArray addObject:rectValue]; - } - return rectArray; -} - -- (BOOL)areTouchesInActionString:(NSSet *)touches { - if (UIAccessibilityIsVoiceOverRunning() || self.makeWholeViewClickable) { - return YES; - } - CGPoint location = [[touches anyObject] locationInView:self.label]; - NSString *actionString = self.actionText; - NSInteger index = [self getActionRange].location; - NSArray *rangeArray = [self getRangeArrayOfWordsInString:actionString withInitalIndex:index]; - NSArray *rectArray = [self getRectArrayFromRangeArray:rangeArray]; - BOOL result = NO; - for (NSValue *aValueOfRect in rectArray) { - CGRect wordRect = [aValueOfRect CGRectValue]; - if (CGRectContainsPoint(wordRect, location)){ - result = YES; - break; - } else if (wordRect.origin.x == 0 && wordRect.origin.y == 0 && wordRect.size.height == 0 && wordRect.size.width == 0) { - //incase word rect is not found for any reason, make the whole label to be clicable to avoid non functioning link in production. - result = YES; - break; - } - } - return result; -} - - -#pragma mark - setter - -- (void)setText:(NSString *)text { - if (text) { - _text = text; - - self.attributedText = [[NSAttributedString alloc] initWithString:text]; - //call the setters to properly set the attributes - [self setNormalTextFont:self.normalTextFont]; - [self setActionTextFont:self.actionTextFont]; - [self setNormalTextColor:self.normalTextColor]; - [self setActionTextColor:self.actionTextColor]; - - } -} - - -- (void)setCurlyBracedText:(nonnull NSString *)text { - [self setText:text startTag:@"{" endTag:@"}"]; -} - -- (void)setText:(NSString *)text startTag:(NSString *)startTag endTag:(NSString *)endTag { - NSRange actionRange = [self rangeOfText:&text startTag:startTag endTag:endTag]; - self.frontText = [text substringWithRange:NSMakeRange(0,actionRange.location)]; - self.actionText = [text substringWithRange:actionRange]; - self.backText = [text substringWithRange:NSMakeRange(self.frontText.length+self.actionText.length, text.length - self.frontText.length-self.actionText.length)]; - self.text = [self getTextFromStringComponents]; - [self setup]; -} - -- (NSRange)rangeOfCurlyBracedText:(NSString **)text { - return [self rangeOfText:text startTag:@"{" endTag:@"}"]; -} - -- (NSRange)rangeOfText:(NSString **)text startTag:(NSString *)startTag endTag:(NSString *)endTag { - - NSString *fullText = *text; - NSRange range = NSMakeRange(0, 0); - NSRange rangeOfLeftBrace = [fullText rangeOfString:startTag]; - - if (rangeOfLeftBrace.location != NSNotFound) { - - fullText = [fullText stringByReplacingCharactersInRange:rangeOfLeftBrace withString:@""]; - NSRange rangeOfRightBrace = [fullText rangeOfString:endTag]; - - if (rangeOfRightBrace.location != NSNotFound) { - - NSInteger length = (rangeOfRightBrace.location - rangeOfLeftBrace.location); - - if (length > 0) { - range = NSMakeRange(rangeOfLeftBrace.location, length); - fullText = [fullText stringByReplacingCharactersInRange:rangeOfRightBrace withString:@""]; - } - } - } - *text = fullText; - - return range; -} - -- (void)setNormalTextColor:(UIColor *)normalTextColor { - if (normalTextColor) { - _normalTextColor = normalTextColor; - [self setAlternateNormalTextAttributes:@{NSForegroundColorAttributeName:normalTextColor}]; - } -} - -- (void)setActionTextColor:(UIColor *)actionTextColor { - if (actionTextColor) { - _actionTextColor = actionTextColor; - [self setAlternateActionTextAttributes:@{NSForegroundColorAttributeName:actionTextColor}]; - } -} - -- (void)setAttributedText:(NSAttributedString *)attributedText { - _attributedText = attributedText; - NSMutableAttributedString *mutableAttributedText = [attributedText mutableCopy]; - NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; - paragraphStyle.lineSpacing = LabelWithInternalButtonLineSpace; - [mutableAttributedText addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, attributedText.length)]; - - if (self.label && mutableAttributedText) { - self.label.attributedText = mutableAttributedText; - } - -} - -- (void)setNormalTextFont:(UIFont *)normalTextFont { - if (normalTextFont) { - _normalTextFont = normalTextFont; - [self setAlternateNormalTextAttributes:@{NSFontAttributeName:normalTextFont}]; - } -} - -- (void)setActionTextFont:(UIFont *)actionTextFont { - if (actionTextFont) { - _actionTextFont = actionTextFont; - [self setAlternateActionTextAttributes:@{NSFontAttributeName:actionTextFont}]; - } -} - -- (void)setActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate { - [self setActionMap:actionMap additionalData:additionalData actionDelegate:delegate buttonDelegate:nil]; -} - -// Reset the text and action map -- (void)setTextWithClickableTextEmbeddedInCurlyBraces:(nullable NSString *)text textAttributes:(nullable NSDictionary *)attributes actionMapForClickableText:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate { - - self.attributedText = [[NSAttributedString alloc] initWithString:text attributes:attributes]; - [self setActionMap:actionMap additionalData:additionalData actionDelegate:delegate]; -} - -- (void)setWithText:(nullable NSString *)fullText startTag:(nullable NSString *)startTag endTag:(nullable NSString *)endTag actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)delegate { - [self setText:fullText startTag:startTag endTag:endTag]; - [self setActionMap:actionMap additionalData:additionalData actionDelegate:delegate]; -} - -- (void)setEnabled:(BOOL)enabled { - [super setEnabled:enabled]; - if (enabled) { - self.alpha = 1; - } else { - self.alpha = DisableOppacity; - } -} - -- (void)setFrontText:(NSString *)frontText actionMap:(NSDictionary *)actionMap backText:(NSString *)backText additionalData:(NSDictionary *)additionalData delegate:(nullable NSObject *)delegate { - [self setFrontText:frontText actionMap:actionMap backText:backText additionalData:additionalData delegate:delegate buttonDelegate:nil]; -} - -// Reset the front text, back text, action map -- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backAttributedText additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate { - [self setFrontAttributedText:frontAttributedText actionMap:actionMap backAttributedText:backAttributedText addNewLine:NO additionalData:additionalData delegate:delegate]; -} - -- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backAttributedText addNewLine:(BOOL) addNewLine additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate { - - [self setFrontAttributedText:frontAttributedText actionMap:actionMap backAttributedText:backAttributedText addNewLine:addNewLine additionalData:additionalData delegate:delegate buttonDelegate:nil]; -} - -- (void)setAlignment:(NSTextAlignment)textAlignment { - self.label.textAlignment = textAlignment; -} - -- (void)setAlternateActionTextAttributes:(nullable NSDictionary *)attributes { - if (attributes) { - NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText]; - [attributedString addAttributes:attributes range:[self getActionRange]]; - self.attributedText = attributedString; - } -} - -- (void)setAlternateNormalTextAttributes:(nullable NSDictionary *)attributes { - if (attributes) { - NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText]; - [attributedString addAttributes:attributes range:[self getFrontRange]]; - [attributedString addAttributes:attributes range:[self getBackRange]]; - - self.attributedText = attributedString; - } -} - -- (void)setActionTextString:(nullable NSString *)actionText { - self.actionText = actionText; - self.text = [self getTextFromStringComponents]; - [self setup]; -} - -/// Used to just reset the texts and actions if already initialized -- (void)resetWithActionMap:(NSDictionary *)actionMap additionalData:(NSDictionary *)additionalData delegate:(NSObject *)delegate { - - self.frontText = [actionMap stringForKey:KeyTitlePrefix]; - self.actionText = [actionMap stringForKey:KeyTitle]; - self.backText = [actionMap stringForKey:KeyTitlePostfix]; - - - __weak typeof(delegate) weakDelegate = delegate; - self.actionBlock = ^{ - [[MVMCoreActionHandler sharedActionHandler] handleActionWithDictionary:actionMap additionalData:additionalData delegate:weakDelegate]; - }; - - self.text = [self getTextFromStringComponents]; - [self setup]; -} - -//#pragma mark - Accessibility -// -//-(BOOL)isAccessibilityElement{ -// return YES; -//} -// -//-(UIAccessibilityTraits)accessibilityTraits{ -// return UIAccessibilityTraitLink; -//} - -- (NSString *)replaceSpaceWithFakeSpace:(NSString *)string { - NSArray *words = [string componentsSeparatedByString:@" "]; - return [words componentsJoinedByString:@"\u00a0"]; -} -- (BOOL)accessibilityActivate { - if (self.actionBlock) { - self.actionBlock(); - return YES; - } else { - return NO; - } - -} - -- (UIAccessibilityCustomAction *)accessibilityCustomAction { - if (self.actionText.length) { - NSString *name = self.actionText; - return [[UIAccessibilityCustomAction alloc] initWithName:name target:self selector:@selector(accessibilityActivate)]; - } else { - return [[UIAccessibilityCustomAction alloc] init]; - } - -} -@end diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift new file mode 100644 index 00000000..c87f0c54 --- /dev/null +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -0,0 +1,647 @@ +// +// LabelWithInternalButton.swift +// MVMCoreUI +// +// Created by Chris Yang on 2/25/16. +// Converted by Christiano, Kevin on 3/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import MVMCore + +public typealias ActionBlock = () -> Void +public typealias ActionObjectDelegate = (NSObject & MVMCoreActionDelegateProtocol) +public typealias ButtonObjectDelegate = (NSObject & ButtonDelegateProtocol) +public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProtocol & MVMCoreLoadDelegateProtocol & MVMCorePresentationDelegateProtocol & NSObjectProtocol + + +@objcMembers open class LabelWithInternalButton: UIControl, MVMCoreViewProtocol, MFButtonProtocol { + //------------------------------------------------------ + // MARK: - Properties + //------------------------------------------------------ + + public var actionBlock: ActionBlock? + public weak var label: MFLabel? + + public var alternateAttributeForActionText: String? + + public var attributedText: NSAttributedString? { + didSet(newAttributedText) { + if newAttributedText != nil { + let mutableAttributedText = newAttributedText as? NSMutableAttributedString + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineSpacing = CGFloat(LabelWithInternalButtonLineSpace) + mutableAttributedText?.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: newAttributedText?.length ?? 0)) + + if let mutableAttText = mutableAttributedText { + label?.attributedText = mutableAttText + } + } + } + } + + // By default, it will follow most of the font standard in zepplin, and should need to be changed + public var normalTextFont: UIFont? + public var actionTextFont: UIFont? + public var normalTextColor: UIColor? + public var actionTextColor: UIColor? + + public var makeWholeViewClickable = false + + override open var isEnabled: Bool { + didSet { + alpha = isEnabled ? 1 : DisableOppacity + } + } + + public var frontText: String? + public var actionText: String? + public var backText: String? + + public var text: String? { + didSet(newText) { + if newText != nil { + attributedText = NSAttributedString(string: newText ?? "") + setAlternateNormalTextAttributes([NSAttributedString.Key.font: normalTextFont as Any]) + setAlternateActionTextAttributes([NSAttributedString.Key.font: actionTextFont as Any]) + setAlternateNormalTextAttributes([NSAttributedString.Key.foregroundColor: normalTextColor as Any]) + setAlternateActionTextAttributes([NSAttributedString.Key.foregroundColor: actionTextColor as Any]) + } + } + } + + //------------------------------------------------------ + // MARK: - Initializaers + //------------------------------------------------------ + + public init() { + super.init(frame: CGRect.zero) + setup() + } + + required public init?(coder: NSCoder) { + super.init(coder: coder) + setup() + } + + override public init(frame: CGRect) { + super.init(frame: frame) + 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) + self.frontText = frontText + self.actionText = actionText + self.backText = backText + actionBlock = block + text = getTextFromStringComponents() + setup() + } + + 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) + } + + 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) + } + + // 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 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) + } + } + + //------------------------------------------------------ + // MARK: - Configuration + //------------------------------------------------------ + + private func setup() { + + if self.label == nil { + let label = MFLabel(frame: CGRect.zero) + + backgroundColor = .clear + label.translatesAutoresizingMaskIntoConstraints = false + label.isUserInteractionEnabled = false + label.numberOfLines = 0 + label.lineBreakMode = NSLineBreakMode.byWordWrapping + label.setContentCompressionResistancePriority(.required, for: .vertical) + addSubview(label) + NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[label]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["label": label])) + NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[label]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["label": label])) + + self.label = label + label.sizeToFit() + } + + if normalTextColor == nil { + normalTextColor = .black + } + + if actionTextColor == nil { + actionTextColor = .black + } + + if normalTextFont == nil { + normalTextFont = MFStyler.fontB2() + } + + if actionTextFont == nil { + actionTextFont = MFStyler.fontB2() + } + + //adding the underline + setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)]) + + self.label?.attributedText = attributedText + self.label?.accessibilityTraits = .button + } + + 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) + } + + if let wDelegate = weakDelegate as? CoreObjectActionLoadPresentDelegate, performAction { + MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: wDelegate ) + } + } + } + + //------------------------------------------------------ + // 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?) { + + self.frontText = frontText + setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate) + 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?) { + + setFrontAttributedText(frontAttributedText, actionMap: actionMap, backAttributedText: backText, addNewLine: false, additionalData: additionalData, delegate: delegate, buttonDelegate: buttonDelegate) + } + + 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 + } + + let newLineAttributed = addNewLine ? "\n" : " " + + if let actions = actionMap, let actionMapCount = actionMap?.keys.count, actionMapCount > 0 { + + var actionString = actions.stringForkey(KeyTitle) + + if !actionString.isEmpty { + + actionString += newLineAttributed + + var actionAttributedString: NSAttributedString? + + if let b2Font = MFStyler.fontB2() { + actionAttributedString = MFStyler.styleGetAttributedString(actionString, font: b2Font, color: .black) + } + + actionText = actionString + setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate) + + if let actionAttribString = actionAttributedString { + mutableAttributedString.append(actionAttribString) + } + } + } 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)]) + } + + @objc public func updateView(_ size: CGFloat) { + + //reset font for app size change + normalTextFont = MFStyler.fontB2() + actionTextFont = MFStyler.fontB2() + label?.attributedText = attributedText + } + + //------------------------------------------------------ + // MARK: - UIControl Override + //------------------------------------------------------ + + override open func touchesEnded(_ touches: Set, with event: UIEvent?) { + + if areTouches(inActionString: touches) { + sendActions(for: .touchUpInside) + if let action = actionBlock { + action() + } + } else { + sendActions(for: .touchUpOutside) + } + } + + private func areTouches(inActionString touches: Set?) -> Bool { + + if UIAccessibility.isVoiceOverRunning || makeWholeViewClickable { + return true + } + + let location: CGPoint? = touches?.first?.location(in: label) + let actionString = actionText + let index: Int = getActionRange().location + let rangeArray = getRangeArrayOfWords(in: actionString, withInitalIndex: index) + let rectArray = getRectArray(fromRangeArray: rangeArray) + var result = false + + for aValueOfRect in rectArray as? [NSValue] ?? [] { + let wordRect: CGRect = aValueOfRect.cgRectValue + + if let position = location, wordRect.contains(position) { + result = true + break + } else if wordRect.origin.x == 0 && wordRect.origin.y == 0 && wordRect.size.height == 0 && wordRect.size.width == 0 { + //incase word rect is not found for any reason, make the whole label to be clicable to avoid non functioning link in production. + result = true + break + } + } + + return result + } + + //------------------------------------------------------ + // MARK: - Helper + //------------------------------------------------------ + + private func getTextFromStringComponents() -> String? { + + if let frontTxt = frontText, !frontTxt.isEmpty { + frontText?.append(" ") + } + + if let actionTxt = actionText, !actionTxt.isEmpty { + actionText?.append(" ") + } + + return "\(frontText ?? "")\(actionText ?? "")\(backText ?? "")" + } + + private func getActionRange() -> NSRange { + + return NSRange(location: frontText?.count ?? 0, length: actionText?.count ?? 0) + } + + private func getFrontRange() -> NSRange { + + return NSRange(location: 0, length: frontText?.count ?? 0) + } + + private func getBackRange() -> NSRange { + + return NSRange(location: (frontText?.count ?? 0) + (actionText?.count ?? 0), length: backText?.count ?? 0) + } + + private func getRangeArrayOfWords(in string: String?, withInitalIndex index: Int) -> [Any]? { + + var index = index + let words = string?.components(separatedBy: " ") + var rangeArray = [AnyHashable]() + + for subString in words ?? [] { + let finalSubString = subString + (" ") + let wordIndex: Int = index + let length: Int = finalSubString.count + let subStringRange = NSRange(location: wordIndex, length: length) + let rangeValue = NSValue(range: subStringRange) + rangeArray.append(rangeValue) + index += length + } + + return rangeArray + } + + private func getRectArray(fromRangeArray rangeArray: [Any]?) -> [Any]? { + + var rectArray = [AnyHashable]() + + for aValueOfRange in rangeArray as? [NSValue] ?? [] { + let wordRange: NSRange = aValueOfRange.rangeValue + if let rect: CGRect = label?.boundingRect(forCharacterRange: wordRange) { + let rectValue = NSValue(cgRect: rect) + rectArray.append(rectValue) + } + } + + return rectArray + } + + @objc public func setCurlyBracedText(_ text: String) { + + setText(text, startTag: "{", endTag: "}") + } + + private func setText(_ text: String?, startTag: String?, endTag: String?) { + + let _text = text + let actionRange: NSRange = rangeOfText(_text, startTag: startTag, endTag: endTag) + + frontText = (_text as NSString?)?.substring(with: NSRange(location: 0, length: actionRange.location)) + actionText = (_text as NSString?)?.substring(with: actionRange) + + if let frontTextCount = frontText?.count, let actiontextCount = actionText?.count { + backText = (_text as NSString?)?.substring(with: NSRange(location: frontTextCount + actiontextCount, length: (_text?.count ?? 0) - frontTextCount - actiontextCount)) + } + + self.text = getTextFromStringComponents() + setup() + } + + // Not used + private func rangeOfCurlyBracedText(_ text: String?) -> NSRange { + + return rangeOfText(text, startTag: "{", endTag: "}") + } + + // TODO: Review this + private func rangeOfText(_ text: String?, startTag: String?, endTag: String?) -> NSRange { + + var fullText = text + var range = NSRange(location: 0, length: 0) + let rangeOfLeftBrace: NSRange? = (fullText as NSString?)?.range(of: startTag ?? "") + + if rangeOfLeftBrace?.location != NSNotFound { + + if let rangeOfLeftBrace = rangeOfLeftBrace { + fullText = (fullText as NSString?)?.replacingCharacters(in: rangeOfLeftBrace, with: "") + } + let rangeOfRightBrace: NSRange? = (fullText as NSString?)?.range(of: endTag ?? "") + + if rangeOfRightBrace?.location != NSNotFound { + + let length: Int = (rangeOfRightBrace?.location ?? 0) - (rangeOfLeftBrace?.location ?? 0) + + if length > 0 { + range = NSRange(location: rangeOfLeftBrace?.location ?? 0, length: length) + if let rangeOfRightBrace = rangeOfRightBrace { + fullText = (fullText as NSString?)?.replacingCharacters(in: rangeOfRightBrace, with: "") + } + } + } + } + + return range + } + + @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?) { + + attributedText = NSAttributedString(string: text ?? "", attributes: attributes as? [NSAttributedString.Key: Any]) + setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate) + } + + @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) + } + + @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 + @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) + } + + @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) + } + + @objc public func setAlignment(_ textAlignment: NSTextAlignment) { + + label?.textAlignment = textAlignment + } + + @objc public func setAlternateActionTextAttributes(_ attributes: [AnyHashable: Any]?) { + + if let theseAttributes = attributes as? [NSAttributedString.Key: Any], let thisAttributedText = attributedText { + let attributedString = NSMutableAttributedString(attributedString: thisAttributedText) + attributedString.addAttributes(theseAttributes, range: getActionRange()) + attributedText = attributedString + } + } + + @objc public func setAlternateNormalTextAttributes(_ attributes: [AnyHashable: Any]?) { + + if let thisAttributedText = attributedText, let theseAttributes = attributes as? [NSAttributedString.Key: Any] { + let attributedString = NSMutableAttributedString(attributedString: thisAttributedText) + attributedString.addAttributes(theseAttributes, range: getFrontRange()) + attributedString.addAttributes(theseAttributes, range: getBackRange()) + attributedText = attributedString + } + } + + @objc public func setActionTextString(_ actionText: String?) { + + self.actionText = actionText + text = getTextFromStringComponents() + setup() + } + + /// Used to just reset the texts and actions if already initialized + @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: - Accessibility + //------------------------------------------------------ + + // Not Used + @objc public func replaceSpace(withFakeSpace string: String?) -> String? { + + return string?.components(separatedBy: " ").joined(separator: "\u{00a0}") + } + + @objc override open func accessibilityActivate() -> Bool { + + if let action = actionBlock { + action() + return true + } + + return false + } + + @objc public func accessibilityCustomAction() -> UIAccessibilityCustomAction? { + + if let actionTxt = actionText, !actionTxt.isEmpty { + let name = actionTxt + return UIAccessibilityCustomAction(name: name, target: self, selector: #selector(LabelWithInternalButton.accessibilityCustomActions)) + } + + return UIAccessibilityCustomAction() + } + +} + + +extension LabelWithInternalButton: MVMCoreUIMoleculeViewProtocol { + //------------------------------------------------------ + // MARK: - Atomization + //------------------------------------------------------ + + // Default values for view. + @objc open func setAsMolecule() { + + /* + + var frontText: String? + var actionText: String? + var backText: String? + var attributedText: NSAttributedString? + // By default, it will follow most of the font standard in zepplin, and should need to be changed + var normalTextFont: UIFont? + var actionTextFont: UIFont? + var normalTextColor: UIColor? + var actionTextColor: UIColor? + var alternateAttributeForActionText: String? + var makeWholeViewClickable = false + */ + } + + @objc open func setWithJSON(_ json: [AnyHashable: Any]?, delegate: NSObject?, additionalData: [AnyHashable: Any]?) { + + // Configure class properties with JSON values + guard let jsonDictionary = json else { return } + + if let backgroundColorHex = jsonDictionary[KeyBackgroundColor] as? String { + backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) + } + + // if let strokeColorHex = jsonDictionary["strokeColor"] as? String { + // strokeColor = UIColor.mfGet(forHex: strokeColorHex) + // } + // + // if let isHiddenValue = jsonDictionary[KeyIsHidden] as? Bool { + // isHidden = isHiddenValue + // } + // + // if let isOpaqueValue = jsonDictionary[KeyIsOpaque] as? Bool { + // isOpaque = isOpaqueValue + // } + // + // if let lineWidthValue = jsonDictionary["lineWidth"] as? CGFloat { + // lineWidth = lineWidthValue + // } + + + } + +} diff --git a/MVMCoreUI/MVMCoreUI.h b/MVMCoreUI/MVMCoreUI.h index 53ceeb3e..fea15913 100644 --- a/MVMCoreUI/MVMCoreUI.h +++ b/MVMCoreUI/MVMCoreUI.h @@ -74,7 +74,6 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[]; #pragma mark Views #import #import -#import #import #import #import From c791d7867185109239f010e10bfb2a3c01cba93a Mon Sep 17 00:00:00 2001 From: "Christiano, Kevin" Date: Fri, 29 Mar 2019 16:37:51 -0400 Subject: [PATCH 02/13] Working with ranges. Overall improvement of swift code. --- .../Atoms/Views/LabelWithInternalButton.swift | 254 +++++++++--------- 1 file changed, 122 insertions(+), 132 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index c87f0c54..10ad74dd 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -10,6 +10,7 @@ import MVMCore public typealias ActionBlock = () -> Void +private typealias ActionIndiciesTuple = (startIndex: String.Index?, endIndex: String.Index?, revisedText: String?) public typealias ActionObjectDelegate = (NSObject & MVMCoreActionDelegateProtocol) public typealias ButtonObjectDelegate = (NSObject & ButtonDelegateProtocol) public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProtocol & MVMCoreLoadDelegateProtocol & MVMCorePresentationDelegateProtocol & NSObjectProtocol @@ -23,15 +24,18 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt public var actionBlock: ActionBlock? public weak var label: MFLabel? - public var alternateAttributeForActionText: String? + // FIXME: I think there are scenarios where attributed text is being set with attributes but there is no text to set. public var attributedText: NSAttributedString? { didSet(newAttributedText) { - if newAttributedText != nil { - let mutableAttributedText = newAttributedText as? NSMutableAttributedString + if let newAttribText = newAttributedText, !newAttribText.string.isEmpty { + let mutableAttributedText = newAttribText as? NSMutableAttributedString let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = CGFloat(LabelWithInternalButtonLineSpace) - mutableAttributedText?.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: newAttributedText?.length ?? 0)) + + if newAttribText.length > 0 { + mutableAttributedText?.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: newAttribText.length)) + } if let mutableAttText = mutableAttributedText { label?.attributedText = mutableAttText @@ -41,10 +45,10 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt } // By default, it will follow most of the font standard in zepplin, and should need to be changed - public var normalTextFont: UIFont? - public var actionTextFont: UIFont? - public var normalTextColor: UIColor? - public var actionTextColor: UIColor? + public var normalTextFont: UIFont? = MFStyler.fontB2() + public var actionTextFont: UIFont? = MFStyler.fontB2() + public var normalTextColor: UIColor = .black + public var actionTextColor: UIColor = .black public var makeWholeViewClickable = false @@ -89,13 +93,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt setup() } - public init(frontText: String?, - actionText: String?, - backText: String?, - actionMap: [AnyHashable: Any]?, - additionalData: [AnyHashable: Any]?, - actionDelegate delegate: ActionObjectDelegate?, - buttonDelegate: ButtonObjectDelegate?) { + 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) @@ -103,6 +101,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt // MARK: - legacy public init(frontText: String?, actionText: String?, backText: String?, actionBlock block: ActionBlock?) { + super.init(frame: CGRect.zero) self.frontText = frontText self.actionText = actionText @@ -112,18 +111,9 @@ 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]?, 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) + 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?) { @@ -187,22 +177,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt label.sizeToFit() } - if normalTextColor == nil { - normalTextColor = .black - } - - if actionTextColor == nil { - actionTextColor = .black - } - - if normalTextFont == nil { - normalTextFont = MFStyler.fontB2() - } - - if actionTextFont == nil { - actionTextFont = MFStyler.fontB2() - } - //adding the underline setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)]) @@ -210,7 +184,8 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt self.label?.accessibilityTraits = .button } - private func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) { + private func + setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) { weak var weakSelf: LabelWithInternalButton? = self weak var weakDelegate: ActionObjectDelegate? = delegate @@ -303,7 +278,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt @objc public func updateView(_ size: CGFloat) { - //reset font for app size change + // Reset font for app size change normalTextFont = MFStyler.fontB2() actionTextFont = MFStyler.fontB2() label?.attributedText = attributedText @@ -364,7 +339,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt frontText?.append(" ") } - if let actionTxt = actionText, !actionTxt.isEmpty { + if let actionTxt = actionText, !actionTxt.isEmpty, let backTxt = backText, !backTxt.isEmpty { actionText?.append(" ") } @@ -376,16 +351,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt return NSRange(location: frontText?.count ?? 0, length: actionText?.count ?? 0) } - private func getFrontRange() -> NSRange { - - return NSRange(location: 0, length: frontText?.count ?? 0) - } - - private func getBackRange() -> NSRange { - - return NSRange(location: (frontText?.count ?? 0) + (actionText?.count ?? 0), length: backText?.count ?? 0) - } - private func getRangeArrayOfWords(in string: String?, withInitalIndex index: Int) -> [Any]? { var index = index @@ -427,54 +392,42 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt private func setText(_ text: String?, startTag: String?, endTag: String?) { - let _text = text - let actionRange: NSRange = rangeOfText(_text, startTag: startTag, endTag: endTag) + guard let actionRange: ActionIndiciesTuple = rangeOfText(text, startTag: startTag, endTag: endTag) else { return } - frontText = (_text as NSString?)?.substring(with: NSRange(location: 0, length: actionRange.location)) - actionText = (_text as NSString?)?.substring(with: actionRange) - - if let frontTextCount = frontText?.count, let actiontextCount = actionText?.count { - backText = (_text as NSString?)?.substring(with: NSRange(location: frontTextCount + actiontextCount, length: (_text?.count ?? 0) - frontTextCount - actiontextCount)) + if let revisedText = actionRange.revisedText, let startBraceIndex = actionRange.startIndex, let endBraceIndex = actionRange.endIndex { + + frontText = String(revisedText[revisedText.startIndex.. NSRange { + + private func rangeOfText(_ text: String?, startTag: String?, endTag: String?) -> ActionIndiciesTuple? { - return rangeOfText(text, startTag: "{", endTag: "}") - } - - // TODO: Review this - private func rangeOfText(_ text: String?, startTag: String?, endTag: String?) -> NSRange { + var fullText = text ?? "" - var fullText = text - var range = NSRange(location: 0, length: 0) - let rangeOfLeftBrace: NSRange? = (fullText as NSString?)?.range(of: startTag ?? "") + guard let start = startTag, let end = endTag else { return nil } - if rangeOfLeftBrace?.location != NSNotFound { - - if let rangeOfLeftBrace = rangeOfLeftBrace { - fullText = (fullText as NSString?)?.replacingCharacters(in: rangeOfLeftBrace, with: "") - } - let rangeOfRightBrace: NSRange? = (fullText as NSString?)?.range(of: endTag ?? "") - - if rangeOfRightBrace?.location != NSNotFound { - - let length: Int = (rangeOfRightBrace?.location ?? 0) - (rangeOfLeftBrace?.location ?? 0) - - if length > 0 { - range = NSRange(location: rangeOfLeftBrace?.location ?? 0, length: length) - if let rangeOfRightBrace = rangeOfRightBrace { - fullText = (fullText as NSString?)?.replacingCharacters(in: rangeOfRightBrace, with: "") - } - } - } + if !fullText.contains(Character(start)) && !fullText.contains(Character(end)) { + return nil } - return range + var actionRange: ActionIndiciesTuple + + if let leftBrace = startTag, let rightBrace = endTag { + actionRange.startIndex = fullText.firstIndex(of: Character(leftBrace)) + fullText = fullText.replacingOccurrences(of: leftBrace, with: "") + + actionRange.endIndex = fullText.firstIndex(of: Character(rightBrace)) + fullText = fullText.replacingOccurrences(of: rightBrace, with: "") + } + + self.text = fullText + actionRange.revisedText = fullText + return actionRange } @objc public func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) { @@ -520,21 +473,38 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt if let theseAttributes = attributes as? [NSAttributedString.Key: Any], let thisAttributedText = attributedText { let attributedString = NSMutableAttributedString(attributedString: thisAttributedText) - attributedString.addAttributes(theseAttributes, range: getActionRange()) + if !attributedString.string.isEmpty { + attributedString.addAttributes(theseAttributes, range: getActionRange()) + } attributedText = attributedString } } @objc public func setAlternateNormalTextAttributes(_ attributes: [AnyHashable: Any]?) { - if let thisAttributedText = attributedText, let theseAttributes = attributes as? [NSAttributedString.Key: Any] { - let attributedString = NSMutableAttributedString(attributedString: thisAttributedText) - attributedString.addAttributes(theseAttributes, range: getFrontRange()) - attributedString.addAttributes(theseAttributes, range: getBackRange()) + if let _attributedText = attributedText, let _attributes = attributes as? [NSAttributedString.Key: Any] { + let attributedString = NSMutableAttributedString(attributedString: _attributedText) + if !attributedString.string.isEmpty { + attributedString.addAttributes(_attributes, range: getFrontRange()) + attributedString.addAttributes(_attributes, range: getBackRange()) + } attributedText = attributedString } } + private func getFrontRange() -> NSRange { + + return NSRange(location: 0, length: frontText?.count ?? 0) + } + + private func getBackRange() -> NSRange { + + let textLocation: Int = (frontText?.count ?? 0) + (actionText?.count ?? 0) + let rangeLength: Int = backText?.count ?? 0 + + return NSRange(location: textLocation, length: rangeLength) + } + @objc public func setActionTextString(_ actionText: String?) { self.actionText = actionText @@ -588,10 +558,8 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt return UIAccessibilityCustomAction() } - } - extension LabelWithInternalButton: MVMCoreUIMoleculeViewProtocol { //------------------------------------------------------ // MARK: - Atomization @@ -600,48 +568,70 @@ extension LabelWithInternalButton: MVMCoreUIMoleculeViewProtocol { // Default values for view. @objc open func setAsMolecule() { - /* - - var frontText: String? - var actionText: String? - var backText: String? - var attributedText: NSAttributedString? - // By default, it will follow most of the font standard in zepplin, and should need to be changed - var normalTextFont: UIFont? - var actionTextFont: UIFont? - var normalTextColor: UIColor? - var actionTextColor: UIColor? - var alternateAttributeForActionText: String? - var makeWholeViewClickable = false - */ } @objc open func setWithJSON(_ json: [AnyHashable: Any]?, delegate: NSObject?, additionalData: [AnyHashable: Any]?) { // 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 { - backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) + if let backgroundColorHex = dictionary[KeyBackgroundColor] as? String { + self.backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) } - // if let strokeColorHex = jsonDictionary["strokeColor"] as? String { - // strokeColor = UIColor.mfGet(forHex: strokeColorHex) - // } - // - // if let isHiddenValue = jsonDictionary[KeyIsHidden] as? Bool { - // isHidden = isHiddenValue - // } - // - // if let isOpaqueValue = jsonDictionary[KeyIsOpaque] as? Bool { - // isOpaque = isOpaqueValue - // } - // - // if let lineWidthValue = jsonDictionary["lineWidth"] as? CGFloat { - // lineWidth = lineWidthValue - // } + if let normalTextFont = dictionary["normalTextFont"] as? String, let normalSize = dictionary["normalSize"] as? CGFloat { + self.normalTextFont = UIFont(name: normalTextFont, size: normalSize) + } + if let actionTextFont = dictionary["actionTextFont"] as? String, let actionSize = dictionary["actionSize"] as? CGFloat { + self.actionTextFont = UIFont(name: actionTextFont, size: actionSize) + } + if let normalTextColorHex = dictionary["normalTextColor"] as? String { + self.normalTextColor = UIColor.mfGet(forHex: normalTextColorHex) + } + + if let actionTextColorHex = dictionary["actionTextColor"] as? String { + self.actionTextColor = UIColor.mfGet(forHex: actionTextColorHex) + } + + if let makeWholeViewClickable = dictionary["makeWholeViewClickable"] as? Bool { + self.makeWholeViewClickable = makeWholeViewClickable + } + + if let frontText = dictionary["frontText"] as? String { + self.frontText = frontText + } + + if let backText = dictionary["backText"] as? String { + self.backText = backText + } + + if let actionText = dictionary["actionText"] as? String { + self.actionText = actionText + } + + // Want this to be last because it has a didSet feature. + if let text = dictionary["text"] as? String { + self.text = text + } } - } + + +/* + public var actionBlock: ActionBlock? + + public var alternateAttributeForActionText: String? + + let mutableAttributedText = newAttributedText as? NSMutableAttributedString + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineSpacing = CGFloat(LabelWithInternalButtonLineSpace) + mutableAttributedText?.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: newAttributedText?.length ?? 0)) + + + override open var isEnabled: Bool { + didSet { + alpha = isEnabled ? 1 : DisableOppacity + } + */ From 27127aacfb315687736999f4ea8aa0627b4d0c5f Mon Sep 17 00:00:00 2001 From: "Christiano, Kevin" Date: Sun, 31 Mar 2019 21:08:11 -0400 Subject: [PATCH 03/13] WIP. Issues from language paradigms. Further work to resolve. --- .../Atoms/Views/LabelWithInternalButton.swift | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index 10ad74dd..1ebe425e 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -45,10 +45,29 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt } // By default, it will follow most of the font standard in zepplin, and should need to be changed - public var normalTextFont: UIFont? = MFStyler.fontB2() - public var actionTextFont: UIFont? = MFStyler.fontB2() - public var normalTextColor: UIColor = .black - public var actionTextColor: UIColor = .black + public var normalTextFont: UIFont? = MFStyler.fontB2() { + didSet(newNormalFont) { + setAlternateNormalTextAttributes([NSAttributedString.Key.font: newNormalFont as Any]) + } + } + + public var actionTextFont: UIFont? = MFStyler.fontB2() { + didSet(newActionFont) { + setAlternateActionTextAttributes([NSAttributedString.Key.font: newActionFont as Any]) + } + } + + public var normalTextColor: UIColor = .black { + didSet(newNormalColor) { + setAlternateNormalTextAttributes([NSAttributedString.Key.foregroundColor: newNormalColor as Any]) + } + } + + public var actionTextColor: UIColor = .black { + didSet(newActionColor) { + setAlternateActionTextAttributes([NSAttributedString.Key.foregroundColor: newActionColor as Any]) + } + } public var makeWholeViewClickable = false @@ -333,7 +352,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt // MARK: - Helper //------------------------------------------------------ - private func getTextFromStringComponents() -> String? { + private func getTextFromStringComponents() -> String { if let frontTxt = frontText, !frontTxt.isEmpty { frontText?.append(" ") @@ -392,32 +411,27 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt private func setText(_ text: String?, startTag: String?, endTag: String?) { - guard let actionRange: ActionIndiciesTuple = rangeOfText(text, startTag: startTag, endTag: endTag) else { return } + let actionRange: ActionIndiciesTuple = rangeOfText(text, startTag: startTag, endTag: endTag) + + frontText = actionRange.revisedText if let revisedText = actionRange.revisedText, let startBraceIndex = actionRange.startIndex, let endBraceIndex = actionRange.endIndex { - + // TODO: Put some of this into a String Extension in MVMCore frontText = String(revisedText[revisedText.startIndex.. ActionIndiciesTuple? { + private func rangeOfText(_ text: String?, startTag: String?, endTag: String?) -> ActionIndiciesTuple { var fullText = text ?? "" - - guard let start = startTag, let end = endTag else { return nil } - - if !fullText.contains(Character(start)) && !fullText.contains(Character(end)) { - return nil - } - var actionRange: ActionIndiciesTuple - if let leftBrace = startTag, let rightBrace = endTag { + if let leftBrace = startTag, let rightBrace = endTag, fullText.contains(Character(leftBrace)) && fullText.contains(Character(rightBrace)) { actionRange.startIndex = fullText.firstIndex(of: Character(leftBrace)) fullText = fullText.replacingOccurrences(of: leftBrace, with: "") @@ -427,6 +441,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt self.text = fullText actionRange.revisedText = fullText + return actionRange } From f68c355527ebd5b1d1421517d7cb9ff530ac6d3d Mon Sep 17 00:00:00 2001 From: "Christiano, Kevin" Date: Mon, 1 Apr 2019 10:08:11 -0400 Subject: [PATCH 04/13] name issue came from property observers. NewValue only appears in willSet, not didSet. --- .../Atoms/Views/LabelWithInternalButton.swift | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index 1ebe425e..46f64280 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -24,8 +24,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt public var actionBlock: ActionBlock? public weak var label: MFLabel? - // FIXME: I think there are scenarios where attributed text is being set with attributes but there is no text to set. - public var attributedText: NSAttributedString? { didSet(newAttributedText) { if let newAttribText = newAttributedText, !newAttribText.string.isEmpty { @@ -82,14 +80,14 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt public var backText: String? public var text: String? { - didSet(newText) { - if newText != nil { + willSet(newText) { +// if newText != nil { attributedText = NSAttributedString(string: newText ?? "") setAlternateNormalTextAttributes([NSAttributedString.Key.font: normalTextFont as Any]) setAlternateActionTextAttributes([NSAttributedString.Key.font: actionTextFont as Any]) setAlternateNormalTextAttributes([NSAttributedString.Key.foregroundColor: normalTextColor as Any]) setAlternateActionTextAttributes([NSAttributedString.Key.foregroundColor: actionTextColor as Any]) - } +// } } } @@ -196,7 +194,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt label.sizeToFit() } - //adding the underline + // Adding the underline setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)]) self.label?.attributedText = attributedText @@ -423,6 +421,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt self.text = getTextFromStringComponents() } + self.text = actionRange.revisedText setup() } @@ -439,9 +438,8 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt fullText = fullText.replacingOccurrences(of: rightBrace, with: "") } - self.text = fullText - actionRange.revisedText = fullText + actionRange.revisedText = fullText return actionRange } From c5233a680d8c5e97f6fcfab4a5c7657a7c31c5e0 Mon Sep 17 00:00:00 2001 From: "Christiano, Kevin" Date: Mon, 1 Apr 2019 11:44:25 -0400 Subject: [PATCH 05/13] Further swapping of didSet/willSet. --- .../Atoms/Views/LabelWithInternalButton.swift | 90 +++++++------------ 1 file changed, 33 insertions(+), 57 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index 46f64280..ddbff108 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -25,7 +25,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt public weak var label: MFLabel? public var attributedText: NSAttributedString? { - didSet(newAttributedText) { + willSet(newAttributedText) { if let newAttribText = newAttributedText, !newAttribText.string.isEmpty { let mutableAttributedText = newAttribText as? NSMutableAttributedString let paragraphStyle = NSMutableParagraphStyle() @@ -44,25 +44,25 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt // By default, it will follow most of the font standard in zepplin, and should need to be changed public var normalTextFont: UIFont? = MFStyler.fontB2() { - didSet(newNormalFont) { + willSet(newNormalFont) { setAlternateNormalTextAttributes([NSAttributedString.Key.font: newNormalFont as Any]) } } public var actionTextFont: UIFont? = MFStyler.fontB2() { - didSet(newActionFont) { + willSet(newActionFont) { setAlternateActionTextAttributes([NSAttributedString.Key.font: newActionFont as Any]) } } public var normalTextColor: UIColor = .black { - didSet(newNormalColor) { + willSet(newNormalColor) { setAlternateNormalTextAttributes([NSAttributedString.Key.foregroundColor: newNormalColor as Any]) } } public var actionTextColor: UIColor = .black { - didSet(newActionColor) { + willSet(newActionColor) { setAlternateActionTextAttributes([NSAttributedString.Key.foregroundColor: newActionColor as Any]) } } @@ -81,13 +81,11 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt public var text: String? { willSet(newText) { -// if newText != nil { - attributedText = NSAttributedString(string: newText ?? "") - setAlternateNormalTextAttributes([NSAttributedString.Key.font: normalTextFont as Any]) - setAlternateActionTextAttributes([NSAttributedString.Key.font: actionTextFont as Any]) - setAlternateNormalTextAttributes([NSAttributedString.Key.foregroundColor: normalTextColor as Any]) - setAlternateActionTextAttributes([NSAttributedString.Key.foregroundColor: actionTextColor as Any]) -// } + attributedText = NSAttributedString(string: newText ?? "") + setAlternateNormalTextAttributes([NSAttributedString.Key.font: normalTextFont as Any]) + setAlternateActionTextAttributes([NSAttributedString.Key.font: actionTextFont as Any]) + setAlternateNormalTextAttributes([NSAttributedString.Key.foregroundColor: normalTextColor as Any]) + setAlternateActionTextAttributes([NSAttributedString.Key.foregroundColor: actionTextColor as Any]) } } @@ -111,15 +109,15 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt } 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) + self.frontText = frontText self.actionText = actionText self.backText = backText @@ -139,23 +137,19 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt } 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) } // 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) } @@ -226,7 +220,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt //------------------------------------------------------ @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) } @@ -289,7 +282,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt attributedText = mutableAttributedString - //added this line for underlining + // Added this line for underlining setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)]) } @@ -337,7 +330,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt result = true break } else if wordRect.origin.x == 0 && wordRect.origin.y == 0 && wordRect.size.height == 0 && wordRect.size.width == 0 { - //incase word rect is not found for any reason, make the whole label to be clicable to avoid non functioning link in production. + // Incase word rect is not found for any reason, make the whole label to be clicable to avoid non functioning link in production. result = true break } @@ -424,7 +417,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt self.text = actionRange.revisedText setup() } - + private func rangeOfText(_ text: String?, startTag: String?, endTag: String?) -> ActionIndiciesTuple { var fullText = text ?? "" @@ -484,25 +477,25 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt @objc public func setAlternateActionTextAttributes(_ attributes: [AnyHashable: Any]?) { - if let theseAttributes = attributes as? [NSAttributedString.Key: Any], let thisAttributedText = attributedText { - let attributedString = NSMutableAttributedString(attributedString: thisAttributedText) - if !attributedString.string.isEmpty { - attributedString.addAttributes(theseAttributes, range: getActionRange()) - } - attributedText = attributedString + guard let theseAttributes = attributes as? [NSAttributedString.Key: Any], let thisAttributedText = attributedText else { return } + let attributedString = NSMutableAttributedString(attributedString: thisAttributedText) + + if !attributedString.string.isEmpty { + attributedString.addAttributes(theseAttributes, range: getActionRange()) } + attributedText = attributedString } - @objc public func setAlternateNormalTextAttributes(_ attributes: [AnyHashable: Any]?) { + public func setAlternateNormalTextAttributes(_ attributes: [AnyHashable: Any]?) { - if let _attributedText = attributedText, let _attributes = attributes as? [NSAttributedString.Key: Any] { - let attributedString = NSMutableAttributedString(attributedString: _attributedText) - if !attributedString.string.isEmpty { - attributedString.addAttributes(_attributes, range: getFrontRange()) - attributedString.addAttributes(_attributes, range: getBackRange()) - } - attributedText = attributedString + guard let _attributedText = attributedText, let _attributes = attributes as? [NSAttributedString.Key: Any] else { return } + let attributedString = NSMutableAttributedString(attributedString: _attributedText) + + if !attributedString.string.isEmpty { + attributedString.addAttributes(_attributes, range: getFrontRange()) + attributedString.addAttributes(_attributes, range: getBackRange()) } + attributedText = attributedString } private func getFrontRange() -> NSRange { @@ -565,8 +558,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt @objc public func accessibilityCustomAction() -> UIAccessibilityCustomAction? { if let actionTxt = actionText, !actionTxt.isEmpty { - let name = actionTxt - return UIAccessibilityCustomAction(name: name, target: self, selector: #selector(LabelWithInternalButton.accessibilityCustomActions)) + return UIAccessibilityCustomAction(name: actionTxt, target: self, selector: #selector(LabelWithInternalButton.accessibilityCustomActions)) } return UIAccessibilityCustomAction() @@ -624,27 +616,11 @@ extension LabelWithInternalButton: MVMCoreUIMoleculeViewProtocol { self.actionText = actionText } - // Want this to be last because it has a didSet feature. + //public var actionBlock: ActionBlock? + + // Want this to be last because it has a willSet feature. if let text = dictionary["text"] as? String { self.text = text } } } - - -/* - public var actionBlock: ActionBlock? - - public var alternateAttributeForActionText: String? - - let mutableAttributedText = newAttributedText as? NSMutableAttributedString - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.lineSpacing = CGFloat(LabelWithInternalButtonLineSpace) - mutableAttributedText?.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: newAttributedText?.length ?? 0)) - - - override open var isEnabled: Bool { - didSet { - alpha = isEnabled ? 1 : DisableOppacity - } - */ From 16c644e12df047bec665877ad7142cde4cf326e8 Mon Sep 17 00:00:00 2001 From: "Christiano, Kevin" Date: Mon, 1 Apr 2019 13:28:15 -0400 Subject: [PATCH 06/13] Removed super call for setWithJSON. Provided more functionality for atom steup. --- MVMCoreUI/Atoms/Buttons/CaretButton.swift | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Atoms/Buttons/CaretButton.swift b/MVMCoreUI/Atoms/Buttons/CaretButton.swift index af7d1d60..c85093d4 100644 --- a/MVMCoreUI/Atoms/Buttons/CaretButton.swift +++ b/MVMCoreUI/Atoms/Buttons/CaretButton.swift @@ -52,7 +52,7 @@ open class CaretButton: MFCustomButton { public func setEnabled(_ enabled: Bool) { super.isEnabled = enabled - + changeCaretColor() } @@ -112,21 +112,31 @@ open class CaretButton: MFCustomButton { } @objc override open func setWithJSON(_ json: [AnyHashable: Any]?, delegate: NSObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegate: delegate, additionalData: additionalData) - - // Configure class properties with JSON values + guard let jsonDictionary = json else { return } if let backgroundColorHex = jsonDictionary[KeyBackgroundColor] as? String { backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) } - if let enableColorHex = jsonDictionary["enableColor"] as? String { + if let enableColorHex = jsonDictionary["enabledColor"] as? String { enabledColor = UIColor.mfGet(forHex: enableColorHex) } if let disabledColorHex = jsonDictionary["disabledColor"] as? String { disabledColor = UIColor.mfGet(forHex: disabledColorHex) } + + if let caretViewHeight = jsonDictionary["caretViewHeight"] as? NSNumber { + rightViewHeight = caretViewHeight + } + + if let caretViewWidth = jsonDictionary["caretViewWidth"] as? NSNumber { + rightViewWidth = caretViewWidth + } + + if let buttonText = jsonDictionary["buttonText"] as? String { + setTitle(buttonText, for: .normal) + } } } From bd69d9fb891b2e209bd7fd48ab82d8343b58a94d Mon Sep 17 00:00:00 2001 From: "Christiano, Kevin" Date: Mon, 1 Apr 2019 14:10:47 -0400 Subject: [PATCH 07/13] mild changes. --- MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index ddbff108..1d8ec52a 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -368,7 +368,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt var rangeArray = [AnyHashable]() for subString in words ?? [] { - let finalSubString = subString + (" ") + let finalSubString = subString + " " let wordIndex: Int = index let length: Int = finalSubString.count let subStringRange = NSRange(location: wordIndex, length: length) @@ -407,7 +407,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt frontText = actionRange.revisedText if let revisedText = actionRange.revisedText, let startBraceIndex = actionRange.startIndex, let endBraceIndex = actionRange.endIndex { - // TODO: Put some of this into a String Extension in MVMCore + frontText = String(revisedText[revisedText.startIndex.. Date: Thu, 4 Apr 2019 13:18:06 -0400 Subject: [PATCH 08/13] only used internally --- MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index 1d8ec52a..cda4d6ec 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -27,6 +27,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt public var attributedText: NSAttributedString? { willSet(newAttributedText) { if let newAttribText = newAttributedText, !newAttribText.string.isEmpty { + let mutableAttributedText = newAttribText as? NSMutableAttributedString let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = CGFloat(LabelWithInternalButtonLineSpace) @@ -79,7 +80,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt public var actionText: String? public var backText: String? - public var text: String? { + private var text: String? { willSet(newText) { attributedText = NSAttributedString(string: newText ?? "") setAlternateNormalTextAttributes([NSAttributedString.Key.font: normalTextFont as Any]) From baa0f3d3f7bd5f0faa485924ddaa79fc0c1a41b6 Mon Sep 17 00:00:00 2001 From: "Christiano, Kevin" Date: Thu, 4 Apr 2019 13:39:59 -0400 Subject: [PATCH 09/13] Fixed how NSMutableAttribute is used. --- MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index cda4d6ec..2473bf85 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -28,17 +28,14 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt willSet(newAttributedText) { if let newAttribText = newAttributedText, !newAttribText.string.isEmpty { - let mutableAttributedText = newAttribText as? NSMutableAttributedString + let mutableAttributedText = NSMutableAttributedString(attributedString: newAttribText) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = CGFloat(LabelWithInternalButtonLineSpace) if newAttribText.length > 0 { - mutableAttributedText?.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: newAttribText.length)) - } - - if let mutableAttText = mutableAttributedText { - label?.attributedText = mutableAttText + mutableAttributedText.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: newAttribText.length)) } + label?.attributedText = mutableAttributedText } } } From 3ee784ccb03070fcfc77f28c47a7e5fe5ec3aad8 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 9 Apr 2019 10:38:26 -0400 Subject: [PATCH 10/13] Changes for new feed template --- MVMCoreUI/Atoms/Buttons/PrimaryButton.h | 4 ++-- MVMCoreUI/Atoms/Buttons/PrimaryButton.m | 4 ++++ MVMCoreUI/Molecules/TwoButtonView.swift | 14 +++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Atoms/Buttons/PrimaryButton.h b/MVMCoreUI/Atoms/Buttons/PrimaryButton.h index fb93c33a..771f8c01 100644 --- a/MVMCoreUI/Atoms/Buttons/PrimaryButton.h +++ b/MVMCoreUI/Atoms/Buttons/PrimaryButton.h @@ -62,8 +62,8 @@ static CGFloat const PrimaryButtonSmallHeight = 30.0; + (nullable instancetype)primaryGraySmallRedButton; + (nullable instancetype)primaryWhiteSmallRedButton; - - +// Returns the current height of the button. +- (CGFloat)getHeight; #pragma mark - For Subclassing diff --git a/MVMCoreUI/Atoms/Buttons/PrimaryButton.m b/MVMCoreUI/Atoms/Buttons/PrimaryButton.m index 5a708f2c..fd7ad2b9 100644 --- a/MVMCoreUI/Atoms/Buttons/PrimaryButton.m +++ b/MVMCoreUI/Atoms/Buttons/PrimaryButton.m @@ -86,6 +86,10 @@ #pragma mark - Sizing +- (CGFloat)getHeight { + return self.height.constant; +} + - (MFSizeObject *)innerPadding { return [MFSizeObject sizeObjectWithStandardSize:24.0 standardiPadPortraitSize:32.0 iPadProLandscapeSize:36.0]; } diff --git a/MVMCoreUI/Molecules/TwoButtonView.swift b/MVMCoreUI/Molecules/TwoButtonView.swift index 9e6cf4ee..ee03ff49 100644 --- a/MVMCoreUI/Molecules/TwoButtonView.swift +++ b/MVMCoreUI/Molecules/TwoButtonView.swift @@ -41,11 +41,7 @@ import UIKit } let primaryButtonMap = json?.optionalDictionaryForKey("primaryButton") let secondaryButtonMap = json?.optionalDictionaryForKey("secondaryButton") - setupUI(withPrimaryButtonMap: primaryButtonMap, secondaryButtonMap: secondaryButtonMap, legacy: false) - primaryButton?.setAsStandardCustom() - secondaryButton?.setAsSecondaryCustom() - primaryButton?.setWithJSON(primaryButtonMap, delegate: delegate, additionalData: additionalData) - secondaryButton?.setWithJSON(secondaryButtonMap, delegate: delegate, additionalData: additionalData) + set(primaryButtonJSON: primaryButtonMap, secondaryButtonJSON: secondaryButtonMap, actionDelegate: delegate, additionalData: additionalData, buttonDelegate: delegate) } // MARK: - Constraining @@ -141,6 +137,14 @@ import UIKit } } + open func set(primaryButtonJSON: [AnyHashable: Any]?, secondaryButtonJSON: [AnyHashable: Any]?, actionDelegate: NSObjectProtocol?, additionalData: [AnyHashable: Any]?, buttonDelegate: Any?) { + setupUI(withPrimaryButtonMap: primaryButtonJSON, secondaryButtonMap: secondaryButtonJSON, legacy: false) + primaryButton?.setAsStandardCustom() + secondaryButton?.setAsSecondaryCustom() + primaryButton?.setWithJSON(primaryButtonJSON, delegate: actionDelegate as? NSObject, additionalData: additionalData) + secondaryButton?.setWithJSON(secondaryButtonJSON, delegate: actionDelegate as? NSObject, additionalData: additionalData) + } + // MARK: - Legacy open func setup(withButtonMap buttonMap: [AnyHashable: Any]?, actionDelegate: NSObjectProtocol?, additionalData: [AnyHashable: Any]?, buttonDelegate: Any?) { let secondaryButtonMap = buttonMap?.optionalDictionaryForKey(KeySecondaryButton) From 6114bbbf92fd8910cf09a1005f09677c7a569066 Mon Sep 17 00:00:00 2001 From: "Christiano, Kevin" Date: Tue, 9 Apr 2019 14:43:06 -0400 Subject: [PATCH 11/13] changed the protocol type. --- MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index 85f628fe..ea3323d1 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -11,8 +11,8 @@ import MVMCore public typealias ActionBlock = () -> Void private typealias ActionIndiciesTuple = (startIndex: String.Index?, endIndex: String.Index?, revisedText: String?) -public typealias ActionObjectDelegate = (NSObject & MVMCoreActionDelegateProtocol) -public typealias ButtonObjectDelegate = (NSObject & ButtonDelegateProtocol) +public typealias ActionObjectDelegate = (NSObjectProtocol & MVMCoreActionDelegateProtocol) +public typealias ButtonObjectDelegate = (NSObjectProtocol & ButtonDelegateProtocol) public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProtocol & MVMCoreLoadDelegateProtocol & MVMCorePresentationDelegateProtocol & NSObjectProtocol From 503bbc46054fcb66b7b5edbcc7d3f5623226e567 Mon Sep 17 00:00:00 2001 From: "Christiano, Kevin" Date: Wed, 10 Apr 2019 10:06:53 -0400 Subject: [PATCH 12/13] removed redundant check. --- MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index ea3323d1..7b5ba239 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -31,10 +31,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt let mutableAttributedText = NSMutableAttributedString(attributedString: newAttribText) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = CGFloat(LabelWithInternalButtonLineSpace) - - if newAttribText.length > 0 { - mutableAttributedText.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: newAttribText.length)) - } + mutableAttributedText.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: newAttribText.length)) label?.attributedText = mutableAttributedText } } From d0bc96e3a5e9f516190d9469c1e25ae6be9f8d38 Mon Sep 17 00:00:00 2001 From: "Christiano, Kevin" Date: Wed, 10 Apr 2019 12:12:44 -0400 Subject: [PATCH 13/13] Corrections made. --- .../Atoms/Views/LabelWithInternalButton.swift | 50 +++++++------------ 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index 7b5ba239..3810294a 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -105,7 +105,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt 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) } @@ -170,10 +170,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt let label = MFLabel(frame: CGRect.zero) backgroundColor = .clear - label.translatesAutoresizingMaskIntoConstraints = false label.isUserInteractionEnabled = false - label.numberOfLines = 0 - label.lineBreakMode = NSLineBreakMode.byWordWrapping label.setContentCompressionResistancePriority(.required, for: .vertical) addSubview(label) NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[label]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["label": label])) @@ -201,11 +198,11 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt 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) + 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 ) + MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: wDelegate) } } } @@ -243,29 +240,17 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt frontText = frontAttributedText.string } - let newLineAttributed = addNewLine ? "\n" : " " - - if let actions = actionMap, let actionMapCount = actionMap?.keys.count, actionMapCount > 0 { + if let b2Font = MFStyler.fontB2(), + let actions = actionMap, + actions.keys.count > 0, + let actionString = actions.optionalStringForKey(KeyTitle), + !actionString.isEmpty { - var actionString = actions.stringForkey(KeyTitle) + let actionStringOnLine = actionString + (addNewLine ? "\n" : " ") + actionText = actionStringOnLine + setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate) + mutableAttributedString.append(MFStyler.styleGetAttributedString(actionStringOnLine, font: b2Font, color: .black)) - if !actionString.isEmpty { - - actionString += newLineAttributed - - var actionAttributedString: NSAttributedString? - - if let b2Font = MFStyler.fontB2() { - actionAttributedString = MFStyler.styleGetAttributedString(actionString, font: b2Font, color: .black) - } - - actionText = actionString - setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate) - - if let actionAttribString = actionAttributedString { - mutableAttributedString.append(actionAttribString) - } - } } else { actionText = nil actionBlock = nil @@ -276,7 +261,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt } attributedText = mutableAttributedString - // Added this line for underlining setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)]) } @@ -399,17 +383,17 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt let actionRange: ActionIndiciesTuple = rangeOfText(text, startTag: startTag, endTag: endTag) - frontText = actionRange.revisedText - if let revisedText = actionRange.revisedText, let startBraceIndex = actionRange.startIndex, let endBraceIndex = actionRange.endIndex { - + frontText = String(revisedText[revisedText.startIndex..