You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
705 lines
24 KiB
705 lines
24 KiB
// |
|
// IQDropDownTextField.swift |
|
// Copyright (c) 2020-21 Iftekhar Qurashi. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a copy |
|
// of this software and associated documentation files (the "Software"), to deal |
|
// in the Software without restriction, including without limitation the rights |
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
// copies of the Software, and to permit persons to whom the Software is |
|
// furnished to do so, subject to the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included in |
|
// all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
// THE SOFTWARE. |
|
|
|
import UIKit |
|
|
|
// swiftlint:disable type_body_length |
|
// swiftlint:disable file_length |
|
open class IQDropDownTextField: UITextField { |
|
|
|
public static let optionalItemIndex: Int = -1 |
|
|
|
open lazy var pickerView: UIPickerView = { |
|
let view = UIPickerView() |
|
view.autoresizingMask = [.flexibleWidth, .flexibleHeight] |
|
view.showsSelectionIndicator = true |
|
view.delegate = self |
|
view.dataSource = self |
|
return view |
|
}() |
|
|
|
open lazy var timePicker: UIDatePicker = { |
|
let view = UIDatePicker() |
|
view.autoresizingMask = [.flexibleWidth, .flexibleHeight] |
|
view.datePickerMode = .time |
|
if #available(iOS 13.4, *) { |
|
view.preferredDatePickerStyle = .wheels |
|
} |
|
view.addTarget(self, action: #selector(timeChanged(_:)), for: .valueChanged) |
|
return view |
|
}() |
|
|
|
open lazy var dateTimePicker: UIDatePicker = { |
|
let view = UIDatePicker() |
|
view.autoresizingMask = [.flexibleWidth, .flexibleHeight] |
|
view.datePickerMode = .dateAndTime |
|
if #available(iOS 13.4, *) { |
|
view.preferredDatePickerStyle = .wheels |
|
} |
|
view.addTarget(self, action: #selector(dateTimeChanged(_:)), for: .valueChanged) |
|
return view |
|
}() |
|
|
|
open lazy var datePicker: UIDatePicker = { |
|
let view = UIDatePicker() |
|
view.autoresizingMask = [.flexibleWidth, .flexibleHeight] |
|
view.datePickerMode = .date |
|
if #available(iOS 13.4, *) { |
|
view.preferredDatePickerStyle = .wheels |
|
} |
|
view.addTarget(self, action: #selector(dateChanged(_:)), for: .valueChanged) |
|
return view |
|
}() |
|
|
|
private lazy var dismissToolbar: UIToolbar = { |
|
let view = UIToolbar() |
|
view.isTranslucent = true |
|
view.sizeToFit() |
|
let buttonflexible: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, |
|
target: nil, action: nil) |
|
let buttonDone: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, |
|
action: #selector(resignFirstResponder)) |
|
view.items = [buttonflexible, buttonDone] |
|
return view |
|
}() |
|
|
|
open var showDismissToolbar: Bool { |
|
get { |
|
return (inputAccessoryView == dismissToolbar) |
|
} |
|
|
|
set { |
|
inputAccessoryView = (newValue ? dismissToolbar : nil) |
|
} |
|
} |
|
|
|
internal let privateMenuButton: UIButton = UIButton() |
|
|
|
// Sets a custom font for the IQDropdownTextField items. Default is boldSystemFontOfSize:18.0. |
|
open var dropDownFont: UIFont? |
|
|
|
// Sets a custom color for the IQDropdownTextField items. Default is blackColor. |
|
open var dropDownTextColor: UIColor? |
|
|
|
// Width and height to adopt for each section. |
|
// If you don't want to specify a row width then use 0 to calculate row width automatically. |
|
open var widthsForComponents: [CGFloat]? |
|
open var heightsForComponents: [CGFloat]? |
|
|
|
open var dateFormatter: DateFormatter = DateFormatter() { |
|
didSet { |
|
datePicker.locale = dateFormatter.locale |
|
} |
|
} |
|
|
|
open var timeFormatter: DateFormatter = DateFormatter() { |
|
didSet { |
|
timePicker.locale = timeFormatter.locale |
|
} |
|
} |
|
|
|
open var dateTimeFormatter: DateFormatter = DateFormatter() { |
|
didSet { |
|
dateTimePicker.locale = dateTimeFormatter.locale |
|
} |
|
} |
|
|
|
weak open var dropDownDelegate: IQDropDownTextFieldDelegate? |
|
weak open override var delegate: UITextFieldDelegate? { |
|
didSet { |
|
dropDownDelegate = delegate as? IQDropDownTextFieldDelegate |
|
} |
|
} |
|
|
|
open var dataSource: IQDropDownTextFieldDataSource? |
|
|
|
open var dropDownMode: IQDropDownMode = .list { |
|
didSet { |
|
switch dropDownMode { |
|
case .list, .multiList: |
|
inputView = pickerView |
|
setSelectedRows(rows: selectedRows, animated: true) |
|
case .date: |
|
|
|
inputView = datePicker |
|
|
|
if !isOptionalDropDown { |
|
date = datePicker.date |
|
} |
|
case .time: |
|
|
|
inputView = timePicker |
|
|
|
if !isOptionalDropDown { |
|
date = timePicker.date |
|
} |
|
case .dateTime: |
|
|
|
inputView = dateTimePicker |
|
|
|
if !isOptionalDropDown { |
|
date = dateTimePicker.date |
|
} |
|
case .textField: |
|
inputView = nil |
|
} |
|
if #available(iOS 15.0, *) { |
|
reconfigureMenu() |
|
} |
|
} |
|
} |
|
|
|
private var privateOptionalItemText: String? |
|
@IBInspectable open var optionalItemText: String? { |
|
get { |
|
if let privateOptionalItemText = privateOptionalItemText, !privateOptionalItemText.isEmpty { |
|
return privateOptionalItemText |
|
} else { |
|
return NSLocalizedString("Select", comment: "") |
|
} |
|
} |
|
set { |
|
privateOptionalItemText = newValue |
|
privateUpdateOptionsList() |
|
} |
|
} |
|
|
|
private var privateOptionalItemTexts: [String?] = [] |
|
open var optionalItemTexts: [String?] { |
|
get { |
|
return privateOptionalItemTexts |
|
} |
|
set { |
|
privateOptionalItemTexts = newValue |
|
privateUpdateOptionsList() |
|
} |
|
} |
|
|
|
@IBInspectable open var isOptionalDropDown: Bool { |
|
get { return privateIsOptionalDropDowns.first ?? true } |
|
set { |
|
isOptionalDropDowns = [newValue] |
|
} |
|
} |
|
|
|
private var privateIsOptionalDropDowns: [Bool] = [] |
|
open var isOptionalDropDowns: [Bool] { |
|
get { return privateIsOptionalDropDowns } |
|
set { |
|
if !hasSetInitialIsOptional || privateIsOptionalDropDowns != newValue { |
|
|
|
let previousSelectedRows: [Int] = selectedRows |
|
|
|
privateIsOptionalDropDowns = newValue |
|
hasSetInitialIsOptional = true |
|
|
|
if dropDownMode == .list || dropDownMode == .multiList { |
|
pickerView.reloadAllComponents() |
|
selectedRows = previousSelectedRows |
|
} |
|
} |
|
} |
|
} |
|
|
|
open var multilistSelectionFormatHandler: ((_ selectedItems: [String?], _ selectedIndexes: [Int]) -> String)? { |
|
didSet { |
|
if let handler = multilistSelectionFormatHandler { |
|
super.text = handler(selectedItems, selectedRows) |
|
} else { |
|
super.text = selectedItems.compactMap({ $0 }).joined(separator: ", ") |
|
} |
|
} |
|
} |
|
|
|
open var selectionFormatHandler: ((_ selectedItem: String?, _ selectedIndex: Int) -> String)? { |
|
didSet { |
|
if let handler = selectionFormatHandler { |
|
super.text = handler(selectedItem, selectedRow) |
|
} else { |
|
super.text = selectedItems.compactMap({ $0 }).joined(separator: ", ") |
|
} |
|
} |
|
} |
|
|
|
@available(*, deprecated, message: "use 'selectedItem' instead") |
|
open override var text: String? { |
|
didSet { |
|
} |
|
} |
|
|
|
@available(*, deprecated, message: "use 'selectedItem' instead") |
|
open override var attributedText: NSAttributedString? { |
|
didSet { |
|
} |
|
} |
|
|
|
open var itemList: [String] { |
|
get { |
|
multiItemList.first ?? [] |
|
} |
|
set { |
|
multiItemList = [newValue] |
|
} |
|
} |
|
|
|
open var itemListView: [UIView?] { |
|
get { |
|
multiItemListView.first ?? [] |
|
} |
|
set { |
|
multiItemListView = [newValue] |
|
} |
|
} |
|
|
|
open var multiItemList: [[String]] = [] { |
|
didSet { |
|
//Refreshing pickerView |
|
isOptionalDropDowns = privateIsOptionalDropDowns |
|
let selectedRows = selectedRows |
|
self.selectedRows = selectedRows |
|
} |
|
} |
|
|
|
open var multiItemListView: [[UIView?]] = [] { |
|
didSet { |
|
//Refreshing pickerView |
|
isOptionalDropDowns = privateIsOptionalDropDowns |
|
let selectedRows = selectedRows |
|
self.selectedRows = selectedRows |
|
} |
|
} |
|
|
|
open override var adjustsFontSizeToFitWidth: Bool { |
|
didSet { |
|
privateUpdateOptionsList() |
|
} |
|
} |
|
|
|
private var hasSetInitialIsOptional: Bool = false |
|
|
|
func dealloc() { |
|
pickerView.delegate = nil |
|
pickerView.dataSource = nil |
|
self.delegate = nil |
|
dataSource = nil |
|
privateOptionalItemText = nil |
|
} |
|
|
|
// MARK: - Initialization |
|
|
|
func initialize() { |
|
contentVerticalAlignment = .center |
|
contentHorizontalAlignment = .center |
|
|
|
// These will update the UI and other components, |
|
// all the validation added if awakeFromNib for textField is called after custom UIView awakeFromNib call |
|
do { |
|
let mode = dropDownMode |
|
dropDownMode = mode |
|
|
|
isOptionalDropDown = hasSetInitialIsOptional ? isOptionalDropDown : true |
|
} |
|
|
|
dateFormatter.dateStyle = .medium |
|
dateFormatter.timeStyle = .none |
|
|
|
timeFormatter.dateStyle = .none |
|
timeFormatter.timeStyle = .short |
|
|
|
dateTimeFormatter.dateStyle = .medium |
|
dateTimeFormatter.timeStyle = .short |
|
|
|
if #available(iOS 15.0, *) { |
|
initializeMenu() |
|
} |
|
} |
|
|
|
override init(frame: CGRect) { |
|
super.init(frame: frame) |
|
initialize() |
|
} |
|
|
|
required public init?(coder: NSCoder) { |
|
super.init(coder: coder) |
|
} |
|
|
|
open override func awakeFromNib() { |
|
super.awakeFromNib() |
|
initialize() |
|
} |
|
|
|
// MARK: - UIView overrides |
|
@discardableResult |
|
open override func becomeFirstResponder() -> Bool { |
|
let result = super.becomeFirstResponder() |
|
|
|
for (index, selectdRow) in privatePickerSelectedRows where 0 <= selectdRow { |
|
pickerView.selectRow(selectdRow, inComponent: index, animated: false) |
|
} |
|
return result |
|
} |
|
|
|
// MARK: - UITextField overrides |
|
open override func caretRect(for position: UITextPosition) -> CGRect { |
|
if dropDownMode == .textField { |
|
return super.caretRect(for: position) |
|
} else { |
|
return .zero |
|
} |
|
} |
|
|
|
// MARK: - Selected Row |
|
|
|
open var selectedRow: Int { |
|
get { |
|
var pickerViewSelectedRow: Int = selectedRows.first /*It may return -1*/ ?? 0 |
|
pickerViewSelectedRow = max(pickerViewSelectedRow, 0) |
|
return pickerViewSelectedRow - (isOptionalDropDown ? 1 : 0) |
|
} |
|
set { |
|
selectedRows = [newValue] |
|
} |
|
} |
|
|
|
// Key represents section index and value represents selection |
|
internal var privatePickerSelectedRows: [Int: Int] = [:] |
|
|
|
open var selectedRows: [Int] { |
|
get { |
|
var selection: [Int] = [] |
|
for index in multiItemList.indices { |
|
|
|
let isOptionalDropDown: Bool |
|
if index < isOptionalDropDowns.count { |
|
isOptionalDropDown = isOptionalDropDowns[index] |
|
} else if let last = isOptionalDropDowns.last { |
|
isOptionalDropDown = last |
|
} else { |
|
isOptionalDropDown = true |
|
} |
|
|
|
var pickerViewSelectedRow: Int = privatePickerSelectedRows[index] ?? -1 /*It may return -1*/ |
|
pickerViewSelectedRow = max(pickerViewSelectedRow, 0) |
|
|
|
let finalSelection = pickerViewSelectedRow - (isOptionalDropDown ? 1 : 0) |
|
selection.append(finalSelection) |
|
} |
|
return selection |
|
} |
|
set { |
|
setSelectedRows(rows: newValue, animated: false) |
|
} |
|
} |
|
|
|
open func selectedRow(inSection section: Int) -> Int { |
|
privatePickerSelectedRows[section] ?? Self.optionalItemIndex |
|
} |
|
// open func rowSize(forComponent component: Int) -> CGSize |
|
|
|
open func setSelectedRow(row: Int, animated: Bool) { |
|
setSelectedRows(rows: [row], animated: animated) |
|
} |
|
|
|
open func setSelectedRow(row: Int, inSection section: Int, animated: Bool) { |
|
var selectedRows = selectedRows |
|
selectedRows[section] = row |
|
setSelectedRows(rows: selectedRows, animated: animated) |
|
} |
|
|
|
open func setSelectedRows(rows: [Int], animated: Bool) { |
|
|
|
var finalResults: [String?] = [] |
|
for (index, row) in rows.enumerated() { |
|
|
|
let itemList: [String] |
|
|
|
if index < multiItemList.count { |
|
itemList = multiItemList[index] |
|
} else { |
|
itemList = [] |
|
} |
|
|
|
let isOptionalDropDown: Bool |
|
if index < isOptionalDropDowns.count { |
|
isOptionalDropDown = isOptionalDropDowns[index] |
|
} else if let last = isOptionalDropDowns.last { |
|
isOptionalDropDown = last |
|
} else { |
|
isOptionalDropDown = true |
|
} |
|
|
|
if row == Self.optionalItemIndex { |
|
|
|
if !isOptionalDropDown, !itemList.isEmpty { |
|
finalResults.append(itemList[0]) |
|
} else { |
|
finalResults.append(nil) |
|
} |
|
} else { |
|
if row < itemList.count { |
|
finalResults.append(itemList[row]) |
|
} else { |
|
finalResults.append(nil) |
|
} |
|
} |
|
|
|
let pickerViewRow: Int = row + (isOptionalDropDown ? 1 : 0) |
|
privatePickerSelectedRows[index] = pickerViewRow |
|
if index < pickerView.numberOfComponents { |
|
pickerView.selectRow(pickerViewRow, inComponent: index, animated: animated) |
|
} |
|
} |
|
|
|
if let multilistSelectionFormatHandler = multilistSelectionFormatHandler { |
|
super.text = multilistSelectionFormatHandler(finalResults, rows) |
|
} else if let selectionFormatHandler = selectionFormatHandler, |
|
let selectedItem = finalResults.first, |
|
let selectedRow = rows.first { |
|
super.text = selectionFormatHandler(selectedItem, selectedRow) |
|
} else { |
|
super.text = finalResults.compactMap({ $0 }).joined(separator: ", ") |
|
} |
|
} |
|
|
|
// MARK: - Setters |
|
// `setDropDownMode:` has moved as a setter. |
|
|
|
// `setItemList:` has moved as a setter. |
|
|
|
open var selectedItem: String? { |
|
get { |
|
return selectedItems.first ?? nil |
|
} |
|
set { |
|
switch dropDownMode { |
|
case .multiList: |
|
if let newValue = newValue { |
|
selectedItems = [newValue] |
|
} else { |
|
selectedItems = multiItemList.map({ _ in nil }) // Resetting every section |
|
} |
|
case .list, .date, .time, .dateTime, .textField: |
|
selectedItems = [newValue] |
|
} |
|
} |
|
} |
|
|
|
open var selectedItems: [String?] { |
|
get { |
|
switch dropDownMode { |
|
case .list, .multiList: |
|
var finalSelection: [String?] = [] |
|
for (index, selectedRow) in selectedRows.enumerated() { |
|
if 0 <= selectedRow, index < multiItemList.count { |
|
finalSelection.append(multiItemList[index][selectedRow]) |
|
} else { |
|
finalSelection.append(nil) |
|
} |
|
} |
|
return finalSelection |
|
case .date: |
|
return (super.text?.isEmpty ?? true) ? [nil] : [dateFormatter.string(from: datePicker.date)] |
|
case .time: |
|
return (super.text?.isEmpty ?? true) ? [nil] : [timeFormatter.string(from: timePicker.date)] |
|
case .dateTime: |
|
return (super.text?.isEmpty ?? true) ? [nil] : [dateTimeFormatter.string(from: dateTimePicker.date)] |
|
case .textField: |
|
return [super.text] |
|
} |
|
} |
|
|
|
set { |
|
privateSetSelectedItems(selectedItems: newValue, animated: false, shouldNotifyDelegate: false) |
|
} |
|
} |
|
|
|
open func setSelectedItem(selectedItem: String?, animated: Bool) { |
|
privateSetSelectedItems(selectedItems: [selectedItem], animated: animated, shouldNotifyDelegate: false) |
|
} |
|
|
|
open func setSelectedItems(selectedItems: [String?], animated: Bool) { |
|
privateSetSelectedItems(selectedItems: selectedItems, animated: animated, shouldNotifyDelegate: false) |
|
} |
|
|
|
open func privateUpdateOptionsList() { |
|
|
|
switch dropDownMode { |
|
case .date: |
|
if !isOptionalDropDown { |
|
date = datePicker.date |
|
} |
|
case .time: |
|
if !isOptionalDropDown { |
|
date = timePicker.date |
|
} |
|
case .dateTime: |
|
|
|
if !isOptionalDropDown { |
|
date = dateTimePicker.date |
|
} |
|
case .list, .multiList: |
|
pickerView.reloadAllComponents() |
|
case .textField: |
|
break |
|
} |
|
} |
|
|
|
open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { |
|
if action == #selector(cut(_:)) || action == #selector(paste(_:)) { |
|
return false |
|
} else { |
|
return super.canPerformAction(action, withSender: sender) |
|
} |
|
} |
|
} |
|
|
|
internal extension IQDropDownTextField { |
|
|
|
// swiftlint:disable cyclomatic_complexity |
|
// swiftlint:disable function_body_length |
|
func privateSetSelectedItems(selectedItems: [String?], |
|
animated: Bool, shouldNotifyDelegate: Bool) { |
|
switch dropDownMode { |
|
case .list, .multiList: |
|
|
|
var finalIndexes: [Int] = [] |
|
var finalSelection: [String?] = [] |
|
|
|
for (index, selectedItem) in selectedItems.enumerated() { |
|
|
|
if let selectedItem = selectedItem, |
|
index < multiItemList.count, |
|
let index = multiItemList[index].firstIndex(of: selectedItem) { |
|
finalIndexes.append(index) |
|
finalSelection.append(selectedItem) |
|
|
|
} else { |
|
|
|
let isOptionalDropDown: Bool |
|
if index < isOptionalDropDowns.count { |
|
isOptionalDropDown = isOptionalDropDowns[index] |
|
} else if let last = isOptionalDropDowns.last { |
|
isOptionalDropDown = last |
|
} else { |
|
isOptionalDropDown = true |
|
} |
|
|
|
let selectedIndex = isOptionalDropDown ? Self.optionalItemIndex : 0 |
|
finalIndexes.append(selectedIndex) |
|
finalSelection.append(nil) |
|
} |
|
} |
|
|
|
setSelectedRows(rows: finalIndexes, animated: animated) |
|
|
|
if shouldNotifyDelegate { |
|
if dropDownMode == .multiList { |
|
dropDownDelegate?.textField(textField: self, didSelectItems: finalSelection) |
|
} else if let selectedItem = finalSelection.first { |
|
dropDownDelegate?.textField(textField: self, didSelectItem: selectedItem) |
|
} |
|
} |
|
|
|
case .date: |
|
|
|
if let selectedItem = selectedItems.first, |
|
let selectedItem = selectedItem, |
|
let date = dateFormatter.date(from: selectedItem) { |
|
super.text = selectedItem |
|
datePicker.setDate(date, animated: animated) |
|
|
|
if shouldNotifyDelegate { |
|
dropDownDelegate?.textField(textField: self, didSelectDate: date) |
|
} |
|
} else if isOptionalDropDown, |
|
let selectedItem = selectedItems.first, |
|
(selectedItem?.isEmpty ?? true) { |
|
super.text = "" |
|
|
|
datePicker.setDate(Date(), animated: animated) |
|
|
|
if shouldNotifyDelegate { |
|
dropDownDelegate?.textField(textField: self, didSelectDate: nil) |
|
} |
|
} |
|
case .time: |
|
|
|
if let selectedItem = selectedItems.first, |
|
let selectedItem = selectedItem, |
|
let time = timeFormatter.date(from: selectedItem) { |
|
let day: Date = Date(timeIntervalSinceReferenceDate: 0) |
|
let componentsForDay: Set<Calendar.Component> = [.era, .year, .month, .day] |
|
let componentsForTime: Set<Calendar.Component> = [.hour, .minute, .second] |
|
var componentsDay: DateComponents = Calendar.current.dateComponents(componentsForDay, from: day) |
|
let componentsTime: DateComponents = Calendar.current.dateComponents(componentsForTime, from: time) |
|
componentsDay.hour = componentsTime.hour |
|
componentsDay.minute = componentsTime.minute |
|
componentsDay.second = componentsTime.second |
|
|
|
if let date = Calendar.current.date(from: componentsDay) { |
|
super.text = selectedItem |
|
timePicker.setDate(date, animated: animated) |
|
|
|
if shouldNotifyDelegate { |
|
dropDownDelegate?.textField(textField: self, didSelectDate: date) |
|
} |
|
} |
|
} else if isOptionalDropDown, |
|
let selectedItem = selectedItems.first, |
|
(selectedItem?.isEmpty ?? true) { |
|
super.text = "" |
|
timePicker.setDate(Date(), animated: animated) |
|
|
|
if shouldNotifyDelegate { |
|
dropDownDelegate?.textField(textField: self, didSelectDate: nil) |
|
} |
|
} |
|
|
|
case .dateTime: |
|
|
|
if let selectedItem = selectedItems.first, |
|
let selectedItem = selectedItem, |
|
let date: Date = dateTimeFormatter.date(from: selectedItem) { |
|
super.text = selectedItem |
|
dateTimePicker.setDate(date, animated: animated) |
|
|
|
if shouldNotifyDelegate { |
|
dropDownDelegate?.textField(textField: self, didSelectDate: date) |
|
} |
|
} else if isOptionalDropDown, |
|
let selectedItem = selectedItems.first, |
|
(selectedItem?.isEmpty ?? true) { |
|
|
|
super.text = "" |
|
dateTimePicker.setDate(Date(), animated: animated) |
|
|
|
if shouldNotifyDelegate { |
|
dropDownDelegate?.textField(textField: self, didSelectDate: nil) |
|
} |
|
} |
|
case .textField: |
|
super.text = selectedItems.compactMap({ $0 }).joined(separator: ", ") |
|
} |
|
} |
|
// swiftlint:enable cyclomatic_complexity |
|
// swiftlint:enable function_body_length |
|
}
|
|
|