damus

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

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 }