damus

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

ProfilePicView.swift (5377B)


      1 //
      2 //  ProfilePicView.swift
      3 //  damus
      4 //
      5 //  Created by William Casarin on 2022-04-16.
      6 //
      7 
      8 import SwiftUI
      9 import Kingfisher
     10 
     11 let PFP_SIZE: CGFloat = 52.0
     12 
     13 func highlight_color(_ h: Highlight) -> Color {
     14     switch h {
     15     case .main: return Color.red
     16     case .reply: return Color.black
     17     case .none: return Color.black
     18     case .custom(let c, _): return c
     19     }
     20 }
     21 
     22 func pfp_line_width(_ h: Highlight) -> CGFloat {
     23     switch h {
     24     case .reply: return 0
     25     case .none: return 0
     26     case .main: return 3
     27     case .custom(_, let lw): return CGFloat(lw)
     28     }
     29 }
     30 
     31 struct InnerProfilePicView: View {
     32     let url: URL?
     33     let fallbackUrl: URL?
     34     let pubkey: Pubkey
     35     let size: CGFloat
     36     let highlight: Highlight
     37     let disable_animation: Bool
     38 
     39     var Placeholder: some View {
     40         Circle()
     41             .frame(width: size, height: size)
     42             .foregroundColor(DamusColors.mediumGrey)
     43             .overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))
     44             .padding(2)
     45     }
     46 
     47     var body: some View {
     48         KFAnimatedImage(url)
     49             .imageContext(.pfp, disable_animation: disable_animation)
     50             .onFailure(fallbackUrl: fallbackUrl, cacheKey: url?.absoluteString)
     51             .cancelOnDisappear(true)
     52             .configure { view in
     53                 view.framePreloadCount = 3
     54             }
     55             .placeholder { _ in
     56                 Placeholder
     57             }
     58             .scaledToFill()
     59         .frame(width: size, height: size)
     60         .clipShape(Circle())
     61         .overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))
     62     }
     63 }
     64 
     65 
     66 struct ProfilePicView: View {
     67     let pubkey: Pubkey
     68     let size: CGFloat
     69     let highlight: Highlight
     70     let profiles: Profiles
     71     let disable_animation: Bool
     72     let zappability_indicator: Bool
     73     
     74     @State var picture: String?
     75     
     76     init(pubkey: Pubkey, size: CGFloat, highlight: Highlight, profiles: Profiles, disable_animation: Bool, picture: String? = nil, show_zappability: Bool? = nil) {
     77         self.pubkey = pubkey
     78         self.profiles = profiles
     79         self.size = size
     80         self.highlight = highlight
     81         self._picture = State(initialValue: picture)
     82         self.disable_animation = disable_animation
     83         self.zappability_indicator = show_zappability ?? false
     84     }
     85     
     86     func get_lnurl() -> String? {
     87         return profiles.lookup_with_timestamp(pubkey)?.unsafeUnownedValue?.lnurl
     88     }
     89     
     90     var body: some View {
     91         ZStack (alignment: Alignment(horizontal: .trailing, vertical: .bottom)) {
     92             InnerProfilePicView(url: get_profile_url(picture: picture, pubkey: pubkey, profiles: profiles), fallbackUrl: URL(string: robohash(pubkey)), pubkey: pubkey, size: size, highlight: highlight, disable_animation: disable_animation)
     93                 .onReceive(handle_notify(.profile_updated)) { updated in
     94                     guard updated.pubkey == self.pubkey else {
     95                         return
     96                     }
     97                     
     98                     switch updated {
     99                         case .manual(_, let profile):
    100                             if let pic = profile.picture {
    101                                 self.picture = pic
    102                             }
    103                         case .remote(pubkey: let pk):
    104                             let profile_txn = profiles.lookup(id: pk)
    105                             let profile = profile_txn?.unsafeUnownedValue
    106                             if let pic = profile?.picture {
    107                                 self.picture = pic
    108                             }
    109                     }
    110                 }
    111             
    112             if self.zappability_indicator, let lnurl = self.get_lnurl(), lnurl != "" {
    113                 Image("zap.fill")
    114                     .resizable()
    115                     .frame(
    116                         width: size * 0.24,
    117                         height: size * 0.24
    118                     )
    119                     .padding(size * 0.04)
    120                     .foregroundColor(.white)
    121                     .background(Color.orange)
    122                     .clipShape(Circle())
    123             }
    124         }
    125     }
    126 }
    127 
    128 func get_profile_url(picture: String?, pubkey: Pubkey, profiles: Profiles) -> URL {
    129     let pic = picture ?? profiles.lookup(id: pubkey, txn_name: "get_profile_url")?.map({ $0?.picture }).value ?? robohash(pubkey)
    130     if let url = URL(string: pic) {
    131         return url
    132     }
    133     return URL(string: robohash(pubkey))!
    134 }
    135 
    136 func make_preview_profiles(_ pubkey: Pubkey) -> Profiles {
    137     let profiles = Profiles(ndb: test_damus_state.ndb)
    138     //let picture = "http://cdn.jb55.com/img/red-me.jpg"
    139     //let profile = Profile(name: "jb55", display_name: "William Casarin", about: "It's me", picture: picture, banner: "", website: "https://jb55.com", lud06: nil, lud16: nil, nip05: "jb55.com", damus_donation: nil)
    140     //let ts_profile = TimestampedProfile(profile: profile, timestamp: 0, event: test_note)
    141     //profiles.add(id: pubkey, profile: ts_profile)
    142     return profiles
    143 }
    144 
    145 struct ProfilePicView_Previews: PreviewProvider {
    146     static let pubkey = test_note.pubkey
    147 
    148     static var previews: some View {
    149         ProfilePicView(
    150             pubkey: pubkey,
    151             size: 100,
    152             highlight: .none,
    153             profiles: make_preview_profiles(pubkey),
    154             disable_animation: false
    155         )
    156     }
    157 }