getting ready to try another refactor.
This commit is contained in:
parent
5c1d7b4a38
commit
6e8a8a78cc
@ -43,6 +43,7 @@
|
||||
0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; };
|
||||
0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; };
|
||||
0A6BF4722360C56C0028F841 /* DropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6BF4712360C56C0028F841 /* DropdownEntryField.swift */; };
|
||||
0A74EB4B236C72C400941B4B /* BoundaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A74EB4A236C72C400941B4B /* BoundaryView.swift */; };
|
||||
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; };
|
||||
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; };
|
||||
9455B19C234F8A0400A574DB /* MVMAnimationFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */; };
|
||||
@ -231,6 +232,7 @@
|
||||
0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = "<group>"; };
|
||||
0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = "<group>"; };
|
||||
0A6BF4712360C56C0028F841 /* DropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownEntryField.swift; sourceTree = "<group>"; };
|
||||
0A74EB4A236C72C400941B4B /* BoundaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoundaryView.swift; sourceTree = "<group>"; };
|
||||
0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = "<group>"; };
|
||||
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
|
||||
0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxWithLabelView.swift; sourceTree = "<group>"; };
|
||||
@ -437,6 +439,14 @@
|
||||
path = FormUIHelpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0A74EB49236C728C00941B4B /* ViewContainer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0A74EB4A236C72C400941B4B /* BoundaryView.swift */,
|
||||
);
|
||||
path = ViewContainer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D224798823142BF2003FCCF9 /* SwitchMolecules */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -641,6 +651,7 @@
|
||||
D29DF11921E68467003B2FB9 /* Containers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0A74EB49236C728C00941B4B /* ViewContainer */,
|
||||
D29DF2B721E7BE79003B2FB9 /* TabBarController */,
|
||||
D29DF2B621E7BE66003B2FB9 /* SplitViewController */,
|
||||
D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */,
|
||||
@ -1071,7 +1082,6 @@
|
||||
01004F3022721C3800991ECC /* RadioButton.swift in Sources */,
|
||||
D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */,
|
||||
D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */,
|
||||
D29DF25321E6A177003B2FB9 /* MFDigitTextField.m in Sources */,
|
||||
D2B18B7F2360913400A9AEDC /* Control.swift in Sources */,
|
||||
D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */,
|
||||
DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */,
|
||||
@ -1092,8 +1102,6 @@
|
||||
D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */,
|
||||
D2755D7B23689C7500485468 /* TableViewCell.swift in Sources */,
|
||||
0A21DB85235E06EF00C160A2 /* MFTextField.m in Sources */,
|
||||
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */,
|
||||
D29DF25421E6A177003B2FB9 /* MFMdnTextField.m in Sources */,
|
||||
D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */,
|
||||
D2A514672213885800345BFB /* StandardHeaderView.swift in Sources */,
|
||||
DBEFFA04225A829700230692 /* Label.swift in Sources */,
|
||||
@ -1123,6 +1131,7 @@
|
||||
D29DF2BF21E7BEA4003B2FB9 /* MVMCoreUITabBarPageControlViewController.m in Sources */,
|
||||
D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */,
|
||||
D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */,
|
||||
0A74EB4B236C72C400941B4B /* BoundaryView.swift in Sources */,
|
||||
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
|
||||
01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */,
|
||||
D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */,
|
||||
|
||||
@ -13,20 +13,29 @@ import UIKit
|
||||
}
|
||||
|
||||
@objcMembers open class DigitBox: UITextField, MVMCoreViewProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
private weak var bottomBar: SeparatorView?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
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
|
||||
}()
|
||||
|
||||
weak var textBoxDelegate: DigitBoxDelegate?
|
||||
|
||||
private var previousSize: CGFloat = 0.0
|
||||
|
||||
/// Determines if a border should be drawn.
|
||||
private var hideBorder = false
|
||||
private var showError = false
|
||||
|
||||
private var borderStrokeColor: UIColor = .mfSilver()
|
||||
private var borderPath: UIBezierPath = UIBezierPath()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
@ -65,20 +74,50 @@ import UIKit
|
||||
textAlignment = .center
|
||||
keyboardType = .numberPad
|
||||
layer.borderWidth = 1
|
||||
hideError()
|
||||
showError(false)
|
||||
|
||||
widthConstraint = widthAnchor.constraint(equalToConstant: 40)
|
||||
widthConstraint = widthAnchor.constraint(equalToConstant: 39)
|
||||
widthConstraint?.isActive = true
|
||||
|
||||
heightConstraint = heightAnchor.constraint(equalToConstant: 60)
|
||||
heightConstraint = heightAnchor.constraint(equalToConstant: 44)
|
||||
heightConstraint?.isActive = true
|
||||
|
||||
bottomBar = SeparatorView.separatorAdd(to: self, position: SeparatorPositionBot)
|
||||
bottomBar?.setAsMedium()
|
||||
layer.addSublayer(bottomBar)
|
||||
|
||||
updateView(MVMCoreUISplitViewController.getDetailViewWidth())
|
||||
}
|
||||
|
||||
open override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
borderPath.removeAllPoints()
|
||||
|
||||
if !hideBorder {
|
||||
// Brings the other half of the line inside the view to prevent cropping.
|
||||
let origin = frame.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()
|
||||
}
|
||||
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
open override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
let barHeight: CGFloat = showError ? 4 : 1
|
||||
bottomBar.frame = CGRect(x: 0, y: bounds.height - barHeight, width: bounds.width, height: barHeight)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
@ -122,16 +161,15 @@ import UIKit
|
||||
}
|
||||
}
|
||||
|
||||
func setAsError() {
|
||||
func showError(_ show: Bool) {
|
||||
|
||||
layer.borderColor = UIColor.mfPumpkin().cgColor
|
||||
bottomBar?.backgroundColor = UIColor.mfPumpkin()
|
||||
bottomBar?.height?.constant = 4
|
||||
}
|
||||
|
||||
func hideError() {
|
||||
showError = show
|
||||
borderStrokeColor = show ? .mfPumpkin() : .mfSilver()
|
||||
bottomBar.backgroundColor = show ? UIColor.mfPumpkin().cgColor : UIColor.black.cgColor
|
||||
let barHeight: CGFloat = show ? 4 : 1
|
||||
bottomBar.frame = CGRect(x: 0, y: bounds.height - barHeight, width: bounds.width, height: barHeight)
|
||||
|
||||
layer.borderColor = UIColor.mfSilver().cgColor
|
||||
bottomBar?.setAsMedium()
|
||||
setNeedsDisplay()
|
||||
layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ import UIKit
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
private weak var digitFieldsView: UIView?
|
||||
public private(set) var digitFieldsView: UIView?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
@ -132,7 +132,7 @@ import UIKit
|
||||
guard let self = self else { return }
|
||||
|
||||
for field in self.digitFields ?? [] {
|
||||
field.hideError()
|
||||
field.showError(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -179,6 +179,16 @@ import UIKit
|
||||
fatalError("DigitEntryField xib has not been implemented")
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Setup
|
||||
//--------------------------------------------------
|
||||
|
||||
open func setup() {
|
||||
|
||||
titleLabel.styleB2(true)
|
||||
alignCenterHorizontal()
|
||||
}
|
||||
|
||||
open override func setupFieldContainerContent(_ container: UIView) {
|
||||
|
||||
setupTextFieldsView(forSize: CGFloat(numberOfDigits))
|
||||
@ -188,13 +198,6 @@ import UIKit
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
open func setup() {
|
||||
|
||||
titleLabel.styleB2(true)
|
||||
title = ""
|
||||
alignCenterHorizontal()
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
|
||||
@ -203,6 +206,7 @@ import UIKit
|
||||
|
||||
self.titleLabel.updateView(size)
|
||||
|
||||
|
||||
if let digitFields = self.digitFields, !digitFields.isEmpty {
|
||||
|
||||
// Remove all current UI.
|
||||
|
||||
@ -31,8 +31,6 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
|
||||
public weak var datePicker: UIDatePicker?
|
||||
public var pickerView: UIPickerView?
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
@ -72,7 +70,7 @@ import UIKit
|
||||
|
||||
setupView()
|
||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: bothDelegates)
|
||||
setBothTextDelegates(bothDelegates)
|
||||
setBothTextDelegates(to: bothDelegates)
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
|
||||
@ -55,7 +55,7 @@ import UIKit
|
||||
return layer
|
||||
}()
|
||||
|
||||
var delegateObject: MVMCoreUIDelegateObject?
|
||||
weak var delegateObject: MVMCoreUIDelegateObject?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
|
||||
@ -20,6 +20,8 @@ import MVMCore
|
||||
public var isNationalMdn = true
|
||||
public var shouldValidateMDN = false
|
||||
|
||||
// public var pickerView: UIPickerView?
|
||||
|
||||
public var mdn: String? {
|
||||
get { return MVMCoreUIUtility.removeMdnFormat(text) }
|
||||
set { text = MVMCoreUIUtility.formatMdn(newValue) }
|
||||
@ -82,7 +84,7 @@ import MVMCore
|
||||
let isValid = hasValidMDN()
|
||||
|
||||
if isValid {
|
||||
clearError()
|
||||
clearErrorState()
|
||||
} else {
|
||||
errorMessage = errorMessage ?? MVMCoreUIUtility.hardcodedString(withKey: "textfield_phone_format_error_message")
|
||||
UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: textField)
|
||||
@ -94,7 +96,7 @@ import MVMCore
|
||||
return true
|
||||
}
|
||||
|
||||
func getContacts(_ sender: Any?) {
|
||||
@objc func getContacts(_ sender: Any?) {
|
||||
|
||||
let picker = CNContactPickerViewController()
|
||||
picker.delegate = self
|
||||
@ -125,7 +127,6 @@ import MVMCore
|
||||
}
|
||||
|
||||
text = unformattedMDN
|
||||
|
||||
textFieldShouldReturn(textField)
|
||||
textFieldDidEndEditing(textField)
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// TextField.swift
|
||||
// TextEntryField.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 10/2/19.
|
||||
@ -24,7 +24,7 @@ import UIKit
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
private(set) var textField: UITextField = {
|
||||
public private(set) var textField: UITextField = {
|
||||
let textField = UITextField(frame: .zero)
|
||||
textField.translatesAutoresizingMaskIntoConstraints = false
|
||||
textField.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
@ -39,10 +39,9 @@ import UIKit
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public var enabledTextColor: UIColor?
|
||||
public var disabledTextColor: UIColor?
|
||||
public var textColor: (enabled: UIColor?, disabled: UIColor?)
|
||||
|
||||
public var observingForChanges = false
|
||||
public var observingForChange = false
|
||||
|
||||
public override var isEnabled: Bool {
|
||||
didSet {
|
||||
@ -50,7 +49,7 @@ import UIKit
|
||||
guard let self = self else { return }
|
||||
|
||||
self.textField.isEnabled = self.isEnabled
|
||||
self.textField.textColor = self.isEnabled ? self.enabledTextColor : self.disabledTextColor
|
||||
self.textField.textColor = self.isEnabled ? self.textColor.enabled : self.textColor.disabled
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -64,6 +63,13 @@ import UIKit
|
||||
}
|
||||
}
|
||||
|
||||
public var placeholder: String? {
|
||||
get { return textField.placeholder }
|
||||
set {
|
||||
textField.placeholder = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public var validationBlock: ((_ value: String?) -> Bool)? {
|
||||
didSet {
|
||||
valueChanged()
|
||||
@ -83,13 +89,13 @@ import UIKit
|
||||
/// The delegate and block for validation. Validates if the text that the user has entered is valid or not. Checked after each change if there is a delegate.
|
||||
public weak var mfTextFieldDelegate: TextFieldDelegate? {
|
||||
didSet {
|
||||
if mfTextFieldDelegate != nil && !observingForChanges {
|
||||
observingForChanges = true
|
||||
if mfTextFieldDelegate != nil && !observingForChange {
|
||||
observingForChange = true
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextField.textDidChangeNotification, object: textField)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(endInputing), name: UITextField.textDidEndEditingNotification, object: textField)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(startEditing), name: UITextField.textDidBeginEditingNotification, object: textField)
|
||||
} else if mfTextFieldDelegate == nil && observingForChanges {
|
||||
observingForChanges = false
|
||||
} else if mfTextFieldDelegate == nil && observingForChange {
|
||||
observingForChange = false
|
||||
NotificationCenter.default.removeObserver(self, name: UITextField.textDidChangeNotification, object: textField)
|
||||
NotificationCenter.default.removeObserver(self, name: UITextField.textDidEndEditingNotification, object: textField)
|
||||
NotificationCenter.default.removeObserver(self, name: UITextField.textDidBeginEditingNotification, object: textField)
|
||||
@ -115,7 +121,6 @@ import UIKit
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
// setupView()
|
||||
}
|
||||
|
||||
public convenience init() {
|
||||
@ -125,9 +130,7 @@ import UIKit
|
||||
/// - parameter bothDelegates: Sets both MF/UI Text Field Delegates.
|
||||
public init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) {
|
||||
super.init(frame: .zero)
|
||||
|
||||
// setupView()
|
||||
setBothTextDelegates(bothDelegates)
|
||||
setBothTextDelegates(to: bothDelegates)
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
@ -142,7 +145,6 @@ import UIKit
|
||||
open override func setupFieldContainerContent(_ container: UIView) {
|
||||
|
||||
MFStyler.styleTextField(textField)
|
||||
|
||||
container.addSubview(textField)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
@ -159,25 +161,24 @@ import UIKit
|
||||
super.updateView(size)
|
||||
|
||||
MFStyler.styleTextField(textField)
|
||||
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
deinit {
|
||||
setBothTextDelegates(nil)
|
||||
setBothTextDelegates(to: nil)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
open func clearError() {
|
||||
open func clearErrorState() {
|
||||
|
||||
feedback = nil
|
||||
textField.accessibilityValue = nil
|
||||
updateUI(appearance: .original)
|
||||
}
|
||||
|
||||
public func setBothTextDelegates(_ delegate: (UITextFieldDelegate & TextFieldDelegate)?) {
|
||||
public func setBothTextDelegates(to delegate: (UITextFieldDelegate & TextFieldDelegate)?) {
|
||||
|
||||
mfTextFieldDelegate = delegate
|
||||
uiTextFieldDelegate = delegate
|
||||
@ -215,7 +216,7 @@ import UIKit
|
||||
mfTextFieldDelegate?.isInvalid?(textfield: self)
|
||||
|
||||
} else if !previousValidity && isValid {
|
||||
clearError()
|
||||
clearErrorState()
|
||||
|
||||
if let mfTextFieldDelegate = mfTextFieldDelegate {
|
||||
mfTextFieldDelegate.isValid?(textfield: self)
|
||||
@ -226,8 +227,7 @@ import UIKit
|
||||
@objc func endInputing() {
|
||||
|
||||
if isValid {
|
||||
clearError()
|
||||
bottomBar.backgroundColor = UIColor.black.cgColor
|
||||
clearErrorState()
|
||||
|
||||
} else if let errMessage = errorMessage {
|
||||
feedback = errMessage
|
||||
@ -254,11 +254,19 @@ extension TextEntryField {
|
||||
FormValidator.setupValidation(molecule: self, delegate: delegateObject.formValidationProtocol)
|
||||
|
||||
if let enabledTextColorHex = dictionary["enabledTextColor"] as? String {
|
||||
enabledTextColor = UIColor.mfGet(forHex: enabledTextColorHex)
|
||||
textColor.enabled = UIColor.mfGet(forHex: enabledTextColorHex)
|
||||
}
|
||||
|
||||
if let disabledTextColorHex = dictionary["disabledTextColor"] as? String {
|
||||
disabledTextColor = UIColor.mfGet(forHex: disabledTextColorHex)
|
||||
textColor.disabled = UIColor.mfGet(forHex: disabledTextColorHex)
|
||||
}
|
||||
|
||||
if let text = dictionary[KeyText] as? String {
|
||||
self.text = text
|
||||
}
|
||||
|
||||
if let placeholder = dictionary[placeholder] as? String {
|
||||
self.placeholder = placeholder
|
||||
}
|
||||
|
||||
switch dictionary.stringForkey(KeyType) {
|
||||
|
||||
13
MVMCoreUI/Containers/ViewContainer/BoundaryView.swift
Normal file
13
MVMCoreUI/Containers/ViewContainer/BoundaryView.swift
Normal file
@ -0,0 +1,13 @@
|
||||
//
|
||||
// BoundaryView.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 11/1/19.
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class BoundaryView: UIView {
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user