lnlink

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

commit 87539b63d04368ba60ca6afd881e02e32a780923
parent 5a289cddd0a761cfc11c906c379a901d20ee2f0e
Author: William Casarin <jb55@jb55.com>
Date:   Sat, 26 Feb 2022 18:05:07 -0800

setup screen working much better

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

Diffstat:
MTODO | 4++--
Mlightninglink/Views/ContentView.swift | 48+++++++++++++++++++++++++++++++++++++++++-------
Mlightninglink/Views/SetupView.swift | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mlightninglink/lightninglinkApp.swift | 34+++++++++-------------------------
4 files changed, 110 insertions(+), 63 deletions(-)

diff --git a/TODO b/TODO @@ -1,6 +1,6 @@ +(B) receive funds / create invoice view parse lnurl make lnurl request bolt12 support -(B) receive funds / create invoice view create offer -(A) auth setup screen +pin or face unlock diff --git a/lightninglink/Views/ContentView.swift b/lightninglink/Views/ContentView.swift @@ -70,6 +70,7 @@ struct ContentView: View { @State private var last_pay: Pay? @State private var dashboard: Dashboard @State private var funds: Funds + @State private var is_reset: Bool = false private var lnlink: LNLink @@ -115,15 +116,33 @@ struct ContentView: View { self.has_alert = true } - var body: some View { + func main_content() -> some View { VStack { - Group { + VStack { + HStack { + VStack { Text(self.dashboard.info.alias) - .font(.largeTitle) - .padding() - Text("\(self.dashboard.info.num_active_channels) active channels") - Text("\(self.dashboard.info.msatoshi_fees_collected / 1000) sats collected in fees") + .font(.title) + } + + Spacer() + + Button("Reset") { + reset_lnlink() + self.is_reset = true } + } + + HStack { + Text("\(self.dashboard.info.msatoshi_fees_collected / 1000) sats earned") + .font(.footnote) + .foregroundColor(.gray) + + Spacer() + } + } + .padding() + Spacer() Text("\(format_last_pay())") .foregroundColor(Color.red) @@ -131,12 +150,18 @@ struct ContentView: View { Text("\(self.funds.channel_sats) sats") .font(.title) .padding() - Text("\(self.funds.onchain_sats) onchain") + + if self.funds.onchain_sats != 0 { + Text("\(self.funds.onchain_sats) onchain") + .foregroundColor(.gray) + } + Spacer() HStack { Spacer() Button("Pay", action: check_pay) .font(.title) + .buttonStyle(.bordered) .padding() } } @@ -188,6 +213,15 @@ struct ContentView: View { self.active_sheet = nil refresh_funds() } + + } + + var body: some View { + if is_reset { + SetupView() + } else { + main_content() + } } } diff --git a/lightninglink/Views/SetupView.swift b/lightninglink/Views/SetupView.swift @@ -28,47 +28,74 @@ public enum SetupResult { public enum SetupViewState { case initial - case validating + case validating(LNLink) case validated } +func initial_state() -> SetupViewState { + let lnlink = load_lnlink() + if lnlink != nil { + return .validating(lnlink!) + } + + return .initial +} + struct SetupView: View { @State var active_sheet: ActiveAuthSheet? = nil - @State var state: SetupViewState = .initial + @State var state: SetupViewState = initial_state() @State var error: String? = nil @State var dashboard: Dashboard = .empty @State var lnlink: LNLink? = nil func perform_validation(_ lnlink: LNLink) { - validate_connection(lnlink: lnlink) { res in - switch res { - case .connection_failed: - self.state = .initial - self.error = "Connection failed" - case .plugin_missing: - self.state = .initial - self.error = "Connected but could not retrieve data, plugin missing?" - case .auth_invalid(let str): - self.state = .initial - self.error = "Auth issue: \(str)" - case .success(let info, let funds): - save_lnlink(lnlink: lnlink) - self.lnlink = lnlink - self.dashboard = Dashboard(info: info, funds: funds) - self.state = .validated - self.error = nil - } - } + DispatchQueue.main.async { + validate_connection(lnlink: lnlink) { res in + switch res { + case .connection_failed: + self.state = .initial + self.error = "Connection failed" + case .plugin_missing: + self.state = .initial + self.error = "Connected but could not retrieve data. Commando plugin missing?" + case .auth_invalid(let str): + self.state = .initial + self.error = "Auth issue: \(str)" + case .success(let info, let funds): + save_lnlink(lnlink: lnlink) + self.lnlink = lnlink + self.dashboard = Dashboard(info: info, funds: funds) + self.state = .validated + self.error = nil + } + } + } } func setup_view() -> some View { VStack { - Button("Scan auth QR") { + Text("Connect") + .font(.headline) + + Spacer() + + Button("Scan LNLink QR Code") { self.active_sheet = .qr } + .foregroundColor(Color.blue) + .padding() + .background(Color(.secondarySystemBackground)) + .cornerRadius(16) + if self.error != nil { - Text("\(self.error!)") + Text("Error: \(self.error!)") + .foregroundColor(Color.red) } + + Spacer() + + Link("What the heck is LNLink?", destination: URL(string:"https://jb55.com/lnlink/qr")!) + .padding() } .sheet(item: $active_sheet) { active_sheet in switch active_sheet { @@ -84,8 +111,7 @@ struct SetupView: View { case .left(let err): self.error = err case .right(let lnlink): - self.state = .validating - self.perform_validation(lnlink) + self.state = .validating(lnlink) } case .failure(let scan_err): @@ -97,8 +123,11 @@ struct SetupView: View { } - func validating_view() -> some View { - Text("Checking connection...") + func validating_view(lnlink: LNLink) -> some View { + Text("Connecting...") + .onAppear() { + self.perform_validation(lnlink) + } } var body: some View { @@ -106,8 +135,8 @@ struct SetupView: View { switch self.state { case .initial: setup_view() - case .validating: - validating_view() + case .validating(let lnlink): + validating_view(lnlink: lnlink) case .validated: ContentView(dashboard: self.dashboard, lnlink: self.lnlink!) } diff --git a/lightninglink/lightninglinkApp.swift b/lightninglink/lightninglinkApp.swift @@ -14,6 +14,7 @@ public struct Dashboard { public static var empty: Dashboard = Dashboard(info: .empty, funds: .empty) } + func fetch_dashboard(lnlink: LNLink) -> Either<String, Dashboard> { let ln = LNSocket() @@ -24,7 +25,7 @@ func fetch_dashboard(lnlink: LNLink) -> Either<String, Dashboard> { let res = rpc_getinfo(ln: ln, token: lnlink.token) switch res { case .failure(let res_err): - return .left(res_err.decoded?.message ?? res_err.description) + return .left(res_err.decoded?.message ?? res_err.errorType.localizedDescription.debugDescription ) case .success(let info): let res2 = rpc_listfunds(ln: ln, token: lnlink.token) switch res2 { @@ -44,30 +45,7 @@ struct lightninglinkApp: App { var body: some Scene { WindowGroup { - if self.error != nil { - Text("Error: \(self.error!)") - } else { - if self.lnlink != nil { - if self.dashboard != nil { - ContentView(dashboard: self.dashboard!, lnlink: self.lnlink!) - } else { - VStack { - Text("Connecting...") - .onAppear() { - let res = fetch_dashboard(lnlink: self.lnlink!) - switch res { - case .left(let err): - self.error = err - case .right(let dash): - self.dashboard = dash - } - } - } - } - } else { - SetupView() - } - } + SetupView() } } } @@ -99,6 +77,12 @@ func save_lnlink(lnlink: LNLink) { UserDefaults.standard.set(lnlink.host, forKey: "lnlink_host") } +func reset_lnlink() { + UserDefaults.standard.removeObject(forKey: "lnlink_token") + UserDefaults.standard.removeObject(forKey: "lnlink_nodeid") + UserDefaults.standard.removeObject(forKey: "lnlink_host") +} + func load_lnlink() -> LNLink? { let m_token = UserDefaults.standard.string(forKey: "lnlink_token") let m_nodeid = UserDefaults.standard.string(forKey: "lnlink_nodeid")