mirror of
git://jb55.com/damus
synced 2024-09-05 21:03:51 +00:00
ndb: switch profile queries to use transactions
this should ensure no crashing occurs when querying profiles
This commit is contained in:
parent
622a436589
commit
fc9b9f2940
@ -45,8 +45,7 @@ struct NIP05Badge: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var username_matches_nip05: Bool {
|
var username_matches_nip05: Bool {
|
||||||
guard let profile = profiles.lookup(id: pubkey),
|
guard let name = profiles.lookup(id: pubkey).map({ p in p?.name }).value
|
||||||
let name = profile.name
|
|
||||||
else {
|
else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,12 @@ import SwiftUI
|
|||||||
struct Reposted: View {
|
struct Reposted: View {
|
||||||
let damus: DamusState
|
let damus: DamusState
|
||||||
let pubkey: Pubkey
|
let pubkey: Pubkey
|
||||||
let profile: Profile?
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment: .center) {
|
HStack(alignment: .center) {
|
||||||
Image("repost")
|
Image("repost")
|
||||||
.foregroundColor(Color.gray)
|
.foregroundColor(Color.gray)
|
||||||
ProfileName(pubkey: pubkey, profile: profile, damus: damus, show_nip5_domain: false)
|
ProfileName(pubkey: pubkey, damus: damus, show_nip5_domain: false)
|
||||||
.foregroundColor(Color.gray)
|
.foregroundColor(Color.gray)
|
||||||
Text("Reposted", comment: "Text indicating that the note was reposted (i.e. re-shared).")
|
Text("Reposted", comment: "Text indicating that the note was reposted (i.e. re-shared).")
|
||||||
.foregroundColor(Color.gray)
|
.foregroundColor(Color.gray)
|
||||||
@ -27,6 +26,6 @@ struct Reposted: View {
|
|||||||
struct Reposted_Previews: PreviewProvider {
|
struct Reposted_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let test_state = test_damus_state()
|
let test_state = test_damus_state()
|
||||||
Reposted(damus: test_state, pubkey: test_state.pubkey, profile: make_test_profile())
|
Reposted(damus: test_state, pubkey: test_state.pubkey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,7 @@ struct UserView: View {
|
|||||||
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
||||||
|
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
let profile = damus_state.profiles.lookup(id: pubkey)
|
ProfileName(pubkey: pubkey, damus: damus_state, show_nip5_domain: false)
|
||||||
ProfileName(pubkey: pubkey, profile: profile, damus: damus_state, show_nip5_domain: false)
|
|
||||||
if let about_text {
|
if let about_text {
|
||||||
about_text
|
about_text
|
||||||
.lineLimit(3)
|
.lineLimit(3)
|
||||||
|
@ -359,13 +359,18 @@ struct ContentView: View {
|
|||||||
// wallet with an associated
|
// wallet with an associated
|
||||||
guard let ds = self.damus_state,
|
guard let ds = self.damus_state,
|
||||||
let lud16 = nwc.lud16,
|
let lud16 = nwc.lud16,
|
||||||
let keypair = ds.keypair.to_full(),
|
let keypair = ds.keypair.to_full()
|
||||||
let profile = ds.profiles.lookup(id: ds.pubkey),
|
|
||||||
lud16 != profile.lud16
|
|
||||||
else {
|
else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let profile_txn = ds.profiles.lookup(id: ds.pubkey)
|
||||||
|
|
||||||
|
guard let profile = profile_txn.unsafeUnownedValue,
|
||||||
|
lud16 != profile.lud16 else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// clear zapper cache for old lud16
|
// clear zapper cache for old lud16
|
||||||
if profile.lud16 != nil {
|
if profile.lud16 != nil {
|
||||||
// TODO: should this be somewhere else, where we process profile events!?
|
// TODO: should this be somewhere else, where we process profile events!?
|
||||||
@ -378,15 +383,9 @@ struct ContentView: View {
|
|||||||
ds.postbox.send(ev)
|
ds.postbox.send(ev)
|
||||||
}
|
}
|
||||||
.onReceive(handle_notify(.broadcast)) { ev in
|
.onReceive(handle_notify(.broadcast)) { ev in
|
||||||
guard let ds = self.damus_state else {
|
guard let ds = self.damus_state else { return }
|
||||||
return
|
|
||||||
}
|
|
||||||
ds.postbox.send(ev)
|
ds.postbox.send(ev)
|
||||||
if let record = ds.profiles.lookup_with_timestamp(ev.pubkey),
|
|
||||||
let event = ds.events.lookup_by_key(record.noteKey)
|
|
||||||
{
|
|
||||||
ds.postbox.send(event)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.onReceive(handle_notify(.unfollow)) { target in
|
.onReceive(handle_notify(.unfollow)) { target in
|
||||||
guard let state = self.damus_state else { return }
|
guard let state = self.damus_state else { return }
|
||||||
@ -489,9 +488,11 @@ struct ContentView: View {
|
|||||||
.onReceive(handle_notify(.onlyzaps_mode)) { hide in
|
.onReceive(handle_notify(.onlyzaps_mode)) { hide in
|
||||||
home.filter_events()
|
home.filter_events()
|
||||||
|
|
||||||
guard let damus_state,
|
guard let ds = damus_state else { return }
|
||||||
let profile = damus_state.profiles.lookup(id: damus_state.pubkey),
|
let profile_txn = ds.profiles.lookup(id: ds.pubkey)
|
||||||
let keypair = damus_state.keypair.to_full()
|
|
||||||
|
guard let profile = profile_txn.unsafeUnownedValue,
|
||||||
|
let keypair = ds.keypair.to_full()
|
||||||
else {
|
else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -499,7 +500,7 @@ struct ContentView: View {
|
|||||||
let prof = Profile(name: profile.name, display_name: profile.display_name, about: profile.about, picture: profile.picture, banner: profile.banner, website: profile.website, lud06: profile.lud06, lud16: profile.lud16, nip05: profile.nip05, damus_donation: profile.damus_donation, reactions: !hide)
|
let prof = Profile(name: profile.name, display_name: profile.display_name, about: profile.about, picture: profile.picture, banner: profile.banner, website: profile.website, lud06: profile.lud06, lud16: profile.lud16, nip05: profile.nip05, damus_donation: profile.damus_donation, reactions: !hide)
|
||||||
|
|
||||||
guard let profile_ev = make_metadata_event(keypair: keypair, metadata: prof) else { return }
|
guard let profile_ev = make_metadata_event(keypair: keypair, metadata: prof) else { return }
|
||||||
damus_state.postbox.send(profile_ev)
|
ds.postbox.send(profile_ev)
|
||||||
}
|
}
|
||||||
.alert(NSLocalizedString("User muted", comment: "Alert message to indicate the user has been muted"), isPresented: $user_muted_confirm, actions: {
|
.alert(NSLocalizedString("User muted", comment: "Alert message to indicate the user has been muted"), isPresented: $user_muted_confirm, actions: {
|
||||||
Button(NSLocalizedString("Thanks!", comment: "Button to close out of alert that informs that the action to muted a user was successful.")) {
|
Button(NSLocalizedString("Thanks!", comment: "Button to close out of alert that informs that the action to muted a user was successful.")) {
|
||||||
@ -507,11 +508,12 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}, message: {
|
}, message: {
|
||||||
if let pubkey = self.muting {
|
if let pubkey = self.muting {
|
||||||
let profile = damus_state!.profiles.lookup(id: pubkey)
|
let name = damus_state!.profiles.lookup(id: pubkey).map { profile in
|
||||||
let name = Profile.displayName(profile: profile, pubkey: pubkey).username.truncate(maxLength: 50)
|
Profile.displayName(profile: profile, pubkey: pubkey).username.truncate(maxLength: 50)
|
||||||
|
}.value
|
||||||
Text("\(name) has been muted", comment: "Alert message that informs a user was muted.")
|
Text("\(name) has been muted", comment: "Alert message that informs a user was muted.")
|
||||||
} else {
|
} else {
|
||||||
Text("User has been muted", comment: "Alert message that informs a user was d.")
|
Text("User has been muted", comment: "Alert message that informs a user was muted.")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.alert(NSLocalizedString("Create new mutelist", comment: "Title of alert prompting the user to create a new mutelist."), isPresented: $confirm_overwrite_mutelist, actions: {
|
.alert(NSLocalizedString("Create new mutelist", comment: "Title of alert prompting the user to create a new mutelist."), isPresented: $confirm_overwrite_mutelist, actions: {
|
||||||
@ -567,8 +569,9 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}, message: {
|
}, message: {
|
||||||
if let pubkey = muting {
|
if let pubkey = muting {
|
||||||
let profile = damus_state?.profiles.lookup(id: pubkey)
|
let name = damus_state?.profiles.lookup(id: pubkey).map({ profile in
|
||||||
let name = Profile.displayName(profile: profile, pubkey: pubkey).username.truncate(maxLength: 50)
|
Profile.displayName(profile: profile, pubkey: pubkey).username.truncate(maxLength: 50)
|
||||||
|
}).value ?? "unknown"
|
||||||
Text("Mute \(name)?", comment: "Alert message prompt to ask if a user should be muted.")
|
Text("Mute \(name)?", comment: "Alert message prompt to ask if a user should be muted.")
|
||||||
} else {
|
} else {
|
||||||
Text("Could not find user to mute...", comment: "Alert message to indicate that the muted user could not be found.")
|
Text("Could not find user to mute...", comment: "Alert message to indicate that the muted user could not be found.")
|
||||||
@ -799,7 +802,7 @@ enum FindEventType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum FoundEvent {
|
enum FoundEvent {
|
||||||
case profile(Profile, NostrEvent)
|
case profile(Pubkey)
|
||||||
case invalid_profile(NostrEvent)
|
case invalid_profile(NostrEvent)
|
||||||
case event(NostrEvent)
|
case event(NostrEvent)
|
||||||
}
|
}
|
||||||
@ -816,11 +819,10 @@ func find_event_with_subid(state: DamusState, query query_: FindEvent, subid: St
|
|||||||
|
|
||||||
switch query {
|
switch query {
|
||||||
case .profile(let pubkey):
|
case .profile(let pubkey):
|
||||||
if let record = state.profiles.lookup_with_timestamp(pubkey),
|
if let record = state.ndb.lookup_profile(pubkey).unsafeUnownedValue,
|
||||||
let profile = record.profile,
|
record.profile != nil
|
||||||
let event = state.events.lookup_by_key(record.noteKey)
|
|
||||||
{
|
{
|
||||||
callback(.profile(profile, event))
|
callback(.profile(pubkey))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
filter = NostrFilter(kinds: [.metadata], limit: 1, authors: [pubkey])
|
filter = NostrFilter(kinds: [.metadata], limit: 1, authors: [pubkey])
|
||||||
@ -857,11 +859,11 @@ func find_event_with_subid(state: DamusState, query query_: FindEvent, subid: St
|
|||||||
switch query {
|
switch query {
|
||||||
case .profile:
|
case .profile:
|
||||||
if ev.known_kind == .metadata {
|
if ev.known_kind == .metadata {
|
||||||
guard let profile = state.profiles.lookup(id: ev.pubkey) else {
|
guard state.ndb.lookup_profile_key(ev.pubkey) != nil else {
|
||||||
callback(.invalid_profile(ev))
|
callback(.invalid_profile(ev))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
callback(.profile(profile, ev))
|
callback(.profile(ev.pubkey))
|
||||||
}
|
}
|
||||||
case .event:
|
case .event:
|
||||||
callback(.event(ev))
|
callback(.event(ev))
|
||||||
|
@ -1108,10 +1108,13 @@ func zap_notification_title(_ zap: Zap) -> String {
|
|||||||
func zap_notification_body(profiles: Profiles, zap: Zap, locale: Locale = Locale.current) -> String {
|
func zap_notification_body(profiles: Profiles, zap: Zap, locale: Locale = Locale.current) -> String {
|
||||||
let src = zap.request.ev
|
let src = zap.request.ev
|
||||||
let pk = zap.is_anon ? ANON_PUBKEY : src.pubkey
|
let pk = zap.is_anon ? ANON_PUBKEY : src.pubkey
|
||||||
let profile = profiles.lookup(id: pk)
|
|
||||||
|
let name = profiles.lookup(id: pk).map { profile in
|
||||||
|
Profile.displayName(profile: profile, pubkey: pk).displayName.truncate(maxLength: 50)
|
||||||
|
}.value
|
||||||
|
|
||||||
let sats = NSNumber(value: (Double(zap.invoice.amount) / 1000.0))
|
let sats = NSNumber(value: (Double(zap.invoice.amount) / 1000.0))
|
||||||
let formattedSats = format_msats_abbrev(zap.invoice.amount)
|
let formattedSats = format_msats_abbrev(zap.invoice.amount)
|
||||||
let name = Profile.displayName(profile: profile, pubkey: pk).displayName.truncate(maxLength: 50)
|
|
||||||
|
|
||||||
if src.content.isEmpty {
|
if src.content.isEmpty {
|
||||||
let format = localizedStringFormat(key: "zap_notification_no_message", locale: locale)
|
let format = localizedStringFormat(key: "zap_notification_no_message", locale: locale)
|
||||||
@ -1361,8 +1364,8 @@ func process_zap_event(damus_state: DamusState, ev: NostrEvent, completion: @esc
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let record = damus_state.profiles.lookup_with_timestamp(ptag),
|
guard let lnurl = damus_state.profiles.lookup_with_timestamp(ptag)
|
||||||
let lnurl = record.lnurl else {
|
.map({ pr in pr?.lnurl }).value else {
|
||||||
completion(.failed)
|
completion(.failed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,16 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
struct ProfileUpdate {
|
enum ProfileUpdate {
|
||||||
let pubkey: Pubkey
|
case manual(pubkey: Pubkey, profile: Profile)
|
||||||
let profile: Profile
|
case remote(pubkey: Pubkey)
|
||||||
|
|
||||||
|
var pubkey: Pubkey {
|
||||||
|
switch self {
|
||||||
|
case .manual(let pubkey, _):
|
||||||
|
return pubkey
|
||||||
|
case .remote(let pubkey):
|
||||||
|
return pubkey
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,15 +8,18 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
typealias Profile = NdbProfile
|
typealias Profile = NdbProfile
|
||||||
|
typealias ProfileKey = UInt64
|
||||||
//typealias ProfileRecord = NdbProfileRecord
|
//typealias ProfileRecord = NdbProfileRecord
|
||||||
|
|
||||||
class ProfileRecord {
|
class ProfileRecord {
|
||||||
let data: NdbProfileRecord
|
let data: NdbProfileRecord
|
||||||
|
|
||||||
init(data: NdbProfileRecord) {
|
init(data: NdbProfileRecord, key: ProfileKey) {
|
||||||
self.data = data
|
self.data = data
|
||||||
|
self.profileKey = key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let profileKey: ProfileKey
|
||||||
var profile: Profile? { return data.profile }
|
var profile: Profile? { return data.profile }
|
||||||
var receivedAt: UInt64 { data.receivedAt }
|
var receivedAt: UInt64 { data.receivedAt }
|
||||||
var noteKey: UInt64 { data.noteKey }
|
var noteKey: UInt64 { data.noteKey }
|
||||||
|
@ -84,7 +84,7 @@ enum NostrResponse {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
let new_note = note_data.assumingMemoryBound(to: ndb_note.self)
|
let new_note = note_data.assumingMemoryBound(to: ndb_note.self)
|
||||||
let note = NdbNote(note: new_note, owned_size: Int(len))
|
let note = NdbNote(note: new_note, owned_size: Int(len), key: nil)
|
||||||
|
|
||||||
guard let subid = sized_cstr(cstr: tce.subid, len: tce.subid_len) else {
|
guard let subid = sized_cstr(cstr: tce.subid, len: tce.subid_len) else {
|
||||||
free(data)
|
free(data)
|
||||||
|
@ -76,18 +76,25 @@ class Profiles {
|
|||||||
profile_data(pubkey).zapper
|
profile_data(pubkey).zapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookup_with_timestamp(_ pubkey: Pubkey) -> ProfileRecord? {
|
func lookup_with_timestamp(_ pubkey: Pubkey) -> NdbTxn<ProfileRecord?> {
|
||||||
return ndb.lookup_profile(pubkey)
|
return ndb.lookup_profile(pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookup(id: Pubkey) -> Profile? {
|
func lookup_by_key(key: ProfileKey) -> NdbTxn<ProfileRecord?> {
|
||||||
return ndb.lookup_profile(id)?.profile
|
return ndb.lookup_profile_by_key(key: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup(id: Pubkey) -> NdbTxn<Profile?> {
|
||||||
|
return ndb.lookup_profile(id).map({ pr in pr?.profile })
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup_key_by_pubkey(_ pubkey: Pubkey) -> ProfileKey? {
|
||||||
|
return ndb.lookup_profile_key(pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func has_fresh_profile(id: Pubkey) -> Bool {
|
func has_fresh_profile(id: Pubkey) -> Bool {
|
||||||
var profile: Profile?
|
guard let recv = lookup_with_timestamp(id).unsafeUnownedValue?.receivedAt else { return false }
|
||||||
guard let profile = lookup_with_timestamp(id) else { return false }
|
return Date.now.timeIntervalSince(Date(timeIntervalSince1970: Double(recv))) < Profiles.db_freshness_threshold
|
||||||
return Date.now.timeIntervalSince(Date(timeIntervalSince1970: Double(profile.receivedAt))) < Profiles.db_freshness_threshold
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ extension NotifyHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension Notifications {
|
extension Notifications {
|
||||||
static func profile_updated(pubkey: Pubkey, profile: Profile) -> Notifications<ProfileUpdatedNotify> {
|
static func profile_updated(_ update: ProfileUpdate) -> Notifications<ProfileUpdatedNotify> {
|
||||||
.init(.init(payload: ProfileUpdate(pubkey: pubkey, profile: profile)))
|
.init(.init(payload: update))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum DisplayName {
|
enum DisplayName: Equatable {
|
||||||
case both(username: String, displayName: String)
|
case both(username: String, displayName: String)
|
||||||
case one(String)
|
case one(String)
|
||||||
|
|
||||||
|
@ -137,6 +137,7 @@ class EventData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class EventCache {
|
class EventCache {
|
||||||
|
// TODO: remove me and change code to use ndb directly
|
||||||
private let ndb: Ndb
|
private let ndb: Ndb
|
||||||
private var events: [NoteId: NostrEvent] = [:]
|
private var events: [NoteId: NostrEvent] = [:]
|
||||||
private var replies = ReplyMap()
|
private var replies = ReplyMap()
|
||||||
@ -253,9 +254,11 @@ class EventCache {
|
|||||||
return ev
|
return ev
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func lookup_by_key(_ key: UInt64) -> NostrEvent? {
|
func lookup_by_key(_ key: UInt64) -> NostrEvent? {
|
||||||
ndb.lookup_note_by_key(key)
|
ndb.lookup_note_by_key(key)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func lookup(_ evid: NoteId) -> NostrEvent? {
|
func lookup(_ evid: NoteId) -> NostrEvent? {
|
||||||
return events[evid]
|
return events[evid]
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct NIP05 {
|
struct NIP05: Equatable {
|
||||||
let username: String
|
let username: String
|
||||||
let host: String
|
let host: String
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ struct EventActionBar: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var lnurl: String? {
|
var lnurl: String? {
|
||||||
damus_state.profiles.lookup_with_timestamp(event.pubkey)?.lnurl
|
damus_state.profiles.lookup_with_timestamp(event.pubkey).map({ pr in pr?.lnurl }).value
|
||||||
}
|
}
|
||||||
|
|
||||||
var show_like: Bool {
|
var show_like: Bool {
|
||||||
|
@ -82,7 +82,9 @@ struct BannerImageView: View {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if let bannerImage = updated.profile.banner {
|
let profile_txn = profiles.lookup(id: updated.pubkey)
|
||||||
|
let profile = profile_txn.unsafeUnownedValue
|
||||||
|
if let bannerImage = profile?.banner, bannerImage != self.banner {
|
||||||
self.banner = bannerImage
|
self.banner = bannerImage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,7 +92,7 @@ struct BannerImageView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func get_banner_url(banner: String?, pubkey: Pubkey, profiles: Profiles) -> URL? {
|
func get_banner_url(banner: String?, pubkey: Pubkey, profiles: Profiles) -> URL? {
|
||||||
let bannerUrlString = banner ?? profiles.lookup(id: pubkey)?.banner ?? ""
|
let bannerUrlString = banner ?? profiles.lookup(id: pubkey).map({ p in p?.banner }).value ?? ""
|
||||||
if let url = URL(string: bannerUrlString) {
|
if let url = URL(string: bannerUrlString) {
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
@ -60,12 +60,11 @@ struct DMChatView: View, KeyboardReadable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var Header: some View {
|
var Header: some View {
|
||||||
let profile = damus_state.profiles.lookup(id: pubkey)
|
|
||||||
return NavigationLink(value: Route.ProfileByKey(pubkey: pubkey)) {
|
return NavigationLink(value: Route.ProfileByKey(pubkey: pubkey)) {
|
||||||
HStack {
|
HStack {
|
||||||
ProfilePicView(pubkey: pubkey, size: 24, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
ProfilePicView(pubkey: pubkey, size: 24, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
||||||
|
|
||||||
ProfileName(pubkey: pubkey, profile: profile, damus: damus_state)
|
ProfileName(pubkey: pubkey, damus: damus_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
|
@ -22,9 +22,8 @@ struct EventTop: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ProfileName(is_anon: Bool) -> some View {
|
func ProfileName(is_anon: Bool) -> some View {
|
||||||
let profile = state.profiles.lookup(id: self.pubkey)
|
|
||||||
let pk = is_anon ? ANON_PUBKEY : self.pubkey
|
let pk = is_anon ? ANON_PUBKEY : self.pubkey
|
||||||
return EventProfileName(pubkey: pk, profile: profile, damus: state, size: .normal)
|
return EventProfileName(pubkey: pk, damus: state, size: .normal)
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@ -11,10 +11,10 @@ import SwiftUI
|
|||||||
struct ReplyDescription: View {
|
struct ReplyDescription: View {
|
||||||
let event: NostrEvent
|
let event: NostrEvent
|
||||||
let replying_to: NostrEvent?
|
let replying_to: NostrEvent?
|
||||||
let profiles: Profiles
|
let ndb: Ndb
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(verbatim: "\(reply_desc(profiles: profiles, event: event, replying_to: replying_to))")
|
Text(verbatim: "\(reply_desc(ndb: ndb, event: event, replying_to: replying_to))")
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
@ -23,11 +23,11 @@ struct ReplyDescription: View {
|
|||||||
|
|
||||||
struct ReplyDescription_Previews: PreviewProvider {
|
struct ReplyDescription_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ReplyDescription(event: test_note, replying_to: test_note, profiles: test_damus_state().profiles)
|
ReplyDescription(event: test_note, replying_to: test_note, ndb: test_damus_state().ndb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func reply_desc(profiles: Profiles, event: NostrEvent, replying_to: NostrEvent?, locale: Locale = Locale.current) -> String {
|
func reply_desc(ndb: Ndb, event: NostrEvent, replying_to: NostrEvent?, locale: Locale = Locale.current) -> String {
|
||||||
let desc = make_reply_description(event, replying_to: replying_to)
|
let desc = make_reply_description(event, replying_to: replying_to)
|
||||||
let pubkeys = desc.pubkeys
|
let pubkeys = desc.pubkeys
|
||||||
let n = desc.others
|
let n = desc.others
|
||||||
@ -38,9 +38,12 @@ func reply_desc(profiles: Profiles, event: NostrEvent, replying_to: NostrEvent?,
|
|||||||
return NSLocalizedString("Replying to self", bundle: bundle, comment: "Label to indicate that the user is replying to themself.")
|
return NSLocalizedString("Replying to self", bundle: bundle, comment: "Label to indicate that the user is replying to themself.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let profile_txn = NdbTxn(ndb: ndb)
|
||||||
|
|
||||||
let names: [String] = pubkeys.map { pk in
|
let names: [String] = pubkeys.map { pk in
|
||||||
let prof = profiles.lookup(id: pk)
|
let prof = ndb.lookup_profile_with_txn(pk, txn: profile_txn)
|
||||||
return Profile.displayName(profile: prof, pubkey: pk).username.truncate(maxLength: 50)
|
|
||||||
|
return Profile.displayName(profile: prof?.profile, pubkey: pk).username.truncate(maxLength: 50)
|
||||||
}
|
}
|
||||||
|
|
||||||
let uniqueNames = NSOrderedSet(array: names).array as! [String]
|
let uniqueNames = NSOrderedSet(array: names).array as! [String]
|
||||||
|
@ -11,7 +11,7 @@ struct ReplyPart: View {
|
|||||||
let events: EventCache
|
let events: EventCache
|
||||||
let event: NostrEvent
|
let event: NostrEvent
|
||||||
let keypair: Keypair
|
let keypair: Keypair
|
||||||
let profiles: Profiles
|
let ndb: Ndb
|
||||||
|
|
||||||
var replying_to: NostrEvent? {
|
var replying_to: NostrEvent? {
|
||||||
guard let note_ref = event.event_refs(keypair).first(where: { evref in evref.is_direct_reply != nil })?.is_direct_reply else {
|
guard let note_ref = event.event_refs(keypair).first(where: { evref in evref.is_direct_reply != nil })?.is_direct_reply else {
|
||||||
@ -24,7 +24,7 @@ struct ReplyPart: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
if event_is_reply(event.event_refs(keypair)) {
|
if event_is_reply(event.event_refs(keypair)) {
|
||||||
ReplyDescription(event: event, replying_to: replying_to, profiles: profiles)
|
ReplyDescription(event: event, replying_to: replying_to, ndb: ndb)
|
||||||
} else {
|
} else {
|
||||||
EmptyView()
|
EmptyView()
|
||||||
}
|
}
|
||||||
@ -34,6 +34,6 @@ struct ReplyPart: View {
|
|||||||
|
|
||||||
struct ReplyPart_Previews: PreviewProvider {
|
struct ReplyPart_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ReplyPart(events: test_damus_state().events, event: test_note, keypair: Keypair(pubkey: .empty, privkey: nil), profiles: test_damus_state().profiles)
|
ReplyPart(events: test_damus_state().events, event: test_note, keypair: Keypair(pubkey: .empty, privkey: nil), ndb: test_damus_state().ndb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ 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
|
||||||
|
|
||||||
@ObservedObject var settings: UserSettingsStore
|
@ObservedObject var settings: UserSettingsStore
|
||||||
|
|
||||||
@State private var isBookmarked: Bool = false
|
@State private var isBookmarked: Bool = false
|
||||||
|
@ -25,7 +25,6 @@ func eventview_pfp_size(_ size: EventViewKind) -> CGFloat {
|
|||||||
struct EventProfile: View {
|
struct EventProfile: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
let pubkey: Pubkey
|
let pubkey: Pubkey
|
||||||
let profile: Profile?
|
|
||||||
let size: EventViewKind
|
let size: EventViewKind
|
||||||
|
|
||||||
var pfp_size: CGFloat {
|
var pfp_size: CGFloat {
|
||||||
@ -44,7 +43,7 @@ struct EventProfile: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
EventProfileName(pubkey: pubkey, profile: profile, damus: damus_state, size: size)
|
EventProfileName(pubkey: pubkey, damus: damus_state, size: size)
|
||||||
|
|
||||||
UserStatusView(status: damus_state.profiles.profile_data(pubkey).status, show_general: damus_state.settings.show_general_statuses, show_music: damus_state.settings.show_music_statuses)
|
UserStatusView(status: damus_state.profiles.profile_data(pubkey).status, show_general: damus_state.settings.show_general_statuses, show_music: damus_state.settings.show_music_statuses)
|
||||||
}
|
}
|
||||||
@ -54,6 +53,6 @@ struct EventProfile: View {
|
|||||||
|
|
||||||
struct EventProfile_Previews: PreviewProvider {
|
struct EventProfile_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
EventProfile(damus_state: test_damus_state(), pubkey: test_note.pubkey, profile: nil, size: .normal)
|
EventProfile(damus_state: test_damus_state(), pubkey: test_note.pubkey, size: .normal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ struct EventShell<Content: View>: View {
|
|||||||
UserStatusView(status: state.profiles.profile_data(pubkey).status, show_general: state.settings.show_general_statuses, show_music: state.settings.show_music_statuses)
|
UserStatusView(status: state.profiles.profile_data(pubkey).status, show_general: state.settings.show_general_statuses, show_music: state.settings.show_music_statuses)
|
||||||
|
|
||||||
if !options.contains(.no_replying_to) {
|
if !options.contains(.no_replying_to) {
|
||||||
ReplyPart(events: state.events, event: event, keypair: state.keypair, profiles: state.profiles)
|
ReplyPart(events: state.events, event: event, keypair: state.keypair, ndb: state.ndb)
|
||||||
}
|
}
|
||||||
|
|
||||||
content
|
content
|
||||||
@ -99,7 +99,7 @@ struct EventShell<Content: View>: View {
|
|||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
EventTop(state: state, event: event, pubkey: pubkey, is_anon: is_anon)
|
EventTop(state: state, event: event, pubkey: pubkey, is_anon: is_anon)
|
||||||
UserStatusView(status: state.profiles.profile_data(pubkey).status, show_general: state.settings.show_general_statuses, show_music: state.settings.show_music_statuses)
|
UserStatusView(status: state.profiles.profile_data(pubkey).status, show_general: state.settings.show_general_statuses, show_music: state.settings.show_music_statuses)
|
||||||
ReplyPart(events: state.events, event: event, keypair: state.keypair, profiles: state.profiles)
|
ReplyPart(events: state.events, event: event, keypair: state.keypair, ndb: state.ndb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
|
@ -35,11 +35,9 @@ struct SelectedEventView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment: .top) {
|
HStack(alignment: .top) {
|
||||||
let profile = damus.profiles.lookup(id: pubkey)
|
|
||||||
|
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
HStack {
|
HStack {
|
||||||
EventProfile(damus_state: damus, pubkey: pubkey, profile: profile, size: .normal)
|
EventProfile(damus_state: damus, pubkey: pubkey, size: .normal)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
@ -51,7 +49,7 @@ struct SelectedEventView: View {
|
|||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
|
|
||||||
if event_is_reply(event.event_refs(damus.keypair)) {
|
if event_is_reply(event.event_refs(damus.keypair)) {
|
||||||
ReplyDescription(event: event, replying_to: replying_to, profiles: damus.profiles)
|
ReplyDescription(event: event, replying_to: replying_to, ndb: damus.ndb)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,7 +273,8 @@ func mention_str(_ m: Mention<MentionRef>, profiles: Profiles) -> CompatibleText
|
|||||||
switch m.ref {
|
switch m.ref {
|
||||||
case .pubkey(let pk):
|
case .pubkey(let pk):
|
||||||
let npub = bech32_pubkey(pk)
|
let npub = bech32_pubkey(pk)
|
||||||
let profile = profiles.lookup(id: pk)
|
let profile_txn = profiles.lookup(id: pk)
|
||||||
|
let profile = profile_txn.unsafeUnownedValue
|
||||||
let disp = Profile.displayName(profile: profile, pubkey: pk).username.truncate(maxLength: 50)
|
let disp = Profile.displayName(profile: profile, pubkey: pk).username.truncate(maxLength: 50)
|
||||||
var attributedString = AttributedString(stringLiteral: "@\(disp)")
|
var attributedString = AttributedString(stringLiteral: "@\(disp)")
|
||||||
attributedString.link = URL(string: "damus:nostr:\(npub)")
|
attributedString.link = URL(string: "damus:nostr:\(npub)")
|
||||||
|
@ -69,8 +69,8 @@ func determine_reacting_to(our_pubkey: Pubkey, ev: NostrEvent?) -> ReactingTo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func event_author_name(profiles: Profiles, pubkey: Pubkey) -> String {
|
func event_author_name(profiles: Profiles, pubkey: Pubkey) -> String {
|
||||||
let alice_prof = profiles.lookup(id: pubkey)
|
let alice_prof_txn = profiles.lookup(id: pubkey).unsafeUnownedValue
|
||||||
return Profile.displayName(profile: alice_prof, pubkey: pubkey).username.truncate(maxLength: 50)
|
return Profile.displayName(profile: alice_prof_txn, pubkey: pubkey).username.truncate(maxLength: 50)
|
||||||
}
|
}
|
||||||
|
|
||||||
func event_group_unique_pubkeys(profiles: Profiles, group: EventGroupType) -> [Pubkey] {
|
func event_group_unique_pubkeys(profiles: Profiles, group: EventGroupType) -> [Pubkey] {
|
||||||
|
@ -86,8 +86,10 @@ struct NotificationsView: View {
|
|||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
var mystery: some View {
|
var mystery: some View {
|
||||||
VStack(spacing: 20) {
|
let profile_txn = state.profiles.lookup(id: state.pubkey)
|
||||||
Text("Wake up, \(Profile.displayName(profile: state.profiles.lookup(id: state.pubkey), pubkey: state.pubkey).displayName.truncate(maxLength: 50))", comment: "Text telling the user to wake up, where the argument is their display name.")
|
let profile = profile_txn.unsafeUnownedValue
|
||||||
|
return VStack(spacing: 20) {
|
||||||
|
Text("Wake up, \(Profile.displayName(profile: profile, pubkey: state.pubkey).displayName.truncate(maxLength: 50))", comment: "Text telling the user to wake up, where the argument is their display name.")
|
||||||
Text("You are dreaming...", comment: "Text telling the user that they are dreaming.")
|
Text("You are dreaming...", comment: "Text telling the user that they are dreaming.")
|
||||||
}
|
}
|
||||||
.id("what")
|
.id("what")
|
||||||
|
@ -12,14 +12,10 @@ struct SuggestedUser {
|
|||||||
let name: String
|
let name: String
|
||||||
let about: String
|
let about: String
|
||||||
let pfp: URL
|
let pfp: URL
|
||||||
let profile: Profile
|
|
||||||
|
|
||||||
init?(profile: Profile, pubkey: Pubkey) {
|
init?(name: String?, about: String?, picture: String?, pubkey: Pubkey) {
|
||||||
|
guard let name, let about, let picture,
|
||||||
guard let name = profile.name,
|
let pfpURL = URL(string: picture) else {
|
||||||
let about = profile.about,
|
|
||||||
let picture = profile.picture,
|
|
||||||
let pfpURL = URL(string: picture) else {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,12 +23,10 @@ struct SuggestedUser {
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.about = about
|
self.about = about
|
||||||
self.pfp = pfpURL
|
self.pfp = pfpURL
|
||||||
self.profile = profile
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SuggestedUserView: View {
|
struct SuggestedUserView: View {
|
||||||
|
|
||||||
let user: SuggestedUser
|
let user: SuggestedUser
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
|
|
||||||
@ -47,7 +41,7 @@ struct SuggestedUserView: View {
|
|||||||
disable_animation: false)
|
disable_animation: false)
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
HStack {
|
HStack {
|
||||||
ProfileName(pubkey: user.pubkey, profile: user.profile, damus: damus_state)
|
ProfileName(pubkey: user.pubkey, damus: damus_state)
|
||||||
}
|
}
|
||||||
Text(user.about)
|
Text(user.about)
|
||||||
.lineLimit(3)
|
.lineLimit(3)
|
||||||
@ -62,9 +56,10 @@ struct SuggestedUserView: View {
|
|||||||
|
|
||||||
struct SuggestedUserView_Previews: PreviewProvider {
|
struct SuggestedUserView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let profile = Profile(name: "klabo", about: "A person who likes nostr a lot and I like to tell people about myself in very long-winded ways that push the limits of UI and almost break things", picture: "https://primal.b-cdn.net/media-cache?s=m&a=1&u=https%3A%2F%2Fpbs.twimg.com%2Fprofile_images%2F1599994711430742017%2F33zLk9Wi_400x400.jpg")
|
let pfp = "https://primal.b-cdn.net/media-cache?s=m&a=1&u=https%3A%2F%2Fpbs.twimg.com%2Fprofile_images%2F1599994711430742017%2F33zLk9Wi_400x400.jpg"
|
||||||
|
let profile = Profile(name: "klabo", about: "A person who likes nostr a lot and I like to tell people about myself in very long-winded ways that push the limits of UI and almost break things", picture: pfp)
|
||||||
|
|
||||||
let user = SuggestedUser(profile: profile, pubkey: test_pubkey)!
|
let user = SuggestedUser(name: "klabo", about: "name", picture: "about", pubkey: test_pubkey)!
|
||||||
List {
|
List {
|
||||||
SuggestedUserView(user: user, damus_state: test_damus_state())
|
SuggestedUserView(user: user, damus_state: test_damus_state())
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,9 @@ class SuggestedUsersViewModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func suggestedUser(pubkey: Pubkey) -> SuggestedUser? {
|
func suggestedUser(pubkey: Pubkey) -> SuggestedUser? {
|
||||||
if let profile = damus_state.profiles.lookup(id: pubkey),
|
let profile_txn = damus_state.profiles.lookup(id: pubkey)
|
||||||
let user = SuggestedUser(profile: profile, pubkey: pubkey) {
|
if let profile = profile_txn.unsafeUnownedValue,
|
||||||
|
let user = SuggestedUser(name: profile.name, about: profile.about, picture: profile.picture, pubkey: pubkey) {
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -173,7 +173,8 @@ struct PostView: View {
|
|||||||
return .init(string: "")
|
return .init(string: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
let profile = damus_state.profiles.lookup(id: pubkey)
|
let profile_txn = damus_state.profiles.lookup(id: pubkey)
|
||||||
|
let profile = profile_txn.unsafeUnownedValue
|
||||||
return user_tag_attr_string(profile: profile, pubkey: pubkey)
|
return user_tag_attr_string(profile: profile, pubkey: pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,15 +7,6 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct SearchedUser: Identifiable {
|
|
||||||
let profile: Profile?
|
|
||||||
let pubkey: Pubkey
|
|
||||||
|
|
||||||
var id: Pubkey {
|
|
||||||
return pubkey
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct UserSearch: View {
|
struct UserSearch: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
let search: String
|
let search: String
|
||||||
@ -25,13 +16,14 @@ struct UserSearch: View {
|
|||||||
@Binding var post: NSMutableAttributedString
|
@Binding var post: NSMutableAttributedString
|
||||||
@EnvironmentObject var tagModel: TagModel
|
@EnvironmentObject var tagModel: TagModel
|
||||||
|
|
||||||
var users: [SearchedUser] {
|
var users: [Pubkey] {
|
||||||
return search_profiles(profiles: damus_state.profiles, search: search)
|
return search_profiles(profiles: damus_state.profiles, search: search)
|
||||||
}
|
}
|
||||||
|
|
||||||
func on_user_tapped(user: SearchedUser) {
|
func on_user_tapped(pk: Pubkey) {
|
||||||
let pk = user.pubkey
|
let profile_txn = damus_state.profiles.lookup(id: pk)
|
||||||
let user_tag = user_tag_attr_string(profile: user.profile, pubkey: pk)
|
let profile = profile_txn.unsafeUnownedValue
|
||||||
|
let user_tag = user_tag_attr_string(profile: profile, pubkey: pk)
|
||||||
|
|
||||||
appendUserTag(withTag: user_tag)
|
appendUserTag(withTag: user_tag)
|
||||||
}
|
}
|
||||||
@ -57,11 +49,11 @@ struct UserSearch: View {
|
|||||||
if users.count == 0 {
|
if users.count == 0 {
|
||||||
EmptyUserSearchView()
|
EmptyUserSearchView()
|
||||||
} else {
|
} else {
|
||||||
ForEach(users) { user in
|
ForEach(users) { pk in
|
||||||
UserView(damus_state: damus_state, pubkey: user.pubkey)
|
UserView(damus_state: damus_state, pubkey: pk)
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
on_user_tapped(user: user)
|
on_user_tapped(pk: pk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ struct EditMetadataView: View {
|
|||||||
@State var name: String
|
@State var name: String
|
||||||
@State var ln: String
|
@State var ln: String
|
||||||
@State var website: String
|
@State var website: String
|
||||||
let profile: Profile?
|
|
||||||
|
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
@ -31,8 +30,7 @@ struct EditMetadataView: View {
|
|||||||
|
|
||||||
init(damus_state: DamusState) {
|
init(damus_state: DamusState) {
|
||||||
self.damus_state = damus_state
|
self.damus_state = damus_state
|
||||||
let data = damus_state.profiles.lookup(id: damus_state.pubkey)
|
let data = damus_state.profiles.lookup(id: damus_state.pubkey).unsafeUnownedValue
|
||||||
self.profile = data
|
|
||||||
|
|
||||||
_name = State(initialValue: data?.name ?? "")
|
_name = State(initialValue: data?.name ?? "")
|
||||||
_display_name = State(initialValue: data?.display_name ?? "")
|
_display_name = State(initialValue: data?.display_name ?? "")
|
||||||
|
@ -12,7 +12,6 @@ import SwiftUI
|
|||||||
struct EventProfileName: View {
|
struct EventProfileName: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
let pubkey: Pubkey
|
let pubkey: Pubkey
|
||||||
let profile: Profile?
|
|
||||||
|
|
||||||
@State var display_name: DisplayName?
|
@State var display_name: DisplayName?
|
||||||
@State var nip05: NIP05?
|
@State var nip05: NIP05?
|
||||||
@ -20,12 +19,12 @@ struct EventProfileName: View {
|
|||||||
|
|
||||||
let size: EventViewKind
|
let size: EventViewKind
|
||||||
|
|
||||||
init(pubkey: Pubkey, profile: Profile?, damus: DamusState, size: EventViewKind = .normal) {
|
init(pubkey: Pubkey, damus: DamusState, size: EventViewKind = .normal) {
|
||||||
self.damus_state = damus
|
self.damus_state = damus
|
||||||
self.pubkey = pubkey
|
self.pubkey = pubkey
|
||||||
self.profile = profile
|
|
||||||
self.size = size
|
self.size = size
|
||||||
self._donation = State(wrappedValue: profile?.damus_donation)
|
let donation = damus.ndb.lookup_profile(pubkey).map({ p in p?.profile?.damus_donation }).value
|
||||||
|
self._donation = State(wrappedValue: donation)
|
||||||
}
|
}
|
||||||
|
|
||||||
var friend_type: FriendType? {
|
var friend_type: FriendType? {
|
||||||
@ -36,11 +35,11 @@ struct EventProfileName: View {
|
|||||||
nip05 ?? damus_state.profiles.is_validated(pubkey)
|
nip05 ?? damus_state.profiles.is_validated(pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
var current_display_name: DisplayName {
|
func current_display_name(_ profile: Profile?) -> DisplayName {
|
||||||
return display_name ?? Profile.displayName(profile: profile, pubkey: pubkey)
|
return display_name ?? Profile.displayName(profile: profile, pubkey: pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
var onlyzapper: Bool {
|
func onlyzapper(_ profile: Profile?) -> Bool {
|
||||||
guard let profile else {
|
guard let profile else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -58,8 +57,10 @@ struct EventProfileName: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
let profile_txn = damus_state.profiles.lookup(id: pubkey)
|
||||||
|
let profile = profile_txn.unsafeUnownedValue
|
||||||
HStack(spacing: 2) {
|
HStack(spacing: 2) {
|
||||||
switch current_display_name {
|
switch current_display_name(profile) {
|
||||||
case .one(let one):
|
case .one(let one):
|
||||||
Text(one)
|
Text(one)
|
||||||
.font(.body.weight(.bold))
|
.font(.body.weight(.bold))
|
||||||
@ -84,7 +85,7 @@ struct EventProfileName: View {
|
|||||||
FriendIcon(friend: frend)
|
FriendIcon(friend: frend)
|
||||||
}
|
}
|
||||||
|
|
||||||
if onlyzapper {
|
if onlyzapper(profile) {
|
||||||
Image("zap-hashtag")
|
Image("zap-hashtag")
|
||||||
.frame(width: 14, height: 14)
|
.frame(width: 14, height: 14)
|
||||||
}
|
}
|
||||||
@ -97,9 +98,24 @@ struct EventProfileName: View {
|
|||||||
if update.pubkey != pubkey {
|
if update.pubkey != pubkey {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
display_name = Profile.displayName(profile: update.profile, pubkey: pubkey)
|
|
||||||
nip05 = damus_state.profiles.is_validated(pubkey)
|
let profile_txn = damus_state.profiles.lookup(id: update.pubkey)
|
||||||
donation = update.profile.damus_donation
|
guard let profile = profile_txn.unsafeUnownedValue else { return }
|
||||||
|
|
||||||
|
let display_name = Profile.displayName(profile: profile, pubkey: pubkey)
|
||||||
|
if display_name != self.display_name {
|
||||||
|
self.display_name = display_name
|
||||||
|
}
|
||||||
|
|
||||||
|
let nip05 = damus_state.profiles.is_validated(pubkey)
|
||||||
|
|
||||||
|
if self.nip05 != nip05 {
|
||||||
|
self.nip05 = nip05
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.donation != profile.damus_donation {
|
||||||
|
donation = profile.damus_donation
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,6 +123,6 @@ struct EventProfileName: View {
|
|||||||
|
|
||||||
struct EventProfileName_Previews: PreviewProvider {
|
struct EventProfileName_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
EventProfileName(pubkey: test_note.pubkey, profile: nil, damus: test_damus_state())
|
EventProfileName(pubkey: test_note.pubkey, damus: test_damus_state())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ func get_friend_type(contacts: Contacts, pubkey: Pubkey) -> FriendType? {
|
|||||||
struct ProfileName: View {
|
struct ProfileName: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
let pubkey: Pubkey
|
let pubkey: Pubkey
|
||||||
let profile: Profile?
|
|
||||||
let prefix: String
|
let prefix: String
|
||||||
|
|
||||||
let show_nip5_domain: Bool
|
let show_nip5_domain: Bool
|
||||||
@ -36,9 +35,8 @@ struct ProfileName: View {
|
|||||||
@State var nip05: NIP05?
|
@State var nip05: NIP05?
|
||||||
@State var donation: Int?
|
@State var donation: Int?
|
||||||
|
|
||||||
init(pubkey: Pubkey, profile: Profile?, prefix: String = "", damus: DamusState, show_nip5_domain: Bool = true) {
|
init(pubkey: Pubkey, prefix: String = "", damus: DamusState, show_nip5_domain: Bool = true) {
|
||||||
self.pubkey = pubkey
|
self.pubkey = pubkey
|
||||||
self.profile = profile
|
|
||||||
self.prefix = prefix
|
self.prefix = prefix
|
||||||
self.damus_state = damus
|
self.damus_state = damus
|
||||||
self.show_nip5_domain = show_nip5_domain
|
self.show_nip5_domain = show_nip5_domain
|
||||||
@ -53,15 +51,15 @@ struct ProfileName: View {
|
|||||||
nip05 ?? damus_state.profiles.is_validated(pubkey)
|
nip05 ?? damus_state.profiles.is_validated(pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
var current_display_name: DisplayName {
|
func current_display_name(profile: Profile?) -> DisplayName {
|
||||||
return display_name ?? Profile.displayName(profile: profile, pubkey: pubkey)
|
return display_name ?? Profile.displayName(profile: profile, pubkey: pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
var name_choice: String {
|
func name_choice(profile: Profile?) -> String {
|
||||||
return prefix == "@" ? current_display_name.username.truncate(maxLength: 50) : current_display_name.displayName.truncate(maxLength: 50)
|
return prefix == "@" ? current_display_name(profile: profile).username.truncate(maxLength: 50) : current_display_name(profile: profile).displayName.truncate(maxLength: 50)
|
||||||
}
|
}
|
||||||
|
|
||||||
var onlyzapper: Bool {
|
func onlyzapper(profile: Profile?) -> Bool {
|
||||||
guard let profile else {
|
guard let profile else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -69,7 +67,7 @@ struct ProfileName: View {
|
|||||||
return profile.reactions == false
|
return profile.reactions == false
|
||||||
}
|
}
|
||||||
|
|
||||||
var supporter: Int? {
|
func supporter(profile: Profile?) -> Int? {
|
||||||
guard let profile,
|
guard let profile,
|
||||||
let donation = profile.damus_donation,
|
let donation = profile.damus_donation,
|
||||||
donation > 0
|
donation > 0
|
||||||
@ -81,21 +79,28 @@ struct ProfileName: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
let profile_txn = damus_state.profiles.lookup(id: pubkey)
|
||||||
|
let profile = profile_txn.unsafeUnownedValue
|
||||||
|
|
||||||
HStack(spacing: 2) {
|
HStack(spacing: 2) {
|
||||||
Text(verbatim: "\(prefix)\(name_choice)")
|
Text(verbatim: "\(prefix)\(name_choice(profile: profile))")
|
||||||
.font(.body)
|
.font(.body)
|
||||||
.fontWeight(prefix == "@" ? .none : .bold)
|
.fontWeight(prefix == "@" ? .none : .bold)
|
||||||
|
|
||||||
if let nip05 = current_nip05 {
|
if let nip05 = current_nip05 {
|
||||||
NIP05Badge(nip05: nip05, pubkey: pubkey, contacts: damus_state.contacts, show_domain: show_nip5_domain, profiles: damus_state.profiles)
|
NIP05Badge(nip05: nip05, pubkey: pubkey, contacts: damus_state.contacts, show_domain: show_nip5_domain, profiles: damus_state.profiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let friend = friend_type, current_nip05 == nil {
|
if let friend = friend_type, current_nip05 == nil {
|
||||||
FriendIcon(friend: friend)
|
FriendIcon(friend: friend)
|
||||||
}
|
}
|
||||||
if onlyzapper {
|
|
||||||
|
if onlyzapper(profile: profile) {
|
||||||
Image("zap-hashtag")
|
Image("zap-hashtag")
|
||||||
.frame(width: 14, height: 14)
|
.frame(width: 14, height: 14)
|
||||||
}
|
}
|
||||||
if let supporter {
|
|
||||||
|
if let supporter = supporter(profile: profile) {
|
||||||
SupporterBadge(percent: supporter)
|
SupporterBadge(percent: supporter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,16 +108,38 @@ struct ProfileName: View {
|
|||||||
if update.pubkey != pubkey {
|
if update.pubkey != pubkey {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
display_name = Profile.displayName(profile: update.profile, pubkey: pubkey)
|
|
||||||
nip05 = damus_state.profiles.is_validated(pubkey)
|
var profile: Profile!
|
||||||
donation = profile?.damus_donation
|
var profile_txn: NdbTxn<Profile?>!
|
||||||
|
|
||||||
|
switch update {
|
||||||
|
case .remote(let pubkey):
|
||||||
|
profile_txn = damus_state.profiles.lookup(id: pubkey)
|
||||||
|
guard let prof = profile_txn.unsafeUnownedValue else { return }
|
||||||
|
profile = prof
|
||||||
|
case .manual(_, let prof):
|
||||||
|
profile = prof
|
||||||
|
}
|
||||||
|
|
||||||
|
let display_name = Profile.displayName(profile: profile, pubkey: pubkey)
|
||||||
|
if self.display_name != display_name {
|
||||||
|
self.display_name = display_name
|
||||||
|
}
|
||||||
|
|
||||||
|
let nip05 = damus_state.profiles.is_validated(pubkey)
|
||||||
|
if nip05 != self.nip05 {
|
||||||
|
self.nip05 = nip05
|
||||||
|
}
|
||||||
|
|
||||||
|
if donation != profile.damus_donation {
|
||||||
|
donation = profile.damus_donation
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProfileName_Previews: PreviewProvider {
|
struct ProfileName_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ProfileName(pubkey:
|
ProfileName(pubkey: test_damus_state().pubkey, damus: test_damus_state())
|
||||||
test_damus_state().pubkey, profile: make_test_profile(), damus: test_damus_state())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,6 @@ fileprivate struct KeyView: View {
|
|||||||
|
|
||||||
struct ProfileNameView: View {
|
struct ProfileNameView: View {
|
||||||
let pubkey: Pubkey
|
let pubkey: Pubkey
|
||||||
let profile: Profile?
|
|
||||||
let damus: DamusState
|
let damus: DamusState
|
||||||
|
|
||||||
var spacing: CGFloat { 10.0 }
|
var spacing: CGFloat { 10.0 }
|
||||||
@ -95,10 +94,13 @@ struct ProfileNameView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
|
let profile_txn = self.damus.profiles.lookup(id: pubkey)
|
||||||
|
let profile = profile_txn.unsafeUnownedValue
|
||||||
|
|
||||||
switch Profile.displayName(profile: profile, pubkey: pubkey) {
|
switch Profile.displayName(profile: profile, pubkey: pubkey) {
|
||||||
case .one:
|
case .one:
|
||||||
HStack(alignment: .center, spacing: spacing) {
|
HStack(alignment: .center, spacing: spacing) {
|
||||||
ProfileName(pubkey: pubkey, profile: profile, damus: damus)
|
ProfileName(pubkey: pubkey, damus: damus)
|
||||||
.font(.title3.weight(.bold))
|
.font(.title3.weight(.bold))
|
||||||
}
|
}
|
||||||
case .both(username: _, displayName: let displayName):
|
case .both(username: _, displayName: let displayName):
|
||||||
@ -106,7 +108,7 @@ struct ProfileNameView: View {
|
|||||||
.font(.title3.weight(.bold))
|
.font(.title3.weight(.bold))
|
||||||
|
|
||||||
HStack(alignment: .center, spacing: spacing) {
|
HStack(alignment: .center, spacing: spacing) {
|
||||||
ProfileName(pubkey: pubkey, profile: profile, prefix: "@", damus: damus)
|
ProfileName(pubkey: pubkey, prefix: "@", damus: damus)
|
||||||
.font(.callout)
|
.font(.callout)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
@ -124,9 +126,9 @@ struct ProfileNameView: View {
|
|||||||
struct ProfileNameView_Previews: PreviewProvider {
|
struct ProfileNameView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
VStack {
|
VStack {
|
||||||
ProfileNameView(pubkey: test_note.pubkey, profile: nil, damus: test_damus_state())
|
ProfileNameView(pubkey: test_note.pubkey, damus: test_damus_state())
|
||||||
|
|
||||||
ProfileNameView(pubkey: test_note.pubkey, profile: nil, damus: test_damus_state())
|
ProfileNameView(pubkey: test_note.pubkey, damus: test_damus_state())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,15 +88,24 @@ struct ProfilePicView: View {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if let pic = updated.profile.picture {
|
switch updated {
|
||||||
self.picture = pic
|
case .manual(_, let profile):
|
||||||
|
if let pic = profile.picture {
|
||||||
|
self.picture = pic
|
||||||
|
}
|
||||||
|
case .remote(pubkey: let pk):
|
||||||
|
let profile_txn = profiles.lookup(id: pk)
|
||||||
|
let profile = profile_txn.unsafeUnownedValue
|
||||||
|
if let pic = profile?.picture {
|
||||||
|
self.picture = pic
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func get_profile_url(picture: String?, pubkey: Pubkey, profiles: Profiles) -> URL {
|
func get_profile_url(picture: String?, pubkey: Pubkey, profiles: Profiles) -> URL {
|
||||||
let pic = picture ?? profiles.lookup(id: pubkey)?.picture ?? robohash(pubkey)
|
let pic = picture ?? profiles.lookup(id: pubkey).map({ $0?.picture }).value ?? robohash(pubkey)
|
||||||
if let url = URL(string: pic) {
|
if let url = URL(string: pic) {
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ struct EditProfilePictureView: View {
|
|||||||
if let profile_url {
|
if let profile_url {
|
||||||
return profile_url
|
return profile_url
|
||||||
} else if let state = damus_state,
|
} else if let state = damus_state,
|
||||||
let picture = state.profiles.lookup(id: pubkey)?.picture {
|
let picture = state.profiles.lookup(id: pubkey).map({ pr in pr?.picture }).value {
|
||||||
return URL(string: picture)
|
return URL(string: picture)
|
||||||
} else {
|
} else {
|
||||||
return profile_url ?? URL(string: robohash(pubkey))
|
return profile_url ?? URL(string: robohash(pubkey))
|
||||||
|
@ -31,11 +31,11 @@ func follow_btn_txt(_ fs: FollowState, follows_you: Bool) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func followedByString(_ friend_intersection: [Pubkey], profiles: Profiles, locale: Locale = Locale.current) -> String {
|
func followedByString<Y>(txn: NdbTxn<Y>, _ friend_intersection: [Pubkey], ndb: Ndb, locale: Locale = Locale.current) -> String {
|
||||||
let bundle = bundleForLocale(locale: locale)
|
let bundle = bundleForLocale(locale: locale)
|
||||||
let names: [String] = friend_intersection.prefix(3).map {
|
let names: [String] = friend_intersection.prefix(3).map { pk in
|
||||||
let profile = profiles.lookup(id: $0)
|
let profile = ndb.lookup_profile_with_txn(pk, txn: txn)?.profile
|
||||||
return Profile.displayName(profile: profile, pubkey: $0).username.truncate(maxLength: 20)
|
return Profile.displayName(profile: profile, pubkey: pk).username.truncate(maxLength: 20)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch friend_intersection.count {
|
switch friend_intersection.count {
|
||||||
@ -216,27 +216,29 @@ struct ProfileView: View {
|
|||||||
.accentColor(DamusColors.white)
|
.accentColor(DamusColors.white)
|
||||||
}
|
}
|
||||||
|
|
||||||
func lnButton(lnurl: String, record: ProfileRecord, profile: Profile) -> some View {
|
func lnButton(lnurl: String, unownedProfile: Profile?, pubkey: Pubkey) -> some View {
|
||||||
let profile = record.profile!
|
let reactions = unownedProfile?.reactions ?? true
|
||||||
let button_img = profile.reactions == false ? "zap.fill" : "zap"
|
let button_img = reactions ? "zap.fill" : "zap"
|
||||||
return Button(action: {
|
let lud16 = unownedProfile?.lud16
|
||||||
|
|
||||||
|
return Button(action: { [lnurl] in
|
||||||
present_sheet(.zap(target: .profile(self.profile.pubkey), lnurl: lnurl))
|
present_sheet(.zap(target: .profile(self.profile.pubkey), lnurl: lnurl))
|
||||||
}) {
|
}) {
|
||||||
Image(button_img)
|
Image(button_img)
|
||||||
.foregroundColor(button_img == "zap.fill" ? .orange : Color.primary)
|
.foregroundColor(button_img == "zap.fill" ? .orange : Color.primary)
|
||||||
.profile_button_style(scheme: colorScheme)
|
.profile_button_style(scheme: colorScheme)
|
||||||
.contextMenu {
|
.contextMenu { [lud16, reactions, lnurl] in
|
||||||
if profile.reactions == false {
|
if reactions == false {
|
||||||
Text("OnlyZaps Enabled", comment: "Non-tappable text in context menu that shows up when the zap button on profile is long pressed to indicate that the user has enabled OnlyZaps, meaning that they would like to be only zapped and not accept reactions to their notes.")
|
Text("OnlyZaps Enabled", comment: "Non-tappable text in context menu that shows up when the zap button on profile is long pressed to indicate that the user has enabled OnlyZaps, meaning that they would like to be only zapped and not accept reactions to their notes.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if let addr = profile.lud16 {
|
if let lud16 {
|
||||||
Button {
|
Button {
|
||||||
UIPasteboard.general.string = addr
|
UIPasteboard.general.string = lud16
|
||||||
} label: {
|
} label: {
|
||||||
Label(addr, image: "copy2")
|
Label(lud16, image: "copy2")
|
||||||
}
|
}
|
||||||
} else if let lnurl = record.lnurl {
|
} else {
|
||||||
Button {
|
Button {
|
||||||
UIPasteboard.general.string = lnurl
|
UIPasteboard.general.string = lnurl
|
||||||
} label: {
|
} label: {
|
||||||
@ -269,14 +271,14 @@ struct ProfileView: View {
|
|||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
}
|
}
|
||||||
|
|
||||||
func actionSection(record: ProfileRecord?) -> some View {
|
func actionSection(record: ProfileRecord?, pubkey: Pubkey) -> some View {
|
||||||
return Group {
|
return Group {
|
||||||
if let record,
|
if let record,
|
||||||
let profile = record.profile,
|
let profile = record.profile,
|
||||||
let lnurl = record.lnurl,
|
let lnurl = record.lnurl,
|
||||||
lnurl != ""
|
lnurl != ""
|
||||||
{
|
{
|
||||||
lnButton(lnurl: lnurl, record: record, profile: profile)
|
lnButton(lnurl: lnurl, unownedProfile: profile, pubkey: pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
dmButton
|
dmButton
|
||||||
@ -311,6 +313,7 @@ struct ProfileView: View {
|
|||||||
func nameSection(profile_data: ProfileRecord?) -> some View {
|
func nameSection(profile_data: ProfileRecord?) -> some View {
|
||||||
return Group {
|
return Group {
|
||||||
let follows_you = profile.pubkey != damus_state.pubkey && profile.follows(pubkey: damus_state.pubkey)
|
let follows_you = profile.pubkey != damus_state.pubkey && profile.follows(pubkey: damus_state.pubkey)
|
||||||
|
|
||||||
HStack(alignment: .center) {
|
HStack(alignment: .center) {
|
||||||
ProfilePicView(pubkey: profile.pubkey, size: pfp_size, highlight: .custom(imageBorderColor(), 4.0), profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
ProfilePicView(pubkey: profile.pubkey, size: pfp_size, highlight: .custom(imageBorderColor(), 4.0), profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
||||||
.padding(.top, -(pfp_size / 2.0))
|
.padding(.top, -(pfp_size / 2.0))
|
||||||
@ -329,10 +332,10 @@ struct ProfileView: View {
|
|||||||
followsYouBadge
|
followsYouBadge
|
||||||
}
|
}
|
||||||
|
|
||||||
actionSection(record: profile_data)
|
actionSection(record: profile_data, pubkey: profile.pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileNameView(pubkey: profile.pubkey, profile: profile_data?.profile, damus: damus_state)
|
ProfileNameView(pubkey: profile.pubkey, damus: damus_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,7 +358,8 @@ struct ProfileView: View {
|
|||||||
|
|
||||||
var aboutSection: some View {
|
var aboutSection: some View {
|
||||||
VStack(alignment: .leading, spacing: 8.0) {
|
VStack(alignment: .leading, spacing: 8.0) {
|
||||||
let profile_data = damus_state.profiles.lookup_with_timestamp(profile.pubkey)
|
let profile_txn = damus_state.profiles.lookup_with_timestamp(profile.pubkey)
|
||||||
|
let profile_data = profile_txn.unsafeUnownedValue
|
||||||
|
|
||||||
nameSection(profile_data: profile_data)
|
nameSection(profile_data: profile_data)
|
||||||
|
|
||||||
@ -422,7 +426,7 @@ struct ProfileView: View {
|
|||||||
NavigationLink(value: Route.FollowersYouKnow(friendedFollowers: friended_followers, followers: followers)) {
|
NavigationLink(value: Route.FollowersYouKnow(friendedFollowers: friended_followers, followers: followers)) {
|
||||||
HStack {
|
HStack {
|
||||||
CondensedProfilePicturesView(state: damus_state, pubkeys: friended_followers, maxPictures: 3)
|
CondensedProfilePicturesView(state: damus_state, pubkeys: friended_followers, maxPictures: 3)
|
||||||
let followedByString = followedByString(friended_followers, profiles: damus_state.profiles)
|
let followedByString = followedByString(txn: profile_txn, friended_followers, ndb: damus_state.ndb)
|
||||||
Text(followedByString)
|
Text(followedByString)
|
||||||
.font(.subheadline).foregroundColor(.gray)
|
.font(.subheadline).foregroundColor(.gray)
|
||||||
.multilineTextAlignment(.leading)
|
.multilineTextAlignment(.leading)
|
||||||
@ -516,7 +520,9 @@ extension View {
|
|||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
func check_nip05_validity(pubkey: Pubkey, profiles: Profiles) {
|
func check_nip05_validity(pubkey: Pubkey, profiles: Profiles) {
|
||||||
guard let profile = profiles.lookup(id: pubkey),
|
let profile_txn = profiles.lookup(id: pubkey)
|
||||||
|
|
||||||
|
guard let profile = profile_txn.unsafeUnownedValue,
|
||||||
let nip05 = profile.nip05,
|
let nip05 = profile.nip05,
|
||||||
profiles.is_validated(pubkey) == nil
|
profiles.is_validated(pubkey) == nil
|
||||||
else {
|
else {
|
||||||
@ -532,7 +538,7 @@ func check_nip05_validity(pubkey: Pubkey, profiles: Profiles) {
|
|||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
profiles.set_validated(pubkey, nip05: validated)
|
profiles.set_validated(pubkey, nip05: validated)
|
||||||
profiles.nip05_pubkey[nip05] = pubkey
|
profiles.nip05_pubkey[nip05] = pubkey
|
||||||
notify(.profile_updated(pubkey: pubkey, profile: profile))
|
notify(.profile_updated(.remote(pubkey: pubkey)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,9 +118,11 @@ struct QRCodeView: View {
|
|||||||
|
|
||||||
var QRView: some View {
|
var QRView: some View {
|
||||||
VStack(alignment: .center) {
|
VStack(alignment: .center) {
|
||||||
let profile = damus_state.profiles.lookup(id: pubkey)
|
let profile_txn = damus_state.profiles.lookup(id: pubkey)
|
||||||
|
let profile = profile_txn.unsafeUnownedValue
|
||||||
|
let our_profile = damus_state.ndb.lookup_profile_with_txn(damus_state.pubkey, txn: profile_txn)
|
||||||
|
|
||||||
if (damus_state.profiles.lookup(id: damus_state.pubkey)?.picture) != nil {
|
if our_profile?.profile?.picture != nil {
|
||||||
ProfilePicView(pubkey: pubkey, size: 90.0, highlight: .custom(DamusColors.white, 3.0), profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
ProfilePicView(pubkey: pubkey, size: 90.0, highlight: .custom(DamusColors.white, 3.0), profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
||||||
.padding(.top, 50)
|
.padding(.top, 50)
|
||||||
} else {
|
} else {
|
||||||
|
@ -24,10 +24,11 @@ struct ReplyView: View {
|
|||||||
var ReplyingToSection: some View {
|
var ReplyingToSection: some View {
|
||||||
HStack {
|
HStack {
|
||||||
Group {
|
Group {
|
||||||
|
let txn = NdbTxn(ndb: damus.ndb)
|
||||||
let names = references
|
let names = references
|
||||||
.map { pubkey in
|
.map { pubkey in
|
||||||
let pk = pubkey
|
let pk = pubkey
|
||||||
let prof = damus.profiles.lookup(id: pk)
|
let prof = damus.ndb.lookup_profile_with_txn(pk, txn: txn)?.profile
|
||||||
return "@" + Profile.displayName(profile: prof, pubkey: pk).username.truncate(maxLength: 50)
|
return "@" + Profile.displayName(profile: prof, pubkey: pk).username.truncate(maxLength: 50)
|
||||||
}
|
}
|
||||||
.joined(separator: " ")
|
.joined(separator: " ")
|
||||||
|
@ -15,10 +15,8 @@ struct RepostedEvent: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
let prof = damus.profiles.lookup(id: event.pubkey)
|
|
||||||
|
|
||||||
NavigationLink(value: Route.ProfileByKey(pubkey: event.pubkey)) {
|
NavigationLink(value: Route.ProfileByKey(pubkey: event.pubkey)) {
|
||||||
Reposted(damus: damus, pubkey: event.pubkey, profile: prof)
|
Reposted(damus: damus, pubkey: event.pubkey)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
|
@ -44,23 +44,25 @@ struct SearchingEventView: View {
|
|||||||
switch search {
|
switch search {
|
||||||
case .nip05(let nip05):
|
case .nip05(let nip05):
|
||||||
if let pk = state.profiles.nip05_pubkey[nip05] {
|
if let pk = state.profiles.nip05_pubkey[nip05] {
|
||||||
if state.profiles.lookup(id: pk) != nil {
|
if state.profiles.lookup_key_by_pubkey(pk) != nil {
|
||||||
self.search_state = .found_profile(pk)
|
self.search_state = .found_profile(pk)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Task {
|
Task {
|
||||||
guard let nip05 = NIP05.parse(nip05) else {
|
guard let nip05 = NIP05.parse(nip05) else {
|
||||||
self.search_state = .not_found
|
Task { @MainActor in
|
||||||
|
self.search_state = .not_found
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let nip05_resp = await fetch_nip05(nip05: nip05) else {
|
guard let nip05_resp = await fetch_nip05(nip05: nip05) else {
|
||||||
DispatchQueue.main.async {
|
Task { @MainActor in
|
||||||
self.search_state = .not_found
|
self.search_state = .not_found
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
Task { @MainActor in
|
||||||
guard let pk = nip05_resp.names[nip05.username] else {
|
guard let pk = nip05_resp.names[nip05.username] else {
|
||||||
self.search_state = .not_found
|
self.search_state = .not_found
|
||||||
return
|
return
|
||||||
@ -81,11 +83,11 @@ struct SearchingEventView: View {
|
|||||||
}
|
}
|
||||||
case .profile(let pubkey):
|
case .profile(let pubkey):
|
||||||
find_event(state: state, query: .profile(pubkey: pubkey)) { res in
|
find_event(state: state, query: .profile(pubkey: pubkey)) { res in
|
||||||
guard case .profile(_, let ev) = res else {
|
guard case .profile(let pubkey) = res else {
|
||||||
self.search_state = .not_found
|
self.search_state = .not_found
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.search_state = .found_profile(ev.pubkey)
|
self.search_state = .found_profile(pubkey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@ import SwiftUI
|
|||||||
|
|
||||||
struct MultiSearch {
|
struct MultiSearch {
|
||||||
let hashtag: String
|
let hashtag: String
|
||||||
let profiles: [SearchedUser]
|
let profiles: [Pubkey]
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Search: Identifiable {
|
enum Search: Identifiable {
|
||||||
case profiles([SearchedUser])
|
case profiles([Pubkey])
|
||||||
case hashtag(String)
|
case hashtag(String)
|
||||||
case profile(Pubkey)
|
case profile(Pubkey)
|
||||||
case note(NoteId)
|
case note(NoteId)
|
||||||
@ -49,10 +49,10 @@ struct InnerSearchResults: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProfilesSearch(_ results: [SearchedUser]) -> some View {
|
func ProfilesSearch(_ results: [Pubkey]) -> some View {
|
||||||
return LazyVStack {
|
return LazyVStack {
|
||||||
ForEach(results) { prof in
|
ForEach(results, id: \.id) { pk in
|
||||||
ProfileSearchResult(pk: prof.pubkey)
|
ProfileSearchResult(pk: pk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,27 +171,23 @@ func make_hashtagable(_ str: String) -> String {
|
|||||||
return String(new.filter{$0 != " "})
|
return String(new.filter{$0 != " "})
|
||||||
}
|
}
|
||||||
|
|
||||||
func search_profiles(profiles: Profiles, search: String) -> [SearchedUser] {
|
func search_profiles(profiles: Profiles, search: String) -> [Pubkey] {
|
||||||
// Search by hex pubkey.
|
// Search by hex pubkey.
|
||||||
if let pubkey = hex_decode_pubkey(search),
|
if let pubkey = hex_decode_pubkey(search),
|
||||||
let profile = profiles.lookup(id: pubkey)
|
profiles.lookup_key_by_pubkey(pubkey) != nil
|
||||||
{
|
{
|
||||||
return [SearchedUser(profile: profile, pubkey: pubkey)]
|
return [pubkey]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search by npub pubkey.
|
// Search by npub pubkey.
|
||||||
if search.starts(with: "npub"),
|
if search.starts(with: "npub"),
|
||||||
let bech32_key = decode_bech32_key(search),
|
let bech32_key = decode_bech32_key(search),
|
||||||
case Bech32Key.pub(let pk) = bech32_key,
|
case Bech32Key.pub(let pk) = bech32_key,
|
||||||
let profile = profiles.lookup(id: pk)
|
profiles.lookup_key_by_pubkey(pk) != nil
|
||||||
{
|
{
|
||||||
return [SearchedUser(profile: profile, pubkey: pk)]
|
return [pk]
|
||||||
}
|
}
|
||||||
|
|
||||||
let new = search.lowercased()
|
let new = search.lowercased()
|
||||||
let matched_pubkeys = profiles.user_search_cache.search(key: new)
|
return profiles.user_search_cache.search(key: new)
|
||||||
|
|
||||||
return matched_pubkeys
|
|
||||||
.map { SearchedUser(profile: profiles.lookup(id: $0), pubkey: $0) }
|
|
||||||
.filter { $0.profile != nil }
|
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,8 @@ struct SideMenuView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var TopProfile: some View {
|
var TopProfile: some View {
|
||||||
let profile = damus_state.profiles.lookup(id: damus_state.pubkey)
|
let profile_txn = damus_state.profiles.lookup(id: damus_state.pubkey)
|
||||||
|
let profile = profile_txn.unsafeUnownedValue
|
||||||
return VStack(alignment: .leading, spacing: verticalSpacing) {
|
return VStack(alignment: .leading, spacing: verticalSpacing) {
|
||||||
HStack {
|
HStack {
|
||||||
ProfilePicView(pubkey: damus_state.pubkey, size: 60, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
ProfilePicView(pubkey: damus_state.pubkey, size: 60, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
||||||
|
@ -145,7 +145,7 @@ struct WalletView: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
|
|
||||||
EventProfile(damus_state: damus_state, pubkey: damus_state.pubkey, profile: damus_state.profiles.lookup(id: damus_state.pubkey), size: .small)
|
EventProfile(damus_state: damus_state, pubkey: damus_state.pubkey, size: .small)
|
||||||
}
|
}
|
||||||
.padding(25)
|
.padding(25)
|
||||||
}
|
}
|
||||||
@ -164,17 +164,20 @@ struct WalletView: View {
|
|||||||
model.initial_percent = settings.donation_percent
|
model.initial_percent = settings.donation_percent
|
||||||
}
|
}
|
||||||
.onChange(of: settings.donation_percent) { p in
|
.onChange(of: settings.donation_percent) { p in
|
||||||
guard let profile = damus_state.profiles.lookup(id: damus_state.pubkey) else {
|
let profile_txn = damus_state.profiles.lookup(id: damus_state.pubkey)
|
||||||
|
guard let profile = profile_txn.unsafeUnownedValue else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let prof = Profile(name: profile.name, display_name: profile.display_name, about: profile.about, picture: profile.picture, banner: profile.banner, website: profile.website, lud06: profile.lud06, lud16: profile.lud16, nip05: profile.nip05, damus_donation: p, reactions: profile.reactions)
|
let prof = Profile(name: profile.name, display_name: profile.display_name, about: profile.about, picture: profile.picture, banner: profile.banner, website: profile.website, lud06: profile.lud06, lud16: profile.lud16, nip05: profile.nip05, damus_donation: p, reactions: profile.reactions)
|
||||||
|
|
||||||
notify(.profile_updated(pubkey: damus_state.pubkey, profile: prof))
|
notify(.profile_updated(.manual(pubkey: self.damus_state.pubkey, profile: prof)))
|
||||||
}
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
|
let profile_txn = damus_state.profiles.lookup(id: damus_state.pubkey)
|
||||||
|
|
||||||
guard let keypair = damus_state.keypair.to_full(),
|
guard let keypair = damus_state.keypair.to_full(),
|
||||||
let profile = damus_state.profiles.lookup(id: damus_state.pubkey),
|
let profile = profile_txn.unsafeUnownedValue,
|
||||||
model.initial_percent != profile.damus_donation
|
model.initial_percent != profile.damus_donation
|
||||||
else {
|
else {
|
||||||
return
|
return
|
||||||
|
@ -117,7 +117,8 @@ func zap_type_desc(type: ZapType, profiles: Profiles, pubkey: Pubkey) -> String
|
|||||||
case .anon:
|
case .anon:
|
||||||
return NSLocalizedString("No one will see that you zapped", comment: "Description of anonymous zap type where the zap is sent anonymously and does not identify the user who sent it.")
|
return NSLocalizedString("No one will see that you zapped", comment: "Description of anonymous zap type where the zap is sent anonymously and does not identify the user who sent it.")
|
||||||
case .priv:
|
case .priv:
|
||||||
let prof = profiles.lookup(id: pubkey)
|
let prof_txn = profiles.lookup(id: pubkey)
|
||||||
|
let prof = prof_txn.unsafeUnownedValue
|
||||||
let name = Profile.displayName(profile: prof, pubkey: pubkey).username.truncate(maxLength: 50)
|
let name = Profile.displayName(profile: prof, pubkey: pubkey).username.truncate(maxLength: 50)
|
||||||
return String.localizedStringWithFormat(NSLocalizedString("private_zap_description", value: "Only '%@' will see that you zapped them", comment: "Description of private zap type where the zap is sent privately and does not identify the user to the public."), name)
|
return String.localizedStringWithFormat(NSLocalizedString("private_zap_description", value: "Only '%@' will see that you zapped them", comment: "Description of private zap type where the zap is sent privately and does not identify the user to the public."), name)
|
||||||
case .non_zap:
|
case .non_zap:
|
||||||
|
@ -49,44 +49,130 @@ class Ndb {
|
|||||||
self.ndb = ndb
|
self.ndb = ndb
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookup_note_by_key(_ key: UInt64) -> NdbNote? {
|
func lookup_note_by_key_with_txn<Y>(_ key: NoteKey, txn: NdbTxn<Y>) -> NdbNote? {
|
||||||
guard let note_p = ndb_get_note_by_key(ndb.ndb, key, nil) else {
|
guard let note_p = ndb_get_note_by_key(&txn.txn, key, nil) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return NdbNote(note: note_p, owned_size: nil)
|
return NdbNote(note: note_p, owned_size: nil, key: key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookup_note(_ id: NoteId) -> NdbNote? {
|
func lookup_note_by_key(_ key: NoteKey) -> NdbTxn<NdbNote?> {
|
||||||
id.id.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) -> NdbNote? in
|
return NdbTxn(ndb: self) { txn in
|
||||||
guard let baseAddress = ptr.baseAddress,
|
lookup_note_by_key_with_txn(key, txn: txn)
|
||||||
let note_p = ndb_get_note_by_id(ndb.ndb, baseAddress, nil) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return NdbNote(note: note_p, owned_size: nil)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookup_profile(_ pubkey: Pubkey) -> ProfileRecord? {
|
private func lookup_profile_by_key_inner<Y>(_ key: ProfileKey, txn: NdbTxn<Y>) -> ProfileRecord? {
|
||||||
|
var size: Int = 0
|
||||||
|
guard let profile_p = ndb_get_profile_by_key(&txn.txn, key, &size) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return profile_flatbuf_to_record(ptr: profile_p, size: size, key: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func profile_flatbuf_to_record(ptr: UnsafeMutableRawPointer, size: Int, key: UInt64) -> ProfileRecord? {
|
||||||
|
do {
|
||||||
|
var buf = ByteBuffer(assumingMemoryBound: ptr, capacity: size)
|
||||||
|
let rec: NdbProfileRecord = try getDebugCheckedRoot(byteBuffer: &buf)
|
||||||
|
return ProfileRecord(data: rec, key: key)
|
||||||
|
} catch {
|
||||||
|
// Handle error appropriately
|
||||||
|
print("UNUSUAL: \(error)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func lookup_note_with_txn_inner<Y>(id: NoteId, txn: NdbTxn<Y>) -> NdbNote? {
|
||||||
|
return id.id.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) -> NdbNote? in
|
||||||
|
var key: UInt64 = 0
|
||||||
|
guard let baseAddress = ptr.baseAddress,
|
||||||
|
let note_p = ndb_get_note_by_id(&txn.txn, baseAddress, nil, &key) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return NdbNote(note: note_p, owned_size: nil, key: key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func lookup_profile_with_txn_inner<Y>(pubkey: Pubkey, txn: NdbTxn<Y>) -> ProfileRecord? {
|
||||||
return pubkey.id.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) -> ProfileRecord? in
|
return pubkey.id.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) -> ProfileRecord? in
|
||||||
var size: Int = 0
|
var size: Int = 0
|
||||||
|
var key: UInt64 = 0
|
||||||
|
|
||||||
guard let baseAddress = ptr.baseAddress,
|
guard let baseAddress = ptr.baseAddress,
|
||||||
let profile_p = ndb_get_profile_by_pubkey(ndb.ndb, baseAddress, &size)
|
let profile_p = ndb_get_profile_by_pubkey(&txn.txn, baseAddress, &size, &key)
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
return profile_flatbuf_to_record(ptr: profile_p, size: size, key: key)
|
||||||
var buf = ByteBuffer(assumingMemoryBound: profile_p, capacity: size)
|
|
||||||
let rec: NdbProfileRecord = try getDebugCheckedRoot(byteBuffer: &buf)
|
|
||||||
return ProfileRecord(data: rec)
|
|
||||||
} catch {
|
|
||||||
// Handle error appropriately
|
|
||||||
print("UNUSUAL: \(error)")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lookup_profile_by_key_with_txn<Y>(key: ProfileKey, txn: NdbTxn<Y>) -> ProfileRecord? {
|
||||||
|
lookup_profile_by_key_inner(key, txn: txn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup_profile_by_key(key: ProfileKey) -> NdbTxn<ProfileRecord?> {
|
||||||
|
return NdbTxn(ndb: self) { txn in
|
||||||
|
lookup_profile_by_key_inner(key, txn: txn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup_note_with_txn<Y>(id: NoteId, txn: NdbTxn<Y>) -> NdbNote? {
|
||||||
|
lookup_note_with_txn_inner(id: id, txn: txn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup_profile_key(_ pubkey: Pubkey) -> ProfileKey? {
|
||||||
|
return NdbTxn(ndb: self) { txn in
|
||||||
|
lookup_profile_key_with_txn(pubkey, txn: txn)
|
||||||
|
}.value
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup_profile_key_with_txn<Y>(_ pubkey: Pubkey, txn: NdbTxn<Y>) -> ProfileKey? {
|
||||||
|
return pubkey.id.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) -> NoteKey? in
|
||||||
|
guard let p = ptr.baseAddress else { return nil }
|
||||||
|
let r = ndb_get_profilekey_by_pubkey(&txn.txn, p)
|
||||||
|
if r == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup_note_key_with_txn<Y>(_ id: NoteId, txn: NdbTxn<Y>) -> NoteKey? {
|
||||||
|
return id.id.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) -> NoteKey? in
|
||||||
|
guard let p = ptr.baseAddress else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let r = ndb_get_notekey_by_id(&txn.txn, p)
|
||||||
|
if r == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup_note_key(_ id: NoteId) -> NoteKey? {
|
||||||
|
NdbTxn(ndb: self, with: { txn in lookup_note_key_with_txn(id, txn: txn) }).value
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup_note(_ id: NoteId) -> NdbTxn<NdbNote?> {
|
||||||
|
return NdbTxn(ndb: self) { txn in
|
||||||
|
lookup_note_with_txn_inner(id: id, txn: txn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup_profile(_ pubkey: Pubkey) -> NdbTxn<ProfileRecord?> {
|
||||||
|
return NdbTxn(ndb: self) { txn in
|
||||||
|
lookup_profile_with_txn_inner(pubkey: pubkey, txn: txn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup_profile_with_txn<Y>(_ pubkey: Pubkey, txn: NdbTxn<Y>) -> ProfileRecord? {
|
||||||
|
lookup_profile_with_txn_inner(pubkey: pubkey, txn: txn)
|
||||||
|
}
|
||||||
|
|
||||||
func process_event(_ str: String) -> Bool {
|
func process_event(_ str: String) -> Bool {
|
||||||
return str.withCString { cstr in
|
return str.withCString { cstr in
|
||||||
return ndb_process_event(ndb.ndb, cstr, Int32(str.utf8.count)) != 0
|
return ndb_process_event(ndb.ndb, cstr, Int32(str.utf8.count)) != 0
|
||||||
@ -106,7 +192,7 @@ class Ndb {
|
|||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
func getDebugCheckedRoot<T: FlatBufferObject & Verifiable>(byteBuffer: inout ByteBuffer) throws -> T {
|
func getDebugCheckedRoot<T: FlatBufferObject & Verifiable>(byteBuffer: inout ByteBuffer) throws -> T {
|
||||||
return try getCheckedRoot(byteBuffer: &byteBuffer)
|
return try getRoot(byteBuffer: &byteBuffer)
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
func getDebugCheckedRoot<T: FlatBufferObject>(byteBuffer: inout ByteBuffer) throws -> T {
|
func getDebugCheckedRoot<T: FlatBufferObject>(byteBuffer: inout ByteBuffer) throws -> T {
|
||||||
|
@ -38,6 +38,7 @@ class NdbNote: Encodable, Equatable, Hashable {
|
|||||||
// we can have owned notes, but we can also have lmdb virtual-memory mapped notes so its optional
|
// we can have owned notes, but we can also have lmdb virtual-memory mapped notes so its optional
|
||||||
private let owned: Bool
|
private let owned: Bool
|
||||||
let count: Int
|
let count: Int
|
||||||
|
let key: NoteKey?
|
||||||
let note: UnsafeMutablePointer<ndb_note>
|
let note: UnsafeMutablePointer<ndb_note>
|
||||||
|
|
||||||
// cached stuff (TODO: remove these)
|
// cached stuff (TODO: remove these)
|
||||||
@ -48,10 +49,11 @@ class NdbNote: Encodable, Equatable, Hashable {
|
|||||||
return NdbNote.owned_from_json_cstr(json: content_raw, json_len: content_len)
|
return NdbNote.owned_from_json_cstr(json: content_raw, json_len: content_len)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
init(note: UnsafeMutablePointer<ndb_note>, owned_size: Int?) {
|
init(note: UnsafeMutablePointer<ndb_note>, owned_size: Int?, key: NoteKey?) {
|
||||||
self.note = note
|
self.note = note
|
||||||
self.owned = owned_size != nil
|
self.owned = owned_size != nil
|
||||||
self.count = owned_size ?? 0
|
self.count = owned_size ?? 0
|
||||||
|
self.key = key
|
||||||
|
|
||||||
#if DEBUG_NOTE_SIZE
|
#if DEBUG_NOTE_SIZE
|
||||||
if let owned_size {
|
if let owned_size {
|
||||||
@ -218,6 +220,7 @@ class NdbNote: Encodable, Equatable, Hashable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.note = r.assumingMemoryBound(to: ndb_note.self)
|
self.note = r.assumingMemoryBound(to: ndb_note.self)
|
||||||
|
self.key = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
static func owned_from_json(json: String, bufsize: Int = 2 << 18) -> NdbNote? {
|
static func owned_from_json(json: String, bufsize: Int = 2 << 18) -> NdbNote? {
|
||||||
@ -245,7 +248,7 @@ class NdbNote: Encodable, Equatable, Hashable {
|
|||||||
guard let note_data = realloc(data, Int(len)) else { return nil }
|
guard let note_data = realloc(data, Int(len)) else { return nil }
|
||||||
let new_note = note_data.assumingMemoryBound(to: ndb_note.self)
|
let new_note = note_data.assumingMemoryBound(to: ndb_note.self)
|
||||||
|
|
||||||
return NdbNote(note: new_note, owned_size: Int(len))
|
return NdbNote(note: new_note, owned_size: Int(len), key: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ struct TagsSequence: Encodable, Sequence {
|
|||||||
}
|
}
|
||||||
precondition(false, "sequence subscript oob")
|
precondition(false, "sequence subscript oob")
|
||||||
// it seems like the compiler needs this or it gets bitchy
|
// it seems like the compiler needs this or it gets bitchy
|
||||||
return .init(note: .init(note: .allocate(capacity: 1), owned_size: nil), tag: .allocate(capacity: 1))
|
return .init(note: .init(note: .allocate(capacity: 1), owned_size: nil, key: nil), tag: .allocate(capacity: 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeIterator() -> TagsIterator {
|
func makeIterator() -> TagsIterator {
|
||||||
|
@ -17,7 +17,7 @@ class NdbTxn<T> {
|
|||||||
private var val: T!
|
private var val: T!
|
||||||
var moved: Bool
|
var moved: Bool
|
||||||
|
|
||||||
init(ndb: Ndb, with: (NdbTxn<T>) -> T) {
|
init(ndb: Ndb, with: (NdbTxn<T>) -> T = { _ in () }) {
|
||||||
self.txn = ndb_txn()
|
self.txn = ndb_txn()
|
||||||
#if TXNDEBUG
|
#if TXNDEBUG
|
||||||
txn_count += 1
|
txn_count += 1
|
||||||
|
@ -264,7 +264,9 @@ int ndb_get_tsid(MDB_txn *txn, struct ndb_lmdb *lmdb, enum ndb_dbs db,
|
|||||||
int success = 0;
|
int success = 0;
|
||||||
struct ndb_tsid tsid;
|
struct ndb_tsid tsid;
|
||||||
|
|
||||||
|
// position at the most recent
|
||||||
ndb_tsid_high(&tsid, id);
|
ndb_tsid_high(&tsid, id);
|
||||||
|
|
||||||
k.mv_data = &tsid;
|
k.mv_data = &tsid;
|
||||||
k.mv_size = sizeof(tsid);
|
k.mv_size = sizeof(tsid);
|
||||||
|
|
||||||
@ -341,32 +343,44 @@ static void *ndb_lookup_tsid(struct ndb_txn *txn, enum ndb_dbs ind,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ndb_get_profile_by_pubkey(struct ndb_txn *txn, const unsigned char *pk, size_t *len, uint32_t *key)
|
void *ndb_get_profile_by_pubkey(struct ndb_txn *txn, const unsigned char *pk, size_t *len, uint64_t *key)
|
||||||
{
|
{
|
||||||
return ndb_lookup_tsid(txn, NDB_DB_PROFILE_PK, NDB_DB_PROFILE, pk, len, key);
|
return ndb_lookup_tsid(txn, NDB_DB_PROFILE_PK, NDB_DB_PROFILE, pk, len, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ndb_note *ndb_get_note_by_id(struct ndb_txn *txn, const unsigned char *id, size_t *len, uint32_t *key)
|
struct ndb_note *ndb_get_note_by_id(struct ndb_txn *txn, const unsigned char *id, size_t *len, uint64_t *key)
|
||||||
{
|
{
|
||||||
return ndb_lookup_tsid(txn, NDB_DB_NOTE_ID, NDB_DB_NOTE, id, len, key);
|
return ndb_lookup_tsid(txn, NDB_DB_NOTE_ID, NDB_DB_NOTE, id, len, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ndb_get_notekey_by_id(struct ndb_txn *txn, const unsigned char *id)
|
static inline uint64_t ndb_get_indexkey_by_id(struct ndb_txn *txn,
|
||||||
|
enum ndb_dbs db,
|
||||||
|
const unsigned char *id)
|
||||||
{
|
{
|
||||||
MDB_val k;
|
MDB_val k;
|
||||||
|
|
||||||
if (!ndb_get_tsid(txn->mdb_txn, &txn->ndb->lmdb, NDB_DB_NOTE_ID, id, &k))
|
if (!ndb_get_tsid(txn->mdb_txn, &txn->ndb->lmdb, db, id, &k))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return *(uint32_t*)k.mv_data;
|
return *(uint32_t*)k.mv_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ndb_note *ndb_get_note_by_key(struct ndb_txn *txn, uint32_t key, size_t *len)
|
uint64_t ndb_get_notekey_by_id(struct ndb_txn *txn, const unsigned char *id)
|
||||||
|
{
|
||||||
|
return ndb_get_indexkey_by_id(txn, NDB_DB_NOTE_ID, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ndb_get_profilekey_by_pubkey(struct ndb_txn *txn, const unsigned char *id)
|
||||||
|
{
|
||||||
|
return ndb_get_indexkey_by_id(txn, NDB_DB_PROFILE_PK, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ndb_note *ndb_get_note_by_key(struct ndb_txn *txn, uint64_t key, size_t *len)
|
||||||
{
|
{
|
||||||
return ndb_lookup_by_key(txn, key, NDB_DB_NOTE, len);
|
return ndb_lookup_by_key(txn, key, NDB_DB_NOTE, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ndb_get_profile_by_key(struct ndb_txn *txn, uint32_t key, size_t *len)
|
void *ndb_get_profile_by_key(struct ndb_txn *txn, uint64_t key, size_t *len)
|
||||||
{
|
{
|
||||||
return ndb_lookup_by_key(txn, key, NDB_DB_PROFILE, len);
|
return ndb_lookup_by_key(txn, key, NDB_DB_PROFILE, len);
|
||||||
}
|
}
|
||||||
|
@ -166,6 +166,7 @@ void ndb_end_query(struct ndb_txn *);
|
|||||||
void *ndb_get_profile_by_pubkey(struct ndb_txn *txn, const unsigned char *pubkey, size_t *len, uint64_t *primkey);
|
void *ndb_get_profile_by_pubkey(struct ndb_txn *txn, const unsigned char *pubkey, size_t *len, uint64_t *primkey);
|
||||||
void *ndb_get_profile_by_key(struct ndb_txn *txn, uint64_t key, size_t *len);
|
void *ndb_get_profile_by_key(struct ndb_txn *txn, uint64_t key, size_t *len);
|
||||||
uint64_t ndb_get_notekey_by_id(struct ndb_txn *txn, const unsigned char *id);
|
uint64_t ndb_get_notekey_by_id(struct ndb_txn *txn, const unsigned char *id);
|
||||||
|
uint64_t ndb_get_profilekey_by_pubkey(struct ndb_txn *txn, const unsigned char *id);
|
||||||
struct ndb_note *ndb_get_note_by_id(struct ndb_txn *txn, const unsigned char *id, size_t *len, uint64_t *primkey);
|
struct ndb_note *ndb_get_note_by_id(struct ndb_txn *txn, const unsigned char *id, size_t *len, uint64_t *primkey);
|
||||||
struct ndb_note *ndb_get_note_by_key(struct ndb_txn *txn, uint64_t key, size_t *len);
|
struct ndb_note *ndb_get_note_by_key(struct ndb_txn *txn, uint64_t key, size_t *len);
|
||||||
void ndb_destroy(struct ndb *);
|
void ndb_destroy(struct ndb *);
|
||||||
|
Loading…
Reference in New Issue
Block a user