// // TextDataApiModelConverter.swift // SttDictionary.iOS.NextGen // // Created by Peter Standret on 9/28/19. // Copyright © 2019 Peter Standret. All rights reserved. // import Foundation import UIKit import STT fileprivate extension UIFont { func withTraits(_ traits: UIFontDescriptor.SymbolicTraits) -> UIFont { if let fontDescriptor = fontDescriptor.withSymbolicTraits(traits) { return UIFont(descriptor: fontDescriptor, size: pointSize) } return self } } fileprivate extension String { func substring(location: Int, lenght: Int) -> Substring { let startIndex = self.index(self.startIndex, offsetBy: location) let endIndex = self.index(self.startIndex, offsetBy: location + lenght) return self[startIndex.. NSAttributedString { let parserData = parameter as! TDConverterParameter let result = NSMutableAttributedString( string: value.value, attributes: Const.defaultAttributes ) for data in value.metaData { // range let start = data.range.location let length = data.range.length let range = NSRange(location: start, length: length) var attributes = Const.defaultAttributes attributes[.foregroundColor] = getColor(data: data) attributes[.font] = UIFont.systemFont(ofSize: 18, weight: getFontWeight(data: data)) if data.fontDecoration == .underline { attributes[.underlineStyle] = NSUnderlineStyle.single.rawValue } if data.fontStyle == .italic { attributes[.font] = (attributes[.font] as! UIFont).withTraits(.traitItalic) } else if data.fontStyle == .monospaced { attributes[.font] = UIFont.monospacedSystemFont(ofSize: 18, weight: getFontWeight(data: data)) } // subscript or superscript if data.textType != .normal { attributes[.font] = (attributes[.font] as! UIFont).withSize(10) attributes[.baselineOffset] = data.textType == .subScript ? -7 : 7 } result.setAttributes(attributes, range: range) } if parserData.rawOutput { return result } return getFormattedString(from: result, parserData: parserData) } private func getFormattedString( from string: NSAttributedString, parserData: TDConverterParameter ) -> NSAttributedString { let closeDeletionRanges = string.string.ranges(for: Const.closeDeletionDelimeter) guard !closeDeletionRanges.isEmpty else { return string } let result = NSMutableAttributedString() var previusEnd = 0 for range in closeDeletionRanges { if previusEnd < range.location { result.append(string.attributedSubstring(from: NSRange(location: previusEnd, length: range.location - previusEnd)) ) } let closeDeletion = string.attributedSubstring( from: NSRange(location: range.location, length: range.length) ) if let delimeterRange = closeDeletion.string.ranges(for: Const.closeHintDelimeter).first { let hint = closeDeletion.attributedSubstring(from: NSRange(location: 2, length: delimeterRange.location - 2) ) let value = closeDeletion.attributedSubstring(from: NSRange( location: delimeterRange.location + delimeterRange.length, length: closeDeletion.length - delimeterRange.location - delimeterRange.length - 2 )) let valueToAppend = parserData.isOpenCloseDeletion ? value : hint let startLocation = result.length result.append(valueToAppend) result.setAttributes( Const.defaultCLDAttributes, range: NSRange(location: startLocation, length: valueToAppend.length) ) } else { if parserData.isOpenCloseDeletion { let valueToAppend = closeDeletion.attributedSubstring(from: NSRange(location: 2, length: closeDeletion.length - 4) ) let startLocation = result.length result.append(valueToAppend) result.setAttributes( Const.defaultCLDAttributes, range: NSRange(location: startLocation, length: valueToAppend.length) ) } else { result.append(NSAttributedString(string: "[...]", attributes: Const.defaultCLDAttributes)) } } previusEnd = range.location + range.length } if previusEnd < string.length { result.append(string.attributedSubstring(from: NSRange(location: previusEnd, length: string.length - previusEnd)) ) } return result } private func getColor(data: TextMetaDataApiModel) -> UIColor { switch data.colorType { case .default: return Asset.NightColors.textColor.color case .highlihted: return Asset.NightColors.mainYellow.color case .custom: if let customColor = data.color { return UIColor( red: CGFloat(CFloat(customColor.red)) / 255.0, green: CGFloat(CFloat(customColor.green)) / 255.0, blue: CGFloat(CFloat(customColor.blue)) / 255.0, alpha: CGFloat(CFloat(customColor.alpha)) / 255.0 ) } return Asset.NightColors.textColor.color } } private func getFontWeight(data: TextMetaDataApiModel) -> UIFont.Weight { switch data.fontWeight { case .black: return .black case .regular: return .regular case .thin: return .thin case .medium: return .medium case .bold: return .bold } } } final class TextDataApiModelConverterCombiner: ConverterType { let converter = TextDataApiModelConverter() func convert(value: [TextDataApiModel], parameter: Any?) -> NSAttributedString { let parserData = parameter as! TDConverterParameter let result = NSMutableAttributedString() for (index, text) in value.enumerated() { result.append(converter.convert(value: text, parameter: parserData)) if index < value.count - 1 { result.append(NSAttributedString(string: "\n")) } } return result } }