diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index b4295986..37c71b4f 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */; }; 01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; }; 01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; + 0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; B8200E192281DC1A007245F4 /* ProgressBarWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */; }; D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -195,6 +196,7 @@ 01CA51B4229716F60071A6EE /* Switch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Switch.swift; sourceTree = ""; }; 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = ""; }; 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = ""; }; + 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarWithLabel.swift; sourceTree = ""; }; D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = ""; }; @@ -476,6 +478,7 @@ D29DF10E21E67A77003B2FB9 /* Molecules */ = { isa = PBXGroup; children = ( + 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */, 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */, D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */, D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */, @@ -1011,6 +1014,7 @@ D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, 0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */, + 0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */, D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */, D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index e3618831..bc79559a 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -191,6 +191,17 @@ public typealias ActionBlock = () -> () setLabel(label, withHTML: json?.optionalStringForKey("html")) + if let alignment = json?.optionalStringForKey("textAlignment") { + switch alignment { + case "center": + label.textAlignment = .center + case "trailing": + label.textAlignment = .right + default: + label.textAlignment = .left + } + } + if let backgroundColorHex = json?.optionalStringForKey(KeyBackgroundColor), !backgroundColorHex.isEmpty { label.backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) } @@ -442,6 +453,7 @@ extension Label { public func reset() { text = nil attributedText = nil + textAlignment = .left originalAttributedString = nil hasAttachmentImageInsideText = false styleB2(true) diff --git a/MVMCoreUI/Atoms/Views/MFRadioButton.h b/MVMCoreUI/Atoms/Views/MFRadioButton.h index 86837256..c5e053c0 100644 --- a/MVMCoreUI/Atoms/Views/MFRadioButton.h +++ b/MVMCoreUI/Atoms/Views/MFRadioButton.h @@ -30,7 +30,6 @@ typedef void (^PerformActionForRadioButton)(void); @property (nullable, copy, nonatomic) PerformActionForRadioButton performActionForCheck; typedef void (^CircleSelectedClosure)(_Nonnull id sender); - @property (nonatomic, strong, nullable) UIColor* fillColor; @property (nonatomic, strong, nullable) UIColor* borderColor; @property (nonatomic) CGFloat circleBorderWidth; @@ -38,11 +37,16 @@ typedef void (^CircleSelectedClosure)(_Nonnull id sender); @property (nonatomic, copy, nullable) CircleSelectedClosure handleSelectionBlock; @property (nonatomic) CGFloat circleDiameter; @property (nonatomic, nullable, strong, readonly) CAShapeLayer * myCircle; - +@property (nullable, weak, nonatomic) UIView *outerCircleView; +@property (nullable, weak, nonatomic) UIView *innerCircleView; @property (nonatomic, strong, nullable) NSLayoutConstraint *heightConstraint; @property (nonatomic, strong, nullable) NSLayoutConstraint *widthConstraint; @property (nonatomic) BOOL respondsToTapGesture; @property (nonatomic, getter = isSelected) BOOL selected; +@property (strong, nonatomic) NSLayoutConstraint *innerHeightConstarint; +@property (strong, nonatomic) NSLayoutConstraint *innerWidthConstarint; +@property (strong, nonatomic) NSLayoutConstraint *outerHeightConstarint; +@property (strong, nonatomic) NSLayoutConstraint *outerWidthConstarint; // Set line width manually - (void)setCheckMarkLineWidth:(CGFloat)lineWidth; diff --git a/MVMCoreUI/Atoms/Views/MFRadioButton.m b/MVMCoreUI/Atoms/Views/MFRadioButton.m index d1a9ee03..06f6c3a0 100644 --- a/MVMCoreUI/Atoms/Views/MFRadioButton.m +++ b/MVMCoreUI/Atoms/Views/MFRadioButton.m @@ -12,11 +12,6 @@ static CGFloat const DefaultOuterCircleSize = 31; static CGFloat const DefaultInnerCircleSize = 19; -@interface MFRadioButton () -@property (nullable, weak, nonatomic) UIView *outerCircleView; -@property (nullable, weak, nonatomic) UIView *innerCircleView; -@end - @implementation MFRadioButton @@ -64,9 +59,11 @@ static CGFloat const DefaultInnerCircleSize = 19; [outerCircleView.leftAnchor constraintEqualToAnchor:self.leftAnchor].active = YES; [outerCircleView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES; [outerCircleView.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES; - - [outerCircleView.widthAnchor constraintEqualToConstant:DefaultOuterCircleSize].active = YES; - [outerCircleView.heightAnchor constraintEqualToConstant:DefaultOuterCircleSize].active = YES; + + self.outerHeightConstarint = [outerCircleView.widthAnchor constraintEqualToConstant:DefaultOuterCircleSize]; + self.outerHeightConstarint.active = YES; + self.outerWidthConstarint = [outerCircleView.heightAnchor constraintEqualToConstant:DefaultOuterCircleSize]; + self.outerWidthConstarint.active = YES; UIView *innerCircleView = [[UIView alloc] init]; [outerCircleView addSubview:innerCircleView]; @@ -76,8 +73,11 @@ static CGFloat const DefaultInnerCircleSize = 19; [innerCircleView.centerXAnchor constraintEqualToAnchor:outerCircleView.centerXAnchor].active = YES; [innerCircleView.centerYAnchor constraintEqualToAnchor:outerCircleView.centerYAnchor].active = YES; - [innerCircleView.widthAnchor constraintEqualToConstant:DefaultInnerCircleSize].active = YES; - [innerCircleView.heightAnchor constraintEqualToConstant:DefaultInnerCircleSize].active = YES; + + self.innerHeightConstarint = [innerCircleView.heightAnchor constraintEqualToConstant:DefaultInnerCircleSize]; + self.innerHeightConstarint.active = YES; + self.innerWidthConstarint = [innerCircleView.widthAnchor constraintEqualToConstant:DefaultInnerCircleSize]; + self.innerWidthConstarint.active = YES; outerCircleView.userInteractionEnabled = NO; innerCircleView.userInteractionEnabled = NO; diff --git a/MVMCoreUI/Atoms/Views/MFView.m b/MVMCoreUI/Atoms/Views/MFView.m index 740c5ad5..4e0d71ab 100644 --- a/MVMCoreUI/Atoms/Views/MFView.m +++ b/MVMCoreUI/Atoms/Views/MFView.m @@ -48,6 +48,9 @@ - (void)setAsMolecule { self.translatesAutoresizingMaskIntoConstraints = NO; + if (@available(iOS 11.0, *)) { + self.insetsLayoutMarginsFromSafeArea = NO; + } } - (void)reset { diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index f46916b3..dff48826 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -336,6 +336,7 @@ } - (void)reset { + [super reset]; self.updateViewHorizontalDefaults = NO; self.updateViewVerticalDefaults = NO; if ([self.molecule respondsToSelector:@selector(alignment)]) { diff --git a/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m b/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m index b728b063..98d2b5ef 100644 --- a/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m +++ b/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m @@ -61,6 +61,9 @@ tableView.separatorStyle = UITableViewCellSeparatorStyleNone; tableView.delegate = self; tableView.dataSource = self; + if (@available(iOS 11.0, *)) { + tableView.insetsContentViewsToSafeArea = NO; + } if ([tableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)]) { tableView.cellLayoutMarginsFollowReadableWidth = NO; } diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index 85127a45..0293e860 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -21,23 +21,21 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { private var topViewBottomConstraint: NSLayoutConstraint? private var bottomViewTopConstraint: NSLayoutConstraint? - //MARK: - MVMCoreViewProtocol + //MARK: - MFViewController open override func updateViews() { super.updateViews() let width = view.bounds.width - MFStyler.setDefaultMarginsFor(contentView, size: width) if let topView = topView as? MVMCoreViewProtocol { topView.updateView(width) - showHeader() + showHeader(width) } if let bottomView = bottomView as? MVMCoreViewProtocol { bottomView.updateView(width) - showFooter() + showFooter(width) } self.tableView?.reloadData() } - //MARK: - MFViewController open override func newDataBuildScreen() { super.newDataBuildScreen() createViewForTableHeader() @@ -103,14 +101,15 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { currentSpaceForCompare = currentSpace * 2; } + let width = view.bounds.width if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 0.1) { if fillTop && fillBottom { // space both let half = newSpace / 2 topViewBottomConstraint?.constant = half bottomViewTopConstraint?.constant = half - showHeader() - showFooter() + showHeader(width) + showFooter(width) } else if fillTop { // Only top is spaced (half the size if the bottom view is out of the scroll because it needs to be sized as if there are two spacers but there is only one. if bottomViewOutsideOfScrollArea { @@ -118,11 +117,11 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { } else { topViewBottomConstraint?.constant = newSpace } - showHeader() + showHeader(width) } else if fillBottom { // Only bottom is spaced. bottomViewTopConstraint?.constant = newSpace - showFooter() + showFooter(width) } } } @@ -141,7 +140,7 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { topViewBottomConstraint = headerView.bottomAnchor.constraint(equalTo: topView.bottomAnchor, constant: spaceBelowTopView() ?? 0) topViewBottomConstraint?.isActive = true self.headerView = headerView - showHeader() + showHeader(nil) } /// Gets the bottom view and adds it to a spacing view, footerView, and then calls showFooter. @@ -157,11 +156,11 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { footerView.rightAnchor.constraint(equalTo: bottomView.rightAnchor).isActive = true footerView.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor).isActive = true self.footerView = footerView - showFooter() + showFooter(nil) } /// Takes the current headerView and adds it to the tableHeaderView - func showHeader() { + func showHeader(_ sizingWidth: CGFloat?) { headerView?.removeFromSuperview() tableView?.tableHeaderView = nil guard let headerView = headerView else { @@ -177,7 +176,7 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { } /// Takes the current footerView and adds it to the tableFooterView - func showFooter() { + func showFooter(_ sizingWidth: CGFloat?) { footerView?.removeFromSuperview() safeAreaView?.removeFromSuperview() guard let footerView = footerView, let tableView = tableView else { diff --git a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.m b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.m index 0fcc51a2..77472e11 100644 --- a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.m +++ b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.m @@ -303,8 +303,9 @@ } - (void)addViewToContentView:(UIView *)bottomView { - - self.bottomConstraint.active = YES; + if (![self bottomViewOutsideOfScroll]) { + self.bottomConstraint.active = YES; + } // Buttons will be at the bottom of the content view. [self.contentView addSubview:bottomView]; diff --git a/MVMCoreUI/Molecules/ActionDetailWithImage.swift b/MVMCoreUI/Molecules/ActionDetailWithImage.swift new file mode 100644 index 00000000..4792dbd6 --- /dev/null +++ b/MVMCoreUI/Molecules/ActionDetailWithImage.swift @@ -0,0 +1,186 @@ +// +// ActionDetailWithImage.swift +// MVMCoreUI +// +// Created by Christiano, Kevin on 6/20/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + + +@objcMembers open class ActionDetailWithImage: ViewConstrainingView { + //------------------------------------------------------ + // MARK: - Outlets + //------------------------------------------------------ + + let title = Label.commonLabelH3(true) + let message = Label.commonLabelB3(true) + let button = PrimaryButton.primaryTinyButton(false)! + let imageLoader = MFLoadImageView(pinnedEdges: .all) + let leftContainer = ViewConstrainingView.empty() + + //------------------------------------------------------ + // MARK: - Properties + //------------------------------------------------------ + + var bottomTitlePadding: CGFloat = PaddingOne + + //------------------------------------------------------ + // MARK: - Constraints + //------------------------------------------------------ + + var imageLeadingConstraint: NSLayoutConstraint? + var buttonTopConstraint: NSLayoutConstraint? + var messageTopConstraint: NSLayoutConstraint? + + //------------------------------------------------------ + // MARK: - Initialization + //------------------------------------------------------ + + public init() { + super.init(frame: .zero) + } + + public override init(frame: CGRect) { + super.init(frame: frame) + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + public convenience init(json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + self.init() + setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + } + + //------------------------------------------------------ + // MARK: - View Lifecycle + //------------------------------------------------------ + + override open func setupView() { + super.setupView() + + guard subviews.isEmpty else { return } + + setDefaultState() + + addSubview(leftContainer) + addSubview(imageLoader) + leftContainer.addSubview(title) + leftContainer.addSubview(message) + leftContainer.addSubview(button) + + leftContainer.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true + leftContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true + + layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: leftContainer.bottomAnchor).isActive = true + let leftContainerBottom = leftContainer.bottomAnchor.constraint(equalTo: bottomAnchor) + leftContainerBottom.priority = UILayoutPriority(249) + leftContainerBottom.isActive = true + + title.topAnchor.constraint(equalTo: leftContainer.topAnchor).isActive = true + title.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + leftContainer.trailingAnchor.constraint(equalTo: title.trailingAnchor).isActive = true + + messageTopConstraint = message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: PaddingOne) + messageTopConstraint?.isActive = true + + message.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + leftContainer.trailingAnchor.constraint(equalTo: message.trailingAnchor).isActive = true + + buttonTopConstraint = button.topAnchor.constraint(equalTo: message.bottomAnchor, constant: PaddingTwo) + buttonTopConstraint?.isActive = true + + button.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + leftContainer.bottomAnchor.constraint(equalTo: button.bottomAnchor).isActive = true + leftContainer.trailingAnchor.constraint(greaterThanOrEqualTo: button.trailingAnchor).isActive = true + + imageLoader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageLoader.trailingAnchor).isActive = true + imageLeadingConstraint = imageLoader.leadingAnchor.constraint(greaterThanOrEqualTo: leftContainer.trailingAnchor, constant: 16) + imageLeadingConstraint?.isActive = true + imageLoader.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true + + layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: imageLoader.bottomAnchor).isActive = true + let imageloaderBottom = imageLoader.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor) + imageloaderBottom.priority = UILayoutPriority(249) + imageloaderBottom.isActive = true + } + + override open func updateView(_ size: CGFloat) { + super.updateView(size) + + title.updateView(size) + message.updateView(size) + button.updateView(size) + imageLoader.updateView(size) + leftContainer.updateView(size) + + + messageTopConstraint?.constant = title.hasText && message.hasText ? bottomTitlePadding : 0 + buttonTopConstraint?.constant = message.hasText || title.hasText ? PaddingTwo : 0 + } + + public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 197 + } + + //------------------------------------------------------ + // MARK: - Methods + //------------------------------------------------------ + + private func setDefaultState() { + + title.font = MFStyler.fontH3() + message.font = MFStyler.fontB3() + button.setAsSecondaryCustom() + button.isHidden = false + imageLoader.imageView.contentMode = .scaleAspectFit + imageLoader.addSizeConstraintsForAspectRatio = true + bottomTitlePadding = PaddingOne + } + + override open func reset() { + super.reset() + + title.reset() + message.reset() + button.reset() + imageLeadingConstraint?.constant = 16 + imageLoader.reset() + + setDefaultState() + } + + open override func setAsMolecule() { + super.setAsMolecule() + + title.setAsMolecule() + message.setAsMolecule() + button.setAsMolecule() + imageLoader.setAsMolecule() + + setDefaultState() + } + + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + + guard let dictionary = json else { return } + + if let padding = dictionary.optionalCGFloatForKey("bottomTitlePadding") { + bottomTitlePadding = padding + } + + title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject, additionalData: additionalData) + message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData) + imageLoader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData) + if let buttonDictionary = dictionary.optionalDictionaryForKey("button") { + button.setWithJSON(buttonDictionary, delegateObject: delegateObject, additionalData: additionalData) + } else { + button.isHidden = true + } + } +} diff --git a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift index 6afec1bc..42a5e5cd 100644 --- a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift @@ -37,6 +37,11 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi } isAccessibilityElement = false contentView.isAccessibilityElement = false + if #available(iOS 11.0, *) { + insetsLayoutMarginsFromSafeArea = false + contentView.insetsLayoutMarginsFromSafeArea = false + contentView.preservesSuperviewLayoutMargins = false + } // Covers the card when peaking. peakingCover.backgroundColor = .white diff --git a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift index c6241667..00ea68ac 100644 --- a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift @@ -80,6 +80,11 @@ import UIKit public func setupView() { selectionStyle = .none + if #available(iOS 11.0, *) { + insetsLayoutMarginsFromSafeArea = false + contentView.insetsLayoutMarginsFromSafeArea = false + contentView.preservesSuperviewLayoutMargins = false + } } // MARK: - MVMCoreUIMoleculeViewProtocol diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 41513bf0..cd829697 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -46,8 +46,9 @@ @"listItem": MoleculeTableViewCell.class, @"switchLineItem": SwitchLineItem.class, @"switch": Switch.class, - @"image": MFLoadImageView.class, @"leftRightLabelView": LeftRightLabelView.class, + @"actionDetailWithImage": ActionDetailWithImage.class, + @"image": MFLoadImageView.class, @"moduleMolecule": ModuleMolecule.class, @"headlineBody": HeadlineBody.class, @"carousel": Carousel.class, diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/Contents.json b/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/Contents.json new file mode 100644 index 00000000..d7771f8a --- /dev/null +++ b/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "closeXBlack.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "closeXBlack@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "closeXBlack@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack.png b/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack.png new file mode 100644 index 00000000..5f31bd28 Binary files /dev/null and b/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack.png differ diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack@2x.png b/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack@2x.png new file mode 100644 index 00000000..d966cb74 Binary files /dev/null and b/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack@2x.png differ diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack@3x.png b/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack@3x.png new file mode 100644 index 00000000..59847565 Binary files /dev/null and b/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack@3x.png differ diff --git a/MVMCoreUI/Templates/MoleculeStackTemplate.swift b/MVMCoreUI/Templates/MoleculeStackTemplate.swift index 064c910c..d6f78b05 100644 --- a/MVMCoreUI/Templates/MoleculeStackTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeStackTemplate.swift @@ -8,7 +8,7 @@ import UIKit -public class MoleculeStackTemplate: ThreeLayerViewController { +open class MoleculeStackTemplate: ThreeLayerViewController { var observer: NSKeyValueObservation? open override var loadObject: MVMCoreLoadObject? { @@ -25,18 +25,18 @@ public class MoleculeStackTemplate: ThreeLayerViewController { } } - public override func spaceBetweenTopAndMiddle() -> CGFloat? { + open override func spaceBetweenTopAndMiddle() -> CGFloat? { return 0 } - public override func viewForTop() -> UIView? { + open override func viewForTop() -> UIView? { guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { return nil } return molecule } - public override func viewForMiddle() -> UIView? { + open override func viewForMiddle() -> UIView? { guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("moleculeStack") else { return nil } @@ -46,7 +46,7 @@ public class MoleculeStackTemplate: ThreeLayerViewController { return stack } - override public func viewForBottom() -> UIView? { + override open func viewForBottom() -> UIView? { guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { return nil } @@ -54,14 +54,14 @@ public class MoleculeStackTemplate: ThreeLayerViewController { } // MARK: - cache handling - public override func pageTypesToListenFor() -> [Any]? { + open override func pageTypesToListenFor() -> [Any]? { guard let pageType = self.pageType else { return super.pageTypesToListenFor() } return [pageType] } - public override func modulesToListenFor() -> [Any]? { + open override func modulesToListenFor() -> [Any]? { return loadObject?.requestParameters?.modules } diff --git a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m index 487a7b51..41237640 100644 --- a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m @@ -181,7 +181,7 @@ static const CGFloat VertialShadowOffset = 6; + (nonnull MFCustomButton *)addCloseButtonToView:(UIView *)view action:(ButtonTapBlock)actionBlock verticalCentered:(BOOL)verticalCentered { MFCustomButton *button = [[MFCustomButton alloc] initWithFrame:CGRectZero]; button.translatesAutoresizingMaskIntoConstraints = NO; - [button setTitle:@"✕" forState:UIControlStateNormal]; + [button setImage:[MVMCoreUIUtility imageNamed:@"closeXBlack"] forState:UIControlStateNormal]; button.titleLabel.font = [MFStyler fontForHeadlineAlternative]; //accessibility diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.h b/MVMCoreUI/Utility/MVMCoreUIUtility.h index b6698537..9300de90 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.h +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.h @@ -71,8 +71,9 @@ NS_ASSUME_NONNULL_BEGIN // Gets the constraint height to be whatever space is left in the scroll view. + (CGFloat)getVariableConstraintHeight:(CGFloat)currentConstant inScrollView:(nonnull UIScrollView *)scrollView minimumHeight:(CGFloat)minimumHeight; -// Sets the view's frame according to constraint. +/// Sets the view's frame according to constraints. + (void)sizeViewToFit:(nullable UIView *)view; ++ (void)sizeViewToFit:(UIView *)view forWidth:(nullable NSNumber *)width; #pragma mark - Keyboard diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.m b/MVMCoreUI/Utility/MVMCoreUIUtility.m index 8201e999..e8523a61 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.m @@ -119,7 +119,7 @@ #pragma mark - Sizing + (CGFloat)getWidth { - UIViewController *controller = [MVMCoreUISession sharedGlobal].splitViewController ?: [MVMCoreUISession sharedGlobal].navigationController ?: [UIApplication sharedApplication].keyWindow.rootViewController; + UIViewController *controller = [MVMCoreUISession sharedGlobal].splitViewController ?: [MVMCoreUISession sharedGlobal].navigationController; if (controller) { return CGRectGetWidth(controller.view.bounds); } else { @@ -138,7 +138,7 @@ } + (CGFloat)getHeightOfView:(nonnull UIView *)view forWidth:(nullable NSNumber *)width { - CGFloat floatWidth = (width ? width.floatValue : CGRectGetWidth([MVMCoreNavigationHandler sharedNavigationHandler].navigationController.view.bounds)); + CGFloat floatWidth = (width ? width.floatValue : [MVMCoreUIUtility getWidth]); return [view systemLayoutSizeFittingSize:CGSizeMake(floatWidth, UILayoutFittingCompressedSize.height) withHorizontalFittingPriority:1000 verticalFittingPriority:250].height; } @@ -192,6 +192,13 @@ view.frame = frame; } ++ (void)sizeViewToFit:(UIView *)view forWidth:(nullable NSNumber *)width { + CGFloat height = [MVMCoreUIUtility getHeightOfView:view forWidth:width]; + CGRect frame = view.frame; + frame.size.height = height; + view.frame = frame; +} + #pragma mark - Keyboard + (void)setScrollViewInsetForKeyboardShow:(nonnull NSNotification *)notification scrollView:(nonnull UIScrollView *)scrollView viewController:(nonnull UIViewController *)viewController rectToScrollTo:(nonnull CGRect (^)(void))rectToScrollTo {