Merge branch 'develop' into feature/client_paramter_processing
This commit is contained in:
commit
befacbd150
@ -11,12 +11,14 @@ import UIKit
|
|||||||
public typealias FacadeElements = (fill: UIColor?, text: UIColor?, border: UIColor?)
|
public typealias FacadeElements = (fill: UIColor?, text: UIColor?, border: UIColor?)
|
||||||
|
|
||||||
|
|
||||||
public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWatcherFieldProtocol, EnableableModelProtocol {
|
open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWatcherFieldProtocol, EnableableModelProtocol {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
//Making static property as class property so that subclasses can override getter function of the property
|
||||||
public static var identifier: String = "button"
|
open class var identifier: String {
|
||||||
|
"button"
|
||||||
|
}
|
||||||
public var backgroundColor: Color?
|
public var backgroundColor: Color?
|
||||||
public var accessibilityIdentifier: String?
|
public var accessibilityIdentifier: String?
|
||||||
public var title: String
|
public var title: String
|
||||||
@ -247,7 +249,7 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
open func encode(to encoder: Encoder) throws {
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
try container.encode(moleculeName, forKey: .moleculeName)
|
try container.encode(moleculeName, forKey: .moleculeName)
|
||||||
try container.encode(title, forKey: .title)
|
try container.encode(title, forKey: .title)
|
||||||
|
|||||||
@ -71,6 +71,10 @@ open class MultiItemDropdownEntryField: BaseItemPickerEntryField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pickerHasComponent(_ index: Int) -> Bool {
|
||||||
|
!pickerComponents.isEmpty && !pickerComponents[index].isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - TextField Observation
|
// MARK: - TextField Observation
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -122,18 +126,14 @@ open class MultiItemDropdownEntryField: BaseItemPickerEntryField {
|
|||||||
|
|
||||||
@objc public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
|
@objc public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
|
||||||
|
|
||||||
guard !pickerComponents.isEmpty,
|
guard pickerHasComponent(component) else { return nil }
|
||||||
!pickerComponents[component].isEmpty
|
|
||||||
else { return nil }
|
|
||||||
|
|
||||||
return pickerComponents[component][row]
|
return pickerComponents[component][row]
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
|
@objc public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
|
||||||
|
|
||||||
guard !pickerComponents.isEmpty,
|
guard pickerHasComponent(component) else { return }
|
||||||
!pickerComponents[component].isEmpty
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
let oldText = text ?? ""
|
let oldText = text ?? ""
|
||||||
dropdownModel?.selectedIndexes[component] = row
|
dropdownModel?.selectedIndexes[component] = row
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import Foundation
|
|||||||
|
|
||||||
public var components: [[String]] = [[]]
|
public var components: [[String]] = [[]]
|
||||||
public var selectedIndexes: [Int: Int] = [:]
|
public var selectedIndexes: [Int: Int] = [:]
|
||||||
public var delimiters: [String]?
|
public var delimiters: [Int: String] = [:]
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Validation
|
// MARK: - Validation
|
||||||
@ -31,12 +31,17 @@ import Foundation
|
|||||||
return selectedRowText
|
return selectedRowText
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// - parameter index: The index of the delimiter.
|
||||||
|
/// - returns: The delimiter for a given index. Defaults to whitespace for valid index if no delimiters is provided. If invalid index, empty string.
|
||||||
public func delimiter(for index: Int) -> String {
|
public func delimiter(for index: Int) -> String {
|
||||||
|
|
||||||
guard let delimiters = delimiters else { return " " }
|
|
||||||
guard index != components.count - 1 else { return "" }
|
guard index != components.count - 1 else { return "" }
|
||||||
|
|
||||||
return delimiters[index]
|
return delimiters[index, default: " "]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A string of the picker row concatenated by whitespace or delimiters if provided.
|
/// A string of the picker row concatenated by whitespace or delimiters if provided.
|
||||||
@ -64,6 +69,18 @@ import Foundation
|
|||||||
return indexArray
|
return indexArray
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var delimiterArray: [String] {
|
||||||
|
|
||||||
|
var array: [String] = []
|
||||||
|
|
||||||
|
for i in 0..<delimiters.count {
|
||||||
|
guard let delimiterIndex = delimiters[i] else { return [] }
|
||||||
|
array.append(delimiterIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Keys
|
// MARK: - Keys
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -83,7 +100,12 @@ import Foundation
|
|||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
components = try typeContainer.decode([[String]].self, forKey: .components)
|
components = try typeContainer.decode([[String]].self, forKey: .components)
|
||||||
delimiters = try typeContainer.decodeIfPresent([String].self, forKey: .delimiters)
|
|
||||||
|
if let delimiters = try typeContainer.decodeIfPresent([String].self, forKey: .delimiters) {
|
||||||
|
for (index, delimiter) in delimiters.enumerated() {
|
||||||
|
self.delimiters[index] = delimiter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let indexes = try typeContainer.decodeIfPresent([Int].self, forKey: .selectedIndexes) {
|
if let indexes = try typeContainer.decodeIfPresent([Int].self, forKey: .selectedIndexes) {
|
||||||
for (component, index) in indexes.enumerated() {
|
for (component, index) in indexes.enumerated() {
|
||||||
@ -99,6 +121,6 @@ import Foundation
|
|||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
try container.encode(components, forKey: .components)
|
try container.encode(components, forKey: .components)
|
||||||
try container.encode(selectedIndexesArray, forKey: .selectedIndexes)
|
try container.encode(selectedIndexesArray, forKey: .selectedIndexes)
|
||||||
try container.encodeIfPresent(delimiters, forKey: .delimiters)
|
try container.encodeIfPresent(delimiterArray, forKey: .delimiters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,10 +60,10 @@ import UIKit
|
|||||||
public var isEnabled: Bool {
|
public var isEnabled: Bool {
|
||||||
get { entryFieldContainer.isEnabled }
|
get { entryFieldContainer.isEnabled }
|
||||||
set (enabled) {
|
set (enabled) {
|
||||||
self.titleLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
titleLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
||||||
self.feedbackLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
feedbackLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
||||||
self.entryFieldContainer.isEnabled = enabled
|
entryFieldContainer.isEnabled = enabled
|
||||||
self.entryFieldModel?.enabled = enabled
|
entryFieldModel?.enabled = enabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,10 +71,10 @@ import UIKit
|
|||||||
public var showError: Bool {
|
public var showError: Bool {
|
||||||
get { entryFieldContainer.showError }
|
get { entryFieldContainer.showError }
|
||||||
set (error) {
|
set (error) {
|
||||||
self.feedback = error ? errorMessage : entryFieldModel?.feedback
|
feedback = error ? errorMessage : entryFieldModel?.feedback
|
||||||
self.feedbackLabel.textColor = error ? entryFieldModel?.errorTextColor?.uiColor ?? .mvmBlack : .mvmBlack
|
feedbackLabel.textColor = error ? entryFieldModel?.errorTextColor?.uiColor ?? .mvmBlack : .mvmBlack
|
||||||
self.entryFieldContainer.showError = error
|
entryFieldContainer.showError = error
|
||||||
self.entryFieldModel?.showError = error
|
entryFieldModel?.showError = error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,8 +86,8 @@ import UIKit
|
|||||||
public var isLocked: Bool {
|
public var isLocked: Bool {
|
||||||
get { entryFieldContainer.isLocked }
|
get { entryFieldContainer.isLocked }
|
||||||
set (locked) {
|
set (locked) {
|
||||||
self.entryFieldContainer.isLocked = locked
|
entryFieldContainer.isLocked = locked
|
||||||
self.entryFieldModel?.locked = locked
|
entryFieldModel?.locked = locked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,17 +95,17 @@ import UIKit
|
|||||||
public var isSelected: Bool {
|
public var isSelected: Bool {
|
||||||
get { entryFieldContainer.isSelected }
|
get { entryFieldContainer.isSelected }
|
||||||
set (selected) {
|
set (selected) {
|
||||||
self.entryFieldContainer.isSelected = selected
|
entryFieldContainer.isSelected = selected
|
||||||
self.entryFieldModel?.selected = selected
|
entryFieldModel?.selected = selected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the text of titleLabel
|
/// Sets the text of titleLabel
|
||||||
public var title: String? {
|
public var title: String? {
|
||||||
get { titleLabel.text }
|
get { titleLabel.text }
|
||||||
set (newText) {
|
set {
|
||||||
titleLabel.text = newText
|
titleLabel.text = newValue
|
||||||
setAccessibilityString(newText)
|
setAccessibilityString(newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,10 +118,9 @@ import UIKit
|
|||||||
/// Sets feedback text in the textField.
|
/// Sets feedback text in the textField.
|
||||||
public var feedback: String? {
|
public var feedback: String? {
|
||||||
get { feedbackLabel.text }
|
get { feedbackLabel.text }
|
||||||
set (newFeedback) {
|
set {
|
||||||
feedbackLabel.text = newFeedback
|
feedbackLabel.text = newValue
|
||||||
feedbackLabel.accessibilityElementsHidden = feedbackLabel.text?.isEmpty ?? true
|
feedbackLabel.accessibilityElementsHidden = feedbackLabel.text?.isEmpty ?? true
|
||||||
entryFieldContainer.refreshUI(updateMoleculeLayout: true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,12 +319,14 @@ import UIKit
|
|||||||
model.updateUIDynamicError = { [weak self] in
|
model.updateUIDynamicError = { [weak self] in
|
||||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
let validState = model.isValid ?? false
|
let validState = model.isValid ?? false
|
||||||
self.updateValidation(validState)
|
|
||||||
if !validState && model.shouldClearText {
|
if !validState && model.shouldClearText {
|
||||||
self.text = ""
|
self.text = ""
|
||||||
model.shouldClearText = false
|
model.shouldClearText = false
|
||||||
}
|
}
|
||||||
|
_ = FormValidator.validate(delegate: self.delegateObject?.formHolderDelegate)
|
||||||
|
self.updateValidation(validState)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -147,6 +147,16 @@ import MVMCore
|
|||||||
MVMCoreNavigationHandler.shared()?.present(picker, animated: true)
|
MVMCoreNavigationHandler.shared()?.present(picker, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
|
textField.keyboardType = .phonePad
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Contact Picker Delegate
|
// MARK: - Contact Picker Delegate
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -97,23 +97,7 @@ import UIKit
|
|||||||
get { textField.text }
|
get { textField.text }
|
||||||
set {
|
set {
|
||||||
textEntryFieldModel?.text = newValue
|
textEntryFieldModel?.text = newValue
|
||||||
|
textField.text = newValue
|
||||||
guard let regex = textEntryFieldModel?.displayFormat,
|
|
||||||
let mask = textEntryFieldModel?.displayMask,
|
|
||||||
let newText = newValue
|
|
||||||
else {
|
|
||||||
textField.text = newValue
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let range = NSRange(newText.startIndex..., in: newText)
|
|
||||||
|
|
||||||
if let regex = try? NSRegularExpression(pattern: regex) {
|
|
||||||
let maskedText = regex.stringByReplacingMatches(in: newText,
|
|
||||||
range: range,
|
|
||||||
withTemplate: mask)
|
|
||||||
textField.text = maskedText
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,9 +263,28 @@ import UIKit
|
|||||||
self.isValid = isValid
|
self.isValid = isValid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regexTextFieldOutputIfAvailable()
|
||||||
|
|
||||||
shouldShowError(!isValid)
|
shouldShowError(!isValid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func regexTextFieldOutputIfAvailable() {
|
||||||
|
|
||||||
|
if let regex = textEntryFieldModel?.displayFormat,
|
||||||
|
let mask = textEntryFieldModel?.displayMask,
|
||||||
|
let finalText = text {
|
||||||
|
|
||||||
|
let range = NSRange(finalText.startIndex..., in: finalText)
|
||||||
|
|
||||||
|
if let regex = try? NSRegularExpression(pattern: regex) {
|
||||||
|
let maskedText = regex.stringByReplacingMatches(in: finalText,
|
||||||
|
range: range,
|
||||||
|
withTemplate: mask)
|
||||||
|
textField.text = maskedText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc public func dismissFieldInput(_ sender: Any?) {
|
@objc public func dismissFieldInput(_ sender: Any?) {
|
||||||
resignFirstResponder()
|
resignFirstResponder()
|
||||||
}
|
}
|
||||||
@ -347,7 +350,8 @@ import UIKit
|
|||||||
case .phone:
|
case .phone:
|
||||||
textField.keyboardType = .phonePad
|
textField.keyboardType = .phonePad
|
||||||
|
|
||||||
default: break
|
default:
|
||||||
|
textField.keyboardType = .default
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override the preset keyboard set in type.
|
// Override the preset keyboard set in type.
|
||||||
|
|||||||
@ -624,6 +624,9 @@ public typealias ActionBlock = () -> ()
|
|||||||
} else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject = sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) {
|
} else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject = sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) {
|
||||||
font = font.updateSize(sizeObject.getValueBased(onSize: size))
|
font = font.updateSize(sizeObject.getValueBased(onSize: size))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Provide the label additional size information to help calculate its intrinsic content.
|
||||||
|
preferredMaxLayoutWidth = Styler.maxAvailableLayoutWidth(size: size)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func setFont(_ font: UIFont, scale: Bool) {
|
@objc public func setFont(_ font: UIFont, scale: Bool) {
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||||
// Fill for left vertical alignment because bottom constraint was breaking with leading. CXTDT-145456
|
// Fill for left vertical alignment because bottom constraint was breaking with leading. CXTDT-145456
|
||||||
stack = Stack<StackModel>.createStack(with: [(view: eyebrowHeadlineBodyLink, model: StackItemModel(horizontalAlignment: .leading, verticalAlignment: .fill)), (view: rightLabel, model: StackItemModel(horizontalAlignment:.fill, verticalAlignment: .leading))], axis: .horizontal)
|
stack = Stack<StackModel>.createStack(with: [(view: eyebrowHeadlineBodyLink, model: StackItemModel(horizontalAlignment: .leading, verticalAlignment: .fill)), (view: rightLabel, model: StackItemModel(horizontalAlignment: .trailing, verticalAlignment: .leading))], axis: .horizontal)
|
||||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +37,8 @@
|
|||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal)
|
rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal)
|
||||||
|
rightLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal)
|
||||||
|
rightLabel.numberOfLines = 1
|
||||||
addMolecule(stack)
|
addMolecule(stack)
|
||||||
stack.restack()
|
stack.restack()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,9 @@ import Foundation
|
|||||||
public var peakingUI: Bool?
|
public var peakingUI: Bool?
|
||||||
public var peakingArrowColor: Color?
|
public var peakingArrowColor: Color?
|
||||||
public var analyticsData: JSONValueDictionary?
|
public var analyticsData: JSONValueDictionary?
|
||||||
|
public var fieldValue: String?
|
||||||
|
|
||||||
|
public func formFieldValue() -> AnyHashable? { return fieldValue }
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Keys
|
// MARK: - Keys
|
||||||
@ -30,6 +33,7 @@ import Foundation
|
|||||||
case peakingUI
|
case peakingUI
|
||||||
case peakingArrowColor
|
case peakingArrowColor
|
||||||
case analyticsData
|
case analyticsData
|
||||||
|
case fieldValue
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -41,6 +45,7 @@ import Foundation
|
|||||||
peakingUI = try typeContainer.decodeIfPresent(Bool.self, forKey: .peakingUI)
|
peakingUI = try typeContainer.decodeIfPresent(Bool.self, forKey: .peakingUI)
|
||||||
peakingArrowColor = try typeContainer.decodeIfPresent(Color.self, forKey: .peakingArrowColor)
|
peakingArrowColor = try typeContainer.decodeIfPresent(Color.self, forKey: .peakingArrowColor)
|
||||||
analyticsData = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .analyticsData)
|
analyticsData = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .analyticsData)
|
||||||
|
fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue)
|
||||||
try super.init(from: decoder)
|
try super.init(from: decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,5 +55,6 @@ import Foundation
|
|||||||
try container.encodeIfPresent(peakingUI, forKey: .peakingUI)
|
try container.encodeIfPresent(peakingUI, forKey: .peakingUI)
|
||||||
try container.encodeIfPresent(peakingArrowColor, forKey: .peakingArrowColor)
|
try container.encodeIfPresent(peakingArrowColor, forKey: .peakingArrowColor)
|
||||||
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
|
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
|
||||||
|
try container.encodeIfPresent(fieldValue, forKey: .fieldValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -167,12 +167,17 @@ open class Carousel: View {
|
|||||||
|
|
||||||
registerCells(with: carouselModel, delegateObject: delegateObject)
|
registerCells(with: carouselModel, delegateObject: delegateObject)
|
||||||
prepareMolecules(with: carouselModel)
|
prepareMolecules(with: carouselModel)
|
||||||
|
FormValidator.setupValidation(for: carouselModel, delegate: delegateObject?.formHolderDelegate)
|
||||||
|
|
||||||
setupPagingMolecule(carouselModel.pagingMolecule, delegateObject: delegateObject)
|
setupPagingMolecule(carouselModel.pagingMolecule, delegateObject: delegateObject)
|
||||||
|
|
||||||
pageIndex = carouselModel.index
|
pageIndex = carouselModel.index
|
||||||
pagingView?.currentIndex = carouselModel.index
|
pagingView?.currentIndex = carouselModel.index
|
||||||
collectionView.reloadData()
|
collectionView.reloadData()
|
||||||
|
if let selectedIndex = carouselModel.selectedIndex {
|
||||||
|
let adjustedIndex = loop ? selectedIndex + 2 : selectedIndex
|
||||||
|
collectionView.selectItem(at: IndexPath(row: adjustedIndex, section: 0), animated: false, scrollPosition: [])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -391,8 +396,25 @@ extension Carousel: UICollectionViewDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension Carousel: UICollectionViewDelegate {
|
extension Carousel: UICollectionViewDelegate {
|
||||||
|
public func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
|
||||||
|
guard let cell = collectionView.cellForItem(at: indexPath) as? CollectionTemplateItemProtocol else { return false }
|
||||||
|
return cell.shouldSelect(at: indexPath, delegateObject: delegateObject, additionalData: nil)
|
||||||
|
}
|
||||||
|
|
||||||
open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||||
(collectionView.cellForItem(at: indexPath) as? CollectionTemplateItemProtocol)?.didSelectCell(at: indexPath, delegateObject: delegateObject, additionalData: nil)
|
// Set the selection in the model
|
||||||
|
if let model = model as? CarouselModel {
|
||||||
|
// Adjust for looping
|
||||||
|
var adjustedIndex = loop ? indexPath.row - 2 : indexPath.row
|
||||||
|
if adjustedIndex < 0 {
|
||||||
|
adjustedIndex = adjustedIndex + numberOfPages
|
||||||
|
}
|
||||||
|
model.selectedIndex = adjustedIndex
|
||||||
|
}
|
||||||
|
if let cell = collectionView.cellForItem(at: indexPath) as? CollectionTemplateItemProtocol {
|
||||||
|
cell.didSelectCell(at: indexPath, delegateObject: delegateObject, additionalData: nil)
|
||||||
|
}
|
||||||
|
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,6 +436,7 @@ extension Carousel: UIScrollViewDelegate {
|
|||||||
if !animated {
|
if !animated {
|
||||||
scrollViewDidEndScrollingAnimation(collectionView)
|
scrollViewDidEndScrollingAnimation(collectionView)
|
||||||
}
|
}
|
||||||
|
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adjusts the current contentOffset if we are going onto buffer cells while looping to help with the endless scrolling appearance.
|
/// Adjusts the current contentOffset if we are going onto buffer cells while looping to help with the endless scrolling appearance.
|
||||||
|
|||||||
@ -9,7 +9,8 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
@objcMembers public class CarouselModel: MoleculeModelProtocol {
|
@objcMembers public class CarouselModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -33,11 +34,31 @@ import UIKit
|
|||||||
public var leftPadding: CGFloat?
|
public var leftPadding: CGFloat?
|
||||||
public var rightPadding: CGFloat?
|
public var rightPadding: CGFloat?
|
||||||
public var accessibilityText: String?
|
public var accessibilityText: String?
|
||||||
|
public var baseValue: AnyHashable?
|
||||||
|
public var fieldKey: String?
|
||||||
|
public var groupName: String = FormValidator.defaultGroupName
|
||||||
|
|
||||||
|
public var selectable = false
|
||||||
|
public var selectedIndex: Int?
|
||||||
|
|
||||||
public init(molecules: [MoleculeModelProtocol & CarouselItemModelProtocol]) {
|
public init(molecules: [MoleculeModelProtocol & CarouselItemModelProtocol]) {
|
||||||
self.molecules = molecules
|
self.molecules = molecules
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func formFieldValue() -> AnyHashable? {
|
||||||
|
guard selectable else {
|
||||||
|
// Use visible item value, else index
|
||||||
|
if let fieldValue = molecules[index].formFieldValue() {
|
||||||
|
return fieldValue
|
||||||
|
}
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
// Use selected item value, else index
|
||||||
|
guard let selectedIndex = selectedIndex else { return nil }
|
||||||
|
guard let fieldValue = molecules[selectedIndex].formFieldValue() else { return selectedIndex }
|
||||||
|
return fieldValue
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Keys
|
// MARK: - Keys
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -59,6 +80,10 @@ import UIKit
|
|||||||
case leftPadding
|
case leftPadding
|
||||||
case rightPadding
|
case rightPadding
|
||||||
case accessibilityText
|
case accessibilityText
|
||||||
|
case groupName
|
||||||
|
case fieldKey
|
||||||
|
case selectable
|
||||||
|
case selectedIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -69,6 +94,8 @@ import UIKit
|
|||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
molecules = try typeContainer.decodeModels(codingKey: .molecules)
|
molecules = try typeContainer.decodeModels(codingKey: .molecules)
|
||||||
index = try typeContainer.decodeIfPresent(Int.self, forKey: .index) ?? 0
|
index = try typeContainer.decodeIfPresent(Int.self, forKey: .index) ?? 0
|
||||||
|
selectable = try typeContainer.decodeIfPresent(Bool.self, forKey: .selectable) ?? false
|
||||||
|
selectedIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedIndex)
|
||||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||||
spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing)
|
spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing)
|
||||||
border = try typeContainer.decodeIfPresent(Bool.self, forKey: .border)
|
border = try typeContainer.decodeIfPresent(Bool.self, forKey: .border)
|
||||||
@ -86,6 +113,11 @@ import UIKit
|
|||||||
leftPadding = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .leftPadding)
|
leftPadding = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .leftPadding)
|
||||||
rightPadding = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .rightPadding)
|
rightPadding = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .rightPadding)
|
||||||
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
|
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
|
||||||
|
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
|
||||||
|
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
|
||||||
|
self.groupName = groupName
|
||||||
|
}
|
||||||
|
baseValue = formFieldValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
@ -105,5 +137,10 @@ import UIKit
|
|||||||
try container.encodeIfPresent(leftPadding, forKey: .leftPadding)
|
try container.encodeIfPresent(leftPadding, forKey: .leftPadding)
|
||||||
try container.encodeIfPresent(rightPadding, forKey: .rightPadding)
|
try container.encodeIfPresent(rightPadding, forKey: .rightPadding)
|
||||||
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
||||||
|
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||||
|
try container.encode(groupName, forKey: .groupName)
|
||||||
|
try container.encode(index, forKey: .index)
|
||||||
|
try container.encode(selectable, forKey: .selectable)
|
||||||
|
try container.encode(selectedIndex, forKey: .selectedIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,11 +11,14 @@ import Foundation
|
|||||||
|
|
||||||
public protocol CarouselItemModelProtocol: ContainerModelProtocol {
|
public protocol CarouselItemModelProtocol: ContainerModelProtocol {
|
||||||
var analyticsData: JSONValueDictionary? { get set }
|
var analyticsData: JSONValueDictionary? { get set }
|
||||||
|
func formFieldValue() -> AnyHashable?
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension CarouselItemModelProtocol {
|
public extension CarouselItemModelProtocol {
|
||||||
|
|
||||||
var analyticsData: JSONValueDictionary? {
|
var analyticsData: JSONValueDictionary? {
|
||||||
get { return nil }
|
get { return nil }
|
||||||
set { analyticsData = newValue }
|
set { analyticsData = newValue }
|
||||||
}
|
}
|
||||||
|
func formFieldValue() -> AnyHashable? { return nil }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,9 @@ public protocol CollectionTemplateItemProtocol: UICollectionViewCell {
|
|||||||
|
|
||||||
/// Called when the cell will display.
|
/// Called when the cell will display.
|
||||||
func willDisplay()
|
func willDisplay()
|
||||||
|
|
||||||
|
/// Handle the selection of cell
|
||||||
|
func shouldSelect(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default implementation does nothing
|
// Default implementation does nothing
|
||||||
@ -26,4 +29,8 @@ extension CollectionTemplateItemProtocol {
|
|||||||
public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {}
|
public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {}
|
||||||
|
|
||||||
public func willDisplay() {}
|
public func willDisplay() {}
|
||||||
|
|
||||||
|
public func shouldSelect(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -116,11 +116,15 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo
|
|||||||
|
|
||||||
// MARK: - Override
|
// MARK: - Override
|
||||||
|
|
||||||
open func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
|
open func shouldSelect(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Bool {
|
||||||
guard let action = model?.action else { return }
|
if let action = model?.action {
|
||||||
Button.performButtonAction(with: action, button: self, delegateObject: delegateObject, additionalData: additionalData)
|
Button.performButtonAction(with: action, button: self, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {}
|
||||||
|
|
||||||
// Column logic, set width.
|
// Column logic, set width.
|
||||||
override open func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
|
override open func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
|
||||||
let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
|
let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
|
||||||
|
|||||||
@ -6,8 +6,6 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
/// Padding is a multiple based on the number 4.
|
/// Padding is a multiple based on the number 4.
|
||||||
public struct Padding {
|
public struct Padding {
|
||||||
@ -30,19 +28,19 @@ public struct Padding {
|
|||||||
public static let VerticalMarginSpacing: CGFloat = 24
|
public static let VerticalMarginSpacing: CGFloat = 24
|
||||||
|
|
||||||
public static var horizontalPaddingForApplicationWidth: CGFloat {
|
public static var horizontalPaddingForApplicationWidth: CGFloat {
|
||||||
return MFSizeObject(scalingStandardSize: HorizontalMarginSpacing)?.getValueBasedOnApplicationWidth() ?? HorizontalMarginSpacing
|
MFSizeObject(scalingStandardSize: HorizontalMarginSpacing)?.getValueBasedOnApplicationWidth() ?? HorizontalMarginSpacing
|
||||||
}
|
}
|
||||||
|
|
||||||
public static var verticalPaddingForApplicationWidth: CGFloat {
|
public static var verticalPaddingForApplicationWidth: CGFloat {
|
||||||
return MFSizeObject(scalingStandardSize: VerticalMarginSpacing)?.getValueBasedOnApplicationWidth() ?? VerticalMarginSpacing
|
MFSizeObject(scalingStandardSize: VerticalMarginSpacing)?.getValueBasedOnApplicationWidth() ?? VerticalMarginSpacing
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func horizontalPaddingForSize(_ size: CGFloat) -> CGFloat {
|
public static func horizontalPaddingForSize(_ size: CGFloat) -> CGFloat {
|
||||||
return MFSizeObject(scalingStandardSize: HorizontalMarginSpacing)?.getValueBased(onSize: size) ?? HorizontalMarginSpacing
|
MFSizeObject(scalingStandardSize: HorizontalMarginSpacing)?.getValueBased(onSize: size) ?? HorizontalMarginSpacing
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func verticalPaddingForSize(_ size: CGFloat) -> CGFloat {
|
public static func verticalPaddingForSize(_ size: CGFloat) -> CGFloat {
|
||||||
return MFSizeObject(scalingStandardSize: VerticalMarginSpacing)?.getValueBased(onSize: size) ?? VerticalMarginSpacing
|
MFSizeObject(scalingStandardSize: VerticalMarginSpacing)?.getValueBased(onSize: size) ?? VerticalMarginSpacing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -209,7 +209,14 @@ open class Styler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open class func sizeFontGeneric(forCurrentDevice size: CGFloat) -> CGFloat {
|
open class func sizeFontGeneric(forCurrentDevice size: CGFloat) -> CGFloat {
|
||||||
return sizeObjectGeneric(forCurrentDevice: size)?.getValueBasedOnApplicationWidth() ?? size
|
sizeObjectGeneric(forCurrentDevice: size)?.getValueBasedOnApplicationWidth() ?? size
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provide additional size information to help calculate its intrinsic height.
|
||||||
|
/// - Returns: The available spacing that can be used for intrinsic content width.
|
||||||
|
open class func maxAvailableLayoutWidth(size: CGFloat) -> CGFloat {
|
||||||
|
// The 2 is the product of both sides of padding.
|
||||||
|
size - (Padding.Component.horizontalPaddingForSize(size) * 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user