perf: cache link previews
Changelog-Added: Cache link previews
This commit is contained in:
@@ -51,6 +51,7 @@
|
|||||||
4C363AA428296DEE006E126D /* SearchModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363AA328296DEE006E126D /* SearchModel.swift */; };
|
4C363AA428296DEE006E126D /* SearchModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363AA328296DEE006E126D /* SearchModel.swift */; };
|
||||||
4C363AA828297703006E126D /* InsertSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363AA728297703006E126D /* InsertSort.swift */; };
|
4C363AA828297703006E126D /* InsertSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363AA728297703006E126D /* InsertSort.swift */; };
|
||||||
4C3A1D332960DB0500558C0F /* Markdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A1D322960DB0500558C0F /* Markdown.swift */; };
|
4C3A1D332960DB0500558C0F /* Markdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A1D322960DB0500558C0F /* Markdown.swift */; };
|
||||||
|
4C3A1D3729637E0500558C0F /* PreviewCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A1D3629637E0500558C0F /* PreviewCache.swift */; };
|
||||||
4C3AC79B28306D7B00E1F516 /* Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79A28306D7B00E1F516 /* Contacts.swift */; };
|
4C3AC79B28306D7B00E1F516 /* Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79A28306D7B00E1F516 /* Contacts.swift */; };
|
||||||
4C3AC79D2833036D00E1F516 /* FollowingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79C2833036D00E1F516 /* FollowingView.swift */; };
|
4C3AC79D2833036D00E1F516 /* FollowingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79C2833036D00E1F516 /* FollowingView.swift */; };
|
||||||
4C3AC79F2833115300E1F516 /* FollowButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79E2833115300E1F516 /* FollowButtonView.swift */; };
|
4C3AC79F2833115300E1F516 /* FollowButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79E2833115300E1F516 /* FollowButtonView.swift */; };
|
||||||
@@ -207,6 +208,7 @@
|
|||||||
4C363AA328296DEE006E126D /* SearchModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchModel.swift; sourceTree = "<group>"; };
|
4C363AA328296DEE006E126D /* SearchModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchModel.swift; sourceTree = "<group>"; };
|
||||||
4C363AA728297703006E126D /* InsertSort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsertSort.swift; sourceTree = "<group>"; };
|
4C363AA728297703006E126D /* InsertSort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsertSort.swift; sourceTree = "<group>"; };
|
||||||
4C3A1D322960DB0500558C0F /* Markdown.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Markdown.swift; sourceTree = "<group>"; };
|
4C3A1D322960DB0500558C0F /* Markdown.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Markdown.swift; sourceTree = "<group>"; };
|
||||||
|
4C3A1D3629637E0500558C0F /* PreviewCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewCache.swift; sourceTree = "<group>"; };
|
||||||
4C3AC79A28306D7B00E1F516 /* Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contacts.swift; sourceTree = "<group>"; };
|
4C3AC79A28306D7B00E1F516 /* Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contacts.swift; sourceTree = "<group>"; };
|
||||||
4C3AC79C2833036D00E1F516 /* FollowingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingView.swift; sourceTree = "<group>"; };
|
4C3AC79C2833036D00E1F516 /* FollowingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingView.swift; sourceTree = "<group>"; };
|
||||||
4C3AC79E2833115300E1F516 /* FollowButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowButtonView.swift; sourceTree = "<group>"; };
|
4C3AC79E2833115300E1F516 /* FollowButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowButtonView.swift; sourceTree = "<group>"; };
|
||||||
@@ -542,6 +544,7 @@
|
|||||||
4C216F352870A9A700040376 /* InputDismissKeyboard.swift */,
|
4C216F352870A9A700040376 /* InputDismissKeyboard.swift */,
|
||||||
3169CAEC294FCCFC00EE4006 /* Constants.swift */,
|
3169CAEC294FCCFC00EE4006 /* Constants.swift */,
|
||||||
3165648A295B70D500C64604 /* LinkView.swift */,
|
3165648A295B70D500C64604 /* LinkView.swift */,
|
||||||
|
4C3A1D3629637E0500558C0F /* PreviewCache.swift */,
|
||||||
);
|
);
|
||||||
path = Util;
|
path = Util;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -842,6 +845,7 @@
|
|||||||
3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */,
|
3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */,
|
||||||
4C3EA64928FF597700C48A62 /* bech32.c in Sources */,
|
4C3EA64928FF597700C48A62 /* bech32.c in Sources */,
|
||||||
4C90BD162839DB54008EE7EF /* NostrMetadata.swift in Sources */,
|
4C90BD162839DB54008EE7EF /* NostrMetadata.swift in Sources */,
|
||||||
|
4C3A1D3729637E0500558C0F /* PreviewCache.swift in Sources */,
|
||||||
4C3EA67528FF7A5A00C48A62 /* take.c in Sources */,
|
4C3EA67528FF7A5A00C48A62 /* take.c in Sources */,
|
||||||
4C3AC7A12835A81400E1F516 /* SetupView.swift in Sources */,
|
4C3AC7A12835A81400E1F516 /* SetupView.swift in Sources */,
|
||||||
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */,
|
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */,
|
||||||
|
|||||||
@@ -423,7 +423,8 @@ struct ContentView: View {
|
|||||||
contacts: Contacts(),
|
contacts: Contacts(),
|
||||||
tips: TipCounter(our_pubkey: pubkey),
|
tips: TipCounter(our_pubkey: pubkey),
|
||||||
profiles: Profiles(),
|
profiles: Profiles(),
|
||||||
dms: home.dms
|
dms: home.dms,
|
||||||
|
previews: PreviewCache()
|
||||||
)
|
)
|
||||||
home.damus_state = self.damus_state!
|
home.damus_state = self.damus_state!
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import LinkPresentation
|
||||||
|
|
||||||
struct DamusState {
|
struct DamusState {
|
||||||
let pool: RelayPool
|
let pool: RelayPool
|
||||||
@@ -16,12 +17,13 @@ struct DamusState {
|
|||||||
let tips: TipCounter
|
let tips: TipCounter
|
||||||
let profiles: Profiles
|
let profiles: Profiles
|
||||||
let dms: DirectMessagesModel
|
let dms: DirectMessagesModel
|
||||||
|
let previews: PreviewCache
|
||||||
|
|
||||||
var pubkey: String {
|
var pubkey: String {
|
||||||
return keypair.pubkey
|
return keypair.pubkey
|
||||||
}
|
}
|
||||||
|
|
||||||
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(), tips: TipCounter(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel())
|
return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(), tips: TipCounter(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(), previews: PreviewCache())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class Constants {
|
|||||||
|
|
||||||
static let PUB_KEY = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
|
static let PUB_KEY = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
|
||||||
|
|
||||||
static let EXAMPLE_DEMOS = DamusState(pool: RelayPool(), keypair: Keypair(pubkey: PUB_KEY, privkey: "privkey"), likes: EventCounter(our_pubkey: PUB_KEY), boosts: EventCounter(our_pubkey: PUB_KEY), contacts: Contacts(), tips: TipCounter(our_pubkey: PUB_KEY), profiles: Profiles(), dms: DirectMessagesModel())
|
static let EXAMPLE_DEMOS: DamusState = .empty
|
||||||
|
|
||||||
static let EXAMPLE_EVENTS = [
|
static let EXAMPLE_EVENTS = [
|
||||||
NostrEvent(id: UUID().description, content: "Nostr - Damus... Haha get it? Bonjour Le Monde mon Ami! C'est la tres importante", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"),
|
NostrEvent(id: UUID().description, content: "Nostr - Damus... Haha get it? Bonjour Le Monde mon Ami! C'est la tres importante", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"),
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ struct ChatView: View {
|
|||||||
|
|
||||||
if let ref_id = thread.replies.lookup(event.id) {
|
if let ref_id = thread.replies.lookup(event.id) {
|
||||||
if !is_reply_to_prev() {
|
if !is_reply_to_prev() {
|
||||||
ReplyQuoteView(privkey: damus_state.keypair.privkey, quoter: event, event_id: ref_id, profiles: damus_state.profiles)
|
ReplyQuoteView(privkey: damus_state.keypair.privkey, quoter: event, event_id: ref_id, profiles: damus_state.profiles, previews: damus_state.previews)
|
||||||
.frame(maxHeight: expand_reply ? nil : 100)
|
.frame(maxHeight: expand_reply ? nil : 100)
|
||||||
.environmentObject(thread)
|
.environmentObject(thread)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
@@ -106,7 +106,7 @@ struct ChatView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, show_images: should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey), artifacts: .just_content(event.content), size: .normal)
|
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, previews: damus_state.previews, show_images: should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey), artifacts: .just_content(event.content), size: .normal)
|
||||||
|
|
||||||
if is_active || next_ev == nil || next_ev!.pubkey != event.pubkey {
|
if is_active || next_ev == nil || next_ev!.pubkey != event.pubkey {
|
||||||
let bar = make_actionbar_model(ev: event, damus: damus_state)
|
let bar = make_actionbar_model(ev: event, damus: damus_state)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ struct DMView: View {
|
|||||||
|
|
||||||
let should_show_img = should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey)
|
let should_show_img = should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey)
|
||||||
|
|
||||||
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, show_images: should_show_img, artifacts: .just_content(event.get_content(damus_state.keypair.privkey)), size: .normal)
|
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, previews: damus_state.previews, show_images: should_show_img, artifacts: .just_content(event.get_content(damus_state.keypair.privkey)), size: .normal)
|
||||||
.foregroundColor(is_ours ? Color.white : Color.primary)
|
.foregroundColor(is_ours ? Color.white : Color.primary)
|
||||||
.padding(10)
|
.padding(10)
|
||||||
.background(is_ours ? Color.accentColor : Color.secondary.opacity(0.15))
|
.background(is_ours ? Color.accentColor : Color.secondary.opacity(0.15))
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ struct EventView: View {
|
|||||||
|
|
||||||
let should_show_img = should_show_images(contacts: damus.contacts, ev: event, our_pubkey: damus.pubkey)
|
let should_show_img = should_show_images(contacts: damus.contacts, ev: event, our_pubkey: damus.pubkey)
|
||||||
|
|
||||||
NoteContentView(privkey: damus.keypair.privkey, event: event, profiles: damus.profiles, show_images: should_show_img, artifacts: .just_content(content), size: self.size)
|
NoteContentView(privkey: damus.keypair.privkey, event: event, profiles: damus.profiles, previews: damus.previews, show_images: should_show_img, artifacts: .just_content(content), size: self.size)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.allowsHitTesting(!embedded)
|
.allowsHitTesting(!embedded)
|
||||||
|
|
||||||
|
|||||||
@@ -61,12 +61,13 @@ struct NoteContentView: View {
|
|||||||
let privkey: String?
|
let privkey: String?
|
||||||
let event: NostrEvent
|
let event: NostrEvent
|
||||||
let profiles: Profiles
|
let profiles: Profiles
|
||||||
|
let previews: PreviewCache
|
||||||
|
|
||||||
let show_images: Bool
|
let show_images: Bool
|
||||||
|
|
||||||
@State var artifacts: NoteArtifacts
|
@State var artifacts: NoteArtifacts
|
||||||
|
|
||||||
@State var metaData: LPLinkMetadata? = nil
|
@State var preview: LinkViewRepresentable? = nil
|
||||||
let size: EventViewKind
|
let size: EventViewKind
|
||||||
|
|
||||||
func MainContent() -> some View {
|
func MainContent() -> some View {
|
||||||
@@ -89,8 +90,8 @@ struct NoteContentView: View {
|
|||||||
InvoicesView(invoices: artifacts.invoices)
|
InvoicesView(invoices: artifacts.invoices)
|
||||||
}
|
}
|
||||||
|
|
||||||
if show_images, self.metaData != nil {
|
if show_images, self.preview != nil {
|
||||||
LinkViewRepresentable(metadata: self.metaData)
|
self.preview
|
||||||
} else {
|
} else {
|
||||||
ForEach(artifacts.links, id:\.self) { link in
|
ForEach(artifacts.links, id:\.self) { link in
|
||||||
LinkViewRepresentable(url: link)
|
LinkViewRepresentable(url: link)
|
||||||
@@ -123,9 +124,22 @@ struct NoteContentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.task {
|
.task {
|
||||||
if show_images, artifacts.links.count == 1 {
|
if let preview = previews.lookup(self.event.id) {
|
||||||
|
switch preview {
|
||||||
|
case .value(let view):
|
||||||
|
self.preview = view
|
||||||
|
case .failed:
|
||||||
|
// don't try to refetch meta if we've failed
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.metaData = await getMetaData(for: artifacts.links.first!)
|
if show_images, artifacts.links.count == 1 {
|
||||||
|
let meta = await getMetaData(for: artifacts.links.first!)
|
||||||
|
|
||||||
|
let view = LinkViewRepresentable(metadata: meta)
|
||||||
|
previews.store(evid: self.event.id, preview: view)
|
||||||
|
self.preview = view
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,6 +184,6 @@ struct NoteContentView_Previews: PreviewProvider {
|
|||||||
let state = test_damus_state()
|
let state = test_damus_state()
|
||||||
let content = "hi there https://jb55.com/s/Oct12-150217.png 5739a762ef6124dd.jpg"
|
let content = "hi there https://jb55.com/s/Oct12-150217.png 5739a762ef6124dd.jpg"
|
||||||
let artifacts = NoteArtifacts(content: content, images: [], invoices: [], links: [])
|
let artifacts = NoteArtifacts(content: content, images: [], invoices: [], links: [])
|
||||||
NoteContentView(privkey: "", event: NostrEvent(content: content, pubkey: "pk"), profiles: state.profiles, show_images: true, artifacts: artifacts, size: .normal)
|
NoteContentView(privkey: "", event: NostrEvent(content: content, pubkey: "pk"), profiles: state.profiles, previews: PreviewCache(), show_images: true, artifacts: artifacts, size: .normal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -306,8 +306,7 @@ struct ProfileView_Previews: PreviewProvider {
|
|||||||
|
|
||||||
func test_damus_state() -> DamusState {
|
func test_damus_state() -> DamusState {
|
||||||
let pubkey = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
|
let pubkey = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
|
||||||
let damus = DamusState(pool: RelayPool(), keypair: Keypair(pubkey: pubkey, privkey: "privkey"), likes: EventCounter(our_pubkey: pubkey), boosts: EventCounter(our_pubkey: pubkey), contacts: Contacts(), tips: TipCounter(our_pubkey: pubkey), profiles: Profiles(), dms: DirectMessagesModel())
|
let damus: DamusState = .empty
|
||||||
|
|
||||||
let prof = Profile(name: "damus", display_name: "Damus", about: "iOS app!", picture: "https://damus.io/img/logo.png", website: "https://damus.io", lud06: nil, lud16: "jb55@sendsats.lol", nip05: "damus.io")
|
let prof = Profile(name: "damus", display_name: "Damus", about: "iOS app!", picture: "https://damus.io/img/logo.png", website: "https://damus.io", lud06: nil, lud16: "jb55@sendsats.lol", nip05: "damus.io")
|
||||||
let tsprof = TimestampedProfile(profile: prof, timestamp: 0)
|
let tsprof = TimestampedProfile(profile: prof, timestamp: 0)
|
||||||
damus.profiles.add(id: pubkey, profile: tsprof)
|
damus.profiles.add(id: pubkey, profile: tsprof)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ struct ReplyQuoteView: View {
|
|||||||
let quoter: NostrEvent
|
let quoter: NostrEvent
|
||||||
let event_id: String
|
let event_id: String
|
||||||
let profiles: Profiles
|
let profiles: Profiles
|
||||||
|
let previews: PreviewCache
|
||||||
|
|
||||||
@EnvironmentObject var thread: ThreadModel
|
@EnvironmentObject var thread: ThreadModel
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ struct ReplyQuoteView: View {
|
|||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteContentView(privkey: privkey, event: event, profiles: profiles, show_images: false, artifacts: .just_content(event.content), size: .normal)
|
NoteContentView(privkey: privkey, event: event, profiles: profiles, previews: previews, show_images: false, artifacts: .just_content(event.content), size: .normal)
|
||||||
.font(.callout)
|
.font(.callout)
|
||||||
.foregroundColor(.accentColor)
|
.foregroundColor(.accentColor)
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ struct ReplyQuoteView_Previews: PreviewProvider {
|
|||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let s = test_damus_state()
|
let s = test_damus_state()
|
||||||
let quoter = NostrEvent(content: "a\nb\nc", pubkey: "pubkey")
|
let quoter = NostrEvent(content: "a\nb\nc", pubkey: "pubkey")
|
||||||
ReplyQuoteView(privkey: s.keypair.privkey, quoter: quoter, event_id: "pubkey2", profiles: s.profiles)
|
ReplyQuoteView(privkey: s.keypair.privkey, quoter: quoter, event_id: "pubkey2", profiles: s.profiles, previews: PreviewCache())
|
||||||
.environmentObject(ThreadModel(event: quoter, damus_state: s))
|
.environmentObject(ThreadModel(event: quoter, damus_state: s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
|
||||||
@main
|
@main
|
||||||
struct damusApp: App {
|
struct damusApp: App {
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
|
|||||||
Reference in New Issue
Block a user