Profile Banner Images

Changelog-Added: Profile banner images
Closes: #302
This commit is contained in:
Jason Jōb
2023-01-10 15:12:34 -08:00
committed by William Casarin
parent 33383265c8
commit 9d44ed0bfe
8 changed files with 151 additions and 15 deletions

View File

@@ -0,0 +1,85 @@
//
// BannerImageView.swift
// damus
//
// Created by Jason Jōb on 2023-01-10.
//
import SwiftUI
import Kingfisher
struct InnerBannerImageView: View {
let url: URL?
let pubkey: String
var body: some View {
ZStack {
Color(uiColor: .systemBackground)
if (url != nil) {
KFAnimatedImage(url)
.callbackQueue(.dispatch(.global(qos: .background)))
.processingQueue(.dispatch(.global(qos: .background)))
.appendProcessor(LargeImageProcessor.shared)
.configure { view in
view.framePreloadCount = 1
}
.placeholder { _ in
Image("profile-banner").resizable()
}
.scaleFactor(UIScreen.main.scale)
.loadDiskFileSynchronously()
.fade(duration: 0.1)
} else {
Image("profile-banner").resizable()
}
}
}
}
struct BannerImageView: View {
let pubkey: String
let profiles: Profiles
@State var banner: String?
init (pubkey: String, profiles: Profiles, banner: String? = nil) {
self.pubkey = pubkey
self.profiles = profiles
self._banner = State(initialValue: banner)
}
var body: some View {
InnerBannerImageView(url: get_banner_url(banner: banner, pubkey: pubkey, profiles: profiles), pubkey: pubkey)
.onReceive(handle_notify(.profile_updated)) { notif in
let updated = notif.object as! ProfileUpdate
guard updated.pubkey == self.pubkey else {
return
}
if let bannerImage = updated.profile.banner {
self.banner = bannerImage
}
}
}
}
func get_banner_url(banner: String?, pubkey: String, profiles: Profiles) -> URL? {
let bannerUrlString = banner ?? profiles.lookup(id: pubkey)?.banner ?? ""
if let url = URL(string: bannerUrlString) {
return url
}
return nil
}
struct BannerImageView_Previews: PreviewProvider {
static let pubkey = "ca48854ac6555fed8e439ebb4fa2d928410e0eef13fa41164ec45aaaa132d846"
static var previews: some View {
BannerImageView(
pubkey: pubkey,
profiles: make_preview_profiles(pubkey))
}
}

View File

@@ -8,6 +8,7 @@
import SwiftUI
let PPM_SIZE: CGFloat = 80.0
let BANNER_HEIGHT: CGFloat = 150.0;
func isHttpsUrl(_ string: String) -> Bool {
let urlRegEx = "^https://.*$"
@@ -56,12 +57,14 @@ struct EditMetadataView: View {
@State var display_name: String
@State var about: String
@State var picture: String
@State var banner: String
@State var nip05: String
@State var name: String
@State var ln: String
@State var website: String
@Environment(\.dismiss) var dismiss
@Environment(\.colorScheme) var colorScheme
init (damus_state: DamusState) {
self.damus_state = damus_state
@@ -72,10 +75,15 @@ struct EditMetadataView: View {
_about = State(initialValue: data?.about ?? "")
_website = State(initialValue: data?.website ?? "")
_picture = State(initialValue: data?.picture ?? "")
_banner = State(initialValue: data?.banner ?? "")
_nip05 = State(initialValue: data?.nip05 ?? "")
_ln = State(initialValue: data?.lud16 ?? data?.lud06 ?? "")
}
func imageBorderColor() -> Color {
colorScheme == .light ? Color("DamusWhite") : Color("DamusBlack")
}
func save() {
let metadata = NostrMetadata(
display_name: display_name,
@@ -84,6 +92,7 @@ struct EditMetadataView: View {
website: website,
nip05: nip05.isEmpty ? nil : nip05,
picture: picture.isEmpty ? nil : picture,
banner: banner.isEmpty ? nil : banner,
lud06: ln.contains("@") ? nil : ln,
lud16: ln.contains("@") ? ln : nil
);
@@ -99,13 +108,32 @@ struct EditMetadataView: View {
return NIP05.parse(nip05)
}
var TopSection: some View {
ZStack(alignment: .top) {
GeometryReader { geo in
BannerImageView(pubkey: damus_state.pubkey, profiles: damus_state.profiles)
.aspectRatio(contentMode: .fill)
.frame(width: geo.size.width, height: BANNER_HEIGHT)
.clipped()
}.frame(height: BANNER_HEIGHT)
VStack(alignment: .leading) {
let pfp_size: CGFloat = 90.0
HStack(alignment: .center) {
ProfilePicView(pubkey: damus_state.pubkey, size: pfp_size, highlight: .custom(imageBorderColor(), 4.0), profiles: damus_state.profiles)
.offset(y: -(pfp_size/2.0)) // Increase if set a frame
Spacer()
}.padding(.bottom,-(pfp_size/2.0))
}
.padding(.horizontal,18)
.padding(.top,BANNER_HEIGHT)
}
}
var body: some View {
VStack(alignment: .leading) {
HStack {
Spacer()
InnerProfilePicView(url: URL(string: picture), fallbackUrl: nil, pubkey: damus_state.pubkey, size: PPM_SIZE, highlight: .none)
Spacer()
}
TopSection
Form {
Section(NSLocalizedString("Your Name", comment: "Label for Your Name section of user profile form.")) {
TextField("Satoshi Nakamoto", text: $display_name)
@@ -126,6 +154,12 @@ struct EditMetadataView: View {
.textInputAutocapitalization(.never)
}
Section (NSLocalizedString("Banner Image", comment: "Label for Banner Image section of user profile form.")) {
TextField(NSLocalizedString("https://example.com/pic.jpg", comment: "Placeholder example text for profile picture URL."), text: $banner)
.autocorrectionDisabled(true)
.textInputAutocapitalization(.never)
}
Section(NSLocalizedString("Website", comment: "Label for Website section of user profile form.")) {
TextField(NSLocalizedString("https://jb55.com", comment: "Placeholder example text for website URL for user profile."), text: $website)
.autocorrectionDisabled(true)
@@ -172,7 +206,7 @@ struct EditMetadataView: View {
}
}
}
.navigationTitle(NSLocalizedString("Edit Profile", comment: "Title of navigation view for Edit Profile."))
.ignoresSafeArea()
}
}

View File

@@ -182,7 +182,7 @@ func get_profile_url(picture: String?, pubkey: String, profiles: Profiles) -> UR
func make_preview_profiles(_ pubkey: String) -> Profiles {
let profiles = Profiles()
let picture = "http://cdn.jb55.com/img/red-me.jpg"
let profile = Profile(name: "jb55", display_name: "William Casarin", about: "It's me", picture: picture, website: "https://jb55.com", lud06: nil, lud16: nil, nip05: "jb55.com")
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")
let ts_profile = TimestampedProfile(profile: profile, timestamp: 0)
profiles.add(id: pubkey, profile: ts_profile)
return profiles

View File

@@ -194,15 +194,14 @@ struct ProfileView: View {
var TopSection: some View {
ZStack(alignment: .top) {
GeometryReader { geo in
Image("profile-banner")
.resizable()
BannerImageView(pubkey: damus_state.pubkey, profiles: damus_state.profiles)
.aspectRatio(contentMode: .fill)
.frame(width: geo.size.width, height: 150)
.frame(width: geo.size.width, height: BANNER_HEIGHT)
.clipped()
ShareButton
.offset(x: geo.size.width - 80.0, y: 50.0 )
}
}.frame(height: BANNER_HEIGHT)
VStack(alignment: .leading) {
let data = damus_state.profiles.lookup(id: profile.pubkey)
let pfp_size: CGFloat = 90.0
@@ -358,7 +357,7 @@ func test_damus_state() -> DamusState {
let pubkey = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
let damus = DamusState(pool: RelayPool(), keypair: Keypair(pubkey: pubkey, privkey: "privkey"), likes: EventCounter(our_pubkey: pubkey), boosts: EventCounter(our_pubkey: pubkey), contacts: Contacts(our_pubkey: pubkey), tips: TipCounter(our_pubkey: pubkey), profiles: Profiles(), dms: DirectMessagesModel(), previews: PreviewCache())
let prof = Profile(name: "damus", display_name: "damus", about: "iOS app!", picture: "https://damus.io/img/logo.png", website: "https://damus.io", lud06: nil, lud16: "jb55@sendsats.lol", nip05: "damus.io")
let prof = Profile(name: "damus", display_name: "damus", about: "iOS app!", picture: "https://damus.io/img/logo.png", banner: "", website: "https://damus.io", lud06: nil, lud16: "jb55@sendsats.lol", nip05: "damus.io")
let tsprof = TimestampedProfile(profile: prof, timestamp: 0)
damus.profiles.add(id: pubkey, profile: tsprof)
return damus