damus

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

ProfilePicView.swift (5400B)


      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         .kfClickable()
     61         .clipShape(Circle())
     62         .overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))
     63     }
     64 }
     65 
     66 
     67 struct ProfilePicView: View {
     68     let pubkey: Pubkey
     69     let size: CGFloat
     70     let highlight: Highlight
     71     let profiles: Profiles
     72     let disable_animation: Bool
     73     let zappability_indicator: Bool
     74     
     75     @State var picture: String?
     76     
     77     init(pubkey: Pubkey, size: CGFloat, highlight: Highlight, profiles: Profiles, disable_animation: Bool, picture: String? = nil, show_zappability: Bool? = nil) {
     78         self.pubkey = pubkey
     79         self.profiles = profiles
     80         self.size = size
     81         self.highlight = highlight
     82         self._picture = State(initialValue: picture)
     83         self.disable_animation = disable_animation
     84         self.zappability_indicator = show_zappability ?? false
     85     }
     86     
     87     func get_lnurl() -> String? {
     88         return profiles.lookup_with_timestamp(pubkey)?.unsafeUnownedValue?.lnurl
     89     }
     90     
     91     var body: some View {
     92         ZStack (alignment: Alignment(horizontal: .trailing, vertical: .bottom)) {
     93             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)
     94                 .onReceive(handle_notify(.profile_updated)) { updated in
     95                     guard updated.pubkey == self.pubkey else {
     96                         return
     97                     }
     98                     
     99                     switch updated {
    100                         case .manual(_, let profile):
    101                             if let pic = profile.picture {
    102                                 self.picture = pic
    103                             }
    104                         case .remote(pubkey: let pk):
    105                             let profile_txn = profiles.lookup(id: pk)
    106                             let profile = profile_txn?.unsafeUnownedValue
    107                             if let pic = profile?.picture {
    108                                 self.picture = pic
    109                             }
    110                     }
    111                 }
    112             
    113             if self.zappability_indicator, let lnurl = self.get_lnurl(), lnurl != "" {
    114                 Image("zap.fill")
    115                     .resizable()
    116                     .frame(
    117                         width: size * 0.24,
    118                         height: size * 0.24
    119                     )
    120                     .padding(size * 0.04)
    121                     .foregroundColor(.white)
    122                     .background(Color.orange)
    123                     .clipShape(Circle())
    124             }
    125         }
    126     }
    127 }
    128 
    129 func get_profile_url(picture: String?, pubkey: Pubkey, profiles: Profiles) -> URL {
    130     let pic = picture ?? profiles.lookup(id: pubkey, txn_name: "get_profile_url")?.map({ $0?.picture }).value ?? robohash(pubkey)
    131     if let url = URL(string: pic) {
    132         return url
    133     }
    134     return URL(string: robohash(pubkey))!
    135 }
    136 
    137 func make_preview_profiles(_ pubkey: Pubkey) -> Profiles {
    138     let profiles = Profiles(ndb: test_damus_state.ndb)
    139     //let picture = "http://cdn.jb55.com/img/red-me.jpg"
    140     //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)
    141     //let ts_profile = TimestampedProfile(profile: profile, timestamp: 0, event: test_note)
    142     //profiles.add(id: pubkey, profile: ts_profile)
    143     return profiles
    144 }
    145 
    146 struct ProfilePicView_Previews: PreviewProvider {
    147     static let pubkey = test_note.pubkey
    148 
    149     static var previews: some View {
    150         ProfilePicView(
    151             pubkey: pubkey,
    152             size: 100,
    153             highlight: .none,
    154             profiles: make_preview_profiles(pubkey),
    155             disable_animation: false
    156         )
    157     }
    158 }