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 }