Add support for rendering highlights with comments

This commit implements rendering comments from the `["comment",
<COMMENT_TEXT>]` tag in a highlight note.

Comment contents get rendered like a kind 1 note's "content" field

This commit also adds the `r` "reference" tag as a standard tag reference type

Changelog-Added: Add support for rendering highlights with comments
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
Daniel D’Aquino
2024-08-17 14:55:23 -07:00
parent 4f881a5667
commit f9271da11c
8 changed files with 69 additions and 12 deletions

View File

@@ -496,6 +496,9 @@
D753CEAA2BE9DE04001C3A5D /* MutingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D753CEA92BE9DE04001C3A5D /* MutingTests.swift */; }; D753CEAA2BE9DE04001C3A5D /* MutingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D753CEA92BE9DE04001C3A5D /* MutingTests.swift */; };
D76556D62B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76556D52B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift */; }; D76556D62B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76556D52B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift */; };
D76874F32AE3632B00FB0F68 /* ProfileZapLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76874F22AE3632B00FB0F68 /* ProfileZapLinkView.swift */; }; D76874F32AE3632B00FB0F68 /* ProfileZapLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76874F22AE3632B00FB0F68 /* ProfileZapLinkView.swift */; };
D773BC5F2C6D538500349F0A /* CommentItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D773BC5E2C6D538500349F0A /* CommentItem.swift */; };
D773BC602C6D538500349F0A /* CommentItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D773BC5E2C6D538500349F0A /* CommentItem.swift */; };
D773BC612C6D58A700349F0A /* CommentItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D773BC5E2C6D538500349F0A /* CommentItem.swift */; };
D77BFA0B2AE3051200621634 /* ProfileActionSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77BFA0A2AE3051200621634 /* ProfileActionSheetView.swift */; }; D77BFA0B2AE3051200621634 /* ProfileActionSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77BFA0A2AE3051200621634 /* ProfileActionSheetView.swift */; };
D783A63F2AD4E53D00658DDA /* SuggestedHashtagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D783A63E2AD4E53D00658DDA /* SuggestedHashtagsView.swift */; }; D783A63F2AD4E53D00658DDA /* SuggestedHashtagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D783A63E2AD4E53D00658DDA /* SuggestedHashtagsView.swift */; };
D78525252A7B2EA4002FA637 /* NoteContentViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78525242A7B2EA4002FA637 /* NoteContentViewTests.swift */; }; D78525252A7B2EA4002FA637 /* NoteContentViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78525242A7B2EA4002FA637 /* NoteContentViewTests.swift */; };
@@ -1425,6 +1428,7 @@
D753CEA92BE9DE04001C3A5D /* MutingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutingTests.swift; sourceTree = "<group>"; }; D753CEA92BE9DE04001C3A5D /* MutingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutingTests.swift; sourceTree = "<group>"; };
D76556D52B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleWelcomeView.swift; sourceTree = "<group>"; }; D76556D52B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleWelcomeView.swift; sourceTree = "<group>"; };
D76874F22AE3632B00FB0F68 /* ProfileZapLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileZapLinkView.swift; sourceTree = "<group>"; }; D76874F22AE3632B00FB0F68 /* ProfileZapLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileZapLinkView.swift; sourceTree = "<group>"; };
D773BC5E2C6D538500349F0A /* CommentItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentItem.swift; sourceTree = "<group>"; };
D77BFA0A2AE3051200621634 /* ProfileActionSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileActionSheetView.swift; sourceTree = "<group>"; }; D77BFA0A2AE3051200621634 /* ProfileActionSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileActionSheetView.swift; sourceTree = "<group>"; };
D783A63E2AD4E53D00658DDA /* SuggestedHashtagsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestedHashtagsView.swift; sourceTree = "<group>"; }; D783A63E2AD4E53D00658DDA /* SuggestedHashtagsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestedHashtagsView.swift; sourceTree = "<group>"; };
D78525242A7B2EA4002FA637 /* NoteContentViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteContentViewTests.swift; sourceTree = "<group>"; }; D78525242A7B2EA4002FA637 /* NoteContentViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteContentViewTests.swift; sourceTree = "<group>"; };
@@ -1681,6 +1685,7 @@
B533694D2B66D791008A805E /* MutelistManager.swift */, B533694D2B66D791008A805E /* MutelistManager.swift */,
D7D2A3802BF815D000E4B42B /* PushNotificationClient.swift */, D7D2A3802BF815D000E4B42B /* PushNotificationClient.swift */,
5CC8529C2BD741CD0039FFC5 /* HighlightEvent.swift */, 5CC8529C2BD741CD0039FFC5 /* HighlightEvent.swift */,
D773BC5E2C6D538500349F0A /* CommentItem.swift */,
); );
path = Models; path = Models;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -3485,6 +3490,7 @@
4CF38C882A9442DC00BE01B6 /* UserStatusView.swift in Sources */, 4CF38C882A9442DC00BE01B6 /* UserStatusView.swift in Sources */,
4CE6DEE727F7A08100C66700 /* damusApp.swift in Sources */, 4CE6DEE727F7A08100C66700 /* damusApp.swift in Sources */,
4C1253582A76C9060004F4B8 /* PresentSheetNotify.swift in Sources */, 4C1253582A76C9060004F4B8 /* PresentSheetNotify.swift in Sources */,
D773BC5F2C6D538500349F0A /* CommentItem.swift in Sources */,
4C363A962827096D006E126D /* PostBlock.swift in Sources */, 4C363A962827096D006E126D /* PostBlock.swift in Sources */,
4CA9275F2A2902B20098A105 /* LongformPreview.swift in Sources */, 4CA9275F2A2902B20098A105 /* LongformPreview.swift in Sources */,
4C5F9116283D855D0052CD1C /* EventsModel.swift in Sources */, 4C5F9116283D855D0052CD1C /* EventsModel.swift in Sources */,
@@ -3720,6 +3726,7 @@
D74AAFC62B155B8B006CF0F4 /* Zaps.swift in Sources */, D74AAFC62B155B8B006CF0F4 /* Zaps.swift in Sources */,
D7CCFC0B2B0585EA00323D86 /* nostrdb.c in Sources */, D7CCFC0B2B0585EA00323D86 /* nostrdb.c in Sources */,
D7CE1B252B0BE1F4002EDAD4 /* sha256.c in Sources */, D7CE1B252B0BE1F4002EDAD4 /* sha256.c in Sources */,
D773BC612C6D58A700349F0A /* CommentItem.swift in Sources */,
D7CE1B262B0BE1F8002EDAD4 /* bech32.c in Sources */, D7CE1B262B0BE1F8002EDAD4 /* bech32.c in Sources */,
D7EDED232B117DFB0018B19C /* NoteContent.swift in Sources */, D7EDED232B117DFB0018B19C /* NoteContent.swift in Sources */,
D798D21B2B0856F200234419 /* NdbTagsIterator.swift in Sources */, D798D21B2B0856F200234419 /* NdbTagsIterator.swift in Sources */,

View File

@@ -12,7 +12,7 @@ enum NoteContent {
case content(String, TagsSequence?) case content(String, TagsSequence?)
init(note: NostrEvent, keypair: Keypair) { init(note: NostrEvent, keypair: Keypair) {
if note.known_kind == .dm { if note.known_kind == .dm || note.known_kind == .highlight {
self = .content(note.get_content(keypair), note.tags) self = .content(note.get_content(keypair), note.tags)
} else { } else {
self = .note(note) self = .note(note)

View File

@@ -1170,7 +1170,7 @@ func on_open_url(state: DamusState, url: URL, result: @escaping (OpenResult?) ->
} }
case .hashtag(let ht): case .hashtag(let ht):
result(.filter(.filter_hashtag([ht.hashtag]))) result(.filter(.filter_hashtag([ht.hashtag])))
case .param, .quote: case .param, .quote, .reference:
// doesn't really make sense here // doesn't really make sense here
break break
case .naddr(let naddr): case .naddr(let naddr):

View File

@@ -0,0 +1,23 @@
//
// CommentItem.swift
// damus
//
// Created by Daniel DAquino on 2024-08-14.
//
import Foundation
struct CommentItem: TagConvertible {
static let TAG_KEY: String = "comment"
let content: String
var tag: [String] {
return [Self.TAG_KEY, content]
}
static func from_tag(tag: TagSequence) -> CommentItem? {
guard tag.count == 2 else { return nil }
guard tag[0].string() == Self.TAG_KEY else { return nil }
return CommentItem(content: tag[1].string())
}
}

View File

@@ -109,7 +109,7 @@ func is_already_following(contacts: NostrEvent, follow: FollowRef) -> Bool {
case let (.pubkey(pk), .pubkey(follow_pk)): case let (.pubkey(pk), .pubkey(follow_pk)):
return pk == follow_pk return pk == follow_pk
case (.hashtag, .pubkey), (.pubkey, .hashtag), case (.hashtag, .pubkey), (.pubkey, .hashtag),
(.event, _), (.quote, _), (.param, _), (.naddr, _): (.event, _), (.quote, _), (.param, _), (.naddr, _), (.reference(_), _):
return false return false
} }
} }

View File

@@ -122,20 +122,22 @@ enum RefId: TagConvertible, TagKeys, Equatable, Hashable {
case hashtag(Hashtag) case hashtag(Hashtag)
case param(TagElem) case param(TagElem)
case naddr(NAddr) case naddr(NAddr)
case reference(String)
var key: RefKey { var key: RefKey {
switch self { switch self {
case .event: return .e case .event: return .e
case .pubkey: return .p case .pubkey: return .p
case .quote: return .q case .quote: return .q
case .hashtag: return .t case .hashtag: return .t
case .param: return .d case .param: return .d
case .naddr: return .a case .naddr: return .a
case .reference: return .r
} }
} }
enum RefKey: AsciiCharacter, TagKey, CustomStringConvertible { enum RefKey: AsciiCharacter, TagKey, CustomStringConvertible {
case e, p, t, d, q, a case e, p, t, d, q, a, r
var keychar: AsciiCharacter { var keychar: AsciiCharacter {
self.rawValue self.rawValue
@@ -159,6 +161,8 @@ enum RefId: TagConvertible, TagKeys, Equatable, Hashable {
case .param(let string): return string.string() case .param(let string): return string.string()
case .naddr(let naddr): case .naddr(let naddr):
return naddr.kind.description + ":" + naddr.author.hex() + ":" + naddr.identifier return naddr.kind.description + ":" + naddr.author.hex() + ":" + naddr.identifier
case .reference(let string):
return string
} }
} }
@@ -179,6 +183,7 @@ enum RefId: TagConvertible, TagKeys, Equatable, Hashable {
case .t: return .hashtag(Hashtag(hashtag: t1.string())) case .t: return .hashtag(Hashtag(hashtag: t1.string()))
case .d: return .param(t1) case .d: return .param(t1)
case .a: return .naddr(NAddr(identifier: "", author: Pubkey(Data()), relays: [], kind: 0)) case .a: return .naddr(NAddr(identifier: "", author: Pubkey(Data()), relays: [], kind: 0))
case .r: return .reference(t1.string())
} }
} }
} }

View File

@@ -59,9 +59,9 @@ struct HighlightBodyView: View {
var body: some View { var body: some View {
Group { Group {
if options.contains(.wide) { if options.contains(.wide) {
Main.padding(.horizontal)
} else {
Main Main
} else {
Main.padding(.horizontal)
} }
} }
} }
@@ -92,6 +92,18 @@ struct HighlightBodyView: View {
var Main: some View { var Main: some View {
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 0) {
if self.event.event.referenced_comment_items.first?.content != nil {
let all_options = options.union(.no_action_bar)
NoteContentView(
damus_state: self.state,
event: self.event.event,
blur_images: should_blur_images(damus_state: self.state, ev: self.event.event),
size: .normal,
options: all_options
).padding(.vertical, 10)
}
HStack { HStack {
var attributedString: AttributedString { var attributedString: AttributedString {
var attributedString: AttributedString = "" var attributedString: AttributedString = ""
@@ -119,14 +131,17 @@ struct HighlightBodyView: View {
RoundedRectangle(cornerRadius: 25).fill(DamusColors.highlight).frame(width: 4), RoundedRectangle(cornerRadius: 25).fill(DamusColors.highlight).frame(width: 4),
alignment: .leading alignment: .leading
) )
.padding(.horizontal)
.padding(.bottom, 10) .padding(.bottom, 10)
if let url = event.url_ref { if let url = event.url_ref {
HighlightLink(state: state, url: url, content: event.event.content) HighlightLink(state: state, url: url, content: event.event.content)
.padding(.horizontal)
} else { } else {
if let evRef = event.event_ref { if let evRef = event.event_ref {
if let eventHex = hex_decode_id(evRef) { if let eventHex = hex_decode_id(evRef) {
HighlightEventRef(damus_state: state, event_ref: NoteId(eventHex)) HighlightEventRef(damus_state: state, event_ref: NoteId(eventHex))
.padding(.horizontal)
.padding(.top, 5) .padding(.top, 5)
} }
} }

View File

@@ -335,6 +335,10 @@ extension NdbNote {
public var referenced_mute_items: References<MuteItem> { public var referenced_mute_items: References<MuteItem> {
References<MuteItem>(tags: self.tags) References<MuteItem>(tags: self.tags)
} }
public var referenced_comment_items: References<CommentItem> {
References<CommentItem>(tags: self.tags)
}
public var references: References<RefId> { public var references: References<RefId> {
References<RefId>(tags: self.tags) References<RefId>(tags: self.tags)
@@ -355,6 +359,9 @@ extension NdbNote {
if known_kind == .dm { if known_kind == .dm {
return decrypted(keypair: keypair) ?? "*failed to decrypt content*" return decrypted(keypair: keypair) ?? "*failed to decrypt content*"
} }
else if known_kind == .highlight {
return self.referenced_comment_items.first?.content ?? ""
}
return content return content
} }