WalletView.swift (10052B)
1 // 2 // WalletView.swift 3 // damus 4 // 5 // Created by William Casarin on 2023-05-05. 6 // 7 8 import SwiftUI 9 10 struct WalletView: View { 11 let damus_state: DamusState 12 @ObservedObject var model: WalletModel 13 @ObservedObject var settings: UserSettingsStore 14 15 init(damus_state: DamusState, model: WalletModel? = nil) { 16 self.damus_state = damus_state 17 self._model = ObservedObject(wrappedValue: model ?? damus_state.wallet) 18 self._settings = ObservedObject(wrappedValue: damus_state.settings) 19 } 20 21 func MainWalletView(nwc: WalletConnectURL) -> some View { 22 VStack { 23 if !damus_state.settings.nozaps { 24 SupportDamus 25 26 Spacer() 27 } 28 29 VStack(spacing: 5) { 30 VStack(spacing: 10) { 31 Text("Wallet Relay") 32 .fontWeight(.semibold) 33 .padding(.top) 34 35 Divider() 36 37 RelayView(state: damus_state, relay: nwc.relay, showActionButtons: .constant(false), recommended: false) 38 } 39 .frame(maxWidth: .infinity, minHeight: 125, alignment: .top) 40 .padding(.horizontal, 10) 41 .background(DamusColors.neutral1) 42 .cornerRadius(10) 43 .overlay( 44 RoundedRectangle(cornerRadius: 10) 45 .stroke(DamusColors.neutral3, lineWidth: 1) 46 ) 47 48 if let lud16 = nwc.lud16 { 49 VStack(spacing: 10) { 50 Text("Wallet Address") 51 .fontWeight(.semibold) 52 53 Divider() 54 55 Text(verbatim: lud16) 56 } 57 .frame(maxWidth: .infinity, minHeight: 75, alignment: .center) 58 .padding(.horizontal, 10) 59 .background(DamusColors.neutral1) 60 .cornerRadius(10) 61 .overlay( 62 RoundedRectangle(cornerRadius: 10) 63 .stroke(DamusColors.neutral3, lineWidth: 1) 64 ) 65 } 66 } 67 68 Button(action: { 69 self.model.disconnect() 70 }) { 71 HStack { 72 Text(NSLocalizedString("Disconnect Wallet", comment: "Text for button to disconnect from Nostr Wallet Connect lightning wallet.")) 73 } 74 .frame(minWidth: 300, maxWidth: .infinity, maxHeight: 18, alignment: .center) 75 } 76 .buttonStyle(GradientButtonStyle()) 77 78 } 79 .navigationTitle(NSLocalizedString("Wallet", comment: "Navigation title for Wallet view")) 80 .navigationBarTitleDisplayMode(.inline) 81 .padding() 82 } 83 84 func donation_binding() -> Binding<Double> { 85 return Binding(get: { 86 return Double(model.settings.donation_percent) 87 }, set: { v in 88 model.settings.donation_percent = Int(v) 89 }) 90 } 91 92 static let min_donation: Double = 0.0 93 static let max_donation: Double = 100.0 94 95 var percent: Double { 96 Double(model.settings.donation_percent) / 100.0 97 } 98 99 var tip_msats: String { 100 let msats = Int64(percent * Double(model.settings.default_zap_amount * 1000)) 101 let s = format_msats_abbrev(msats) 102 // TODO: fix formatting and remove this hack 103 let parts = s.split(separator: ".") 104 if parts.count == 1 { 105 return s 106 } 107 if let end = parts[safe: 1] { 108 if end.allSatisfy({ c in c.isNumber }) { 109 return String(parts[0]) 110 } else { 111 return s 112 } 113 } 114 return s 115 } 116 117 var SupportDamus: some View { 118 ZStack(alignment: .topLeading) { 119 RoundedRectangle(cornerRadius: 20) 120 .fill(DamusGradient.gradient.opacity(0.5)) 121 122 VStack(alignment: .leading, spacing: 20) { 123 HStack { 124 Image("logo-nobg") 125 .resizable() 126 .frame(width: 50, height: 50) 127 Text("Support Damus", comment: "Text calling for the user to support Damus through zaps") 128 .font(.title.bold()) 129 .foregroundColor(.white) 130 } 131 132 Text("Help build the future of decentralized communication on the web.", comment: "Text indicating the goal of developing Damus which the user can help with.") 133 .fixedSize(horizontal: false, vertical: true) 134 .foregroundColor(.white) 135 136 Text("An additional percentage of each zap will be sent to support Damus development", comment: "Text indicating that they can contribute zaps to support Damus development.") 137 .fixedSize(horizontal: false, vertical: true) 138 .foregroundColor(.white) 139 140 let binding = donation_binding() 141 142 HStack { 143 Slider(value: binding, 144 in: WalletView.min_donation...WalletView.max_donation, 145 label: { }) 146 Text("\(Int(binding.wrappedValue))%", comment: "Percentage of additional zap that should be sent to support Damus development.") 147 .font(.title.bold()) 148 .foregroundColor(.white) 149 .frame(width: 80) 150 } 151 152 HStack{ 153 Spacer() 154 155 VStack { 156 HStack { 157 Text("\(Image("zap.fill")) \(format_msats_abbrev(Int64(model.settings.default_zap_amount) * 1000))") 158 .font(.title) 159 .foregroundColor(percent == 0 ? .gray : .yellow) 160 .frame(width: 120) 161 } 162 163 Text("Zap", comment: "Text underneath the number of sats indicating that it's the amount used for zaps.") 164 .foregroundColor(.white) 165 } 166 Spacer() 167 168 Text(verbatim: "+") 169 .font(.title) 170 .foregroundColor(.white) 171 Spacer() 172 173 VStack { 174 HStack { 175 Text("\(Image("zap.fill")) \(tip_msats)") 176 .font(.title) 177 .foregroundColor(percent == 0 ? .gray : Color.yellow) 178 .frame(width: 120) 179 } 180 181 Text(verbatim: percent == 0 ? "🩶" : "💜") 182 .foregroundColor(.white) 183 } 184 Spacer() 185 } 186 187 EventProfile(damus_state: damus_state, pubkey: damus_state.pubkey, size: .small) 188 } 189 .padding(25) 190 } 191 .frame(height: 370) 192 } 193 194 var body: some View { 195 switch model.connect_state { 196 case .new: 197 ConnectWalletView(model: model, nav: damus_state.nav) 198 case .none: 199 ConnectWalletView(model: model, nav: damus_state.nav) 200 case .existing(let nwc): 201 MainWalletView(nwc: nwc) 202 .onAppear() { 203 model.initial_percent = settings.donation_percent 204 } 205 .onChange(of: settings.donation_percent) { p in 206 let profile_txn = damus_state.profiles.lookup(id: damus_state.pubkey) 207 guard let profile = profile_txn?.unsafeUnownedValue else { 208 return 209 } 210 211 let prof = Profile(name: profile.name, display_name: profile.display_name, about: profile.about, picture: profile.picture, banner: profile.banner, website: profile.website, lud06: profile.lud06, lud16: profile.lud16, nip05: profile.nip05, damus_donation: p, reactions: profile.reactions) 212 213 notify(.profile_updated(.manual(pubkey: self.damus_state.pubkey, profile: prof))) 214 } 215 .onDisappear { 216 let profile_txn = damus_state.profiles.lookup(id: damus_state.pubkey) 217 218 guard let keypair = damus_state.keypair.to_full(), 219 let profile = profile_txn?.unsafeUnownedValue, 220 model.initial_percent != profile.damus_donation 221 else { 222 return 223 } 224 225 let prof = Profile(name: profile.name, display_name: profile.display_name, about: profile.about, picture: profile.picture, banner: profile.banner, website: profile.website, lud06: profile.lud06, lud16: profile.lud16, nip05: profile.nip05, damus_donation: settings.donation_percent, reactions: profile.reactions) 226 227 guard let meta = make_metadata_event(keypair: keypair, metadata: prof) else { 228 return 229 } 230 damus_state.postbox.send(meta) 231 } 232 } 233 } 234 } 235 236 let test_wallet_connect_url = WalletConnectURL(pubkey: test_pubkey, relay: .init("wss://relay.damus.io")!, keypair: test_damus_state.keypair.to_full()!, lud16: "jb55@sendsats.com") 237 238 struct WalletView_Previews: PreviewProvider { 239 static let tds = test_damus_state 240 static var previews: some View { 241 WalletView(damus_state: tds, model: WalletModel(state: .existing(test_wallet_connect_url), settings: tds.settings)) 242 } 243 }