damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit 88db9de4ea6d94fca94ee04e03c16e404dd190cd
parent d667a9d8f7eed846ee789634d0fff0cb4a6b63cf
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 19 Apr 2023 11:08:59 -0700

Fix reposts on macos

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 12++++++++++++
Mdamus/ContentView.swift | 48+++---------------------------------------------
Mdamus/Models/ActionBarModel.swift | 12++++++++++++
Mdamus/Util/Notifications.swift | 6+++---
Adamus/Views/ActionBar/BigButton.swift | 41+++++++++++++++++++++++++++++++++++++++++
Mdamus/Views/ActionBar/EventActionBar.swift | 63+++++++++++++++++++++++----------------------------------------
Adamus/Views/ActionBar/RepostAction.swift | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdamus/Views/ActionBar/ShareAction.swift | 63++++++++++++++-------------------------------------------------
Adamus/Views/ActionBar/ShareActionButton.swift | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 232 insertions(+), 137 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -199,6 +199,9 @@ 4CE0E2AF29A2E82100DB4CA2 /* EventHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE0E2AE29A2E82100DB4CA2 /* EventHolder.swift */; }; 4CE0E2B229A3DF6900DB4CA2 /* LoadMoreButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE0E2B129A3DF6900DB4CA2 /* LoadMoreButton.swift */; }; 4CE0E2B629A3ED5500DB4CA2 /* InnerTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE0E2B529A3ED5500DB4CA2 /* InnerTimelineView.swift */; }; + 4CE1399029F0661A00AC6A0B /* RepostAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE1398F29F0661A00AC6A0B /* RepostAction.swift */; }; + 4CE1399229F0666100AC6A0B /* ShareActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE1399129F0666100AC6A0B /* ShareActionButton.swift */; }; + 4CE1399429F0669900AC6A0B /* BigButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE1399329F0669900AC6A0B /* BigButton.swift */; }; 4CE4F0F229D4FCFA005914DB /* DebouncedOnChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE4F0F129D4FCFA005914DB /* DebouncedOnChange.swift */; }; 4CE4F0F429D779B5005914DB /* PostBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE4F0F329D779B5005914DB /* PostBox.swift */; }; 4CE4F0F829DB7399005914DB /* ThiccDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE4F0F729DB7399005914DB /* ThiccDivider.swift */; }; @@ -609,6 +612,9 @@ 4CE0E2AE29A2E82100DB4CA2 /* EventHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventHolder.swift; sourceTree = "<group>"; }; 4CE0E2B129A3DF6900DB4CA2 /* LoadMoreButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadMoreButton.swift; sourceTree = "<group>"; }; 4CE0E2B529A3ED5500DB4CA2 /* InnerTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InnerTimelineView.swift; sourceTree = "<group>"; }; + 4CE1398F29F0661A00AC6A0B /* RepostAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostAction.swift; sourceTree = "<group>"; }; + 4CE1399129F0666100AC6A0B /* ShareActionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareActionButton.swift; sourceTree = "<group>"; }; + 4CE1399329F0669900AC6A0B /* BigButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BigButton.swift; sourceTree = "<group>"; }; 4CE4F0F129D4FCFA005914DB /* DebouncedOnChange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebouncedOnChange.swift; sourceTree = "<group>"; }; 4CE4F0F329D779B5005914DB /* PostBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostBox.swift; sourceTree = "<group>"; }; 4CE4F0F729DB7399005914DB /* ThiccDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThiccDivider.swift; sourceTree = "<group>"; }; @@ -1047,6 +1053,9 @@ 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */, 4CB88388296AF99A00DC99E7 /* EventDetailBar.swift */, 5CF72FC129B9142F00124A13 /* ShareAction.swift */, + 4CE1398F29F0661A00AC6A0B /* RepostAction.swift */, + 4CE1399129F0666100AC6A0B /* ShareActionButton.swift */, + 4CE1399329F0669900AC6A0B /* BigButton.swift */, ); path = ActionBar; sourceTree = "<group>"; @@ -1642,6 +1651,8 @@ 4C9F18E229AA9B6C008C55EC /* CustomizeZapView.swift in Sources */, 4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */, 4C3EA64C28FF59AC00C48A62 /* bech32_util.c in Sources */, + 4CE1399029F0661A00AC6A0B /* RepostAction.swift in Sources */, + 4CE1399229F0666100AC6A0B /* ShareActionButton.swift in Sources */, 4C42812C298C848200DBF26F /* TranslateView.swift in Sources */, 4C363A9C282838B9006E126D /* EventRef.swift in Sources */, 3AA24802297E3DC20090C62D /* RepostView.swift in Sources */, @@ -1666,6 +1677,7 @@ 4C30AC8029A6A53F00E2BD5A /* ProfilePicturesView.swift in Sources */, 4C8EC52529D1FA6C0085D9A8 /* DamusColors.swift in Sources */, 4C5C7E6A284EDE2E00A22DF5 /* SearchResultsView.swift in Sources */, + 4CE1399429F0669900AC6A0B /* BigButton.swift in Sources */, 7C60CAEF298471A1009C80D6 /* CoreSVG.swift in Sources */, 6439E014296790CF0020672B /* ProfilePicImageView.swift in Sources */, 4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */, diff --git a/damus/ContentView.swift b/damus/ContentView.swift @@ -77,11 +77,9 @@ struct ContentView: View { @State var confirm_mute: Bool = false @State var user_muted_confirm: Bool = false @State var confirm_overwrite_mutelist: Bool = false - @State var current_boost: NostrEvent? = nil @State var filter_state : FilterState = .posts_and_replies @State private var isSideBarOpened = false @StateObject var home: HomeModel = HomeModel() - @State var shouldShowBoostAlert = false // connect retry timer let timer = Timer.publish(every: 4, on: .main, in: .common).autoconnect() @@ -349,19 +347,9 @@ struct ContentView: View { } } - .onReceive(handle_notify(.boost)) { notif in - guard let ev = notif.object as? NostrEvent else { - return - } - - current_boost = ev - shouldShowBoostAlert = true - } - .onReceive(handle_notify(.reply)) { notif in - let ev = notif.object as! NostrEvent - self.active_sheet = .post(.replying_to(ev)) - } - .onReceive(handle_notify(.like)) { like in + .onReceive(handle_notify(.compose)) { notif in + let action = notif.object as! PostAction + self.active_sheet = .post(action) } .onReceive(handle_notify(.deleted_account)) { notif in self.is_deleted_account = true @@ -605,36 +593,6 @@ struct ContentView: View { Text("Could not find user to mute...", comment: "Alert message to indicate that the muted user could not be found.") } }) - .confirmationDialog("Repost", isPresented: $shouldShowBoostAlert) { - Button(NSLocalizedString("Repost", comment: "Title of alert for confirming to repost a post.")) { - guard let current_boost else { - return - } - - guard let privkey = self.damus_state?.keypair.privkey else { - return - } - - guard let damus_state else { - return - } - - let boost = make_boost_event(pubkey: damus_state.keypair.pubkey, privkey: privkey, boosted: current_boost) - damus_state.postbox.send(boost) - } - - Button(NSLocalizedString("Quote", comment: "Title of alert for confirming to make a quoted post.")) { - guard let current_boost else { - return - } - self.active_sheet = .post(.quoting(current_boost)) - } - } - .onChange(of: shouldShowBoostAlert) { v in - if v == false { - self.current_boost = nil - } - } } func switch_timeline(_ timeline: Timeline) { diff --git a/damus/Models/ActionBarModel.swift b/damus/Models/ActionBarModel.swift @@ -23,6 +23,18 @@ class ActionBarModel: ObservableObject { return ActionBarModel(likes: 0, boosts: 0, zaps: 0, zap_total: 0, replies: 0, our_like: nil, our_boost: nil, our_zap: nil, our_reply: nil) } + init() { + self.our_like = nil + self.our_boost = nil + self.our_reply = nil + self.our_zap = nil + self.likes = 0 + self.boosts = 0 + self.zaps = 0 + self.zap_total = 0 + self.replies = 0 + } + init(likes: Int, boosts: Int, zaps: Int, zap_total: Int64, replies: Int, our_like: NostrEvent?, our_boost: NostrEvent?, our_zap: Zap?, our_reply: NostrEvent?) { self.likes = likes self.boosts = boosts diff --git a/damus/Util/Notifications.swift b/damus/Util/Notifications.swift @@ -20,9 +20,6 @@ extension Notification.Name { static var select_quote: Notification.Name { return Notification.Name("select quote") } - static var reply: Notification.Name { - return Notification.Name("reply") - } static var profile_updated: Notification.Name { return Notification.Name("profile_updated") } @@ -56,6 +53,9 @@ extension Notification.Name { static var post: Notification.Name { return Notification.Name("send post") } + static var compose: Notification.Name { + return Notification.Name("compose") + } static var boost: Notification.Name { return Notification.Name("boost") } diff --git a/damus/Views/ActionBar/BigButton.swift b/damus/Views/ActionBar/BigButton.swift @@ -0,0 +1,41 @@ +// +// BigButton.swift +// damus +// +// Created by William Casarin on 2023-04-19. +// + +import SwiftUI + +struct BigButton: View { + let text: String + let action: () -> () + + @Environment(\.colorScheme) var colorScheme + + init(_ text: String, action: @escaping () -> ()) { + self.text = text + self.action = action + } + + var body: some View { + Button(action: { + action() + }) { + Text(text) + .frame(minWidth: 300, maxWidth: .infinity, minHeight: 50, maxHeight: 50, alignment: .center) + .foregroundColor(colorScheme == .light ? DamusColors.black : DamusColors.white) + .overlay { + RoundedRectangle(cornerRadius: 24) + .stroke(colorScheme == .light ? DamusColors.mediumGrey : DamusColors.white, lineWidth: 1) + } + .padding(EdgeInsets(top: 10, leading: 50, bottom: 25, trailing: 50)) + } + } +} + +struct BigButton_Previews: PreviewProvider { + static var previews: some View { + BigButton("Cancel", action: {}) + } +} diff --git a/damus/Views/ActionBar/EventActionBar.swift b/damus/Views/ActionBar/EventActionBar.swift @@ -8,46 +8,26 @@ import SwiftUI import UIKit -enum ActionBarSheet: Identifiable { - case reply - - var id: String { - switch self { - case .reply: return "reply" - } - } -} struct EventActionBar: View { let damus_state: DamusState let event: NostrEvent - let test_lnurl: String? let generator = UIImpactFeedbackGenerator(style: .medium) // just used for previews - @State var sheet: ActionBarSheet? = nil @State var show_share_sheet: Bool = false @State var show_share_action: Bool = false - - @ObservedObject var bar: ActionBarModel - @ObservedObject var settings: UserSettingsStore + @State var show_repost_action: Bool = false + @State var bar: ActionBarModel = ActionBarModel() @Environment(\.colorScheme) var colorScheme - init(damus_state: DamusState, event: NostrEvent, bar: ActionBarModel? = nil, test_lnurl: String? = nil) { - self.damus_state = damus_state - self.event = event - self.test_lnurl = test_lnurl - _bar = ObservedObject(wrappedValue: bar ?? make_actionbar_model(ev: event.id, damus: damus_state)) - _settings = ObservedObject(wrappedValue: damus_state.settings) - } - var lnurl: String? { - test_lnurl ?? damus_state.profiles.lookup(id: event.pubkey)?.lnurl + damus_state.profiles.lookup(id: event.pubkey)?.lnurl } var show_like: Bool { - if settings.onlyzaps_mode { + if damus_state.settings.onlyzaps_mode { return false } @@ -59,7 +39,7 @@ struct EventActionBar: View { if damus_state.keypair.privkey != nil { HStack(spacing: 4) { EventActionButton(img: "bubble.left", col: bar.replied ? DamusColors.purple : Color.gray) { - notify(.reply, event) + notify(.compose, PostAction.replying_to(event)) } .accessibilityLabel(NSLocalizedString("Reply", comment: "Accessibility label for reply button")) Text(verbatim: "\(bar.replies > 0 ? "\(bar.replies)" : "")") @@ -74,7 +54,7 @@ struct EventActionBar: View { if bar.boosted { notify(.delete, bar.our_boost) } else { - send_boost() + self.show_repost_action = true } } .accessibilityLabel(NSLocalizedString("Boosts", comment: "Accessibility label for boosts button")) @@ -112,26 +92,35 @@ struct EventActionBar: View { } .accessibilityLabel(NSLocalizedString("Share", comment: "Button to share a post")) } - .sheet(isPresented: $show_share_action) { + .onAppear { + self.bar.update(damus: damus_state, evid: self.event.id) + } + .sheet(isPresented: $show_share_action, onDismiss: { self.show_share_action = false }) { if #available(iOS 16.0, *) { - ShareAction(event: event, bookmarks: damus_state.bookmarks, show_share_sheet: $show_share_sheet, show_share_action: $show_share_action) + ShareAction(event: event, bookmarks: damus_state.bookmarks, show_share: $show_share_sheet) .presentationDetents([.height(300)]) .presentationDragIndicator(.visible) } else { - if let note_id = bech32_note_id(event.id) { - if let url = URL(string: "https://damus.io/" + note_id) { - ShareSheet(activityItems: [url]) - } - } + ShareAction(event: event, bookmarks: damus_state.bookmarks, show_share: $show_share_sheet) } } - .sheet(isPresented: $show_share_sheet) { + .sheet(isPresented: $show_share_sheet, onDismiss: { self.show_share_sheet = false }) { if let note_id = bech32_note_id(event.id) { if let url = URL(string: "https://damus.io/" + note_id) { ShareSheet(activityItems: [url]) } } } + .sheet(isPresented: $show_repost_action, onDismiss: { self.show_repost_action = false }) { + + if #available(iOS 16.0, *) { + RepostAction(damus_state: self.damus_state, event: event) + .presentationDetents([.height(300)]) + .presentationDragIndicator(.visible) + } else { + RepostAction(damus_state: self.damus_state, event: event) + } + } .onReceive(handle_notify(.update_stats)) { n in let target = n.object as! String guard target == self.event.id else { return } @@ -149,10 +138,6 @@ struct EventActionBar: View { } } - func send_boost() { - notify(.boost, self.event) - } - func send_like() { guard let privkey = damus_state.keypair.privkey else { return @@ -254,8 +239,6 @@ struct EventActionBar_Previews: PreviewProvider { EventActionBar(damus_state: ds, event: ev, bar: extra_max_bar) EventActionBar(damus_state: ds, event: ev, bar: mega_max_bar) - - EventActionBar(damus_state: ds, event: ev, bar: zapbar, test_lnurl: "lnurl") } .padding(20) } diff --git a/damus/Views/ActionBar/RepostAction.swift b/damus/Views/ActionBar/RepostAction.swift @@ -0,0 +1,62 @@ +// +// RepostAction.swift +// damus +// +// Created by William Casarin on 2023-04-19. +// + +import SwiftUI + +struct RepostAction: View { + let damus_state: DamusState + let event: NostrEvent + + @Environment(\.dismiss) var dismiss + + var body: some View { + VStack { + Text("Repost Note", comment: "Title text to indicate that the buttons below are meant to be used to repost a note to others.") + .padding() + .font(.system(size: 17, weight: .bold)) + + Spacer() + + HStack(alignment: .top, spacing: 100) { + + ShareActionButton(img: "arrow.2.squarepath", text: NSLocalizedString("Repost", comment: "Button to repost a note")) { + dismiss() + + guard let privkey = self.damus_state.keypair.privkey else { + return + } + + let boost = make_boost_event(pubkey: damus_state.keypair.pubkey, privkey: privkey, boosted: self.event) + + damus_state.postbox.send(boost) + } + + ShareActionButton(img: "quote.opening", text: NSLocalizedString("Quote", comment: "Button to compose a quoted note")) { + dismiss() + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + notify(.compose, PostAction.quoting(self.event)) + } + } + + } + + Spacer() + + HStack { + BigButton(NSLocalizedString("Cancel", comment: "Button to cancel a repost.")) { + dismiss() + } + } + } + } +} + +struct RepostAction_Previews: PreviewProvider { + static var previews: some View { + RepostAction(damus_state: test_damus_state(), event: test_event) + } +} diff --git a/damus/Views/ActionBar/ShareAction.swift b/damus/Views/ActionBar/ShareAction.swift @@ -12,25 +12,22 @@ struct ShareAction: View { let bookmarks: BookmarksManager @State private var isBookmarked: Bool = false - @Binding var show_share_sheet: Bool - @Binding var show_share_action: Bool + @Binding var show_share: Bool @Environment(\.colorScheme) var colorScheme + @Environment(\.dismiss) var dismiss - init(event: NostrEvent, bookmarks: BookmarksManager, show_share_sheet: Binding<Bool>, show_share_action: Binding<Bool>) { + init(event: NostrEvent, bookmarks: BookmarksManager, show_share: Binding<Bool>) { let bookmarked = bookmarks.isBookmarked(event) self._isBookmarked = State(initialValue: bookmarked) self.bookmarks = bookmarks self.event = event - self._show_share_sheet = show_share_sheet - self._show_share_action = show_share_action + self._show_share = show_share } var body: some View { - let col = colorScheme == .light ? DamusColors.mediumGrey : DamusColors.white - VStack { Text("Share Note", comment: "Title text to indicate that the buttons below are meant to be used to share a note with others.") .padding() @@ -40,28 +37,27 @@ struct ShareAction: View { HStack(alignment: .top, spacing: 25) { - ShareActionButton(img: "link", text: NSLocalizedString("Copy Link", comment: "Button to copy link to note"), col: col) { - show_share_action = false + ShareActionButton(img: "link", text: NSLocalizedString("Copy Link", comment: "Button to copy link to note")) { UIPasteboard.general.string = "https://damus.io/" + (bech32_note_id(event.id) ?? event.id) } let bookmarkImg = isBookmarked ? "bookmark.slash" : "bookmark" let bookmarkTxt = isBookmarked ? NSLocalizedString("Remove Bookmark", comment: "Button text to remove bookmark from a note.") : NSLocalizedString("Add Bookmark", comment: "Button text to add bookmark to a note.") - let boomarkCol = isBookmarked ? Color(.red) : col + let boomarkCol = isBookmarked ? Color(.red) : nil ShareActionButton(img: bookmarkImg, text: bookmarkTxt, col: boomarkCol) { - show_share_action = false + dismiss() self.bookmarks.updateBookmark(event) isBookmarked = self.bookmarks.isBookmarked(event) } - ShareActionButton(img: "globe", text: NSLocalizedString("Broadcast", comment: "Button to broadcast note to all your relays"), col: col) { - show_share_action = false + ShareActionButton(img: "globe", text: NSLocalizedString("Broadcast", comment: "Button to broadcast note to all your relays")) { + dismiss() NotificationCenter.default.post(name: .broadcast_event, object: event) } - ShareActionButton(img: "square.and.arrow.up", text: NSLocalizedString("Share Via...", comment: "Button to present iOS share sheet"), col: col) { - show_share_action = false - show_share_sheet = true + ShareActionButton(img: "square.and.arrow.up", text: NSLocalizedString("Share Via...", comment: "Button to present iOS share sheet")) { + show_share = true + dismiss() } } @@ -69,42 +65,11 @@ struct ShareAction: View { Spacer() HStack { - - Button(action: { - show_share_action = false - }) { - Text(NSLocalizedString("Cancel", comment: "Button to cancel a repost.")) - .frame(minWidth: 300, maxWidth: .infinity, minHeight: 50, maxHeight: 50, alignment: .center) - .foregroundColor(colorScheme == .light ? DamusColors.black : DamusColors.white) - .overlay { - RoundedRectangle(cornerRadius: 24) - .stroke(colorScheme == .light ? DamusColors.mediumGrey : DamusColors.white, lineWidth: 1) - } - .padding(EdgeInsets(top: 10, leading: 50, bottom: 25, trailing: 50)) + BigButton(NSLocalizedString("Cancel", comment: "Button to cancel a repost.")) { + dismiss() } } } } } -func ShareActionButton(img: String, text: String, col: Color, action: @escaping () -> ()) -> some View { - Button(action: action) { - VStack() { - Image(systemName: img) - .foregroundColor(col) - .font(.system(size: 23, weight: .bold)) - .overlay { - Circle() - .stroke(col, lineWidth: 1) - .frame(width: 55.0, height: 55.0) - } - .frame(height: 25) - Text(verbatim: text) - .foregroundColor(col) - .font(.footnote) - .multilineTextAlignment(.center) - .padding(.top) - } - } - -} diff --git a/damus/Views/ActionBar/ShareActionButton.swift b/damus/Views/ActionBar/ShareActionButton.swift @@ -0,0 +1,62 @@ +// +// ShareActionButton.swift +// damus +// +// Created by William Casarin on 2023-04-19. +// + +import SwiftUI + +struct ShareActionButton: View { + let img: String + let text: String + let color: Color? + let action: () -> () + + init(img: String, text: String, col: Color?, action: @escaping () -> ()) { + self.img = img + self.text = text + self.color = col + self.action = action + } + + init(img: String, text: String, action: @escaping () -> ()) { + self.img = img + self.text = text + self.action = action + self.color = nil + } + + var col: Color { + colorScheme == .light ? DamusColors.mediumGrey : DamusColors.white + } + + @Environment(\.colorScheme) var colorScheme + + var body: some View { + Button(action: action) { + VStack() { + Image(systemName: img) + .foregroundColor(col) + .font(.system(size: 23, weight: .bold)) + .overlay { + Circle() + .stroke(col, lineWidth: 1) + .frame(width: 55.0, height: 55.0) + } + .frame(height: 25) + Text(verbatim: text) + .foregroundColor(col) + .font(.footnote) + .multilineTextAlignment(.center) + .padding(.top) + } + } + } +} + +struct ShareActionButton_Previews: PreviewProvider { + static var previews: some View { + ShareActionButton(img: "figure.flexibility", text: "Stretch", action: {}) + } +}