damus

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

commit bc638f79f6bc4d17d86062dbbf1f44a106bd5a41
parent 47a6f7ff3809319ccb0695ad69e80ff7df641a4c
Author: Terry Yiu <963907+tyiu@users.noreply.github.com>
Date:   Sun, 12 Feb 2023 21:22:25 -0500

Add saved drafts to posts, replies, and DMs

Changelog-Added: Save drafts to posts, replies and DMs
Closes: #582

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 4++++
Mdamus/ContentView.swift | 28+++++++++++++++-------------
Mdamus/Models/DamusState.swift | 3++-
Mdamus/Models/DirectMessageModel.swift | 4++++
Adamus/Models/DraftsModel.swift | 13+++++++++++++
Mdamus/Models/HomeModel.swift | 3+++
Mdamus/Views/DMChatView.swift | 18+++++++++++-------
Mdamus/Views/PostView.swift | 31+++++++++++++++++++++++++++++++
8 files changed, 83 insertions(+), 21 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */; }; 3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FE297E3D900090C62D /* RepostsView.swift */; }; 3AA24802297E3DC20090C62D /* RepostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA24801297E3DC20090C62D /* RepostView.swift */; }; + 3AA59D1D2999B0400061C48E /* DraftsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA59D1C2999B0400061C48E /* DraftsModel.swift */; }; 3AAA95CA298DF87B00F3D526 /* TranslationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AAA95C9298DF87B00F3D526 /* TranslationService.swift */; }; 3AAA95CC298E07E900F3D526 /* DeepLPlan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AAA95CB298E07E900F3D526 /* DeepLPlan.swift */; }; 3AB72AB9298ECF30004BB58C /* Translator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB72AB8298ECF30004BB58C /* Translator.swift */; }; @@ -270,6 +271,7 @@ 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepostsModel.swift; sourceTree = "<group>"; }; 3AA247FE297E3D900090C62D /* RepostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostsView.swift; sourceTree = "<group>"; }; 3AA24801297E3DC20090C62D /* RepostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostView.swift; sourceTree = "<group>"; }; + 3AA59D1C2999B0400061C48E /* DraftsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsModel.swift; sourceTree = "<group>"; }; 3AAA95C9298DF87B00F3D526 /* TranslationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationService.swift; sourceTree = "<group>"; }; 3AAA95CB298E07E900F3D526 /* DeepLPlan.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLPlan.swift; sourceTree = "<group>"; }; 3AB5B86A2986D8A3006599D2 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = "<group>"; }; @@ -660,6 +662,7 @@ 3AAA95C9298DF87B00F3D526 /* TranslationService.swift */, 3AAA95CB298E07E900F3D526 /* DeepLPlan.swift */, 4CE8795A2996C47A00F758CC /* ZapsModel.swift */, + 3AA59D1C2999B0400061C48E /* DraftsModel.swift */, ); path = Models; sourceTree = "<group>"; @@ -1352,6 +1355,7 @@ 4CC7AAFA297F64AC00430951 /* EventMenu.swift in Sources */, 4C75EFBB2804A34C0006080F /* ProofOfWork.swift in Sources */, 4C3AC7A52836987600E1F516 /* MainTabView.swift in Sources */, + 3AA59D1D2999B0400061C48E /* DraftsModel.swift in Sources */, 3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */, 4CB9D4A72992D02B00A9A7E4 /* ProfileNameView.swift in Sources */, ); diff --git a/damus/ContentView.swift b/damus/ContentView.swift @@ -606,19 +606,21 @@ struct ContentView: View { pool.register_handler(sub_id: sub_id, handler: home.handle_event) - self.damus_state = DamusState(pool: pool, keypair: keypair, - likes: EventCounter(our_pubkey: pubkey), - boosts: EventCounter(our_pubkey: pubkey), - contacts: Contacts(our_pubkey: pubkey), - tips: TipCounter(our_pubkey: pubkey), - profiles: Profiles(), - dms: home.dms, - previews: PreviewCache(), - zaps: Zaps(our_pubkey: pubkey), - lnurls: LNUrls(), - settings: UserSettingsStore(), - relay_filters: relay_filters, - relay_metadata: metadatas + self.damus_state = DamusState(pool: pool, + keypair: keypair, + likes: EventCounter(our_pubkey: pubkey), + boosts: EventCounter(our_pubkey: pubkey), + contacts: Contacts(our_pubkey: pubkey), + tips: TipCounter(our_pubkey: pubkey), + profiles: Profiles(), + dms: home.dms, + previews: PreviewCache(), + zaps: Zaps(our_pubkey: pubkey), + lnurls: LNUrls(), + settings: UserSettingsStore(), + relay_filters: relay_filters, + relay_metadata: metadatas, + drafts_model: home.drafts_model ) home.damus_state = self.damus_state! diff --git a/damus/Models/DamusState.swift b/damus/Models/DamusState.swift @@ -23,6 +23,7 @@ struct DamusState { let settings: UserSettingsStore let relay_filters: RelayFilters let relay_metadata: RelayMetadatas + let drafts_model: DraftsModel var pubkey: String { return keypair.pubkey @@ -34,6 +35,6 @@ struct DamusState { static var empty: DamusState { - return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(our_pubkey: ""), tips: TipCounter(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(our_pubkey: ""), previews: PreviewCache(), zaps: Zaps(our_pubkey: ""), lnurls: LNUrls(), settings: UserSettingsStore(), relay_filters: RelayFilters(our_pubkey: ""), relay_metadata: RelayMetadatas()) + return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(our_pubkey: ""), tips: TipCounter(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(our_pubkey: ""), previews: PreviewCache(), zaps: Zaps(our_pubkey: ""), lnurls: LNUrls(), settings: UserSettingsStore(), relay_filters: RelayFilters(our_pubkey: ""), relay_metadata: RelayMetadatas(), drafts_model: DraftsModel()) } } diff --git a/damus/Models/DirectMessageModel.swift b/damus/Models/DirectMessageModel.swift @@ -13,6 +13,8 @@ class DirectMessageModel: ObservableObject { is_request = determine_is_request() } } + + @Published var draft: String var is_request: Bool var our_pubkey: String @@ -31,11 +33,13 @@ class DirectMessageModel: ObservableObject { self.events = events self.is_request = false self.our_pubkey = our_pubkey + self.draft = "" } init(our_pubkey: String) { self.events = [] self.is_request = false self.our_pubkey = our_pubkey + self.draft = "" } } diff --git a/damus/Models/DraftsModel.swift b/damus/Models/DraftsModel.swift @@ -0,0 +1,13 @@ +// +// DraftsModel.swift +// damus +// +// Created by Terry Yiu on 2/12/23. +// + +import Foundation + +class DraftsModel: ObservableObject { + @Published var post: String = "" + @Published var replies = Dictionary<NostrEvent, String>() +} diff --git a/damus/Models/HomeModel.swift b/damus/Models/HomeModel.swift @@ -52,15 +52,18 @@ class HomeModel: ObservableObject { @Published var events: [NostrEvent] = [] @Published var loading: Bool = false @Published var signal: SignalModel = SignalModel() + @Published var drafts_model: DraftsModel init() { self.damus_state = DamusState.empty self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey) + self.drafts_model = DraftsModel() } init(damus_state: DamusState) { self.damus_state = damus_state self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey) + self.drafts_model = DraftsModel() } var pool: RelayPool { diff --git a/damus/Views/DMChatView.swift b/damus/Views/DMChatView.swift @@ -11,7 +11,6 @@ struct DMChatView: View { let damus_state: DamusState let pubkey: String @EnvironmentObject var dms: DirectMessageModel - @State var message: String = "" @State var showPrivateKeyWarning: Bool = false var Messages: some View { @@ -52,7 +51,7 @@ struct DMChatView: View { } var InputField: some View { - TextEditor(text: $message) + TextEditor(text: $dms.draft) .textEditorBackground { InputBackground() } @@ -93,11 +92,11 @@ struct DMChatView: View { HStack(spacing: 0) { InputField - if !message.isEmpty { + if !dms.draft.isEmpty { Button( role: .none, action: { - showPrivateKeyWarning = contentContainsPrivateKey(message) + showPrivateKeyWarning = contentContainsPrivateKey(dms.draft) if !showPrivateKeyWarning { send_message() @@ -112,7 +111,7 @@ struct DMChatView: View { .fixedSize(horizontal: false, vertical: true) .frame(minHeight: 70, maxHeight: 150, alignment: .bottom) - Text(message).opacity(0).padding(.all, 8) + Text(dms.draft).opacity(0).padding(.all, 8) .fixedSize(horizontal: false, vertical: true) .frame(minHeight: 70, maxHeight: 150, alignment: .bottom) } @@ -122,7 +121,7 @@ struct DMChatView: View { func send_message() { let tags = [["p", pubkey]] - let post_blocks = parse_post_blocks(content: message) + let post_blocks = parse_post_blocks(content: dms.draft) let post_tags = make_post_tags(post_blocks: post_blocks, tags: tags) let content = render_blocks(blocks: post_tags.blocks) @@ -131,7 +130,7 @@ struct DMChatView: View { return } - message = "" + dms.draft = "" damus_state.pool.send(.event(dm)) end_editing() @@ -157,6 +156,11 @@ struct DMChatView: View { } .navigationTitle(NSLocalizedString("DMs", comment: "Navigation title for DMs view, where DM is the English abbreviation for Direct Message.")) .toolbar { Header } + .onDisappear { + if dms.draft.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { + dms.draft = "" + } + } .alert(NSLocalizedString("Note contains \"nsec1\" private key. Are you sure?", comment: "Alert user that they might be attempting to paste a private key and ask them to confirm."), isPresented: $showPrivateKeyWarning, actions: { Button(NSLocalizedString("No", comment: "Button to cancel out of posting a note after being alerted that it looks like they might be posting a private key."), role: .cancel) { showPrivateKeyWarning = false diff --git a/damus/Views/PostView.swift b/damus/Views/PostView.swift @@ -16,6 +16,7 @@ let POST_PLACEHOLDER = NSLocalizedString("Type your post here...", comment: "Tex struct PostView: View { @State var post: String = "" + @FocusState var focus: Bool @State var showPrivateKeyWarning: Bool = false @@ -47,6 +48,13 @@ struct PostView: View { let new_post = NostrPost(content: content, references: references, kind: kind) NotificationCenter.default.post(name: .post, object: NostrPostResult.post(new_post)) + + if replying_to == nil { + damus_state.drafts_model.post = "" + } else { + damus_state.drafts_model.replies.removeValue(forKey: replying_to!) + } + dismiss() } @@ -80,6 +88,13 @@ struct PostView: View { TextEditor(text: $post) .focused($focus) .textInputAutocapitalization(.sentences) + .onChange(of: post) { _ in + if replying_to == nil { + damus_state.drafts_model.post = post + } else { + damus_state.drafts_model.replies[replying_to!] = post + } + } if post.isEmpty { Text(POST_PLACEHOLDER) @@ -99,10 +114,26 @@ struct PostView: View { } } .onAppear() { + if replying_to == nil { + post = damus_state.drafts_model.post + } else { + if damus_state.drafts_model.replies[replying_to!] == nil { + damus_state.drafts_model.replies[replying_to!] = "" + } + post = damus_state.drafts_model.replies[replying_to!]! + } + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.focus = true } } + .onDisappear { + if replying_to == nil && damus_state.drafts_model.post.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { + damus_state.drafts_model.post = "" + } else if replying_to != nil && damus_state.drafts_model.replies[replying_to!]?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true { + damus_state.drafts_model.replies.removeValue(forKey: replying_to!) + } + } .padding() .alert(NSLocalizedString("Note contains \"nsec1\" private key. Are you sure?", comment: "Alert user that they might be attempting to paste a private key and ask them to confirm."), isPresented: $showPrivateKeyWarning, actions: { Button(NSLocalizedString("No", comment: "Button to cancel out of posting a note after being alerted that it looks like they might be posting a private key."), role: .cancel) {