Fixing issues for model reuse.

This commit is contained in:
Kevin G Christiano 2020-01-23 14:26:04 -05:00
parent e143c75215
commit 0c7a2940d9
12 changed files with 349 additions and 97 deletions

View File

@ -22,7 +22,20 @@ import UIKit
return calendar
}()
public var dateFormat: String?
public var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeZone = NSTimeZone.system
formatter.locale = .current
formatter.formatterBehavior = .default
return formatter
}()
public var dateFormat: String = "MMM d, y" {
didSet {
dateFormatter.dateFormat = dateFormat
}
}
//--------------------------------------------------
// MARK: - Initializers
@ -83,7 +96,7 @@ import UIKit
if calendar.isDate(date, inSameDayAs: Date()) {
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
} else {
text = dateFormatter().string(from: date)
text = dateFormatter.string(from: date)
}
}
@ -98,29 +111,12 @@ import UIKit
setTextWith(date: datePicker?.date)
}
public func dateFormatter() -> DateFormatter {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeZone = NSTimeZone.system
formatter.locale = .current
formatter.formatterBehavior = .default
if let dateFormat = dateFormat {
formatter.dateFormat = dateFormat
}
return formatter
}
public override func setWithModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.setWithModel(model, delegateObject, additionalData)
guard let model = model as? DateDropdownEntryFieldModel else { return }
if let dateFormat = model.dateFormat {
self.dateFormat = dateFormat
}
self.dateFormat = model.dateFormat
}
}

View File

@ -15,7 +15,7 @@
return "dateDropdownEntryField"
}
public var dateFormat: String?
public var dateFormat: String = "MMM d, y"
//--------------------------------------------------
// MARK: - Keys
@ -32,7 +32,7 @@
required public init(from decoder: Decoder) throws {
try super.init(from: decoder)
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
dateFormat = try typeContainer.decodeIfPresent(String.self, forKey: .dateFormat)
dateFormat = try typeContainer.decodeIfPresent(String.self, forKey: .dateFormat) ?? "MMM d, y"
}
public override func encode(to encoder: Encoder) throws {

View File

@ -333,11 +333,9 @@ import UIKit
guard let model = model as? DigitEntryFieldModel else { return }
numberOfDigits = model.digits ?? 4
numberOfDigits = model.digits
if let secureEntry = model.secureEntry, secureEntry {
setAsSecureTextEntry(true)
}
setAsSecureTextEntry(model.secureEntry)
for digitBox in digitBoxes {
MVMCoreUICommonViewsUtility.addDismissToolbar(digitBox.digitField, delegate: delegateObject as? UITextFieldDelegate)

View File

@ -16,8 +16,8 @@
return "digitTextField"
}
public var digits: Int?
public var secureEntry: Bool?
public var digits: Int = 4
public var secureEntry: Bool = false
//--------------------------------------------------
// MARK: - Keys
@ -35,8 +35,8 @@
required public init(from decoder: Decoder) throws {
try super.init(from: decoder)
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
digits = try typeContainer.decodeIfPresent(Int.self, forKey: .digits)
secureEntry = try typeContainer.decodeIfPresent(Bool.self, forKey: .secureEntry)
digits = try typeContainer.decodeIfPresent(Int.self, forKey: .digits) ?? 4
secureEntry = try typeContainer.decodeIfPresent(Bool.self, forKey: .secureEntry) ?? false
}
public override func encode(to encoder: Encoder) throws {

View File

@ -248,29 +248,12 @@ import UIKit
entryFieldContainer.setWithModel(model, delegateObject, additionalData)
if let title = model.title {
self.title = title
}
if let isDisabled = model.isDisabled {
self.isEnabled = isDisabled
}
if let feedback = model.feedback {
self.feedback = feedback
}
if let errorMessage = model.errorMessage {
self.errorMessage = errorMessage
}
if let isLocked = model.isLocked {
self.isLocked = isLocked
}
if let isSelected = model.isSelected {
self.isSelected = isSelected
}
title = model.title
isEnabled = model.isEnabled
feedback = model.feedback
errorMessage = model.errorMessage
isLocked = model.isLocked
isSelected = model.isSelected
if let fieldKey = model.fieldKey {
self.fieldKey = fieldKey

View File

@ -21,11 +21,10 @@ import Foundation
public var backgroundColor: Color?
public var title: String?
public var feedback: String?
public var errorMessage: String?
public var isDisabled: Bool?
public var isLocked: Bool?
public var isSelected: Bool?
public var errorMessage: String = ""
public var isEnabled: Bool = true
public var isLocked: Bool = false
public var isSelected: Bool = false
public var fieldKey: String?
public var isValid: Bool?
public var isRequired: Bool?
@ -37,7 +36,7 @@ import Foundation
private enum CodingKeys: String, CodingKey {
case backgroundColor
case title
case isDisabled
case isEnabled
case feedback
case errorMessage = "errorMsg"
case isLocked
@ -56,10 +55,10 @@ import Foundation
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
title = try typeContainer.decodeIfPresent(String.self, forKey: .title)
feedback = try typeContainer.decodeIfPresent(String.self, forKey: .feedback)
errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage)
isDisabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .isDisabled)
isLocked = try typeContainer.decodeIfPresent(Bool.self, forKey: .isLocked)
isSelected = try typeContainer.decodeIfPresent(Bool.self, forKey: .isSelected)
errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage) ?? ""
isEnabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .isEnabled) ?? true
isLocked = try typeContainer.decodeIfPresent(Bool.self, forKey: .isLocked) ?? false
isSelected = try typeContainer.decodeIfPresent(Bool.self, forKey: .isSelected) ?? false
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
isValid = try typeContainer.decodeIfPresent(Bool.self, forKey: .isValid)
}
@ -70,7 +69,7 @@ import Foundation
try container.encodeIfPresent(title, forKey: .title)
try container.encodeIfPresent(feedback, forKey: .feedback)
try container.encodeIfPresent(errorMessage, forKey: .errorMessage)
try container.encodeIfPresent(isDisabled, forKey: .isDisabled)
try container.encodeIfPresent(isEnabled, forKey: .isEnabled)
try container.encodeIfPresent(isLocked, forKey: .isLocked)
try container.encodeIfPresent(isSelected, forKey: .isSelected)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)

View File

@ -115,10 +115,14 @@ extension ItemDropdownEntryField: UIPickerViewDelegate, UIPickerViewDataSource {
}
@objc public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
guard !pickerData.isEmpty else { return nil }
return pickerData[row]
}
@objc public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
guard !pickerData.isEmpty else { return }
observeDropdownChange?(text ?? "", pickerData[row])
text = pickerData[row]
}

View File

@ -16,28 +16,4 @@
}
public var options: [String]?
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case options
}
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
try super.init(from: decoder)
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
options = try typeContainer.decodeIfPresent([String].self, forKey: .options)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(options, forKey: .options)
}
}

View File

@ -286,13 +286,9 @@ import UIKit
textColor.disabled = disabledTextColor.uiColor
}
if let text = model.text {
self.text = text
}
text = model.text
placeholder = model.placeholder
if let placeholder = model.placeholder {
self.placeholder = placeholder
}
switch model.type {
case "password":

View File

@ -0,0 +1,293 @@
//
// EntryFieldContainer.swift
// MVMCoreUI
//
// Created by Kevin Christiano on 11/12/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class EntryFieldContainer: View {
//--------------------------------------------------
// MARK: - Drawing Properties
//--------------------------------------------------
/// The bottom border line. Height is dynamic based on scenario.
public var bottomBar: CAShapeLayer? = {
let layer = CAShapeLayer()
layer.backgroundColor = UIColor.black.cgColor
layer.drawsAsynchronously = true
layer.anchorPoint = CGPoint(x: 0.5, y: 1.0);
return layer
}()
/// Total control over the drawn top, bottom, left and right borders.
public var disableAllBorders = false {
didSet {
bottomBar?.isHidden = disableAllBorders
}
}
private(set) var fieldState: FieldState = .original {
didSet (oldState) {
// Will not update if new state is the same as old.
if fieldState != oldState {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
self.fieldState.setStateUI(for: self)
}
}
}
}
/// Determines if the top, left, and right borders should be drawn.
private var hideBorders = false
public var borderStrokeColor: UIColor = .mfSilver()
private var borderPath: UIBezierPath = UIBezierPath()
//--------------------------------------------------
// MARK: - Property Observers
//--------------------------------------------------
private var _isEnabled: Bool = true
private var _showError: Bool = false
private var _isLocked: Bool = false
private var _isSelected: Bool = false
public var isEnabled: Bool {
get { return _isEnabled }
set (enabled) {
_isEnabled = enabled
_isLocked = false
_isSelected = false
_showError = false
fieldState = enabled ? .original : .disabled
}
}
public var showError: Bool {
get { return _showError }
set (error) {
_showError = error
_isEnabled = true
_isLocked = false
_isSelected = false
fieldState = error ? .error : .original
}
}
public var isLocked: Bool {
get { return _isLocked }
set (locked) {
_isLocked = locked
_isEnabled = true
_isSelected = false
_showError = false
fieldState = locked ? .locked : .original
}
}
public var isSelected: Bool {
get { return _isSelected }
set (selected) {
_isSelected = selected
_isLocked = false
_isEnabled = true
if _showError {
fieldState = selected ? .selectedError : .error
} else {
fieldState = selected ? .selected : .original
}
}
}
//--------------------------------------------------
// MARK: - Delegate
//--------------------------------------------------
/// Holds reference to delegateObject to inform molecular tableView of an update.
var delegateObject: MVMCoreUIDelegateObject?
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func layoutSubviews() {
super.layoutSubviews()
refreshUI(bottomBarSize: showError ? 4 : 1)
}
open override func updateView(_ size: CGFloat) {
super.updateView(size)
refreshUI()
}
/// This handles the top, left, and right border lines.
open override func draw(_ rect: CGRect) {
super.draw(rect)
borderPath.removeAllPoints()
if !disableAllBorders && !hideBorders {
// Brings the other half of the line inside the view to prevent cropping.
let origin = bounds.origin
let size = frame.size
let insetLean: CGFloat = 0.5
borderPath.lineWidth = 1
borderPath.move(to: CGPoint(x: origin.x + insetLean, y: origin.y + size.height))
borderPath.addLine(to: CGPoint(x: origin.x + insetLean, y: origin.y + insetLean))
borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + insetLean))
borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + size.height))
borderStrokeColor.setStroke()
borderPath.stroke()
}
}
override open func setupView() {
super.setupView()
isAccessibilityElement = false
isOpaque = false
if let bottomBar = bottomBar {
layer.addSublayer(bottomBar)
}
}
//--------------------------------------------------
// MARK: - Draw States
//--------------------------------------------------
public enum FieldState {
case original
case error
case selectedError
case selected
case locked
case disabled
public func setStateUI(for formField: EntryFieldContainer) {
switch self {
case .original:
formField.originalUI()
case .error:
formField.errorUI()
case .selectedError:
formField.selectedErrorUI()
case .selected:
formField.selectedUI()
case .locked:
formField.lockedUI()
case .disabled:
formField.disabledUI()
}
}
}
open func originalUI() {
isUserInteractionEnabled = true
hideBorders = false
borderStrokeColor = .mfSilver()
bottomBar?.backgroundColor = UIColor.black.cgColor
refreshUI(bottomBarSize: 1)
}
open func errorUI() {
isUserInteractionEnabled = true
hideBorders = false
borderStrokeColor = .mfPumpkin()
bottomBar?.backgroundColor = UIColor.mfPumpkin().cgColor
refreshUI(bottomBarSize: 4)
}
open func selectedErrorUI() {
isUserInteractionEnabled = true
hideBorders = false
borderStrokeColor = .black
bottomBar?.backgroundColor = UIColor.mfPumpkin().cgColor
refreshUI(bottomBarSize: 4)
}
open func selectedUI() {
isUserInteractionEnabled = true
hideBorders = false
borderStrokeColor = .black
bottomBar?.backgroundColor = UIColor.black.cgColor
refreshUI(bottomBarSize: 1)
}
open func lockedUI() {
isUserInteractionEnabled = false
hideBorders = true
borderStrokeColor = .clear
bottomBar?.backgroundColor = UIColor.clear.cgColor
refreshUI(bottomBarSize: 1)
}
open func disabledUI() {
isUserInteractionEnabled = false
hideBorders = false
borderStrokeColor = .mfSilver()
bottomBar?.backgroundColor = UIColor.mfSilver().cgColor
refreshUI(bottomBarSize: 1)
}
open func refreshUI(bottomBarSize: CGFloat? = nil) {
if !disableAllBorders {
let size: CGFloat = bottomBarSize ?? (showError ? 4 : 1)
bottomBar?.frame = CGRect(x: 0, y: bounds.height - size, width: bounds.width, height: size)
delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self)
setNeedsDisplay()
layoutIfNeeded()
}
}
//--------------------------------------------------
// MARK: - MVMCoreUIMoleculeViewProtocol
//--------------------------------------------------
open override func setWithModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.setWithModel(model, delegateObject, additionalData)
self.delegateObject = delegateObject
}
}
extension EntryFieldContainer {
override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
self.delegateObject = delegateObject
guard let dictionary = json, !dictionary.isEmpty else { return }
}
}

View File

@ -9,21 +9,25 @@
import UIKit
@objcMembers public class DropDownFilterTableViewCell: TableViewCell {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
var dropDownListItemModel: DropDownListItemModel?
let dropDown = ItemDropdownEntryField()
var delegateObject: MVMCoreUIDelegateObject?
var previousIndex = NSNotFound
var dropDownSelectionObservation: NSKeyValueObservation?
//--------------------------------------------------
// MARK: - MFViewProtocol
//--------------------------------------------------
override public func setupView() {
super.setupView()
guard dropDown.superview == nil else { return }
dropDown.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(dropDown)
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: dropDown, useMargins: true).values))
dropDown.observeDropdownChange = { [weak self] oldValue, newValue in

View File

@ -9,6 +9,7 @@
import Foundation
@objcMembers public class DropDownListItemModel: ContainerModel, ListItemModelProtocol {
public static var identifier: String = "dropDownListItem"
public var molecules: [[ListItemModelProtocol]]
public var dropDown: ItemDropdownEntryFieldModel
@ -33,9 +34,11 @@ import Foundation
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
molecules = try typeContainer.decodeMolecules2D(codingKey: .molecules) as! [[ListItemModelProtocol]]
dropDown = try typeContainer.decode(ItemDropdownEntryFieldModel.self, forKey: .dropDown)
if let lineModel = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) {
line = lineModel
}
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
try super.init(from: decoder)
}