1
0
mirror of git://jb55.com/damus synced 2024-09-19 19:46:51 +00:00

Add saved drafts to posts, replies, and DMs

Changelog-Added: Save drafts to posts, replies and DMs
Closes: #582
This commit is contained in:
Terry Yiu 2023-02-12 21:22:25 -05:00 committed by William Casarin
parent 47a6f7ff38
commit bc638f79f6
8 changed files with 83 additions and 21 deletions

View File

@ -15,6 +15,7 @@
3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */; }; 3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */; };
3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FE297E3D900090C62D /* RepostsView.swift */; }; 3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FE297E3D900090C62D /* RepostsView.swift */; };
3AA24802297E3DC20090C62D /* RepostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA24801297E3DC20090C62D /* RepostView.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 */; }; 3AAA95CA298DF87B00F3D526 /* TranslationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AAA95C9298DF87B00F3D526 /* TranslationService.swift */; };
3AAA95CC298E07E900F3D526 /* DeepLPlan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AAA95CB298E07E900F3D526 /* DeepLPlan.swift */; }; 3AAA95CC298E07E900F3D526 /* DeepLPlan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AAA95CB298E07E900F3D526 /* DeepLPlan.swift */; };
3AB72AB9298ECF30004BB58C /* Translator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB72AB8298ECF30004BB58C /* Translator.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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 3AB5B86A2986D8A3006599D2 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@ -660,6 +662,7 @@
3AAA95C9298DF87B00F3D526 /* TranslationService.swift */, 3AAA95C9298DF87B00F3D526 /* TranslationService.swift */,
3AAA95CB298E07E900F3D526 /* DeepLPlan.swift */, 3AAA95CB298E07E900F3D526 /* DeepLPlan.swift */,
4CE8795A2996C47A00F758CC /* ZapsModel.swift */, 4CE8795A2996C47A00F758CC /* ZapsModel.swift */,
3AA59D1C2999B0400061C48E /* DraftsModel.swift */,
); );
path = Models; path = Models;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1352,6 +1355,7 @@
4CC7AAFA297F64AC00430951 /* EventMenu.swift in Sources */, 4CC7AAFA297F64AC00430951 /* EventMenu.swift in Sources */,
4C75EFBB2804A34C0006080F /* ProofOfWork.swift in Sources */, 4C75EFBB2804A34C0006080F /* ProofOfWork.swift in Sources */,
4C3AC7A52836987600E1F516 /* MainTabView.swift in Sources */, 4C3AC7A52836987600E1F516 /* MainTabView.swift in Sources */,
3AA59D1D2999B0400061C48E /* DraftsModel.swift in Sources */,
3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */, 3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */,
4CB9D4A72992D02B00A9A7E4 /* ProfileNameView.swift in Sources */, 4CB9D4A72992D02B00A9A7E4 /* ProfileNameView.swift in Sources */,
); );

View File

@ -606,19 +606,21 @@ struct ContentView: View {
pool.register_handler(sub_id: sub_id, handler: home.handle_event) pool.register_handler(sub_id: sub_id, handler: home.handle_event)
self.damus_state = DamusState(pool: pool, keypair: keypair, self.damus_state = DamusState(pool: pool,
likes: EventCounter(our_pubkey: pubkey), keypair: keypair,
boosts: EventCounter(our_pubkey: pubkey), likes: EventCounter(our_pubkey: pubkey),
contacts: Contacts(our_pubkey: pubkey), boosts: EventCounter(our_pubkey: pubkey),
tips: TipCounter(our_pubkey: pubkey), contacts: Contacts(our_pubkey: pubkey),
profiles: Profiles(), tips: TipCounter(our_pubkey: pubkey),
dms: home.dms, profiles: Profiles(),
previews: PreviewCache(), dms: home.dms,
zaps: Zaps(our_pubkey: pubkey), previews: PreviewCache(),
lnurls: LNUrls(), zaps: Zaps(our_pubkey: pubkey),
settings: UserSettingsStore(), lnurls: LNUrls(),
relay_filters: relay_filters, settings: UserSettingsStore(),
relay_metadata: metadatas relay_filters: relay_filters,
relay_metadata: metadatas,
drafts_model: home.drafts_model
) )
home.damus_state = self.damus_state! home.damus_state = self.damus_state!

View File

@ -23,6 +23,7 @@ struct DamusState {
let settings: UserSettingsStore let settings: UserSettingsStore
let relay_filters: RelayFilters let relay_filters: RelayFilters
let relay_metadata: RelayMetadatas let relay_metadata: RelayMetadatas
let drafts_model: DraftsModel
var pubkey: String { var pubkey: String {
return keypair.pubkey return keypair.pubkey
@ -34,6 +35,6 @@ struct DamusState {
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(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())
} }
} }

View File

@ -13,6 +13,8 @@ class DirectMessageModel: ObservableObject {
is_request = determine_is_request() is_request = determine_is_request()
} }
} }
@Published var draft: String
var is_request: Bool var is_request: Bool
var our_pubkey: String var our_pubkey: String
@ -31,11 +33,13 @@ class DirectMessageModel: ObservableObject {
self.events = events self.events = events
self.is_request = false self.is_request = false
self.our_pubkey = our_pubkey self.our_pubkey = our_pubkey
self.draft = ""
} }
init(our_pubkey: String) { init(our_pubkey: String) {
self.events = [] self.events = []
self.is_request = false self.is_request = false
self.our_pubkey = our_pubkey self.our_pubkey = our_pubkey
self.draft = ""
} }
} }

View File

@ -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>()
}

View File

@ -52,15 +52,18 @@ class HomeModel: ObservableObject {
@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()
@Published var drafts_model: DraftsModel
init() { init() {
self.damus_state = DamusState.empty self.damus_state = DamusState.empty
self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey) self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey)
self.drafts_model = DraftsModel()
} }
init(damus_state: DamusState) { init(damus_state: DamusState) {
self.damus_state = damus_state self.damus_state = damus_state
self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey) self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey)
self.drafts_model = DraftsModel()
} }
var pool: RelayPool { var pool: RelayPool {

View File

@ -11,7 +11,6 @@ struct DMChatView: View {
let damus_state: DamusState let damus_state: DamusState
let pubkey: String let pubkey: String
@EnvironmentObject var dms: DirectMessageModel @EnvironmentObject var dms: DirectMessageModel
@State var message: String = ""
@State var showPrivateKeyWarning: Bool = false @State var showPrivateKeyWarning: Bool = false
var Messages: some View { var Messages: some View {
@ -52,7 +51,7 @@ struct DMChatView: View {
} }
var InputField: some View { var InputField: some View {
TextEditor(text: $message) TextEditor(text: $dms.draft)
.textEditorBackground { .textEditorBackground {
InputBackground() InputBackground()
} }
@ -93,11 +92,11 @@ struct DMChatView: View {
HStack(spacing: 0) { HStack(spacing: 0) {
InputField InputField
if !message.isEmpty { if !dms.draft.isEmpty {
Button( Button(
role: .none, role: .none,
action: { action: {
showPrivateKeyWarning = contentContainsPrivateKey(message) showPrivateKeyWarning = contentContainsPrivateKey(dms.draft)
if !showPrivateKeyWarning { if !showPrivateKeyWarning {
send_message() send_message()
@ -112,7 +111,7 @@ struct DMChatView: View {
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
.frame(minHeight: 70, maxHeight: 150, alignment: .bottom) .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) .fixedSize(horizontal: false, vertical: true)
.frame(minHeight: 70, maxHeight: 150, alignment: .bottom) .frame(minHeight: 70, maxHeight: 150, alignment: .bottom)
} }
@ -122,7 +121,7 @@ struct DMChatView: View {
func send_message() { func send_message() {
let tags = [["p", pubkey]] 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 post_tags = make_post_tags(post_blocks: post_blocks, tags: tags)
let content = render_blocks(blocks: post_tags.blocks) let content = render_blocks(blocks: post_tags.blocks)
@ -131,7 +130,7 @@ struct DMChatView: View {
return return
} }
message = "" dms.draft = ""
damus_state.pool.send(.event(dm)) damus_state.pool.send(.event(dm))
end_editing() 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.")) .navigationTitle(NSLocalizedString("DMs", comment: "Navigation title for DMs view, where DM is the English abbreviation for Direct Message."))
.toolbar { Header } .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: { .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) { 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 showPrivateKeyWarning = false

View File

@ -16,6 +16,7 @@ let POST_PLACEHOLDER = NSLocalizedString("Type your post here...", comment: "Tex
struct PostView: View { struct PostView: View {
@State var post: String = "" @State var post: String = ""
@FocusState var focus: Bool @FocusState var focus: Bool
@State var showPrivateKeyWarning: Bool = false @State var showPrivateKeyWarning: Bool = false
@ -47,6 +48,13 @@ struct PostView: View {
let new_post = NostrPost(content: content, references: references, kind: kind) let new_post = NostrPost(content: content, references: references, kind: kind)
NotificationCenter.default.post(name: .post, object: NostrPostResult.post(new_post)) 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() dismiss()
} }
@ -80,6 +88,13 @@ struct PostView: View {
TextEditor(text: $post) TextEditor(text: $post)
.focused($focus) .focused($focus)
.textInputAutocapitalization(.sentences) .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 { if post.isEmpty {
Text(POST_PLACEHOLDER) Text(POST_PLACEHOLDER)
@ -99,10 +114,26 @@ struct PostView: View {
} }
} }
.onAppear() { .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) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.focus = true 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() .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: { .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) { 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) {