WalletView.swift (10579B)
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 ScrollView { 23 VStack(spacing: 35) { 24 if !damus_state.settings.nozaps { 25 SupportDamus 26 .padding(.vertical, 20) 27 } 28 29 VStack(spacing: 5) { 30 VStack(spacing: 10) { 31 Text("Wallet Relay", comment: "Label text indicating that below it is the information about the 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", comment: "Label text indicating that below it is the wallet address.") 51 .fontWeight(.semibold) 52 53 Divider() 54 55 Text(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("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 .padding(.bottom, 50) // Bottom padding while Scrolling 78 79 } 80 .navigationTitle(NSLocalizedString("Wallet", comment: "Navigation title for Wallet view")) 81 .navigationBarTitleDisplayMode(.inline) 82 .padding() 83 } 84 } 85 86 func donation_binding() -> Binding<Double> { 87 return Binding(get: { 88 return Double(model.settings.donation_percent) 89 }, set: { v in 90 model.settings.donation_percent = Int(v) 91 }) 92 } 93 94 static let min_donation: Double = 0.0 95 static let max_donation: Double = 100.0 96 97 var percent: Double { 98 Double(model.settings.donation_percent) / 100.0 99 } 100 101 var tip_msats: String { 102 let msats = Int64(percent * Double(model.settings.default_zap_amount * 1000)) 103 let s = format_msats_abbrev(msats) 104 // TODO: fix formatting and remove this hack 105 let parts = s.split(separator: ".") 106 if parts.count == 1 { 107 return s 108 } 109 if let end = parts[safe: 1] { 110 if end.allSatisfy({ c in c.isNumber }) { 111 return String(parts[0]) 112 } else { 113 return s 114 } 115 } 116 return s 117 } 118 119 var SupportDamus: some View { 120 ZStack(alignment: .topLeading) { 121 RoundedRectangle(cornerRadius: 20) 122 .fill(DamusGradient.gradient.opacity(0.5)) 123 124 VStack(alignment: .leading, spacing: 20) { 125 HStack { 126 Image("logo-nobg") 127 .resizable() 128 .frame(width: 50, height: 50) 129 Text("Support Damus", comment: "Text calling for the user to support Damus through zaps") 130 .font(.title.bold()) 131 .foregroundColor(.white) 132 } 133 134 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.") 135 .fixedSize(horizontal: false, vertical: true) 136 .foregroundColor(.white) 137 138 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.") 139 .fixedSize(horizontal: false, vertical: true) 140 .foregroundColor(.white) 141 142 let binding = donation_binding() 143 144 HStack { 145 Slider(value: binding, 146 in: WalletView.min_donation...WalletView.max_donation, 147 label: { }) 148 Text("\(Int(binding.wrappedValue))%", comment: "Percentage of additional zap that should be sent to support Damus development.") 149 .font(.title.bold()) 150 .foregroundColor(.white) 151 .frame(width: 80) 152 } 153 154 HStack{ 155 Spacer() 156 157 VStack { 158 HStack { 159 Text("\(Image("zap.fill")) \(format_msats_abbrev(Int64(model.settings.default_zap_amount) * 1000))") 160 .font(.title) 161 .foregroundColor(percent == 0 ? .gray : .yellow) 162 .frame(width: 120) 163 } 164 165 Text("Zap", comment: "Text underneath the number of sats indicating that it's the amount used for zaps.") 166 .foregroundColor(.white) 167 } 168 Spacer() 169 170 Text(verbatim: "+") 171 .font(.title) 172 .foregroundColor(.white) 173 Spacer() 174 175 VStack { 176 HStack { 177 Text("\(Image("zap.fill")) \(tip_msats)") 178 .font(.title) 179 .foregroundColor(percent == 0 ? .gray : Color.yellow) 180 .frame(width: 120) 181 } 182 183 Text(verbatim: percent == 0 ? "🩶" : "💜") 184 .foregroundColor(.white) 185 } 186 Spacer() 187 } 188 189 EventProfile(damus_state: damus_state, pubkey: damus_state.pubkey, size: .small) 190 } 191 .padding(25) 192 } 193 .frame(height: 370) 194 } 195 196 var body: some View { 197 switch model.connect_state { 198 case .new: 199 ConnectWalletView(model: model, nav: damus_state.nav) 200 case .none: 201 ConnectWalletView(model: model, nav: damus_state.nav) 202 case .existing(let nwc): 203 MainWalletView(nwc: nwc) 204 .onAppear() { 205 model.initial_percent = settings.donation_percent 206 } 207 .onChange(of: settings.donation_percent) { p in 208 let profile_txn = damus_state.profiles.lookup(id: damus_state.pubkey) 209 guard let profile = profile_txn?.unsafeUnownedValue else { 210 return 211 } 212 213 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) 214 215 notify(.profile_updated(.manual(pubkey: self.damus_state.pubkey, profile: prof))) 216 } 217 .onDisappear { 218 let profile_txn = damus_state.profiles.lookup(id: damus_state.pubkey) 219 220 guard let keypair = damus_state.keypair.to_full(), 221 let profile = profile_txn?.unsafeUnownedValue, 222 model.initial_percent != profile.damus_donation 223 else { 224 return 225 } 226 227 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) 228 229 guard let meta = make_metadata_event(keypair: keypair, metadata: prof) else { 230 return 231 } 232 damus_state.postbox.send(meta) 233 } 234 } 235 } 236 } 237 238 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") 239 240 struct WalletView_Previews: PreviewProvider { 241 static let tds = test_damus_state 242 static var previews: some View { 243 WalletView(damus_state: tds, model: WalletModel(state: .existing(test_wallet_connect_url), settings: tds.settings)) 244 } 245 }