taler-ios

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

TalerStrings.swift (5052B)


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