Changelog-Added: Added Conversations tab to profiles Signed-off-by: Terry Yiu <git@tyiu.xyz>
588 lines
25 KiB
Swift
588 lines
25 KiB
Swift
//
|
|
// ProfileView.swift
|
|
// damus
|
|
//
|
|
// Created by William Casarin on 2022-04-23.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
func follow_btn_txt(_ fs: FollowState, follows_you: Bool) -> String {
|
|
switch fs {
|
|
case .follows:
|
|
return NSLocalizedString("Unfollow", comment: "Button to unfollow a user.")
|
|
case .following:
|
|
return NSLocalizedString("Following...", comment: "Label to indicate that the user is in the process of following another user.")
|
|
case .unfollowing:
|
|
return NSLocalizedString("Unfollowing...", comment: "Label to indicate that the user is in the process of unfollowing another user.")
|
|
case .unfollows:
|
|
if follows_you {
|
|
return NSLocalizedString("Follow Back", comment: "Button to follow a user back.")
|
|
} else {
|
|
return NSLocalizedString("Follow", comment: "Button to follow a user.")
|
|
}
|
|
}
|
|
}
|
|
|
|
func followedByString(_ friend_intersection: [Pubkey], ndb: Ndb, locale: Locale = Locale.current) -> String {
|
|
let bundle = bundleForLocale(locale: locale)
|
|
let names: [String] = friend_intersection.prefix(3).map { pk in
|
|
let profile = ndb.lookup_profile(pk)?.unsafeUnownedValue?.profile
|
|
return Profile.displayName(profile: profile, pubkey: pk).username.truncate(maxLength: 20)
|
|
}
|
|
|
|
switch friend_intersection.count {
|
|
case 0:
|
|
return ""
|
|
case 1:
|
|
let format = NSLocalizedString("Followed by %@", bundle: bundle, comment: "Text to indicate that the user is followed by one of our follows.")
|
|
return String(format: format, locale: locale, names[0])
|
|
case 2:
|
|
let format = NSLocalizedString("Followed by %@ & %@", bundle: bundle, comment: "Text to indicate that the user is followed by two of our follows.")
|
|
return String(format: format, locale: locale, names[0], names[1])
|
|
case 3:
|
|
let format = NSLocalizedString("Followed by %@, %@ & %@", bundle: bundle, comment: "Text to indicate that the user is followed by three of our follows.")
|
|
return String(format: format, locale: locale, names[0], names[1], names[2])
|
|
default:
|
|
let format = localizedStringFormat(key: "followed_by_three_and_others", locale: locale)
|
|
return String(format: format, locale: locale, friend_intersection.count - 3, names[0], names[1], names[2])
|
|
}
|
|
}
|
|
|
|
struct VisualEffectView: UIViewRepresentable {
|
|
var effect: UIVisualEffect?
|
|
var darkeningOpacity: CGFloat = 0.3 // degree of darkening
|
|
|
|
func makeUIView(context: UIViewRepresentableContext<Self>) -> UIVisualEffectView {
|
|
let effectView = UIVisualEffectView()
|
|
effectView.backgroundColor = UIColor.black.withAlphaComponent(darkeningOpacity)
|
|
return effectView
|
|
}
|
|
|
|
func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext<Self>) {
|
|
uiView.effect = effect
|
|
uiView.backgroundColor = UIColor.black.withAlphaComponent(darkeningOpacity)
|
|
}
|
|
}
|
|
|
|
struct ProfileView: View {
|
|
let damus_state: DamusState
|
|
let pfp_size: CGFloat = 90.0
|
|
let bannerHeight: CGFloat = 150.0
|
|
|
|
@State var is_zoomed: Bool = false
|
|
@State var show_share_sheet: Bool = false
|
|
@State var show_qr_code: Bool = false
|
|
@State var action_sheet_presented: Bool = false
|
|
@State var mute_dialog_presented: Bool = false
|
|
@State var filter_state : FilterState = .posts
|
|
@State var yOffset: CGFloat = 0
|
|
|
|
@StateObject var profile: ProfileModel
|
|
@StateObject var followers: FollowersModel
|
|
@StateObject var zap_button_model: ZapButtonModel = ZapButtonModel()
|
|
|
|
init(damus_state: DamusState, profile: ProfileModel, followers: FollowersModel) {
|
|
self.damus_state = damus_state
|
|
self._profile = StateObject(wrappedValue: profile)
|
|
self._followers = StateObject(wrappedValue: followers)
|
|
}
|
|
|
|
init(damus_state: DamusState, pubkey: Pubkey) {
|
|
self.damus_state = damus_state
|
|
self._profile = StateObject(wrappedValue: ProfileModel(pubkey: pubkey, damus: damus_state))
|
|
self._followers = StateObject(wrappedValue: FollowersModel(damus_state: damus_state, target: pubkey))
|
|
}
|
|
|
|
@Environment(\.dismiss) var dismiss
|
|
@Environment(\.colorScheme) var colorScheme
|
|
@Environment(\.presentationMode) var presentationMode
|
|
|
|
func imageBorderColor() -> Color {
|
|
colorScheme == .light ? DamusColors.white : DamusColors.black
|
|
}
|
|
|
|
func bannerBlurViewOpacity() -> Double {
|
|
let progress = -(yOffset + navbarHeight) / 100
|
|
return Double(-yOffset > navbarHeight ? progress : 0)
|
|
}
|
|
|
|
func getProfileInfo() -> (String, String) {
|
|
let profile_txn = self.damus_state.profiles.lookup(id: profile.pubkey)
|
|
let ndbprofile = profile_txn?.unsafeUnownedValue
|
|
let displayName = Profile.displayName(profile: ndbprofile, pubkey: profile.pubkey).displayName.truncate(maxLength: 25)
|
|
let userName = Profile.displayName(profile: ndbprofile, pubkey: profile.pubkey).username.truncate(maxLength: 25)
|
|
return (displayName, "@\(userName)")
|
|
}
|
|
|
|
func showFollowBtnInBlurrBanner() -> Bool {
|
|
damus_state.contacts.follow_state(profile.pubkey) == .unfollows && bannerBlurViewOpacity() > 1.0
|
|
}
|
|
|
|
func content_filter(_ fstate: FilterState) -> ((NostrEvent) -> Bool) {
|
|
var filters = ContentFilters.defaults(damus_state: damus_state)
|
|
filters.append(fstate.filter)
|
|
if fstate == .conversations {
|
|
filters.append({ profile.conversation_events.contains($0.id) } )
|
|
}
|
|
return ContentFilters(filters: filters).filter
|
|
}
|
|
|
|
var bannerSection: some View {
|
|
GeometryReader { proxy -> AnyView in
|
|
|
|
let minY = proxy.frame(in: .global).minY
|
|
|
|
DispatchQueue.main.async {
|
|
self.yOffset = minY
|
|
}
|
|
|
|
return AnyView(
|
|
VStack(spacing: 0) {
|
|
ZStack {
|
|
BannerImageView(pubkey: profile.pubkey, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
|
.aspectRatio(contentMode: .fill)
|
|
.frame(width: proxy.size.width, height: minY > 0 ? bannerHeight + minY : bannerHeight)
|
|
.clipped()
|
|
|
|
VisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterial)).opacity(bannerBlurViewOpacity())
|
|
}
|
|
|
|
Divider().opacity(bannerBlurViewOpacity())
|
|
}
|
|
.frame(height: minY > 0 ? bannerHeight + minY : nil)
|
|
.offset(y: minY > 0 ? -minY : -minY < navbarHeight ? 0 : -minY - navbarHeight)
|
|
)
|
|
|
|
}
|
|
.frame(height: bannerHeight)
|
|
.allowsHitTesting(false)
|
|
}
|
|
|
|
var navbarHeight: CGFloat {
|
|
return 100.0 - (Theme.safeAreaInsets?.top ?? 0)
|
|
}
|
|
|
|
func navImage(img: String) -> some View {
|
|
Image(img)
|
|
.frame(width: 33, height: 33)
|
|
.background(Color.black.opacity(0.6))
|
|
.clipShape(Circle())
|
|
}
|
|
|
|
var navBackButton: some View {
|
|
Button {
|
|
presentationMode.wrappedValue.dismiss()
|
|
} label: {
|
|
navImage(img: "chevron-left")
|
|
}
|
|
}
|
|
|
|
var navActionSheetButton: some View {
|
|
Button(action: {
|
|
action_sheet_presented = true
|
|
}) {
|
|
Image(systemName: "ellipsis")
|
|
.frame(width: 33, height: 33)
|
|
.background(Color.black.opacity(0.6))
|
|
.clipShape(Circle())
|
|
}
|
|
.confirmationDialog(NSLocalizedString("Actions", comment: "Title for confirmation dialog to either share, report, or mute a profile."), isPresented: $action_sheet_presented) {
|
|
Button(NSLocalizedString("Share", comment: "Button to share the link to a profile.")) {
|
|
show_share_sheet = true
|
|
}
|
|
|
|
Button(NSLocalizedString("QR Code", comment: "Button to view profile's qr code.")) {
|
|
show_qr_code = true
|
|
}
|
|
|
|
// Only allow reporting if logged in with private key and the currently viewed profile is not the logged in profile.
|
|
if profile.pubkey != damus_state.pubkey && damus_state.is_privkey_user {
|
|
Button(NSLocalizedString("Report", comment: "Button to report a profile."), role: .destructive) {
|
|
notify(.report(.user(profile.pubkey)))
|
|
}
|
|
|
|
if damus_state.mutelist_manager.is_muted(.user(profile.pubkey, nil)) {
|
|
Button(NSLocalizedString("Unmute", comment: "Button to unmute a profile.")) {
|
|
guard
|
|
let keypair = damus_state.keypair.to_full(),
|
|
let mutelist = damus_state.mutelist_manager.event
|
|
else {
|
|
return
|
|
}
|
|
|
|
guard let new_ev = remove_from_mutelist(keypair: keypair, prev: mutelist, to_remove: .user(profile.pubkey, nil)) else {
|
|
return
|
|
}
|
|
|
|
damus_state.mutelist_manager.set_mutelist(new_ev)
|
|
damus_state.postbox.send(new_ev)
|
|
}
|
|
} else {
|
|
Button(NSLocalizedString("Mute", comment: "Button to mute a profile"), role: .destructive) {
|
|
mute_dialog_presented = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.confirmationDialog(NSLocalizedString("Mute", comment: "Title for confirmation dialog to mute a profile."), isPresented: $mute_dialog_presented) {
|
|
ForEach(DamusDuration.allCases, id: \.self) { duration in
|
|
Button {
|
|
notify(.mute(.user(profile.pubkey, duration.date_from_now)))
|
|
} label: {
|
|
Text(duration.title)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func lnButton(unownedProfile: Profile?, record: ProfileRecord?) -> some View {
|
|
return ProfileZapLinkView(unownedProfileRecord: record, profileModel: self.profile) { reactions_enabled, lud16, lnurl in
|
|
Image(reactions_enabled ? "zap.fill" : "zap")
|
|
.foregroundColor(reactions_enabled ? .orange : Color.primary)
|
|
.profile_button_style(scheme: colorScheme)
|
|
.cornerRadius(24)
|
|
}
|
|
}
|
|
|
|
var dmButton: some View {
|
|
let dm_model = damus_state.dms.lookup_or_create(profile.pubkey)
|
|
return NavigationLink(value: Route.DMChat(dms: dm_model)) {
|
|
Image("messages")
|
|
.profile_button_style(scheme: colorScheme)
|
|
}
|
|
}
|
|
|
|
private var followsYouBadge: some View {
|
|
Text("Follows you", comment: "Text to indicate that a user is following your profile.")
|
|
.padding([.leading, .trailing], 6.0)
|
|
.padding([.top, .bottom], 2.0)
|
|
.foregroundColor(.gray)
|
|
.background {
|
|
RoundedRectangle(cornerRadius: 5.0)
|
|
.foregroundColor(DamusColors.adaptableGrey)
|
|
}
|
|
.font(.footnote)
|
|
}
|
|
|
|
func actionSection(record: ProfileRecord?, pubkey: Pubkey) -> some View {
|
|
return Group {
|
|
if let record,
|
|
let profile = record.profile,
|
|
let lnurl = record.lnurl,
|
|
lnurl != ""
|
|
{
|
|
lnButton(unownedProfile: profile, record: record)
|
|
}
|
|
|
|
dmButton
|
|
|
|
if profile.pubkey != damus_state.pubkey {
|
|
FollowButtonView(
|
|
target: profile.get_follow_target(),
|
|
follows_you: profile.follows(pubkey: damus_state.pubkey),
|
|
follow_state: damus_state.contacts.follow_state(profile.pubkey)
|
|
)
|
|
} else if damus_state.keypair.privkey != nil {
|
|
NavigationLink(value: Route.EditMetadata) {
|
|
ProfileEditButton(damus_state: damus_state)
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
func pfpOffset() -> CGFloat {
|
|
let progress = -yOffset / navbarHeight
|
|
let offset = (pfp_size / 4.0) * (progress < 1.0 ? progress : 1)
|
|
return offset > 0 ? offset : 0
|
|
}
|
|
|
|
func pfpScale() -> CGFloat {
|
|
let progress = -yOffset / navbarHeight
|
|
let scale = 1.0 - (0.5 * (progress < 1.0 ? progress : 1))
|
|
return scale < 1 ? scale : 1
|
|
}
|
|
|
|
func nameSection(profile_data: ProfileRecord?) -> some View {
|
|
return Group {
|
|
let follows_you = profile.pubkey != damus_state.pubkey && profile.follows(pubkey: damus_state.pubkey)
|
|
|
|
HStack(alignment: .center) {
|
|
ProfilePicView(pubkey: profile.pubkey, size: pfp_size, highlight: .custom(imageBorderColor(), 4.0), profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
|
.padding(.top, -(pfp_size / 2.0))
|
|
.offset(y: pfpOffset())
|
|
.scaleEffect(pfpScale())
|
|
.onTapGesture {
|
|
is_zoomed.toggle()
|
|
}
|
|
.damus_full_screen_cover($is_zoomed, damus_state: damus_state) {
|
|
ProfilePicImageView(pubkey: profile.pubkey, profiles: damus_state.profiles, settings: damus_state.settings, nav: damus_state.nav, shouldShowEditButton: damus_state.pubkey == profile.pubkey)
|
|
}
|
|
|
|
Spacer()
|
|
|
|
if follows_you {
|
|
followsYouBadge
|
|
}
|
|
|
|
actionSection(record: profile_data, pubkey: profile.pubkey)
|
|
}
|
|
|
|
ProfileNameView(pubkey: profile.pubkey, damus: damus_state)
|
|
}
|
|
}
|
|
|
|
var followersCount: some View {
|
|
HStack {
|
|
if let followerCount = followers.count {
|
|
let nounString = pluralizedString(key: "followers_count", count: followerCount)
|
|
let nounText = Text(verbatim: nounString).font(.subheadline).foregroundColor(.gray)
|
|
Text("\(Text(verbatim: followerCount.formatted()).font(.subheadline.weight(.medium))) \(nounText)", comment: "Sentence composed of 2 variables to describe how many people are following a user. In source English, the first variable is the number of followers, and the second variable is 'Follower' or 'Followers'.")
|
|
} else {
|
|
Image("download")
|
|
.resizable()
|
|
.frame(width: 20, height: 20)
|
|
Text("Followers", comment: "Label describing followers of a user.")
|
|
.font(.subheadline)
|
|
.foregroundColor(.gray)
|
|
}
|
|
}
|
|
}
|
|
|
|
var aboutSection: some View {
|
|
VStack(alignment: .leading, spacing: 8.0) {
|
|
let profile_txn = damus_state.profiles.lookup_with_timestamp(profile.pubkey)
|
|
let profile_data = profile_txn?.unsafeUnownedValue
|
|
|
|
nameSection(profile_data: profile_data)
|
|
|
|
if let about = profile_data?.profile?.about {
|
|
AboutView(state: damus_state, about: about)
|
|
}
|
|
|
|
if let url = profile_data?.profile?.website_url {
|
|
WebsiteLink(url: url)
|
|
}
|
|
|
|
HStack {
|
|
if let contact = profile.contacts {
|
|
let contacts = Array(contact.referenced_pubkeys)
|
|
let hashtags = Array(contact.referenced_hashtags)
|
|
let following_model = FollowingModel(damus_state: damus_state, contacts: contacts, hashtags: hashtags)
|
|
NavigationLink(value: Route.Following(following: following_model)) {
|
|
HStack {
|
|
let noun_text = Text(verbatim: "\(pluralizedString(key: "following_count", count: profile.following))").font(.subheadline).foregroundColor(.gray)
|
|
Text("\(Text(verbatim: profile.following.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.")
|
|
}
|
|
}
|
|
.buttonStyle(PlainButtonStyle())
|
|
}
|
|
|
|
if followers.contacts != nil {
|
|
NavigationLink(value: Route.Followers(followers: followers)) {
|
|
followersCount
|
|
}
|
|
.buttonStyle(PlainButtonStyle())
|
|
} else {
|
|
followersCount
|
|
.onTapGesture {
|
|
UIImpactFeedbackGenerator(style: .light).impactOccurred()
|
|
followers.contacts = []
|
|
followers.subscribe()
|
|
}
|
|
}
|
|
|
|
if let relays = profile.relays {
|
|
// Only open relay config view if the user is logged in with private key and they are looking at their own profile.
|
|
let noun_string = pluralizedString(key: "relays_count", count: relays.keys.count)
|
|
let noun_text = Text(noun_string).font(.subheadline).foregroundColor(.gray)
|
|
let relay_text = Text("\(Text(verbatim: relays.keys.count.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.")
|
|
if profile.pubkey == damus_state.pubkey && damus_state.is_privkey_user {
|
|
NavigationLink(value: Route.RelayConfig) {
|
|
relay_text
|
|
}
|
|
.buttonStyle(PlainButtonStyle())
|
|
} else {
|
|
NavigationLink(value: Route.UserRelays(relays: Array(relays.keys).sorted())) {
|
|
relay_text
|
|
}
|
|
.buttonStyle(PlainButtonStyle())
|
|
}
|
|
}
|
|
}
|
|
|
|
if profile.pubkey != damus_state.pubkey {
|
|
let friended_followers = damus_state.contacts.get_friended_followers(profile.pubkey)
|
|
if !friended_followers.isEmpty {
|
|
Spacer()
|
|
|
|
NavigationLink(value: Route.FollowersYouKnow(friendedFollowers: friended_followers, followers: followers)) {
|
|
HStack {
|
|
CondensedProfilePicturesView(state: damus_state, pubkeys: friended_followers, maxPictures: 3)
|
|
let followedByString = followedByString(friended_followers, ndb: damus_state.ndb)
|
|
Text(followedByString)
|
|
.font(.subheadline).foregroundColor(.gray)
|
|
.multilineTextAlignment(.leading)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.padding(.horizontal)
|
|
}
|
|
|
|
var tabs: [(String, FilterState)] {
|
|
var tabs = [
|
|
(NSLocalizedString("Notes", comment: "Label for filter for seeing only notes (instead of notes and replies)."), FilterState.posts),
|
|
(NSLocalizedString("Notes & Replies", comment: "Label for filter for seeing notes and replies (instead of only notes)."), FilterState.posts_and_replies)
|
|
]
|
|
if profile.pubkey != damus_state.pubkey && !profile.conversation_events.isEmpty {
|
|
tabs.append((NSLocalizedString("Conversations", comment: "Label for filter for seeing notes and replies that involve conversations between the signed in user and the current profile."), FilterState.conversations))
|
|
}
|
|
return tabs
|
|
}
|
|
|
|
var body: some View {
|
|
ZStack {
|
|
ScrollView(.vertical) {
|
|
VStack(spacing: 0) {
|
|
bannerSection
|
|
.zIndex(1)
|
|
|
|
VStack() {
|
|
aboutSection
|
|
|
|
VStack(spacing: 0) {
|
|
CustomPicker(tabs: tabs, selection: $filter_state)
|
|
Divider()
|
|
.frame(height: 1)
|
|
}
|
|
.background(colorScheme == .dark ? Color.black : Color.white)
|
|
|
|
if filter_state == FilterState.posts {
|
|
InnerTimelineView(events: profile.events, damus: damus_state, filter: content_filter(FilterState.posts))
|
|
}
|
|
if filter_state == FilterState.posts_and_replies {
|
|
InnerTimelineView(events: profile.events, damus: damus_state, filter: content_filter(FilterState.posts_and_replies))
|
|
}
|
|
if filter_state == FilterState.conversations && !profile.conversation_events.isEmpty {
|
|
InnerTimelineView(events: profile.events, damus: damus_state, filter: content_filter(FilterState.conversations))
|
|
}
|
|
}
|
|
.padding(.horizontal, Theme.safeAreaInsets?.left)
|
|
.zIndex(-yOffset > navbarHeight ? 0 : 1)
|
|
}
|
|
}
|
|
.padding(.bottom, tabHeight + getSafeAreaBottom())
|
|
.ignoresSafeArea()
|
|
.navigationTitle("")
|
|
.navigationBarBackButtonHidden()
|
|
.toolbar {
|
|
ToolbarItem(placement: .topBarLeading) {
|
|
HStack(spacing: 8) {
|
|
navBackButton
|
|
.padding(.top, 5)
|
|
.accentColor(DamusColors.white)
|
|
VStack(alignment: .leading, spacing: -4.5) {
|
|
Text(getProfileInfo().0) // Display name
|
|
.font(.headline)
|
|
.foregroundColor(.white)
|
|
Text(getProfileInfo().1) // Username
|
|
.font(.subheadline)
|
|
.foregroundColor(.white.opacity(0.8))
|
|
}
|
|
.opacity(bannerBlurViewOpacity())
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.padding(.top, max(5, 15 + (yOffset / 30)))
|
|
}
|
|
}
|
|
if showFollowBtnInBlurrBanner() {
|
|
ToolbarItem(placement: .topBarTrailing) {
|
|
FollowButtonView(
|
|
target: profile.get_follow_target(),
|
|
follows_you: profile.follows(pubkey: damus_state.pubkey),
|
|
follow_state: damus_state.contacts.follow_state(profile.pubkey)
|
|
)
|
|
.padding(.top, 8)
|
|
}
|
|
} else {
|
|
ToolbarItem(placement: .topBarTrailing) {
|
|
navActionSheetButton
|
|
.padding(.top, 5)
|
|
.accentColor(DamusColors.white)
|
|
}
|
|
}
|
|
}
|
|
.toolbarBackground(.hidden)
|
|
.onReceive(handle_notify(.switched_timeline)) { _ in
|
|
dismiss()
|
|
}
|
|
.onAppear() {
|
|
check_nip05_validity(pubkey: self.profile.pubkey, profiles: self.damus_state.profiles)
|
|
profile.subscribe()
|
|
//followers.subscribe()
|
|
}
|
|
.onDisappear {
|
|
profile.unsubscribe()
|
|
followers.unsubscribe()
|
|
// our profilemodel needs a bit more help
|
|
}
|
|
.sheet(isPresented: $show_share_sheet) {
|
|
let url = URL(string: "https://damus.io/" + profile.pubkey.npub)!
|
|
ShareSheet(activityItems: [url])
|
|
}
|
|
.damus_full_screen_cover($show_qr_code, damus_state: damus_state) {
|
|
QRCodeView(damus_state: damus_state, pubkey: profile.pubkey)
|
|
}
|
|
|
|
if damus_state.is_privkey_user {
|
|
PostButtonContainer(is_left_handed: damus_state.settings.left_handed) {
|
|
notify(.compose(.posting(.user(profile.pubkey))))
|
|
}
|
|
.padding(.bottom, tabHeight)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct ProfileView_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
let ds = test_damus_state
|
|
ProfileView(damus_state: ds, pubkey: ds.pubkey)
|
|
}
|
|
}
|
|
|
|
extension View {
|
|
func profile_button_style(scheme: ColorScheme) -> some View {
|
|
self.symbolRenderingMode(.palette)
|
|
.font(.system(size: 32).weight(.thin))
|
|
.foregroundStyle(scheme == .dark ? .white : .black, scheme == .dark ? .white : .black)
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
func check_nip05_validity(pubkey: Pubkey, profiles: Profiles) {
|
|
let profile_txn = profiles.lookup(id: pubkey)
|
|
|
|
guard let profile = profile_txn?.unsafeUnownedValue,
|
|
let nip05 = profile.nip05,
|
|
profiles.is_validated(pubkey) == nil
|
|
else {
|
|
return
|
|
}
|
|
|
|
Task.detached(priority: .background) {
|
|
let validated = await validate_nip05(pubkey: pubkey, nip05_str: nip05)
|
|
if validated != nil {
|
|
print("validated nip05 for '\(nip05)'")
|
|
}
|
|
|
|
Task { @MainActor in
|
|
profiles.set_validated(pubkey, nip05: validated)
|
|
profiles.nip05_pubkey[nip05] = pubkey
|
|
notify(.profile_updated(.remote(pubkey: pubkey)))
|
|
}
|
|
}
|
|
}
|