damus

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

commit dff450282b38de84bf534b52b6280447e169b6f3
parent 549cbb9bce76443aedaec9394f3926acd546667e
Author: Thomas <31560900+0xtlt@users.noreply.github.com>
Date:   Fri, 23 Dec 2022 16:12:50 +0100

Metadata screen

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 4++++
Mdamus/Models/ProfileModel.swift | 10+++++++++-
Mdamus/Nostr/Nostr.swift | 6++----
Mdamus/Nostr/NostrMetadata.swift | 6+++++-
Mdamus/Views/ConfigView.swift | 18++++++++++++++----
Adamus/Views/MetadataView.swift | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdamus/Views/PostView.swift | 1+
Mdamus/Views/ProfilePicView.swift | 2+-
Mdamus/Views/ProfileView.swift | 2+-
9 files changed, 150 insertions(+), 12 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -129,6 +129,7 @@ 4CEE2AF7280B2DEA00AB5EEF /* ProfileName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */; }; 4CEE2AF9280B2EAC00AB5EEF /* PowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */; }; 4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */; }; + E990020F2955F837003BBC5A /* MetadataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E990020E2955F837003BBC5A /* MetadataView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -306,6 +307,7 @@ 4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileName.swift; sourceTree = "<group>"; }; 4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowView.swift; sourceTree = "<group>"; }; 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventActionBar.swift; sourceTree = "<group>"; }; + E990020E2955F837003BBC5A /* MetadataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetadataView.swift; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -473,6 +475,7 @@ 4C216F31286E388800040376 /* DMChatView.swift */, 4C216F33286F5ACD00040376 /* DMView.swift */, 4C06670028FC7C5900038D2A /* RelayView.swift */, + E990020E2955F837003BBC5A /* MetadataView.swift */, ); path = Views; sourceTree = "<group>"; @@ -845,6 +848,7 @@ 4C3EA67D28FFBBA300C48A62 /* InvoicesView.swift in Sources */, 4C363A8E28236FE4006E126D /* NoteContentView.swift in Sources */, 4C90BD1A283AA67F008EE7EF /* Bech32.swift in Sources */, + E990020F2955F837003BBC5A /* MetadataView.swift in Sources */, 4CACA9D5280C31E100D9BBE8 /* ReplyView.swift in Sources */, 4C0A3F97280F8E02000448DE /* ThreadView.swift in Sources */, 4C06670B28FDE64700038D2A /* damus.c in Sources */, diff --git a/damus/Models/ProfileModel.swift b/damus/Models/ProfileModel.swift @@ -7,7 +7,7 @@ import Foundation -class ProfileModel: ObservableObject { +class ProfileModel: ObservableObject, Equatable { @Published var events: [NostrEvent] = [] @Published var contacts: NostrEvent? = nil @Published var following: Int = 0 @@ -31,6 +31,14 @@ class ProfileModel: ObservableObject { self.damus = damus } + static func == (lhs: ProfileModel, rhs: ProfileModel) -> Bool { + return lhs.pubkey == rhs.pubkey + } + + func hash(into hasher: inout Hasher) { + hasher.combine(pubkey) + } + func unsubscribe() { print("unsubscribing from profile \(pubkey) with sub_id \(sub_id)") damus.pool.unsubscribe(sub_id: sub_id) diff --git a/damus/Nostr/Nostr.swift b/damus/Nostr/Nostr.swift @@ -8,12 +8,13 @@ import Foundation -struct Profile: Decodable { +struct Profile: Decodable, Equatable { let name: String? let display_name: String? let about: String? let picture: String? let website: String? + let nip05: String? let lud06: String? let lud16: String? @@ -34,6 +35,3 @@ struct NostrSubscription { let sub_id: String let filter: NostrFilter } - - - diff --git a/damus/Nostr/NostrMetadata.swift b/damus/Nostr/NostrMetadata.swift @@ -13,8 +13,12 @@ struct NostrMetadata: Codable { let name: String? let about: String? let website: String? + let nip05: String? + let picture: String? + let lud06: String? + let lud16: String? } func create_account_to_metadata(_ model: CreateAccountModel) -> NostrMetadata { - return NostrMetadata(display_name: model.real_name, name: model.nick_name, about: model.about, website: nil) + return NostrMetadata(display_name: model.real_name, name: model.nick_name, about: model.about, website: nil, nip05: nil, picture: nil, lud06: nil, lud16: nil) } diff --git a/damus/Views/ConfigView.swift b/damus/Views/ConfigView.swift @@ -73,11 +73,19 @@ struct ConfigView: View { CopyButton(is_pk: false) } - + Toggle("Show", isOn: $show_privkey) } } - + + Section("Account settings") { + NavigationLink { + MetadataView(damus_state: state, profileModel: ProfileModel(pubkey: state.pubkey, damus: state)) + } label: { + Text("Profile metadata") + } + } + Section("Reset") { Button("Logout") { confirm_logout = true @@ -129,7 +137,7 @@ struct ConfigView: View { guard let privkey = state.keypair.privkey else { return } - + let info = RelayInfo.rw guard (try? state.pool.add_relay(url, info: info)) != nil else { @@ -154,6 +162,8 @@ struct ConfigView: View { struct ConfigView_Previews: PreviewProvider { static var previews: some View { - ConfigView(state: test_damus_state()) + NavigationView { + ConfigView(state: test_damus_state()) + } } } diff --git a/damus/Views/MetadataView.swift b/damus/Views/MetadataView.swift @@ -0,0 +1,113 @@ +// +// MetadataView.swift +// damus +// +// Created by Thomas Tastet on 23/12/2022. +// + +import SwiftUI + +struct MetadataView: View { + let damus_state: DamusState + @State var name: String = "" + @State var about: String = "" + @State var picture: String = "" + @State var nip05: String = "" + @State var nickname: String = "" + @State var lud06: String = "" + @State var lud16: String = "" + @State private var showAlert = false + @State private var isFocused = false + + @StateObject var profileModel: ProfileModel + + func save() { + let metadata = NostrMetadata( + display_name: name, + name: nickname, + about: about, + website: nil, + nip05: nip05.isEmpty ? nil : nip05, + picture: picture.isEmpty ? nil : picture, + lud06: lud06.isEmpty ? nil : lud06, + lud16: lud16.isEmpty ? nil : lud16 + ); + + let m_metadata_ev = make_metadata_event(keypair: damus_state.keypair, metadata: metadata) + + if let metadata_ev = m_metadata_ev { + damus_state.pool.send(.event(metadata_ev)) + } + } + + var body: some View { + VStack(alignment: .leading) { + Form { + Section("Your Nostr Profile") { + TextField("Your username", text: $name) + .textInputAutocapitalization(.never) + TextField("Your @", text: $nickname) + .textInputAutocapitalization(.never) + TextField("Profile Picture Url", text: $picture) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + TextField("NIP 05 (@)", text: $nip05) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + } + + Section("Description") { + ZStack(alignment: .topLeading) { + TextEditor(text: $about) + .textInputAutocapitalization(.sentences) + if about.isEmpty { + Text("Type your description here...") + .offset(x: 0, y: 7) + .foregroundColor(Color(uiColor: .placeholderText)) + } + } + } + + Section("Advanced") { + TextField("Lud06", text: $lud06) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + TextField("Lud16", text: $lud16) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + } + + Button("Save") { + save() + showAlert = true + }.alert(isPresented: $showAlert) { + Alert(title: Text("Saved"), message: Text("Your metadata has been saved."), dismissButton: .default(Text("OK"))) + } + } + } + .onAppear() { + profileModel.subscribe() + + let data = damus_state.profiles.lookup(id: profileModel.pubkey) + + name = data?.display_name ?? name + nickname = data?.name ?? name + about = data?.about ?? about + picture = data?.picture ?? picture + nip05 = data?.nip05 ?? nip05 + lud06 = data?.lud06 ?? lud06 + lud16 = data?.lud16 ?? lud16 + } + .onDisappear { + profileModel.unsubscribe() + } + } +} + +struct MetadataView_Previews: PreviewProvider { + static var previews: some View { + let ds = test_damus_state() + let profile_model = ProfileModel(pubkey: ds.pubkey, damus: ds) + MetadataView(damus_state: ds, profileModel: profile_model) + } +} diff --git a/damus/Views/PostView.swift b/damus/Views/PostView.swift @@ -79,6 +79,7 @@ struct PostView: View { .padding(.top, 8) .padding(.leading, 10) .foregroundColor(Color(uiColor: .placeholderText)) + .allowsHitTesting(false) } } } diff --git a/damus/Views/ProfilePicView.swift b/damus/Views/ProfilePicView.swift @@ -101,7 +101,7 @@ struct ProfilePicView: View { 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) + let profile = Profile(name: "jb55", display_name: "William Casarin", about: "It's me", picture: picture, website: "https://jb55.com", nip05: "jb55@damus.io", lud06: nil, lud16: nil) let ts_profile = TimestampedProfile(profile: profile, timestamp: 0) profiles.add(id: pubkey, profile: ts_profile) return profiles diff --git a/damus/Views/ProfileView.swift b/damus/Views/ProfileView.swift @@ -211,7 +211,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(), tips: TipCounter(our_pubkey: pubkey), profiles: Profiles(), dms: DirectMessagesModel()) - 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") + let prof = Profile(name: "damus", display_name: "Damus", about: "iOS app!", picture: "https://damus.io/img/logo.png", website: "https://damus.io", nip05: "jb@damus.io", lud06: nil, lud16: "jb55@sendsats.lol") let tsprof = TimestampedProfile(profile: prof, timestamp: 0) damus.profiles.add(id: pubkey, profile: tsprof) return damus