TalerStrings.swift (4695B)
1 /* 2 * This file is part of GNU Taler, ©2022-25 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 func replacingOccurrences(of str1: String, with str2: String) -> String { 63 let fragments = self.components(separatedBy: str1) 64 if fragments.count > 1 { 65 return fragments.joined(separator: str2) 66 } 67 return self 68 } 69 70 func deletingPrefix(_ prefix: String) -> String { 71 guard self.hasPrefix(prefix) else { return self } 72 return String(self.dropFirst(prefix.count)) 73 } 74 75 var spaced: String { 76 String(self.map { 77 $0 == NONBREAKING ? SPACECHAR : $0 78 }) 79 } 80 var nbs: String { 81 String(self.map { 82 $0 == SPACECHAR ? NONBREAKING : $0 83 }) 84 } 85 86 func tabbed(oneLine: Bool) -> String { 87 let fragments = self.components(separatedBy: "\t") 88 if fragments.count > 1 { 89 let separator = oneLine ? SPACE : "\n" 90 return fragments.joined(separator: separator) 91 } 92 return self 93 } 94 95 func widthOfString(usingUIFont font: UIFont) -> CGFloat { 96 let fontAttributes = [NSAttributedString.Key.font: font] 97 let size = self.size(withAttributes: fontAttributes) 98 return size.width 99 } 100 101 func widthOfString(usingUIFont font: UIFont, _ sizeCategory: ContentSizeCategory) -> CGFloat { 102 let width = widthOfString(usingUIFont: font) 103 let correctForSize = correctForSize(sizeCategory) 104 return width * correctForSize 105 } 106 107 public func width(largeAmountFont: Bool, _ sizeCategory: ContentSizeCategory) -> CGFloat { 108 let uiFont = TalerUIFont.uiFont(largeAmountFont ? .title : .title2) 109 return widthOfString(usingUIFont: uiFont, sizeCategory) 110 } 111 112 // This would be used like so: 113 // let uiFont = UIFont.systemFont(ofSize: 17, weight: .bold) 114 // let width = "SomeString".widthOfString(usingUIFont: uiFont) 115 116 /// 117 fileprivate func correctForSize(_ sizeCategory: ContentSizeCategory) -> CGFloat { 118 // empirical values 119 let corrValue = switch sizeCategory { 120 case .extraSmall: 0.7 121 case .small: 0.8 122 case .medium: 0.9 123 // case .large: 1.0 124 case .extraLarge: 1.15 125 case .extraExtraLarge: 1.25 126 case .extraExtraExtraLarge: 1.33 127 case .accessibilityMedium: 1.52 128 case .accessibilityLarge: 1.8 129 case .accessibilityExtraLarge: 2.0 130 case .accessibilityExtraExtraLarge: 2.2 131 case .accessibilityExtraExtraExtraLarge: 2.5 132 default: 1.0 133 } 134 if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { 135 // directly return the empirical value 136 return corrValue 137 } else { 138 // preview doesn't use ContentSizeCategory for widthOfString(usingUIFont) 139 // thus the empirical values are the square of what's really needed 140 return sqrt(corrValue) 141 } 142 } 143 }