model throw, view adapt
This commit is contained in:
parent
bd4cadce3f
commit
3765c771ec
@ -326,7 +326,9 @@ public typealias ActionBlock = () -> ()
|
|||||||
let attributedString = NSMutableAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font.updateSize(standardFontSize), NSAttributedString.Key.foregroundColor: textColor as UIColor])
|
let attributedString = NSMutableAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font.updateSize(standardFontSize), NSAttributedString.Key.foregroundColor: textColor as UIColor])
|
||||||
|
|
||||||
for attribute in attributes {
|
for attribute in attributes {
|
||||||
let range = NSRange(location: attribute.location, length: attribute.length)
|
guard let range = validateAttribute(range: NSRange(location: attribute.location, length: attribute.length) , in: attributedString)
|
||||||
|
else { continue }
|
||||||
|
|
||||||
switch attribute {
|
switch attribute {
|
||||||
case let underlineAtt as LabelAttributeUnderlineModel:
|
case let underlineAtt as LabelAttributeUnderlineModel:
|
||||||
attributedString.addAttribute(.underlineStyle, value: underlineAtt.underlineValue.rawValue, range: range)
|
attributedString.addAttribute(.underlineStyle, value: underlineAtt.underlineValue.rawValue, range: range)
|
||||||
@ -458,10 +460,9 @@ public typealias ActionBlock = () -> ()
|
|||||||
for case let attribute as [String: Any] in attributes {
|
for case let attribute as [String: Any] in attributes {
|
||||||
guard let attributeType = attribute.optionalStringForKey(KeyType),
|
guard let attributeType = attribute.optionalStringForKey(KeyType),
|
||||||
let location = attribute["location"] as? Int,
|
let location = attribute["location"] as? Int,
|
||||||
let length = attribute["length"] as? Int
|
let length = attribute["length"] as? Int,
|
||||||
else { continue }
|
let range = validateAttribute(range: NSRange(location: location, length: length), in: attributedString)
|
||||||
|
else { continue }
|
||||||
let range = NSRange(location: location, length: length)
|
|
||||||
|
|
||||||
switch attributeType {
|
switch attributeType {
|
||||||
case "underline":
|
case "underline":
|
||||||
@ -834,18 +835,8 @@ extension Label {
|
|||||||
private func addActionAttributes(range: NSRange, string: NSMutableAttributedString?) {
|
private func addActionAttributes(range: NSRange, string: NSMutableAttributedString?) {
|
||||||
|
|
||||||
guard let string = string,
|
guard let string = string,
|
||||||
range.location > 0 && range.location < string.length
|
let range = validateAttribute(range: range, in: string)
|
||||||
else {
|
else { return }
|
||||||
MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute starting location \(range.lowerBound) is out of bounds for '\(string?.string ?? "")'. Attribute is discarded.", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var range = range
|
|
||||||
if range.upperBound > string.length {
|
|
||||||
let newRange = NSRange(location: range.location, length: string.length - range.location)
|
|
||||||
MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute ending location \(range.upperBound) is out of bounds for '\(string)'. Adjusting to \(newRange.upperBound).", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!)
|
|
||||||
range = newRange
|
|
||||||
}
|
|
||||||
|
|
||||||
string.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue], range: range)
|
string.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue], range: range)
|
||||||
}
|
}
|
||||||
@ -1005,3 +996,26 @@ extension Label {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
// MARK: - Validations
|
||||||
|
//------------------------------------------------------
|
||||||
|
|
||||||
|
func validateAttribute(range: NSRange, in string: NSAttributedString) -> NSRange? {
|
||||||
|
guard range.location >= 0 && range.location < string.length else {
|
||||||
|
if let loggingHandler = MVMCoreLoggingHandler.shared(), loggingHandler.responds(to: #selector(MVMCoreLoggingHandler.addError(toLog:))) {
|
||||||
|
loggingHandler.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute starting location \(range.lowerBound) is out of bounds for '\(string.string)'. Attribute is discarded.", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if range.upperBound > string.length {
|
||||||
|
let newRange = NSRange(location: range.location, length: string.length - range.location)
|
||||||
|
if let loggingHandler = MVMCoreLoggingHandler.shared(), loggingHandler.responds(to: #selector(MVMCoreLoggingHandler.addError(toLog:))) {
|
||||||
|
loggingHandler.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute ending location \(range.upperBound) is out of bounds for '\(string)'. Adjusting to \(newRange.upperBound).", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!)
|
||||||
|
}
|
||||||
|
return newRange
|
||||||
|
}
|
||||||
|
|
||||||
|
return range
|
||||||
|
}
|
||||||
|
|||||||
@ -36,12 +36,15 @@ class LabelAttributeImageModel: LabelAttributeModel {
|
|||||||
case URL
|
case URL
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func validateInRange(of text: String) -> Bool {
|
//--------------------------------------------------
|
||||||
guard location > 0 && location <= text.count else {
|
// MARK: - Validations
|
||||||
MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute starting location \(location) is out of bounds for '\(text)'. Attribute is discarded.", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!)
|
//--------------------------------------------------
|
||||||
return false
|
|
||||||
|
public override func validateInRange(of text: String) -> MolecularError? {
|
||||||
|
guard location >= 0 && location <= text.count else {
|
||||||
|
return MolecularError.validationError("Attribute starting location \(location) is out of bounds for '\(text)'.")
|
||||||
}
|
}
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -44,21 +44,20 @@
|
|||||||
case length
|
case length
|
||||||
}
|
}
|
||||||
|
|
||||||
public func validateInRange(of text: String) -> Bool {
|
//--------------------------------------------------
|
||||||
|
// MARK: - Validations
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public func validateInRange(of text: String) -> MolecularError? {
|
||||||
// Prevent invalid starting locations.
|
// Prevent invalid starting locations.
|
||||||
guard location > 0 && location <= text.count else {
|
guard location >= 0 && location <= text.count else {
|
||||||
MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute starting location \(location) is out of bounds for '\(text)'. Attribute is discarded.", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!)
|
return MolecularError.validationError("Attribute starting location \(location) is out of bounds for '\(text)'.")
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
// Prevent lengths extending beyond the bounds of the string.
|
||||||
// Truncate long lengths
|
|
||||||
guard length + location <= text.count else {
|
guard length + location <= text.count else {
|
||||||
MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute length \(length) is out of bounds for '\(text)'. Adjusting to \(text.count - location).", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!)
|
return MolecularError.validationError("Attribute length \(length) starting at \(location) is out of bounds for '\(text)'.")
|
||||||
length = text.count - location
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -21,17 +21,7 @@
|
|||||||
public var fontName: String?
|
public var fontName: String?
|
||||||
public var fontSize: CGFloat?
|
public var fontSize: CGFloat?
|
||||||
public var textAlignment: NSTextAlignment?
|
public var textAlignment: NSTextAlignment?
|
||||||
private var _attributes: [LabelAttributeModel]?
|
public var attributes: [LabelAttributeModel]?
|
||||||
public var attributes: [LabelAttributeModel]? {
|
|
||||||
get { _attributes }
|
|
||||||
set {
|
|
||||||
if let attributes = newValue {
|
|
||||||
_attributes = validate(attributes)
|
|
||||||
} else {
|
|
||||||
_attributes = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public var html: String?
|
public var html: String?
|
||||||
public var hero: Int?
|
public var hero: Int?
|
||||||
public var makeWholeViewClickable: Bool?
|
public var makeWholeViewClickable: Bool?
|
||||||
@ -75,8 +65,14 @@
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Validations
|
// MARK: - Validations
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
public func validate(_ attributes: [LabelAttributeModel]) -> [LabelAttributeModel] {
|
|
||||||
return attributes.filter { $0.validateInRange(of: text) }
|
public func validate(_ attributes: [LabelAttributeModel]) -> MolecularError? {
|
||||||
|
for attribute in attributes {
|
||||||
|
if let molecularError = attribute.validateInRange(of: text) {
|
||||||
|
return molecularError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -99,6 +95,11 @@
|
|||||||
makeWholeViewClickable = try typeContainer.decodeIfPresent(Bool.self, forKey: .makeWholeViewClickable)
|
makeWholeViewClickable = try typeContainer.decodeIfPresent(Bool.self, forKey: .makeWholeViewClickable)
|
||||||
numberOfLines = try typeContainer.decodeIfPresent(Int.self, forKey: .numberOfLines)
|
numberOfLines = try typeContainer.decodeIfPresent(Int.self, forKey: .numberOfLines)
|
||||||
shouldMaskRecordedView = try typeContainer.decodeIfPresent(Bool.self, forKey: .shouldMaskRecordedView) ?? false
|
shouldMaskRecordedView = try typeContainer.decodeIfPresent(Bool.self, forKey: .shouldMaskRecordedView) ?? false
|
||||||
|
|
||||||
|
// Later make protocol based validate outside of decoding?
|
||||||
|
if let attributes = attributes, let error = validate(attributes) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open func encode(to encoder: Encoder) throws {
|
open func encode(to encoder: Encoder) throws {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
public enum MolecularError: Swift.Error {
|
public enum MolecularError: Swift.Error {
|
||||||
case error(String)
|
case error(String)
|
||||||
|
case validationError(String)
|
||||||
case countImbalance(String)
|
case countImbalance(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user