Browse Source

Add DM button to profile

Signed-off-by: William Casarin <jb55@jb55.com>
profiles-everywhere
William Casarin 3 years ago
parent
commit
366293315d
  1. 4
      damus.xcodeproj/project.pbxproj
  2. 6
      damus/ContentView.swift
  3. 3
      damus/Models/DamusState.swift
  4. 20
      damus/Models/DirectMessageModel.swift
  5. 20
      damus/Models/DirectMessagesModel.swift
  6. 16
      damus/Models/HomeModel.swift
  7. 14
      damus/Views/DMChatView.swift
  8. 35
      damus/Views/DirectMessagesView.swift
  9. 2
      damus/Views/NoteContentView.swift
  10. 15
      damus/Views/ProfileView.swift

4
damus.xcodeproj/project.pbxproj

@ -16,6 +16,7 @@
4C216F32286E388800040376 /* DMChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C216F31286E388800040376 /* DMChatView.swift */; }; 4C216F32286E388800040376 /* DMChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C216F31286E388800040376 /* DMChatView.swift */; };
4C216F34286F5ACD00040376 /* DMView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C216F33286F5ACD00040376 /* DMView.swift */; }; 4C216F34286F5ACD00040376 /* DMView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C216F33286F5ACD00040376 /* DMView.swift */; };
4C216F362870A9A700040376 /* InputDismissKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C216F352870A9A700040376 /* InputDismissKeyboard.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 */; }; 4C285C8228385570008A31F1 /* CarouselView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8128385570008A31F1 /* CarouselView.swift */; };
4C285C8428385690008A31F1 /* CreateAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8328385690008A31F1 /* CreateAccountView.swift */; }; 4C285C8428385690008A31F1 /* CreateAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8328385690008A31F1 /* CreateAccountView.swift */; };
4C285C86283892E7008A31F1 /* CreateAccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C85283892E7008A31F1 /* CreateAccountModel.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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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 /* CreateAccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateAccountModel.swift; sourceTree = "<group>"; };
@ -279,6 +281,7 @@
4C5C7E67284ED36500A22DF5 /* SearchHomeModel.swift */, 4C5C7E67284ED36500A22DF5 /* SearchHomeModel.swift */,
4C649843285A952100EAE2B3 /* LocalUserConfig.swift */, 4C649843285A952100EAE2B3 /* LocalUserConfig.swift */,
4C64987D286D082C00EAE2B3 /* DirectMessagesModel.swift */, 4C64987D286D082C00EAE2B3 /* DirectMessagesModel.swift */,
4C216F372871EDE300040376 /* DirectMessageModel.swift */,
); );
path = Models; path = Models;
sourceTree = "<group>"; sourceTree = "<group>";
@ -609,6 +612,7 @@
4C477C9E282C3A4800033AA3 /* TipCounter.swift in Sources */, 4C477C9E282C3A4800033AA3 /* TipCounter.swift in Sources */,
4C0A3F91280F6528000448DE /* ChatView.swift in Sources */, 4C0A3F91280F6528000448DE /* ChatView.swift in Sources */,
4C216F362870A9A700040376 /* InputDismissKeyboard.swift in Sources */, 4C216F362870A9A700040376 /* InputDismissKeyboard.swift in Sources */,
4C216F382871EDE300040376 /* DirectMessageModel.swift in Sources */,
4C75EFA627FF87A20006080F /* Nostr.swift in Sources */, 4C75EFA627FF87A20006080F /* Nostr.swift in Sources */,
4CE4F9DE2852768D00C00DD9 /* ConfigView.swift in Sources */, 4CE4F9DE2852768D00C00DD9 /* ConfigView.swift in Sources */,
4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */, 4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */,

6
damus/ContentView.swift

@ -123,7 +123,8 @@ struct ContentView: View {
.navigationTitle("Notifications") .navigationTitle("Notifications")
case .dms: case .dms:
DirectMessagesView(damus_state: damus_state!, dms: $home.dms) DirectMessagesView(damus_state: damus_state!)
.environmentObject(home.dms)
case .none: case .none:
EmptyView() EmptyView()
@ -345,7 +346,8 @@ struct ContentView: View {
contacts: Contacts(), contacts: Contacts(),
tips: TipCounter(our_pubkey: pubkey), tips: TipCounter(our_pubkey: pubkey),
image_cache: ImageCache(), image_cache: ImageCache(),
profiles: Profiles() profiles: Profiles(),
dms: home.dms
) )
home.damus_state = self.damus_state! home.damus_state = self.damus_state!

3
damus/Models/DamusState.swift

@ -16,12 +16,13 @@ struct DamusState {
let tips: TipCounter let tips: TipCounter
let image_cache: ImageCache let image_cache: ImageCache
let profiles: Profiles let profiles: Profiles
let dms: DirectMessagesModel
var pubkey: String { var pubkey: String {
return keypair.pubkey return keypair.pubkey
} }
static var empty: DamusState { 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())
} }
} }

20
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 = []
}
}

20
damus/Models/DirectMessagesModel.swift

@ -8,8 +8,26 @@
import Foundation import Foundation
class DirectMessagesModel: ObservableObject { class DirectMessagesModel: ObservableObject {
@Published var events: [(String, [NostrEvent])] = [] @Published var dms: [(String, DirectMessageModel)] = []
@Published var loading: Bool = false @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
}
} }

16
damus/Models/HomeModel.swift

@ -44,7 +44,7 @@ class HomeModel: ObservableObject {
@Published var new_events: NewEventsBits = NewEventsBits() @Published var new_events: NewEventsBits = NewEventsBits()
@Published var notifications: [NostrEvent] = [] @Published var notifications: [NostrEvent] = []
@Published var dms: [(String, [NostrEvent])] = [] @Published var dms: DirectMessagesModel = DirectMessagesModel()
@Published var events: [NostrEvent] = [] @Published var events: [NostrEvent] = []
@Published var loading: Bool = false @Published var loading: Bool = false
@Published var signal: SignalModel = SignalModel() @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 { if pk == the_pk {
found = true 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 $0.created_at < $1.created_at
} }
@ -386,14 +386,18 @@ class HomeModel: ObservableObject {
if !found { if !found {
inserted = true inserted = true
dms.append((the_pk, [ev])) let model = DirectMessageModel(events: [ev])
dms.dms.append((the_pk, model))
} }
if inserted { if inserted {
handle_last_event(ev: ev, timeline: .dms) handle_last_event(ev: ev, timeline: .dms)
dms = dms.sorted { a, b in dms.dms = dms.dms.sorted { a, b in
a.1.last!.created_at > b.1.last!.created_at 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
} }
} }
} }

14
damus/Views/DMChatView.swift

@ -10,15 +10,15 @@ import SwiftUI
struct DMChatView: View { struct DMChatView: View {
let damus_state: DamusState let damus_state: DamusState
let pubkey: String let pubkey: String
@Binding var events: [NostrEvent] @EnvironmentObject var dms: DirectMessageModel
@State var message: String = "" @State var message: String = ""
var Messages: some View { var Messages: some View {
ScrollViewReader { scroller in ScrollViewReader { scroller in
ScrollView { ScrollView {
VStack(alignment: .leading) { VStack(alignment: .leading) {
ForEach(Array(zip(events, events.indices)), id: \.0.id) { (ev, ind) in ForEach(Array(zip(dms.events, dms.events.indices)), id: \.0.id) { (ev, ind) in
DMView(event: events[ind], damus_state: damus_state) DMView(event: dms.events[ind], damus_state: damus_state)
.event_context_menu(ev) .event_context_menu(ev)
} }
Color.white.opacity(0) Color.white.opacity(0)
@ -125,11 +125,11 @@ struct DMChatView: View {
struct DMChatView_Previews: PreviewProvider { struct DMChatView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
let ev = NostrEvent(content: "hi", pubkey: "pubkey", kind: 1, tags: []) 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)
} }
} }

35
damus/Views/DirectMessagesView.swift

@ -9,22 +9,29 @@ import SwiftUI
struct DirectMessagesView: View { struct DirectMessagesView: View {
let damus_state: DamusState let damus_state: DamusState
@Binding var dms: [(String, [NostrEvent])] @EnvironmentObject var model: DirectMessagesModel
var MainContent: some View { var MainContent: some View {
ScrollView { ScrollView {
VStack { VStack {
ForEach(dms, id: \.0) { tup in ForEach(model.dms, id: \.0) { tup in
let evs = Binding<[NostrEvent]>.init( MaybeEvent(tup)
get: { tup.1 }, }
set: { _ in } }
) }
let chat = DMChatView(damus_state: damus_state, pubkey: tup.0, events: evs) }
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) { NavigationLink(destination: chat) {
EventView(damus: damus_state, event: tup.1.last!, pubkey: tup.0) EventView(damus: damus_state, event: ev, pubkey: tup.0)
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
} } else {
EmptyView()
} }
} }
} }
@ -41,12 +48,8 @@ struct DirectMessagesView_Previews: PreviewProvider {
pubkey: "pubkey", pubkey: "pubkey",
kind: 4, kind: 4,
tags: []) tags: [])
let dms = Binding<[(String, [NostrEvent])]>.init( let model = DirectMessageModel(events: [ev])
get: { DirectMessagesView(damus_state: test_damus_state())
return [ ("pubkey", [ ev ]) ] .environmentObject(model)
},
set: { _ in }
)
DirectMessagesView(damus_state: test_damus_state(), dms: dms)
} }
} }

2
damus/Views/NoteContentView.swift

@ -33,7 +33,7 @@ struct NoteContentView: View {
let md_opts: AttributedString.MarkdownParsingOptions = let md_opts: AttributedString.MarkdownParsingOptions =
.init(interpretedSyntax: .inlineOnlyPreservingWhitespace) .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) return Text(content)
} }

15
damus/Views/ProfileView.swift

@ -75,6 +75,16 @@ struct ProfileView: View {
//@EnvironmentObject var profile: ProfileModel //@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 { var TopSection: some View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
let data = damus_state.profiles.lookup(id: profile.pubkey) let data = damus_state.profiles.lookup(id: profile.pubkey)
@ -86,6 +96,9 @@ struct ProfileView: View {
Spacer() Spacer()
DMButton
.padding([.trailing], 20)
FollowButtonView(target: profile.get_follow_target(), follow_state: damus_state.contacts.follow_state(profile.pubkey)) 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 { func test_damus_state() -> DamusState {
let pubkey = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681" 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 prof = Profile(name: "damus", display_name: "Damus", about: "iOS app!", picture: "https://damus.io/img/logo.png")
let tsprof = TimestampedProfile(profile: prof, timestamp: 0) let tsprof = TimestampedProfile(profile: prof, timestamp: 0)

Loading…
Cancel
Save