damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit 340574235044eb0ced77d7859dc3c0f669962d2f
parent 205774f684fedb2330929f840c04423146309db0
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 28 Dec 2022 13:10:36 -0800

Wallet Selector

Closes: #107
Changelog-Added: lightning wallet selector

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 4++++
Adamus/Assets.xcassets/bluewallet.imageset/Contents.json | 21+++++++++++++++++++++
Adamus/Assets.xcassets/bluewallet.imageset/bluewallet.png | 0
Adamus/Assets.xcassets/cashapp.imageset/Contents.json | 21+++++++++++++++++++++
Adamus/Assets.xcassets/cashapp.imageset/cashapp.png | 0
Adamus/Assets.xcassets/lnlink.imageset/Contents.json | 21+++++++++++++++++++++
Adamus/Assets.xcassets/lnlink.imageset/lnlink.png | 0
Adamus/Assets.xcassets/muun.imageset/Contents.json | 21+++++++++++++++++++++
Adamus/Assets.xcassets/muun.imageset/muun.png | 0
Adamus/Assets.xcassets/phoenix.imageset/Contents.json | 21+++++++++++++++++++++
Adamus/Assets.xcassets/phoenix.imageset/phoenix.png | 0
Adamus/Assets.xcassets/strike.imageset/Contents.json | 21+++++++++++++++++++++
Adamus/Assets.xcassets/strike.imageset/strike.png | 0
Adamus/Assets.xcassets/walletofsatoshi.imageset/Contents.json | 21+++++++++++++++++++++
Adamus/Assets.xcassets/walletofsatoshi.imageset/walletofsatoshi.png | 0
Adamus/Assets.xcassets/zebedee.imageset/Contents.json | 21+++++++++++++++++++++
Adamus/Assets.xcassets/zebedee.imageset/zebedee.png | 0
Adamus/Assets.xcassets/zeusln.imageset/Contents.json | 21+++++++++++++++++++++
Adamus/Assets.xcassets/zeusln.imageset/zeus.png | 0
Mdamus/Components/InvoiceView.swift | 14++++++++++----
Mdamus/Info.plist | 4++++
Mdamus/Util/Constants.swift | 14++++++++++++++
Mdamus/Views/ProfileView.swift | 19++++++++++++++-----
Adamus/Views/SelectWalletView.swift | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
24 files changed, 326 insertions(+), 9 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -131,6 +131,7 @@ 4CEE2AF9280B2EAC00AB5EEF /* PowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */; }; 4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */; }; 6C7DE41F2955169800E66263 /* Vault in Frameworks */ = {isa = PBXBuildFile; productRef = 6C7DE41E2955169800E66263 /* Vault */; }; + BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; }; E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E990020E2955F837003BBC5A /* EditMetadataView.swift */; }; E9E4ED0B295867B900DD7078 /* ThreadV2View.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E4ED0A295867B900DD7078 /* ThreadV2View.swift */; }; /* End PBXBuildFile section */ @@ -311,6 +312,7 @@ 4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileName.swift; sourceTree = "<group>"; }; 4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowView.swift; sourceTree = "<group>"; }; 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventActionBar.swift; sourceTree = "<group>"; }; + BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectWalletView.swift; sourceTree = "<group>"; }; E990020E2955F837003BBC5A /* EditMetadataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditMetadataView.swift; sourceTree = "<group>"; }; E9E4ED0A295867B900DD7078 /* ThreadV2View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadV2View.swift; sourceTree = "<group>"; }; /* End PBXFileReference section */ @@ -482,6 +484,7 @@ 4C216F33286F5ACD00040376 /* DMView.swift */, 4C06670028FC7C5900038D2A /* RelayView.swift */, E990020E2955F837003BBC5A /* EditMetadataView.swift */, + BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */, E9E4ED0A295867B900DD7078 /* ThreadV2View.swift */, ); path = Views; @@ -811,6 +814,7 @@ 4C3AC79F2833115300E1F516 /* FollowButtonView.swift in Sources */, 4C3BEFD22819DB9B00B3DE84 /* ProfileModel.swift in Sources */, 4C0A3F93280F66F5000448DE /* ReplyMap.swift in Sources */, + BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */, 3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */, 4C3EA64928FF597700C48A62 /* bech32.c in Sources */, 4C90BD162839DB54008EE7EF /* NostrMetadata.swift in Sources */, diff --git a/damus/Assets.xcassets/bluewallet.imageset/Contents.json b/damus/Assets.xcassets/bluewallet.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "bluewallet.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/damus/Assets.xcassets/bluewallet.imageset/bluewallet.png b/damus/Assets.xcassets/bluewallet.imageset/bluewallet.png Binary files differ. diff --git a/damus/Assets.xcassets/cashapp.imageset/Contents.json b/damus/Assets.xcassets/cashapp.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "cashapp.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/damus/Assets.xcassets/cashapp.imageset/cashapp.png b/damus/Assets.xcassets/cashapp.imageset/cashapp.png Binary files differ. diff --git a/damus/Assets.xcassets/lnlink.imageset/Contents.json b/damus/Assets.xcassets/lnlink.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "lnlink.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/damus/Assets.xcassets/lnlink.imageset/lnlink.png b/damus/Assets.xcassets/lnlink.imageset/lnlink.png Binary files differ. diff --git a/damus/Assets.xcassets/muun.imageset/Contents.json b/damus/Assets.xcassets/muun.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "muun.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/damus/Assets.xcassets/muun.imageset/muun.png b/damus/Assets.xcassets/muun.imageset/muun.png Binary files differ. diff --git a/damus/Assets.xcassets/phoenix.imageset/Contents.json b/damus/Assets.xcassets/phoenix.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "phoenix.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/damus/Assets.xcassets/phoenix.imageset/phoenix.png b/damus/Assets.xcassets/phoenix.imageset/phoenix.png Binary files differ. diff --git a/damus/Assets.xcassets/strike.imageset/Contents.json b/damus/Assets.xcassets/strike.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "strike.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/damus/Assets.xcassets/strike.imageset/strike.png b/damus/Assets.xcassets/strike.imageset/strike.png Binary files differ. diff --git a/damus/Assets.xcassets/walletofsatoshi.imageset/Contents.json b/damus/Assets.xcassets/walletofsatoshi.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "walletofsatoshi.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/damus/Assets.xcassets/walletofsatoshi.imageset/walletofsatoshi.png b/damus/Assets.xcassets/walletofsatoshi.imageset/walletofsatoshi.png Binary files differ. diff --git a/damus/Assets.xcassets/zebedee.imageset/Contents.json b/damus/Assets.xcassets/zebedee.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "zebedee.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/damus/Assets.xcassets/zebedee.imageset/zebedee.png b/damus/Assets.xcassets/zebedee.imageset/zebedee.png Binary files differ. diff --git a/damus/Assets.xcassets/zeusln.imageset/Contents.json b/damus/Assets.xcassets/zeusln.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "zeus.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/damus/Assets.xcassets/zeusln.imageset/zeus.png b/damus/Assets.xcassets/zeusln.imageset/zeus.png Binary files differ. diff --git a/damus/Components/InvoiceView.swift b/damus/Components/InvoiceView.swift @@ -12,13 +12,13 @@ struct InvoiceView: View { @Environment(\.colorScheme) var colorScheme let invoice: Invoice + @State var showingSelectWallet: Bool = false + @State var inv: String = "" var PayButton: some View { Button { - guard let url = URL(string: "lightning:" + invoice.string) else { - return - } - UIApplication.shared.open(url) + inv = invoice.string + showingSelectWallet = true } label: { RoundedRectangle(cornerRadius: 20) .foregroundColor(colorScheme == .light ? .black : .white) @@ -28,6 +28,10 @@ struct InvoiceView: View { .foregroundColor(colorScheme == .light ? .white : .black) } } + .buttonStyle(.bordered) + .onTapGesture { + // Temporary solution so that the "pay" button can be clicked (Yes we need an empty tap gesture) + } } var body: some View { @@ -49,6 +53,8 @@ struct InvoiceView: View { .zIndex(5.0) } .padding() + }.sheet(isPresented: $showingSelectWallet, onDismiss: {showingSelectWallet = false}) { + SelectWalletView(showingSelectWallet: $showingSelectWallet, invoice: $inv) } } } diff --git a/damus/Info.plist b/damus/Info.plist @@ -15,6 +15,10 @@ </array> </dict> </array> + <key>LSApplicationQueriesSchemes</key> + <array> + <string>lightning</string> + </array> <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> diff --git a/damus/Util/Constants.swift b/damus/Util/Constants.swift @@ -24,4 +24,18 @@ public class Constants { NostrEvent(id: UUID().description, content: "Hello World! This is so cool!", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"), NostrEvent(id: UUID().description, content: "Bonjour Le Monde", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"), ] + + static let WALLETS = """ + [ + {"id": 0, "name": "Strike", "link": "strike:", "appStoreLink": "https://apps.apple.com/us/app/strike-bitcoin-payments/id1488724463", "image": "strike"}, + {"id": 1, "name": "Cash App", "link": "squarecash://", "appStoreLink": "https://apps.apple.com/us/app/cash-app/id711923939", "image": "cashapp"}, + {"id": 2, "name": "Muun", "link": "muun:", "appStoreLink": "https://apps.apple.com/us/app/muun-wallet/id1482037683", "image": "muun"}, + {"id": 3, "name": "Blue Wallet", "link": "bluewallet:lightning:", "appStoreLink": "https://apps.apple.com/us/app/bluewallet-bitcoin-wallet/id1376878040", "image": "bluewallet"}, + {"id": 4, "name": "Wallet Of Satoshi", "link": "walletofsatoshi:lightning:", "appStoreLink": "https://apps.apple.com/us/app/wallet-of-satoshi/id1438599608", "image": "walletofsatoshi"}, + {"id": 5, "name": "Zebedee", "link": "zebedee:lightning:", "appStoreLink": "https://apps.apple.com/us/app/zebedee-wallet/id1484394401", "image": "zebedee"}, + {"id": 6, "name": "Zeus LN", "link": "zeusln:lightning:", "appStoreLink": "https://apps.apple.com/us/app/zeus-ln/id1456038895", "image": "zeusln"}, + {"id": 7, "name": "LNLink", "link": "lnlink://", "appStoreLink": "https://testflight.apple.com/join/aNY4yuuZ", "image": "lnlink"}, + {"id": 8, "name": "Phoenix", "link": "phoenix://", "appStoreLink": "https://apps.apple.com/us/app/phoenix-wallet/id1544097028", "image": "phoenix"}, + ] + """.data(using: .utf8)! } diff --git a/damus/Views/ProfileView.swift b/damus/Views/ProfileView.swift @@ -119,6 +119,8 @@ struct ProfileView: View { @StateObject var profile: ProfileModel @StateObject var followers: FollowersModel @State private var showingEditProfile = false + @State var showingSelectWallet: Bool = false + @State var inv: String = "" @State var is_zoomed: Bool = false @Environment(\.dismiss) var dismiss @@ -126,9 +128,14 @@ struct ProfileView: View { //@EnvironmentObject var profile: ProfileModel - func LNButton(_ url: URL, profile: Profile) -> some View { + func LNButton(lud06: String?, lud16: String?, profile: Profile) -> some View { Button(action: { - UIApplication.shared.open(url) + if let l = lud06 { + inv = l + } else { + inv = lud16 ?? "" + } + showingSelectWallet = true }) { Image(systemName: "bolt.circle") .symbolRenderingMode(.palette) @@ -141,6 +148,8 @@ struct ProfileView: View { Label("Copy LNURL", systemImage: "doc.on.doc") } } + }.sheet(isPresented: $showingSelectWallet, onDismiss: {showingSelectWallet = false}) { + SelectWalletView(showingSelectWallet: $showingSelectWallet, invoice: $inv) } } @@ -170,10 +179,10 @@ struct ProfileView: View { } Spacer() - + if let profile = data { - if let lnuri = profile.lightning_uri { - LNButton(lnuri, profile: profile) + if (profile.lud06 != nil || profile.lud16 != nil) { + LNButton(lud06: profile.lud06, lud16: profile.lud16, profile: profile) } } diff --git a/damus/Views/SelectWalletView.swift b/damus/Views/SelectWalletView.swift @@ -0,0 +1,91 @@ +// +// SelectWalletView.swift +// damus +// +// Created by Suhail Saqan on 12/22/22. +// + +import SwiftUI + +struct WalletItem : Decodable, Identifiable, Hashable { + var id: Int + var name : String + var link : String + var appStoreLink : String + var image: String +} + +struct SelectWalletView: View { + @Binding var showingSelectWallet: Bool + @Binding var invoice: String + @Environment(\.openURL) private var openURL + @State var invoice_copied: Bool = false + + let generator = UIImpactFeedbackGenerator(style: .light) + + let walletItems = try! JSONDecoder().decode([WalletItem].self, from: Constants.WALLETS) + + var body: some View { + NavigationView { + Form { + Section("Copy invoice") { + HStack { + Text(invoice).font(.body) + .lineLimit(2) + .truncationMode(.tail) + + Spacer() + + Image(systemName: self.invoice_copied ? "checkmark.circle" : "doc.on.doc").foregroundColor(.blue) + }.clipShape(RoundedRectangle(cornerRadius: 5)).onTapGesture { + UIPasteboard.general.string = invoice + self.invoice_copied = true + generator.impactOccurred() + } + } + Section("Select a lightning wallet"){ + List{ + Button() { + if let url = URL(string: "lightning:\(invoice)"), UIApplication.shared.canOpenURL(url) { + openURL(url) + } + } label: { + HStack { + Text("Default Wallet").font(.body).foregroundColor(.blue) + } + }.buttonStyle(.plain) + ForEach(walletItems, id: \.self) { wallet in + Button() { + if let url = URL(string: "\(wallet.link)\(invoice)"), UIApplication.shared.canOpenURL(url) { + openURL(url) + } else { + if let url = URL(string: wallet.appStoreLink), UIApplication.shared.canOpenURL(url) { + openURL(url) + } + } + } label: { + HStack { + Image(wallet.image).resizable().frame(width: 32.0, height: 32.0,alignment: .center).cornerRadius(5) + Text(wallet.name).font(.body) + } + }.buttonStyle(.plain) + } + }.padding(.vertical, 2.5) + } + }.navigationBarTitle(Text("Pay the lightning invoice"), displayMode: .inline).navigationBarItems(trailing: Button(action: { + self.showingSelectWallet = false + }) { + Text("Done").bold() + }) + } + } +} + +struct SelectWalletView_Previews: PreviewProvider { + @State static var show: Bool = true + @State static var invoice: String = "" + + static var previews: some View { + SelectWalletView(showingSelectWallet: $show, invoice: $invoice) + } +}