taler-ios

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

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 }