Customized Zaps
Changelog-Added: Customized zaps
This commit is contained in:
@@ -129,26 +129,14 @@ struct ConfigView: View {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Section(NSLocalizedString("Default Zap Amount in sats", comment: "Section title for zap configuration")) {
|
||||
TextField(String("1000"), text: $default_zap_amount)
|
||||
.keyboardType(.numberPad)
|
||||
.onReceive(Just(default_zap_amount)) { newValue in
|
||||
let filtered = newValue.filter { Set("0123456789").contains($0) }
|
||||
|
||||
if filtered != newValue {
|
||||
default_zap_amount = filtered
|
||||
|
||||
if let parsed = handle_string_amount(new_value: newValue) {
|
||||
self.default_zap_amount = String(parsed)
|
||||
}
|
||||
|
||||
if filtered == "" {
|
||||
set_default_zap_amount(pubkey: state.pubkey, amount: 1000)
|
||||
return
|
||||
}
|
||||
|
||||
guard let amt = Int(filtered) else {
|
||||
return
|
||||
}
|
||||
set_default_zap_amount(pubkey: state.pubkey, amount: amt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,3 +334,18 @@ struct ConfigView_Previews: PreviewProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func handle_string_amount(new_value: String) -> Int? {
|
||||
let filtered = new_value.filter { Set("0123456789").contains($0) }
|
||||
|
||||
if filtered == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let amt = Int(filtered) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return amt
|
||||
}
|
||||
|
||||
@@ -18,17 +18,17 @@ struct TextEvent: View {
|
||||
HStack(alignment: .top) {
|
||||
let profile = damus.profiles.lookup(id: pubkey)
|
||||
|
||||
let is_anon = event_is_anonymous(ev: event)
|
||||
VStack {
|
||||
NavigationLink(destination: ProfileView(damus_state: damus, pubkey: pubkey)) {
|
||||
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, profiles: damus.profiles)
|
||||
}
|
||||
MaybeAnonPfpView(state: damus, is_anon: is_anon, pubkey: pubkey)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
HStack(alignment: .center) {
|
||||
EventProfileName(pubkey: pubkey, profile: profile, damus: damus, show_friend_confirmed: true, size: .normal)
|
||||
let pk = is_anon ? "anon" : pubkey
|
||||
EventProfileName(pubkey: pk, profile: profile, damus: damus, show_friend_confirmed: true, size: .normal)
|
||||
|
||||
Text(verbatim: "\(format_relative_time(event.created_at))")
|
||||
.foregroundColor(.gray)
|
||||
@@ -65,3 +65,18 @@ struct TextEvent_Previews: PreviewProvider {
|
||||
TextEvent(damus: test_damus_state(), event: test_event, pubkey: "pk", has_action_bar: true, booster_pubkey: nil)
|
||||
}
|
||||
}
|
||||
|
||||
func event_has_tag(ev: NostrEvent, tag: String) -> Bool {
|
||||
for t in ev.tags {
|
||||
if t.count >= 1 && t[0] == tag {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
func event_is_anonymous(ev: NostrEvent) -> Bool {
|
||||
return ev.known_kind == .zap_request && event_has_tag(ev: ev, tag: "anon")
|
||||
}
|
||||
|
||||
46
damus/Views/Profile/MaybeAnonPfpView.swift
Normal file
46
damus/Views/Profile/MaybeAnonPfpView.swift
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// MaybeAnonPfpView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-02-26.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct MaybeAnonPfpView: View {
|
||||
let state: DamusState
|
||||
let is_anon: Bool
|
||||
let pubkey: String
|
||||
|
||||
init(state: DamusState, event: NostrEvent, pubkey: String) {
|
||||
self.state = state
|
||||
self.is_anon = event_is_anonymous(ev: event)
|
||||
self.pubkey = pubkey
|
||||
}
|
||||
|
||||
init(state: DamusState, is_anon: Bool, pubkey: String) {
|
||||
self.state = state
|
||||
self.is_anon = is_anon
|
||||
self.pubkey = pubkey
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if is_anon {
|
||||
Image(systemName: "person.fill.questionmark")
|
||||
.font(.largeTitle)
|
||||
.frame(width: PFP_SIZE, height: PFP_SIZE)
|
||||
} else {
|
||||
NavigationLink(destination: ProfileView(damus_state: state, pubkey: pubkey)) {
|
||||
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, profiles: state.profiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MaybeAnonPfpView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MaybeAnonPfpView(state: test_damus_state(), is_anon: true, pubkey: "anon")
|
||||
}
|
||||
}
|
||||
215
damus/Views/Zaps/CustomizeZapView.swift
Normal file
215
damus/Views/Zaps/CustomizeZapView.swift
Normal file
@@ -0,0 +1,215 @@
|
||||
//
|
||||
// CustomizeZapView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-02-25.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
|
||||
enum ZapType {
|
||||
case pub
|
||||
case anon
|
||||
case non_zap
|
||||
}
|
||||
|
||||
struct ZapAmountItem: Identifiable, Hashable {
|
||||
let amount: Int
|
||||
let icon: String
|
||||
|
||||
var id: String {
|
||||
return icon
|
||||
}
|
||||
}
|
||||
|
||||
func get_default_zap_amount_item(_ pubkey: String) -> ZapAmountItem {
|
||||
let def = get_default_zap_amount(pubkey: pubkey) ?? 1000
|
||||
return ZapAmountItem(amount: def, icon: "🤙")
|
||||
}
|
||||
|
||||
func get_zap_amount_items(pubkey: String) -> [ZapAmountItem] {
|
||||
let def_item = get_default_zap_amount_item(pubkey)
|
||||
var entries = [
|
||||
ZapAmountItem(amount: 500, icon: "🙂"),
|
||||
ZapAmountItem(amount: 5000, icon: "💜"),
|
||||
ZapAmountItem(amount: 10_000, icon: "😍"),
|
||||
ZapAmountItem(amount: 20_000, icon: "🤩"),
|
||||
ZapAmountItem(amount: 50_000, icon: "🔥"),
|
||||
ZapAmountItem(amount: 100_000, icon: "🚀"),
|
||||
ZapAmountItem(amount: 1_000_000, icon: "🤯"),
|
||||
]
|
||||
entries.append(def_item)
|
||||
|
||||
entries.sort { $0.amount < $1.amount }
|
||||
return entries
|
||||
}
|
||||
|
||||
struct CustomizeZapView: View {
|
||||
let state: DamusState
|
||||
let event: NostrEvent
|
||||
let lnurl: String
|
||||
@State var comment: String
|
||||
@State var custom_amount: String
|
||||
@State var custom_amount_sats: Int?
|
||||
@State var selected_amount: ZapAmountItem
|
||||
@State var zap_type: ZapType
|
||||
@State var invoice: String
|
||||
@State var error: String?
|
||||
@State var showing_wallet_selector: Bool
|
||||
@State var zapping: Bool
|
||||
|
||||
let zap_amounts: [ZapAmountItem]
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
init(state: DamusState, event: NostrEvent, lnurl: String) {
|
||||
self._comment = State(initialValue: "")
|
||||
self.event = event
|
||||
self.zap_amounts = get_zap_amount_items(pubkey: state.pubkey)
|
||||
self._error = State(initialValue: nil)
|
||||
self._invoice = State(initialValue: "")
|
||||
self._showing_wallet_selector = State(initialValue: false)
|
||||
self._custom_amount = State(initialValue: "")
|
||||
self._zap_type = State(initialValue: .pub)
|
||||
let selected = get_default_zap_amount_item(state.pubkey)
|
||||
self._selected_amount = State(initialValue: selected)
|
||||
self._custom_amount_sats = State(initialValue: nil)
|
||||
self._zapping = State(initialValue: false)
|
||||
self.lnurl = lnurl
|
||||
self.state = state
|
||||
}
|
||||
|
||||
var ZapTypePicker: some View {
|
||||
Picker("Zap Type", selection: $zap_type) {
|
||||
Text("Public").tag(ZapType.pub)
|
||||
Text("Anonymous").tag(ZapType.anon)
|
||||
Text("Non-Zap").tag(ZapType.non_zap)
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
}
|
||||
|
||||
var AmountPicker: some View {
|
||||
Picker("Zap Amount", selection: $selected_amount) {
|
||||
ForEach(zap_amounts) { entry in
|
||||
let fmt = format_msats_abbrev(Int64(entry.amount) * 1000)
|
||||
HStack(alignment: .firstTextBaseline) {
|
||||
Text("\(entry.icon)")
|
||||
.frame(width: 30)
|
||||
Text("\(fmt)")
|
||||
.frame(width: 50)
|
||||
}
|
||||
.tag(entry)
|
||||
}
|
||||
}
|
||||
.pickerStyle(.wheel)
|
||||
}
|
||||
|
||||
func receive_zap(notif: Notification) {
|
||||
let zap_ev = notif.object as! ZappingEvent
|
||||
guard zap_ev.is_custom else {
|
||||
return
|
||||
}
|
||||
guard zap_ev.event.id == event.id else {
|
||||
return
|
||||
}
|
||||
|
||||
self.zapping = false
|
||||
|
||||
switch zap_ev.type {
|
||||
case .failed(let err):
|
||||
switch err {
|
||||
case .fetching_invoice:
|
||||
self.error = "Error fetching lightning invoice"
|
||||
case .bad_lnurl:
|
||||
self.error = "Invalid lightning address"
|
||||
}
|
||||
break
|
||||
case .got_zap_invoice(let inv):
|
||||
if should_show_wallet_selector(state.pubkey) {
|
||||
self.invoice = inv
|
||||
self.showing_wallet_selector = true
|
||||
} else {
|
||||
open_with_wallet(wallet: get_default_wallet(state.pubkey).model, invoice: inv)
|
||||
self.showing_wallet_selector = false
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
MainContent
|
||||
.sheet(isPresented: $showing_wallet_selector) {
|
||||
SelectWalletView(showingSelectWallet: $showing_wallet_selector, our_pubkey: state.pubkey, invoice: invoice)
|
||||
}
|
||||
.onReceive(handle_notify(.zapping)) { notif in
|
||||
receive_zap(notif: notif)
|
||||
}
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
|
||||
var MainContent: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Form {
|
||||
Section(content: {
|
||||
AmountPicker
|
||||
}, header: {
|
||||
Text("Zap Amount in sats")
|
||||
})
|
||||
|
||||
Section(content: {
|
||||
TextField("100000", text: $custom_amount)
|
||||
.keyboardType(.numberPad)
|
||||
.onReceive(Just(custom_amount)) { newValue in
|
||||
|
||||
if let parsed = handle_string_amount(new_value: newValue) {
|
||||
self.custom_amount = String(parsed)
|
||||
self.custom_amount_sats = parsed
|
||||
}
|
||||
}
|
||||
}, header: {
|
||||
Text("Custom Zap Amount")
|
||||
})
|
||||
.dismissKeyboardOnTap()
|
||||
|
||||
Section(content: {
|
||||
TextField("Awesome post!", text: $comment)
|
||||
}, header: {
|
||||
Text("Comment")
|
||||
})
|
||||
.dismissKeyboardOnTap()
|
||||
|
||||
Section(content: {
|
||||
ZapTypePicker
|
||||
}, header: {
|
||||
Text("Zap Type")
|
||||
})
|
||||
|
||||
if zapping {
|
||||
Text("Zapping...")
|
||||
} else {
|
||||
Button("Zap") {
|
||||
let amount = custom_amount_sats ?? selected_amount.amount
|
||||
send_zap(damus_state: state, event: event, lnurl: lnurl, is_custom: true, comment: comment, amount_sats: amount, zap_type: zap_type)
|
||||
self.zapping = true
|
||||
}
|
||||
.zIndex(16)
|
||||
}
|
||||
|
||||
if let error {
|
||||
Text(error)
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomizeZapView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
CustomizeZapView(state: test_damus_state(), event: test_event, lnurl: "")
|
||||
.frame(width: 400, height: 600)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user