TalerStrings.swift (4792B)
1 /* 2 * This file is part of GNU Taler, ©2022-26 Taler Systems S.A. 3 * See LICENSE.md 4 */ 5 /** 6 * @author Marc Stibane 7 */ 8 import SwiftUI 9 import Foundation 10 import UIKit 11 12 extension StringProtocol { 13 var trimURL: String { 14 if let url = URL(string: String(self)) { 15 if let host = url.host { 16 return host.deletingPrefix("exchange.") 17 } 18 } 19 return String(self) 20 } 21 22 func index<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> Index? { 23 range(of: string, options: options)?.lowerBound 24 } 25 func endIndex<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> Index? { 26 range(of: string, options: options)?.upperBound 27 } 28 func indices<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> [Index] { 29 ranges(of: string, options: options).map(\.lowerBound) 30 } 31 func ranges<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> [Range<Index>] { 32 var result: [Range<Index>] = [] 33 var startIndex = self.startIndex 34 while startIndex < endIndex, 35 let range = self[startIndex...] 36 .range(of: string, options: options) { 37 result.append(range) 38 startIndex = range.lowerBound < range.upperBound ? range.upperBound : 39 index(range.lowerBound, offsetBy: 1, limitedBy: endIndex) ?? endIndex 40 } 41 return result 42 } 43 } 44 45 extension Data { 46 public var bytes: [UInt8] { 47 return [UInt8](self) 48 } 49 } 50 51 extension String { 52 53 public var bytes: String { 54 var result: String = EMPTYSTRING 55 for k in self.utf8 { 56 result += String(k) 57 result += SPACE 58 } 59 return result 60 } 61 62 public var toURL: URL? { 63 if let someURL = URL(string: self) { 64 return someURL 65 } 66 if let encodedString = self.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) { 67 if let encodedURL = URL(string: encodedString) { 68 return encodedURL 69 } 70 } 71 return nil 72 } 73 74 func deletingPrefix(_ prefix: String) -> String { 75 guard self.hasPrefix(prefix) else { return self } 76 return String(self.dropFirst(prefix.count)) 77 } 78 79 var spaced: String { 80 String(self.map { 81 $0 == NONBREAKING ? SPACECHAR : $0 82 }) 83 } 84 var nbs: String { 85 String(self.map { 86 $0 == SPACECHAR ? NONBREAKING : $0 87 }) 88 } 89 90 func tabbed(oneLine: Bool) -> String { 91 let fragments = self.components(separatedBy: "\t") 92 if fragments.count > 1 { 93 let separator = oneLine ? SPACE : "\n" 94 return fragments.joined(separator: separator) 95 } 96 return self 97 } 98 99 func widthOfString(usingUIFont font: UIFont) -> CGFloat { 100 let fontAttributes = [NSAttributedString.Key.font: font] 101 let size = self.size(withAttributes: fontAttributes) 102 return size.width 103 } 104 105 func widthOfString(usingUIFont font: UIFont, _ sizeCategory: ContentSizeCategory) -> CGFloat { 106 let width = widthOfString(usingUIFont: font) 107 let correctForSize = correctForSize(sizeCategory) 108 return width * correctForSize 109 } 110 111 public func width(largeAmountFont: Bool, _ sizeCategory: ContentSizeCategory) -> CGFloat { 112 let uiFont = TalerUIFont.uiFont(largeAmountFont ? .title : .title2) 113 return widthOfString(usingUIFont: uiFont, sizeCategory) 114 } 115 116 // This would be used like so: 117 // let uiFont = UIFont.systemFont(ofSize: 17, weight: .bold) 118 // let width = "SomeString".widthOfString(usingUIFont: uiFont) 119 120 /// 121 fileprivate func correctForSize(_ sizeCategory: ContentSizeCategory) -> CGFloat { 122 // empirical values 123 let corrValue = switch sizeCategory { 124 case .extraSmall: 0.7 125 case .small: 0.8 126 case .medium: 0.9 127 // case .large: 1.0 128 case .extraLarge: 1.15 129 case .extraExtraLarge: 1.25 130 case .extraExtraExtraLarge: 1.33 131 case .accessibilityMedium: 1.52 132 case .accessibilityLarge: 1.8 133 case .accessibilityExtraLarge: 2.0 134 case .accessibilityExtraExtraLarge: 2.2 135 case .accessibilityExtraExtraExtraLarge: 2.5 136 default: 1.0 137 } 138 if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { 139 // directly return the empirical value 140 return corrValue 141 } else { 142 // preview doesn't use ContentSizeCategory for widthOfString(usingUIFont) 143 // thus the empirical values are the square of what's really needed 144 return sqrt(corrValue) 145 } 146 } 147 }