commit 6e3e784be868d96aed0b3993dad30549018ee2ca
parent 654a8b28b45ea0bff0f109f7c052ecf3021b51eb
Author: William Casarin <jb55@jb55.com>
Date: Fri, 11 Mar 2022 20:06:21 -0800
handle lnlink: and lightning: urls
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
3 files changed, 99 insertions(+), 21 deletions(-)
diff --git a/lightninglink/Info.plist b/lightninglink/Info.plist
@@ -1,5 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
-<dict/>
+<dict>
+ <key>CFBundleURLTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>CFBundleURLIconFile</key>
+ <string> q</string>
+ <key>CFBundleURLName</key>
+ <string>com.jb55.lightning</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>lightning</string>
+ </array>
+ </dict>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>CFBundleURLName</key>
+ <string>com.jb55.lnlink</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>lnlink</string>
+ </array>
+ </dict>
+ </array>
+</dict>
</plist>
diff --git a/lightninglink/Views/ContentView.swift b/lightninglink/Views/ContentView.swift
@@ -82,13 +82,15 @@ struct ContentView: View {
@State private var dashboard: Dashboard
@State private var funds: Funds
@State private var is_reset: Bool = false
+ @State private var scan_invoice: String?
- private var lnlink: LNLink
+ private let lnlink: LNLink
- init(dashboard: Dashboard, lnlink: LNLink) {
+ init(dashboard: Dashboard, lnlink: LNLink, scan_invoice: String?) {
self.dashboard = dashboard
self.lnlink = lnlink
self.has_alert = false
+ self.scan_invoice = scan_invoice
self.funds = Funds.from_listfunds(fs: dashboard.funds)
}
@@ -193,18 +195,7 @@ struct ContentView: View {
CodeScannerView(codeTypes: SCAN_TYPES) { res in
switch res {
case .success(let scan_res):
- let code = scan_res.string
- var invstr: String = code
- if code.starts(with: "lightning:") {
- let index = code.index(code.startIndex, offsetBy: 10)
- invstr = String(code[index...])
- }
- invstr = invstr.trimmingCharacters(in: .whitespacesAndNewlines)
- let m_parsed = parseInvoiceString(invstr)
- guard let parsed = m_parsed else {
- return
- }
- self.active_sheet = .pay(parsed, invstr)
+ handle_scan(scan_res.string)
case .failure:
self.active_sheet = nil
@@ -228,12 +219,37 @@ struct ContentView: View {
.onReceive(NotificationCenter.default.publisher(for: .donate)) { _ in
self.active_sheet = .pay(.offer, "lno1pfsycnjvd9hxkgrfwvsxvun9v5s8xmmxw3mkzun9yysyyateypkk2grpyrcflrd6ypek7gzfyp3kzm3qvdhkuarfde6k2grd0ysxzmrrda5x7mrfwdkj6en4v4kx2epqvdhkg6twvusxzerkv4h8gatjv4eju9q2d3hxc6twdvhxzursrcs08sggen2ndwzjdpqlpfw9sgfth8n9sjs7kjfssrnurnp5lqk66u0sgr32zxwrh0kmxnvmt5hyn0my534209573mp9ck5ekvywvugm5x3kq8ztex8yumafeft0arh6dke04jqgckmdzekqxegxzhecl23lurrj")
}
+ .onOpenURL() { url in
+ handle_scan(url.absoluteString)
+ }
+ .onAppear() {
+ if scan_invoice != nil {
+ handle_scan(scan_invoice!)
+ scan_invoice = nil
+ }
+ }
.navigationBarTitle("", displayMode: .inline)
.navigationBarHidden(true)
}
}
+
+ func handle_scan(_ str: String) {
+ switch handle_qrcode(str) {
+ case .left(let err):
+ print("scan error: \(err)")
+ break
+ case .right(let scanres):
+ switch scanres {
+ case .lightning(let decode, let invstr):
+ self.active_sheet = .pay(decode, invstr)
+ case .lnlink:
+ print("got a lnlink, not an invoice")
+ // TODO: report that this is an lnlink, not an invoice
+ }
+ }
+ }
var body: some View {
if is_reset {
@@ -254,6 +270,37 @@ struct ContentView_Previews: PreviewProvider {
}
*/
+public enum LNScanResult {
+ case lightning(DecodeType, String)
+ case lnlink(LNLink)
+}
+
+
+func handle_qrcode(_ qr: String) -> Either<String, LNScanResult> {
+ var invstr = qr.trimmingCharacters(in: .whitespacesAndNewlines)
+ let lowered = invstr.lowercased()
+
+ if lowered.starts(with: "lnlink:") {
+ switch parse_auth_qr(invstr) {
+ case .left(let err):
+ return .left(err)
+ case .right(let lnlink):
+ return .right(.lnlink(lnlink))
+ }
+ }
+
+ if lowered.starts(with: "lightning:") {
+ let index = invstr.index(invstr.startIndex, offsetBy: 10)
+ invstr = String(lowered[index...])
+ }
+
+ guard let parsed = parseInvoiceString(invstr) else {
+ return .left("Failed to parse invoice")
+ }
+
+ return .right(.lightning(parsed, invstr))
+}
+
func get_clipboard_invoice() -> (DecodeType, String)? {
guard let inv = UIPasteboard.general.string else {
diff --git a/lightninglink/Views/SetupView.swift b/lightninglink/Views/SetupView.swift
@@ -47,6 +47,7 @@ struct SetupView: View {
@State var error: String? = nil
@State var dashboard: Dashboard = .empty
@State var lnlink: LNLink? = nil
+ @State var scan_invoice: String? = nil
func perform_validation(_ lnlink: LNLink) {
DispatchQueue.global(qos: .background).async {
@@ -101,6 +102,9 @@ struct SetupView: View {
Link("What the heck is LNLink?", destination: URL(string:"http://lnlink.app/qr")!)
}
.padding()
+ .onOpenURL() { url in
+ self.scan_invoice = url.absoluteString
+ }
.sheet(item: $active_sheet) { active_sheet in
switch active_sheet {
case .qr:
@@ -128,12 +132,16 @@ struct SetupView: View {
}
func validating_view(lnlink: LNLink) -> some View {
- Text("Connecting...")
+ ProgressView()
+ .progressViewStyle(.circular)
.onAppear() {
self.perform_validation(lnlink)
}
+ .onOpenURL() { url in
+ self.scan_invoice = url.absoluteString
+ }
}
-
+
var body: some View {
Group {
switch self.state {
@@ -142,7 +150,7 @@ struct SetupView: View {
case .validating(let lnlink):
validating_view(lnlink: lnlink)
case .validated:
- ContentView(dashboard: self.dashboard, lnlink: self.lnlink!)
+ ContentView(dashboard: self.dashboard, lnlink: self.lnlink!, scan_invoice: self.scan_invoice)
}
}
}
@@ -166,9 +174,6 @@ func parse_auth_qr(_ qr: String) -> Either<String, LNLink> {
auth_qr = qr.replacingOccurrences(of: "lnlink:", with: "lnlink://")
}
- // some qrcodes are weird like this
- auth_qr = auth_qr.trimmingCharacters(in: .whitespacesAndNewlines)
-
guard let url = URL(string: auth_qr) else {
return .left("Invalid url")
}