vds_ios/VDS/Components/Label/Attributes/LabelAttributeModel.swift

103 lines
3.3 KiB
Swift

//
// LabelAttributeModel.swift
// VDS
//
// Created by Matt Bruce on 8/3/22.
//
import Foundation
import UIKit
public protocol LabelAttributeModel: AnyEquatable, Withable, Equatable, Identifiable where ID == UUID {
/// Position of the starting point for this LabelAttribute.
var location: Int { get set }
/// Length from the location.
var length: Int { get set }
/// Applies the attribute to the attributedString that is given.
/// - Parameter attributedString: AttributedString that the attributed is applied.
func setAttribute(on attributedString: NSMutableAttributedString)
}
extension LabelAttributeModel {
/// Range for this AttributeModel
public var range: NSRange {
NSRange(location: location, length: length)
}
public static func == (lhs: any LabelAttributeModel, rhs: any LabelAttributeModel) -> Bool {
lhs.isEqual(rhs)
}
public func isValidRange(on attributedString: NSMutableAttributedString) -> Bool {
attributedString.isValid(range: range)
}
}
public extension String {
func isValid(range: NSRange) -> Bool {
range.location >= 0 && range.length > 0 && range.location + range.length <= count
}
func index(from: Int) -> Index {
return self.index(startIndex, offsetBy: from)
}
func substring(from: Int) -> String {
let fromIndex = index(from: from)
return String(self[fromIndex...])
}
func substring(to: Int) -> String {
let toIndex = index(from: to)
return String(self[..<toIndex])
}
func substring(with r: Range<Int>) -> String {
let startIndex = index(from: r.lowerBound)
let endIndex = index(from: r.upperBound)
return String(self[startIndex..<endIndex])
}
}
public extension NSAttributedString {
func isValid(range: NSRange) -> Bool {
range.location >= 0 && range.length > 0 && range.location + range.length <= length
}
func createAttributeModels() -> [(any LabelAttributeModel)] {
var attributes: [any VDS.LabelAttributeModel] = []
enumerateAttributes(in: NSMakeRange(0, length)) { attributeMap, range, stop in
attributeMap.forEach { (key: NSAttributedString.Key, value: Any) in
if let attribute = NSAttributedString.createAttributeModelFor(key: key, range: range, value: value) {
attributes.append(attribute)
}
}
}
return attributes
}
static func createAttributeModelFor(key: NSAttributedString.Key, range: NSRange, value: Any) -> (any LabelAttributeModel)? {
guard let value = value as? AnyHashable else { return nil }
guard let font = value as? UIFont, let style = TextStyle.style(for: font.fontName, size: font.pointSize), key == .font
else {
return AnyAttribute(location: range.location, length: range.length, key: key, value: value)
}
return TextStyleLabelAttribute(location: range.location, length: range.length, textStyle: style)
}
}
extension NSMutableAttributedString {
public func apply(attribute: any LabelAttributeModel) {
attribute.setAttribute(on: self)
}
public func apply(attributes: [any LabelAttributeModel]) {
attributes.forEach { apply(attribute: $0) }
}
}