nip19: generate nip19 data in ellipsis & share menus

In the ellipsis menu, when the user selects the 'Copy user public key',
an nprofile Bech32 entity will be generated which will include TLV data
with the user's public key and entire relay list, if available.
The nprofile will be added to the user's copy clipboard.

When the user presses the share menu on an event and clicks the 'copy
link' button, a damus link with the nevent for the note will be
generated and copied to the user's clipboard.

Closes: https://github.com/damus-io/damus/issues/1844
Changelog-Changed: Generate nprofile/nevent links in share menus
Lightning-url: LNURL1DP68GURN8GHJ7EM9W3SKCCNE9E3K7MF0D3H82UNVWQHKWUN9V4HXGCTHDC6RZVGR8SW3G
Signed-off-by: kernelkind <kernelkind@gmail.com>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
kernelkind
2024-01-18 14:59:31 -05:00
committed by William Casarin
parent 0650a62791
commit 5840b85213
5 changed files with 50 additions and 8 deletions

View File

@@ -20,6 +20,7 @@ class ProfileModel: ObservableObject, Equatable {
var seen_event: Set<NoteId> = Set() var seen_event: Set<NoteId> = Set()
var sub_id = UUID().description var sub_id = UUID().description
var prof_subid = UUID().description var prof_subid = UUID().description
var findRelay_subid = UUID().description
init(pubkey: Pubkey, damus: DamusState) { init(pubkey: Pubkey, damus: DamusState) {
self.pubkey = pubkey self.pubkey = pubkey
@@ -139,6 +140,27 @@ class ProfileModel: ObservableObject, Equatable {
} }
} }
} }
private func findRelaysHandler(relay_id: String, ev: NostrConnectionEvent) {
if case .nostr_event(let resp) = ev, case .event(_, let event) = resp, case .contacts = event.known_kind {
self.relays = decode_json_relays(event.content)
}
}
func subscribeToFindRelays() {
var profile_filter = NostrFilter(kinds: [.contacts])
profile_filter.authors = [pubkey]
damus.pool.subscribe(sub_id: findRelay_subid, filters: [profile_filter], handler: findRelaysHandler)
}
func unsubscribeFindRelays() {
damus.pool.unsubscribe(sub_id: findRelay_subid)
}
func getRelayStrings() -> [String] {
return relays?.keys.map {$0} ?? []
}
} }

View File

@@ -13,6 +13,7 @@ struct EventActionBar: View {
let damus_state: DamusState let damus_state: DamusState
let event: NostrEvent let event: NostrEvent
let generator = UIImpactFeedbackGenerator(style: .medium) let generator = UIImpactFeedbackGenerator(style: .medium)
let userProfile : ProfileModel
// just used for previews // just used for previews
@State var show_share_sheet: Bool = false @State var show_share_sheet: Bool = false
@@ -25,6 +26,7 @@ struct EventActionBar: View {
self.damus_state = damus_state self.damus_state = damus_state
self.event = event self.event = event
_bar = ObservedObject(wrappedValue: bar ?? make_actionbar_model(ev: event.id, damus: damus_state)) _bar = ObservedObject(wrappedValue: bar ?? make_actionbar_model(ev: event.id, damus: damus_state))
self.userProfile = ProfileModel(pubkey: event.pubkey, damus: damus_state)
} }
var lnurl: String? { var lnurl: String? {
@@ -100,11 +102,11 @@ struct EventActionBar: View {
} }
.sheet(isPresented: $show_share_action, onDismiss: { self.show_share_action = false }) { .sheet(isPresented: $show_share_action, onDismiss: { self.show_share_action = false }) {
if #available(iOS 16.0, *) { if #available(iOS 16.0, *) {
ShareAction(event: event, bookmarks: damus_state.bookmarks, show_share: $show_share_sheet) ShareAction(event: event, bookmarks: damus_state.bookmarks, show_share: $show_share_sheet, userProfile: userProfile)
.presentationDetents([.height(300)]) .presentationDetents([.height(300)])
.presentationDragIndicator(.visible) .presentationDragIndicator(.visible)
} else { } else {
ShareAction(event: event, bookmarks: damus_state.bookmarks, show_share: $show_share_sheet) ShareAction(event: event, bookmarks: damus_state.bookmarks, show_share: $show_share_sheet, userProfile: userProfile)
} }
} }
.sheet(isPresented: $show_share_sheet, onDismiss: { self.show_share_sheet = false }) { .sheet(isPresented: $show_share_sheet, onDismiss: { self.show_share_sheet = false }) {

View File

@@ -10,18 +10,20 @@ import SwiftUI
struct ShareAction: View { struct ShareAction: View {
let event: NostrEvent let event: NostrEvent
let bookmarks: BookmarksManager let bookmarks: BookmarksManager
let userProfile: ProfileModel
@State private var isBookmarked: Bool = false @State private var isBookmarked: Bool = false
@Binding var show_share: Bool @Binding var show_share: Bool
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
init(event: NostrEvent, bookmarks: BookmarksManager, show_share: Binding<Bool>) { init(event: NostrEvent, bookmarks: BookmarksManager, show_share: Binding<Bool>, userProfile: ProfileModel) {
let bookmarked = bookmarks.isBookmarked(event) let bookmarked = bookmarks.isBookmarked(event)
self._isBookmarked = State(initialValue: bookmarked) self._isBookmarked = State(initialValue: bookmarked)
self.bookmarks = bookmarks self.bookmarks = bookmarks
self.event = event self.event = event
self.userProfile = userProfile
self._show_share = show_share self._show_share = show_share
} }
@@ -38,7 +40,7 @@ struct ShareAction: View {
ShareActionButton(img: "link", text: NSLocalizedString("Copy Link", comment: "Button to copy link to note")) { ShareActionButton(img: "link", text: NSLocalizedString("Copy Link", comment: "Button to copy link to note")) {
dismiss() dismiss()
UIPasteboard.general.string = "https://damus.io/" + event.id.bech32 UIPasteboard.general.string = "https://damus.io/" + Bech32Object.encode(.nevent(NEvent(noteid: event.id, relays: userProfile.getRelayStrings())))
} }
let bookmarkImg = isBookmarked ? "bookmark.fill" : "bookmark" let bookmarkImg = isBookmarked ? "bookmark.fill" : "bookmark"
@@ -69,6 +71,12 @@ struct ShareAction: View {
} }
} }
} }
.onAppear() {
userProfile.subscribeToFindRelays()
}
.onDisappear() {
userProfile.unsubscribeFindRelays()
}
} }
} }

View File

@@ -22,7 +22,7 @@ struct DMChatView: View, KeyboardReadable {
LazyVStack(alignment: .leading) { LazyVStack(alignment: .leading) {
ForEach(Array(zip(dms.events, dms.events.indices)), id: \.0.id) { (ev, ind) in ForEach(Array(zip(dms.events, dms.events.indices)), id: \.0.id) { (ev, ind) in
DMView(event: dms.events[ind], damus_state: damus_state) DMView(event: dms.events[ind], damus_state: damus_state)
.contextMenu{MenuItems(event: ev, keypair: damus_state.keypair, target_pubkey: ev.pubkey, bookmarks: damus_state.bookmarks, muted_threads: damus_state.muted_threads, settings: damus_state.settings)} .contextMenu{MenuItems(event: ev, keypair: damus_state.keypair, target_pubkey: ev.pubkey, bookmarks: damus_state.bookmarks, muted_threads: damus_state.muted_threads, settings: damus_state.settings, profileModel: ProfileModel(pubkey: ev.pubkey, damus: damus_state))}
} }
EndBlock(height: 1) EndBlock(height: 1)
} }

View File

@@ -13,6 +13,7 @@ struct EventMenuContext: View {
let target_pubkey: Pubkey let target_pubkey: Pubkey
let bookmarks: BookmarksManager let bookmarks: BookmarksManager
let muted_threads: MutedThreadsManager let muted_threads: MutedThreadsManager
let profileModel : ProfileModel
@ObservedObject var settings: UserSettingsStore @ObservedObject var settings: UserSettingsStore
init(damus: DamusState, event: NostrEvent) { init(damus: DamusState, event: NostrEvent) {
@@ -22,6 +23,7 @@ struct EventMenuContext: View {
self.bookmarks = damus.bookmarks self.bookmarks = damus.bookmarks
self.muted_threads = damus.muted_threads self.muted_threads = damus.muted_threads
self._settings = ObservedObject(wrappedValue: damus.settings) self._settings = ObservedObject(wrappedValue: damus.settings)
self.profileModel = ProfileModel(pubkey: target_pubkey, damus: damus)
} }
var body: some View { var body: some View {
@@ -32,7 +34,7 @@ struct EventMenuContext: View {
// Add our Menu button inside an overlay modifier to avoid affecting the rest of the layout around us. // Add our Menu button inside an overlay modifier to avoid affecting the rest of the layout around us.
.overlay( .overlay(
Menu { Menu {
MenuItems(event: event, keypair: keypair, target_pubkey: target_pubkey, bookmarks: bookmarks, muted_threads: muted_threads, settings: settings) MenuItems(event: event, keypair: keypair, target_pubkey: target_pubkey, bookmarks: bookmarks, muted_threads: muted_threads, settings: settings, profileModel: profileModel)
} label: { } label: {
Color.clear Color.clear
} }
@@ -52,13 +54,14 @@ struct MenuItems: View {
let target_pubkey: Pubkey let target_pubkey: Pubkey
let bookmarks: BookmarksManager let bookmarks: BookmarksManager
let muted_threads: MutedThreadsManager let muted_threads: MutedThreadsManager
let profileModel: ProfileModel
@ObservedObject var settings: UserSettingsStore @ObservedObject var settings: UserSettingsStore
@State private var isBookmarked: Bool = false @State private var isBookmarked: Bool = false
@State private var isMutedThread: Bool = false @State private var isMutedThread: Bool = false
init(event: NostrEvent, keypair: Keypair, target_pubkey: Pubkey, bookmarks: BookmarksManager, muted_threads: MutedThreadsManager, settings: UserSettingsStore) { init(event: NostrEvent, keypair: Keypair, target_pubkey: Pubkey, bookmarks: BookmarksManager, muted_threads: MutedThreadsManager, settings: UserSettingsStore, profileModel: ProfileModel) {
let bookmarked = bookmarks.isBookmarked(event) let bookmarked = bookmarks.isBookmarked(event)
self._isBookmarked = State(initialValue: bookmarked) self._isBookmarked = State(initialValue: bookmarked)
@@ -71,6 +74,7 @@ struct MenuItems: View {
self.keypair = keypair self.keypair = keypair
self.target_pubkey = target_pubkey self.target_pubkey = target_pubkey
self.settings = settings self.settings = settings
self.profileModel = profileModel
} }
var body: some View { var body: some View {
@@ -82,7 +86,7 @@ struct MenuItems: View {
} }
Button { Button {
UIPasteboard.general.string = target_pubkey.npub UIPasteboard.general.string = Bech32Object.encode(.nprofile(NProfile(author: target_pubkey, relays: profileModel.getRelayStrings())))
} label: { } label: {
Label(NSLocalizedString("Copy user public key", comment: "Context menu option for copying the ID of the user who created the note."), image: "user") Label(NSLocalizedString("Copy user public key", comment: "Context menu option for copying the ID of the user who created the note."), image: "user")
} }
@@ -144,6 +148,12 @@ struct MenuItems: View {
} }
} }
} }
.onAppear() {
profileModel.subscribeToFindRelays()
}
.onDisappear() {
profileModel.unsubscribeFindRelays()
}
} }
} }