diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj index 10c89777..71888053 100644 --- a/damus.xcodeproj/project.pbxproj +++ b/damus.xcodeproj/project.pbxproj @@ -192,6 +192,12 @@ 4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */; }; 4CA3FA1029F593D000FDB3C3 /* ZapTypePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA3FA0F29F593D000FDB3C3 /* ZapTypePicker.swift */; }; 4CA5588329F33F5B00DC6A45 /* StringCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA5588229F33F5B00DC6A45 /* StringCodable.swift */; }; + 4CA927612A290E340098A105 /* EventShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA927602A290E340098A105 /* EventShell.swift */; }; + 4CA927632A290EB10098A105 /* EventTop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA927622A290EB10098A105 /* EventTop.swift */; }; + 4CA927652A290F1A0098A105 /* TimeDot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA927642A290F1A0098A105 /* TimeDot.swift */; }; + 4CA927672A290F8B0098A105 /* RelativeTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA927662A290F8B0098A105 /* RelativeTime.swift */; }; + 4CA9276A2A290FC00098A105 /* ContextButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA927692A290FC00098A105 /* ContextButton.swift */; }; + 4CA9276C2A2910D10098A105 /* ReplyPart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA9276B2A2910D10098A105 /* ReplyPart.swift */; }; 4CAAD8AD298851D000060CEA /* AccountDeletion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAAD8AC298851D000060CEA /* AccountDeletion.swift */; }; 4CAAD8B029888AD200060CEA /* RelayConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */; }; 4CACA9D5280C31E100D9BBE8 /* ReplyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */; }; @@ -664,6 +670,12 @@ 4CA927712A2A5D480098A105 /* error.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = error.h; sourceTree = ""; }; 4CA927742A2A5E2F0098A105 /* varint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = varint.h; sourceTree = ""; }; 4CA927752A2A5E2F0098A105 /* typedefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = typedefs.h; sourceTree = ""; }; + 4CA927602A290E340098A105 /* EventShell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventShell.swift; sourceTree = ""; }; + 4CA927622A290EB10098A105 /* EventTop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventTop.swift; sourceTree = ""; }; + 4CA927642A290F1A0098A105 /* TimeDot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeDot.swift; sourceTree = ""; }; + 4CA927662A290F8B0098A105 /* RelativeTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelativeTime.swift; sourceTree = ""; }; + 4CA927692A290FC00098A105 /* ContextButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextButton.swift; sourceTree = ""; }; + 4CA9276B2A2910D10098A105 /* ReplyPart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyPart.swift; sourceTree = ""; }; 4CAAD8AC298851D000060CEA /* AccountDeletion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDeletion.swift; sourceTree = ""; }; 4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayConfigView.swift; sourceTree = ""; }; 4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyView.swift; sourceTree = ""; }; @@ -1257,6 +1269,18 @@ 4C9146FB2A2A77B300DDEA40 /* NostrScript.swift */, ); path = nostrscript; + }; + 4CA927682A290F8F0098A105 /* Components */ = { + isa = PBXGroup; + children = ( + 4CA927642A290F1A0098A105 /* TimeDot.swift */, + 4CA927622A290EB10098A105 /* EventTop.swift */, + 4CC7AAF3297F18B400430951 /* ReplyDescription.swift */, + 4CA927662A290F8B0098A105 /* RelativeTime.swift */, + 4CA927692A290FC00098A105 /* ContextButton.swift */, + 4CA9276B2A2910D10098A105 /* ReplyPart.swift */, + ); + path = Components; sourceTree = ""; }; 4CA927732A2A5DCC0098A105 /* nostrscript */ = { @@ -1328,8 +1352,8 @@ 4CC7AAEE297F11B300430951 /* Events */ = { isa = PBXGroup; children = ( + 4CA927682A290F8F0098A105 /* Components */, 4CC7AAEF297F11C700430951 /* SelectedEventView.swift */, - 4CC7AAF3297F18B400430951 /* ReplyDescription.swift */, 4CC7AAF5297F1A6A00430951 /* EventBody.swift */, 4CC7AAEA297F0AEC00430951 /* BuilderEventView.swift */, 4CC7AAF7297F1CEE00430951 /* EventProfile.swift */, @@ -1338,6 +1362,7 @@ 4C3D52B5298DB4E6001C5831 /* ZapEvent.swift */, 4C3D52B7298DB5C6001C5831 /* TextEvent.swift */, 4CFF8F6C29CD022E008DB934 /* WideEventView.swift */, + 4CA927602A290E340098A105 /* EventShell.swift */, ); path = Events; sourceTree = ""; @@ -1782,6 +1807,7 @@ 4C3EA64428FF558100C48A62 /* sha256.c in Sources */, 4CCF9AAF2A1FDBDB00E03CFB /* VideoPlayer.swift in Sources */, 504323A72A34915F006AE6DC /* RelayModel.swift in Sources */, + 4CA9276A2A290FC00098A105 /* ContextButton.swift in Sources */, 4CF0ABF62985CD5500D66079 /* UserSearch.swift in Sources */, 4C363AA828297703006E126D /* InsertSort.swift in Sources */, 4C285C86283892E7008A31F1 /* CreateAccountModel.swift in Sources */, @@ -1806,6 +1832,7 @@ 4CB55EF5295E679D007FD187 /* UserRelaysView.swift in Sources */, 4C363AA228296A7E006E126D /* SearchView.swift in Sources */, 4CC7AAED297F0B9E00430951 /* Highlight.swift in Sources */, + 4CA927652A290F1A0098A105 /* TimeDot.swift in Sources */, 4CC6193A29DC777C006A86D1 /* RelayBootstrap.swift in Sources */, 4C285C8A2838B985008A31F1 /* ProfilePictureSelector.swift in Sources */, 4C9F18E429ABDE6D008C55EC /* MaybeAnonPfpView.swift in Sources */, @@ -1835,6 +1862,7 @@ 3A5E47C52A4A6CF400C0D090 /* Trie.swift in Sources */, 4C216F382871EDE300040376 /* DirectMessageModel.swift in Sources */, 4C75EFA627FF87A20006080F /* Nostr.swift in Sources */, + 4CA927672A290F8B0098A105 /* RelativeTime.swift in Sources */, 4CB883A62975F83C00DC99E7 /* LNUrlPayRequest.swift in Sources */, 4C7D096D2A0AEA0400943473 /* CodeScanner.swift in Sources */, 4CE4F9DE2852768D00C00DD9 /* ConfigView.swift in Sources */, @@ -1854,6 +1882,7 @@ 4C363A9A28283854006E126D /* Reply.swift in Sources */, BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */, 4CFF8F6729CC9E3A008DB934 /* ImageView.swift in Sources */, + 4CA927632A290EB10098A105 /* EventTop.swift in Sources */, 4C90BD18283A9EE5008EE7EF /* LoginView.swift in Sources */, 4CB8838B296F6E1E00DC99E7 /* NIP05Badge.swift in Sources */, 4CA3FA1029F593D000FDB3C3 /* ZapTypePicker.swift in Sources */, @@ -1938,6 +1967,7 @@ 4C9146FD2A2A87C200DDEA40 /* wasm.c in Sources */, 4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */, 4C3EA64C28FF59AC00C48A62 /* bech32_util.c in Sources */, + 4CA9276C2A2910D10098A105 /* ReplyPart.swift in Sources */, 4CE1399029F0661A00AC6A0B /* RepostAction.swift in Sources */, 4CE1399229F0666100AC6A0B /* ShareActionButton.swift in Sources */, 4C42812C298C848200DBF26F /* TranslateView.swift in Sources */, @@ -1981,6 +2011,7 @@ 4CDA128C29EB19C40006FA5A /* LocalNotification.swift in Sources */, 4C3BEFD6281D995700B3DE84 /* ActionBarModel.swift in Sources */, 4C7D09762A0AF19E00943473 /* FillAndStroke.swift in Sources */, + 4CA927612A290E340098A105 /* EventShell.swift in Sources */, 4C363AA428296DEE006E126D /* SearchModel.swift in Sources */, 4C8D00CC29DF92DF0036AF10 /* Hashtags.swift in Sources */, 4C7D096F2A0AEA0400943473 /* ScannerViewController.swift in Sources */, diff --git a/damus/Views/Events/Components/ContextButton.swift b/damus/Views/Events/Components/ContextButton.swift new file mode 100644 index 00000000..49c57b64 --- /dev/null +++ b/damus/Views/Events/Components/ContextButton.swift @@ -0,0 +1,20 @@ +// +// ContextButton.swift +// damus +// +// Created by William Casarin on 2023-06-01. +// + +import SwiftUI + +struct ContextButton: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +struct ContextButton_Previews: PreviewProvider { + static var previews: some View { + ContextButton() + } +} diff --git a/damus/Views/Events/Components/EventTop.swift b/damus/Views/Events/Components/EventTop.swift new file mode 100644 index 00000000..c3987847 --- /dev/null +++ b/damus/Views/Events/Components/EventTop.swift @@ -0,0 +1,44 @@ +// +// EventTop.swift +// damus +// +// Created by William Casarin on 2023-06-01. +// + +import SwiftUI + +struct EventTop: View { + let state: DamusState + let event: NostrEvent + let is_anon: Bool + + init(state: DamusState, event: NostrEvent, is_anon: Bool) { + self.state = state + self.event = event + self.is_anon = is_anon + } + + func ProfileName(is_anon: Bool) -> some View { + let profile = state.profiles.lookup(id: event.pubkey) + let pk = is_anon ? "anon" : event.pubkey + return EventProfileName(pubkey: pk, profile: profile, damus: state, size: .normal) + } + + var body: some View { + HStack(alignment: .center, spacing: 0) { + ProfileName(is_anon: is_anon) + TimeDot() + RelativeTime(time: state.events.get_cache_data(event.id).relative_time) + Spacer() + EventMenuContext(damus: state, event: event) + } + + .lineLimit(1) + } +} + +struct EventTop_Previews: PreviewProvider { + static var previews: some View { + EventTop(state: test_damus_state(), event: test_event, is_anon: false) + } +} diff --git a/damus/Views/Events/Components/RelativeTime.swift b/damus/Views/Events/Components/RelativeTime.swift new file mode 100644 index 00000000..802568eb --- /dev/null +++ b/damus/Views/Events/Components/RelativeTime.swift @@ -0,0 +1,25 @@ +// +// RelativeTime.swift +// damus +// +// Created by William Casarin on 2023-06-01. +// + +import SwiftUI + +struct RelativeTime: View { + @ObservedObject var time: RelativeTimeModel + + var body: some View { + Text(verbatim: "\(time.value)") + .font(.system(size: 16)) + .foregroundColor(.gray) + } +} + + +struct RelativeTime_Previews: PreviewProvider { + static var previews: some View { + RelativeTime(time: RelativeTimeModel()) + } +} diff --git a/damus/Views/Events/ReplyDescription.swift b/damus/Views/Events/Components/ReplyDescription.swift similarity index 100% rename from damus/Views/Events/ReplyDescription.swift rename to damus/Views/Events/Components/ReplyDescription.swift diff --git a/damus/Views/Events/Components/ReplyPart.swift b/damus/Views/Events/Components/ReplyPart.swift new file mode 100644 index 00000000..1a301a48 --- /dev/null +++ b/damus/Views/Events/Components/ReplyPart.swift @@ -0,0 +1,30 @@ +// +// ReplyPart.swift +// damus +// +// Created by William Casarin on 2023-06-01. +// + +import SwiftUI + +struct ReplyPart: View { + let event: NostrEvent + let privkey: String? + let profiles: Profiles + + var body: some View { + Group { + if event_is_reply(event, privkey: privkey) { + ReplyDescription(event: event, profiles: profiles) + } else { + EmptyView() + } + } + } +} + +struct ReplyPart_Previews: PreviewProvider { + static var previews: some View { + ReplyPart(event: test_event, privkey: nil, profiles: test_damus_state().profiles) + } +} diff --git a/damus/Views/Events/Components/TimeDot.swift b/damus/Views/Events/Components/TimeDot.swift new file mode 100644 index 00000000..817b5629 --- /dev/null +++ b/damus/Views/Events/Components/TimeDot.swift @@ -0,0 +1,22 @@ +// +// TimeDot.swift +// damus +// +// Created by William Casarin on 2023-06-01. +// + +import SwiftUI + +struct TimeDot: View { + var body: some View { + Text(verbatim: "⋅") + .font(.footnote) + .foregroundColor(.gray) + } +} + +struct TimeDot_Previews: PreviewProvider { + static var previews: some View { + TimeDot() + } +} diff --git a/damus/Views/Events/EventMenu.swift b/damus/Views/Events/EventMenu.swift index b3615d61..b7f9c1ce 100644 --- a/damus/Views/Events/EventMenu.swift +++ b/damus/Views/Events/EventMenu.swift @@ -15,6 +15,15 @@ struct EventMenuContext: View { let muted_threads: MutedThreadsManager @ObservedObject var settings: UserSettingsStore + init(damus: DamusState, event: NostrEvent) { + self.event = event + self.keypair = damus.keypair + self.target_pubkey = event.pubkey + self.bookmarks = damus.bookmarks + self.muted_threads = damus.muted_threads + self._settings = ObservedObject(wrappedValue: damus.settings) + } + var body: some View { HStack { Menu { @@ -26,6 +35,7 @@ struct EventMenuContext: View { .foregroundColor(Color.gray) } } + .padding([.bottom], 4) .contentShape(Rectangle()) .onTapGesture {} } diff --git a/damus/Views/Events/EventShell.swift b/damus/Views/Events/EventShell.swift new file mode 100644 index 00000000..762d2b7e --- /dev/null +++ b/damus/Views/Events/EventShell.swift @@ -0,0 +1,72 @@ +// +// EventShell.swift +// damus +// +// Created by William Casarin on 2023-06-01. +// + +import SwiftUI + +struct EventShell: View { + let state: DamusState + let event: NostrEvent + let options: EventViewOptions + let content: Content + + init(state: DamusState, event: NostrEvent, options: EventViewOptions, @ViewBuilder content: () -> Content) { + self.state = state + self.event = event + self.options = options + self.content = content() + } + + var has_action_bar: Bool { + !options.contains(.no_action_bar) + } + + func get_mention() -> Mention? { + if self.options.contains(.nested) { + return nil + } + + return first_eref_mention(ev: event, privkey: state.keypair.privkey) + } + + var body: some View { + VStack(alignment: .leading) { + let is_anon = event_is_anonymous(ev: event) + + HStack(spacing: 10) { + MaybeAnonPfpView(state: state, is_anon: is_anon, pubkey: event.pubkey, size: options.contains(.small_pfp) ? eventview_pfp_size(.small) : PFP_SIZE ) + + VStack { + EventTop(state: state, event: event, is_anon: is_anon) + ReplyPart(event: event, privkey: state.keypair.privkey, profiles: state.profiles) + } + } + .padding(.horizontal) + + content + + if !options.contains(.no_mentions), let mention = get_mention() { + + BuilderEventView(damus: state, event_id: mention.ref.id) + .padding(.horizontal) + } + + if has_action_bar { + //EmptyRect + EventActionBar(damus_state: state, event: event) + .padding(.horizontal) + } + } + } +} + +struct EventShell_Previews: PreviewProvider { + static var previews: some View { + EventShell(state: test_damus_state(), event: test_event, options: [.no_action_bar]) { + Text("Hello") + } + } +} diff --git a/damus/Views/Events/SelectedEventView.swift b/damus/Views/Events/SelectedEventView.swift index 7c1d1b2f..444d7dec 100644 --- a/damus/Views/Events/SelectedEventView.swift +++ b/damus/Views/Events/SelectedEventView.swift @@ -35,9 +35,8 @@ struct SelectedEventView: View { Spacer() - EventMenuContext(event: event, keypair: damus.keypair, target_pubkey: event.pubkey, bookmarks: damus.bookmarks, muted_threads: damus.muted_threads, settings: damus.settings) + EventMenuContext(damus: damus, event: event) .padding([.bottom], 4) - } .padding(.horizontal) .minimumScaleFactor(0.75) diff --git a/damus/Views/Events/TextEvent.swift b/damus/Views/Events/TextEvent.swift index e2a62ac6..4eee37d9 100644 --- a/damus/Views/Events/TextEvent.swift +++ b/damus/Views/Events/TextEvent.swift @@ -24,16 +24,6 @@ struct EventViewOptions: OptionSet { static let embedded: EventViewOptions = [.no_action_bar, .small_pfp, .wide, .truncate_content, .nested] } -struct RelativeTime: View { - @ObservedObject var time: RelativeTimeModel - - var body: some View { - Text(verbatim: "\(time.value)") - .font(.system(size: 16)) - .foregroundColor(.gray) - } -} - struct TextEvent: View { let damus: DamusState let event: NostrEvent @@ -74,63 +64,20 @@ struct TextEvent: View { func TopPart(is_anon: Bool) -> some View { HStack(alignment: .center, spacing: 0) { ProfileName(is_anon: is_anon) - TimeDot + TimeDot() RelativeTime(time: self.evdata.relative_time) Spacer() - ContextButton + EventMenuContext(damus: damus, event: event) } .lineLimit(1) } - var ReplyPart: some View { - Group { - if event_is_reply(event, privkey: damus.keypair.privkey) { - ReplyDescription(event: event, profiles: damus.profiles) - } else { - EmptyView() - } - } - } - var WideStyle: some View { - VStack(alignment: .leading) { - let is_anon = event_is_anonymous(ev: event) - - HStack(spacing: 10) { - Pfp(is_anon: is_anon) - VStack { - TopPart(is_anon: is_anon) - ReplyPart - } - } - .padding(.horizontal) - + EventShell(state: damus, event: event, options: options) { EvBody(options: self.options.union(.pad_content)) - - if let mention = get_mention() { - Mention(mention) - .padding(.horizontal) - } - - if has_action_bar { - //EmptyRect - ActionBar - .padding(.horizontal) - } } } - var TimeDot: some View { - Text(verbatim: "⋅") - .font(.footnote) - .foregroundColor(.gray) - } - - var ContextButton: some View { - EventMenuContext(event: event, keypair: damus.keypair, target_pubkey: event.pubkey, bookmarks: damus.bookmarks, muted_threads: damus.muted_threads, settings: damus.settings) - .padding([.bottom], 4) - } - func ProfileName(is_anon: Bool) -> some View { let profile = damus.profiles.lookup(id: pubkey) let pk = is_anon ? ANON_PUBKEY : pubkey @@ -184,7 +131,7 @@ struct TextEvent: View { TopPart(is_anon: is_anon) if !options.contains(.no_replying_to) { - ReplyPart + ReplyPart(event: event, privkey: damus.keypair.privkey, profiles: damus.profiles) } EvBody(options: self.options)