Merge branch 'develop' into feature/swiftified_textField
This commit is contained in:
commit
134ba463b9
@ -19,7 +19,8 @@ import MVMCore
|
|||||||
// Form Validation
|
// Form Validation
|
||||||
var isRequired = false
|
var isRequired = false
|
||||||
var fieldKey: String?
|
var fieldKey: String?
|
||||||
var delegateObject: DelegateObject?
|
var groupName: String?
|
||||||
|
var delegateObject: MVMCoreUIDelegateObject?
|
||||||
|
|
||||||
public static let defaultHeightWidth: CGFloat = 18.0
|
public static let defaultHeightWidth: CGFloat = 18.0
|
||||||
|
|
||||||
@ -104,12 +105,8 @@ import MVMCore
|
|||||||
layoutIfNeeded()
|
layoutIfNeeded()
|
||||||
shapeLayer?.removeAllAnimations()
|
shapeLayer?.removeAllAnimations()
|
||||||
|
|
||||||
updateCheckboxUI(isSelected: isSelected, isAnimated: isAnimated)
|
updateCheckboxUI(isSelected: isSelected, isAnimated: isAnimated)
|
||||||
|
FormValidator.enableByValidationWith(delegate: delegateObject?.formValidationProtocol)
|
||||||
if let delegate = delegateObject as? FormValidationProtocol {
|
|
||||||
delegate.formValidatorModel?()?.enableByValidation()
|
|
||||||
}
|
|
||||||
|
|
||||||
updateAccessibilityLabel()
|
updateAccessibilityLabel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,7 +208,6 @@ import MVMCore
|
|||||||
|
|
||||||
/// This will toggle the state of the Checkbox and execute the actionBlock if provided.
|
/// This will toggle the state of the Checkbox and execute the actionBlock if provided.
|
||||||
public func toggleAndAction() {
|
public func toggleAndAction() {
|
||||||
|
|
||||||
isSelected.toggle()
|
isSelected.toggle()
|
||||||
actionBlock?()
|
actionBlock?()
|
||||||
}
|
}
|
||||||
@ -308,8 +304,9 @@ import MVMCore
|
|||||||
/// Adjust accessibility label based on state of Checkbox.
|
/// Adjust accessibility label based on state of Checkbox.
|
||||||
func updateAccessibilityLabel() {
|
func updateAccessibilityLabel() {
|
||||||
// Attention: This needs to be addressed with the accessibility team.
|
// Attention: This needs to be addressed with the accessibility team.
|
||||||
|
// NOTE: Currently emptying description part of MVMCoreUICheckBox accessibility label to avoid crashing!
|
||||||
if let state = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "checkbox_checked_state" : "checkbox_unchecked_state") {
|
if let state = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "checkbox_checked_state" : "checkbox_unchecked_state") {
|
||||||
accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state") ?? "%@", state)
|
accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state") ?? "%@%@", "", state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +405,8 @@ import MVMCore
|
|||||||
FormValidator.setupValidation(molecule: self, delegate: delegateObject?.formValidationProtocol)
|
FormValidator.setupValidation(molecule: self, delegate: delegateObject?.formValidationProtocol)
|
||||||
|
|
||||||
guard let dictionary = json else { return }
|
guard let dictionary = json else { return }
|
||||||
|
|
||||||
|
groupName = dictionary.optionalStringForKey("groupName")
|
||||||
if let fieldKey = dictionary[KeyFieldKey] as? String {
|
if let fieldKey = dictionary[KeyFieldKey] as? String {
|
||||||
self.fieldKey = fieldKey
|
self.fieldKey = fieldKey
|
||||||
}
|
}
|
||||||
@ -462,7 +460,11 @@ import MVMCore
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK:- FormValidationProtocol
|
// MARK:- FormValidationProtocol
|
||||||
extension Checkbox: FormValidationProtocol {
|
extension Checkbox: FormValidationFormFieldProtocol {
|
||||||
|
|
||||||
|
public func formFieldGroupName() -> String? {
|
||||||
|
return groupName
|
||||||
|
}
|
||||||
|
|
||||||
public func isValidField() -> Bool {
|
public func isValidField() -> Bool {
|
||||||
return isRequired ? isSelected : true
|
return isRequired ? isSelected : true
|
||||||
|
|||||||
@ -266,7 +266,7 @@ public typealias ActionBlock = () -> ()
|
|||||||
let length = attribute["length"] as? Int
|
let length = attribute["length"] as? Int
|
||||||
else { continue }
|
else { continue }
|
||||||
|
|
||||||
let range = NSRange(location: location, length: length)
|
var range = NSRange(location: location, length: length)
|
||||||
|
|
||||||
switch attributeType {
|
switch attributeType {
|
||||||
case "underline":
|
case "underline":
|
||||||
@ -278,7 +278,17 @@ public typealias ActionBlock = () -> ()
|
|||||||
|
|
||||||
case "color":
|
case "color":
|
||||||
if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty {
|
if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty {
|
||||||
attributedString.removeAttribute(.foregroundColor, range: range)
|
// crash fix: removing attribute, even though it does not exists
|
||||||
|
let foregroundColorAttributesArray = attributedString.attributes(at: location, effectiveRange: &range).filter { (attribute) -> Bool in
|
||||||
|
if attribute.key == .foregroundColor {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if foregroundColorAttributesArray.isEmpty == false {
|
||||||
|
attributedString.removeAttribute(.foregroundColor, range: range)
|
||||||
|
}
|
||||||
attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range)
|
attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range)
|
||||||
}
|
}
|
||||||
case "image":
|
case "image":
|
||||||
@ -300,8 +310,28 @@ public typealias ActionBlock = () -> ()
|
|||||||
case "font":
|
case "font":
|
||||||
if let fontStyle = attribute.optionalStringForKey("style") {
|
if let fontStyle = attribute.optionalStringForKey("style") {
|
||||||
let styles = MFStyler.styleGetAttributedString("0", withStyle: fontStyle)
|
let styles = MFStyler.styleGetAttributedString("0", withStyle: fontStyle)
|
||||||
attributedString.removeAttribute(.font, range: range)
|
// crash fix: removing font attribute, even though it does not exists
|
||||||
attributedString.removeAttribute(.foregroundColor, range: range)
|
let fontAttributesArray = attributedString.attributes(at: location, effectiveRange: &range).filter { (attribute) -> Bool in
|
||||||
|
if attribute.key == .font {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fontAttributesArray.isEmpty == false {
|
||||||
|
attributedString.removeAttribute(.font, range: range)
|
||||||
|
}
|
||||||
|
// crash fix: removing attribute, even though it does not exists
|
||||||
|
let foregroundColorAttributesArray = attributedString.attributes(at: location, effectiveRange: &range).filter { (attribute) -> Bool in
|
||||||
|
if attribute.key == .foregroundColor {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if foregroundColorAttributesArray.isEmpty == false {
|
||||||
|
attributedString.removeAttribute(.foregroundColor, range: range)
|
||||||
|
}
|
||||||
attributedString.addAttributes(styles.attributes(at: 0, effectiveRange: nil), range: range)
|
attributedString.addAttributes(styles.attributes(at: 0, effectiveRange: nil), range: range)
|
||||||
} else {
|
} else {
|
||||||
let fontSize = attribute["size"] as? CGFloat
|
let fontSize = attribute["size"] as? CGFloat
|
||||||
@ -314,7 +344,17 @@ public typealias ActionBlock = () -> ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let font = font {
|
if let font = font {
|
||||||
attributedString.removeAttribute(.font, range: range)
|
// crash fix: removing font attribute, even though it does not exists
|
||||||
|
let fontAttributesArray = attributedString.attributes(at: location, effectiveRange: &range).filter { (attribute) -> Bool in
|
||||||
|
if attribute.key == .font {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fontAttributesArray.isEmpty == false {
|
||||||
|
attributedString.removeAttribute(.font, range: range)
|
||||||
|
}
|
||||||
attributedString.addAttribute(.font, value: font, range: range)
|
attributedString.addAttribute(.font, value: font, range: range)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,7 @@ typedef void(^ValueChangeBlock)(void);
|
|||||||
|
|
||||||
@property (nonatomic) BOOL shouldTouchToSwitch;
|
@property (nonatomic) BOOL shouldTouchToSwitch;
|
||||||
@property (nullable, copy, nonatomic) ValueChangeBlock valueChangedBlock;
|
@property (nullable, copy, nonatomic) ValueChangeBlock valueChangedBlock;
|
||||||
|
@property (nullable, copy, nonatomic) ValueChangeBlock actionBlock;
|
||||||
|
|
||||||
+ (nonnull instancetype)mvmSwitchDefault;
|
+ (nonnull instancetype)mvmSwitchDefault;
|
||||||
+ (nonnull instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block;
|
+ (nonnull instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block;
|
||||||
|
|||||||
@ -22,7 +22,7 @@ const CGFloat SwitchKnobWidth = 20;
|
|||||||
const CGFloat SwitchKnobHeight = 20;
|
const CGFloat SwitchKnobHeight = 20;
|
||||||
const CGFloat SwitchShakeIntensity = 2;
|
const CGFloat SwitchShakeIntensity = 2;
|
||||||
|
|
||||||
@interface MVMCoreUISwitch () <FormValidationProtocol, MVMCoreUIViewConstrainingProtocol>
|
@interface MVMCoreUISwitch () <FormValidationFormFieldProtocol, MVMCoreUIViewConstrainingProtocol>
|
||||||
|
|
||||||
@property (weak, nonatomic) UIView *baseView;
|
@property (weak, nonatomic) UIView *baseView;
|
||||||
@property (weak, nonatomic) UIView *knobView;
|
@property (weak, nonatomic) UIView *knobView;
|
||||||
@ -169,6 +169,18 @@ const CGFloat SwitchShakeIntensity = 2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
[self setState:[json boolForKey:@"state"] animated:false];
|
[self setState:[json boolForKey:@"state"] animated:false];
|
||||||
|
|
||||||
|
self.delegate = delegateObject;
|
||||||
|
NSDictionary *actionMap = [json dict:@"actionMap"];
|
||||||
|
if (actionMap) {
|
||||||
|
[self addTarget:self action:@selector(addCustomAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addCustomAction {
|
||||||
|
if (self.actionBlock) {
|
||||||
|
self.actionBlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject {
|
+ (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject {
|
||||||
|
|||||||
@ -61,6 +61,11 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Space between the bottom view and the table sections, nil to fill. nil default
|
||||||
|
open func spaceBelowBottomView() -> CGFloat? {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
/// can override to return a minimum fill space.
|
/// can override to return a minimum fill space.
|
||||||
open func minimumFillSpace() -> CGFloat {
|
open func minimumFillSpace() -> CGFloat {
|
||||||
return 0
|
return 0
|
||||||
@ -154,7 +159,7 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
|
|||||||
bottomViewTopConstraint?.isActive = true
|
bottomViewTopConstraint?.isActive = true
|
||||||
bottomView.leftAnchor.constraint(equalTo: footerView.leftAnchor).isActive = true
|
bottomView.leftAnchor.constraint(equalTo: footerView.leftAnchor).isActive = true
|
||||||
footerView.rightAnchor.constraint(equalTo: bottomView.rightAnchor).isActive = true
|
footerView.rightAnchor.constraint(equalTo: bottomView.rightAnchor).isActive = true
|
||||||
footerView.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor).isActive = true
|
footerView.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor, constant: spaceBelowBottomView() ?? 0).isActive = true
|
||||||
self.footerView = footerView
|
self.footerView = footerView
|
||||||
showFooter(nil)
|
showFooter(nil)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -330,7 +330,7 @@
|
|||||||
bottomViewBot.active = YES;
|
bottomViewBot.active = YES;
|
||||||
|
|
||||||
UIView *safeAreaView = [MVMCoreUICommonViewsUtility getAndSetupSafeAreaViewOnView:self.view];
|
UIView *safeAreaView = [MVMCoreUICommonViewsUtility getAndSetupSafeAreaViewOnView:self.view];
|
||||||
safeAreaView.backgroundColor = footerView.backgroundColor;
|
safeAreaView.backgroundColor = self.bottomView.backgroundColor;
|
||||||
self.safeAreaView = safeAreaView;
|
self.safeAreaView = safeAreaView;
|
||||||
|
|
||||||
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[footerView]-0@900-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(footerView)]];
|
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[footerView]-0@900-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(footerView)]];
|
||||||
|
|||||||
@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@objcMembers public class HeadlineBodySwitch: ViewConstrainingView {
|
@objcMembers open class HeadlineBodySwitch: ViewConstrainingView {
|
||||||
let headlineBody = HeadlineBody(frame: .zero)
|
public let headlineBody = HeadlineBody(frame: .zero)
|
||||||
let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault()
|
public let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault()
|
||||||
|
|
||||||
// MARK: - MVMCoreViewProtocol
|
// MARK: - MVMCoreViewProtocol
|
||||||
open override func updateView(_ size: CGFloat) {
|
open override func updateView(_ size: CGFloat) {
|
||||||
@ -35,7 +35,7 @@ import UIKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MVMCoreUIMoleculeViewProtocol
|
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||||
public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
|
open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
|
||||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
headlineBody.setWithJSON(json?.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData)
|
headlineBody.setWithJSON(json?.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData)
|
||||||
mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData)
|
mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
|||||||
@ -33,7 +33,7 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - FormValidationProtocol
|
// MARK: - FormValidationFormFieldProtocol
|
||||||
extension RadioButtonModel: FormValidationFormFieldProtocol {
|
extension RadioButtonModel: FormValidationFormFieldProtocol {
|
||||||
public func formFieldGroupName() -> String? {
|
public func formFieldGroupName() -> String? {
|
||||||
return selectedRadioButton?.formFieldGroupName() ?? self.fieldGroupName
|
return selectedRadioButton?.formFieldGroupName() ?? self.fieldGroupName
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
mapping = [@{
|
mapping = [@{
|
||||||
@"label": Label.class,
|
@"label": Label.class,
|
||||||
@"separator": SeparatorView.class,
|
@"line": SeparatorView.class,
|
||||||
@"button": ButtonView.class,
|
@"button": ButtonView.class,
|
||||||
@"textButton": MFTextButton.class,
|
@"textButton": MFTextButton.class,
|
||||||
@"header": StandardHeaderView.class,
|
@"header": StandardHeaderView.class,
|
||||||
@ -43,7 +43,7 @@
|
|||||||
@"checkbox" : Checkbox.class,
|
@"checkbox" : Checkbox.class,
|
||||||
@"checkboxWithLabelView" : CheckboxWithLabelView.class,
|
@"checkboxWithLabelView" : CheckboxWithLabelView.class,
|
||||||
@"cornerLabels" : CornerLabels.class,
|
@"cornerLabels" : CornerLabels.class,
|
||||||
@"progressBar": ProgressBar.class,
|
@"progressbar": ProgressBar.class,
|
||||||
@"multiProgressBar": MultiProgress.class,
|
@"multiProgressBar": MultiProgress.class,
|
||||||
@"checkbox": MVMCoreUICheckBox.class,
|
@"checkbox": MVMCoreUICheckBox.class,
|
||||||
@"radioButton": RadioButton.class,
|
@"radioButton": RadioButton.class,
|
||||||
|
|||||||
@ -42,6 +42,11 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
|
|||||||
return molecule
|
return molecule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for bottom gutter/free space
|
||||||
|
open override func spaceBelowBottomView() -> CGFloat? {
|
||||||
|
return PaddingDefaultVerticalSpacing
|
||||||
|
}
|
||||||
|
|
||||||
open override func newDataBuildScreen() {
|
open override func newDataBuildScreen() {
|
||||||
super.newDataBuildScreen()
|
super.newDataBuildScreen()
|
||||||
setup()
|
setup()
|
||||||
@ -153,6 +158,23 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.tableView?.deleteRows(at: indexPaths, with: animation)
|
self.tableView?.deleteRows(at: indexPaths, with: animation)
|
||||||
|
// crash fix
|
||||||
|
self.tableView?.reloadData()
|
||||||
|
self.updateViewConstraints()
|
||||||
|
self.view.layoutIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func removeListItem(_ molecule: [AnyHashable : Any], animation: UITableView.RowAnimation) {
|
||||||
|
var indexPaths: [IndexPath] = []
|
||||||
|
if let removeIndex = moleculesInfo?.firstIndex(where: { (moleculeInfo) -> Bool in
|
||||||
|
return NSDictionary(dictionary: molecule).isEqual(to: moleculeInfo.molecule["molecule"] as? [AnyHashable : Any] ?? [:])
|
||||||
|
}) {
|
||||||
|
moleculesInfo?.remove(at: removeIndex)
|
||||||
|
indexPaths.append(IndexPath(row: removeIndex + indexPaths.count, section: 0))
|
||||||
|
}
|
||||||
|
self.tableView?.deleteRows(at: indexPaths, with: animation)
|
||||||
|
// crash fix
|
||||||
|
self.tableView?.reloadData()
|
||||||
self.updateViewConstraints()
|
self.updateViewConstraints()
|
||||||
self.view.layoutIfNeeded()
|
self.view.layoutIfNeeded()
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user