AmountInputView.swift (2802B)
1 // 2 // AmountInput.swift 3 // lightninglink 4 // 5 // Created by William Casarin on 2022-03-25. 6 // 7 8 import SwiftUI 9 import Combine 10 11 enum BTCDenomination: String { 12 case sats 13 case bits 14 case mbtc 15 case btc 16 } 17 18 enum Denomination: CustomStringConvertible, Identifiable, Hashable { 19 case fiat(Currency) 20 case bitcoin(BTCDenomination) 21 22 var description: String { 23 switch self { 24 case .fiat(let cur): 25 return cur.rawValue 26 case .bitcoin(let btc): 27 return btc.rawValue 28 } 29 } 30 31 var id: String { 32 return self.description 33 } 34 } 35 36 func get_preferred_denominations() -> [Denomination] { 37 let fiat_pref_str = UserDefaults.standard.string(forKey: "fiat_denomination") ?? "USD" 38 let btc_pref_str = UserDefaults.standard.string(forKey: "btc_denomination") ?? "sats" 39 40 let btc_pref = BTCDenomination(rawValue: btc_pref_str) ?? .sats 41 let fiat_pref = Currency(rawValue: fiat_pref_str) ?? .USD 42 43 return [.bitcoin(btc_pref), .fiat(fiat_pref)] 44 } 45 46 struct ParsedAmount { 47 let msats_str: String? 48 let msats: Int64? 49 50 static var empty: ParsedAmount { 51 ParsedAmount(msats_str: nil, msats: nil) 52 } 53 } 54 55 struct AmountInput: View { 56 @State var amount_msat: Int64? = nil 57 let text: Binding<String> 58 let placeholder: String 59 let onReceive: (ParsedAmount) -> () 60 61 var body: some View { 62 VStack { 63 HStack(alignment: .lastTextBaseline) { 64 TextField(placeholder, text: self.text) 65 .font(.largeTitle.bold()) 66 .keyboardType(.numberPad) 67 .multilineTextAlignment(.trailing) 68 .onReceive(Just(self.text)) { 69 onReceive(parse_msat_input($0.wrappedValue)) 70 } 71 Text("sats") 72 .font(.subheadline) 73 } 74 75 } 76 } 77 } 78 79 80 func msats_to_fiat(msats: Int64, xr: ExchangeRate) -> String { 81 let btc = Double(msats) / Double(100_000_000_000) 82 let rate = xr.rate * btc 83 let num_fmt = NumberFormatter() 84 num_fmt.numberStyle = .currency 85 return num_fmt.string(from: NSNumber(value: round(rate * 100) / 100.0))! 86 } 87 88 89 func parse_msat_input(_ new_val: String) -> ParsedAmount { 90 if new_val == "" { 91 return ParsedAmount(msats_str: "", msats: nil) 92 } 93 94 let ok = new_val.allSatisfy { $0 == "," || ($0 >= "0" && $0 <= "9") } 95 if ok { 96 let num_fmt = NumberFormatter() 97 num_fmt.numberStyle = .decimal 98 99 let filtered = new_val.filter { $0 >= "0" && $0 <= "9" } 100 let sats = Int64(filtered) ?? 0 101 let msats = sats * 1000 102 let ret = num_fmt.string(from: NSNumber(value: sats)) ?? new_val 103 return ParsedAmount(msats_str: ret, msats: msats) 104 } 105 106 return .empty 107 } 108