commit 35df9f7ab74e777e40d60f93ea2b7d526303ca7e
parent 605d88add16e60f517bf2296051e7617a7202c9f
Author: Daniel D’Aquino <daniel@daquino.me>
Date: Sat, 13 Jul 2024 00:31:44 +0000
Add support for OnlyZaps mode on the new chat thread
With this commit, long-presses on chat bubbles will now reveal a zap
sheet if they are on OnlyZaps mode and have zaps unlocked.
Users without OnlyZaps or with Zaps blocked will continue to see the
emoji reaction sheet
Closes: https://github.com/damus-io/damus/issues/2327
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Diffstat:
2 files changed, 112 insertions(+), 11 deletions(-)
diff --git a/damus/Views/Chat/ChatEventView.swift b/damus/Views/Chat/ChatEventView.swift
@@ -31,7 +31,7 @@ struct ChatEventView: View {
@State var long_press_bounce_work_item: DispatchWorkItem?
@State var popover_state: PopoverState = .closed {
didSet {
- let generator = UIImpactFeedbackGenerator(style: popover_state == .open_emoji_selector ? .heavy : .light)
+ let generator = UIImpactFeedbackGenerator(style: popover_state.some_sheet_open() ? .heavy : .light)
generator.impactOccurred()
}
}
@@ -43,6 +43,11 @@ struct ChatEventView: View {
enum PopoverState: String {
case closed
case open_emoji_selector
+ case open_zap_sheet
+
+ func some_sheet_open() -> Bool {
+ return self == .open_zap_sheet || self == .open_emoji_selector
+ }
}
var just_started: Bool {
@@ -90,9 +95,22 @@ struct ChatEventView: View {
var by_other_user: Bool {
return event.pubkey != damus_state.pubkey
}
-
+
var is_ours: Bool { return !by_other_user }
-
+
+ // MARK: Zapping properties
+
+ var lnurl: String? {
+ damus_state.profiles.lookup_with_timestamp(event.pubkey)?.map({ pr in
+ pr?.lnurl
+ }).value
+ }
+ var zap_target: ZapTarget {
+ ZapTarget.note(id: event.id, author: event.pubkey)
+ }
+
+ // MARK: Views
+
var event_bubble: some View {
ChatBubble(
direction: is_ours ? .right : .left,
@@ -170,6 +188,14 @@ struct ChatEventView: View {
EmojiPickerView(selectedEmoji: $selected_emoji, emojiProvider: damus_state.emoji_provider)
}.presentationDetents([.medium, .large])
}
+ .sheet(isPresented: Binding(get: { popover_state == .open_zap_sheet }, set: { new_state in
+ withAnimation(new_state == true ? .easeIn(duration: 0.5) : .easeOut(duration: 0.1)) {
+ popover_state = new_state == true ? .open_zap_sheet : .closed
+ }
+ })) {
+ ZapSheetViewIfPossible(damus_state: damus_state, target: zap_target, lnurl: lnurl)
+ .presentationDetents([.medium, .large])
+ }
.onChange(of: selected_emoji) { newSelectedEmoji in
if let newSelectedEmoji {
send_like(emoji: newSelectedEmoji.value)
@@ -177,8 +203,8 @@ struct ChatEventView: View {
}
}
}
- .scaleEffect(self.popover_state == .open_emoji_selector ? 1.08 : is_pressing ? 1.02 : 1)
- .shadow(color: (is_pressing || self.popover_state == .open_emoji_selector) ? .black.opacity(0.1) : .black.opacity(0.3), radius: (is_pressing || self.popover_state == .open_emoji_selector) ? 8 : 0, y: (is_pressing || self.popover_state == .open_emoji_selector) ? 15 : 0)
+ .scaleEffect(self.popover_state.some_sheet_open() ? 1.08 : is_pressing ? 1.02 : 1)
+ .shadow(color: (is_pressing || self.popover_state.some_sheet_open()) ? .black.opacity(0.1) : .black.opacity(0.3), radius: (is_pressing || self.popover_state.some_sheet_open()) ? 8 : 0, y: (is_pressing || self.popover_state.some_sheet_open()) ? 15 : 0)
.onLongPressGesture(minimumDuration: 0.5, maximumDistance: 10, perform: {
long_press_bounce_work_item?.cancel()
}, onPressingChanged: { is_pressing in
@@ -192,7 +218,8 @@ struct ChatEventView: View {
// Ensure the action is performed only if the condition is still valid
if self.is_pressing {
withAnimation(.bouncy(duration: 0.2, extraBounce: 0.35)) {
- popover_state = .open_emoji_selector
+ let should_show_zap_sheet = !damus_state.settings.nozaps && damus_state.settings.onlyzaps_mode
+ popover_state = should_show_zap_sheet ? .open_zap_sheet : .open_emoji_selector
}
}
}
diff --git a/damus/Views/Zaps/CustomizeZapView.swift b/damus/Views/Zaps/CustomizeZapView.swift
@@ -295,6 +295,64 @@ struct CustomizeZapView: View {
}
}
+struct ZapSheetViewIfPossible: View {
+ let damus_state: DamusState
+ let target: ZapTarget
+ let lnurl: String?
+ var zap_sheet: ZapSheet? {
+ guard let lnurl else { return nil }
+ return ZapSheet(target: target, lnurl: lnurl)
+ }
+
+ @Environment(\.dismiss) var dismiss
+ @Environment(\.colorScheme) var colorScheme
+
+ var body: some View {
+ if let zap_sheet {
+ CustomizeZapView(state: damus_state, target: zap_sheet.target, lnurl: zap_sheet.lnurl)
+ }
+ else {
+ zap_sheet_not_possible
+ }
+ }
+
+ var zap_sheet_not_possible: some View {
+ VStack(alignment: .center, spacing: 20) {
+ Image(systemName: "bolt.trianglebadge.exclamationmark.fill")
+ .resizable()
+ .scaledToFit()
+ .frame(width: 70)
+ Text("User not zappable", comment: "Headline indicating a user cannot be zapped")
+ .font(.headline)
+ Text("This user cannot be zapped because they have not configured zaps on their account yet. Time to orange-pill?", comment: "Comment explaining why a user cannot be zapped.")
+ .multilineTextAlignment(.center)
+ .opacity(0.6)
+ self.dm_button
+ }
+ .padding()
+ }
+
+ var dm_button: some View {
+ let dm_model = damus_state.dms.lookup_or_create(target.pubkey)
+ return VStack(alignment: .center, spacing: 10) {
+ Button(
+ action: {
+ damus_state.nav.push(route: Route.DMChat(dms: dm_model))
+ dismiss()
+ },
+ label: {
+ Image("messages")
+ .profile_button_style(scheme: colorScheme)
+ }
+ )
+ .buttonStyle(NeutralButtonShape.circle.style)
+ Text("Orange-pill", comment: "Button label that allows the user to start a direct message conversation with the user shown on-screen, to orange-pill them (i.e. help them to setup zaps)")
+ .foregroundStyle(.secondary)
+ .font(.caption)
+ }
+ }
+}
+
extension View {
func hideKeyboard() {
let resign = #selector(UIResponder.resignFirstResponder)
@@ -302,9 +360,25 @@ extension View {
}
}
-struct CustomizeZapView_Previews: PreviewProvider {
- static var previews: some View {
- CustomizeZapView(state: test_damus_state, target: ZapTarget.note(id: test_note.id, author: test_note.pubkey), lnurl: "")
- .frame(width: 400, height: 600)
- }
+
+
+fileprivate func test_zap_sheet() -> ZapSheet {
+ let zap_target = ZapTarget.note(id: test_note.id, author: test_note.pubkey)
+ let lnurl = ""
+ return ZapSheet(target: zap_target, lnurl: lnurl)
+}
+
+#Preview {
+ CustomizeZapView(state: test_damus_state, target: test_zap_sheet().target, lnurl: test_zap_sheet().lnurl)
+ .frame(width: 400, height: 600)
+}
+
+#Preview {
+ ZapSheetViewIfPossible(damus_state: test_damus_state, target: test_zap_sheet().target, lnurl: test_zap_sheet().lnurl)
+ .frame(width: 400, height: 600)
+}
+
+#Preview {
+ ZapSheetViewIfPossible(damus_state: test_damus_state, target: test_zap_sheet().target, lnurl: nil)
+ .frame(width: 400, height: 600)
}