lnlink

iOS app for connecting to lightning nodes
git clone git://jb55.com/lnlink
Log | Files | Refs | Submodules | README | LICENSE

commit 3ab644a3fd9774d5d9985f76d6fffd28041b6630
parent 2b8806932db23c6a2d86794832d7b634c0e89032
Author: William Casarin <jb55@jb55.com>
Date:   Sat,  5 Mar 2022 14:51:26 -0800

Initial tipping buttons

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Mlightninglink/Views/ContentView.swift | 9++-------
Mlightninglink/Views/PayView.swift | 140++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
2 files changed, 90 insertions(+), 59 deletions(-)

diff --git a/lightninglink/Views/ContentView.swift b/lightninglink/Views/ContentView.swift @@ -98,13 +98,8 @@ struct ContentView: View { return "" } - if (pay.msatoshi >= 1000) { - let sats = pay.msatoshi / 1000 - let fee = (pay.msatoshi_sent - pay.msatoshi) / 1000 - return "-\(sats) sats (\(fee) sats fee)" - } - - return "-\(pay.msatoshi) msats (\(pay.msatoshi_sent) msats sent)" + let fee = pay.msatoshi_sent - pay.msatoshi + return "-\(render_amount_msats(pay.msatoshi)) (\(render_amount_msats(fee)) fee)" } func check_pay() { diff --git a/lightninglink/Views/PayView.swift b/lightninglink/Views/PayView.swift @@ -46,7 +46,8 @@ struct PayView: View { @State var invoice: Decode? @State var error: String? @State var expiry_percent: Double? - @State var custom_amount: String = "" + @State var custom_amount_input: String = "" + @State var custom_amount_msats: Int64 = 0 @Environment(\.presentationMode) var presentationMode @@ -167,7 +168,60 @@ struct PayView: View { func handle_custom_receive(_ new_val: String) { let filtered = new_val.filter { "0123456789".contains($0) } if filtered != new_val { - self.custom_amount = filtered + self.custom_amount_input = filtered + let msats = (Int64(filtered) ?? 0) * 1000 + self.custom_amount_msats = msats + } + } + + func tip_percent(_ percent: Double) { + if percent == 0 { + self.custom_amount_msats = 0 + return + } + + guard let invoice = self.invoice else { + return + } + guard let amount_msat_str = invoice.amount_msat else { + return + } + guard let amount_msat = parse_msat(amount_msat_str) else { + return + } + + self.custom_amount_msats = Int64((Double(amount_msat) * percent)) + } + + func tip_view() -> some View { + Group { + Text("Tip?") + HStack { + Button("None") { + tip_percent(0) + } + .padding() + + Button("10%") { + tip_percent(0.1) + } + .padding() + + Button("15%") { + tip_percent(0.15) + } + .padding() + + Button("20%") { + tip_percent(0.2) + } + .padding() + } + .padding() + + let tip_str = self.custom_amount_msats == 0 ? "No tip" : "\(render_amount_msats(self.custom_amount_msats)) tip" + + Text(tip_str) } } @@ -178,17 +232,14 @@ struct PayView: View { case .min(let min_amt): Text("\(render_amount_msats(min_amt))") .font(.title) - Text("Tip?") - TextField("Amount", text: $custom_amount) - .keyboardType(.numberPad) - .onReceive(Just(self.custom_amount)) { - handle_custom_receive($0) - } + Spacer() + tip_view() case .any: - TextField("Amount", text: $custom_amount) + TextField("Amount", text: $custom_amount_input) + .font(.title) .keyboardType(.numberPad) - .onReceive(Just(self.custom_amount)) { + .onReceive(Just(self.custom_amount_input)) { handle_custom_receive($0) } case .amount(let amt): @@ -212,67 +263,52 @@ struct PayView: View { } } - func get_pay_amount(_ amt: InvoiceAmount) -> Either<String, PayAmount> { - let m_pay_amount = Int64(self.custom_amount) - + func get_pay_amount(_ amt: InvoiceAmount) -> PayAmount { switch amt { case .min(let min_amt): - // TODO: get tip from tip percent buttons - let tip = m_pay_amount ?? 0 - return .right(PayAmount(tip: tip, amount: min_amt)) + let tip = self.custom_amount_msats + return PayAmount(tip: tip, amount: min_amt) case .any: - guard let custom_amount = Int64(self.custom_amount) else { - return .left("Invalid amount: '\(self.custom_amount)'") - } - return .right(PayAmount(tip: 0, amount: custom_amount)) + return PayAmount(tip: 0, amount: custom_amount_msats) case .amount(let amt): - return .right(PayAmount(tip: 0, amount: amt)) + return PayAmount(tip: 0, amount: amt) } } func handle_confirm(ln mln: LNSocket?) { switch self.state { case .offer_input(let inv, let decoded): - switch get_pay_amount(inv.amount) { + let pay_amt = get_pay_amount(inv.amount) + let req = fetchinvoice_req_from_offer( + offer: decoded, + offer_str: inv.invoice, + pay_amt: pay_amt) + switch req { case .left(let err): self.error = err - return - case .right(let pay_amt): - let req = fetchinvoice_req_from_offer( - offer: decoded, - offer_str: inv.invoice, - pay_amt: pay_amt) - switch req { - case .left(let err): - self.error = err - case .right(let req): - let token = self.lnlink.token - DispatchQueue.global(qos: .background).async { - let ln = mln ?? LNSocket() - if mln == nil { - guard ln.connect_and_init(node_id: self.lnlink.node_id, host: self.lnlink.host) else { - self.error = "Connection failed when fetching invoice" - return - } - } - switch rpc_fetchinvoice(ln: ln, token: token, req: req) { - case .failure(let err): - self.error = err.description - case .success(let fetch_invoice): - confirm_pay(ln: ln, inv: fetch_invoice.invoice, pay_amt: nil) + case .right(let req): + let token = self.lnlink.token + DispatchQueue.global(qos: .background).async { + let ln = mln ?? LNSocket() + if mln == nil { + guard ln.connect_and_init(node_id: self.lnlink.node_id, host: self.lnlink.host) else { + self.error = "Connection failed when fetching invoice" + return } } + switch rpc_fetchinvoice(ln: ln, token: token, req: req) { + case .failure(let err): + self.error = err.description + case .success(let fetch_invoice): + confirm_pay(ln: ln, inv: fetch_invoice.invoice, pay_amt: nil) + } } } case .ready(let ready_invoice): - switch get_pay_amount(ready_invoice.amount) { - case .left(let err): - self.error = err - case .right(let pay_amt): - confirm_pay(ln: mln, inv: ready_invoice.invoice, pay_amt: pay_amt) - } + let pay_amt = get_pay_amount(ready_invoice.amount) + confirm_pay(ln: mln, inv: ready_invoice.invoice, pay_amt: pay_amt) case .initial: fallthrough case .decoding: fallthrough