Event Preloading

Changelog-Added: Added event preloading when scrolling
Changelog-Added: Preload images so they don't pop in
Changelog-Fixed: Fixed preview elements popping in
Changelog-Changed: Cached various UI elements so its not as laggy
Changelog-Fixed: Fixed glitchy preview
This commit is contained in:
William Casarin
2023-04-30 19:31:14 -07:00
parent c87f19b479
commit 1ca0519e25
11 changed files with 532 additions and 192 deletions

View File

@@ -30,8 +30,12 @@ struct NoteContentView: View {
let preview_height: CGFloat?
let options: EventViewOptions
@State var artifacts: NoteArtifacts
@State var preview: LinkViewRepresentable?
@ObservedObject var artifacts_model: NoteArtifactsModel
@ObservedObject var preview_model: PreviewModel
var artifacts: NoteArtifacts {
return self.artifacts_model.state.artifacts ?? .just_content(event.get_content(damus_state.keypair.privkey))
}
init(damus_state: DamusState, event: NostrEvent, show_images: Bool, size: EventViewKind, artifacts: NoteArtifacts, options: EventViewOptions) {
self.damus_state = damus_state
@@ -39,16 +43,10 @@ struct NoteContentView: View {
self.show_images = show_images
self.size = size
self.options = options
self._artifacts = State(initialValue: artifacts)
self.preview_height = lookup_cached_preview_size(previews: damus_state.previews, evid: event.id)
self._preview = State(initialValue: load_cached_preview(previews: damus_state.previews, evid: event.id))
if let cache = damus_state.events.lookup_artifacts(evid: event.id) {
self._artifacts = State(initialValue: cache)
} else {
let artifacts = render_note_content(ev: event, profiles: damus_state.profiles, privkey: damus_state.keypair.privkey)
damus_state.events.store_artifacts(evid: event.id, artifacts: artifacts)
self._artifacts = State(initialValue: artifacts)
}
let cached = damus_state.events.get_cache_data(event.id)
self._preview_model = ObservedObject(wrappedValue: cached.preview_model)
self._artifacts_model = ObservedObject(wrappedValue: cached.artifacts_model)
}
var truncate: Bool {
@@ -59,6 +57,16 @@ struct NoteContentView: View {
return options.contains(.pad_content)
}
var preview: LinkViewRepresentable? {
guard show_images,
case .loaded(let preview) = preview_model.state,
case .value(let cached) = preview else {
return nil
}
return LinkViewRepresentable(meta: .linkmeta(cached))
}
var truncatedText: some View {
Group {
if truncate {
@@ -151,6 +159,18 @@ struct NoteContentView: View {
}
}
func load() async {
guard let plan = get_preload_plan(cache: damus_state.events.get_cache_data(event.id), ev: event, our_keypair: damus_state.keypair, settings: damus_state.settings) else {
return
}
let result = await preload_event(plan: plan, profiles: damus_state.profiles, our_keypair: damus_state.keypair, settings: damus_state.settings)
DispatchQueue.main.async {
set_preload_results(plan: plan, res: result, privkey: damus_state.keypair.privkey)
}
}
var body: some View {
MainContent
.onReceive(handle_notify(.profile_updated)) { notif in
@@ -160,7 +180,11 @@ struct NoteContentView: View {
switch block {
case .mention(let m):
if m.type == .pubkey && m.ref.ref_id == profile.pubkey {
self.artifacts = render_note_content(ev: event, profiles: damus_state.profiles, privkey: damus_state.keypair.privkey)
self.artifacts_model.state = .loading
Task.init {
await load()
}
return
}
case .relay: return
case .text: return
@@ -171,39 +195,10 @@ struct NoteContentView: View {
}
}
.task {
guard self.preview == nil else {
return
}
if show_images, artifacts.links.count == 1 {
let meta = await getMetaData(for: artifacts.links.first!)
damus_state.previews.store(evid: self.event.id, preview: meta)
guard case .value(let cached) = damus_state.previews.lookup(self.event.id) else {
return
}
let view = LinkViewRepresentable(meta: .linkmeta(cached))
self.preview = view
}
await load()
}
}
func getMetaData(for url: URL) async -> LPLinkMetadata? {
// iOS 15 is crashing for some reason
guard #available(iOS 16, *) else {
return nil
}
let provider = LPMetadataProvider()
do {
return try await provider.startFetchingMetadata(for: url)
} catch {
return nil
}
}
}
enum ImageName {
@@ -274,6 +269,42 @@ struct NoteArtifacts: Equatable {
}
}
enum NoteArtifactState {
case not_loaded
case loading
case loaded(NoteArtifacts)
var artifacts: NoteArtifacts? {
if case .loaded(let artifacts) = self {
return artifacts
}
return nil
}
var is_loaded: Bool {
switch self {
case .not_loaded:
return false
case .loading:
return false
case .loaded:
return true
}
}
var should_preload: Bool {
switch self {
case .loaded:
return false
case .loading:
return false
case .not_loaded:
return true
}
}
}
func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -> NoteArtifacts {
let blocks = ev.blocks(privkey)