NIP05DomainTimelineHeaderView.swift (4635B)
1 // 2 // NIP05DomainTimelineHeaderView.swift 3 // damus 4 // 5 // Created by Terry Yiu on 5/16/25. 6 // 7 8 import FaviconFinder 9 import Kingfisher 10 import SwiftUI 11 12 struct NIP05DomainTimelineHeaderView: View { 13 let damus_state: DamusState 14 @ObservedObject var model: NIP05DomainEventsModel 15 let nip05_domain_favicon: FaviconURL? 16 17 @Environment(\.openURL) var openURL 18 19 var Icon: some View { 20 ZStack { 21 if let nip05_domain_favicon { 22 KFImage(nip05_domain_favicon.source) 23 .imageContext(.favicon, disable_animation: true) 24 .resizable() 25 .aspectRatio(contentMode: .fit) 26 .frame(width: 18, height: 18) 27 .clipped() 28 } else { 29 EmptyView() 30 } 31 } 32 } 33 34 var friendsOfFriends: [Pubkey] { 35 // Order it such that the pubkeys that have events come first in the array so that their profile pictures 36 // show first. 37 let pubkeys = model.events.all_events.map { $0.pubkey } + (model.filter.authors ?? []) 38 39 // Filter out duplicates but retain order, and filter out any that do not have a validated NIP-05. 40 return (NSMutableOrderedSet(array: pubkeys).array as? [Pubkey] ?? []) 41 .filter { 42 damus_state.contacts.is_in_friendosphere($0) && damus_state.profiles.is_validated($0) != nil 43 } 44 } 45 46 var body: some View { 47 VStack(alignment: .leading) { 48 HStack { 49 if nip05_domain_favicon != nil { 50 Icon 51 } 52 53 Text(model.domain) 54 .foregroundStyle(DamusLogoGradient.gradient) 55 .font(.title.bold()) 56 .onTapGesture { 57 if let url = URL(string: "https://\(model.domain)") { 58 openURL(url) 59 } 60 } 61 } 62 63 let friendsOfFriends = friendsOfFriends 64 65 HStack { 66 CondensedProfilePicturesView(state: damus_state, pubkeys: friendsOfFriends, maxPictures: 3) 67 let friendsOfFriendsString = friendsOfFriendsString(friendsOfFriends, ndb: damus_state.ndb) 68 Text(friendsOfFriendsString) 69 .font(.subheadline) 70 .foregroundColor(.gray) 71 .multilineTextAlignment(.leading) 72 } 73 .onTapGesture { 74 if !friendsOfFriends.isEmpty { 75 damus_state.nav.push(route: Route.NIP05DomainPubkeys(domain: model.domain, nip05_domain_favicon: nip05_domain_favicon, pubkeys: friendsOfFriends)) 76 } 77 } 78 } 79 } 80 } 81 82 func friendsOfFriendsString(_ friendsOfFriends: [Pubkey], ndb: Ndb, locale: Locale = Locale.current) -> String { 83 let bundle = bundleForLocale(locale: locale) 84 let names: [String] = friendsOfFriends.prefix(3).map { pk in 85 let profile = ndb.lookup_profile(pk)?.unsafeUnownedValue?.profile 86 return Profile.displayName(profile: profile, pubkey: pk).username.truncate(maxLength: 20) 87 } 88 89 switch friendsOfFriends.count { 90 case 0: 91 return "No one in your trusted network is associated with this domain." 92 case 1: 93 let format = NSLocalizedString("Notes from %@", bundle: bundle, comment: "Text to indicate that notes from one pubkey in our trusted network are shown below.") 94 return String(format: format, locale: locale, names[0]) 95 case 2: 96 let format = NSLocalizedString("Notes from %@ & %@", bundle: bundle, comment: "Text to indicate that notes from two pubkeys in our trusted network are shown below.") 97 return String(format: format, locale: locale, names[0], names[1]) 98 case 3: 99 let format = NSLocalizedString("Notes from %@, %@ & %@", bundle: bundle, comment: "Text to indicate that notes from three pubkeys in our trusted network are shown below.") 100 return String(format: format, locale: locale, names[0], names[1], names[2]) 101 default: 102 let format = localizedStringFormat(key: "notes_from_three_and_others", locale: locale) 103 return String(format: format, locale: locale, friendsOfFriends.count - 3, names[0], names[1], names[2]) 104 } 105 } 106 107 #Preview { 108 let model = NIP05DomainEventsModel(state: test_damus_state, domain: "damus.io") 109 let nip05_domain_favicon = FaviconURL(source: URL(string: "https://damus.io/favicon.ico")!, format: .ico, sourceType: .ico) 110 NIP05DomainTimelineHeaderView(damus_state: test_damus_state, model: model, nip05_domain_favicon: nip05_domain_favicon) 111 }