taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

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 }