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:
@@ -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 */,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
23
damus/Models/CommentItem.swift
Normal file
23
damus/Models/CommentItem.swift
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// CommentItem.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by Daniel D’Aquino 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())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user