Profile Editor
Changelog-Added: Added profile edit view Changelog-Changed: Don't fetch followers right away
This commit is contained in:
@@ -58,21 +58,22 @@ struct EditMetadataView: View {
|
|||||||
@State var picture: String
|
@State var picture: String
|
||||||
@State var nip05: String
|
@State var nip05: String
|
||||||
@State var name: String
|
@State var name: String
|
||||||
@State var lud06: String
|
@State var ln: String
|
||||||
@State var lud16: String
|
@State var website: String
|
||||||
@State private var showAlert = false
|
|
||||||
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
init (damus_state: DamusState) {
|
init (damus_state: DamusState) {
|
||||||
self.damus_state = damus_state
|
self.damus_state = damus_state
|
||||||
let data = damus_state.profiles.lookup(id: damus_state.pubkey)
|
let data = damus_state.profiles.lookup(id: damus_state.pubkey)
|
||||||
|
|
||||||
name = data?.name ?? ""
|
_name = State(initialValue: data?.name ?? "")
|
||||||
display_name = data?.display_name ?? ""
|
_display_name = State(initialValue: data?.display_name ?? "")
|
||||||
about = data?.about ?? ""
|
_about = State(initialValue: data?.about ?? "")
|
||||||
picture = data?.picture ?? ""
|
_website = State(initialValue: data?.website ?? "")
|
||||||
nip05 = data?.nip05 ?? ""
|
_picture = State(initialValue: data?.picture ?? "")
|
||||||
lud06 = data?.lud06 ?? ""
|
_nip05 = State(initialValue: data?.nip05 ?? "")
|
||||||
lud16 = data?.lud16 ?? ""
|
_ln = State(initialValue: data?.lud16 ?? data?.lud06 ?? "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func save() {
|
func save() {
|
||||||
@@ -80,11 +81,11 @@ struct EditMetadataView: View {
|
|||||||
display_name: display_name,
|
display_name: display_name,
|
||||||
name: name,
|
name: name,
|
||||||
about: about,
|
about: about,
|
||||||
website: nil,
|
website: website,
|
||||||
nip05: nip05.isEmpty ? nil : nip05,
|
nip05: nip05.isEmpty ? nil : nip05,
|
||||||
picture: picture.isEmpty ? nil : picture,
|
picture: picture.isEmpty ? nil : picture,
|
||||||
lud06: lud06.isEmpty ? nil : lud06,
|
lud06: ln.contains("@") ? ln : nil,
|
||||||
lud16: lud16.isEmpty ? nil : lud16
|
lud16: ln.contains("@") ? nil : ln
|
||||||
);
|
);
|
||||||
|
|
||||||
let m_metadata_ev = make_metadata_event(keypair: damus_state.keypair, metadata: metadata)
|
let m_metadata_ev = make_metadata_event(keypair: damus_state.keypair, metadata: metadata)
|
||||||
@@ -98,10 +99,9 @@ struct EditMetadataView: View {
|
|||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
HStack {
|
HStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
ProfilePicView(pubkey: damus_state.pubkey, size: PPM_SIZE, highlight: .none, profiles: damus_state.profiles, picture: picture)
|
InnerProfilePicView(url: URL(string: picture), pubkey: damus_state.pubkey, size: PPM_SIZE, highlight: .none)
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
.padding([.top], 30)
|
|
||||||
Form {
|
Form {
|
||||||
Section("Your Name") {
|
Section("Your Name") {
|
||||||
TextField("Satoshi Nakamoto", text: $display_name)
|
TextField("Satoshi Nakamoto", text: $display_name)
|
||||||
@@ -120,7 +120,12 @@ struct EditMetadataView: View {
|
|||||||
TextField("https://example.com/pic.jpg", text: $picture)
|
TextField("https://example.com/pic.jpg", text: $picture)
|
||||||
.autocorrectionDisabled(true)
|
.autocorrectionDisabled(true)
|
||||||
.textInputAutocapitalization(.never)
|
.textInputAutocapitalization(.never)
|
||||||
|
}
|
||||||
|
|
||||||
|
Section("Website") {
|
||||||
|
TextField("https://jb55.com", text: $website)
|
||||||
|
.autocorrectionDisabled(true)
|
||||||
|
.textInputAutocapitalization(.never)
|
||||||
}
|
}
|
||||||
|
|
||||||
Section("About Me") {
|
Section("About Me") {
|
||||||
@@ -135,18 +140,11 @@ struct EditMetadataView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section(content: {
|
Section("Bitcoin Lightning Tips") {
|
||||||
TextField("Lightning Address", text: $lud16)
|
TextField("Lightning Address or LNURL", text: $ln)
|
||||||
.autocorrectionDisabled(true)
|
.autocorrectionDisabled(true)
|
||||||
.textInputAutocapitalization(.never)
|
.textInputAutocapitalization(.never)
|
||||||
TextField("LNURL", text: $lud06)
|
}
|
||||||
.autocorrectionDisabled(true)
|
|
||||||
.textInputAutocapitalization(.never)
|
|
||||||
}, header: {
|
|
||||||
Text("Bitcoin Lightning Tips")
|
|
||||||
}, footer: {
|
|
||||||
Text("Only one needs to be set")
|
|
||||||
})
|
|
||||||
|
|
||||||
Section(content: {
|
Section(content: {
|
||||||
TextField("example.com", text: $nip05)
|
TextField("example.com", text: $nip05)
|
||||||
@@ -160,12 +158,11 @@ struct EditMetadataView: View {
|
|||||||
|
|
||||||
Button("Save") {
|
Button("Save") {
|
||||||
save()
|
save()
|
||||||
showAlert = true
|
dismiss()
|
||||||
}.alert(isPresented: $showAlert) {
|
|
||||||
Alert(title: Text("Saved"), message: Text("Your metadata has been saved."), dismissButton: .default(Text("OK")))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.navigationTitle("Edit Profile")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,14 +13,9 @@ struct FollowButtonView: View {
|
|||||||
|
|
||||||
let target: FollowTarget
|
let target: FollowTarget
|
||||||
@State var follow_state: FollowState
|
@State var follow_state: FollowState
|
||||||
let perform: (() -> Void)?
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Button {
|
Button {
|
||||||
if perform != nil {
|
|
||||||
perform!()
|
|
||||||
}
|
|
||||||
|
|
||||||
follow_state = perform_follow_btn_action(follow_state, target: target)
|
follow_state = perform_follow_btn_action(follow_state, target: target)
|
||||||
} label: {
|
} label: {
|
||||||
Text(follow_btn_txt(follow_state))
|
Text(follow_btn_txt(follow_state))
|
||||||
@@ -71,19 +66,16 @@ struct FollowButtonPreviews: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
Text("Unfollows")
|
Text("Unfollows")
|
||||||
FollowButtonView(target: target, follow_state: .unfollows, perform: nil)
|
FollowButtonView(target: target, follow_state: .unfollows)
|
||||||
|
|
||||||
Text("Following")
|
Text("Following")
|
||||||
FollowButtonView(target: target, follow_state: .following, perform: nil)
|
FollowButtonView(target: target, follow_state: .following)
|
||||||
|
|
||||||
Text("Follows")
|
Text("Follows")
|
||||||
FollowButtonView(target: target, follow_state: .follows, perform: nil)
|
FollowButtonView(target: target, follow_state: .follows)
|
||||||
|
|
||||||
Text("Unfollowing")
|
Text("Unfollowing")
|
||||||
FollowButtonView(target: target, follow_state: .unfollowing, perform: nil)
|
FollowButtonView(target: target, follow_state: .unfollowing)
|
||||||
|
|
||||||
Text("Edit")
|
|
||||||
FollowButtonView(target: target, follow_state: .edit, perform: nil)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,8 +98,6 @@ func perform_follow_btn_action(_ fs: FollowState, target: FollowTarget) -> Follo
|
|||||||
case .unfollows:
|
case .unfollows:
|
||||||
notify(.follow, target)
|
notify(.follow, target)
|
||||||
return .unfollowing
|
return .unfollowing
|
||||||
case .edit:
|
|
||||||
return .edit
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ struct FollowUserView: View {
|
|||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
|
|
||||||
FollowButtonView(target: target, follow_state: damus_state.contacts.follow_state(target.pubkey), perform: nil)
|
FollowButtonView(target: target, follow_state: damus_state.contacts.follow_state(target.pubkey))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,6 +53,12 @@ struct FollowersView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationBarTitle("\(Profile.displayName(profile: profile, pubkey: whos))'s Followers")
|
.navigationBarTitle("\(Profile.displayName(profile: profile, pubkey: whos))'s Followers")
|
||||||
|
.onAppear {
|
||||||
|
followers.subscribe()
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
followers.unsubscribe()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,17 +32,13 @@ func pfp_line_width(_ h: Highlight) -> CGFloat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProfilePicView: View {
|
struct InnerProfilePicView: View {
|
||||||
|
|
||||||
@Environment(\.redactionReasons) private var reasons
|
@Environment(\.redactionReasons) private var reasons
|
||||||
|
|
||||||
|
let url: URL?
|
||||||
let pubkey: String
|
let pubkey: String
|
||||||
let size: CGFloat
|
let size: CGFloat
|
||||||
let highlight: Highlight
|
let highlight: Highlight
|
||||||
let profiles: Profiles
|
|
||||||
let isPlaceholder: Bool = false
|
|
||||||
|
|
||||||
@State var picture: String? = nil
|
|
||||||
|
|
||||||
var PlaceholderColor: Color {
|
var PlaceholderColor: Color {
|
||||||
return id_to_color(pubkey)
|
return id_to_color(pubkey)
|
||||||
@@ -56,11 +52,8 @@ struct ProfilePicView: View {
|
|||||||
.padding(2)
|
.padding(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
var MainContent: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
let pic = picture ?? profiles.lookup(id: pubkey)?.picture ?? robohash(pubkey)
|
|
||||||
let url = URL(string: pic)
|
|
||||||
|
|
||||||
if reasons.isEmpty {
|
if reasons.isEmpty {
|
||||||
KFAnimatedImage(url)
|
KFAnimatedImage(url)
|
||||||
.configure { view in
|
.configure { view in
|
||||||
@@ -82,8 +75,27 @@ struct ProfilePicView: View {
|
|||||||
.overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))
|
.overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ProfilePicView: View {
|
||||||
|
|
||||||
|
let pubkey: String
|
||||||
|
let size: CGFloat
|
||||||
|
let highlight: Highlight
|
||||||
|
let profiles: Profiles
|
||||||
|
|
||||||
|
@State var picture: String?
|
||||||
|
|
||||||
|
init (pubkey: String, size: CGFloat, highlight: Highlight, profiles: Profiles, picture: String? = nil) {
|
||||||
|
self.pubkey = pubkey
|
||||||
|
self.profiles = profiles
|
||||||
|
self.size = size
|
||||||
|
self.highlight = highlight
|
||||||
|
self._picture = State(initialValue: picture)
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
MainContent
|
InnerProfilePicView(url: get_profile_url(picture: picture, pubkey: pubkey, profiles: profiles), pubkey: pubkey, size: size, highlight: highlight)
|
||||||
.onReceive(handle_notify(.profile_updated)) { notif in
|
.onReceive(handle_notify(.profile_updated)) { notif in
|
||||||
let updated = notif.object as! ProfileUpdate
|
let updated = notif.object as! ProfileUpdate
|
||||||
|
|
||||||
@@ -98,6 +110,14 @@ struct ProfilePicView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func get_profile_url(picture: String?, pubkey: String, profiles: Profiles) -> URL {
|
||||||
|
let pic = picture ?? profiles.lookup(id: pubkey)?.picture ?? robohash(pubkey)
|
||||||
|
if let url = URL(string: pic) {
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
return URL(string: robohash(pubkey))!
|
||||||
|
}
|
||||||
|
|
||||||
func make_preview_profiles(_ pubkey: String) -> Profiles {
|
func make_preview_profiles(_ pubkey: String) -> Profiles {
|
||||||
let profiles = Profiles()
|
let profiles = Profiles()
|
||||||
let picture = "http://cdn.jb55.com/img/red-me.jpg"
|
let picture = "http://cdn.jb55.com/img/red-me.jpg"
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ enum FollowState {
|
|||||||
case following
|
case following
|
||||||
case unfollowing
|
case unfollowing
|
||||||
case unfollows
|
case unfollows
|
||||||
case edit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func follow_btn_txt(_ fs: FollowState) -> String {
|
func follow_btn_txt(_ fs: FollowState) -> String {
|
||||||
@@ -30,8 +29,6 @@ func follow_btn_txt(_ fs: FollowState) -> String {
|
|||||||
return "Unfollowing..."
|
return "Unfollowing..."
|
||||||
case .unfollows:
|
case .unfollows:
|
||||||
return "Follow"
|
return "Follow"
|
||||||
case .edit:
|
|
||||||
return "Edit"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,8 +42,6 @@ func follow_btn_enabled_state(_ fs: FollowState) -> Bool {
|
|||||||
return false
|
return false
|
||||||
case .unfollows:
|
case .unfollows:
|
||||||
return true
|
return true
|
||||||
case .edit:
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +77,40 @@ struct ProfileNameView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct EditButton: View {
|
||||||
|
let damus_state: DamusState
|
||||||
|
|
||||||
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationLink(destination: EditMetadataView(damus_state: damus_state)) {
|
||||||
|
Text("Edit")
|
||||||
|
.padding(.horizontal, 25)
|
||||||
|
.padding(.vertical, 10)
|
||||||
|
.font(.caption.weight(.bold))
|
||||||
|
.foregroundColor(fillColor())
|
||||||
|
.background(emptyColor())
|
||||||
|
.cornerRadius(20)
|
||||||
|
.overlay {
|
||||||
|
RoundedRectangle(cornerRadius: 16)
|
||||||
|
.stroke(borderColor(), lineWidth: 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillColor() -> Color {
|
||||||
|
colorScheme == .light ? .black : .white
|
||||||
|
}
|
||||||
|
|
||||||
|
func emptyColor() -> Color {
|
||||||
|
colorScheme == .light ? .white : .black
|
||||||
|
}
|
||||||
|
|
||||||
|
func borderColor() -> Color {
|
||||||
|
colorScheme == .light ? .black.opacity(0.1) : .white.opacity(0.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ProfileView: View {
|
struct ProfileView: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
|
|
||||||
@@ -134,14 +163,17 @@ struct ProfileView: View {
|
|||||||
DMButton
|
DMButton
|
||||||
|
|
||||||
|
|
||||||
FollowButtonView(
|
if profile.pubkey != damus_state.pubkey {
|
||||||
target: profile.get_follow_target(),
|
FollowButtonView(
|
||||||
follow_state: profile.pubkey == damus_state.pubkey ? .edit : damus_state.contacts.follow_state(profile.pubkey),
|
target: profile.get_follow_target(),
|
||||||
perform: profile.pubkey == damus_state.pubkey ? { showingEditProfile.toggle() } : nil
|
follow_state: damus_state.contacts.follow_state(profile.pubkey)
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
NavigationLink(destination: EditMetadataView(damus_state: damus_state)) {
|
||||||
|
EditButton(damus_state: damus_state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}.sheet(isPresented: $showingEditProfile) {
|
|
||||||
EditMetadataView(damus_state: damus_state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileNameView(pubkey: profile.pubkey, profile: data, contacts: damus_state.contacts)
|
ProfileNameView(pubkey: profile.pubkey, profile: data, contacts: damus_state.contacts)
|
||||||
@@ -201,11 +233,11 @@ struct ProfileView: View {
|
|||||||
}
|
}
|
||||||
.onAppear() {
|
.onAppear() {
|
||||||
profile.subscribe()
|
profile.subscribe()
|
||||||
followers.subscribe()
|
//followers.subscribe()
|
||||||
}
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
profile.unsubscribe()
|
profile.unsubscribe()
|
||||||
followers.unsubscribe()
|
//followers.unsubscribe()
|
||||||
// our profilemodel needs a bit more help
|
// our profilemodel needs a bit more help
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user