damus

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

commit 366293315d93da92f6e7b2312cc714888b35c205
parent 471f29f7ea6847571deaa3313c5b632f26dc2a91
Author: William Casarin <jb55@jb55.com>
Date:   Sun,  3 Jul 2022 09:23:08 -0700

Add DM button to profile

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 4++++
Mdamus/ContentView.swift | 6++++--
Mdamus/Models/DamusState.swift | 3++-
Adamus/Models/DirectMessageModel.swift | 20++++++++++++++++++++
Mdamus/Models/DirectMessagesModel.swift | 20+++++++++++++++++++-
Mdamus/Models/HomeModel.swift | 16++++++++++------
Mdamus/Views/DMChatView.swift | 14+++++++-------
Mdamus/Views/DirectMessagesView.swift | 39+++++++++++++++++++++------------------
Mdamus/Views/NoteContentView.swift | 2+-
Mdamus/Views/ProfileView.swift | 15++++++++++++++-
10 files changed, 102 insertions(+), 37 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 4C216F32286E388800040376 /* DMChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C216F31286E388800040376 /* DMChatView.swift */; }; 4C216F34286F5ACD00040376 /* DMView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C216F33286F5ACD00040376 /* DMView.swift */; }; 4C216F362870A9A700040376 /* InputDismissKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C216F352870A9A700040376 /* InputDismissKeyboard.swift */; }; + 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 */; }; @@ -132,6 +133,7 @@ 4C216F31286E388800040376 /* DMChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DMChatView.swift; sourceTree = "<group>"; }; 4C216F33286F5ACD00040376 /* DMView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DMView.swift; sourceTree = "<group>"; }; 4C216F352870A9A700040376 /* InputDismissKeyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputDismissKeyboard.swift; sourceTree = "<group>"; }; + 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>"; }; @@ -279,6 +281,7 @@ 4C5C7E67284ED36500A22DF5 /* SearchHomeModel.swift */, 4C649843285A952100EAE2B3 /* LocalUserConfig.swift */, 4C64987D286D082C00EAE2B3 /* DirectMessagesModel.swift */, + 4C216F372871EDE300040376 /* DirectMessageModel.swift */, ); path = Models; sourceTree = "<group>"; @@ -609,6 +612,7 @@ 4C477C9E282C3A4800033AA3 /* TipCounter.swift in Sources */, 4C0A3F91280F6528000448DE /* ChatView.swift in Sources */, 4C216F362870A9A700040376 /* InputDismissKeyboard.swift in Sources */, + 4C216F382871EDE300040376 /* DirectMessageModel.swift in Sources */, 4C75EFA627FF87A20006080F /* Nostr.swift in Sources */, 4CE4F9DE2852768D00C00DD9 /* ConfigView.swift in Sources */, 4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */, diff --git a/damus/ContentView.swift b/damus/ContentView.swift @@ -123,7 +123,8 @@ struct ContentView: View { .navigationTitle("Notifications") case .dms: - DirectMessagesView(damus_state: damus_state!, dms: $home.dms) + DirectMessagesView(damus_state: damus_state!) + .environmentObject(home.dms) case .none: EmptyView() @@ -345,7 +346,8 @@ struct ContentView: View { contacts: Contacts(), tips: TipCounter(our_pubkey: pubkey), image_cache: ImageCache(), - profiles: Profiles() + profiles: Profiles(), + dms: home.dms ) home.damus_state = self.damus_state! diff --git a/damus/Models/DamusState.swift b/damus/Models/DamusState.swift @@ -16,12 +16,13 @@ struct DamusState { let tips: TipCounter let image_cache: ImageCache let profiles: Profiles + let dms: DirectMessagesModel var pubkey: String { return keypair.pubkey } static var empty: DamusState { - return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(), tips: TipCounter(our_pubkey: ""), image_cache: ImageCache(), profiles: Profiles()) + return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(), tips: TipCounter(our_pubkey: ""), image_cache: ImageCache(), profiles: Profiles(), dms: DirectMessagesModel()) } } diff --git a/damus/Models/DirectMessageModel.swift b/damus/Models/DirectMessageModel.swift @@ -0,0 +1,20 @@ +// +// DirectMessageModel.swift +// damus +// +// Created by William Casarin on 2022-07-03. +// + +import Foundation + +class DirectMessageModel: ObservableObject { + @Published var events: [NostrEvent] + + init(events: [NostrEvent]) { + self.events = events + } + + init() { + self.events = [] + } +} diff --git a/damus/Models/DirectMessagesModel.swift b/damus/Models/DirectMessagesModel.swift @@ -8,8 +8,26 @@ import Foundation class DirectMessagesModel: ObservableObject { - @Published var events: [(String, [NostrEvent])] = [] + @Published var dms: [(String, DirectMessageModel)] = [] @Published var loading: Bool = false + func lookup_or_create(_ pubkey: String) -> DirectMessageModel { + if let dm = lookup(pubkey) { + return dm + } + + let new = DirectMessageModel() + dms.append((pubkey, new)) + return new + } + func lookup(_ pubkey: String) -> DirectMessageModel? { + for dm in dms { + if pubkey == dm.0 { + return dm.1 + } + } + + return nil + } } diff --git a/damus/Models/HomeModel.swift b/damus/Models/HomeModel.swift @@ -44,7 +44,7 @@ class HomeModel: ObservableObject { @Published var new_events: NewEventsBits = NewEventsBits() @Published var notifications: [NostrEvent] = [] - @Published var dms: [(String, [NostrEvent])] = [] + @Published var dms: DirectMessagesModel = DirectMessagesModel() @Published var events: [NostrEvent] = [] @Published var loading: Bool = false @Published var signal: SignalModel = SignalModel() @@ -372,10 +372,10 @@ class HomeModel: ObservableObject { } } - for (pk, _) in dms { + for (pk, _) in dms.dms { if pk == the_pk { found = true - inserted = insert_uniq_sorted_event(events: &(dms[i].1), new_ev: ev) { + inserted = insert_uniq_sorted_event(events: &(dms.dms[i].1.events), new_ev: ev) { $0.created_at < $1.created_at } @@ -386,14 +386,18 @@ class HomeModel: ObservableObject { if !found { inserted = true - dms.append((the_pk, [ev])) + let model = DirectMessageModel(events: [ev]) + dms.dms.append((the_pk, model)) } if inserted { handle_last_event(ev: ev, timeline: .dms) - dms = dms.sorted { a, b in - a.1.last!.created_at > b.1.last!.created_at + dms.dms = dms.dms.sorted { a, b in + if a.1.events.count > 0 && b.1.events.count > 0 { + return a.1.events.last!.created_at > b.1.events.last!.created_at + } + return true } } } diff --git a/damus/Views/DMChatView.swift b/damus/Views/DMChatView.swift @@ -10,15 +10,15 @@ import SwiftUI struct DMChatView: View { let damus_state: DamusState let pubkey: String - @Binding var events: [NostrEvent] + @EnvironmentObject var dms: DirectMessageModel @State var message: String = "" var Messages: some View { ScrollViewReader { scroller in ScrollView { VStack(alignment: .leading) { - ForEach(Array(zip(events, events.indices)), id: \.0.id) { (ev, ind) in - DMView(event: events[ind], damus_state: damus_state) + ForEach(Array(zip(dms.events, dms.events.indices)), id: \.0.id) { (ev, ind) in + DMView(event: dms.events[ind], damus_state: damus_state) .event_context_menu(ev) } Color.white.opacity(0) @@ -125,11 +125,11 @@ struct DMChatView: View { struct DMChatView_Previews: PreviewProvider { static var previews: some View { let ev = NostrEvent(content: "hi", pubkey: "pubkey", kind: 1, tags: []) - let evs = Binding<[NostrEvent]>.init( - get: { [ev] }, - set: { _ in }) - DMChatView(damus_state: test_damus_state(), pubkey: "pubkey", events: evs) + let model = DirectMessageModel(events: [ev]) + + DMChatView(damus_state: test_damus_state(), pubkey: "pubkey") + .environmentObject(model) } } diff --git a/damus/Views/DirectMessagesView.swift b/damus/Views/DirectMessagesView.swift @@ -9,26 +9,33 @@ import SwiftUI struct DirectMessagesView: View { let damus_state: DamusState - @Binding var dms: [(String, [NostrEvent])] + @EnvironmentObject var model: DirectMessagesModel var MainContent: some View { ScrollView { VStack { - ForEach(dms, id: \.0) { tup in - let evs = Binding<[NostrEvent]>.init( - get: { tup.1 }, - set: { _ in } - ) - let chat = DMChatView(damus_state: damus_state, pubkey: tup.0, events: evs) - NavigationLink(destination: chat) { - EventView(damus: damus_state, event: tup.1.last!, pubkey: tup.0) - } - .buttonStyle(PlainButtonStyle()) + ForEach(model.dms, id: \.0) { tup in + MaybeEvent(tup) } } } } + func MaybeEvent(_ tup: (String, DirectMessageModel)) -> some View { + Group { + if let ev = tup.1.events.last { + let chat = DMChatView(damus_state: damus_state, pubkey: tup.0) + .environmentObject(tup.1) + NavigationLink(destination: chat) { + EventView(damus: damus_state, event: ev, pubkey: tup.0) + } + .buttonStyle(PlainButtonStyle()) + } else { + EmptyView() + } + } + } + var body: some View { MainContent .navigationTitle("Encrypted DMs") @@ -41,12 +48,8 @@ struct DirectMessagesView_Previews: PreviewProvider { pubkey: "pubkey", kind: 4, tags: []) - let dms = Binding<[(String, [NostrEvent])]>.init( - get: { - return [ ("pubkey", [ ev ]) ] - }, - set: { _ in } - ) - DirectMessagesView(damus_state: test_damus_state(), dms: dms) + let model = DirectMessageModel(events: [ev]) + DirectMessagesView(damus_state: test_damus_state()) + .environmentObject(model) } } diff --git a/damus/Views/NoteContentView.swift b/damus/Views/NoteContentView.swift @@ -33,7 +33,7 @@ struct NoteContentView: View { let md_opts: AttributedString.MarkdownParsingOptions = .init(interpretedSyntax: .inlineOnlyPreservingWhitespace) - guard var txt = try? AttributedString(markdown: content, options: md_opts) else { + guard let txt = try? AttributedString(markdown: content, options: md_opts) else { return Text(content) } diff --git a/damus/Views/ProfileView.swift b/damus/Views/ProfileView.swift @@ -75,6 +75,16 @@ struct ProfileView: View { //@EnvironmentObject var profile: ProfileModel + var DMButton: some View { + let dm_model = damus_state.dms.lookup_or_create(profile.pubkey) + let dmview = DMChatView(damus_state: damus_state, pubkey: profile.pubkey) + .environmentObject(dm_model) + return NavigationLink(destination: dmview) { + Label("", systemImage: "text.bubble") + } + .buttonStyle(PlainButtonStyle()) + } + var TopSection: some View { VStack(alignment: .leading) { let data = damus_state.profiles.lookup(id: profile.pubkey) @@ -86,6 +96,9 @@ struct ProfileView: View { Spacer() + DMButton + .padding([.trailing], 20) + FollowButtonView(target: profile.get_follow_target(), follow_state: damus_state.contacts.follow_state(profile.pubkey)) } @@ -162,7 +175,7 @@ struct ProfileView_Previews: PreviewProvider { 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), image_cache: ImageCache(), profiles: Profiles()) + 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), image_cache: ImageCache(), profiles: Profiles(), dms: DirectMessagesModel()) let prof = Profile(name: "damus", display_name: "Damus", about: "iOS app!", picture: "https://damus.io/img/logo.png") let tsprof = TimestampedProfile(profile: prof, timestamp: 0)