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>
This commit is contained in:
committed by
William Casarin
parent
605d88add1
commit
35df9f7ab7
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user