Browse Source

Bunch of new views and logic changes to allow for editing profiles. Sometimes works but most of the time it doesn't Cant figure out whats going on there

profile-edit
Sam DuBois 2 years ago
committed by William Casarin
parent
commit
816b6a9d8e
  1. 28
      damus.xcodeproj/project.pbxproj
  2. 113
      damus/ContentView.swift
  3. 25
      damus/DamusViewModel.swift
  4. 12
      damus/Models/AccountModel.swift
  5. 5
      damus/Nostr/NostrMetadata.swift
  6. 41
      damus/Views/Account/EditAccountButton.swift
  7. 122
      damus/Views/Account/EditAccountView.swift
  8. 4
      damus/Views/CreateAccountView.swift
  9. 6
      damus/Views/ProfileView.swift
  10. 8
      damus/Views/SaveKeysView.swift
  11. 3
      damus/damusApp.swift

28
damus.xcodeproj/project.pbxproj

@ -10,6 +10,9 @@
3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAE5294E69C000EE4006 /* EmptyTimelineView.swift */; };
3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAEC294FCCFC00EE4006 /* Constants.swift */; };
31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D2E846295218AF006D67F8 /* Shimmer.swift */; };
31D2E84D295225C3006D67F8 /* EditAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D2E84C295225C3006D67F8 /* EditAccountView.swift */; };
31FE49F629535D3700D6DEA1 /* DamusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31FE49F529535D3700D6DEA1 /* DamusViewModel.swift */; };
31FE49F92953731D00D6DEA1 /* EditAccountButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31FE49F82953731D00D6DEA1 /* EditAccountButton.swift */; };
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670028FC7C5900038D2A /* RelayView.swift */; };
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 4C06670328FC7EC500038D2A /* Kingfisher */; };
4C06670628FCB08600038D2A /* ImageCarousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670528FCB08600038D2A /* ImageCarousel.swift */; };
@ -27,7 +30,7 @@
4C216F382871EDE300040376 /* DirectMessageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C216F372871EDE300040376 /* DirectMessageModel.swift */; };
4C285C8228385570008A31F1 /* CarouselView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8128385570008A31F1 /* CarouselView.swift */; };
4C285C8428385690008A31F1 /* CreateAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8328385690008A31F1 /* CreateAccountView.swift */; };
4C285C86283892E7008A31F1 /* CreateAccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C85283892E7008A31F1 /* CreateAccountModel.swift */; };
4C285C86283892E7008A31F1 /* AccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C85283892E7008A31F1 /* AccountModel.swift */; };
4C285C8A2838B985008A31F1 /* ProfilePictureSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */; };
4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8B28398BC6008A31F1 /* Keys.swift */; };
4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8D28399BFD008A31F1 /* SaveKeysView.swift */; };
@ -152,6 +155,9 @@
3169CAE5294E69C000EE4006 /* EmptyTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyTimelineView.swift; sourceTree = "<group>"; };
3169CAEC294FCCFC00EE4006 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Constants.swift; path = damus/Util/Constants.swift; sourceTree = SOURCE_ROOT; };
31D2E846295218AF006D67F8 /* Shimmer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shimmer.swift; sourceTree = "<group>"; };
31D2E84C295225C3006D67F8 /* EditAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAccountView.swift; sourceTree = "<group>"; };
31FE49F529535D3700D6DEA1 /* DamusViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusViewModel.swift; sourceTree = "<group>"; };
31FE49F82953731D00D6DEA1 /* EditAccountButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAccountButton.swift; sourceTree = "<group>"; };
4C06670028FC7C5900038D2A /* RelayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayView.swift; sourceTree = "<group>"; };
4C06670528FCB08600038D2A /* ImageCarousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCarousel.swift; sourceTree = "<group>"; };
4C06670828FDE64700038D2A /* damus-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "damus-Bridging-Header.h"; sourceTree = "<group>"; };
@ -171,7 +177,7 @@
4C216F372871EDE300040376 /* DirectMessageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectMessageModel.swift; sourceTree = "<group>"; };
4C285C8128385570008A31F1 /* CarouselView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselView.swift; sourceTree = "<group>"; };
4C285C8328385690008A31F1 /* CreateAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateAccountView.swift; sourceTree = "<group>"; };
4C285C85283892E7008A31F1 /* CreateAccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateAccountModel.swift; sourceTree = "<group>"; };
4C285C85283892E7008A31F1 /* AccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountModel.swift; sourceTree = "<group>"; };
4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePictureSelector.swift; sourceTree = "<group>"; };
4C285C8B28398BC6008A31F1 /* Keys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keys.swift; sourceTree = "<group>"; };
4C285C8D28399BFD008A31F1 /* SaveKeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveKeysView.swift; sourceTree = "<group>"; };
@ -344,6 +350,15 @@
path = "Empty Views";
sourceTree = "<group>";
};
31FE49F72953730900D6DEA1 /* Account */ = {
isa = PBXGroup;
children = (
31D2E84C295225C3006D67F8 /* EditAccountView.swift */,
31FE49F82953731D00D6DEA1 /* EditAccountButton.swift */,
);
path = Account;
sourceTree = "<group>";
};
4C06670728FDE62900038D2A /* damus-c */ = {
isa = PBXGroup;
children = (
@ -416,7 +431,7 @@
4C363A9B282838B9006E126D /* EventRef.swift */,
4C363AA328296DEE006E126D /* SearchModel.swift */,
4C3AC79A28306D7B00E1F516 /* Contacts.swift */,
4C285C85283892E7008A31F1 /* CreateAccountModel.swift */,
4C285C85283892E7008A31F1 /* AccountModel.swift */,
4C63334F283D40E500B1C9C3 /* HomeModel.swift */,
4C633351283D419F00B1C9C3 /* SignalModel.swift */,
4C5F9113283D694D0052CD1C /* FollowTarget.swift */,
@ -442,6 +457,7 @@
4CEE2AF0280B216B00AB5EEF /* EventDetailView.swift */,
4CEE2AF2280B25C500AB5EEF /* ProfilePicView.swift */,
4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */,
31FE49F72953730900D6DEA1 /* Account */,
4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */,
4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */,
4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */,
@ -559,6 +575,7 @@
4C75EFA72804823E0006080F /* Info.plist */,
4C75EFA227FA576C0006080F /* Views */,
4CE6DEE627F7A08100C66700 /* damusApp.swift */,
31FE49F529535D3700D6DEA1 /* DamusViewModel.swift */,
4CE6DEE827F7A08100C66700 /* ContentView.swift */,
4CE6DEEA27F7A08200C66700 /* Assets.xcassets */,
4CE6DEEC27F7A08200C66700 /* Preview Content */,
@ -748,12 +765,13 @@
4C3AC79D2833036D00E1F516 /* FollowingView.swift in Sources */,
4C363A8A28236B57006E126D /* MentionView.swift in Sources */,
4CE4F8CD281352B30009DFBB /* Notifications.swift in Sources */,
31D2E84D295225C3006D67F8 /* EditAccountView.swift in Sources */,
4C285C8428385690008A31F1 /* CreateAccountView.swift in Sources */,
4C216F34286F5ACD00040376 /* DMView.swift in Sources */,
4C3EA64428FF558100C48A62 /* sha256.c in Sources */,
4CE4F9E1285287B800C00DD9 /* TextFieldAlert.swift in Sources */,
4C363AA828297703006E126D /* InsertSort.swift in Sources */,
4C285C86283892E7008A31F1 /* CreateAccountModel.swift in Sources */,
4C285C86283892E7008A31F1 /* AccountModel.swift in Sources */,
4C64987C286D03E000EAE2B3 /* DirectMessagesView.swift in Sources */,
4C363A8C28236B92006E126D /* PubkeyView.swift in Sources */,
4C5C7E68284ED36500A22DF5 /* SearchHomeModel.swift in Sources */,
@ -803,9 +821,11 @@
4C3EA67528FF7A5A00C48A62 /* take.c in Sources */,
4C3AC7A12835A81400E1F516 /* SetupView.swift in Sources */,
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */,
31FE49F92953731D00D6DEA1 /* EditAccountButton.swift in Sources */,
4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */,
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */,
4C633352283D419F00B1C9C3 /* SignalModel.swift in Sources */,
31FE49F629535D3700D6DEA1 /* DamusViewModel.swift in Sources */,
4C363A94282704FA006E126D /* Post.swift in Sources */,
4C216F32286E388800040376 /* DMChatView.swift in Sources */,
4C3EA67928FF7ABF00C48A62 /* list.c in Sources */,

113
damus/ContentView.swift

@ -54,20 +54,7 @@ struct ContentView: View {
return keypair.privkey
}
@State var status: String = "Not connected"
@State var active_sheet: Sheets? = nil
@State var damus_state: DamusState? = nil
@State var selected_timeline: Timeline? = .home
@State var is_thread_open: Bool = false
@State var is_profile_open: Bool = false
@State var event: NostrEvent? = nil
@State var active_profile: String? = nil
@State var active_search: NostrFilter? = nil
@State var active_event_id: String? = nil
@State var profile_open: Bool = false
@State var thread_open: Bool = false
@State var search_open: Bool = false
@State var filter_state : FilterState = .posts_and_replies
@EnvironmentObject var viewModel: DamusViewModel
@StateObject var home: HomeModel = HomeModel()
// connect retry timer
@ -80,12 +67,12 @@ struct ContentView: View {
var PostingTimelineView: some View {
VStack{
ZStack {
if let damus = self.damus_state {
if let damus = viewModel.damus_state {
TimelineView(events: $home.events, loading: $home.loading, damus: damus, show_friend_icon: false, filter: filter_event)
}
if privkey != nil {
PostButtonContainer {
self.active_sheet = .post
viewModel.active_sheet = .post
}
}
}
@ -104,7 +91,7 @@ struct ContentView: View {
var FiltersView: some View {
VStack{
Picker("Filter State", selection: $filter_state) {
Picker("Filter State", selection: $viewModel.filter_state) {
Text("Posts").tag(FilterState.posts)
Text("Posts & Replies").tag(FilterState.posts_and_replies)
}
@ -113,7 +100,7 @@ struct ContentView: View {
}
func filter_event(_ ev: NostrEvent) -> Bool {
if self.filter_state == .posts {
if viewModel.filter_state == .posts {
return !ev.is_reply(nil)
}
@ -122,18 +109,18 @@ struct ContentView: View {
func MainContent(damus: DamusState) -> some View {
VStack {
NavigationLink(destination: MaybeProfileView, isActive: $profile_open) {
NavigationLink(destination: MaybeProfileView, isActive: $viewModel.profile_open) {
EmptyView()
}
NavigationLink(destination: MaybeThreadView, isActive: $thread_open) {
NavigationLink(destination: MaybeThreadView, isActive: $viewModel.thread_open) {
EmptyView()
}
NavigationLink(destination: MaybeSearchView, isActive: $search_open) {
NavigationLink(destination: MaybeSearchView, isActive: $viewModel.search_open) {
EmptyView()
}
switch selected_timeline {
switch viewModel.selected_timeline {
case .search:
SearchHomeView(damus_state: damus_state!, model: SearchHomeModel(damus_state: damus_state!))
SearchHomeView(damus_state: viewModel.damus_state!, model: SearchHomeModel(damus_state: viewModel.damus_state!))
case .home:
PostingTimelineView
@ -143,20 +130,20 @@ struct ContentView: View {
.navigationTitle("Notifications")
case .dms:
DirectMessagesView(damus_state: damus_state!)
DirectMessagesView(damus_state: viewModel.damus_state!)
.environmentObject(home.dms)
case .none:
EmptyView()
}
}
.navigationBarTitle(selected_timeline == .home ? "Home" : "Global", displayMode: .inline)
.navigationBarTitle(viewModel.selected_timeline == .home ? "Home" : "Global", displayMode: .inline)
}
var MaybeSearchView: some View {
Group {
if let search = self.active_search {
SearchView(appstate: damus_state!, search: SearchModel(pool: damus_state!.pool, search: search))
if let search = viewModel.active_search {
SearchView(appstate: viewModel.damus_state!, search: SearchModel(pool: viewModel.damus_state!.pool, search: search))
} else {
EmptyView()
}
@ -165,9 +152,9 @@ struct ContentView: View {
var MaybeThreadView: some View {
Group {
if let evid = self.active_event_id {
let thread_model = ThreadModel(evid: evid, damus_state: damus_state!)
ThreadView(thread: thread_model, damus: damus_state!, is_chatroom: false)
if let evid = viewModel.active_event_id {
let thread_model = ThreadModel(evid: evid, damus_state: viewModel.damus_state!)
ThreadView(thread: thread_model, damus: viewModel.damus_state!, is_chatroom: false)
} else {
EmptyView()
}
@ -176,10 +163,10 @@ struct ContentView: View {
var MaybeProfileView: some View {
Group {
if let pk = self.active_profile {
let profile_model = ProfileModel(pubkey: pk, damus: damus_state!)
let followers = FollowersModel(damus_state: damus_state!, target: pk)
ProfileView(damus_state: damus_state!, profile: profile_model, followers: followers)
if let pk = viewModel.active_profile {
let profile_model = ProfileModel(pubkey: pk, damus: viewModel.damus_state!)
let followers = FollowersModel(damus_state: viewModel.damus_state!, target: pk)
ProfileView(damus_state: viewModel.damus_state!, profile: profile_model, followers: followers)
} else {
EmptyView()
}
@ -188,20 +175,20 @@ struct ContentView: View {
var body: some View {
VStack(alignment: .leading, spacing: 0) {
if let damus = self.damus_state {
if let damus = viewModel.damus_state {
NavigationView {
MainContent(damus: damus)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
let profile_model = ProfileModel(pubkey: damus_state!.pubkey, damus: damus_state!)
let followers_model = FollowersModel(damus_state: damus_state!, target: damus_state!.pubkey)
let prof_dest = ProfileView(damus_state: damus_state!, profile: profile_model, followers: followers_model)
let profile_model = ProfileModel(pubkey: viewModel.damus_state!.pubkey, damus: viewModel.damus_state!)
let followers_model = FollowersModel(damus_state: viewModel.damus_state!, target: viewModel.damus_state!.pubkey)
let prof_dest = ProfileView(damus_state: viewModel.damus_state!, profile: profile_model, followers: followers_model)
NavigationLink(destination: prof_dest) {
/// Verify that the user has a profile picture, if not display a generic SF Symbol
/// (Resolves an in-app error where ``Robohash`` pictures are not generated so the button dissapears
if let picture = damus_state?.profiles.lookup(id: pubkey)?.picture {
ProfilePicView(pubkey: damus_state!.pubkey, size: 32, highlight: .none, profiles: damus_state!.profiles, picture: picture)
if let picture = viewModel.damus_state?.profiles.lookup(id: pubkey)?.picture {
ProfilePicView(pubkey: viewModel.damus_state!.pubkey, size: 32, highlight: .none, profiles: viewModel.damus_state!.profiles, picture: picture)
} else {
Image(systemName: "person.fill")
}
@ -217,7 +204,7 @@ struct ContentView: View {
.foregroundColor(.gray)
}
NavigationLink(destination: ConfigView(state: damus_state!)) {
NavigationLink(destination: ConfigView(state: viewModel.damus_state!)) {
Label("", systemImage: "gear")
}
.buttonStyle(PlainButtonStyle())
@ -228,19 +215,19 @@ struct ContentView: View {
.navigationViewStyle(.stack)
}
TabBar(new_events: $home.new_events, selected: $selected_timeline, action: switch_timeline)
TabBar(new_events: $home.new_events, selected: $viewModel.selected_timeline, action: switch_timeline)
}
.onAppear() {
self.connect()
//KingfisherManager.shared.cache.clearDiskCache()
setup_notifications()
}
.sheet(item: $active_sheet) { item in
.sheet(item: $viewModel.active_sheet) { item in
switch item {
case .post:
PostView(replying_to: nil, references: [])
case .reply(let event):
ReplyView(replying_to: event, damus: damus_state!)
ReplyView(replying_to: event, damus: viewModel.damus_state!)
}
}
.onOpenURL { url in
@ -251,15 +238,15 @@ struct ContentView: View {
switch link {
case .ref(let ref):
if ref.key == "p" {
active_profile = ref.ref_id
profile_open = true
viewModel.active_profile = ref.ref_id
viewModel.profile_open = true
} else if ref.key == "e" {
active_event_id = ref.ref_id
thread_open = true
viewModel.active_event_id = ref.ref_id
viewModel.thread_open = true
}
case .filter(let filt):
active_search = filt
search_open = true
viewModel.active_search = filt
viewModel.search_open = true
break
// TODO: handle filter searches?
}
@ -272,7 +259,7 @@ struct ContentView: View {
let ev = notif.object as! NostrEvent
let boost = make_boost_event(pubkey: pubkey, privkey: privkey, boosted: ev)
self.damus_state?.pool.send(.event(boost))
viewModel.damus_state?.pool.send(.event(boost))
}
.onReceive(handle_notify(.open_thread)) { obj in
//let ev = obj.object as! NostrEvent
@ -281,20 +268,20 @@ struct ContentView: View {
}
.onReceive(handle_notify(.reply)) { notif in
let ev = notif.object as! NostrEvent
self.active_sheet = .reply(ev)
viewModel.active_sheet = .reply(ev)
}
.onReceive(handle_notify(.like)) { like in
}
.onReceive(handle_notify(.broadcast_event)) { obj in
let ev = obj.object as! NostrEvent
self.damus_state?.pool.send(.event(ev))
viewModel.damus_state?.pool.send(.event(ev))
}
.onReceive(handle_notify(.unfollow)) { notif in
guard let privkey = self.privkey else {
return
}
guard let damus = self.damus_state else {
guard let damus = viewModel.damus_state else {
return
}
@ -319,7 +306,7 @@ struct ContentView: View {
}
let fnotify = notif.object as! FollowTarget
guard let damus = self.damus_state else {
guard let damus = viewModel.damus_state else {
return
}
@ -330,7 +317,7 @@ struct ContentView: View {
follow: ReferencedId(ref_id: fnotify.pubkey, relay_id: nil, key: "p")) {
notify(.followed, fnotify.pubkey)
damus_state?.contacts.event = ev
viewModel.damus_state?.contacts.event = ev
switch fnotify {
case .pubkey(let pk):
@ -350,26 +337,26 @@ struct ContentView: View {
case .post(let post):
print("post \(post.content)")
let new_ev = post_to_event(post: post, privkey: privkey, pubkey: pubkey)
self.damus_state?.pool.send(.event(new_ev))
viewModel.damus_state?.pool.send(.event(new_ev))
case .cancel:
active_sheet = nil
viewModel.active_sheet = nil
print("post cancelled")
}
}
.onReceive(timer) { n in
self.damus_state?.pool.connect_to_disconnected()
viewModel.damus_state?.pool.connect_to_disconnected()
}
}
func switch_timeline(_ timeline: Timeline) {
NotificationCenter.default.post(name: .switched_timeline, object: timeline)
if timeline == self.selected_timeline {
if timeline == viewModel.selected_timeline {
NotificationCenter.default.post(name: .scroll_to_top, object: nil)
return
}
self.selected_timeline = timeline
viewModel.selected_timeline = timeline
//NotificationCenter.default.post(name: .switched_timeline, object: timeline)
//self.selected_timeline = timeline
}
@ -394,7 +381,7 @@ struct ContentView: View {
pool.register_handler(sub_id: sub_id, handler: home.handle_event)
self.damus_state = DamusState(pool: pool, keypair: keypair,
viewModel.damus_state = DamusState(pool: pool, keypair: keypair,
likes: EventCounter(our_pubkey: pubkey),
boosts: EventCounter(our_pubkey: pubkey),
contacts: Contacts(),
@ -402,7 +389,7 @@ struct ContentView: View {
profiles: Profiles(),
dms: home.dms
)
home.damus_state = self.damus_state!
home.damus_state = viewModel.damus_state!
pool.connect()
}

25
damus/DamusViewModel.swift

@ -0,0 +1,25 @@
//
// DamusViewModel.swift
// damus
//
// Created by Sam DuBois on 12/21/22.
//
import SwiftUI
class DamusViewModel: ObservableObject {
@Published var status: String = "Not connected"
@Published var active_sheet: Sheets? = nil
@Published var damus_state: DamusState? = nil
@Published var selected_timeline: Timeline? = .home
@Published var is_thread_open: Bool = false
@Published var is_profile_open: Bool = false
@Published var event: NostrEvent? = nil
@Published var active_profile: String? = nil
@Published var active_search: NostrFilter? = nil
@Published var active_event_id: String? = nil
@Published var profile_open: Bool = false
@Published var thread_open: Bool = false
@Published var search_open: Bool = false
@Published var filter_state : FilterState = .posts_and_replies
}

12
damus/Models/CreateAccountModel.swift → damus/Models/AccountModel.swift

@ -8,12 +8,13 @@
import Foundation
class CreateAccountModel: ObservableObject {
class AccountModel: ObservableObject {
@Published var real_name: String = ""
@Published var nick_name: String = ""
@Published var about: String = ""
@Published var pubkey: String = ""
@Published var privkey: String = ""
@Published var picture: String = ""
var pubkey_bech32: String {
return bech32_pubkey(self.pubkey) ?? ""
@ -49,4 +50,13 @@ class CreateAccountModel: ObservableObject {
self.nick_name = nick
self.about = about
}
init(keys: Keypair, real: String, user: String, about: String, picture: String) {
self.pubkey = keys.pubkey
self.privkey = keys.privkey ?? ""
self.real_name = real
self.nick_name = user
self.about = about
self.picture = picture
}
}

5
damus/Nostr/NostrMetadata.swift

@ -13,8 +13,9 @@ struct NostrMetadata: Codable {
let name: String?
let about: String?
let website: String?
let picture: 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)
func account_to_metadata(_ model: AccountModel) -> NostrMetadata {
return NostrMetadata(display_name: model.real_name, name: model.nick_name, about: model.about, website: model.picture, picture: model.picture)
}

41
damus/Views/Account/EditAccountButton.swift

@ -0,0 +1,41 @@
//
// EditAccountButton.swift
// damus
//
// Created by Sam DuBois on 12/21/22.
//
import SwiftUI
struct EditAccountButton: View {
@EnvironmentObject var viewModel: DamusViewModel
@State private var presentEditAccountView: Bool = false
var body: some View {
Button {
presentEditAccountView.toggle()
} label: {
Text("Edit")
.padding(.horizontal, 20)
.padding(.vertical, 7)
.font(.caption.weight(.bold))
.foregroundColor(.white)
.background(viewModel.damus_state != nil ? hex_to_rgb(viewModel.damus_state!.pubkey) : .black)
.cornerRadius(20)
}
.sheet(isPresented: $presentEditAccountView, content: {
EditAccountView()
})
}
}
struct EditAccountButton_Previews: PreviewProvider {
static var previews: some View {
EditAccountButton()
.environmentObject(DamusViewModel())
}
}

122
damus/Views/Account/EditAccountView.swift

@ -0,0 +1,122 @@
//
// EditAccountView.swift
// damus
//
// Created by Sam DuBois on 12/20/22.
//
import SwiftUI
struct EditAccountView: View {
@EnvironmentObject var viewModel: DamusViewModel
@Environment(\.dismiss) var dismiss
@State var account: AccountModel = AccountModel()
@State var loading: Bool = true
@State var error: Error?
var body: some View {
NavigationView {
if let state = viewModel.damus_state, !loading {
Form {
HStack {
Spacer()
ProfilePicView(pubkey: state.pubkey, size: 100, highlight: .main, profiles: state.profiles)
Spacer()
}
.listRowBackground(Color.clear)
Section(header: Text("Photo")) {
TextField("Photo URL", text: $account.picture)
}
Section(header: Text("Details")) {
TextField("Username", text: $account.real_name)
TextField("Personal Name", text: $account.nick_name)
TextEditor(text: $account.about)
.frame(height: 150)
}
Section(header: Text("Keys")) {
TextField("Public Key", text: .constant(account.keypair.pubkey))
TextField("Secret Key", text: .constant(account.keypair.privkey ?? ""))
}
}
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button {
self.loading = true
viewModel.damus_state!.pool.register_handler(sub_id: "editaccount", handler: handle_event)
viewModel.damus_state!.pool.connect()
} label: {
Text("Save")
}
}
ToolbarItem(placement: .cancellationAction) {
Button {
dismiss()
} label: {
Text("Cancel")
}
}
}
} else {
ProgressView()
}
}
.onAppear {
if let state = viewModel.damus_state {
guard let profile = state.profiles.lookup(id: state.pubkey) else { return }
account = AccountModel(keys: state.keypair, real: profile.display_name ?? "", user: profile.name ?? "", about: profile.about ?? "", picture: profile.picture ?? "")
loading = false
}
}
}
func handle_event(relay: String, ev: NostrConnectionEvent) {
switch ev {
case .ws_event(let wsev):
switch wsev {
case .connected:
let metadata = account_to_metadata(account)
let m_metadata_ev = make_metadata_event(keypair: account.keypair, metadata: metadata)
if let state = viewModel.damus_state {
if let metadata_ev = m_metadata_ev {
state.pool.send(.event(metadata_ev))
}
}
case .error(let error):
self.loading = false
print(error)
default:
dismiss()
}
case .nostr_event(let resp):
switch resp {
case .notice(let msg):
// TODO handle message
// self.loading = false
// self.error = msg
print(msg)
case .event:
print("event in account edit request?")
case .eose:
break
}
}
}
}
struct EditAccountView_Previews: PreviewProvider {
static var previews: some View {
EditAccountView()
.environmentObject(DamusViewModel())
}
}

4
damus/Views/CreateAccountView.swift

@ -8,7 +8,7 @@
import SwiftUI
struct CreateAccountView: View {
@StateObject var account: CreateAccountModel = CreateAccountModel()
@StateObject var account: AccountModel = AccountModel()
@State var is_light: Bool = false
@State var is_done: Bool = false
@ -118,7 +118,7 @@ extension View {
struct CreateAccountView_Previews: PreviewProvider {
static var previews: some View {
let model = CreateAccountModel(real: "", nick: "jb55", about: "")
let model = AccountModel(real: "", nick: "jb55", about: "")
return CreateAccountView(account: model)
}
}

6
damus/Views/ProfileView.swift

@ -127,7 +127,11 @@ struct ProfileView: View {
DMButton
FollowButtonView(target: profile.get_follow_target(), follow_state: damus_state.contacts.follow_state(profile.pubkey))
if damus_state.pubkey == profile.pubkey {
EditAccountButton()
} else {
FollowButtonView(target: profile.get_follow_target(), follow_state: damus_state.contacts.follow_state(profile.pubkey))
}
}
ProfileNameView(pubkey: profile.pubkey, profile: data, contacts: damus_state.contacts)

8
damus/Views/SaveKeysView.swift

@ -8,7 +8,7 @@
import SwiftUI
struct SaveKeysView: View {
let account: CreateAccountModel
let account: AccountModel
let pool: RelayPool = RelayPool()
@State var is_done: Bool = false
@State var pub_copied: Bool = false
@ -79,7 +79,7 @@ struct SaveKeysView: View {
.navigationBarItems(leading: BackNav())
}
func complete_account_creation(_ account: CreateAccountModel) {
func complete_account_creation(_ account: AccountModel) {
for relay in BOOTSTRAP_RELAYS {
add_rw_relay(self.pool, relay)
}
@ -96,7 +96,7 @@ struct SaveKeysView: View {
case .ws_event(let wsev):
switch wsev {
case .connected:
let metadata = create_account_to_metadata(account)
let metadata = account_to_metadata(account)
let m_metadata_ev = make_metadata_event(keypair: account.keypair, metadata: metadata)
let m_contacts_ev = make_first_contact_event(keypair: account.keypair)
@ -175,7 +175,7 @@ struct SaveKeyView: View {
struct SaveKeysView_Previews: PreviewProvider {
static var previews: some View {
let model = CreateAccountModel(real: "William", nick: "jb55", about: "I'm me")
let model = AccountModel(real: "William", nick: "jb55", about: "I'm me")
SaveKeysView(account: model)
}
}

3
damus/damusApp.swift

@ -23,10 +23,13 @@ struct MainView: View {
@State var needs_setup = false;
@State var keypair: Keypair? = nil;
@ObservedObject var viewModel: DamusViewModel = DamusViewModel()
var body: some View {
Group {
if let kp = keypair, !needs_setup {
ContentView(keypair: kp)
.environmentObject(viewModel)
} else {
SetupView()
.onReceive(handle_notify(.login)) { notif in

Loading…
Cancel
Save